summaryrefslogtreecommitdiff
path: root/asl/maybe_uninit.hpp
diff options
context:
space:
mode:
authorSteven Le Rouzic <steven.lerouzic@gmail.com>2024-09-06 23:22:18 +0200
committerSteven Le Rouzic <steven.lerouzic@gmail.com>2024-09-06 23:22:18 +0200
commitdef67bba57e7cfdf9942bc2c88a4ce484963f9d2 (patch)
treea0c2024343151166bebc70440e2adb58c611d409 /asl/maybe_uninit.hpp
parentaa427cb5fe7564a85703f14f76f854419274decc (diff)
maybe_uninit
Diffstat (limited to 'asl/maybe_uninit.hpp')
-rw-r--r--asl/maybe_uninit.hpp44
1 files changed, 44 insertions, 0 deletions
diff --git a/asl/maybe_uninit.hpp b/asl/maybe_uninit.hpp
new file mode 100644
index 0000000..ffbbb1c
--- /dev/null
+++ b/asl/maybe_uninit.hpp
@@ -0,0 +1,44 @@
+#pragma once
+
+#include "asl/annotations.hpp"
+#include "asl/layout.hpp"
+#include "asl/memory.hpp"
+#include "asl/meta.hpp"
+
+namespace asl
+{
+
+template<is_object T>
+class alignas(align_of<T>) maybe_uninit
+{
+ char m_storage[size_of<T>];
+
+public:
+ constexpr void* uninit_ptr() const { return m_storage; }
+
+ // @Safety Pointer must only be accessed when in initialized state.
+ constexpr const T* init_ptr(unsafe) const { return reinterpret_cast<const T*>(m_storage); }
+ constexpr T* init_ptr(unsafe) { return reinterpret_cast< T*>(m_storage); }
+
+ // @Safety Reference must only be accessed when in initialized state.
+ constexpr const T& as_init(unsafe) const { return *reinterpret_cast<const T*>(m_storage); }
+ constexpr T& as_init(unsafe) { return *reinterpret_cast< T*>(m_storage); }
+
+ // @Safety Must be called only when in uninitialized state.
+ template<typename... Args>
+ inline void init(unsafe, Args&&... args)
+ {
+ new(uninit_ptr()) T(ASL_FWD(args)...);
+ }
+
+ // @Safety Must be called only when in initialized state.
+ inline void uninit(unsafe)
+ {
+ if constexpr (!trivially_destructible<T>)
+ {
+ init_ptr(unsafe("Caller has checked init state"))->~T();
+ }
+ }
+};
+
+} // namespace asl