59#define CELLPTR_CAST_TO_PTR 1
62#ifndef CELLPTR_COUNT_INSTANCES
63#define CELLPTR_COUNT_INSTANCES 0
67#ifndef CELLPTR_LOG_REFS
68#define CELLPTR_LOG_REFS 0
72#ifndef CELLPTR_LOG_INSTANCES
73#define CELLPTR_LOG_INSTANCES 0
77#ifndef CELLPTR_LOG_METHOD
78#define CELLPTR_LOG_METHOD wxLogDebug
89 class ControlBlock final
94 unsigned int m_refCount = 0;
96 static size_t m_instanceCount;
99 void LogConstruct(
const Observed *)
const;
102 void LogDestruct()
const;
104 static void LogConstruct(
const Observed *) {}
107 static void LogDestruct() {}
111 explicit ControlBlock(
Observed *
object) : m_object(
object)
113#if CELLPTR_COUNT_INSTANCES
116 LogConstruct(
object);
120#if CELLPTR_COUNT_INSTANCES
125 ControlBlock(
const ControlBlock &) =
delete;
126 void operator=(
const ControlBlock &) =
delete;
128 void reset()
noexcept { m_object =
nullptr; }
129 inline Observed *Get()
const noexcept {
return m_object; }
144 wxASSERT(m_refCount >= 1);
148 static size_t GetLiveInstanceCount() {
return m_instanceCount; }
151 static_assert(
alignof(ControlBlock) >= 4,
"Observed::ControlBlock doesn't have minimum viable alignment");
159 class CellPtrImplPointer final
161 friend void swap(CellPtrImplPointer &a, CellPtrImplPointer &b)
noexcept;
162 uintptr_t m_ptr = {};
163 enum Tag : uintptr_t {
168 to_MASK_OUT = uintptr_t(-intptr_t(to_MASK + 1)),
172 static uintptr_t ReprFor(
Observed *ptr)
noexcept
173 {
return reinterpret_cast<uintptr_t
>(ptr) | to_Observed; }
174 static uintptr_t ReprFor(ControlBlock *ptr)
noexcept
175 {
return reinterpret_cast<uintptr_t
>(ptr) | to_ControlBlock; }
176 static uintptr_t ReprFor(
CellPtrBase *ptr)
noexcept
177 {
return reinterpret_cast<uintptr_t
>(ptr) | to_CellPtrBase; }
179 constexpr CellPtrImplPointer()
noexcept {}
180 constexpr CellPtrImplPointer(
const CellPtrImplPointer &)
noexcept =
default;
182 constexpr CellPtrImplPointer(
decltype(
nullptr))
noexcept {}
184 CellPtrImplPointer(
Observed *ptr) noexcept : m_ptr(ReprFor(ptr)) {}
186 CellPtrImplPointer(ControlBlock *ptr) noexcept : m_ptr(ReprFor(ptr)) {}
188 CellPtrImplPointer(
CellPtrBase *ptr) noexcept : m_ptr(ReprFor(ptr)) {}
190 constexpr CellPtrImplPointer &operator=(
decltype(
nullptr))
noexcept { m_ptr = {};
return *
this; }
191 constexpr CellPtrImplPointer &operator=(CellPtrImplPointer o)
noexcept { m_ptr = o.m_ptr;
return *
this; }
192 CellPtrImplPointer &operator=(
Observed *ptr)
noexcept { m_ptr = ReprFor(ptr);
return *
this; }
193 CellPtrImplPointer &operator=(ControlBlock *ptr)
noexcept { m_ptr = ReprFor(ptr);
return *
this; }
194 CellPtrImplPointer &operator=(
CellPtrBase *ptr)
noexcept { m_ptr = ReprFor(ptr);
return *
this; }
196 constexpr explicit inline operator bool()
const noexcept {
return m_ptr != 0; }
197 constexpr inline bool HasObserved()
const noexcept {
return (m_ptr & to_MASK) == to_Observed; }
198 constexpr inline bool HasControlBlock()
const noexcept {
return (m_ptr & to_MASK) == to_ControlBlock; }
199 constexpr inline bool HasCellPtrBase()
const noexcept {
return (m_ptr & to_MASK) == to_CellPtrBase; }
200 constexpr inline auto GetObserved()
const noexcept {
static_assert((to_Observed & to_MASK_OUT) == 0,
"");
201 return HasObserved() ?
reinterpret_cast<Observed *
> (m_ptr) :
nullptr; }
202 constexpr inline auto GetControlBlock()
const noexcept {
return HasControlBlock() ?
reinterpret_cast<ControlBlock *
>(m_ptr & to_MASK_OUT) :
nullptr; }
203 constexpr inline auto GetCellPtrBase()
const noexcept {
return HasCellPtrBase() ?
reinterpret_cast<CellPtrBase *
> (m_ptr & to_MASK_OUT) :
nullptr; }
205 constexpr inline auto GetImpl()
const noexcept {
return m_ptr; }
206 inline auto CastAsObserved()
const noexcept {
return reinterpret_cast<Observed *
>(m_ptr); }
207 inline auto CastAsControlBlock()
const noexcept {
return reinterpret_cast<ControlBlock *
>(m_ptr & to_MASK_OUT); }
210 friend void swap(CellPtrImplPointer &a, CellPtrImplPointer &b)
noexcept;
212 static size_t m_instanceCount;
222 CellPtrImplPointer m_ptr;
225 void operator=(
const Observed &) =
delete;
227 void OnEndOfLife()
const noexcept;
239#if CELLPTR_COUNT_INSTANCES
240 { ++m_instanceCount; }
246 if (m_ptr) OnEndOfLife();
247#if CELLPTR_COUNT_INSTANCES
253 static size_t GetLiveInstanceCount() {
return m_instanceCount; }
254 static size_t GetLiveControlBlockInstanceCount() {
return ControlBlock::GetLiveInstanceCount(); }
255 bool IsNull()
const {
return !m_ptr.GetImpl(); }
256 bool HasControlBlock()
const {
return m_ptr.GetControlBlock(); }
257 bool HasOneCellPtr()
const {
return m_ptr.GetCellPtrBase(); }
260inline void swap(Observed::CellPtrImplPointer &a, Observed::CellPtrImplPointer &b)
noexcept
261{ std::swap(a.m_ptr, b.m_ptr); }
278 using CellPtrImplPointer = Observed::CellPtrImplPointer;
279 using ControlBlock = Observed::ControlBlock;
280 static size_t m_instanceCount;
290 mutable CellPtrImplPointer m_ptr;
296 void Deref()
noexcept;
300 decltype(
nullptr) DerefControlBlock()
const noexcept;
302#if CELLPTR_LOG_INSTANCES
303 void LogConstruction(
Observed *obj)
const;
306 void LogDestruction()
const;
308 static inline void LogConstruction(
Observed *) {}
310 static inline void LogAssignment(
const CellPtrBase &) {}
311 static inline void LogDestruction() {}
317#if CELLPTR_COUNT_INSTANCES
321 LogConstruction(obj);
328#if CELLPTR_COUNT_INSTANCES
334 auto *thisObserved = m_ptr.GetObserved();
337 wxASSERT(thisObserved->m_ptr.GetCellPtrBase() ==
this);
338 thisObserved->LogDeref(
this);
339 thisObserved->LogRef(&o);
340 thisObserved->m_ptr = &o;
343 auto *otherObserved = o.m_ptr.GetObserved();
346 wxASSERT(otherObserved->m_ptr.GetCellPtrBase() == &o);
347 otherObserved->LogDeref(&o);
348 otherObserved->LogRef(
this);
349 otherObserved->m_ptr =
this;
352 swap(m_ptr, o.m_ptr);
357#if CELLPTR_COUNT_INSTANCES
374 swap(m_ptr, o.m_ptr);
378 inline Observed *base_get()
const noexcept
397 if (m_ptr.HasObserved())
398 return m_ptr.CastAsObserved();
405 auto *
const observed = m_ptr.CastAsControlBlock()->Get();
414 return DerefControlBlock();
420 template <
typename U>
421 static bool constexpr is_pointer() {
422 return std::is_same<U,
decltype(
nullptr)>::value
423 || (std::is_pointer<U>::value && std::is_convertible<U, Observed*>::value);
426 explicit operator bool()
const noexcept {
return base_get(); }
428 inline void reset()
noexcept {
base_reset(); }
439 static size_t GetLiveInstanceCount() noexcept {
return m_instanceCount; }
441 bool IsNull()
const {
return !m_ptr.GetImpl(); }
442 bool HasOneObserved()
const {
return m_ptr.GetObserved(); }
443 bool HasControlBlock()
const {
return m_ptr.GetControlBlock(); }
446static_assert(
alignof(
Observed) >= 4,
"Observed doesn't have minimum viable alignment");
447static_assert(
alignof(
CellPtrBase) >= 4,
"CellPtrBase doesn't have minimum viable alignment");
481 template <
typename U>
483 static bool constexpr is_pointer() {
484 return std::is_same<U,
decltype(
nullptr)>::value
485 || (std::is_pointer<U>::value && std::is_convertible<U, pointer>::value);
488 using value_type = T;
490 using const_pointer =
const T*;
491 using reference = T&;
498 inline reference operator*()
const noexcept {
return *get(); }
499 inline pointer operator->()
const noexcept {
return get(); }
501#if CELLPTR_CAST_TO_PTR
502 operator pointer()
const noexcept {
return get(); }
505 template <typename PtrT, typename std::enable_if<std::is_pointer<PtrT>::value,
bool>::type =
true>
506 PtrT CastAs()
const noexcept;
510 explicit CellPtr(
int) =
delete;
511 explicit CellPtr(
void *) =
delete;
517 explicit CellPtr(
decltype(
nullptr))
noexcept {}
519 bool operator==(
decltype(
nullptr))
const noexcept {
return !
static_cast<bool>(*this); }
520 bool operator!=(
decltype(
nullptr))
const noexcept {
return static_cast<bool>(*this); }
524 template <typename U, typename std::enable_if<is_pointer<U>(),
bool>::type =
true>
527 template <typename U, typename std::enable_if<is_pointer<U>(),
bool>::type =
true>
528 CellPtr &operator=(U obj)
noexcept
534 template <typename U, typename std::enable_if<is_pointer<U>(),
bool>::type =
true>
535 void reset(U obj)
noexcept
541 CellPtr &operator=(
const CellPtr &o)
noexcept { CellPtrBase::operator=(o);
return *
this; }
542 CellPtr &operator=(
CellPtr &&o)
noexcept { CellPtrBase::operator=(std::move(o));
return *
this; }
544 template <
typename U,
545 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
549 template <
typename U,
550 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
554 template <
typename U,
555 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
558 CellPtrBase::operator=(o);
561 template <
typename U,
562 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
565 CellPtrBase::operator=(o);
569#if !CELLPTR_CAST_TO_PTR
570 template <
typename U,
571 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
572 bool operator==(
const CellPtr<U> &ptr)
const noexcept {
return cmpControlBlocks(ptr) == 0; }
573 template <
typename U,
574 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
575 bool operator!=(
const CellPtr<U> &ptr)
const noexcept {
return cmpControlBlocks(ptr) != 0; }
576 template <
typename U,
577 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
583 template <
typename U,
typename Del>
584 explicit CellPtr(std::unique_ptr<U, Del> &&) =
delete;
586 template <
typename U,
typename Del,
587 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
588 explicit CellPtr(
const std::unique_ptr<U, Del> &ptr) noexcept :
CellPtrBase(ptr.get()) {}
590 template <
typename U,
typename Del>
591 CellPtr &operator=(std::unique_ptr<U, Del> &&) =
delete;
593 template <
typename U,
typename Del,
594 typename std::enable_if<std::is_convertible<typename std::add_pointer<U>::type,
pointer>::value,
bool>::type =
true>
595 CellPtr &operator=(
const std::unique_ptr<U, Del> &o)
noexcept
596 {
return *
this = o.get(); }
601template <
typename T>
typename
613template <typename T, typename U>
616#if !CELLPTR_CAST_TO_PTR
617template <
typename T,
typename U,
618 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
619bool operator==(U left,
const CellPtr<T> &right)
noexcept {
return right.cmpObjects(left) == 0; }
622template <
typename T,
typename U,
623 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
624bool operator==(
const CellPtr<T> &left, U right)
noexcept {
return left.cmpObjects(right) == 0; }
626template <
typename T,
typename U>
627bool operator!=(
const CellPtr<T> &left,
const CellPtr<U> &right)
noexcept {
return left.cmpPointers(right) != 0; }
629#if !CELLPTR_CAST_TO_PTR
630template <
typename T,
typename U,
631 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
632bool operator!=(U left,
const CellPtr<T> &right)
noexcept {
return right.cmpObjects(left) != 0; }
635template <
typename T,
typename U,
636 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
637bool operator!=(
const CellPtr<T> &left, U right)
noexcept {
return left.cmpObjects(right) != 0; }
639template <
typename T,
typename U>
640bool operator<(
const CellPtr<T> &left,
const CellPtr<U> &right)
noexcept {
return left.cmpObjects(right) < 0; }
642#if !CELLPTR_CAST_TO_PTR
643template <
typename T,
typename U,
644 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
645bool operator<(U left,
const CellPtr<T> &right)
noexcept {
return right.cmpObjects(left) > 0; }
648template <
typename T,
typename U,
649 typename std::enable_if<CellPtrBase::is_pointer<U>(),
bool>::type =
true>
650bool operator<(
const CellPtr<T> &left, U right)
noexcept {
return left.cmpObjects(right) < 0; }
656template<
typename Derived,
typename Base>
659 auto d =
static_cast<Derived *
>(p.release());
660 return std::unique_ptr<Derived>(d);
666template<
typename Derived,
typename Base>
669 auto d =
dynamic_cast<Derived *
>(p.get());
672 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:657
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:667
An implementation detail for the type-specific templated cell pointers.
Definition: CellPtr.h:277
auto cmpPointers(const CellPtrBase &o) const noexcept
This is exactly like the spaceship operator in C++20.
Definition: CellPtr.h:431
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:434
auto cmpObjects(const Observed *o) const noexcept
This is the spaceship operator acting on pointed-to objects.
Definition: CellPtr.h:437
A weak non-owning pointer that becomes null whenever the observed object is destroyed.
Definition: CellPtr.h:480
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:74
Objects deriving from this class can be observed by the CellPtr.
Definition: CellPtr.h:88
A class that is inherited from the external class Test.
Definition: tag.cpp:5