1270 lines
40 KiB
C++
1270 lines
40 KiB
C++
#pragma once
|
|
|
|
#include "tl/detail/prologue.h"
|
|
#include <compare>
|
|
#include "tl/functional.h"
|
|
#include "tl/atomic.h"
|
|
#include "tl/assert.h"
|
|
#include "tl/crash.h"
|
|
|
|
namespace tl
|
|
{
|
|
|
|
|
|
#ifdef TL_DEBUG
|
|
# define CHECKED_PTR 1
|
|
#else
|
|
# define CHECKED_PTR 0
|
|
#endif
|
|
|
|
template<typename T> class unique_ref;
|
|
template<typename T> class unique_ptr;
|
|
template<typename T> class lent_ref;
|
|
template<typename T> class lent_ptr;
|
|
|
|
template<typename T>
|
|
using delete_callback = eastl::function<void(T*)>;
|
|
|
|
|
|
template<typename T, bool>
|
|
struct ptr_traits_passes_virtual_destructor_check
|
|
{
|
|
static constexpr inline bool value = !std::is_polymorphic<T>::value || std::is_final<T>::value || std::has_virtual_destructor<T>::value;
|
|
};
|
|
|
|
template<typename T>
|
|
struct ptr_traits_passes_virtual_destructor_check<T, false> // check not required
|
|
{
|
|
static constexpr inline bool value = true;
|
|
};
|
|
|
|
template<typename T>
|
|
struct ptr_traits
|
|
{
|
|
static constexpr inline bool custom_deleter = false;
|
|
static constexpr inline bool requires_virtual_destructor_check = true;
|
|
};
|
|
|
|
namespace detail
|
|
{
|
|
|
|
template<typename T, bool Custom>
|
|
struct deleter
|
|
{};
|
|
|
|
template<typename T>
|
|
struct deleter<T, false>
|
|
{
|
|
constexpr deleter() noexcept = default;
|
|
|
|
constexpr deleter(const deleter<T, false>& other) noexcept = default;
|
|
constexpr deleter(deleter<T, false>&& other) noexcept = default;
|
|
constexpr deleter& operator=(const deleter<T, false>& other) noexcept = default;
|
|
constexpr deleter& operator=(deleter<T, false>&& other) noexcept = default;
|
|
|
|
constexpr void destroy(T* p) noexcept { delete p; }
|
|
};
|
|
|
|
template<typename T>
|
|
struct deleter<T, true>
|
|
{
|
|
constexpr deleter() noexcept = default;
|
|
constexpr deleter(delete_callback<T> callback) noexcept : callback(std::move(callback)) {}
|
|
|
|
constexpr deleter(const deleter<T, true>& other) noexcept = default;
|
|
constexpr deleter(deleter<T, true>&& other) noexcept = default;
|
|
constexpr deleter& operator=(const deleter<T, true>& other) noexcept = default;
|
|
constexpr deleter& operator=(deleter<T, true>&& other) noexcept = default;
|
|
|
|
constexpr void destroy(T* p) noexcept { if (callback && p) callback(p); }
|
|
delete_callback<T> callback;
|
|
};
|
|
|
|
struct ptr_control_block
|
|
{
|
|
tl::atomic<int32_t> unique_count = { 1 };
|
|
tl::atomic<int32_t> lent_count = { 0 };
|
|
};
|
|
|
|
#if CHECKED_PTR == 1
|
|
template<typename Ptr, typename SrcPtr, typename T> Ptr build_copy(T* t, const SrcPtr& src) noexcept { return Ptr(t, src.get_control_block(), Ptr::increment_ref_count); }
|
|
template<typename Ptr, typename SrcPtr, typename T> Ptr build_move(T* t, SrcPtr& src) noexcept { return Ptr(t, src.release_control_block()); }
|
|
template<typename Ptr, typename SrcPtr, typename T> Ptr build_move_with_deleter(T* t, SrcPtr& src) noexcept { return Ptr(t, src.get_deleter(), src.release_control_block()); }
|
|
#else
|
|
template<typename Ptr, typename SrcPtr, typename T> Ptr build_copy(T* t, const SrcPtr& src) noexcept { return Ptr(t); }
|
|
template<typename Ptr, typename SrcPtr, typename T> Ptr build_move(T* t, SrcPtr& src) noexcept { return Ptr(t); }
|
|
template<typename Ptr, typename SrcPtr, typename T> Ptr build_move_with_deleter(T* t, SrcPtr& src) noexcept { return Ptr(t, src.get_deleter()); }
|
|
#endif
|
|
|
|
extern thread_local int32_t s_ptr_checking_disabled;
|
|
|
|
}
|
|
|
|
#define CHECK_NULL if (!m_ptr) [[unlikely]] TL_PLAIN_CRASH("nullptr")
|
|
|
|
|
|
#if CHECKED_PTR == 1
|
|
|
|
#define CB_DECLARE_NULL() detail::ptr_control_block* m_cb = nullptr
|
|
#define CB_ALLOCATE() m_cb = new detail::ptr_control_block()
|
|
#define CB_ASSIGN(other) m_cb = other.get_control_block()
|
|
#define CB_MOVE(other) m_cb = other.release_control_block()
|
|
#define CB_LENT_INC_REF() if (m_cb) [[likely]] m_cb->lent_count.fetch_add(1, tl::memory_order_release);
|
|
#define CB_LENT_DEC_REF() \
|
|
if (m_cb) [[likely]] \
|
|
{ \
|
|
bool is_dangling = m_cb->unique_count.load(tl::memory_order_acquire) == 0; \
|
|
if (is_dangling && is_ptr_checking_enabled()) [[unlikely]] \
|
|
TL_FAIL("lent: {} dangling lent ptrs detected", m_cb->lent_count.load(tl::memory_order_acquire)); \
|
|
if (m_cb->lent_count.fetch_sub(1, tl::memory_order_acquire) == 1) /* last one? cleanup */ \
|
|
{ \
|
|
if (is_dangling) [[unlikely]] \
|
|
delete m_cb; \
|
|
} \
|
|
m_cb = nullptr; \
|
|
}
|
|
|
|
#define CB_LENT_COPY_CTOR() \
|
|
CB_ASSIGN(other); \
|
|
CB_LENT_INC_REF()
|
|
|
|
#define CB_LENT_MOVE_CTOR() \
|
|
CB_MOVE(other)
|
|
|
|
#define CB_LENT_COPY_ASSIGN() \
|
|
CB_LENT_DEC_REF(); \
|
|
CB_ASSIGN(other); \
|
|
CB_LENT_INC_REF()
|
|
|
|
#define CB_LENT_MOVE_ASSIGN() \
|
|
CB_LENT_DEC_REF(); \
|
|
CB_MOVE(other);
|
|
|
|
|
|
#define CB_UNIQUE_DEC_REF() \
|
|
if (m_cb && m_cb->unique_count.fetch_sub(1, tl::memory_order_acquire) == 1) [[likely]] \
|
|
{ \
|
|
int32_t count = m_cb->lent_count.load(tl::memory_order_acquire); \
|
|
if (count == 0) [[likely]] \
|
|
delete m_cb; \
|
|
else if (is_ptr_checking_enabled()) [[likely]] \
|
|
TL_FAIL("unique: {} dangling lent ptrs detected", count); \
|
|
m_cb = nullptr; \
|
|
}
|
|
|
|
#define CB_UNIQUE_MOVE_CTOR() \
|
|
CB_MOVE(other)
|
|
|
|
#define CB_UNIQUE_MOVE_ASSIGN() \
|
|
CB_UNIQUE_DEC_REF(); \
|
|
CB_MOVE(other);
|
|
|
|
#else
|
|
|
|
|
|
#define CB_DECLARE_NULL()
|
|
#define CB_ALLOCATE()
|
|
#define CB_ASSIGN(other)
|
|
#define CB_MOVE(other)
|
|
#define CB_LENT_INC_REF()
|
|
#define CB_LENT_DEC_REF()
|
|
#define CB_LENT_COPY_CTOR()
|
|
#define CB_LENT_MOVE_CTOR()
|
|
#define CB_LENT_COPY_ASSIGN()
|
|
#define CB_LENT_MOVE_ASSIGN()
|
|
#define CB_UNIQUE_DEC_REF()
|
|
#define CB_UNIQUE_MOVE_CTOR()
|
|
#define CB_UNIQUE_MOVE_ASSIGN()
|
|
|
|
#endif
|
|
|
|
extern void enable_ptr_checking() noexcept;
|
|
extern void disable_ptr_checking() noexcept;
|
|
extern void set_ptr_checking_enabled(bool v) noexcept;
|
|
inline bool is_ptr_checking_enabled() noexcept { return detail::s_ptr_checking_disabled == 0; }
|
|
|
|
struct disable_ptr_checking_scope
|
|
{
|
|
disable_ptr_checking_scope() noexcept { disable_ptr_checking(); }
|
|
~disable_ptr_checking_scope() noexcept { enable_ptr_checking(); }
|
|
};
|
|
|
|
|
|
template<typename T>
|
|
class unique_ptr
|
|
{
|
|
template<typename U> friend class unique_ref;
|
|
template<typename U> friend class unique_ptr;
|
|
template<typename U> friend class lent_ref;
|
|
template<typename U> friend class lent_ptr;
|
|
template<typename Ptr, typename SrcPtr, typename U> friend Ptr detail::build_copy(U* t, const SrcPtr& src) noexcept;
|
|
template<typename Ptr, typename SrcPtr, typename U> friend Ptr detail::build_move(U* t, SrcPtr& src) noexcept;
|
|
template<typename Ptr, typename SrcPtr, typename U> friend Ptr detail::build_move_with_deleter(U* t, SrcPtr& src) noexcept;
|
|
|
|
using deleter_t = detail::deleter<T, ptr_traits<T>::custom_deleter>;
|
|
|
|
private:
|
|
|
|
#if CHECKED_PTR == 1
|
|
using cb_t = detail::ptr_control_block;
|
|
|
|
unique_ptr(T* ptr, cb_t* cb) noexcept requires(ptr_traits<T>::custom_deleter == false)
|
|
: m_ptr(ptr)
|
|
, m_cb(cb)
|
|
{
|
|
}
|
|
unique_ptr(T* ptr, delete_callback<T> del, cb_t* cb) noexcept requires(ptr_traits<T>::custom_deleter == true)
|
|
: m_ptr(ptr)
|
|
, m_del(std::move(del))
|
|
, m_cb(cb)
|
|
{
|
|
}
|
|
cb_t* get_control_block() const noexcept
|
|
{
|
|
return m_cb;
|
|
}
|
|
cb_t* release_control_block() noexcept
|
|
{
|
|
const auto cb = m_cb;
|
|
m_cb = nullptr;
|
|
return cb;
|
|
}
|
|
#endif
|
|
|
|
public:
|
|
|
|
unique_ptr() = default;
|
|
|
|
explicit unique_ptr(T* ptr) noexcept requires(ptr_traits<T>::custom_deleter == false)
|
|
: m_ptr(ptr)
|
|
{
|
|
CB_ALLOCATE();
|
|
}
|
|
|
|
unique_ptr(T* ptr, delete_callback<T> del) noexcept requires(ptr_traits<T>::custom_deleter == true)
|
|
: m_ptr(ptr)
|
|
, m_del(std::move(del))
|
|
{
|
|
CB_ALLOCATE();
|
|
}
|
|
|
|
unique_ptr(std::nullptr_t) noexcept
|
|
: m_ptr(nullptr)
|
|
{
|
|
CB_ALLOCATE();
|
|
}
|
|
~unique_ptr() noexcept
|
|
{
|
|
m_del.destroy(m_ptr);
|
|
CB_UNIQUE_DEC_REF();
|
|
|
|
static_assert(ptr_traits_passes_virtual_destructor_check<T, ptr_traits<T>::requires_virtual_destructor_check>::value, "Destructor is not virtual");
|
|
}
|
|
unique_ptr(const unique_ptr<T>&) noexcept = delete;
|
|
template<typename U> unique_ptr(unique_ptr<U>&& other) noexcept
|
|
: m_ptr(other.release())
|
|
{
|
|
CB_UNIQUE_MOVE_CTOR();
|
|
if constexpr (ptr_traits<T>::custom_deleter == true)
|
|
m_del = std::move(other.m_del);
|
|
}
|
|
template<typename U> unique_ptr(unique_ref<U>&& other) noexcept
|
|
: m_ptr(other.release())
|
|
{
|
|
CB_UNIQUE_MOVE_CTOR();
|
|
if constexpr (ptr_traits<T>::custom_deleter == true)
|
|
m_del = std::move(other.m_del);
|
|
}
|
|
unique_ptr& operator=(const unique_ptr<T>&) noexcept = delete;
|
|
template<typename U> unique_ptr& operator=(unique_ptr<U>&& other) noexcept
|
|
{
|
|
m_del.destroy(m_ptr);
|
|
CB_UNIQUE_MOVE_ASSIGN();
|
|
m_ptr = other.release();
|
|
if constexpr (ptr_traits<T>::custom_deleter == true)
|
|
m_del = std::move(other.m_del);
|
|
return *this;
|
|
}
|
|
template<typename U> unique_ptr& operator=(unique_ref<U>&& other) noexcept
|
|
{
|
|
m_del.destroy(m_ptr);
|
|
CB_UNIQUE_MOVE_ASSIGN();
|
|
m_ptr = other.release();
|
|
if constexpr (ptr_traits<T>::custom_deleter == true)
|
|
m_del = std::move(other.m_del);
|
|
return *this;
|
|
}
|
|
unique_ptr& operator=(std::nullptr_t) noexcept
|
|
{
|
|
reset(nullptr);
|
|
return *this;
|
|
}
|
|
explicit operator bool() const noexcept
|
|
{
|
|
return m_ptr != nullptr;
|
|
}
|
|
constexpr T* get() const noexcept
|
|
{
|
|
return m_ptr;
|
|
}
|
|
delete_callback<T> get_deleter() const noexcept requires(ptr_traits<T>::custom_deleter == true)
|
|
{
|
|
return m_del.callback;
|
|
}
|
|
void reset(T* new_ptr = nullptr) noexcept
|
|
{
|
|
auto* p = m_ptr;
|
|
m_ptr = new_ptr;
|
|
m_del.destroy(p);
|
|
CB_UNIQUE_DEC_REF();
|
|
CB_ALLOCATE();
|
|
}
|
|
void reset(T* new_ptr, delete_callback<T> del) noexcept requires(ptr_traits<T>::custom_deleter == true)
|
|
{
|
|
auto* p = m_ptr;
|
|
m_ptr = new_ptr;
|
|
m_del.destroy(p);
|
|
m_del = std::move(del);
|
|
CB_UNIQUE_DEC_REF();
|
|
CB_ALLOCATE();
|
|
}
|
|
T* release() noexcept
|
|
{
|
|
auto* p = m_ptr;
|
|
m_ptr = nullptr;
|
|
return p;
|
|
}
|
|
T& operator*() const noexcept
|
|
{
|
|
CHECK_NULL;
|
|
return *m_ptr;
|
|
}
|
|
T* operator->() const noexcept
|
|
{
|
|
CHECK_NULL;
|
|
return m_ptr;
|
|
}
|
|
|
|
private:
|
|
T* m_ptr = nullptr;
|
|
#ifdef TL_TOOLCHAIN_MSC
|
|
[[msvc::no_unique_address]] deleter_t m_del;
|
|
#else
|
|
[[no_unique_address]] deleter_t m_del;
|
|
#endif
|
|
CB_DECLARE_NULL();
|
|
};
|
|
|
|
template<typename T>
|
|
class unique_ref
|
|
{
|
|
template<typename U> friend class unique_ref;
|
|
template<typename U> friend class unique_ptr;
|
|
template<typename U> friend class lent_ref;
|
|
template<typename U> friend class lent_ptr;
|
|
template<typename Ptr, typename SrcPtr, typename U> friend Ptr detail::build_copy(U* t, const SrcPtr& src) noexcept;
|
|
template<typename Ptr, typename SrcPtr, typename U> friend Ptr detail::build_move(U* t, SrcPtr& src) noexcept;
|
|
template<typename Ptr, typename SrcPtr, typename U> friend Ptr detail::build_move_with_deleter(U* t, SrcPtr& src) noexcept;
|
|
|
|
using deleter_t = detail::deleter<T, ptr_traits<T>::custom_deleter>;
|
|
|
|
#if CHECKED_PTR == 1
|
|
using cb_t = detail::ptr_control_block;
|
|
|
|
unique_ref(T* ptr, cb_t* cb) noexcept requires(ptr_traits<T>::custom_deleter == false)
|
|
: m_ptr(ptr)
|
|
, m_cb(cb)
|
|
{
|
|
CHECK_NULL;
|
|
}
|
|
unique_ref(T* ptr, delete_callback<T> del, cb_t* cb) noexcept requires(ptr_traits<T>::custom_deleter == true)
|
|
: m_ptr(ptr)
|
|
, m_del(std::move(del))
|
|
, m_cb(cb)
|
|
{
|
|
CHECK_NULL;
|
|
}
|
|
cb_t* get_control_block() const noexcept
|
|
{
|
|
return m_cb;
|
|
}
|
|
cb_t* release_control_block() noexcept
|
|
{
|
|
const auto cb = m_cb;
|
|
m_cb = nullptr;
|
|
return cb;
|
|
}
|
|
#endif
|
|
public:
|
|
|
|
explicit unique_ref(T* ptr) noexcept requires(ptr_traits<T>::custom_deleter == false)
|
|
: m_ptr(ptr)
|
|
{
|
|
CHECK_NULL;
|
|
CB_ALLOCATE();
|
|
}
|
|
unique_ref(T* ptr, delete_callback<T> del) noexcept requires(ptr_traits<T>::custom_deleter == true)
|
|
: m_ptr(ptr)
|
|
, m_del(std::move(del))
|
|
{
|
|
CHECK_NULL;
|
|
CB_ALLOCATE();
|
|
}
|
|
~unique_ref() noexcept
|
|
{
|
|
static_assert(ptr_traits_passes_virtual_destructor_check<T, ptr_traits<T>::requires_virtual_destructor_check>::value, "Destructor is not virtual");
|
|
|
|
m_del.destroy(m_ptr);
|
|
CB_UNIQUE_DEC_REF();
|
|
}
|
|
unique_ref(const unique_ref<T>&) noexcept = delete;
|
|
template<typename U> unique_ref(unique_ref<U>&& other) noexcept
|
|
: m_ptr(other.release())
|
|
{
|
|
CB_UNIQUE_MOVE_CTOR();
|
|
if constexpr (ptr_traits<T>::custom_deleter == true)
|
|
m_del = std::move(other.m_del);
|
|
}
|
|
template<typename U> unique_ref(unique_ptr<U>&& other) noexcept
|
|
: m_ptr(other.release())
|
|
{
|
|
CB_UNIQUE_MOVE_CTOR();
|
|
if constexpr (ptr_traits<T>::custom_deleter == true)
|
|
m_del = std::move(other.m_del);
|
|
CHECK_NULL;
|
|
}
|
|
unique_ref& operator=(const unique_ref<T>&) noexcept = delete;
|
|
template<typename U> unique_ref& operator=(unique_ref<U>&& other) noexcept
|
|
{
|
|
m_del.destroy(m_ptr);
|
|
CB_UNIQUE_MOVE_ASSIGN();
|
|
m_ptr = other.release();
|
|
if constexpr (ptr_traits<T>::custom_deleter == true)
|
|
m_del = std::move(other.m_del);
|
|
CHECK_NULL;
|
|
CB_MOVE(other);
|
|
return *this;
|
|
}
|
|
void reset(T* new_ptr) noexcept requires(ptr_traits<T>::custom_deleter == false)
|
|
{
|
|
auto* p = m_ptr;
|
|
m_ptr = new_ptr;
|
|
m_del.destroy(p);
|
|
CB_UNIQUE_DEC_REF();
|
|
CHECK_NULL;
|
|
CB_ALLOCATE();
|
|
}
|
|
void reset(T* new_ptr, delete_callback<T> del) noexcept requires(ptr_traits<T>::custom_deleter == true)
|
|
{
|
|
auto* p = m_ptr;
|
|
m_ptr = new_ptr;
|
|
m_del.destroy(p);
|
|
m_del = std::move(del);
|
|
CB_UNIQUE_DEC_REF();
|
|
CHECK_NULL;
|
|
CB_ALLOCATE();
|
|
}
|
|
constexpr T* get() const noexcept
|
|
{
|
|
return m_ptr;
|
|
}
|
|
delete_callback<T> get_deleter() const noexcept requires(ptr_traits<T>::custom_deleter == true)
|
|
{
|
|
return m_del.callback;
|
|
}
|
|
T* release() noexcept
|
|
{
|
|
auto* p = m_ptr;
|
|
m_ptr = nullptr;
|
|
return p;
|
|
}
|
|
T& operator*() const noexcept
|
|
{
|
|
CHECK_NULL;
|
|
return *m_ptr;
|
|
}
|
|
T* operator->() const noexcept
|
|
{
|
|
CHECK_NULL;
|
|
return m_ptr;
|
|
}
|
|
|
|
private:
|
|
T* m_ptr = nullptr;
|
|
#ifdef TL_TOOLCHAIN_MSC
|
|
[[msvc::no_unique_address]] deleter_t m_del;
|
|
#else
|
|
[[no_unique_address]] deleter_t m_del;
|
|
#endif
|
|
CB_DECLARE_NULL();
|
|
};
|
|
|
|
|
|
template<typename T>
|
|
class lent_ptr
|
|
{
|
|
template<typename U> friend class unique_ref;
|
|
template<typename U> friend class unique_ptr;
|
|
template<typename U> friend class lent_ref;
|
|
template<typename U> friend class lent_ptr;
|
|
template<typename Ptr, typename SrcPtr, typename U> friend Ptr detail::build_copy(U* t, const SrcPtr& src) noexcept;
|
|
template<typename Ptr, typename SrcPtr, typename U> friend Ptr detail::build_move(U* t, SrcPtr& src) noexcept;
|
|
template<typename Ptr, typename SrcPtr, typename U> friend Ptr detail::build_move_with_deleter(U* t, SrcPtr& src) noexcept;
|
|
|
|
#if CHECKED_PTR == 1
|
|
using cb_t = detail::ptr_control_block;
|
|
enum increment_ref_count_t { increment_ref_count };
|
|
lent_ptr(T* ptr, cb_t* cb, increment_ref_count_t) noexcept
|
|
: m_ptr(ptr)
|
|
, m_cb(cb)
|
|
{
|
|
CB_LENT_INC_REF();
|
|
}
|
|
lent_ptr(T* ptr, cb_t* cb) noexcept
|
|
: m_ptr(ptr)
|
|
, m_cb(cb)
|
|
{
|
|
}
|
|
cb_t* get_control_block() const noexcept
|
|
{
|
|
return m_cb;
|
|
}
|
|
cb_t* release_control_block() noexcept
|
|
{
|
|
const auto cb = m_cb;
|
|
m_cb = nullptr;
|
|
return cb;
|
|
}
|
|
#else
|
|
explicit lent_ptr(T* ptr) noexcept
|
|
: m_ptr(ptr)
|
|
{}
|
|
#endif
|
|
public:
|
|
lent_ptr() noexcept = default;
|
|
lent_ptr(std::nullptr_t) noexcept
|
|
: m_ptr(nullptr)
|
|
{}
|
|
~lent_ptr() noexcept
|
|
{
|
|
CB_LENT_DEC_REF();
|
|
}
|
|
lent_ptr(const lent_ptr<T>& other) noexcept
|
|
: m_ptr(other.m_ptr)
|
|
{
|
|
CB_LENT_COPY_CTOR();
|
|
}
|
|
template<typename U> lent_ptr(const lent_ptr<U>& other) noexcept
|
|
: m_ptr(other.m_ptr)
|
|
{
|
|
CB_LENT_COPY_CTOR();
|
|
}
|
|
template<typename U> lent_ptr(const lent_ref<U>& other) noexcept
|
|
: m_ptr(other.m_ptr)
|
|
{
|
|
CB_LENT_COPY_CTOR();
|
|
}
|
|
template<typename U> lent_ptr(const unique_ptr<U>& other) noexcept
|
|
: m_ptr(other.m_ptr)
|
|
{
|
|
CB_LENT_COPY_CTOR();
|
|
}
|
|
template<typename U> lent_ptr(const unique_ref<U>& other) noexcept
|
|
: m_ptr(other.m_ptr)
|
|
{
|
|
CB_LENT_COPY_CTOR();
|
|
}
|
|
|
|
template<typename U> lent_ptr(unique_ref<U>&& other) = delete;
|
|
template<typename U> lent_ptr(unique_ptr<U>&& other) = delete;
|
|
template<typename U> lent_ptr& operator = (unique_ref<U>&& other) = delete;
|
|
template<typename U> lent_ptr& operator = (unique_ptr<U>&& other) = delete;
|
|
|
|
template<typename U> lent_ptr(lent_ptr<U>&& other) noexcept
|
|
: m_ptr(other.m_ptr)
|
|
{
|
|
other.m_ptr = nullptr;
|
|
CB_LENT_MOVE_CTOR();
|
|
}
|
|
template<typename U> lent_ptr(lent_ref<U>&& other) noexcept
|
|
: m_ptr(other.m_ptr)
|
|
{
|
|
other.m_ptr = nullptr;
|
|
CB_LENT_MOVE_CTOR();
|
|
}
|
|
lent_ptr& operator=(const lent_ptr<T>& other) noexcept
|
|
{
|
|
if (this == &other) [[unlikely]]
|
|
return *this;
|
|
CB_LENT_COPY_ASSIGN();
|
|
m_ptr = other.m_ptr;
|
|
return *this;
|
|
}
|
|
template<typename U> lent_ptr& operator=(const lent_ptr<U>& other) noexcept
|
|
{
|
|
if (this == &other) [[unlikely]]
|
|
return *this;
|
|
CB_LENT_COPY_ASSIGN();
|
|
m_ptr = other.m_ptr;
|
|
return *this;
|
|
}
|
|
template<typename U> lent_ptr& operator=(const lent_ref<U>& other) noexcept
|
|
{
|
|
CB_LENT_COPY_ASSIGN();
|
|
m_ptr = other.m_ptr;
|
|
return *this;
|
|
}
|
|
template<typename U> lent_ptr& operator=(const unique_ptr<U>& other) noexcept
|
|
{
|
|
CB_LENT_COPY_ASSIGN();
|
|
m_ptr = other.m_ptr;
|
|
return *this;
|
|
}
|
|
template<typename U> lent_ptr& operator=(const unique_ref<U>& other) noexcept
|
|
{
|
|
CB_LENT_COPY_ASSIGN();
|
|
m_ptr = other.m_ptr;
|
|
return *this;
|
|
}
|
|
lent_ptr& operator=(lent_ptr<T>&& other) noexcept
|
|
{
|
|
if (this == &other) [[unlikely]]
|
|
return *this;
|
|
CB_LENT_MOVE_ASSIGN();
|
|
m_ptr = other.m_ptr;
|
|
other.m_ptr = nullptr;
|
|
return *this;
|
|
}
|
|
template<typename U> lent_ptr& operator=(lent_ptr<U>&& other) noexcept
|
|
{
|
|
CB_LENT_MOVE_ASSIGN();
|
|
m_ptr = other.m_ptr;
|
|
other.m_ptr = nullptr;
|
|
return *this;
|
|
}
|
|
template<typename U> lent_ptr& operator=(lent_ref<U>&& other) noexcept
|
|
{
|
|
CB_LENT_MOVE_ASSIGN();
|
|
m_ptr = other.m_ptr;
|
|
other.m_ptr = nullptr;
|
|
return *this;
|
|
}
|
|
lent_ptr& operator=(std::nullptr_t) noexcept
|
|
{
|
|
CB_LENT_DEC_REF();
|
|
m_ptr = nullptr;
|
|
return *this;
|
|
}
|
|
explicit operator bool() const noexcept
|
|
{
|
|
return m_ptr != nullptr;
|
|
}
|
|
constexpr T* get() const noexcept
|
|
{
|
|
return m_ptr;
|
|
}
|
|
T& operator*() const noexcept
|
|
{
|
|
CHECK_NULL;
|
|
return *m_ptr;
|
|
}
|
|
T* operator->() const noexcept
|
|
{
|
|
CHECK_NULL;
|
|
return m_ptr;
|
|
}
|
|
|
|
private:
|
|
T* m_ptr = nullptr;
|
|
CB_DECLARE_NULL();
|
|
};
|
|
|
|
template<typename T>
|
|
class lent_ref
|
|
{
|
|
template<typename U> friend class unique_ref;
|
|
template<typename U> friend class unique_ptr;
|
|
template<typename U> friend class lent_ref;
|
|
template<typename U> friend class lent_ptr;
|
|
template<typename Ptr, typename SrcPtr, typename U> friend Ptr detail::build_copy(U* t, const SrcPtr& src) noexcept;
|
|
template<typename Ptr, typename SrcPtr, typename U> friend Ptr detail::build_move(U* t, SrcPtr& src) noexcept;
|
|
template<typename Ptr, typename SrcPtr, typename U> friend Ptr detail::build_move_with_deleter(U* t, SrcPtr& src) noexcept;
|
|
|
|
#if CHECKED_PTR == 1
|
|
using cb_t = detail::ptr_control_block;
|
|
enum increment_ref_count_t { increment_ref_count };
|
|
lent_ref(T* ptr, cb_t* cb, increment_ref_count_t) noexcept
|
|
: m_ptr(ptr)
|
|
, m_cb(cb)
|
|
{
|
|
CHECK_NULL;
|
|
CB_LENT_INC_REF();
|
|
}
|
|
lent_ref(T* ptr, cb_t* cb) noexcept
|
|
: m_ptr(ptr)
|
|
, m_cb(cb)
|
|
{
|
|
CHECK_NULL;
|
|
}
|
|
cb_t* get_control_block() const noexcept
|
|
{
|
|
return m_cb;
|
|
}
|
|
cb_t* release_control_block() noexcept
|
|
{
|
|
const auto cb = m_cb;
|
|
m_cb = nullptr;
|
|
return cb;
|
|
}
|
|
#else
|
|
explicit lent_ref(T* ptr) noexcept
|
|
: m_ptr(ptr)
|
|
{
|
|
CHECK_NULL;
|
|
}
|
|
#endif
|
|
public:
|
|
~lent_ref() noexcept
|
|
{
|
|
CB_LENT_DEC_REF();
|
|
}
|
|
lent_ref(const lent_ref<T>& other) noexcept
|
|
: m_ptr(other.m_ptr)
|
|
{
|
|
CHECK_NULL;
|
|
CB_LENT_COPY_CTOR();
|
|
}
|
|
template<typename U> lent_ref(const lent_ref<U>& other) noexcept
|
|
: m_ptr(other.m_ptr)
|
|
{
|
|
CHECK_NULL;
|
|
CB_LENT_COPY_CTOR();
|
|
}
|
|
template<typename U> lent_ref(const unique_ref<U>& other) noexcept
|
|
: m_ptr(other.m_ptr)
|
|
{
|
|
CHECK_NULL;
|
|
CB_LENT_COPY_CTOR();
|
|
}
|
|
|
|
template<typename U> lent_ref(unique_ref<U>&& other) = delete;
|
|
template<typename U> lent_ref& operator = (unique_ref<U>&& other) = delete;
|
|
|
|
lent_ref(lent_ref<T>&& other) noexcept
|
|
: m_ptr(other.m_ptr)
|
|
{
|
|
CHECK_NULL;
|
|
other.m_ptr = nullptr;
|
|
CB_LENT_MOVE_CTOR();
|
|
}
|
|
lent_ref& operator=(const lent_ref<T>& other) noexcept
|
|
{
|
|
if (this == &other) [[unlikely]]
|
|
return *this;
|
|
CB_LENT_COPY_ASSIGN();
|
|
m_ptr = other.m_ptr;
|
|
CHECK_NULL;
|
|
return *this;
|
|
}
|
|
template<typename U> lent_ref& operator=(const lent_ref<U>& other) noexcept
|
|
{
|
|
if (this == &other) [[unlikely]]
|
|
return *this;
|
|
CB_LENT_COPY_ASSIGN();
|
|
m_ptr = other.m_ptr;
|
|
CHECK_NULL;
|
|
return *this;
|
|
}
|
|
template<typename U> lent_ref& operator=(lent_ref<U>&& other) noexcept
|
|
{
|
|
if (this == &other) [[unlikely]]
|
|
return *this;
|
|
CB_LENT_MOVE_ASSIGN();
|
|
m_ptr = other.m_ptr;
|
|
CHECK_NULL;
|
|
other.m_ptr = nullptr;
|
|
return *this;
|
|
}
|
|
constexpr T* get() const noexcept
|
|
{
|
|
CHECK_NULL;
|
|
return m_ptr;
|
|
}
|
|
T& operator*() const noexcept
|
|
{
|
|
CHECK_NULL;
|
|
return *m_ptr;
|
|
}
|
|
T* operator->() const noexcept
|
|
{
|
|
CHECK_NULL;
|
|
return m_ptr;
|
|
}
|
|
|
|
private:
|
|
T* m_ptr = nullptr;
|
|
CB_DECLARE_NULL();
|
|
};
|
|
|
|
template<typename T>
|
|
class lendable
|
|
{
|
|
template<typename U> friend class unique_ref;
|
|
template<typename U> friend class unique_ptr;
|
|
template<typename U> friend class lent_ref;
|
|
template<typename U> friend class lent_ptr;
|
|
|
|
template<typename Ptr, typename SrcPtr, typename U> friend Ptr detail::build_copy(U* t, const SrcPtr& src) noexcept;
|
|
template<typename Ptr, typename SrcPtr, typename U> friend Ptr detail::build_move(U* t, SrcPtr& src) noexcept;
|
|
template<typename Ptr, typename SrcPtr, typename U> friend Ptr detail::build_move_with_deleter(U* t, SrcPtr& src) noexcept;
|
|
|
|
#if CHECKED_PTR == 1
|
|
using cb_t = detail::ptr_control_block;
|
|
cb_t* get_control_block() const noexcept
|
|
{
|
|
return m_cb;
|
|
}
|
|
cb_t* release_control_block() noexcept
|
|
{
|
|
const auto cb = m_cb;
|
|
m_cb = nullptr;
|
|
return cb;
|
|
}
|
|
#endif
|
|
CB_DECLARE_NULL();
|
|
|
|
public:
|
|
template<typename... Args>
|
|
lendable(Args&&... args) noexcept
|
|
: data(std::forward<Args>(args)...)
|
|
{
|
|
CB_ALLOCATE();
|
|
}
|
|
explicit lendable(const T& other) noexcept
|
|
: data(other)
|
|
{
|
|
CB_ALLOCATE();
|
|
}
|
|
explicit lendable(T&& other) noexcept
|
|
: data(std::move(other))
|
|
{
|
|
CB_ALLOCATE();
|
|
}
|
|
~lendable() noexcept = default;
|
|
|
|
template<typename U> lendable(const lendable<U>& other) noexcept
|
|
: data(other.data)
|
|
{
|
|
CB_ALLOCATE();
|
|
}
|
|
template<typename U> lendable& operator=(const lendable<U>& other) noexcept
|
|
{
|
|
data = other.data;
|
|
return *this;
|
|
}
|
|
template<typename U> lendable& operator=(lendable<U>&& other) noexcept
|
|
{
|
|
data = std::move(other.data);
|
|
return *this;
|
|
}
|
|
lendable& operator=(const lendable<T>& other) noexcept
|
|
{
|
|
if (this == &other) [[unlikely]]
|
|
return *this;
|
|
data = other.data;
|
|
return *this;
|
|
}
|
|
lendable& operator=(lendable<T>&& other) noexcept
|
|
{
|
|
data = std::move(other.data);
|
|
return *this;
|
|
}
|
|
|
|
constexpr const T& get() const noexcept
|
|
{
|
|
return data;
|
|
}
|
|
constexpr T& get() noexcept
|
|
{
|
|
return data;
|
|
}
|
|
T& operator*() noexcept
|
|
{
|
|
return data;
|
|
}
|
|
const T& operator*() const noexcept
|
|
{
|
|
return data;
|
|
}
|
|
const T* operator->() const noexcept
|
|
{
|
|
return &data;
|
|
}
|
|
T* operator->() noexcept
|
|
{
|
|
return &data;
|
|
}
|
|
|
|
private:
|
|
T data;
|
|
};
|
|
|
|
// unique - unique
|
|
template<typename T, typename U> constexpr auto operator<=>(const unique_ref<T>& a, const unique_ref<U>& b) noexcept { return a.get() <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const unique_ref<T>& a, const unique_ref<U>& b) noexcept { return a.get() == b.get(); }
|
|
template<typename T, typename U> constexpr auto operator<=>(const unique_ptr<T>& a, const unique_ptr<U>& b) noexcept { return a.get() <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const unique_ptr<T>& a, const unique_ptr<U>& b) noexcept { return a.get() == b.get(); }
|
|
template<typename T, typename U> constexpr auto operator<=>(const unique_ptr<T>& a, const unique_ref<U>& b) noexcept { return a.get() <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const unique_ptr<T>& a, const unique_ref<U>& b) noexcept { return a.get() == b.get(); }
|
|
template<typename T, typename U> constexpr auto operator<=>(const unique_ref<T>& a, const unique_ptr<U>& b) noexcept { return a.get() <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const unique_ref<T>& a, const unique_ptr<U>& b) noexcept { return a.get() == b.get(); }
|
|
|
|
//unique - lent
|
|
template<typename T, typename U> constexpr auto operator<=>(const unique_ref<T>& a, const lent_ref<U>& b) noexcept { return a.get() <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const unique_ref<T>& a, const lent_ref<U>& b) noexcept { return a.get() == b.get(); }
|
|
template<typename T, typename U> constexpr auto operator<=>(const unique_ptr<T>& a, const lent_ptr<U>& b) noexcept { return a.get() <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const unique_ptr<T>& a, const lent_ptr<U>& b) noexcept { return a.get() == b.get(); }
|
|
template<typename T, typename U> constexpr auto operator<=>(const unique_ptr<T>& a, const lent_ref<U>& b) noexcept { return a.get() <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const unique_ptr<T>& a, const lent_ref<U>& b) noexcept { return a.get() == b.get(); }
|
|
template<typename T, typename U> constexpr auto operator<=>(const unique_ref<T>& a, const lent_ptr<U>& b) noexcept { return a.get() <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const unique_ref<T>& a, const lent_ptr<U>& b) noexcept { return a.get() == b.get(); }
|
|
|
|
//lendable - lent
|
|
template<typename T, typename U> constexpr auto operator<=>(const lendable<T>& a, const lent_ref<U>& b) noexcept { return &a.get() <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const lendable<T>& a, const lent_ref<U>& b) noexcept { return &a.get() == b.get(); }
|
|
template<typename T, typename U> constexpr auto operator<=>(const lendable<T>& a, const lent_ptr<U>& b) noexcept { return &a.get() <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const lendable<T>& a, const lent_ptr<U>& b) noexcept { return &a.get() == b.get(); }
|
|
|
|
//unique - raw
|
|
template<typename T, typename U> constexpr auto operator<=>(const unique_ref<T>& a, const U* b) noexcept { return a.get() <=> b; }
|
|
template<typename T, typename U> constexpr bool operator== (const unique_ref<T>& a, const U* b) noexcept { return a.get() == b; }
|
|
template<typename T, typename U> constexpr auto operator<=>(const unique_ptr<T>& a, const U* b) noexcept { return a.get() <=> b; }
|
|
template<typename T, typename U> constexpr bool operator== (const unique_ptr<T>& a, const U* b) noexcept { return a.get() == b; }
|
|
|
|
//unique - nullptr
|
|
template<typename T> constexpr auto operator<=>(const unique_ref<T>& a, std::nullptr_t) noexcept { return a.get() <=> nullptr; }
|
|
template<typename T> constexpr bool operator== (const unique_ref<T>& a, std::nullptr_t) noexcept { return a.get() == nullptr; }
|
|
template<typename T> constexpr auto operator<=>(const unique_ptr<T>& a, std::nullptr_t) noexcept { return a.get() <=> nullptr; }
|
|
template<typename T> constexpr bool operator== (const unique_ptr<T>& a, std::nullptr_t) noexcept { return a.get() == nullptr; }
|
|
|
|
//lent - unique
|
|
template<typename T, typename U> constexpr auto operator<=>(const lent_ref<T>& a, const unique_ref<U>& b) noexcept { return a.get() <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const lent_ref<T>& a, const unique_ref<U>& b) noexcept { return a.get() == b.get(); }
|
|
template<typename T, typename U> constexpr auto operator<=>(const lent_ptr<T>& a, const unique_ptr<U>& b) noexcept { return a.get() <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const lent_ptr<T>& a, const unique_ptr<U>& b) noexcept { return a.get() == b.get(); }
|
|
template<typename T, typename U> constexpr auto operator<=>(const lent_ptr<T>& a, const unique_ref<U>& b) noexcept { return a.get() <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const lent_ptr<T>& a, const unique_ref<U>& b) noexcept { return a.get() == b.get(); }
|
|
template<typename T, typename U> constexpr auto operator<=>(const lent_ref<T>& a, const unique_ptr<U>& b) noexcept { return a.get() <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const lent_ref<T>& a, const unique_ptr<U>& b) noexcept { return a.get() == b.get(); }
|
|
|
|
//raw - unique
|
|
template<typename T, typename U> constexpr auto operator<=>(const T* a, const unique_ref<U>& b) noexcept { return a <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const T* a, const unique_ref<U>& b) noexcept { return a == b.get(); }
|
|
template<typename T, typename U> constexpr auto operator<=>(const T* a, const unique_ptr<U>& b) noexcept { return a <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const T* a, const unique_ptr<U>& b) noexcept { return a == b.get(); }
|
|
|
|
//nullptr - unique
|
|
template<typename T> constexpr auto operator<=>(std::nullptr_t, const unique_ref<T>& b) noexcept { return nullptr <=> b.get(); }
|
|
template<typename T> constexpr bool operator== (std::nullptr_t, const unique_ref<T>& b) noexcept { return nullptr == b.get(); }
|
|
template<typename T> constexpr auto operator<=>(std::nullptr_t, const unique_ptr<T>& b) noexcept { return nullptr <=> b.get(); }
|
|
template<typename T> constexpr bool operator== (std::nullptr_t, const unique_ptr<T>& b) noexcept { return nullptr == b.get(); }
|
|
|
|
//lent - lent
|
|
template<typename T, typename U> constexpr auto operator<=>(const lent_ref<T>& a, const lent_ref<U>& b) noexcept { return a.get() <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const lent_ref<T>& a, const lent_ref<U>& b) noexcept { return a.get() == b.get(); }
|
|
template<typename T, typename U> constexpr auto operator<=>(const lent_ptr<T>& a, const lent_ptr<U>& b) noexcept { return a.get() <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const lent_ptr<T>& a, const lent_ptr<U>& b) noexcept { return a.get() == b.get(); }
|
|
template<typename T, typename U> constexpr auto operator<=>(const lent_ptr<T>& a, const lent_ref<U>& b) noexcept { return a.get() <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const lent_ptr<T>& a, const lent_ref<U>& b) noexcept { return a.get() == b.get(); }
|
|
template<typename T, typename U> constexpr auto operator<=>(const lent_ref<T>& a, const lent_ptr<U>& b) noexcept { return a.get() <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const lent_ref<T>& a, const lent_ptr<U>& b) noexcept { return a.get() == b.get(); }
|
|
|
|
//lent - raw
|
|
template<typename T, typename U> constexpr auto operator<=>(const lent_ref<T>& a, const U* b) noexcept { return a.get() <=> b; }
|
|
template<typename T, typename U> constexpr bool operator== (const lent_ref<T>& a, const U* b) noexcept { return a.get() == b; }
|
|
template<typename T, typename U> constexpr auto operator<=>(const lent_ptr<T>& a, const U* b) noexcept { return a.get() <=> b; }
|
|
template<typename T, typename U> constexpr bool operator== (const lent_ptr<T>& a, const U* b) noexcept { return a.get() == b; }
|
|
|
|
//lent - nullptr
|
|
template<typename T> constexpr auto operator<=>(const lent_ref<T>& a, std::nullptr_t) noexcept { return a.get() <=> nullptr; }
|
|
template<typename T> constexpr bool operator== (const lent_ref<T>& a, std::nullptr_t) noexcept { return a.get() == nullptr; }
|
|
template<typename T> constexpr auto operator<=>(const lent_ptr<T>& a, std::nullptr_t) noexcept { return a.get() <=> nullptr; }
|
|
template<typename T> constexpr bool operator== (const lent_ptr<T>& a, std::nullptr_t) noexcept { return a.get() == nullptr; }
|
|
|
|
//raw - lent
|
|
template<typename T, typename U> constexpr auto operator<=>(const T* a, const lent_ref<U>& b) noexcept { return a <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const T* a, const lent_ref<U>& b) noexcept { return a == b.get(); }
|
|
template<typename T, typename U> constexpr auto operator<=>(const T* a, const lent_ptr<U>& b) noexcept { return a <=> b.get(); }
|
|
template<typename T, typename U> constexpr bool operator== (const T* a, const lent_ptr<U>& b) noexcept { return a == b.get(); }
|
|
|
|
//raw - lent
|
|
template<typename T> constexpr auto operator<=>(std::nullptr_t, const lent_ref<T>& b) noexcept { return nullptr <=> b.get(); }
|
|
template<typename T> constexpr bool operator== (std::nullptr_t, const lent_ref<T>& b) noexcept { return nullptr == b.get(); }
|
|
template<typename T> constexpr auto operator<=>(std::nullptr_t, const lent_ptr<T>& b) noexcept { return nullptr <=> b.get(); }
|
|
template<typename T> constexpr bool operator== (std::nullptr_t, const lent_ptr<T>& b) noexcept { return nullptr == b.get(); }
|
|
|
|
template<typename T>
|
|
class lendable_base
|
|
{
|
|
template<typename Ptr, typename SrcPtr, typename U> friend Ptr detail::build_copy(U* t, const SrcPtr& src) noexcept;
|
|
template<typename Ptr, typename SrcPtr, typename U> friend Ptr detail::build_move(U* t, SrcPtr& src) noexcept;
|
|
template<typename Ptr, typename SrcPtr, typename U> friend Ptr detail::build_move_with_deleter(U* t, SrcPtr& src) noexcept;
|
|
|
|
private:
|
|
#if CHECKED_PTR == 1
|
|
using cb_t = detail::ptr_control_block;
|
|
cb_t* get_control_block() const noexcept
|
|
{
|
|
return m_cb;
|
|
}
|
|
cb_t* release_control_block() noexcept
|
|
{
|
|
const auto cb = m_cb;
|
|
m_cb = nullptr;
|
|
return cb;
|
|
}
|
|
CB_DECLARE_NULL();
|
|
|
|
protected:
|
|
~lendable_base() noexcept
|
|
{
|
|
CB_UNIQUE_DEC_REF();
|
|
}
|
|
|
|
public:
|
|
lendable_base() noexcept
|
|
{
|
|
CB_ALLOCATE();
|
|
}
|
|
lendable_base(const lendable_base&) noexcept
|
|
{
|
|
CB_ALLOCATE();
|
|
}
|
|
lendable_base(lendable_base&&) noexcept
|
|
{
|
|
CB_ALLOCATE();
|
|
}
|
|
lendable_base& operator=(const lendable_base&) noexcept { return *this; }
|
|
lendable_base& operator=(lendable_base&&) noexcept { return *this; }
|
|
#else
|
|
|
|
protected:
|
|
~lendable_base() noexcept = default;
|
|
|
|
public:
|
|
lendable_base() noexcept = default;
|
|
lendable_base(const lendable_base&) noexcept = default;
|
|
lendable_base(lendable_base&&) noexcept = default;
|
|
lendable_base& operator=(const lendable_base&) noexcept = default;
|
|
lendable_base& operator=(lendable_base&&) noexcept = default;
|
|
|
|
#endif
|
|
};
|
|
|
|
|
|
template<typename T, typename... Args>
|
|
unique_ref<T> make_unique(Args&&... args) noexcept { return unique_ref<T>(new T(std::forward<Args>(args)...)); }
|
|
|
|
template<typename T, typename Deleter>
|
|
unique_ref<T> make_unique_del(T* p, Deleter del) noexcept { return unique_ref<T>(p, std::move(del)); }
|
|
|
|
template<typename T>
|
|
lent_ref<T> promote(lent_ptr<T> ptr) noexcept { return detail::build_move<lent_ref<T>>(ptr.get(), ptr); }
|
|
|
|
template<typename T>
|
|
unique_ref<T> promote(unique_ptr<T>&& ptr) noexcept
|
|
{
|
|
if constexpr (ptr_traits<T>::custom_deleter)
|
|
return detail::build_move_with_deleter<unique_ref<T>>(ptr.release(), ptr);
|
|
else
|
|
return detail::build_move<unique_ref<T>>(ptr.release(), ptr);
|
|
}
|
|
|
|
template<typename T>
|
|
unique_ptr<T> demote(unique_ref<T> ptr) noexcept
|
|
{
|
|
if constexpr (ptr_traits<T>::custom_deleter)
|
|
return detail::build_move_with_deleter<unique_ptr<T>>(ptr.release(), ptr);
|
|
else
|
|
return detail::build_move<unique_ptr<T>>(ptr.release(), ptr);
|
|
}
|
|
template<typename T>
|
|
lent_ptr<T> demote(lent_ref<T> ptr) noexcept { return detail::build_move<lent_ptr<T>>(ptr.get(), ptr); }
|
|
template<typename T>
|
|
lent_ptr<T> demote(const lendable<T>& ptr) noexcept { return detail::build_copy<lent_ptr<T>>((T*)&ptr.get(), ptr); }
|
|
template<typename T>
|
|
lent_ptr<T> demote(const lendable_base<T>& ptr) noexcept { return detail::build_copy<lent_ptr<T>>((T*)&ptr, ptr); }
|
|
|
|
|
|
template<typename T>
|
|
lent_ptr<T> lend(const unique_ptr<T>& ptr) noexcept { return detail::build_copy<lent_ptr<T>>(ptr.get(), ptr); }
|
|
template<typename T, typename U>
|
|
lent_ptr<T> lend(const unique_ptr<U>& ptr) noexcept { return detail::build_copy<lent_ptr<T>>(const_cast<T*>(static_cast<const T*>(ptr.get())), ptr); }
|
|
|
|
template<typename T>
|
|
lent_ref<T> lend(const unique_ref<T>& ptr) noexcept { return detail::build_copy<lent_ref<T>>(ptr.get(), ptr); }
|
|
template<typename T, typename U>
|
|
lent_ref<T> lend(const unique_ref<U>& ptr) noexcept { return detail::build_copy<lent_ref<T>>(const_cast<T*>(static_cast<const T*>(ptr.get())), ptr); }
|
|
|
|
template<typename T, typename U>
|
|
lent_ref<T> lend(const lendable_base<U>& ptr) noexcept { return detail::build_copy<lent_ref<T>>(const_cast<T*>(static_cast<const T*>(&ptr)), ptr); }
|
|
|
|
template<typename T, typename U>
|
|
lent_ref<T> lend(const lendable_base<U>* ptr) noexcept { return detail::build_copy<lent_ref<T>>(const_cast<T*>(static_cast<const T*>(ptr)), *ptr); }
|
|
|
|
template<typename T>
|
|
lent_ref<T> lend(const lendable_base<T>& ptr) noexcept { return detail::build_copy<lent_ref<T>>((T*)&ptr, ptr); }
|
|
|
|
template<typename T>
|
|
lent_ref<T> lend(const lendable_base<T>* ptr) noexcept { return detail::build_copy<lent_ref<T>>((T*)ptr, *ptr); }
|
|
|
|
template<typename T>
|
|
lent_ref<T> lend(const lendable<T>& ptr) noexcept { return detail::build_copy<lent_ref<T>>((T*)&ptr.get(), ptr); }
|
|
|
|
template<typename T>
|
|
lent_ref<T> lend(const T* ptr) noexcept { return detail::build_copy<lent_ref<T>>(const_cast<T*>(static_cast<const T*>(ptr)), *ptr); }
|
|
|
|
template<typename T>
|
|
lent_ref<T> promote(const unique_ptr<T>& ptr) noexcept { return detail::build_copy<lent_ref<T>>(ptr.get(), ptr); }
|
|
|
|
|
|
template<typename T, typename U>
|
|
lent_ptr<T> dynamic_lent_cast(lent_ptr<U> ptr) noexcept { return detail::build_move<lent_ptr<T>>(dynamic_cast<T*>(ptr.get()), ptr); }
|
|
|
|
template<typename T, typename U>
|
|
lent_ptr<T> dynamic_lent_cast(lent_ref<U> ptr) noexcept { return detail::build_move<lent_ptr<T>>(dynamic_cast<T*>(ptr.get()), ptr); }
|
|
|
|
template<typename T, typename U>
|
|
lent_ptr<T> dynamic_lent_cast(const unique_ptr<U>& ptr) noexcept { return detail::build_copy<lent_ptr<T>>(dynamic_cast<T*>(ptr.get()), ptr); }
|
|
|
|
template<typename T, typename U>
|
|
lent_ptr<T> dynamic_lent_cast(const unique_ref<U>& ptr) noexcept { return detail::build_copy<lent_ptr<T>>(dynamic_cast<T*>(ptr.get()), ptr); }
|
|
|
|
|
|
template<typename T, typename U>
|
|
lent_ptr<T> static_lent_cast(lent_ptr<U> ptr) noexcept { return detail::build_move<lent_ptr<T>>(static_cast<T*>(ptr.get()), ptr); }
|
|
|
|
template<typename T, typename U>
|
|
lent_ref<T> static_lent_cast(lent_ref<U> ptr) noexcept { return detail::build_move<lent_ref<T>>(static_cast<T*>(ptr.get()), ptr); }
|
|
|
|
template<typename T, typename U>
|
|
lent_ptr<T> static_lent_cast(const unique_ptr<U>& ptr) noexcept { return detail::build_copy<lent_ptr<T>>(static_cast<T*>(ptr.get()), ptr); }
|
|
|
|
template<typename T, typename U>
|
|
lent_ref<T> static_lent_cast(const unique_ref<U>& ptr) noexcept { return detail::build_copy<lent_ref<T>>(static_cast<T*>(ptr.get()), ptr); }
|
|
|
|
|
|
template<typename T, typename U>
|
|
unique_ptr<T> dynamic_unique_cast(unique_ptr<U> ptr) noexcept
|
|
{
|
|
auto* p = ptr.release();
|
|
if (auto* t = dynamic_cast<T*>(p))
|
|
{
|
|
if constexpr (ptr_traits<T>::custom_deleter)
|
|
return detail::build_move_with_deleter<unique_ptr<T>>(t, ptr);
|
|
else
|
|
return detail::build_move<unique_ptr<T>>(t, ptr);
|
|
}
|
|
delete p;
|
|
return nullptr;
|
|
}
|
|
|
|
template<typename T, typename U>
|
|
unique_ptr<T> dynamic_unique_cast(unique_ref<U> ptr) noexcept
|
|
{
|
|
auto* p = ptr.release();
|
|
if (auto* t = dynamic_cast<T*>(p))
|
|
{
|
|
if constexpr (ptr_traits<T>::custom_deleter)
|
|
return detail::build_move_with_deleter<unique_ptr<T>>(t, ptr);
|
|
else
|
|
return detail::build_move<unique_ptr<T>>(t, ptr);
|
|
}
|
|
delete p;
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
template<typename T, typename U>
|
|
lent_ref<T> const_lent_cast(lent_ref<U> ref) noexcept { return detail::build_copy<lent_ref<T>>(const_cast<T*>(ref.get()), ref); }
|
|
|
|
template<typename T, typename U>
|
|
lent_ptr<T> const_lent_cast(lent_ptr<U> ptr) noexcept { return detail::build_copy<lent_ptr<T>>(const_cast<T*>(ptr.get()), ptr); }
|
|
|
|
}
|
|
|
|
namespace std
|
|
{
|
|
template<typename T> struct hash<tl::lent_ref<T>>
|
|
{
|
|
size_t operator()(const tl::lent_ref<T>& ptr) const noexcept
|
|
{
|
|
std::hash<T*> hasher;
|
|
return hasher(ptr.get());
|
|
}
|
|
};
|
|
template<typename T> struct hash<tl::lent_ptr<T>>
|
|
{
|
|
size_t operator()(const tl::lent_ptr<T>& ptr) const noexcept
|
|
{
|
|
std::hash<T*> hasher;
|
|
return hasher(ptr.get());
|
|
}
|
|
};
|
|
template<typename T> struct hash<tl::unique_ref<T>>
|
|
{
|
|
size_t operator()(const tl::unique_ref<T>& ptr) const noexcept
|
|
{
|
|
std::hash<T*> hasher;
|
|
return hasher(ptr.get());
|
|
}
|
|
};
|
|
template<typename T> struct hash<tl::unique_ptr<T>>
|
|
{
|
|
size_t operator()(const tl::unique_ptr<T>& ptr) const noexcept
|
|
{
|
|
std::hash<T*> hasher;
|
|
return hasher(ptr.get());
|
|
}
|
|
};
|
|
}
|
|
namespace eastl
|
|
{
|
|
template<typename T> struct hash<tl::lent_ref<T>>
|
|
{
|
|
size_t operator()(const tl::lent_ref<T>& ptr) const noexcept
|
|
{
|
|
eastl::hash<T*> hasher;
|
|
return hasher(ptr.get());
|
|
}
|
|
};
|
|
template<typename T> struct hash<tl::lent_ptr<T>>
|
|
{
|
|
size_t operator()(const tl::lent_ptr<T>& ptr) const noexcept
|
|
{
|
|
eastl::hash<T*> hasher;
|
|
return hasher(ptr.get());
|
|
}
|
|
};
|
|
template<typename T> struct hash<tl::unique_ref<T>>
|
|
{
|
|
size_t operator()(const tl::unique_ref<T>& ptr) const noexcept
|
|
{
|
|
eastl::hash<T*> hasher;
|
|
return hasher(ptr.get());
|
|
}
|
|
};
|
|
template<typename T> struct hash<tl::unique_ptr<T>>
|
|
{
|
|
size_t operator()(const tl::unique_ptr<T>& ptr) const noexcept
|
|
{
|
|
eastl::hash<T*> hasher;
|
|
return hasher(ptr.get());
|
|
}
|
|
};
|
|
|
|
#undef CHECK_NULL
|
|
|
|
}
|
|
|