StormByte 2.0.0
C++26 foundation of the StormByte suite
 
Loading...
Searching...
No Matches
pointers.hxx
Go to the documentation of this file.
1/*
2 * Copyright (C) 2024-2026 David C. Manuelda (StormBytePP)
3 *
4 * This file is part of StormByte.
5 *
6 * StormByte original source is dual-licensed:
7 *
8 * 1. GNU Lesser General Public License v3.0 (or later)
9 * You may redistribute and/or modify this file under the terms of the
10 * GNU Lesser General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option)
12 * any later version.
13 *
14 * 2. Commercial license
15 * Alternatively, this file may be used under the terms of a commercial
16 * license agreement with the copyright holder
17 * (David C. Manuelda <StormByte@gmail.com>).
18 *
19 * Both licenses apply only to original StormByte source in this repository.
20 * They do not cover other StormByte modules or any third-party material
21 * shipped with this repository (including everything under thirdparty/),
22 * which remains under its own license.
23 *
24 * Neither license grants any patent rights. Any patent licenses required
25 * to use this software or third-party components must be obtained separately
26 * from the patent holders.
27 *
28 * StormByte is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU Lesser General Public License for more details.
32 *
33 * You should have received a copy of the GNU Lesser General Public License
34 * version 3 along with StormByte. If not, see
35 * <https://www.gnu.org/licenses/lgpl-3.0.html>.
36 *
37 * SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-StormByte-Commercial
38 */
39
40#pragma once
41
44
45#include <compare>
46#include <cstddef>
47#include <functional>
48#include <memory>
49#include <type_traits>
50#include <utility>
51
65namespace StormByte {
70 namespace Safe {
71 template<class T>
73
74 template<class T>
76
77 template<class T>
79
87 namespace Heap {
94 STORMBYTE_PUBLIC void* Allocate(std::size_t bytes);
95
100 STORMBYTE_PUBLIC void Free(void* pointer) noexcept;
101
112 template<class U>
113 void operator()(U* pointer) const noexcept {
114 pointer->~U();
115 Free(pointer);
116 }
117 };
118
124 template<typename T>
126 using value_type = T;
127
131 constexpr Allocator() noexcept = default;
132
137 template<typename U>
138 constexpr Allocator(const Allocator<U>&) noexcept {}
139
145 [[nodiscard]] T* allocate(std::size_t count) {
146 return static_cast<T*>(Allocate(count * sizeof(T)));
147 }
148
153 void deallocate(T* pointer, std::size_t) noexcept {
154 Free(pointer);
155 }
156
162 template<typename U>
163 constexpr bool operator==(const Allocator<U>&) const noexcept {
164 return true;
165 }
166 };
167
175 template<class T, class... Args>
176 Shared<T> MakeShared(Args&&... args);
177
185 template<class T, class... Args>
186 Unique<T> MakeUnique(Args&&... args);
187 }
188
205 template<class T>
207 public:
208 using element_type = T;
210
214 Shared() noexcept = default;
215
219 Shared(std::nullptr_t) noexcept {}
220
226 template<class U>
228 Shared(const Shared<U>& other) noexcept: m_ptr(other.m_ptr) {}
229
235 template<class U>
237 Shared(Shared<U>&& other) noexcept: m_ptr(std::move(other.m_ptr)) {}
238
242 Shared(const Shared&) noexcept = default;
243
247 Shared(Shared&&) noexcept = default;
248
254 explicit Shared(const Weak<T>& weak);
255
260 Shared& operator=(const Shared&) noexcept = default;
261
266 Shared& operator=(Shared&&) noexcept = default;
267
271 ~Shared() = default;
272
277 T* get() const noexcept {
278 return m_ptr.get();
279 }
280
285 T& operator*() const {
286 return *m_ptr;
287 }
288
293 T* operator->() const noexcept {
294 return m_ptr.get();
295 }
296
301 explicit operator bool() const noexcept {
302 return static_cast<bool>(m_ptr);
303 }
304
309 operator std::shared_ptr<T>() const noexcept {
310 return m_ptr;
311 }
312
317 long use_count() const noexcept {
318 return m_ptr.use_count();
319 }
320
324 void reset() noexcept {
325 m_ptr.reset();
326 }
327
332 void swap(Shared& other) noexcept {
333 m_ptr.swap(other.m_ptr);
334 }
335
342 template<class U>
343 bool owner_before(const Shared<U>& other) const noexcept {
344 return m_ptr.owner_before(other.m_ptr);
345 }
346
353 template<class U>
354 bool owner_before(const Weak<U>& other) const noexcept;
355
363 template<class Target, class... Args>
365 static Shared<T> MakePointer(Args&&... args) {
366 return Heap::MakeShared<Target>(std::forward<Args>(args)...);
367 }
368
374 friend bool operator==(const Shared& lhs, std::nullptr_t) noexcept {
375 return !lhs.m_ptr;
376 }
377
383 friend bool operator!=(const Shared& lhs, std::nullptr_t) noexcept {
384 return static_cast<bool>(lhs.m_ptr);
385 }
386
392 friend bool operator==(std::nullptr_t, const Shared& rhs) noexcept {
393 return !rhs.m_ptr;
394 }
395
401 friend bool operator!=(std::nullptr_t, const Shared& rhs) noexcept {
402 return static_cast<bool>(rhs.m_ptr);
403 }
404
411 friend bool operator==(const Shared& lhs, const Shared& rhs) noexcept {
412 return lhs.get() == rhs.get();
413 }
414
421 friend auto operator<=>(const Shared& lhs, const Shared& rhs) noexcept {
422 return std::compare_three_way{}(lhs.get(), rhs.get());
423 }
424
430 friend void swap(Shared& left, Shared& right) noexcept {
431 left.swap(right);
432 }
433
434 private:
439 explicit Shared(std::shared_ptr<T> pointer) noexcept: m_ptr(std::move(pointer)) {}
440
444 struct Adopt {
445 explicit constexpr Adopt() noexcept = default;
446 };
447
452 explicit Shared(Adopt, T* object): m_ptr(object, Heap::ObjectDeleter{}, Heap::Allocator<T>{}) {}
453
454 template<class U>
455 friend class Shared;
456
457 template<class U>
458 friend class Weak;
459
460 template<class U, class... Args>
461 friend Shared<U> Heap::MakeShared(Args&&...);
462
463 template<class X, class Y>
464 friend Shared<X> StaticPointerCast(const Shared<Y>&) noexcept;
465
466 template<class X, class Y>
467 friend Shared<X> DynamicPointerCast(const Shared<Y>&) noexcept;
468
469 template<class X, class Y>
470 friend Shared<X> ConstPointerCast(const Shared<Y>&) noexcept;
471
472 template<class X, class Y>
474
475 std::shared_ptr<T> m_ptr;
476 };
477
494 template<class T>
496 public:
497 using element_type = T;
498 using pointer = T*;
500
504 Unique() noexcept = default;
505
509 Unique(std::nullptr_t) noexcept {}
510
516 template<class U>
517 requires Type::SameAs<U, T> || (Type::DerivedFrom<U, T> && std::has_virtual_destructor_v<T>)
518 Unique(Unique<U>&& other) noexcept: m_ptr(std::move(other.m_ptr)) {}
519
523 Unique(const Unique&) = delete;
524
528 Unique(Unique&&) noexcept = default;
529
534 Unique& operator=(const Unique&) = delete;
535
540 Unique& operator=(Unique&&) noexcept = default;
541
545 ~Unique() = default;
546
551 T* get() const noexcept {
552 return m_ptr.get();
553 }
554
559 T& operator*() const {
560 return *m_ptr;
561 }
562
567 T* operator->() const noexcept {
568 return m_ptr.get();
569 }
570
575 explicit operator bool() const noexcept {
576 return static_cast<bool>(m_ptr);
577 }
578
583 operator std::unique_ptr<T, Heap::ObjectDeleter>() && noexcept {
584 return std::move(m_ptr);
585 }
586
592 return m_ptr.get_deleter();
593 }
594
599 const deleter_type& get_deleter() const noexcept {
600 return m_ptr.get_deleter();
601 }
602
606 void reset() noexcept {
607 m_ptr.reset();
608 }
609
614 void swap(Unique& other) noexcept {
615 m_ptr.swap(other.m_ptr);
616 }
617
626 template<class Target, class... Args>
627 requires Type::SameAs<Target, T> || (Type::DerivedFrom<Target, T> && std::has_virtual_destructor_v<T>)
628 static Unique<T> MakePointer(Args&&... args) {
629 return Heap::MakeUnique<Target>(std::forward<Args>(args)...);
630 }
631
637 friend bool operator==(const Unique& lhs, std::nullptr_t) noexcept {
638 return !lhs.m_ptr;
639 }
640
646 friend bool operator!=(const Unique& lhs, std::nullptr_t) noexcept {
647 return static_cast<bool>(lhs.m_ptr);
648 }
649
655 friend bool operator==(std::nullptr_t, const Unique& rhs) noexcept {
656 return !rhs.m_ptr;
657 }
658
664 friend bool operator!=(std::nullptr_t, const Unique& rhs) noexcept {
665 return static_cast<bool>(rhs.m_ptr);
666 }
667
674 friend bool operator==(const Unique& lhs, const Unique& rhs) noexcept {
675 return lhs.get() == rhs.get();
676 }
677
684 friend auto operator<=>(const Unique& lhs, const Unique& rhs) noexcept {
685 return std::compare_three_way{}(lhs.get(), rhs.get());
686 }
687
693 friend void swap(Unique& left, Unique& right) noexcept {
694 left.swap(right);
695 }
696
697 private:
701 struct Adopt {
702 explicit constexpr Adopt() noexcept = default;
703 };
704
709 explicit Unique(Adopt, T* object): m_ptr(object) {}
710
711 template<class U>
712 friend class Unique;
713
714 template<class U, class... Args>
715 friend Unique<U> Heap::MakeUnique(Args&&...);
716
717 std::unique_ptr<T, Heap::ObjectDeleter> m_ptr;
718 };
719
729 template<class T>
731 public:
732 using element_type = T;
733
737 Weak() noexcept = default;
738
742 Weak(std::nullptr_t) noexcept {}
743
749 template<class U>
751 Weak(const Shared<U>& owner) noexcept: m_weak(owner.m_ptr) {}
752
756 Weak(const Weak&) noexcept = default;
757
761 Weak(Weak&&) noexcept = default;
762
767 Weak& operator=(const Weak&) noexcept = default;
768
773 Weak& operator=(Weak&&) noexcept = default;
774
778 ~Weak() = default;
779
784 Shared<T> lock() const noexcept {
785 return Shared<T>(m_weak.lock());
786 }
787
792 bool expired() const noexcept {
793 return m_weak.expired();
794 }
795
800 long use_count() const noexcept {
801 return m_weak.use_count();
802 }
803
807 void reset() noexcept {
808 m_weak.reset();
809 }
810
815 void swap(Weak& other) noexcept {
816 m_weak.swap(other.m_weak);
817 }
818
825 template<class U>
826 bool owner_before(const Weak<U>& other) const noexcept {
827 return m_weak.owner_before(other.m_weak);
828 }
829
836 template<class U>
837 bool owner_before(const Shared<U>& other) const noexcept {
838 return m_weak.owner_before(other.m_ptr);
839 }
840
846 friend void swap(Weak& left, Weak& right) noexcept {
847 left.swap(right);
848 }
849
850 private:
851 template<class U>
852 friend class Weak;
853
854 template<class U>
855 friend class Shared;
856
857 std::weak_ptr<T> m_weak;
858 };
859
867 template<class T, class U>
868 Shared<T> StaticPointerCast(const Shared<U>& from) noexcept {
869 return Shared<T>(std::static_pointer_cast<T>(std::shared_ptr<U>(from)));
870 }
871
879 template<class T, class U>
880 Shared<T> DynamicPointerCast(const Shared<U>& from) noexcept {
881 return Shared<T>(std::dynamic_pointer_cast<T>(std::shared_ptr<U>(from)));
882 }
883
891 template<class T, class U>
892 Shared<T> ConstPointerCast(const Shared<U>& from) noexcept {
893 return Shared<T>(std::const_pointer_cast<T>(std::shared_ptr<U>(from)));
894 }
895
903 template<class T, class U>
905 return Shared<T>(std::reinterpret_pointer_cast<T>(std::shared_ptr<U>(from)));
906 }
907
908 template<class T>
909 Shared<T>::Shared(const Weak<T>& weak): m_ptr(weak.m_weak) {}
910
911 template<class T>
912 template<class U>
913 bool Shared<T>::owner_before(const Weak<U>& other) const noexcept {
914 return m_ptr.owner_before(other.m_weak);
915 }
916 }
917}
918
919
920template<class T>
921struct std::hash<StormByte::Safe::Shared<T>> {
927 std::size_t operator()(const StormByte::Safe::Shared<T>& value) const noexcept {
928 return std::hash<T*>{}(value.get());
929 }
930};
931
932template<class T>
933struct std::hash<StormByte::Safe::Unique<T>> {
939 std::size_t operator()(const StormByte::Safe::Unique<T>& value) const noexcept {
940 return std::hash<T*>{}(value.get());
941 }
942};
943
Shared owner of a T allocated on Base's heap.
Definition pointers.hxx:206
friend Shared< X > ConstPointerCast(const Shared< Y > &) noexcept
Shared(Shared< U > &&other) noexcept
Take ownership from other.
Definition pointers.hxx:237
friend Shared< X > ReinterpretPointerCast(const Shared< Y > &) noexcept
friend Shared< X > DynamicPointerCast(const Shared< Y > &) noexcept
T * operator->() const noexcept
Member access.
Definition pointers.hxx:293
friend bool operator!=(const Shared &lhs, std::nullptr_t) noexcept
Inequality with null.
Definition pointers.hxx:383
T & operator*() const
Dereference.
Definition pointers.hxx:285
friend bool operator==(const Shared &lhs, const Shared &rhs) noexcept
Same stored pointer.
Definition pointers.hxx:411
Shared() noexcept=default
Empty owner.
void swap(Shared &other) noexcept
Exchange owners with other.
Definition pointers.hxx:332
Shared(const Shared &) noexcept=default
Copy constructor.
friend Shared< X > StaticPointerCast(const Shared< Y > &) noexcept
friend auto operator<=>(const Shared &lhs, const Shared &rhs) noexcept
Order of the stored pointers.
Definition pointers.hxx:421
friend bool operator==(std::nullptr_t, const Shared &rhs) noexcept
Equality with null.
Definition pointers.hxx:392
Shared(const Shared< U > &other) noexcept
Share ownership with other.
Definition pointers.hxx:228
bool owner_before(const Shared< U > &other) const noexcept
Ownership order, same as std::shared_ptr::owner_before.
Definition pointers.hxx:343
friend bool operator!=(std::nullptr_t, const Shared &rhs) noexcept
Inequality with null.
Definition pointers.hxx:401
void reset() noexcept
Drop this owner's reference.
Definition pointers.hxx:324
T element_type
Pointee type.
Definition pointers.hxx:208
static Shared< T > MakePointer(Args &&... args)
Allocate Target on Base's heap and own it as T.
Definition pointers.hxx:365
long use_count() const noexcept
Number of Shared sharing this object.
Definition pointers.hxx:317
friend bool operator==(const Shared &lhs, std::nullptr_t) noexcept
Equality with null.
Definition pointers.hxx:374
Shared(Shared &&) noexcept=default
Move constructor.
T * get() const noexcept
Raw pointer, or null.
Definition pointers.hxx:277
friend void swap(Shared &left, Shared &right) noexcept
Exchange left and right.
Definition pointers.hxx:430
Unique owner of a T allocated on Base's heap.
Definition pointers.hxx:495
T * operator->() const noexcept
Member access.
Definition pointers.hxx:567
const deleter_type & get_deleter() const noexcept
Deleter stored in this owner.
Definition pointers.hxx:599
friend auto operator<=>(const Unique &lhs, const Unique &rhs) noexcept
Order of the stored pointers.
Definition pointers.hxx:684
T element_type
Pointee type.
Definition pointers.hxx:497
friend bool operator==(std::nullptr_t, const Unique &rhs) noexcept
Equality with null.
Definition pointers.hxx:655
void reset() noexcept
Destroy the object and drop this owner.
Definition pointers.hxx:606
T * get() const noexcept
Raw pointer, or null.
Definition pointers.hxx:551
friend void swap(Unique &left, Unique &right) noexcept
Exchange left and right.
Definition pointers.hxx:693
void swap(Unique &other) noexcept
Exchange owners with other.
Definition pointers.hxx:614
deleter_type & get_deleter() noexcept
Deleter stored in this owner.
Definition pointers.hxx:591
Unique(Unique< U > &&other) noexcept
Take ownership from other.
Definition pointers.hxx:518
friend bool operator!=(std::nullptr_t, const Unique &rhs) noexcept
Inequality with null.
Definition pointers.hxx:664
friend bool operator!=(const Unique &lhs, std::nullptr_t) noexcept
Inequality with null.
Definition pointers.hxx:646
friend bool operator==(const Unique &lhs, std::nullptr_t) noexcept
Equality with null.
Definition pointers.hxx:637
static Unique< T > MakePointer(Args &&... args)
Allocate Target on Base's heap and own it as T.
Definition pointers.hxx:628
Unique() noexcept=default
Empty owner.
Unique(const Unique &)=delete
Copy constructor.
friend bool operator==(const Unique &lhs, const Unique &rhs) noexcept
Same stored pointer.
Definition pointers.hxx:674
T * pointer
Stored pointer.
Definition pointers.hxx:498
T & operator*() const
Dereference.
Definition pointers.hxx:559
Unique(Unique &&) noexcept=default
Move constructor.
Non-owning observer of a Shared control block.
Definition pointers.hxx:730
bool owner_before(const Shared< U > &other) const noexcept
Ownership order against a Shared.
Definition pointers.hxx:837
void swap(Weak &other) noexcept
Exchange observers with other.
Definition pointers.hxx:815
Weak(const Weak &) noexcept=default
Copy constructor.
friend void swap(Weak &left, Weak &right) noexcept
Exchange left and right.
Definition pointers.hxx:846
void reset() noexcept
Drop this observer.
Definition pointers.hxx:807
bool expired() const noexcept
Whether the object is already gone.
Definition pointers.hxx:792
Weak(const Shared< U > &owner) noexcept
Observe owner.
Definition pointers.hxx:751
Weak() noexcept=default
Empty observer.
Weak(Weak &&) noexcept=default
Move constructor.
long use_count() const noexcept
Number of Shared still holding the object.
Definition pointers.hxx:800
bool owner_before(const Weak< U > &other) const noexcept
Ownership order, same as std::weak_ptr::owner_before.
Definition pointers.hxx:826
T element_type
Pointee type.
Definition pointers.hxx:732
Derived derives from Base (std::is_base_of).
Definition relations.hxx:113
Same type after stripping cv and references from both sides.
Definition relations.hxx:94
void * Allocate(std::size_t bytes)
Allocate bytes on Base's heap.
Unique< T > MakeUnique(Args &&... args)
Construct T on Base's heap and wrap it in Unique.
void Free(void *pointer) noexcept
Release a block obtained from Allocate.
Shared< T > MakeShared(Args &&... args)
Construct T on Base's heap and wrap it in Shared.
Shared< T > ReinterpretPointerCast(const Shared< U > &from) noexcept
reinterpret_cast of the stored pointer.
Definition pointers.hxx:904
Shared< T > ConstPointerCast(const Shared< U > &from) noexcept
const_cast of the stored pointer.
Definition pointers.hxx:892
Shared< T > StaticPointerCast(const Shared< U > &from) noexcept
static_cast of the stored pointer.
Definition pointers.hxx:868
Shared< T > DynamicPointerCast(const Shared< U > &from) noexcept
dynamic_cast of the stored pointer.
Definition pointers.hxx:880
Root namespace of the StormByte suite.
STL namespace.
std::shared_ptr allocator that uses Allocate / Free.
Definition pointers.hxx:125
T * allocate(std::size_t count)
Allocate count objects of T.
Definition pointers.hxx:145
T value_type
Allocator value type.
Definition pointers.hxx:126
constexpr Allocator() noexcept=default
Default constructor.
void deallocate(T *pointer, std::size_t) noexcept
Release storage obtained from allocate.
Definition pointers.hxx:153
constexpr bool operator==(const Allocator< U > &) const noexcept
All Allocator instances compare equal.
Definition pointers.hxx:163
Destroy T and return its block to Free.
Definition pointers.hxx:106
void operator()(U *pointer) const noexcept
Destroy pointer and free its block on Base's heap.
Definition pointers.hxx:113
std::size_t operator()(const StormByte::Safe::Shared< T > &value) const noexcept
Hashes the stored address.
Definition pointers.hxx:927
std::size_t operator()(const StormByte::Safe::Unique< T > &value) const noexcept
Hashes the stored address.
Definition pointers.hxx:939
#define STORMBYTE_PUBLIC_TYPE
Definition visibility.h:57
#define STORMBYTE_PUBLIC
Definition visibility.h:52