55 #include <type_traits>
58 #define CELLPTR_CAST_TO_PTR 1
61 #ifndef CELLPTR_COUNT_INSTANCES
62 #define CELLPTR_COUNT_INSTANCES 0
66 #ifndef CELLPTR_LOG_REFS
67 #define CELLPTR_LOG_REFS 0
71 #ifndef CELLPTR_LOG_INSTANCES
72 #define CELLPTR_LOG_INSTANCES 0
76 #ifndef CELLPTR_LOG_METHOD
77 #define CELLPTR_LOG_METHOD wxLogDebug
88 class ControlBlock final
93 unsigned int m_refCount = 0;
95 static size_t m_instanceCount;
98 void LogConstruct(
const Observed *)
const;
101 void LogDestruct()
const;
103 void LogConstruct(
const Observed *)
const {}
106 void LogDestruct()
const {}
110 explicit ControlBlock(
Observed *
object) : m_object(
object)
112 #if CELLPTR_COUNT_INSTANCES
115 LogConstruct(
object);
119 #if CELLPTR_COUNT_INSTANCES
124 ControlBlock(
const ControlBlock &) =
delete;
125 void operator=(
const ControlBlock &) =
delete;
127 void reset() noexcept { m_object =
nullptr; }
128 inline Observed *Get()
const noexcept {
return m_object; }
143 wxASSERT(m_refCount >= 1);
147 static size_t GetLiveInstanceCount() {
return m_instanceCount; }
150 static_assert(
alignof(ControlBlock) >= 4,
"Observed::ControlBlock doesn't have minimum viable alignment");
158 class CellPtrImplPointer final
160 friend void swap(CellPtrImplPointer &a, CellPtrImplPointer &b) noexcept;
161 uintptr_t m_ptr = {};
162 enum Tag : uintptr_t {
167 to_MASK_OUT = uintptr_t(-intptr_t(to_MASK + 1)),
169 static uintptr_t ReprFor(
Observed *ptr) noexcept
170 {
return reinterpret_cast<uintptr_t
>(ptr) | to_Observed; }
171 static uintptr_t ReprFor(ControlBlock *ptr) noexcept
172 {
return reinterpret_cast<uintptr_t
>(ptr) | to_ControlBlock; }
173 static uintptr_t ReprFor(
CellPtrBase *ptr) noexcept
174 {
return reinterpret_cast<uintptr_t
>(ptr) | to_CellPtrBase; }
176 constexpr CellPtrImplPointer() noexcept {}
177 constexpr CellPtrImplPointer(
const CellPtrImplPointer &) noexcept =
default;
179 constexpr CellPtrImplPointer(decltype(
nullptr)) noexcept {}
181 CellPtrImplPointer(
Observed *ptr) noexcept : m_ptr(ReprFor(ptr)) {}
183 CellPtrImplPointer(ControlBlock *ptr) noexcept : m_ptr(ReprFor(ptr)) {}
185 CellPtrImplPointer(
CellPtrBase *ptr) noexcept : m_ptr(ReprFor(ptr)) {}
187 constexpr CellPtrImplPointer &operator=(decltype(
nullptr)) noexcept { m_ptr = {};
return *
this; }
188 constexpr CellPtrImplPointer &operator=(CellPtrImplPointer o) noexcept { m_ptr = o.m_ptr;
return *
this; }
189 CellPtrImplPointer &operator=(
Observed *ptr) noexcept { m_ptr = ReprFor(ptr);
return *
this; }
190 CellPtrImplPointer &operator=(ControlBlock *ptr) noexcept { m_ptr = ReprFor(ptr);
return *
this; }
191 CellPtrImplPointer &operator=(
CellPtrBase *ptr) noexcept { m_ptr = ReprFor(ptr);
return *
this; }
193 constexpr
explicit inline operator bool()
const noexcept {
return m_ptr != 0; }
194 constexpr
inline bool HasObserved()
const noexcept {
return (m_ptr & to_MASK) == to_Observed; }
195 constexpr
inline bool HasControlBlock()
const noexcept {
return (m_ptr & to_MASK) == to_ControlBlock; }
196 constexpr
inline bool HasCellPtrBase()
const noexcept {
return (m_ptr & to_MASK) == to_CellPtrBase; }
197 constexpr
inline auto GetObserved()
const noexcept { static_assert((to_Observed & to_MASK_OUT) == 0,
"");
198 return HasObserved() ?
reinterpret_cast<Observed *
> (m_ptr) :
nullptr; }
199 constexpr
inline auto GetControlBlock()
const noexcept {
return HasControlBlock() ?
reinterpret_cast<ControlBlock *
>(m_ptr & to_MASK_OUT) :
nullptr; }
200 constexpr
inline auto GetCellPtrBase()
const noexcept {
return HasCellPtrBase() ?
reinterpret_cast<CellPtrBase *
> (m_ptr & to_MASK_OUT) :
nullptr; }
202 constexpr
inline auto GetImpl()
const noexcept {
return m_ptr; }
203 inline auto CastAsObserved()
const noexcept {
return reinterpret_cast<Observed *
>(m_ptr); }
204 inline auto CastAsControlBlock()
const noexcept {
return reinterpret_cast<ControlBlock *
>(m_ptr & to_MASK_OUT); }
207 friend void swap(CellPtrImplPointer &a, CellPtrImplPointer &b) noexcept;
209 static size_t m_instanceCount;
219 CellPtrImplPointer m_ptr;
222 void operator=(
const Observed &) =
delete;
224 void OnEndOfLife() noexcept;
236 #if CELLPTR_COUNT_INSTANCES
237 { ++ m_instanceCount; }
243 if (m_ptr) OnEndOfLife();
244 #if CELLPTR_COUNT_INSTANCES
250 static size_t GetLiveInstanceCount() {
return m_instanceCount; }
251 static size_t GetLiveControlBlockInstanceCount() {
return ControlBlock::GetLiveInstanceCount(); }
252 bool IsNull()
const {
return !m_ptr.GetImpl(); }
253 bool HasControlBlock()
const {
return m_ptr.GetControlBlock(); }
254 bool HasOneCellPtr()
const {
return m_ptr.GetCellPtrBase(); }
257 inline void swap(Observed::CellPtrImplPointer &a, Observed::CellPtrImplPointer &b) noexcept
258 { std::swap(a.m_ptr, b.m_ptr); }
274 using CellPtrImplPointer = Observed::CellPtrImplPointer;
275 using ControlBlock = Observed::ControlBlock;
276 static size_t m_instanceCount;
286 mutable CellPtrImplPointer m_ptr;
292 void Deref() noexcept;
296 decltype(
nullptr) DerefControlBlock()
const noexcept;
298 #if CELLPTR_LOG_INSTANCES
299 void LogConstruction(
Observed *obj)
const;
302 void LogDestruction()
const;
304 inline void LogConstruction(
Observed *)
const {}
306 inline void LogAssignment(
const CellPtrBase &)
const {}
307 inline void LogDestruction()
const {}
313 #if CELLPTR_COUNT_INSTANCES
317 LogConstruction(obj);
324 #if CELLPTR_COUNT_INSTANCES
330 auto *thisObserved = m_ptr.GetObserved();
333 wxASSERT(thisObserved->m_ptr.GetCellPtrBase() ==
this);
334 thisObserved->LogDeref(
this);
335 thisObserved->LogRef(&o);
336 thisObserved->m_ptr = &o;
339 auto *otherObserved = o.m_ptr.GetObserved();
342 wxASSERT(otherObserved->m_ptr.GetCellPtrBase() == &o);
343 otherObserved->LogDeref(&o);
344 otherObserved->LogRef(
this);
345 otherObserved->m_ptr =
this;
348 swap(m_ptr, o.m_ptr);
353 #if CELLPTR_COUNT_INSTANCES
370 swap(m_ptr, o.m_ptr);
374 inline Observed *base_get()
const noexcept
393 if (m_ptr.HasObserved())
394 return m_ptr.CastAsObserved();
401 auto *
const observed = m_ptr.CastAsControlBlock()->Get();
410 return DerefControlBlock();
416 template <
typename U>
417 static bool constexpr is_pointer() {
418 return std::is_same<U, decltype(
nullptr)>::value
419 || (std::is_pointer<U>::value && std::is_convertible<U, Observed*>::value);
422 explicit operator bool()
const noexcept {
return base_get(); }
424 inline void reset() noexcept {
base_reset(); }
435 static size_t GetLiveInstanceCount() noexcept {
return m_instanceCount; }
437 bool IsNull()
const {
return !m_ptr.GetImpl(); }
438 bool HasOneObserved()
const {
return m_ptr.GetObserved(); }
439 bool HasControlBlock()
const {
return m_ptr.GetControlBlock(); }
442 static_assert(
alignof(
Observed) >= 4,
"Observed doesn't have minimum viable alignment");
443 static_assert(
alignof(
CellPtrBase) >= 4,
"CellPtrBase doesn't have minimum viable alignment");
474 template <
typename T>
477 template <
typename U>
478 static bool constexpr is_pointer() {
479 return std::is_same<U, decltype(
nullptr)>::value
480 || (std::is_pointer<U>::value && std::is_convertible<U, pointer>::value);
483 using value_type = T;
485 using const_pointer =
const T*;
486 using reference = T&;
493 inline reference operator*()
const noexcept {
return *get(); }
494 inline pointer operator->()
const noexcept {
return get(); }
496 #if CELLPTR_CAST_TO_PTR
497 operator pointer()
const noexcept {
return get(); }
500 template <typename PtrT, typename std::enable_if<std::is_pointer<PtrT>::value,
bool>::type =
true>
501 PtrT CastAs()
const noexcept;
505 explicit CellPtr(
int) =
delete;
506 explicit CellPtr(
void *) =
delete;
511 explicit CellPtr(decltype(
nullptr)) noexcept {}
513 bool operator==(decltype(
nullptr))
const noexcept {
return !bool(*
this); }
514 bool operator!=(decltype(
nullptr))
const noexcept {
return bool(*
this); }
518 template <typename U, typename std::enable_if<is_pointer<U>(),
bool>::type =
true>
521 template <typename U, typename std::enable_if<is_pointer<U>(),
bool>::type =
true>
522 CellPtr &operator=(U obj) noexcept
528 template <typename U, typename std::enable_if<is_pointer<U>(),
bool>::type =
true>
529 void reset(U obj) noexcept
535 CellPtr &operator=(
const CellPtr &o) noexcept { CellPtrBase::operator=(o);
return *
this; }
536 CellPtr &operator=(
CellPtr &&o) noexcept { CellPtrBase::operator=(std::move(o));
return *
this; }
538 template <
typename U,
539 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
543 template <
typename U,
544 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
548 template <
typename U,
549 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
552 CellPtrBase::operator=(o);
555 template <
typename U,
556 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
559 CellPtrBase::operator=(o);
563 #if !CELLPTR_CAST_TO_PTR
564 template <
typename U,
565 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
566 bool operator==(
const CellPtr<U> &ptr)
const noexcept {
return cmpControlBlocks(ptr) == 0; }
567 template <
typename U,
568 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
569 bool operator!=(
const CellPtr<U> &ptr)
const noexcept {
return cmpControlBlocks(ptr) != 0; }
570 template <
typename U,
571 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
577 template <
typename U,
typename Del>
578 explicit CellPtr(std::unique_ptr<U, Del> &&) =
delete;
580 template <
typename U,
typename Del,
581 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
582 explicit CellPtr(
const std::unique_ptr<U, Del> &ptr) noexcept :
CellPtrBase(ptr.get()) {}
584 template <
typename U,
typename Del>
585 CellPtr &operator=(std::unique_ptr<U, Del> &&) =
delete;
587 template <
typename U,
typename Del,
588 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
589 CellPtr &operator=(
const std::unique_ptr<U, Del> &o) noexcept
590 {
return *
this = o.get(); }
595 template <
typename T>
typename
607 template <typename T, typename U>
610 #if !CELLPTR_CAST_TO_PTR
611 template <
typename T,
typename U,
612 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
613 bool operator==(U left,
const CellPtr<T> &right) noexcept {
return right.cmpObjects(left) == 0; }
616 template <
typename T,
typename U,
617 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
618 bool operator==(
const CellPtr<T> &left, U right) noexcept {
return left.cmpObjects(right) == 0; }
620 template <
typename T,
typename U>
621 bool operator!=(
const CellPtr<T> &left,
const CellPtr<U> &right) noexcept {
return left.cmpPointers(right) != 0; }
623 #if !CELLPTR_CAST_TO_PTR
624 template <
typename T,
typename U,
625 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
626 bool operator!=(U left,
const CellPtr<T> &right) noexcept {
return right.cmpObjects(left) != 0; }
629 template <
typename T,
typename U,
630 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
631 bool operator!=(
const CellPtr<T> &left, U right) noexcept {
return left.cmpObjects(right) != 0; }
633 template <
typename T,
typename U>
634 bool operator<(
const CellPtr<T> &left,
const CellPtr<U> &right) noexcept {
return left.cmpObjects(right) < 0; }
636 #if !CELLPTR_CAST_TO_PTR
637 template <
typename T,
typename U,
638 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
639 bool operator<(U left,
const CellPtr<T> &right) noexcept {
return right.cmpObjects(left) > 0; }
642 template <
typename T,
typename U,
643 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
644 bool operator<(
const CellPtr<T> &left, U right) noexcept {
return left.cmpObjects(right) < 0; }
650 template<
typename Derived,
typename Base>
653 auto d =
static_cast<Derived *
>(p.release());
654 return std::unique_ptr<Derived>(d);
660 template<
typename Derived,
typename Base>
663 auto d =
dynamic_cast<Derived *
>(p.get());
666 return std::unique_ptr<Derived>(d);