mirror of
https://github.com/catchorg/Catch2.git
synced 2025-08-03 05:45:39 +02:00
Implement a simplified variant of std::unique_ptr<T>
This simplified variant supports only a subset of the functionality in `std::unique_ptr<T>`. `Catch::Detail::unique_ptr<T>` only supports single element pointer (no array support) with default deleter. By removing the support for custom deleters, we also avoid requiring significant machinery to support EBO, speeding up instantiations of `unique_ptr<T>` significantly. Catch2 also currently does not need to support `unique_ptr<T[]>`, so that is not supported either.
This commit is contained in:
@@ -125,6 +125,7 @@ set(INTERNAL_HEADERS
|
||||
${SOURCES_DIR}/catch_totals.hpp
|
||||
${SOURCES_DIR}/catch_translate_exception.hpp
|
||||
${SOURCES_DIR}/internal/catch_uncaught_exceptions.hpp
|
||||
${SOURCES_DIR}/internal/catch_unique_ptr.hpp
|
||||
${SOURCES_DIR}/catch_version.hpp
|
||||
${SOURCES_DIR}/catch_version_macros.hpp
|
||||
${SOURCES_DIR}/internal/catch_wildcard_pattern.hpp
|
||||
|
@@ -85,6 +85,7 @@
|
||||
#include <catch2/internal/catch_text.hpp>
|
||||
#include <catch2/internal/catch_to_string.hpp>
|
||||
#include <catch2/internal/catch_uncaught_exceptions.hpp>
|
||||
#include <catch2/internal/catch_unique_ptr.hpp>
|
||||
#include <catch2/internal/catch_wildcard_pattern.hpp>
|
||||
#include <catch2/internal/catch_windows_h_proxy.hpp>
|
||||
#include <catch2/internal/catch_xmlwriter.hpp>
|
||||
|
110
src/catch2/internal/catch_unique_ptr.hpp
Normal file
110
src/catch2/internal/catch_unique_ptr.hpp
Normal file
@@ -0,0 +1,110 @@
|
||||
#ifndef CATCH_UNIQUE_PTR_HPP_INCLUDED
|
||||
#define CATCH_UNIQUE_PTR_HPP_INCLUDED
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
|
||||
namespace Catch {
|
||||
namespace Detail {
|
||||
// reimplementation of unique_ptr for improved compilation times
|
||||
// Does not support custom deleters (and thus does not require EBO)
|
||||
// Does not support arrays
|
||||
template <typename T>
|
||||
class unique_ptr {
|
||||
T* m_ptr;
|
||||
public:
|
||||
constexpr unique_ptr(std::nullptr_t = nullptr):
|
||||
m_ptr{}
|
||||
{}
|
||||
explicit constexpr unique_ptr(T* ptr):
|
||||
m_ptr(ptr)
|
||||
{}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
|
||||
unique_ptr(unique_ptr<U>&& from):
|
||||
m_ptr(from.release())
|
||||
{}
|
||||
|
||||
template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
|
||||
unique_ptr& operator=(unique_ptr<U>&& from) {
|
||||
reset(from.release());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
unique_ptr(unique_ptr const&) = delete;
|
||||
unique_ptr& operator=(unique_ptr const&) = delete;
|
||||
|
||||
unique_ptr(unique_ptr&& rhs) noexcept:
|
||||
m_ptr(rhs.m_ptr) {
|
||||
rhs.m_ptr = nullptr;
|
||||
}
|
||||
unique_ptr& operator=(unique_ptr&& rhs) noexcept {
|
||||
reset(rhs.release());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
~unique_ptr() {
|
||||
delete m_ptr;
|
||||
}
|
||||
|
||||
T& operator*() {
|
||||
assert(m_ptr);
|
||||
return *m_ptr;
|
||||
}
|
||||
T const& operator*() const {
|
||||
assert(m_ptr);
|
||||
return *m_ptr;
|
||||
}
|
||||
T* operator->() const noexcept {
|
||||
assert(m_ptr);
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
T* get() { return m_ptr; }
|
||||
T const* get() const { return m_ptr; }
|
||||
|
||||
void reset(T* ptr = nullptr) {
|
||||
delete m_ptr;
|
||||
m_ptr = ptr;
|
||||
}
|
||||
|
||||
T* release() {
|
||||
auto temp = m_ptr;
|
||||
m_ptr = nullptr;
|
||||
return temp;
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
friend void swap(unique_ptr& lhs, unique_ptr& rhs) {
|
||||
auto temp = lhs.m_ptr;
|
||||
lhs.m_ptr = rhs.m_ptr;
|
||||
rhs.m_ptr = temp;
|
||||
}
|
||||
};
|
||||
|
||||
// Purposefully doesn't exist
|
||||
// We could also rely on compiler warning + werror for calling plain delete
|
||||
// on a T[], but this seems better.
|
||||
// Maybe add definition and a static assert?
|
||||
template <typename T>
|
||||
class unique_ptr<T[]>;
|
||||
|
||||
template <typename T, typename... Args>
|
||||
unique_ptr<T> make_unique(Args&&... args) {
|
||||
// static_cast<Args&&> does the same thing as std::forward in
|
||||
// this case, but does not require including big header (<utility>)
|
||||
// and compiles faster thanks to not requiring template instantiation
|
||||
// and overload resolution
|
||||
return unique_ptr<T>(new T(static_cast<Args&&>(args)...));
|
||||
}
|
||||
|
||||
|
||||
} // end namespace Detail
|
||||
} // end namespace Catch
|
||||
|
||||
#endif // CATCH_UNIQUE_PTR_HPP_INCLUDED
|
Reference in New Issue
Block a user