LeviLamina
Loading...
Searching...
No Matches
IndirectValue.h
1#pragma once
2
3#include <memory>
4#include <type_traits>
5#include <utility>
6
7#include "ll/api/base/Concepts.h"
8#include "ll/api/data/TightPair.h"
9
10namespace ll::data {
11
12template <class T>
14 constexpr defaultCopy() noexcept = default;
15 constexpr defaultCopy(defaultCopy const&) noexcept {}
16
17 constexpr T* operator()(T const& t) const noexcept { return new T(t); }
18};
19template <class T>
21 using Fn = void*(void const*);
22 Fn* ctor;
23 constexpr polymorphicCopy() noexcept
24 : ctor(+[](void const* t) -> void* { return new T(*reinterpret_cast<T const*>(t)); }) {}
25 template <class U>
26 requires(std::is_convertible_v<U*, T*>)
27 constexpr polymorphicCopy(polymorphicCopy<U> const& other) noexcept : ctor(other.ctor) {}
28
29 T* operator()(T const& t) const noexcept { return reinterpret_cast<T*>(ctor(&t)); }
30};
31template <class T>
33 constexpr virtualCloneCopy() noexcept = default;
34 template <class U>
35 requires(std::is_convertible_v<U*, T*>)
36 constexpr virtualCloneCopy(virtualCloneCopy<U> const&) noexcept {}
37 constexpr T* operator()(T const& t) const noexcept {
38 if constexpr (requires { static_cast<T*>(t.clone()); }) {
39 return static_cast<T*>(t.clone());
40 } else {
41 return static_cast<T*>(t.clone().release());
42 }
43 }
44};
45
46template <class T, class CopyCtor, class Deleter = std::default_delete<T>>
48 template <class U, class C2, class D2>
49 friend class IndirectValue;
50
52
53 constexpr auto& unique() noexcept { return storage.second(); }
54 constexpr auto const& unique() const noexcept { return storage.second(); }
55
56public:
57 constexpr T* get() noexcept { return unique().get(); }
58 constexpr T const* get() const noexcept { return unique().get(); }
59
60 constexpr CopyCtor& getCopyCtor() noexcept { return storage.first(); }
61 constexpr CopyCtor const& getCopyCtor() const noexcept { return storage.first(); }
62
63 constexpr Deleter& getDeleter() noexcept { return unique().get_deleter(); }
64 constexpr Deleter const& getDeleter() const noexcept { return unique().get_deleter(); }
65
66 constexpr T* release() noexcept { return unique().release(); }
67
68 constexpr void reset(T* ptr = nullptr, CopyCtor const& copy = CopyCtor{}) noexcept {
69 getCopyCtor() = copy;
70 return unique().reset(ptr);
71 }
72
73 constexpr explicit operator bool() const noexcept { return get(); }
74
75 template <class... Args>
76 constexpr T& emplace(Args&&... args) {
77 reset(new T(std::forward<Args>(args)...));
78 return *get();
79 }
80
81private:
82 std::unique_ptr<T, Deleter> clone() const noexcept {
83 if (get()) {
84 return std::unique_ptr<T, Deleter>{getCopyCtor()(*get()), getDeleter()};
85 }
86 return std::unique_ptr<T, Deleter>{nullptr, getDeleter()};
87 }
88
89public:
90 constexpr IndirectValue(std::nullptr_t) noexcept : storage(zeroThenVariadicArgs) {}
91
92 constexpr IndirectValue(T* ptr) noexcept : storage(zeroThenVariadicArgs, ptr) {}
93
94 constexpr IndirectValue() noexcept : storage(zeroThenVariadicArgs) {}
95
96 template <class... Args>
97 constexpr IndirectValue(std::in_place_t, Args&&... args)
98 : storage(zeroThenVariadicArgs, new T(std::forward<Args>(args)...)) {}
99
100 constexpr IndirectValue(IndirectValue const& other) noexcept(std::is_nothrow_copy_constructible_v<T>)
101 : storage(oneThenVariadicArgs, other.getCopyCtor(), other.clone()) {}
102
103 template <class U, class C2, class D2>
104 requires(std::is_convertible_v<U*, T*>)
105 constexpr IndirectValue(IndirectValue<U, C2, D2> const& other) noexcept(std::is_nothrow_copy_constructible_v<U>)
106 : storage(oneThenVariadicArgs, other.getCopyCtor(), other.clone()) {}
107
108 constexpr IndirectValue(IndirectValue&& other) noexcept
109 : storage(oneThenVariadicArgs, std::move(other.getCopyCtor()), std::move(other.unique())) {}
110
111 template <class U, class C2, class D2>
112 requires(std::is_convertible_v<U*, T*>)
113 constexpr IndirectValue(IndirectValue<U, C2, D2>&& other) noexcept
114 : storage(oneThenVariadicArgs, std::move(other.getCopyCtor()), std::move(other.unique())) {}
115
116 constexpr IndirectValue& operator=(IndirectValue const& other) noexcept(std::is_nothrow_copy_constructible_v<T>) {
117 if (std::addressof(other) == this) {
118 return *this;
119 }
120 unique() = other.clone();
121 getCopyCtor() = other.getCopyCtor();
122 return *this;
123 }
124 template <class U, class C2, class D2>
125 requires(std::is_convertible_v<U*, T*>)
126 constexpr IndirectValue& operator=(IndirectValue<U, C2, D2> const& other
127 ) noexcept(std::is_nothrow_copy_constructible_v<U>) {
128 if constexpr (std::is_same_v<U, T>) {
129 if (std::addressof(other) == this) {
130 return *this;
131 }
132 }
133 unique() = other.clone();
134 getCopyCtor() = other.getCopyCtor();
135 return *this;
136 }
137
138 constexpr IndirectValue& operator=(IndirectValue&& other) noexcept {
139 if (std::addressof(other) == this) {
140 return *this;
141 }
142 unique() = std::move(other.unique());
143 getCopyCtor() = std::move(other.getCopyCtor());
144 return *this;
145 }
146 template <class U, class C2, class D2>
147 requires(std::is_convertible_v<U*, T*>)
148 constexpr IndirectValue& operator=(IndirectValue<U, C2, D2>&& other) noexcept {
149 if constexpr (std::is_same_v<U, T>) {
150 if (std::addressof(other) == this) {
151 return *this;
152 }
153 }
154 unique() = std::move(other.unique());
155 getCopyCtor() = std::move(other.getCopyCtor());
156 return *this;
157 }
158
159 [[nodiscard]] constexpr T* operator->() noexcept { return get(); }
160 [[nodiscard]] constexpr T const* operator->() const noexcept { return get(); }
161 [[nodiscard]] constexpr T& operator*() & noexcept { return *get(); }
162 [[nodiscard]] constexpr T const& operator*() const& noexcept { return *get(); }
163 [[nodiscard]] constexpr T&& operator*() && noexcept { return std::forward<T>(*get()); }
164 [[nodiscard]] constexpr T const&& operator*() const&& noexcept { return std::forward<T const>(*get()); }
165};
166template <class T, class C, class D>
167[[nodiscard]] constexpr bool operator==(IndirectValue<T, C, D> const& lhs, IndirectValue<T, C, D> const& rhs) {
168 return lhs.get() == rhs.get();
169}
170template <class T, class C, class D>
171[[nodiscard]] constexpr auto operator<=>(IndirectValue<T, C, D> const& lhs, IndirectValue<T, C, D> const& rhs) {
172 return lhs.get() <=> rhs.get();
173}
174template <class T, class C, class D>
175[[nodiscard]] constexpr bool operator==(IndirectValue<T, C, D> const& lhs, std::nullptr_t) {
176 return lhs.get() == nullptr;
177}
178} // namespace ll::data
179
180namespace std {
181template <class T, class C, class D>
182struct hash<::ll::data::IndirectValue<T, C, D>> {
183 std::size_t operator()(::ll::data::IndirectValue<T, C, D> const& value) const { return hash<T*>{}(value.get()); }
184};
185} // namespace std
186
187namespace ll {
188template <class T, class D = std::default_delete<T>>
189using Indirect = data::IndirectValue<T, data::defaultCopy<T>, D>;
190template <
191 class T,
192 class C =
193 std::conditional_t<traits::is_virtual_cloneable_v<T>, data::virtualCloneCopy<T>, data::polymorphicCopy<T>>,
194 class D = std::default_delete<T>>
195using Polymorphic = data::IndirectValue<T, C, D>;
196
197template <class T, class... Args>
198Indirect<T> makeIndirect(Args&&... args) {
199 return Indirect<T>(new T(std::forward<Args>(args)...));
200}
201template <class T, class... Args>
202Polymorphic<T> makePolymorphic(Args&&... args) {
203 return Polymorphic<T>(new T(std::forward<Args>(args)...));
204}
205
206} // namespace ll
Definition IndirectValue.h:47
Definition TightPair.h:13
STL namespace.
Definition IndirectValue.h:13
Definition IndirectValue.h:20
Definition IndirectValue.h:32