Hubris Engine Dev
A Project to learn and get into Game Engine developement.
 
Loading...
Searching...
No Matches
Memory.h
Go to the documentation of this file.
1#pragma once
2#include <memory>
3#include <version>
4#include <cstddef>
5#include <new>
6#include <tuple>
7#include <utility>
8#include <type_traits>
9#include <algorithm>
10
11namespace Hubris{
12 template<typename From, typename To>
13 concept Castable = std::convertible_to<From, To> && !std::same_as<From, To>;
14 template<typename From, typename To>
15 concept PolymorphicConvertible = std::convertible_to<From*, To*> && std::derived_from<From, To> && std::has_virtual_destructor_v<To>;
16 template<typename From, typename To>
17 concept SafelyUpcastable = Castable<From*, To*> && std::derived_from<From, To>&& std::has_virtual_destructor_v<To>;
18 template<typename T, typename V>
19 concept SameUnqualifiedType = std::same_as<std::remove_cv_t<T>, std::remove_cv_t<V>>;
20 template<typename T, typename V>
22
23 struct Block{
24 size_t blk_id;
25 void* pointer;
26
27 // constexpr operator void*()const noexcept{
28 // return pointer;
29 // }
30 };
31
36
37 };
38
39 struct Arena{
40 size_t Size;
41
42 };
43 class Memory{
44 private:
45
46 public:
50 static Block Alloc(size_t bufSize);
62 static Block Resize(Block& block, size_t newSize);
66 static void Free(Block& buffer);
73 static void ExpandInternalArena(size_t width);
81 static Arena& CreateArena(size_t size);
86 static SharedBlock AllocShared(size_t size);
93 static Arena& CreateGlobalArena(size_t width);
97 static void FreeArena(Arena);
98 //Utility Checks.
99 static bool IsValid(const void* pointer);
100 static bool IsEngineAllocated(const void* pointer);
101 static bool IsFree(const Block& block)noexcept;
102 static bool IsThreadLocal(const Block& block)noexcept;
103 static bool IsShared(const void* blockptr)noexcept;
104 //Statistics
105 static size_t MemoryUsed(const Arena& arena);
106 static size_t GetMemoryAvailable(const Arena& arena);
107 static unsigned int TotalAllocationCount()noexcept;
108 static unsigned int TotalDeallocationCount()noexcept;
109 static unsigned int TotalBlockResizeCount()noexcept;
110 static unsigned int TotalArenasAllocated()noexcept;
111 static unsigned int TotalArenasFreed()noexcept;
112 static unsigned int ThreadAllocationCount()noexcept;
113 static unsigned int ThreadDeallocationCount()noexcept;
114 static unsigned int ThreadBlockResizeCount()noexcept;
115 static unsigned int ThreadArenasAllocated()noexcept;
116 static unsigned int ThreadArenasFreed()noexcept;
117 static size_t TotalMemoryAllocated()noexcept;
118 static size_t TotalMemoryFreed()noexcept;
119 static size_t ThreadMemoryUsed()noexcept;
120 static size_t ThreadMemoryFreed()noexcept;
121 };
122
123
124 template<typename T>
126 using type = T;
127 };
128
129 template<typename T>
132 };
133 template<typename T>
134 struct remove_all_pointers<T* const> {
136 };
137
138 template<typename T>
139 struct remove_all_pointers<T* volatile> {
141 };
142
143 template<typename T>
144 struct remove_all_pointers<T* const volatile> {
146 };
147
148 template<typename T>
150
151
152 template<typename T>
153 concept IsType = !std::is_void_v<remove_all_pointers_t<T>> && !std::is_null_pointer_v<T>;
154
155 template<typename T> requires IsType<T>
156 struct Weak;
157 template<typename T> requires IsType<T>
158 struct Handle;
159
161 void* raw;
162 std::atomic_uint32_t ref_count = { 1 };
163 std::atomic_uint32_t weak_count = { 1 };
166 };
167
168 template<typename T>
169 consteval size_t padded_size() {
170 return (sizeof(T) + alignof(T) - 1) & ~(alignof(T) - 1);
171 }
172
173
174 template<typename T, typename F>
175 void Traverse(T&& container, F&& func) {
176 if constexpr (std::ranges::range<T> && !std::is_same_v<std::decay_t<T>, std::string>) {
177 for (auto&& elem : container) {
178 Traverse(std::forward<decltype(elem)>(elem), func);
179 }
180 } else {
181 func(std::forward<T>(container));
182 }
183 }
184
185
188 template<typename T>
190 static_assert(!std::is_unbounded_array_v<T>, "Cannot CoAllocate Unbounded arrays (at least for now, may create a special handle)");
191 constexpr size_t alloc_align = std::max(alignof(ControlBlock), alignof(T));
192 constexpr size_t Toffset = alignof(ControlBlock) > alignof(T) ? padded_size<ControlBlock>() : 0;
193 constexpr size_t CTR_offset = alignof(ControlBlock) > alignof(T) ? 0 : padded_size<ControlBlock>();
194 char* ptr = (char*)(alignof(ControlBlock) > alignof(T)
195 ? operator new(padded_size<ControlBlock>() + sizeof(T), std::align_val_t{ alloc_align })
196 : operator new(padded_size<T>() + sizeof(ControlBlock), std::align_val_t{ alloc_align }));
197
198 //This is aligned because either it is at the start (alignof(Crt) > alignof(T)) or T is padded at the end to align make this aligned
199 ControlBlock* ctr = new(ptr + CTR_offset)ControlBlock();
200 ctr->alloc_align = alloc_align;
201 ctr->BaseLocation = ptr;
202 //The logic is flipped but applies here.
203 ctr->raw = ptr + Toffset;
204
205 return ctr;
206 }
207
213 template<typename T, typename ...Args>
214 constexpr void Construct_T_Inplace(void* placement, Args&& ...args){
215 // static_assert(std::is_pointer<T>)
216 new(placement)std::remove_cv_t<T>(std::forward<Args>(args)...);
217 }
218
223 template<typename T, typename ...Args>
224 constexpr ControlBlock* CoAllocate(Args&& ...args){
225 constexpr size_t Toffset = alignof(ControlBlock) > alignof(T) ? padded_size<ControlBlock>() : 0;
227 Construct_T_Inplace<Args...>(ctr->raw, std::forward<Args>(args)...);
228 return ctr;
229 }
230
231 // template<typename T>
232 // constexpr void CoDelete(ControlBlock* crt){
233 // assert(crt->raw && "ControlBlock is observing no object");
234 // if constexpr(!std::is_array_v<T>){
235
236 // }
237 // }
238
239 template<typename T> requires IsType<T>
240 struct Shared {
241 static_assert(!std::is_reference_v<T>, "No reference is allowed.");
242 using Unqualified = std::remove_cv_t<T>;
243 #ifdef _DEBUG
244 bool HasBeenConverted = false;
245 const type_info& Converted_Type_Info = typeid(T);
246 #endif
247 private:
250 ControlBlock* ctr_blk = nullptr;
251
254 constexpr Shared(T* t) noexcept {
255 ctr_blk = new ControlBlock;
256 ctr_blk->raw = (void*)t;
257 }
258
261 constexpr Shared(ControlBlock* ctr) noexcept{
262 assert(ctr && "Attempted to create a Shared with an empty ControlBlock");
263 ctr_blk = ctr;
264 if(!ctr_blk)return; //Pre-caution, but a stupid case.
265 ctr_blk->ref_count.fetch_add(1, std::memory_order_release);
266 }
267
268 public:
269 constexpr Shared() noexcept = default;
270
271 template<typename ...Args>
272 constexpr Shared(Args&& ...args){
273 //For now, CoAllocates blocks unbounded arrays. So calling dtor is possible by indexing the array.
274 ctr_blk = CoAllocate<std::remove_cv_t<T>>(std::forward<Args>(args)...);
275 }
276
277 constexpr explicit Shared(Weak<T>&& promote) noexcept{
278 if(promote.Expired())return;
279 this->ctr_blk = promote.ctr_blk;
280 ctr_blk->ref_count.fetch_add(1, std::memory_order_release);
281 promote.Reset();
282 }
283
284 template<typename U>
285 constexpr explicit Shared(const Shared<U>& other) noexcept requires PolymorphicConvertible<U, T> {
286 this->ctr_blk = other.ctr_blk;
287 this->ctr_blk->ref_count.fetch_add(1, std::memory_order_release);
288 #ifdef _DEBUG
289 if constexpr (!std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<U>>){
290 HasBeenConverted = true;
291 Converted_Type_Info = typeid(U);
292 }
293 #endif
294 }
295
296 template<typename U>
297 Shared& operator=(const Shared<U>& cpy) noexcept requires PolymorphicConvertible<U, T>{
298 if(this == &cpy)return *this;
299 Release();
300 this->ctr_blk = cpy.ctr_blk;
301 //Copied an "empty" Shared into this one. User at fault but still we do what they wanted.
302 if(!ctr_blk)return;
303 ctr_blk->ref_count.fetch_add(1, std::memory_order_acquire);
304 #ifdef _DEBUG
305 if constexpr (!std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<U>>){
306 HasBeenConverted = true;
307 Converted_Type_Info = typeid(U);
308 }
309 #endif
310 return *this;
311 }
312
313 template<typename U>
314 constexpr explicit Shared(Shared<U>&& other) noexcept requires PolymorphicConvertible<U, T> {
315 std::swap(this->ctr_blk, other->crt_blk);
316 #ifdef _DEBUG
317 if constexpr (!std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<U>>){
318 HasBeenConverted = true;
319 Converted_Type_Info = typeid(U);
320 }
321 #endif
322 }
323
324 template<typename U>
325 Shared& operator=(Shared<U>&& mv) noexcept requires PolymorphicConvertible<U, T> {
326 if(this == &mv)return *this;
327 Release();
328 std::swap(this->ctr_blk, mv.ctr_blk);
329 #ifdef _DEBUG
330 if constexpr (!std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<U>>){
331 HasBeenConverted = true;
332 Converted_Type_Info = typeid(U);
333 }
334 #endif
335 return *this;
336 }
337
338 ~Shared() noexcept {
339 Release();
340 }
341
342
343 void Release() {
344 if (ctr_blk) {
345 if (ctr_blk->ref_count.fetch_sub(1, std::memory_order_acq_rel) == 1) {
346 Traverse(*(Unqualified*)ctr_blk->raw, [](std::remove_all_extents_t<Unqualified>& t){
347 std::destroy_at(std::addressof(t));
348 });
349 ctr_blk->raw = nullptr;
350 // }
351 if (ctr_blk->weak_count.load(std::memory_order_acq_rel) == 0) {
352 auto loc = ctr_blk->BaseLocation;
353 auto align_val = std::align_val_t{ctr_blk->alloc_align};
354 ctr_blk->~ControlBlock();
355 operator delete(loc, align_val);
356 }
357 }
358 ctr_blk = nullptr;
359 }
360 }
361
362 constexpr T* get() noexcept { return ctr_blk ? (T*)ctr_blk->raw : nullptr;}
363 const T* get()const noexcept { return ctr_blk ? (T*)ctr_blk->raw : nullptr; }
364
372 return (T*)ctr_blk->raw;
373 }
374 const T* operator->()const {
375 return (const T*)ctr_blk->raw;
376 }
377
378 T& operator*(){ return *(T*)ctr_blk->raw; }
379 const T& operator*()const { return *(T*)ctr_blk->raw; }
380
381 uint_fast32_t UseCount() const noexcept { return ctr_blk ? ctr_blk->ref_count.load(std::memory_order_acquire) : 0; }
382
388 bool Constructed()const noexcept { return ctr_blk; }
389
390 operator bool(){
391 return ctr_blk && ctr_blk->raw; //rely on short-circuit to avoid UB.
392 }
393
394 template<typename U>
395 constexpr void swap(Shared<U>& rhs) noexcept requires PolymorphicConvertible<U, T> {
396 std::swap(this->ctr_blk, rhs.ctr_blk);
397 #ifdef _DEBUG
398 if constexpr (!std::is_same_v<std::remove_cv_t<T>, std::remove_cv_t<U>>){
399 HasBeenConverted = true;
400 Converted_Type_Info = typeid(U);
401 }
402 #endif
403 }
404
405 friend Weak<T>;
406 friend Handle<T>;
407 };
408
409 template<typename T> requires IsType<T>
410 struct Weak{
411 private:
412 ControlBlock* ctr_blk;
413 public:
414 constexpr Weak(const Shared<T>& s) noexcept{
415 // static_assert(s.ctr_blk != nullptr, "Attempted to create a weak reference from an empty Shared");
416 ctr_blk = s.ctr_blk;
417 //This is memory order release instead of relax because it is creating a Weak reference and it must be valid upon return.
418 //in the case of other operation, whoever deletes the control block doesn't matter as long it is deleted,
419 //the deletion is ensure by the atomicity of the counter, but order doesn't matter. Correct me if i'm wrong.
420 ctr_blk->weak_count.fetch_add(1, std::memory_order_release);
421 }
422
424 Reset();
425 }
426
427 Shared<T> Lock()const noexcept {
428 if(ctr_blk->ref_count.load(std::memory_order_acquire) == 0)return Shared<T>();
429 return Shared<T>(*this);
430 }
431
432 bool Expired()const noexcept{
433 return ctr_blk && ctr_blk->ref_count.load(std::memory_order_acquire) == 0;
434 }
435
436 void Reset() noexcept{
437 if (ctr_blk) {
438 //This condition, decrements the weak_count, so even if the ctr_blk isn't expired, the counter still got down.
439 if (ctr_blk->weak_count.fetch_sub(1, std::memory_order_relaxed) == 1 &&
440 ctr_blk->ref_count.load(std::memory_order_acquire) == 0) {
441 auto loc = ctr_blk->BaseLocation;
442 auto align_val = std::align_val_t{ctr_blk->alloc_align};
443 ctr_blk->~ControlBlock();
444 operator delete(loc, align_val);
445 }
446 ctr_blk = nullptr;
447 }
448 }
449
450 uint_fast32_t UseCount()const noexcept{
451 return ctr_blk ? ctr_blk->ref_count.load(std::memory_order_acquire) : 0;
452 }
453
454 operator bool()const noexcept{
455 return !Expired() && ctr_blk->raw;
456 }
457
458 friend Shared<T>;
459 };
460 //Unique pointer equiv. Handle owns the object referenced. Planning on making a seperate container for Array (Handles for Arrays)
461 template<typename T> requires IsType<T>
462 struct Handle{
463 private:
464 T* raw = nullptr;
465 public:
466 constexpr Handle() noexcept = default;
467 constexpr Handle(std::nullptr_t) {};
468 constexpr Handle(T* t) noexcept {
469 raw = t;
470 }
471
472 template<typename U>
473 constexpr explicit Handle(U* other) noexcept requires SafelyUpcastable<U, T> && !SameUnqualifiedType<T,U>{
474 //If U is polymorphic => U*->T* => T::~T() must be virtual <=> T base of U
475
476 //This is safe even without the cast as the concepts ensure only convertible types are allowed,
477 //This is done work for explicit cast operators.
478 raw = static_cast<T*>(other);
479 }
480
481 template<typename U>
482 constexpr Handle(Handle<U>&& other) noexcept requires Castable<U*, T*>{
483 reset();
484 std::swap(this->raw, other.raw);
485 }
486
487 constexpr Handle(Handle&& mv) noexcept {
488 std::swap(this->raw, mv.raw);
489 }
490
491 ~Handle() noexcept {
492 reset();
493 }
494 Handle& operator=(Handle&& mv) noexcept{
495 if(this == &mv)return *this;
496 reset();
497 std::swap(this->raw, mv.raw);
498 return *this;
499 }
500 template<typename U>
502 if(this == &mv)return *this;
503 reset();
504 std::swap(this->raw, static_cast<T*>(mv.raw));
505 return *this;
506 }
507
508 Handle(const Handle& cp) noexcept = delete;
509 Handle& operator=(const Handle& cp) = delete;
510
511 constexpr T* get() noexcept {return raw;}
512 constexpr const T* get()const noexcept {return raw;}
513
514 inline void reset(T* ptr = nullptr) noexcept{
515 if(raw != ptr){
516 if constexpr (std::is_array_v<T>){
517 delete[] raw;
518 }else {
519 delete raw; //delete nullptr is both safe and defined as no-op.
520 }
521 raw = ptr;
522 }
523 }
524
525 constexpr T* release() noexcept /*dangerous_release*/ {
526 return std::exchange(raw, nullptr);
527 }
528
529 template<typename U>
530 constexpr void swap(Handle<U>& rhs) noexcept requires PolymorphicConvertible<U, T> {
531 std::swap(this->raw, static_cast<T*>(rhs.raw));
532 }
533
535 if(raw == nullptr) return Shared<T>();
536 Shared<T> shared;
537 //I think at compile time this will be optimized.
538 if constexpr (std::is_trivially_copyable_v<T>){
539 shared.ctr_blk = CoAllocate_Unsafe<T>();
540 //Assumed safe because CoAllocate Allocates size T and we're moving in it.
541 memmove(shared.ctr_blk->raw, raw, sizeof(T));
542 }else if constexpr (std::is_move_constructible_v<T>){
543 shared = Shared<T>(std::move(*raw));
544 }else if constexpr (std::is_copy_constructible_v<T>){
545 shared = Shared<T>((const T&)*raw);
546 }
547 reset();
548 //without RVO, this will be a slightly costly. Ctor(inc)->Copy(inc.)->Delete(dec.) will be called.
549 return shared;
550 }
551
557 constexpr inline T* operator->() noexcept{
558 return raw;
559 }
560
565 constexpr inline const T* operator->()const noexcept{
566 return raw;
567 }
568
573 constexpr inline T& operator*() { return *raw;} //this can throw, it's the users responsibility to check for ptr validity.
574
580 constexpr inline const T& operator*() const {return *raw;} //this can throw, it's the users responsibility to check for ptr validity.
581
582 template<typename U>
583 constexpr bool operator==(const Handle<U>& rhs)const noexcept {
584 return this->raw == rhs.raw;
585 }
586
587 template<typename U>
588 constexpr bool operator!=(const Handle<U>& rhs)const noexcept {
589 return rhs.raw != this->raw;
590 }
591 //This is fine and left for simple checks.
592 constexpr inline operator bool()const noexcept{
593 return this->raw;
594 }
595
596 constexpr inline bool operator!() const noexcept { return !this->raw; }
597
598 //Explicitly disallow cast operators
599 operator T*() = delete;
600 operator void*() = delete;
601 };
602
603 template <typename T>
604 class Observer {
605 static_assert(!std::is_reference_v<T>, "Observer<T> cannot be instantiated with a reference type");
606 public:
607 using element_type = T;
608
609 // Constructors
610 constexpr Observer() noexcept = default;
611 constexpr Observer(std::nullptr_t) noexcept : ptr_(nullptr) {}
612
613 constexpr explicit Observer(T* ptr) noexcept : ptr_(ptr) {}
614
615 template <typename U> requires PolymorphicConvertible<U, T>
616 constexpr Observer(U* ptr) noexcept : ptr_(ptr) {}
617
618 // Copy constructor
619 constexpr Observer(const Observer& other) noexcept = default;
620
621 // Converting copy constructor
622 template <typename U> requires PolymorphicConvertible<U, T>
623 constexpr Observer(const Observer<U>& other) noexcept : ptr_(other.get()) {}
624
625 // Assignment
626 constexpr Observer& operator=(const Observer& other) noexcept = default;
627
628 // Converting assignment
629 template <typename U> requires PolymorphicConvertible<U, T>
630 constexpr Observer& operator=(const Observer<U>& other) noexcept {
631 ptr_ = other.get();
632 return *this;
633 }
634
635 // Assignment from pointer
636 constexpr Observer& operator=(T* ptr) noexcept {
637 ptr_ = ptr;
638 return *this;
639 }
640
641 // Modifiers
642 constexpr void reset(T* ptr = nullptr) noexcept { ptr_ = ptr; }
643 constexpr void release() noexcept { ptr_ = nullptr; }
644
645 // Observers
646 constexpr T* get() const noexcept { return ptr_; }
647 constexpr T& operator*() const {
648 assert(ptr_ && "Observer dereference is null");
649 return *ptr_;
650 }
651
652 constexpr T* operator->() const {
653 assert(ptr_ && "Observer dereference is null");
654 return ptr_;
655 }
656
657 constexpr explicit operator bool() const noexcept { return ptr_ != nullptr; }
658
659 // Comparisons
660 constexpr auto operator<=>(const Observer&) const = default;
661
662 template <typename U>
663 constexpr bool operator==(const Observer<U>& other) const noexcept {
664 return ptr_ == other.get();
665 }
666
667 private:
668 T* ptr_ = nullptr;
669 };
670
671 // Deduction guide
672 template <typename T> Handle(T*) -> Handle<T>;
673 template <typename T> Shared(T*) -> Shared<T>;
674 template <typename T> Shared(Weak<T>) -> Shared<T>;
675 template <typename T> Observer(T*) -> Observer<T>;
676
677 // Aliases
678 template <typename T>
680
681}
682
683template<typename T>
684constexpr void swap(Hubris::Handle<T>& lhs, Hubris::Handle<T>& rhs) noexcept {
685 lhs.swap(rhs);
686};
687
688template<typename T, typename U>
690 lhs.swap(rhs);
691}
692
693template<typename T>
694constexpr void swap(Hubris::Shared<T>& lhs, Hubris::Shared<T>& rhs) noexcept {
695 lhs.swap(rhs);
696};
697
698template<typename T, typename U>
700 lhs.swap(rhs);
701}
static unsigned int TotalArenasAllocated() noexcept
static Arena & CreateArena(size_t size)
Creates a thread-local arena.
static bool IsEngineAllocated(const void *pointer)
static size_t ThreadMemoryFreed() noexcept
static size_t GetMemoryAvailable(const Arena &arena)
static bool IsShared(const void *blockptr) noexcept
static void ExpandInternalArena(size_t width)
Internal use. Arenas are not expandable except the internal arena.
static unsigned int ThreadArenasFreed() noexcept
static unsigned int TotalArenasFreed() noexcept
static unsigned int TotalBlockResizeCount() noexcept
static Block Resize(Block &block, size_t newSize)
Attempts to resize a block, this can move the block to a diffrent location.
static unsigned int ThreadDeallocationCount() noexcept
static bool IsValid(const void *pointer)
static unsigned int ThreadArenasAllocated() noexcept
static unsigned int ThreadBlockResizeCount() noexcept
static Arena & CreateGlobalArena(size_t width)
Allocates a shared arena for multi-threaded use.
static size_t MemoryUsed(const Arena &arena)
static unsigned int TotalDeallocationCount() noexcept
static void Free(Block &buffer)
Frees a buffer.
static void FreeArena(Arena)
Attempts to free an areana, if the arean has any blocks in use this call with throw.
static unsigned int ThreadAllocationCount() noexcept
static SharedBlock AllocShared(size_t size)
Allocates a block with syncing constructs.
static size_t TotalMemoryAllocated() noexcept
static bool IsThreadLocal(const Block &block) noexcept
static size_t ThreadMemoryUsed() noexcept
static size_t TotalMemoryFreed() noexcept
static unsigned int TotalAllocationCount() noexcept
static Block Alloc(size_t bufSize)
Allocates a thread-local block.
static bool IsFree(const Block &block) noexcept
constexpr Observer(const Observer &other) noexcept=default
constexpr Observer & operator=(T *ptr) noexcept
Definition Memory.h:636
constexpr Observer & operator=(const Observer &other) noexcept=default
constexpr void reset(T *ptr=nullptr) noexcept
Definition Memory.h:642
constexpr Observer() noexcept=default
constexpr Observer(const Observer< U > &other) noexcept
Definition Memory.h:623
constexpr bool operator==(const Observer< U > &other) const noexcept
Definition Memory.h:663
constexpr T * operator->() const
Definition Memory.h:652
constexpr void release() noexcept
Definition Memory.h:643
constexpr T * get() const noexcept
Definition Memory.h:646
constexpr T & operator*() const
Definition Memory.h:647
constexpr Observer(T *ptr) noexcept
Definition Memory.h:613
constexpr auto operator<=>(const Observer &) const =default
constexpr Observer & operator=(const Observer< U > &other) noexcept
Definition Memory.h:630
constexpr Observer(U *ptr) noexcept
Definition Memory.h:616
The Hubris Engine main namespace.
Definition EventBus.h:4
typename remove_all_pointers< T >::type remove_all_pointers_t
Definition Memory.h:149
consteval size_t padded_size()
Definition Memory.h:169
Observer(T *) -> Observer< T >
void Traverse(T &&container, F &&func)
Definition Memory.h:175
void swap(List< T > &lhs, List< T > &rhs) noexcept
Definition List.h:776
Shared(T *) -> Shared< T >
constexpr void Construct_T_Inplace(void *placement, Args &&...args)
Constructs any object at location (placment new) with the specified arguments.
Definition Memory.h:214
Observer< T > observer_ptr
Definition Memory.h:679
constexpr ControlBlock * CoAllocate(Args &&...args)
Allocates and constructs both the ControlBlock and the Object T and returns the instanciated controlb...
Definition Memory.h:224
constexpr ControlBlock * CoAllocate_Unsafe()
Allocates memory for the ControlBlock and T but does not construct T. This can lead to UB if not used...
Definition Memory.h:189
Handle(T *) -> Handle< T >
size_t Size
Definition Memory.h:40
void * pointer
Definition Memory.h:25
size_t blk_id
Definition Memory.h:24
std::atomic_uint32_t ref_count
Definition Memory.h:162
std::atomic_uint32_t weak_count
Definition Memory.h:163
constexpr Handle(U *other) noexcept
Definition Memory.h:473
constexpr T * get() noexcept
Definition Memory.h:511
constexpr Handle() noexcept=default
constexpr void swap(Handle< U > &rhs) noexcept
Definition Memory.h:530
constexpr T * release() noexcept
Definition Memory.h:525
constexpr bool operator!=(const Handle< U > &rhs) const noexcept
Definition Memory.h:588
constexpr const T * get() const noexcept
Definition Memory.h:512
constexpr bool operator==(const Handle< U > &rhs) const noexcept
Definition Memory.h:583
constexpr T & operator*()
Definition Memory.h:573
Handle & operator=(const Handle &cp)=delete
void reset(T *ptr=nullptr) noexcept
Definition Memory.h:514
Handle(const Handle &cp) noexcept=delete
constexpr Handle(Handle &&mv) noexcept
Definition Memory.h:487
Handle & operator=(Handle< U > &&mv) noexcept
Definition Memory.h:501
constexpr Handle(T *t) noexcept
Definition Memory.h:468
constexpr Handle(Handle< U > &&other) noexcept
Definition Memory.h:482
Shared< T > ToShared()
Definition Memory.h:534
constexpr const T * operator->() const noexcept
Definition Memory.h:565
constexpr const T & operator*() const
Definition Memory.h:580
constexpr T * operator->() noexcept
Definition Memory.h:557
Handle & operator=(Handle &&mv) noexcept
Definition Memory.h:494
constexpr bool operator!() const noexcept
Definition Memory.h:596
~Handle() noexcept
Definition Memory.h:491
Shared blocks are thread shared blocks.
Definition Memory.h:35
constexpr Shared(const Shared< U > &other) noexcept
Definition Memory.h:285
T * operator->()
Unchecked Operation: This is dangerous if the control block is null. That happens only when the Share...
Definition Memory.h:371
constexpr Shared(Weak< T > &&promote) noexcept
Definition Memory.h:277
constexpr T * get() noexcept
Definition Memory.h:362
Shared & operator=(Shared< U > &&mv) noexcept
Definition Memory.h:325
constexpr void swap(Shared< U > &rhs) noexcept
Definition Memory.h:395
void Release()
Definition Memory.h:343
bool Constructed() const noexcept
returns true if the control block has been created
Definition Memory.h:388
uint_fast32_t UseCount() const noexcept
Definition Memory.h:381
T & operator*()
Definition Memory.h:378
constexpr Shared(Shared< U > &&other) noexcept
Definition Memory.h:314
Shared & operator=(const Shared< U > &cpy) noexcept
Definition Memory.h:297
constexpr Shared() noexcept=default
std::remove_cv_t< T > Unqualified
Definition Memory.h:242
const T * get() const noexcept
Definition Memory.h:363
const T * operator->() const
Definition Memory.h:374
~Shared() noexcept
Definition Memory.h:338
const T & operator*() const
Definition Memory.h:379
constexpr Weak(const Shared< T > &s) noexcept
Definition Memory.h:414
bool Expired() const noexcept
Definition Memory.h:432
void Reset() noexcept
Definition Memory.h:436
uint_fast32_t UseCount() const noexcept
Definition Memory.h:450
Shared< T > Lock() const noexcept
Definition Memory.h:427
typename remove_all_pointers< T >::type type
Definition Memory.h:131
typename remove_all_pointers< T >::type type
Definition Memory.h:135
typename remove_all_pointers< T >::type type
Definition Memory.h:145
typename remove_all_pointers< T >::type type
Definition Memory.h:140