CeresEngine 0.2.0
A game development framework
Loading...
Searching...
No Matches
SmartPtr.hpp
Go to the documentation of this file.
1//
2// CeresEngine - A game development framework
3//
4// Created by Rogiel Sulzbach.
5// Copyright (c) 2018-2022 Rogiel Sulzbach. All rights reserved.
6//
7
8#pragma once
9
12
15
16#include <atomic>
17#include <memory>
18#include <type_traits>
19#ifndef NDEBUG
20#include <cstring>
21#endif
22
23namespace CeresEngine {
24
28 template<typename T, typename Deleter = std::default_delete<T>> using UPtr = std::unique_ptr<T, Deleter>;
29
37 template<typename T> using SPtr = std::shared_ptr<T>;
38
42 template<typename T> using WPtr = std::weak_ptr<T>;
43
44 // ---------------------------------------------------------------------------------------------
45
46 template<typename T, typename... Args> [[nodiscard]] inline constexpr T* ce_new(Args&&... args) { // NOLINT
47 return new T(std::forward<Args>(args)...);
48 }
49
50 template<typename T, typename... Args> [[nodiscard]] inline constexpr UPtr<T> ce_unique_new(Args&&... args) { // NOLINT
51 return std::make_unique<T>(std::forward<Args>(args)...);
52 }
53
54 template<typename T, typename RawAllocator, typename... Args>
55 [[nodiscard]] inline constexpr UPtr<T, AllocatorDeleter<T, RawAllocator>> ce_unique_alloc(RawAllocator& allocator, Args&&... args) { // NOLINT
57
58 // RawPtr deallocates memory in case of constructor exception
59 void* const memory = allocator.allocate_node(sizeof(T), alignof(T));
60 PtrGuard result(static_cast<T*>(memory), {allocator});
61
62 // Call constructor
63 ::new(memory) T(std::forward<Args>(args)...);
64
65 // Pass ownership to return value using a deleter that calls destructor
66 return {result.release(), {allocator}};
67 }
68
69 template<typename T, typename... Args> [[nodiscard]] inline constexpr SPtr<T> ce_shared_new(Args&&... args) { // NOLINT
70 return std::make_shared<T>(std::forward<Args>(args)...);
71 }
72
73 template<typename T, typename Allocator, typename... Args>
74 [[nodiscard]] inline constexpr SPtr<T> ce_shared_alloc(Allocator& allocator,
75 Args&&... args) { // NOLINT
76 return std::allocate_shared<T>(make_std_allocator(make_allocator_reference(allocator)), std::forward<Args>(args)...);
77 }
78
79 // ---------------------------------------------------------------------------------------------
80 // ---------------------------------------------------------------------------------------------
81
82 template<bool ThreadSafe> class RefCounter;
83
90 template<typename T, typename Counter = RefCounter<true>, typename Deleter = std::default_delete<T>> class RefCounted;
91
95 template<typename T, bool = true> struct CountedPtrTrait;
96
99 static const constexpr struct AdoptPtrT {
100 } adoptPtr;
101
103 // and `release` pair of methods.
105 template<typename T>
106 concept IntrusiveReferenceCountable = requires(T* ptr) {
107 ptr->retain();
108 ptr->release();
109 };
110
114 template<typename T>
115 concept ReferenceCountable = requires(T* ptr) {
116 CountedPtrTrait<T>::retain(ptr);
117 CountedPtrTrait<T>::release(ptr);
118 };
119
132 template<typename T> class CountedPtr final {
133 template<typename TT> friend class CountedPtr;
134
137
138 public:
140 using ElementType = T;
141
143 using Pointer = T*;
144
146 using Reference = T&;
147
148 private:
150 Pointer ptr = nullptr;
151
152 public:
155
159
161 CountedPtr(std::nullptr_t) noexcept { set(nullptr); }
162
165 CountedPtr(AdoptPtrT, const Pointer aPtr) noexcept : ptr(aPtr) {}
166
169 CountedPtr(const CountedPtr& other) noexcept : CountedPtr(other.ptr) {}
170
173 template<typename U> CountedPtr(const CountedPtr<U>& other) noexcept : CountedPtr(other.ptr) {}
174
178 CountedPtr& operator=(const CountedPtr& other) noexcept { // NOLINT(cert-oop54-cpp)
179 set(other.ptr);
180 return *this;
181 }
182
186 template<typename U> CountedPtr& operator=(const CountedPtr<U>& other) noexcept {
187 set(other.ptr);
188 return *this;
189 }
190
193 CountedPtr(CountedPtr&& other) noexcept : ptr(std::exchange(other.ptr, nullptr)) { }
194
197 template<typename U> CountedPtr(CountedPtr<U>&& other) noexcept : ptr(std::exchange(other.ptr, nullptr)) { // NOLINT
198 }
199
203 CountedPtr& operator=(CountedPtr&& other) noexcept {
204 if(other.ptr == ptr) {
205 return *this;
206 }
207
208 reset();
209 ptr = std::exchange(other.ptr, nullptr);
210 return *this;
211 }
212
216 template<typename U> CountedPtr& operator=(CountedPtr<U>&& other) noexcept {
217 if(other.ptr == ptr) {
218 return *this;
219 }
220
221 reset();
222 ptr = std::exchange(other.ptr, nullptr);
223
224 return *this;
225 }
226
230 template<typename U> CountedPtr& operator=(U* aPtr) noexcept {
231 if(aPtr == ptr) {
232 return *this;
233 }
234
235 set(aPtr);
236 return *this;
237 }
238
241
242 public:
245
248
251
254 [[nodiscard]] explicit operator bool() const noexcept { return ptr != nullptr; }
255
257 void reset() noexcept { set(nullptr); }
258
263 // NOTE: no ref count decrement
264 return std::exchange(ptr, nullptr);
265 }
266
267 public:
269 static CountedPtr<T> adopt(T* const ptr) { return {adoptPtr, ptr}; }
270
271 private:
274 void set(Pointer newPtr) noexcept {
275 if(newPtr == ptr) {
276 return;
277 }
278
279 if(ptr) {
280 Trait::release(ptr);
281 }
282
283 ptr = newPtr;
284 if(ptr) {
285 Trait::retain(ptr);
286 }
287 }
288
289 public:
293
294 public:
301 template<typename U1, typename U2> friend inline bool operator==(const CountedPtr<U1>& a, const CountedPtr<U2>& b) noexcept;
302
309 template<typename U1, typename U2> friend inline bool operator!=(const CountedPtr<U1>& a, const CountedPtr<U2>& b) noexcept;
310
317 template<typename U1, typename U2> friend inline bool operator==(const CountedPtr<U1>& a, const U2* b) noexcept;
318
325 template<typename U1, typename U2> friend inline bool operator!=(const CountedPtr<U1>& a, const U2* b) noexcept;
326
333 template<typename U1, typename U2> friend inline bool operator==(const U1* a, const CountedPtr<U2>& b) noexcept;
334
341 template<typename U1, typename U2> friend inline bool operator!=(const U1* a, const CountedPtr<U2>& b) noexcept;
342
347 template<typename U> friend inline bool operator==(const CountedPtr<U>& a, std::nullptr_t) noexcept;
348
353 template<typename U> friend inline bool operator!=(const CountedPtr<U>& a, std::nullptr_t) noexcept;
354 };
355
356 // additional deduction guide
357 template<typename Pointer> CountedPtr(Pointer) -> CountedPtr<Pointer>;
358
363 template<typename T> using RC = CountedPtr<T>;
364
365 template<IntrusiveReferenceCountable T> struct CountedPtrTrait<T> {
368 static void retain(T* ptr) noexcept { ptr->retain(); }
369
372 static void release(T* ptr) noexcept { ptr->release(); }
373 };
374
375#define CE_RCPTR_TRAIT_DECL(ClassName) \
376 template<> struct CeresEngine::CountedPtrTrait<ClassName> { \
377 static void retain(ClassName* ptr) noexcept; \
378 static void release(ClassName* ptr) noexcept; \
379 };
380
381#define CE_RCPTR_TRAIT_DEF(ClassName) \
382 void ::CeresEngine::CountedPtrTrait<ClassName>::retain(ClassName* ptr) noexcept { ptr->retain(); } \
383 void ::CeresEngine::CountedPtrTrait<ClassName>::release(ClassName* ptr) noexcept { ptr->release(); }
384
385 // ---------------------------------------------------------------------------------------------
386
387 template<ReferenceCountable T> RC<T> ce_counted_adopt(T* const ptr) { // NOLINT
388 return RC<T>::adopt(ptr);
389 }
390
391 template<ReferenceCountable T, typename... Args> RC<T> ce_counted_new(Args&&... args) { // NOLINT
392 return new T(std::forward<Args>(args)...);
393 }
394
395 // ---------------------------------------------------------------------------------------------
396
398 template<bool ThreadSafe = true> class RefCounter;
399
402 template<> class RefCounter<true> final {
404 Atomic<UInt64> mCounter = 0;
405
406 public:
407 RefCounter() = default;
408 explicit RefCounter(const UInt64 initialCount) : mCounter(initialCount) {}
409
410 public:
413
416 [[nodiscard]] bool decrement() noexcept;
417 };
418
423 UInt64 mCounter = 0;
424
425 public:
426 RefCounter() = default;
427 explicit RefCounter(const UInt64 initialCount) : mCounter(initialCount) {}
428
429 public:
432
435 [[nodiscard]] bool decrement() noexcept;
436 };
437
441
443 Deleter mDeleter;
444
445 public:
450 template<typename... Args> explicit RefCounted(Args&&... args) : mDeleter(std::forward<Args>(args)...){};
451
452 public:
454 void retain() noexcept { mRefCounter.increment(); }
455
459 if(mRefCounter.decrement()) {
460 mDeleter(static_cast<T*>(this));
461 return true;
462 }
463 return false;
464 }
465 };
466
471 template<typename T, typename Counter> class RefCounted<T, Counter, std::default_delete<T>> {
473 using Deleter = std::default_delete<T>;
474
476 Counter mRefCounter;
477
478 public:
480 void retain() noexcept { mRefCounter.increment(); }
481
484 bool release() noexcept {
485 if(mRefCounter.decrement()) {
486 Deleter{}(static_cast<T*>(this));
487 return true;
488 }
489 return false;
490 }
491 };
492
493 // ---------------------------------------------------------------------------------------------
494
495 template<typename U1, typename U2> inline bool operator==(const CountedPtr<U1>& a, const CountedPtr<U2>& b) noexcept { return a.ptr == b.ptr; }
496 template<typename U1, typename U2> inline bool operator!=(const CountedPtr<U1>& a, const CountedPtr<U2>& b) noexcept { return a.ptr != b.ptr; }
497 template<typename U1, typename U2> inline bool operator==(const CountedPtr<U1>& a, const U2* b) noexcept { return a.ptr == b; }
498 template<typename U1, typename U2> inline bool operator!=(const CountedPtr<U1>& a, const U2* b) noexcept { return a.ptr != b; }
499 template<typename U1, typename U2> inline bool operator==(const U1* a, const CountedPtr<U2>& b) noexcept { return a == b.ptr; }
500 template<typename U1, typename U2> inline bool operator!=(const U1* a, const CountedPtr<U2>& b) noexcept { return a != b.ptr; }
501 template<typename U> inline bool operator==(const CountedPtr<U>& a, std::nullptr_t) noexcept { return a.ptr == nullptr; }
502 template<typename U> inline bool operator!=(const CountedPtr<U>& a, std::nullptr_t) noexcept { return a.ptr != nullptr; }
503
504 // ---------------------------------------------------------------------------------------------
505 // ---------------------------------------------------------------------------------------------
506
510 template<typename T> class CopyOnWritePtr {
511 // static_assert(std::is_copy_constructible_v<T>, "T must be copy constructible.");
512
513 private:
514 struct Data {
518
520 SPtr<T> (*copy)(const SPtr<T>& other);
521
522 explicit Data() = default;
523 explicit Data(const SPtr<T>& data, SPtr<T> (*copy)(const SPtr<T>&)) : data(data), copy(copy) {}
524
525 Data(const Data&) = default;
526 Data& operator=(const Data&) = default;
527
528 Data(Data&&) noexcept = default;
529 Data& operator=(Data&&) noexcept = default;
530 };
531
534 Data mData;
535
536 public:
538 CopyOnWritePtr() = default;
539
543 template<typename U>
544 CopyOnWritePtr(U&& value) requires(std::is_constructible_v<T, U>)
545 : CopyOnWritePtr(std::in_place_type_t<U>{}, std::forward<U>(value)) {}
546
548 CE_EXPLICIT(false) CopyOnWritePtr(std::nullptr_t) noexcept {}
549
552 CopyOnWritePtr(const CopyOnWritePtr&) noexcept = default;
553
556 CopyOnWritePtr& operator=(const CopyOnWritePtr&) noexcept = default;
557
559 CopyOnWritePtr(CopyOnWritePtr&&) noexcept = default;
560
562 CopyOnWritePtr& operator=(CopyOnWritePtr&&) noexcept = default;
563
564 private:
569 template<typename U, typename... Args>
570 explicit CopyOnWritePtr(std::in_place_type_t<U>, Args&&... args)
571 : mData(ce_shared_new<U>(std::forward<Args>(args)...),
572 [](const SPtr<T>& other) -> SPtr<T> { return ce_shared_new<U>(static_cast<const U&>(*other)); }) {}
573
574 public:
576 [[nodiscard]] bool valid() const noexcept { return mData.data != nullptr; }
577
579 [[nodiscard]] explicit operator bool() const noexcept { return valid(); }
580
582 [[nodiscard]] const T* get() const noexcept { return mData.data.get(); }
583
585 [[nodiscard]] const T& operator*() const noexcept { return *get(); }
586
588 [[nodiscard]] const T* operator->() const noexcept { return get(); }
589
591 void reset() { mData.data.reset(); }
592
593 public: // Write
600 template<typename Func> decltype(auto) mutate(Func&& func) {
601 makeCopyIfNeeded();
602
603 // At this point, we MUST be the only instance of the CoW pointer.
604 //
605 CE_ASSERT(mData.data.use_count() == 1);
606 return func(*mData.data);
607 }
608
609 private:
612 inline void makeCopyIfNeeded() {
613 if(mData.data.use_count() == 1) {
614 return;
615 }
616 mData.data = mData.copy(mData.data);
617 }
618
619 public:
621 friend bool operator==(const CopyOnWritePtr& lhs, const CopyOnWritePtr& rhs) noexcept { return lhs.mData.data == rhs.mData.data; }
622
624 friend bool operator!=(const CopyOnWritePtr& lhs, const CopyOnWritePtr& rhs) noexcept { return lhs.mData.data != rhs.mData.data; }
625
627 friend bool operator==(const CopyOnWritePtr& lhs, std::nullptr_t) noexcept { return lhs.mData.data == nullptr; }
628
630 friend bool operator!=(const CopyOnWritePtr& lhs, std::nullptr_t) noexcept { return lhs.mData.data != nullptr; }
631
633 friend bool operator==(std::nullptr_t, const CopyOnWritePtr& rhs) noexcept { return nullptr == rhs.mData.data; }
634
636 friend bool operator!=(std::nullptr_t, const CopyOnWritePtr& rhs) noexcept { return nullptr != rhs.mData.data; }
637
638 template<typename T1, typename U, typename... Args> friend CopyOnWritePtr<T1> ce_cow_new(Args&&... args);
639 };
640
642 template<typename T> using CoW = CopyOnWritePtr<T>;
643
644 // ---------------------------------------------------------------------------------------------
645
652 template<typename T, typename U = T, typename... Args> [[nodiscard]] CopyOnWritePtr<T> ce_cow_new(Args&&... args) { // NOLINT
653 return CopyOnWritePtr<T>(std::in_place_type_t<U>{}, std::forward<Args>(args)...);
654 }
655
656 // ---------------------------------------------------------------------------------------------
657 // ---------------------------------------------------------------------------------------------
658
659#define CE_VPTR_TMPL(T) typename T, size_t T##SmallSize
660#define CE_VPTR_TYPE(T) ValuePtr<T, T##SmallSize>
661
675 template<typename T, size_t SmallSize = sizeof(int*) * 4> class ValuePtr final {
676 private:
677 struct VTable;
678
680 const VTable* vtable = nullptr;
681
683 alignas(T) mutable UInt8 raw[SmallSize];
684
685 public:
687 template<typename U> static constexpr inline bool isSmall = sizeof(U) <= SmallSize;
688
689 private:
690 struct VTable {
691 T* (*get)(void*);
692 void (*copy)(void*, const void*);
693 void (*move)(void*, void*);
694 void (*destroy)(void*);
695
696 template<typename TT> static const VTable* create() {
697 if constexpr(sizeof(TT) <= SmallSize) {
698 static const VTable vtable{
699 .get = [](void* ptr) -> T* { return reinterpret_cast<TT*>(ptr); },
700 .copy = []() -> decltype(VTable::copy) {
701 if constexpr(std::is_copy_constructible_v<TT>) {
702 return [](void* destination, const void* source) {
703 new(destination) TT(*reinterpret_cast<const TT*>(source));
704 };
705 }
706 return nullptr;
707 }(),
708 .move = []() -> decltype(VTable::move) {
709 if constexpr(std::is_move_constructible_v<TT>) {
710 return [](void* destination, void* source) {
711 new(destination) TT(std::move(*reinterpret_cast<TT*>(source)));
712 };
713 }
714 return nullptr;
715 }(),
716 .destroy = [](void* ptr) { reinterpret_cast<TT*>(ptr)->~TT(); },
717 };
718 return &vtable;
719 } else {
720 static const VTable vtable{
721 .get = [](void* ptr) -> T* { return *reinterpret_cast<TT**>(ptr); },
722 .copy = []() -> decltype(VTable::copy) {
723 if constexpr(std::is_copy_constructible_v<TT>) {
724 return [](void* destination, const void* source) {
725 *reinterpret_cast<TT**>(destination) = new TT(**reinterpret_cast<const TT* const*>(source));
726 };
727 }
728 return nullptr;
729 }(),
730 .move =
731 [](void* destination, void* source) { //
732 *reinterpret_cast<TT**>(destination) = std::exchange(*reinterpret_cast<TT**>(source), nullptr);
733 },
734 .destroy = [](void* ptr) { delete *reinterpret_cast<TT**>(ptr); },
735 };
736 return &vtable;
737 }
738 }
739 };
740
741 public:
743 [[nodiscard]] bool isCopyable() const noexcept { return vtable == nullptr || vtable->copy != nullptr; }
744
747 ValuePtr(const ValuePtr& other) : vtable(other.vtable) {
748 CE_ASSERT(other.isCopyable());
749
750 if(vtable == nullptr) {
751 return;
752 }
753
754 CE_ASSERT(vtable->copy != nullptr);
755 vtable->copy(raw, other.raw);
756 }
757
761 ValuePtr& operator=(const ValuePtr& other) { // NOLINT(bugprone-unhandled-self-assignment,cert-oop54-cpp)
762 CE_ASSERT(other.isCopyable());
763
764 // If both objects are pointing to the same object, no need to do
765 // anything. Just return.
766 //
767 if(other.get() == get()) {
768 return *this;
769 }
770
771 reset();
772 vtable = other.vtable;
773 if(vtable != nullptr) {
774 CE_ASSERT(vtable->copy != nullptr);
775 vtable->copy(raw, other.raw);
776 }
777
778 return *this;
779 }
780
782 [[nodiscard]] bool isMovable() const noexcept { return vtable == nullptr || vtable->move != nullptr; }
783
786 ValuePtr(ValuePtr&& other) noexcept : vtable(other.vtable) {
787 CE_ASSERT(other.isMovable());
788
789 if(vtable == nullptr) {
790 return;
791 }
792
793 CE_ASSERT(vtable->move != nullptr);
794 vtable->move(raw, other.raw);
795 }
796
800 ValuePtr& operator=(ValuePtr&& other) { // NOLINT
801 CE_ASSERT(other.isMovable());
802
803 // If both objects are pointing to the same object, no need to do
804 // anything. Just return.
805 //
806 if(other.get() == get()) {
807 return *this;
808 }
809
810 reset();
811
812 vtable = other.vtable;
813 if(vtable != nullptr) {
814 CE_ASSERT(vtable->move != nullptr);
815 vtable->move(raw, other.raw);
816 }
817
818 return *this;
819 }
820
822 ValuePtr(std::nullptr_t) noexcept : vtable(nullptr) {} // NOLINT
823
826 ValuePtr& operator=(std::nullptr_t) noexcept {
827 reset();
828 return *this;
829 }
830
832 ~ValuePtr() noexcept { reset(); }
833
834 private:
838 template<typename TT> struct ConstructTag {};
839
845 template<typename TT, typename... Args, typename = std::enable_if_t<std::is_convertible_v<TT*, T*> && std::is_constructible_v<TT, Args...>>>
846 explicit ValuePtr(ConstructTag<TT>, Args&&... args) {
847 emplace<TT>(std::forward<Args>(args)...);
848 }
849
850 public:
852 template<bool B = std::is_default_constructible_v<T>&& std::is_copy_constructible_v<T>, typename = std::enable_if_t<B>>
853 ValuePtr() noexcept : ValuePtr(ConstructTag<T>{}) {}
854
859 template<typename... Args, typename = std::enable_if_t<std::is_constructible_v<T, Args...>>>
860 explicit ValuePtr(Args&&... args) : ValuePtr(ConstructTag<T>{}, std::forward<Args>(args)...) {}
861
865 template<typename TT> requires(std::is_convertible_v<TT*, T*>)
866 ValuePtr(TT object) // NOLINT
867 : ValuePtr(ConstructTag<TT>{}, std::forward<TT>(object)) {}
868
873 template<typename TT, typename... Args, typename = std::enable_if_t<std::is_constructible_v<TT, Args...>>> TT& emplace(Args&&... args) {
874 reset();
875
876 vtable = VTable::template create<TT>();
877 CE_ASSERT(vtable != nullptr);
878
879 if constexpr(sizeof(TT) <= SmallSize) {
880 new(raw) TT(std::forward<Args>(args)...);
881 } else {
882 *reinterpret_cast<TT**>(raw) = new TT(std::forward<Args>(args)...);
883 }
884
885 return static_cast<TT&>(*get());
886 }
887
888 public: // Public interface
891 [[nodiscard]] bool valid() const { return vtable != nullptr; }
892
895 [[nodiscard]] bool empty() const { return vtable == nullptr; }
896
898 [[nodiscard]] T* get() const { return vtable == nullptr ? nullptr : vtable->get(raw); }
899
902 void reset() {
903 if(vtable == nullptr) {
904 return;
905 }
906
907 CE_ASSERT(vtable->destroy != nullptr);
908 vtable->destroy(raw);
909 vtable = nullptr;
910#ifndef NDEBUG
911 std::memset(raw, 0x00, sizeof(raw));
912#endif
913 }
914
917 explicit operator bool() const { return vtable != nullptr; }
918
920 T* operator->() const { return get(); }
921
923 T& operator*() const { return *get(); }
924
925 public:
930 template<typename... Args> static ValuePtr<T, SmallSize> create(Args&&... args) { return ValuePtr<T, SmallSize>(std::forward<Args>(args)...); }
931
937 template<typename U, typename... Args> static ValuePtr<T, SmallSize> create(Args&&... args) {
938 return ValuePtr<T, SmallSize>(ConstructTag<U>{}, std::forward<Args>(args)...);
939 }
940 };
941
946 template<CE_VPTR_TMPL(T), CE_VPTR_TMPL(U)> bool operator==(const CE_VPTR_TYPE(T) & lhs, const CE_VPTR_TYPE(U) & rhs) noexcept {
947 if(lhs.get() == nullptr) {
948 return false;
949 }
950 if(rhs.get() == nullptr) {
951 return false;
952 }
953 return *(lhs.get()) == *(rhs.get());
954 }
955
960 template<CE_VPTR_TMPL(T), typename U> bool operator==(const CE_VPTR_TYPE(T) & lhs, const U& rhs) noexcept {
961 if(lhs.get() == nullptr) {
962 return false;
963 }
964 return *(lhs.get()) == rhs;
965 }
966
971 template<typename U, CE_VPTR_TMPL(T)> bool operator==(const U& lhs, const CE_VPTR_TYPE(T) & rhs) noexcept {
972 if(rhs.get() == nullptr) {
973 return false;
974 }
975 return lhs == *(rhs.get());
976 }
977
982 template<CE_VPTR_TMPL(T), CE_VPTR_TMPL(U)> bool operator!=(const CE_VPTR_TYPE(T) & lhs, const CE_VPTR_TYPE(U) & rhs) noexcept {
983 if(lhs.get() == nullptr) {
984 return true;
985 }
986 if(rhs.get() == nullptr) {
987 return true;
988 }
989 return *(lhs.get()) != *(rhs.get());
990 }
991
996 template<CE_VPTR_TMPL(T), typename U> bool operator!=(const CE_VPTR_TYPE(T) & lhs, const U& rhs) noexcept {
997 if(lhs.get() == nullptr) {
998 return true;
999 }
1000 return *(lhs.get()) != rhs;
1001 }
1002
1007 template<typename U, CE_VPTR_TMPL(T)> bool operator!=(const U& lhs, const CE_VPTR_TYPE(T) & rhs) noexcept {
1008 if(rhs.get() == nullptr) {
1009 return true;
1010 }
1011 return lhs != *(rhs.get());
1012 }
1013
1018 template<CE_VPTR_TMPL(T), CE_VPTR_TMPL(U)> bool operator>(const CE_VPTR_TYPE(T) & lhs, const CE_VPTR_TYPE(U) & rhs) noexcept {
1019 if(lhs.get() == nullptr) {
1020 return false;
1021 }
1022 if(rhs.get() == nullptr) {
1023 return false;
1024 }
1025 return *(lhs.get()) > *(rhs.get());
1026 }
1027
1032 template<CE_VPTR_TMPL(T), typename U> bool operator>(const CE_VPTR_TYPE(T) & lhs, const U& rhs) noexcept {
1033 if(lhs.get() == nullptr) {
1034 return false;
1035 }
1036 return *(lhs.get()) > rhs;
1037 }
1038
1043 template<typename U, CE_VPTR_TMPL(T)> bool operator>(const U& lhs, const CE_VPTR_TYPE(T) & rhs) noexcept {
1044 if(rhs.get() == nullptr) {
1045 return false;
1046 }
1047 return lhs > *(rhs.get());
1048 }
1049
1054 template<CE_VPTR_TMPL(T), CE_VPTR_TMPL(U)> bool operator>=(const CE_VPTR_TYPE(T) & lhs, const CE_VPTR_TYPE(U) & rhs) noexcept {
1055 if(lhs.get() == nullptr) {
1056 return false;
1057 }
1058 if(rhs.get() == nullptr) {
1059 return false;
1060 }
1061 return *(lhs.get()) >= *(rhs.get());
1062 }
1063
1068 template<CE_VPTR_TMPL(T), typename U> bool operator>=(const CE_VPTR_TYPE(T) & lhs, const U& rhs) noexcept {
1069 if(lhs.get() == nullptr) {
1070 return false;
1071 }
1072 return *(lhs.get()) >= rhs;
1073 }
1074
1079 template<typename U, CE_VPTR_TMPL(T)> bool operator>=(const U& lhs, const CE_VPTR_TYPE(T) & rhs) noexcept {
1080 if(rhs.get() == nullptr) {
1081 return false;
1082 }
1083 return lhs >= *(rhs.get());
1084 }
1085
1090 template<CE_VPTR_TMPL(T), CE_VPTR_TMPL(U)> bool operator<(const CE_VPTR_TYPE(T) & lhs, const CE_VPTR_TYPE(U) & rhs) noexcept {
1091 if(lhs.get() == nullptr) {
1092 return false;
1093 }
1094 if(rhs.get() == nullptr) {
1095 return false;
1096 }
1097 return *(lhs.get()) < *(rhs.get());
1098 }
1099
1104 template<CE_VPTR_TMPL(T), typename U> bool operator<(const CE_VPTR_TYPE(T) & lhs, const U& rhs) noexcept {
1105 if(lhs.get() == nullptr) {
1106 return false;
1107 }
1108 return *(lhs.get()) < rhs;
1109 }
1110
1115 template<typename U, CE_VPTR_TMPL(T)> bool operator<(const U& lhs, const CE_VPTR_TYPE(T) & rhs) noexcept {
1116 if(rhs.get() == nullptr) {
1117 return false;
1118 }
1119 return lhs < *(rhs.get());
1120 }
1121
1126 template<CE_VPTR_TMPL(T), CE_VPTR_TMPL(U)> bool operator<=(const CE_VPTR_TYPE(T) & lhs, const CE_VPTR_TYPE(U) & rhs) noexcept {
1127 if(lhs.get() == nullptr) {
1128 return false;
1129 }
1130 if(rhs.get() == nullptr) {
1131 return false;
1132 }
1133 return *(lhs.get()) <= *(rhs.get());
1134 }
1135
1140 template<CE_VPTR_TMPL(T), typename U> bool operator<=(const CE_VPTR_TYPE(T) & lhs, const U& rhs) noexcept {
1141 if(lhs.get() == nullptr) {
1142 return false;
1143 }
1144 return *(lhs.get()) <= rhs;
1145 }
1146
1151 template<typename U, CE_VPTR_TMPL(T)> bool operator<=(const U& lhs, const CE_VPTR_TYPE(T) & rhs) noexcept {
1152 if(rhs.get() == nullptr) {
1153 return false;
1154 }
1155 return lhs <= *(rhs.get());
1156 }
1157
1161 template<CE_VPTR_TMPL(T)> bool operator==(const CE_VPTR_TYPE(T) & lhs, std::nullptr_t) noexcept { return lhs.get() == nullptr; }
1162
1166 template<CE_VPTR_TMPL(T)> bool operator!=(const CE_VPTR_TYPE(T) & lhs, std::nullptr_t) noexcept { return lhs.get() != nullptr; }
1167
1168#undef CE_VPTR_TMPL
1169#undef CE_VPTR_TYPE
1170
1183 template<typename T, size_t SmallSize = sizeof(int*) * 3> using VPtr = ValuePtr<T, SmallSize>;
1184
1185} // namespace CeresEngine
1186
1187template<typename T> struct std::hash<CeresEngine::CountedPtr<T>> {
1188 using Type = CeresEngine::CountedPtr<T>;
1189 inline size_t operator()(const Type& obj) const noexcept { return std::hash<T*>{}(obj.get()); }
1190};
#define CE_ASSERT(...)
Definition Macros.hpp:323
#define CE_EXPLICIT(EXPR)
Definition Macros.hpp:413
#define CE_VPTR_TYPE(T)
Definition SmartPtr.hpp:660
A copy-on-write pointer type that shares a single instance of an object when copied but allows.
Definition SmartPtr.hpp:510
void reset()
Resets the stored pointer and empties the CoW pointer.
Definition SmartPtr.hpp:591
CopyOnWritePtr & operator=(const CopyOnWritePtr &) noexcept=default
Assigns a copy of the CoW pointer.
decltype(auto) mutate(Func &&func)
Changes the pointer.
Definition SmartPtr.hpp:600
const T * operator->() const noexcept
Gets a const pointer to the object.
Definition SmartPtr.hpp:588
const T * get() const noexcept
Gets a const pointer to the object.
Definition SmartPtr.hpp:582
void makeCopyIfNeeded()
Checks if we are the only user of the CoW pointer.
Definition SmartPtr.hpp:612
bool valid() const noexcept
Checks if the pointer points to a valid object.
Definition SmartPtr.hpp:576
const T & operator*() const noexcept
Gets a const pointer to the object.
Definition SmartPtr.hpp:585
friend bool operator!=(const CopyOnWritePtr &lhs, std::nullptr_t) noexcept
Checks if the two pointers do not point to the same copy of the object.
Definition SmartPtr.hpp:630
friend bool operator==(std::nullptr_t, const CopyOnWritePtr &rhs) noexcept
Checks if the two pointers point to the same copy of the object.
Definition SmartPtr.hpp:633
CopyOnWritePtr(CopyOnWritePtr &&) noexcept=default
Creates a copy of the CoW pointer.
friend bool operator!=(std::nullptr_t, const CopyOnWritePtr &rhs) noexcept
Checks if the two pointers do not point to the same copy of the object.
Definition SmartPtr.hpp:636
friend bool operator==(const CopyOnWritePtr &lhs, const CopyOnWritePtr &rhs) noexcept
Checks if the two pointers point to the same copy of the object.
Definition SmartPtr.hpp:621
friend bool operator==(const CopyOnWritePtr &lhs, std::nullptr_t) noexcept
Checks if the two pointers point to the same copy of the object.
Definition SmartPtr.hpp:627
friend bool operator!=(const CopyOnWritePtr &lhs, const CopyOnWritePtr &rhs) noexcept
Checks if the two pointers do not point to the same copy of the object.
Definition SmartPtr.hpp:624
CopyOnWritePtr(const CopyOnWritePtr &) noexcept=default
Creates a copy of the CoW pointer.
A retain-release type of smart pointer.
Definition SmartPtr.hpp:132
friend bool operator==(const CountedPtr< U1 > &a, const CountedPtr< U2 > &b) noexcept
Checks if both intrusive pointers represent the same object.
Definition SmartPtr.hpp:495
friend bool operator!=(const CountedPtr< U1 > &a, const CountedPtr< U2 > &b) noexcept
Checks if both intrusive pointers not represent the same object.
Definition SmartPtr.hpp:496
void set(Pointer newPtr) noexcept
Sets a new value for the pointer.
Definition SmartPtr.hpp:274
friend bool operator!=(const CountedPtr< U > &a, std::nullptr_t) noexcept
Checks if the intrusive pointer a is not nullptr.
Definition SmartPtr.hpp:502
CountedPtr(AdoptPtrT, const Pointer aPtr) noexcept
Creates a new CountedPtr from an existing reference counted object.
Definition SmartPtr.hpp:165
CountedPtrTrait< T > Trait
The CountedPtrTrait specialization for type T.
Definition SmartPtr.hpp:136
~CountedPtr() noexcept
Destroys the CountedPtr.
Definition SmartPtr.hpp:240
CountedPtr & operator=(const CountedPtr< U > &other) noexcept
Assigns the CountedPtr by copying another.
Definition SmartPtr.hpp:186
friend bool operator==(const U1 *a, const CountedPtr< U2 > &b) noexcept
Checks if both intrusive pointers represent the same object.
Definition SmartPtr.hpp:499
friend bool operator!=(const CountedPtr< U1 > &a, const U2 *b) noexcept
Checks if both intrusive pointers not represent the same object.
Definition SmartPtr.hpp:498
CountedPtr() noexcept=default
Creates a new null CountedPtr
CountedPtr(CountedPtr &&other) noexcept
Creates a new CountedPtr by moving another.
Definition SmartPtr.hpp:193
CountedPtr & operator=(CountedPtr &&other) noexcept
Assigns the CountedPtr by moving another.
Definition SmartPtr.hpp:203
friend bool operator==(const CountedPtr< U1 > &a, const U2 *b) noexcept
Checks if both intrusive pointers represent the same object.
Definition SmartPtr.hpp:497
friend bool operator==(const CountedPtr< U > &a, std::nullptr_t) noexcept
Checks if the intrusive pointer a is nullptr.
Definition SmartPtr.hpp:501
Reference operator*() const noexcept
Definition SmartPtr.hpp:250
CountedPtr(CountedPtr< U > &&other) noexcept
Creates a new CountedPtr by copying another.
Definition SmartPtr.hpp:197
T * Pointer
A pointer to the reference counted object.
Definition SmartPtr.hpp:143
void reset() noexcept
Resets the pointer by setting it to nullptr.
Definition SmartPtr.hpp:257
static CountedPtr< T > adopt(T *const ptr)
Creates a new CountedPtr from an existing reference counted object.
Definition SmartPtr.hpp:269
Pointer release() noexcept
Releases the pointer from the CountedPtr.
Definition SmartPtr.hpp:262
Pointer operator->() const noexcept
Definition SmartPtr.hpp:247
CountedPtr & operator=(const CountedPtr &other) noexcept
Assigns the CountedPtr by copying another.
Definition SmartPtr.hpp:178
friend bool operator!=(const U1 *a, const CountedPtr< U2 > &b) noexcept
Checks if both intrusive pointers not represent the same object.
Definition SmartPtr.hpp:500
CountedPtr(const CountedPtr &other) noexcept
Creates a new CountedPtr by copying another.
Definition SmartPtr.hpp:169
CountedPtr(const CountedPtr< U > &other) noexcept
Creates a new CountedPtr by copying another.
Definition SmartPtr.hpp:173
CountedPtr(std::nullptr_t) noexcept
Creates a new empty CountedPtr object.
Definition SmartPtr.hpp:161
CountedPtr & operator=(U *aPtr) noexcept
Assigns the CountedPtr by assigning a new pointer.
Definition SmartPtr.hpp:230
Pointer get() const noexcept
Definition SmartPtr.hpp:244
Pointer ptr
The raw-pointer to the reference counted object.
Definition SmartPtr.hpp:150
T & Reference
A reference to the reference counted object.
Definition SmartPtr.hpp:146
CountedPtr & operator=(CountedPtr< U > &&other) noexcept
Assigns the CountedPtr by copying another.
Definition SmartPtr.hpp:216
T ElementType
The element type contained by the pointer.
Definition SmartPtr.hpp:140
A simple reference counter base class.
Definition SmartPtr.hpp:438
Counter mRefCounter
The object's reference counter.
Definition SmartPtr.hpp:440
void retain() noexcept
Retains the object by increment it's reference count by one.
Definition SmartPtr.hpp:454
RefCounted(Args &&... args)
Creates a new RefCounted object and constructs a new Deleter by forwarding Args to it.
Definition SmartPtr.hpp:450
Deleter mDeleter
The deleter object type.
Definition SmartPtr.hpp:443
bool release() noexcept
Relases the object by decrementing it's reference count by one.
Definition SmartPtr.hpp:458
RefCounter(const UInt64 initialCount)
Definition SmartPtr.hpp:427
void increment() noexcept
Increments the reference counter by one.
void increment() noexcept
Increments the reference counter by one.
RefCounter(const UInt64 initialCount)
Definition SmartPtr.hpp:408
A class that implements a simple interface for reference counting.
Definition SmartPtr.hpp:82
A pointer type that has value semantics.
Definition SmartPtr.hpp:675
UInt8 raw[SmallSize]
The underlying storage memory.
Definition SmartPtr.hpp:683
void reset()
Resets the stored object into an empty state.
Definition SmartPtr.hpp:902
ValuePtr(const ValuePtr &other)
Creates a new ValuePtr by copying an existing one.
Definition SmartPtr.hpp:747
const VTable * vtable
A VTable that contains implementation for copy, move and destroy.
Definition SmartPtr.hpp:680
ValuePtr(ValuePtr &&other) noexcept
Creates a new ValuePtr by moving an existing one.
Definition SmartPtr.hpp:786
ValuePtr(ConstructTag< TT >, Args &&... args)
Creates a new ValuePtr that holds a newly constructed object of type TT.
Definition SmartPtr.hpp:846
bool empty() const
Checks if the pointer has a valid object stored in it.
Definition SmartPtr.hpp:895
ValuePtr(Args &&... args)
Creates a new ValuePtr that holds a newly constructed object of type T.
Definition SmartPtr.hpp:860
~ValuePtr() noexcept
Destroys the ValuePtr and destroys the object is present.
Definition SmartPtr.hpp:832
ValuePtr & operator=(std::nullptr_t) noexcept
Assigns the ValuePtr a nullptr value.
Definition SmartPtr.hpp:826
ValuePtr() noexcept
Creates a new empty ValuePtr.
Definition SmartPtr.hpp:853
T & operator*() const
Definition SmartPtr.hpp:923
TT & emplace(Args &&... args)
Emplace a new object of type TT into the ValuePtr.
Definition SmartPtr.hpp:873
T * operator->() const
Definition SmartPtr.hpp:920
static ValuePtr< T, SmallSize > create(Args &&... args)
Create a new ValuePtr with an object of type U
Definition SmartPtr.hpp:937
ValuePtr(std::nullptr_t) noexcept
Creates a new empty ValuePtr.
Definition SmartPtr.hpp:822
bool isMovable() const noexcept
Checks if the ValuePtr move constructor can be safely called.
Definition SmartPtr.hpp:782
ValuePtr(TT object)
Creates a new ValuePtr that holds a copy constructed object of type TT.
Definition SmartPtr.hpp:866
bool isCopyable() const noexcept
Checks if the ValuePtr copy constructor can be safely called.
Definition SmartPtr.hpp:743
static ValuePtr< T, SmallSize > create(Args &&... args)
Create a new ValuePtr with an object of type T
Definition SmartPtr.hpp:930
bool valid() const
Checks if the pointer has a valid object stored in it.
Definition SmartPtr.hpp:891
ValuePtr & operator=(ValuePtr &&other)
Assigns a ValuePtr by moving an existing one.
Definition SmartPtr.hpp:800
ValuePtr & operator=(const ValuePtr &other)
Assigns a ValuePtr by copying an existing one.
Definition SmartPtr.hpp:761
T * get() const
Definition SmartPtr.hpp:898
A concept type that checks if a given type T has a intrusive retain
Definition SmartPtr.hpp:106
A concept type that checks if a given type T has a CountedPtrTrait specialization that allows it to b...
Definition SmartPtr.hpp:115
Definition Application.hpp:19
std::unique_ptr< T, Deleter > UPtr
UPtr is a smart pointer that owns and manages another object through a pointer and disposes of that o...
Definition SmartPtr.hpp:28
std::uint64_t UInt64
Definition DataTypes.hpp:26
std::shared_ptr< T > SPtr
SPtr is a smart pointer that retains shared ownership of an object through a pointer.
Definition SmartPtr.hpp:37
constexpr UPtr< T > ce_unique_new(Args &&... args)
Definition SmartPtr.hpp:50
CopyOnWritePtr< T > ce_cow_new(Args &&... args)
Creates a new copy-on-write pointer by constructing a new object of type U.
Definition SmartPtr.hpp:652
auto move(Vector3 position)
Moves a entity to the given position.
Definition Helpers.hpp:22
bool operator!=(const ShortAllocator< T, N, A1 > &x, const ShortAllocator< U, M, A2 > &y) noexcept
Definition Allocator.hpp:416
RC< T > ce_counted_new(Args &&... args)
Definition SmartPtr.hpp:391
std::uint8_t UInt8
Definition DataTypes.hpp:17
constexpr SPtr< T > ce_shared_new(Args &&... args)
Definition SmartPtr.hpp:69
bool operator==(const ShortAllocator< T, N, A1 > &x, const ShortAllocator< U, M, A2 > &y) noexcept
Definition Allocator.hpp:411
constexpr SPtr< T > ce_shared_alloc(Allocator &allocator, Args &&... args)
Definition SmartPtr.hpp:74
std::atomic< T > Atomic
The Atomic template defines an atomic type.
Definition Atomic.hpp:16
constexpr T * ce_new(Args &&... args)
Definition SmartPtr.hpp:46
std::weak_ptr< T > WPtr
WPtr is a smart pointer that holds a non-owning ("weak") reference to an object that is managed by SP...
Definition SmartPtr.hpp:42
void copy(const A &a, B &b, T &&t=T())
Copies values from one container to another.
Definition Iterator.hpp:564
constexpr size_t hash(const T &v)
Generates a hash for the provided type.
Definition Hash.hpp:25
constexpr UPtr< T, AllocatorDeleter< T, RawAllocator > > ce_unique_alloc(RawAllocator &allocator, Args &&... args)
Definition SmartPtr.hpp:55
RC< T > ce_counted_adopt(T *const ptr)
Definition SmartPtr.hpp:387
Definition Span.hpp:668
Definition SmartPtr.hpp:514
Data(const Data &)=default
Data(const SPtr< T > &data, SPtr< T >(*copy)(const SPtr< T > &))
Definition SmartPtr.hpp:523
Data & operator=(const Data &)=default
Data(Data &&) noexcept=default
A trait template class that can be specialized for custom types.
Definition SmartPtr.hpp:95
A tag used for tagged dispatching the object constructing constructor.
Definition SmartPtr.hpp:838
Definition SmartPtr.hpp:690
T *(* get)(void *)
Definition SmartPtr.hpp:691
void(* move)(void *, void *)
Definition SmartPtr.hpp:693
static const VTable * create()
Definition SmartPtr.hpp:696
void(* copy)(void *, const void *)
Definition SmartPtr.hpp:692