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
428 if (m_ptr.HasObserved())
429 return m_ptr.CastAsObserved();
436 auto *
const observed = m_ptr.CastAsControlBlock()->Get();
445 return DerefControlBlock();
451 template <
typename U>
452 static bool constexpr is_pointer() {
453 return std::is_same<U,
decltype(
nullptr)>::value
454 || (std::is_pointer<U>::value && std::is_convertible<U, Observed*>::value);
457 explicit operator bool()
const noexcept {
return base_get(); }
459 inline void reset()
noexcept {
base_reset(); }
470 static size_t GetLiveInstanceCount() noexcept {
return m_instanceCount; }
472 bool IsNull()
const {
return !m_ptr.GetImpl(); }
473 bool HasOneObserved()
const {
return m_ptr.GetObserved(); }
474 bool HasControlBlock()
const {
return m_ptr.GetControlBlock(); }
477static_assert(
alignof(
Observed) >= 4,
"Observed doesn't have minimum viable alignment");
478static_assert(
alignof(
CellPtrBase) >= 4,
"CellPtrBase doesn't have minimum viable alignment");
512 template <
typename U>
514 static bool constexpr is_pointer() {
515 return std::is_same<U,
decltype(
nullptr)>::value
516 || (std::is_pointer<U>::value && std::is_convertible<U, pointer>::value);
519 using value_type = T;
521 using const_pointer =
const T*;
522 using reference = T&;
529 inline reference operator*()
const noexcept {
return *get(); }
530 inline pointer operator->()
const noexcept {
return get(); }
532#if CELLPTR_CAST_TO_PTR
533 operator pointer()
const noexcept {
return get(); }
536 template <typename PtrT, typename std::enable_if<std::is_pointer<PtrT>::value,
bool>::type =
true>
537 PtrT CastAs()
const noexcept;
541 explicit CellPtr(
int) =
delete;
542 explicit CellPtr(
void *) =
delete;
548 explicit CellPtr(
decltype(
nullptr))
noexcept {}
550 bool operator==(
decltype(
nullptr))
const noexcept {
return !
static_cast<bool>(*this); }
551 bool operator!=(
decltype(
nullptr))
const noexcept {
return static_cast<bool>(*this); }
555 template <typename U, typename std::enable_if<is_pointer<U>(),
bool>::type =
true>
558 template <typename U, typename std::enable_if<is_pointer<U>(),
bool>::type =
true>
559 CellPtr &operator=(U obj)
noexcept
565 template <typename U, typename std::enable_if<is_pointer<U>(),
bool>::type =
true>
566 void reset(U obj)
noexcept
572 CellPtr &operator=(
const CellPtr &o)
noexcept { CellPtrBase::operator=(o);
return *
this; }
573 CellPtr &operator=(
CellPtr &&o)
noexcept { CellPtrBase::operator=(std::move(o));
return *
this; }
575 template <
typename U,
576 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
580 template <
typename U,
581 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
585 template <
typename U,
586 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
589 CellPtrBase::operator=(o);
592 template <
typename U,
593 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
596 CellPtrBase::operator=(o);
600#if !CELLPTR_CAST_TO_PTR
601 template <
typename U,
602 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
603 bool operator==(
const CellPtr<U> &ptr)
const noexcept {
return cmpControlBlocks(ptr) == 0; }
604 template <
typename U,
605 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
606 bool operator!=(
const CellPtr<U> &ptr)
const noexcept {
return cmpControlBlocks(ptr) != 0; }
607 template <
typename U,
608 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
614 template <
typename U,
typename Del>
615 explicit CellPtr(std::unique_ptr<U, Del> &&) =
delete;
617 template <
typename U,
typename Del,
618 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
619 explicit CellPtr(
const std::unique_ptr<U, Del> &ptr) noexcept :
CellPtrBase(ptr.get()) {}
621 template <
typename U,
typename Del>
622 CellPtr &operator=(std::unique_ptr<U, Del> &&) =
delete;
624 template <
typename U,
typename Del,
625 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
626 CellPtr &operator=(
const std::unique_ptr<U, Del> &o)
noexcept
627 {
return *
this = o.get(); }
632template <
typename T>
typename
644template <typename T, typename U>
647#if !CELLPTR_CAST_TO_PTR
648template <
typename T,
typename U,
649 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
650bool operator==(U left,
const CellPtr<T> &right)
noexcept {
return right.cmpObjects(left) == 0; }
653template <
typename T,
typename U,
654 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
655bool operator==(
const CellPtr<T> &left, U right)
noexcept {
return left.cmpObjects(right) == 0; }
657template <
typename T,
typename U>
658bool operator!=(
const CellPtr<T> &left,
const CellPtr<U> &right)
noexcept {
return left.cmpPointers(right) != 0; }
660#if !CELLPTR_CAST_TO_PTR
661template <
typename T,
typename U,
662 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
663bool operator!=(U left,
const CellPtr<T> &right)
noexcept {
return right.cmpObjects(left) != 0; }
666template <
typename T,
typename U,
667 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
668bool operator!=(
const CellPtr<T> &left, U right)
noexcept {
return left.cmpObjects(right) != 0; }
670template <
typename T,
typename U>
671bool operator<(
const CellPtr<T> &left,
const CellPtr<U> &right)
noexcept {
return left.cmpObjects(right) < 0; }
673#if !CELLPTR_CAST_TO_PTR
674template <
typename T,
typename U,
675 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
676bool operator<(U left,
const CellPtr<T> &right)
noexcept {
return right.cmpObjects(left) > 0; }
679template <
typename T,
typename U,
680 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
681bool operator<(
const CellPtr<T> &left, U right)
noexcept {
return left.cmpObjects(right) < 0; }
687template<
typename Derived,
typename Base>
690 auto d =
static_cast<Derived *
>(p.release());
691 return std::unique_ptr<Derived>(d);
697template<
typename Derived,
typename Base>
700 auto d =
dynamic_cast<Derived *
>(p.get());
703 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:688
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:698
An implementation detail for the type-specific templated cell pointers.
Definition: CellPtr.h:286
auto cmpPointers(const CellPtrBase &o) const noexcept
This is exactly like the spaceship operator in C++20.
Definition: CellPtr.h:462
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:465
auto cmpObjects(const Observed *o) const noexcept
This is the spaceship operator acting on pointed-to objects.
Definition: CellPtr.h:468
A weak non-owning pointer that becomes null whenever the observed object is destroyed.
Definition: CellPtr.h:511
The base class all cell types the worksheet can consist of are derived from.
Definition: Cell.h:141
A cell grouping input (and, if there is one, also the output) cell to a foldable item.
Definition: GroupCell.h:87
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