mitteLib
Loading...
Searching...
No Matches
any_of.hpp
Go to the documentation of this file.
1//
2// Created by spak on 2/9/21.
3//
4
5#ifndef MLAB_ANY_OF_HPP
6#define MLAB_ANY_OF_HPP
7
8#include <cassert>
9#include <cstdint>
10#include <mlab/log.hpp>
11#include <type_traits>
12#include <utility>
13
14namespace mlab {
15
16 template <class Enum, template <Enum> class T, Enum Default = Enum{}>
17 class any_of {
18 public:
19 template <Enum E>
20 using value_type = T<E>;
21 using enum_type = Enum;
22 static constexpr enum_type default_type = Default;
23
25
26 template <enum_type E>
27 any_of(T<E> obj);
28
29 any_of(any_of &&other) noexcept;
30
31 any_of &operator=(any_of &&other) noexcept;
32
33 any_of(any_of const &) = delete;
34
35 any_of &operator=(any_of const &) = delete;
36
38
39 [[nodiscard]] enum_type type() const;
40
41 template <enum_type E>
42 [[nodiscard]] T<E> const &get() const;
43
44 template <enum_type E>
45 [[nodiscard]] T<E> &get();
46
47 template <enum_type E>
48 any_of &operator=(T<E> obj);
49
50 protected:
71 explicit any_of(enum_type e);
72
73 template <enum_type E, class U>
74 void set(U &&obj);
75
76 private:
80 using deleter_type = void (*)(void *);
81
86 template <enum_type E>
87 static constexpr bool can_be_stored_in_place_v =
88 sizeof(T<E>) <= sizeof(std::uintptr_t) and (alignof(std::uintptr_t) % alignof(T<E>)) == 0 and std::is_trivial_v<T<E>>;
89
96 std::uintptr_t _storage{};
98
103 template <enum_type E>
104 static void default_deleter_fn(void *ptr);
105
106 template <enum_type E>
107 [[nodiscard]] static constexpr deleter_type get_default_deleter();
108
112 [[nodiscard]] bool holds_memory() const;
113
116
117
122 void free();
123
131 [[nodiscard]] [[maybe_unused]] void const *storage_allocated() const;
132
137 [[nodiscard]] [[maybe_unused]] void *&storage_allocated();
138
152 [[nodiscard]] [[maybe_unused]] void const *storage_in_place() const;
153
154 [[nodiscard]] [[maybe_unused]] void *storage_in_place();
155
159 };
160}// namespace mlab
161
162namespace mlab {
163
164 template <class Enum, template <Enum> class T, Enum Default>
166 *this = std::move(other);
167 }
168
169 template <class Enum, template <Enum> class T, Enum Default>
171 if (&other != this) {
172 std::swap(_deleter, other._deleter);
173 std::swap(_storage, other._storage);
174 std::swap(_active, other._active);
175 }
176 return *this;
177 }
178
179 template <class Enum, template <Enum> class T, Enum Default>
180 any_of<Enum, T, Default>::any_of(enum_type e) : _active{e}, _storage{}, _deleter{nullptr} {}
181
182 template <class Enum, template <Enum> class T, Enum Default>
183 template <Enum E>
185 set<E>(std::move(obj));
186 }
187
188 template <class Enum, template <Enum> class T, Enum Default>
190
191 template <class Enum, template <Enum> class T, Enum Default>
195
196 template <class Enum, template <Enum> class T, Enum Default>
198 return _active;
199 }
200
201 template <class Enum, template <Enum> class T, Enum Default>
202 template <Enum E>
203 T<E> const &any_of<Enum, T, Default>::get() const {
204 assert_type_is(E);
205 if constexpr (can_be_stored_in_place_v<E>) {
206 return *reinterpret_cast<T<E> const *>(storage_in_place());
207 } else {
208 assert_holds_memory();
209 return *reinterpret_cast<T<E> const *>(storage_allocated());
210 }
211 }
212
213 template <class Enum, template <Enum> class T, Enum Default>
214 template <Enum E>
216 assert_type_is(E);
217 if constexpr (can_be_stored_in_place_v<E>) {
218 return *reinterpret_cast<T<E> *>(storage_in_place());
219 } else {
220 assert_holds_memory();
221 return *reinterpret_cast<T<E> *>(storage_allocated());
222 }
223 }
224
225 template <class Enum, template <Enum> class T, Enum Default>
226 template <Enum E>
228 set<E>(std::move(obj));
229 return *this;
230 }
231
232
233 template <class Enum, template <Enum> class T, Enum Default>
234 template <Enum E, class U>
236 if constexpr (can_be_stored_in_place_v<E>) {
237 // Make sure the memory that may have been allocated by other T<E>s is freed, we will use the storage in place
238 free();
239 // Can call trivial assignment operator
240 *reinterpret_cast<T<E> *>(storage_in_place()) = std::forward<U>(obj);
241 _active = E;
242 } else {
243 // It is critical to check that memory is being held before actually getting that pointer
244 if (type() == E and holds_memory()) {
245 // Can call assignment operator
246 *reinterpret_cast<T<E> *>(storage_allocated()) = std::forward<U>(obj);
247 } else {
248 // We must allocate the memory anew, because the E in T<E> changed or we are being called in the cctor
249 free();
250 storage_allocated() = new T<E>(std::forward<U>(obj));
251 _deleter = get_default_deleter<E>();
252 _active = E;
253 }
254 }
255 }
256
257
258 template <class Enum, template <Enum> class T, Enum Default>
260 if (type() != e) {
261 LOGE("MLAB", "any_of holds <type %d>, cannot get reference to <type %d>.",
262 static_cast<unsigned>(type()), static_cast<unsigned>(e));
263 std::abort();
264 }
265 }
266
267 template <class Enum, template <Enum> class T, Enum Default>
269 if (not holds_memory()) {
270 LOGE("MLAB", "any_of is empty, cannot get reference.");
271 std::abort();
272 }
273 }
274
275 template <class Enum, template <Enum> class T, Enum Default>
277 // Deleter is defined only if we stored a pointer
278 if (holds_memory()) {
279 assert(_deleter);
280 _deleter(storage_allocated());
281 _deleter = nullptr;
282 }
283 // Always set this to nullptr so we being with a consistent state
284 storage_allocated() = nullptr;
285 }
286
287 template <class Enum, template <Enum> class T, Enum Default>
288 template <Enum E>
290 return &default_deleter_fn<E>;
291 }
292
293 template <class Enum, template <Enum> class T, Enum Default>
294 template <Enum E>
296 auto *typed_ptr = reinterpret_cast<T<E> *>(ptr);
297 delete typed_ptr;
298 }
299
300 template <class Enum, template <Enum> class T, Enum Default>
302 return _deleter != nullptr;
303 }
304
305 template <class Enum, template <Enum> class T, Enum Default>
307 return *reinterpret_cast<void const *const *>(&_storage);
308 }
309
310 template <class Enum, template <Enum> class T, Enum Default>
312 return *reinterpret_cast<void **>(&_storage);
313 }
314
315 template <class Enum, template <Enum> class T, Enum Default>
317 return reinterpret_cast<void const *>(&_storage);
318 }
319
320 template <class Enum, template <Enum> class T, Enum Default>
322 return reinterpret_cast<void *>(&_storage);
323 }
324}// namespace mlab
325
326#endif//MLAB_ANY_OF_HPP
Definition any_of.hpp:17
any_of(any_of const &)=delete
Enum enum_type
Definition any_of.hpp:21
any_of(T< E > obj)
Definition any_of.hpp:184
any_of(any_of &&other) noexcept
Definition any_of.hpp:165
any_of & operator=(any_of const &)=delete
any_of()
Definition any_of.hpp:189
any_of(enum_type e)
Definition any_of.hpp:180
static constexpr enum_type default_type
Definition any_of.hpp:22
void(*)(void *) deleter_type
Definition any_of.hpp:80
void free()
Definition any_of.hpp:276
T< E > & get()
Definition any_of.hpp:215
T< E > value_type
Definition any_of.hpp:20
static constexpr deleter_type get_default_deleter()
Definition any_of.hpp:289
~any_of()
Definition any_of.hpp:192
static constexpr bool can_be_stored_in_place_v
Definition any_of.hpp:87
void set(U &&obj)
Definition any_of.hpp:235
void assert_holds_memory() const
Definition any_of.hpp:268
any_of & operator=(T< E > obj)
void assert_type_is(enum_type e) const
Definition any_of.hpp:259
enum_type type() const
Definition any_of.hpp:197
any_of & operator=(any_of &&other) noexcept
Definition any_of.hpp:170
T< E > const & get() const
bool holds_memory() const
Definition any_of.hpp:301
static void default_deleter_fn(void *ptr)
Definition any_of.hpp:295
deleter_type _deleter
Definition any_of.hpp:97
enum_type _active
Definition any_of.hpp:95
std::uintptr_t _storage
Definition any_of.hpp:96
void const * storage_allocated() const
Definition any_of.hpp:306
void *& storage_allocated()
Definition any_of.hpp:311
void * storage_in_place()
Definition any_of.hpp:321
void const * storage_in_place() const
Definition any_of.hpp:316
#define LOGE(tag, format,...)
Definition log.hpp:35
Definition log.cpp:8
result_content
Definition result.hpp:15