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
383 swap(m_ptr, o.m_ptr);
387 inline Observed *base_get()
const noexcept
406 if (m_ptr.HasObserved())
407 return m_ptr.CastAsObserved();
414 auto *
const observed = m_ptr.CastAsControlBlock()->Get();
423 return DerefControlBlock();
429 template <
typename U>
430 static bool constexpr is_pointer() {
431 return std::is_same<U,
decltype(
nullptr)>::value
432 || (std::is_pointer<U>::value && std::is_convertible<U, Observed*>::value);
435 explicit operator bool()
const noexcept {
return base_get(); }
437 inline void reset()
noexcept {
base_reset(); }
448 static size_t GetLiveInstanceCount() noexcept {
return m_instanceCount; }
450 bool IsNull()
const {
return !m_ptr.GetImpl(); }
451 bool HasOneObserved()
const {
return m_ptr.GetObserved(); }
452 bool HasControlBlock()
const {
return m_ptr.GetControlBlock(); }
455static_assert(
alignof(
Observed) >= 4,
"Observed doesn't have minimum viable alignment");
456static_assert(
alignof(
CellPtrBase) >= 4,
"CellPtrBase doesn't have minimum viable alignment");
490 template <
typename U>
492 static bool constexpr is_pointer() {
493 return std::is_same<U,
decltype(
nullptr)>::value
494 || (std::is_pointer<U>::value && std::is_convertible<U, pointer>::value);
497 using value_type = T;
499 using const_pointer =
const T*;
500 using reference = T&;
507 inline reference operator*()
const noexcept {
return *get(); }
508 inline pointer operator->()
const noexcept {
return get(); }
510#if CELLPTR_CAST_TO_PTR
511 operator pointer()
const noexcept {
return get(); }
514 template <typename PtrT, typename std::enable_if<std::is_pointer<PtrT>::value,
bool>::type =
true>
515 PtrT CastAs()
const noexcept;
519 explicit CellPtr(
int) =
delete;
520 explicit CellPtr(
void *) =
delete;
526 explicit CellPtr(
decltype(
nullptr))
noexcept {}
528 bool operator==(
decltype(
nullptr))
const noexcept {
return !
static_cast<bool>(*this); }
529 bool operator!=(
decltype(
nullptr))
const noexcept {
return static_cast<bool>(*this); }
533 template <typename U, typename std::enable_if<is_pointer<U>(),
bool>::type =
true>
536 template <typename U, typename std::enable_if<is_pointer<U>(),
bool>::type =
true>
537 CellPtr &operator=(U obj)
noexcept
543 template <typename U, typename std::enable_if<is_pointer<U>(),
bool>::type =
true>
544 void reset(U obj)
noexcept
550 CellPtr &operator=(
const CellPtr &o)
noexcept { CellPtrBase::operator=(o);
return *
this; }
551 CellPtr &operator=(
CellPtr &&o)
noexcept { CellPtrBase::operator=(std::move(o));
return *
this; }
553 template <
typename U,
554 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
558 template <
typename U,
559 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
563 template <
typename U,
564 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
567 CellPtrBase::operator=(o);
570 template <
typename U,
571 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
574 CellPtrBase::operator=(o);
578#if !CELLPTR_CAST_TO_PTR
579 template <
typename U,
580 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
581 bool operator==(
const CellPtr<U> &ptr)
const noexcept {
return cmpControlBlocks(ptr) == 0; }
582 template <
typename U,
583 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
584 bool operator!=(
const CellPtr<U> &ptr)
const noexcept {
return cmpControlBlocks(ptr) != 0; }
585 template <
typename U,
586 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
592 template <
typename U,
typename Del>
593 explicit CellPtr(std::unique_ptr<U, Del> &&) =
delete;
595 template <
typename U,
typename Del,
596 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
597 explicit CellPtr(
const std::unique_ptr<U, Del> &ptr) noexcept :
CellPtrBase(ptr.get()) {}
599 template <
typename U,
typename Del>
600 CellPtr &operator=(std::unique_ptr<U, Del> &&) =
delete;
602 template <
typename U,
typename Del,
603 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
604 CellPtr &operator=(
const std::unique_ptr<U, Del> &o)
noexcept
605 {
return *
this = o.get(); }
610template <
typename T>
typename
622template <typename T, typename U>
625#if !CELLPTR_CAST_TO_PTR
626template <
typename T,
typename U,
627 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
628bool operator==(U left,
const CellPtr<T> &right)
noexcept {
return right.cmpObjects(left) == 0; }
631template <
typename T,
typename U,
632 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
633bool operator==(
const CellPtr<T> &left, U right)
noexcept {
return left.cmpObjects(right) == 0; }
635template <
typename T,
typename U>
636bool operator!=(
const CellPtr<T> &left,
const CellPtr<U> &right)
noexcept {
return left.cmpPointers(right) != 0; }
638#if !CELLPTR_CAST_TO_PTR
639template <
typename T,
typename U,
640 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
641bool operator!=(U left,
const CellPtr<T> &right)
noexcept {
return right.cmpObjects(left) != 0; }
644template <
typename T,
typename U,
645 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
646bool operator!=(
const CellPtr<T> &left, U right)
noexcept {
return left.cmpObjects(right) != 0; }
648template <
typename T,
typename U>
649bool operator<(
const CellPtr<T> &left,
const CellPtr<U> &right)
noexcept {
return left.cmpObjects(right) < 0; }
651#if !CELLPTR_CAST_TO_PTR
652template <
typename T,
typename U,
653 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
654bool operator<(U left,
const CellPtr<T> &right)
noexcept {
return right.cmpObjects(left) > 0; }
657template <
typename T,
typename U,
658 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
659bool operator<(
const CellPtr<T> &left, U right)
noexcept {
return left.cmpObjects(right) < 0; }
665template<
typename Derived,
typename Base>
668 auto d =
static_cast<Derived *
>(p.release());
669 return std::unique_ptr<Derived>(d);
675template<
typename Derived,
typename Base>
678 auto d =
dynamic_cast<Derived *
>(p.get());
681 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:666
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:676
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:440
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:443
auto cmpObjects(const Observed *o) const noexcept
This is the spaceship operator acting on pointed-to objects.
Definition: CellPtr.h:446
A weak non-owning pointer that becomes null whenever the observed object is destroyed.
Definition: CellPtr.h:489
The base class all cell types the worksheet can consist of are derived from.
Definition: Cell.h:142
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