68#define CELLPTR_CAST_TO_PTR 1
71#ifndef CELLPTR_COUNT_INSTANCES
72#define CELLPTR_COUNT_INSTANCES 0
76#ifndef CELLPTR_LOG_REFS
77#define CELLPTR_LOG_REFS 0
81#ifndef CELLPTR_LOG_INSTANCES
82#define CELLPTR_LOG_INSTANCES 0
86#ifndef CELLPTR_LOG_METHOD
87#define CELLPTR_LOG_METHOD wxLogDebug
98 class ControlBlock final
103 unsigned int m_refCount = 0;
105 static size_t m_instanceCount;
108 void LogConstruct(
const Observed *)
const;
111 void LogDestruct()
const;
113 static void LogConstruct(
const Observed *) {}
116 static void LogDestruct() {}
120 explicit ControlBlock(
Observed *
object) : m_object(
object)
122#if CELLPTR_COUNT_INSTANCES
125 LogConstruct(
object);
129#if CELLPTR_COUNT_INSTANCES
134 ControlBlock(
const ControlBlock &) =
delete;
135 void operator=(
const ControlBlock &) =
delete;
137 void reset()
noexcept { m_object =
nullptr; }
138 inline Observed *Get()
const noexcept {
return m_object; }
153 wxASSERT(m_refCount >= 1);
157 static size_t GetLiveInstanceCount() {
return m_instanceCount; }
160 static_assert(
alignof(ControlBlock) >= 4,
"Observed::ControlBlock doesn't have minimum viable alignment");
168 class CellPtrImplPointer final
170 friend void swap(CellPtrImplPointer &a, CellPtrImplPointer &b)
noexcept;
171 uintptr_t m_ptr = {};
172 enum Tag : uintptr_t {
177 to_MASK_OUT = uintptr_t(-intptr_t(to_MASK + 1)),
181 static uintptr_t ReprFor(
Observed *ptr)
noexcept
182 {
return reinterpret_cast<uintptr_t
>(ptr) | to_Observed; }
183 static uintptr_t ReprFor(ControlBlock *ptr)
noexcept
184 {
return reinterpret_cast<uintptr_t
>(ptr) | to_ControlBlock; }
185 static uintptr_t ReprFor(
CellPtrBase *ptr)
noexcept
186 {
return reinterpret_cast<uintptr_t
>(ptr) | to_CellPtrBase; }
188 constexpr CellPtrImplPointer()
noexcept {}
189 constexpr CellPtrImplPointer(
const CellPtrImplPointer &)
noexcept =
default;
191 constexpr CellPtrImplPointer(
decltype(
nullptr))
noexcept {}
193 CellPtrImplPointer(
Observed *ptr) noexcept : m_ptr(ReprFor(ptr)) {}
195 CellPtrImplPointer(ControlBlock *ptr) noexcept : m_ptr(ReprFor(ptr)) {}
197 CellPtrImplPointer(
CellPtrBase *ptr) noexcept : m_ptr(ReprFor(ptr)) {}
199 constexpr CellPtrImplPointer &operator=(
decltype(
nullptr))
noexcept { m_ptr = {};
return *
this; }
200 constexpr CellPtrImplPointer &operator=(CellPtrImplPointer o)
noexcept { m_ptr = o.m_ptr;
return *
this; }
201 CellPtrImplPointer &operator=(
Observed *ptr)
noexcept { m_ptr = ReprFor(ptr);
return *
this; }
202 CellPtrImplPointer &operator=(ControlBlock *ptr)
noexcept { m_ptr = ReprFor(ptr);
return *
this; }
203 CellPtrImplPointer &operator=(
CellPtrBase *ptr)
noexcept { m_ptr = ReprFor(ptr);
return *
this; }
205 constexpr explicit inline operator bool()
const noexcept {
return m_ptr != 0; }
206 constexpr inline bool HasObserved()
const noexcept {
return (m_ptr & to_MASK) == to_Observed; }
207 constexpr inline bool HasControlBlock()
const noexcept {
return (m_ptr & to_MASK) == to_ControlBlock; }
208 constexpr inline bool HasCellPtrBase()
const noexcept {
return (m_ptr & to_MASK) == to_CellPtrBase; }
209 constexpr inline auto GetObserved()
const noexcept {
static_assert((to_Observed & to_MASK_OUT) == 0,
"");
210 return HasObserved() ?
reinterpret_cast<Observed *
> (m_ptr) :
nullptr; }
211 constexpr inline auto GetControlBlock()
const noexcept {
return HasControlBlock() ?
reinterpret_cast<ControlBlock *
>(m_ptr & to_MASK_OUT) :
nullptr; }
212 constexpr inline auto GetCellPtrBase()
const noexcept {
return HasCellPtrBase() ?
reinterpret_cast<CellPtrBase *
> (m_ptr & to_MASK_OUT) :
nullptr; }
214 constexpr inline auto GetImpl()
const noexcept {
return m_ptr; }
215 inline auto CastAsObserved()
const noexcept {
return reinterpret_cast<Observed *
>(m_ptr); }
216 inline auto CastAsControlBlock()
const noexcept {
return reinterpret_cast<ControlBlock *
>(m_ptr & to_MASK_OUT); }
219 friend void swap(CellPtrImplPointer &a, CellPtrImplPointer &b)
noexcept;
221 static size_t m_instanceCount;
231 CellPtrImplPointer m_ptr;
234 void operator=(
const Observed &) =
delete;
236 void OnEndOfLife()
const noexcept;
248#if CELLPTR_COUNT_INSTANCES
249 { ++m_instanceCount; }
255 if (m_ptr) OnEndOfLife();
256#if CELLPTR_COUNT_INSTANCES
262 static size_t GetLiveInstanceCount() {
return m_instanceCount; }
263 static size_t GetLiveControlBlockInstanceCount() {
return ControlBlock::GetLiveInstanceCount(); }
264 bool IsNull()
const {
return !m_ptr.GetImpl(); }
265 bool HasControlBlock()
const {
return m_ptr.GetControlBlock(); }
266 bool HasOneCellPtr()
const {
return m_ptr.GetCellPtrBase(); }
269inline void swap(Observed::CellPtrImplPointer &a, Observed::CellPtrImplPointer &b)
noexcept
270{ std::swap(a.m_ptr, b.m_ptr); }
287 using CellPtrImplPointer = Observed::CellPtrImplPointer;
288 using ControlBlock = Observed::ControlBlock;
289 static size_t m_instanceCount;
299 mutable CellPtrImplPointer m_ptr;
305 void Deref()
noexcept;
309 decltype(
nullptr) DerefControlBlock()
const noexcept;
311#if CELLPTR_LOG_INSTANCES
312 void LogConstruction(
Observed *obj)
const;
315 void LogDestruction()
const;
317 static inline void LogConstruction(
Observed *) {}
319 static inline void LogAssignment(
const CellPtrBase &) {}
320 static inline void LogDestruction() {}
326#if CELLPTR_COUNT_INSTANCES
330 LogConstruction(obj);
337#if CELLPTR_COUNT_INSTANCES
343 auto *thisObserved = m_ptr.GetObserved();
346 wxASSERT(thisObserved->m_ptr.GetCellPtrBase() ==
this);
347 thisObserved->LogDeref(
this);
348 thisObserved->LogRef(&o);
349 thisObserved->m_ptr = &o;
352 auto *otherObserved = o.m_ptr.GetObserved();
355 wxASSERT(otherObserved->m_ptr.GetCellPtrBase() == &o);
356 otherObserved->LogDeref(&o);
357 otherObserved->LogRef(
this);
358 otherObserved->m_ptr =
this;
361 swap(m_ptr, o.m_ptr);
366#if CELLPTR_COUNT_INSTANCES
389 auto *thisObserved = m_ptr.GetObserved();
390 auto *otherObserved = o.m_ptr.GetObserved();
393 wxASSERT(thisObserved->m_ptr.GetCellPtrBase() ==
this);
394 thisObserved->LogDeref(
this);
395 thisObserved->LogRef(&o);
396 thisObserved->m_ptr = &o;
400 wxASSERT(otherObserved->m_ptr.GetCellPtrBase() == &o);
401 otherObserved->LogDeref(&o);
402 otherObserved->LogRef(
this);
403 otherObserved->m_ptr =
this;
405 swap(m_ptr, o.m_ptr);
409 inline Observed *base_get()
const noexcept
431 if (m_ptr.HasObserved())
432 return m_ptr.CastAsObserved();
439 auto *
const observed = m_ptr.CastAsControlBlock()->Get();
448 return DerefControlBlock();
457 const auto ia =
reinterpret_cast<uintptr_t
>(a);
458 const auto ib =
reinterpret_cast<uintptr_t
>(b);
459 return (ia > ib) - (ia < ib);
463 template <
typename U>
464 static bool constexpr is_pointer() {
465 return std::is_same<U,
decltype(
nullptr)>::value
466 || (std::is_pointer<U>::value && std::is_convertible<U, Observed*>::value);
469 explicit operator bool() const noexcept {
return base_get(); }
471 inline void reset() noexcept {
base_reset(); }
496 static size_t GetLiveInstanceCount() noexcept {
return m_instanceCount; }
498 bool IsNull()
const {
return !m_ptr.GetImpl(); }
499 bool HasOneObserved()
const {
return m_ptr.GetObserved(); }
500 bool HasControlBlock()
const {
return m_ptr.GetControlBlock(); }
503static_assert(
alignof(
Observed) >= 4,
"Observed doesn't have minimum viable alignment");
504static_assert(
alignof(
CellPtrBase) >= 4,
"CellPtrBase doesn't have minimum viable alignment");
540 template <
typename U>
542 static bool constexpr is_pointer() {
543 return std::is_same<U,
decltype(
nullptr)>::value
544 || (std::is_pointer<U>::value && std::is_convertible<U, pointer>::value);
547 using value_type = T;
549 using const_pointer =
const T*;
550 using reference = T&;
557 inline reference operator*()
const noexcept {
return *get(); }
558 inline pointer operator->()
const noexcept {
return get(); }
560#if CELLPTR_CAST_TO_PTR
561 operator pointer()
const noexcept {
return get(); }
564 template <typename PtrT, typename std::enable_if<std::is_pointer<PtrT>::value,
bool>::type =
true>
565 PtrT CastAs()
const noexcept;
569 explicit CellPtr(
int) =
delete;
570 explicit CellPtr(
void *) =
delete;
576 explicit CellPtr(
decltype(
nullptr))
noexcept {}
578 bool operator==(
decltype(
nullptr))
const noexcept {
return !
static_cast<bool>(*this); }
579 bool operator!=(
decltype(
nullptr))
const noexcept {
return static_cast<bool>(*this); }
583 template <typename U, typename std::enable_if<is_pointer<U>(),
bool>::type =
true>
586 template <typename U, typename std::enable_if<is_pointer<U>(),
bool>::type =
true>
587 CellPtr &operator=(U obj)
noexcept
593 template <typename U, typename std::enable_if<is_pointer<U>(),
bool>::type =
true>
594 void reset(U obj)
noexcept
600 CellPtr &operator=(
const CellPtr &o)
noexcept { CellPtrBase::operator=(o);
return *
this; }
601 CellPtr &operator=(
CellPtr &&o)
noexcept { CellPtrBase::operator=(std::move(o));
return *
this; }
603 template <
typename U,
604 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
608 template <
typename U,
609 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
613 template <
typename U,
614 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
617 CellPtrBase::operator=(o);
620 template <
typename U,
621 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
624 CellPtrBase::operator=(o);
628#if !CELLPTR_CAST_TO_PTR
629 template <
typename U,
630 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
631 bool operator==(
const CellPtr<U> &ptr)
const noexcept {
return cmpControlBlocks(ptr) == 0; }
632 template <
typename U,
633 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
634 bool operator!=(
const CellPtr<U> &ptr)
const noexcept {
return cmpControlBlocks(ptr) != 0; }
635 template <
typename U,
636 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
642 template <
typename U,
typename Del>
643 explicit CellPtr(std::unique_ptr<U, Del> &&) =
delete;
645 template <
typename U,
typename Del,
646 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
647 explicit CellPtr(
const std::unique_ptr<U, Del> &ptr) noexcept :
CellPtrBase(ptr.get()) {}
649 template <
typename U,
typename Del>
650 CellPtr &operator=(std::unique_ptr<U, Del> &&) =
delete;
652 template <
typename U,
typename Del,
653 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
654 CellPtr &operator=(
const std::unique_ptr<U, Del> &o)
noexcept
655 {
return *
this = o.get(); }
660template <
typename T>
typename
672template <typename T, typename U>
675#if !CELLPTR_CAST_TO_PTR
676template <
typename T,
typename U,
677 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
678bool operator==(U left,
const CellPtr<T> &right)
noexcept {
return right.cmpObjects(left) == 0; }
681template <
typename T,
typename U,
682 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
683bool operator==(
const CellPtr<T> &left, U right)
noexcept {
return left.cmpObjects(right) == 0; }
685template <
typename T,
typename U>
686bool operator!=(
const CellPtr<T> &left,
const CellPtr<U> &right)
noexcept {
return left.cmpPointers(right) != 0; }
688#if !CELLPTR_CAST_TO_PTR
689template <
typename T,
typename U,
690 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
691bool operator!=(U left,
const CellPtr<T> &right)
noexcept {
return right.cmpObjects(left) != 0; }
694template <
typename T,
typename U,
695 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
696bool operator!=(
const CellPtr<T> &left, U right)
noexcept {
return left.cmpObjects(right) != 0; }
698template <
typename T,
typename U>
699bool operator<(
const CellPtr<T> &left,
const CellPtr<U> &right)
noexcept {
return left.cmpObjects(right) < 0; }
701#if !CELLPTR_CAST_TO_PTR
702template <
typename T,
typename U,
703 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
704bool operator<(U left,
const CellPtr<T> &right)
noexcept {
return right.cmpObjects(left) > 0; }
707template <
typename T,
typename U,
708 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
709bool operator<(
const CellPtr<T> &left, U right)
noexcept {
return left.cmpObjects(right) < 0; }
715template<
typename Derived,
typename Base>
718 auto d =
static_cast<Derived *
>(p.release());
719 return std::unique_ptr<Derived>(d);
725template<
typename Derived,
typename Base>
728 auto d =
dynamic_cast<Derived *
>(p.get());
731 return std::unique_ptr<Derived>(std::move(d));
std::unique_ptr< Derived > static_unique_ptr_cast(std::unique_ptr< Base > &&p) noexcept
A cast for unique pointers, used to downcast to a derived type iff we're certain the cell is indeed o...
Definition: CellPtr.h:716
std::unique_ptr< Derived > dynamic_unique_ptr_cast(std::unique_ptr< Base > &&p) noexcept
A cast for unique pointers, used to downcast to a derived type in a type-safe manner.
Definition: CellPtr.h:726
An implementation detail for the type-specific templated cell pointers.
Definition: CellPtr.h:286
static int CmpAddresses(const void *a, const void *b) noexcept
A total order over two (possibly unrelated) addresses, usable with < 0 / == 0 / > 0....
Definition: CellPtr.h:456
auto cmpPointers(const CellPtrBase &o) const noexcept
This is exactly like the spaceship operator in C++20.
Definition: CellPtr.h:474
void base_reset(Observed *obj=nullptr) noexcept
Definition: CellPtr.cpp:155
auto cmpObjects(const CellPtrBase &o) const noexcept
This is the spaceship operator acting on pointed-to objects.
Definition: CellPtr.h:487
auto cmpObjects(const Observed *o) const noexcept
This is the spaceship operator acting on pointed-to objects.
Definition: CellPtr.h:492
A weak non-owning pointer that becomes null whenever the observed object is destroyed.
Definition: CellPtr.h:539
The base class all cell types the worksheet can consist of are derived from.
Definition: Cell.h:148
A cell grouping input (and, if there is one, also the output) cell to a foldable item.
Definition: GroupCell.h:88
Objects deriving from this class can be observed by the CellPtr.
Definition: CellPtr.h:97
A class that is inherited from the external class Test.
Definition: tag.cpp:5