diff options
author | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2024-10-01 23:38:01 +0200 |
---|---|---|
committer | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2024-10-01 23:38:01 +0200 |
commit | 0f2d186fbd4cc637a359b1d62370174aebd2b80f (patch) | |
tree | 3852f378c6f25dae63e16355c9cccc8bcffb551c /asl | |
parent | def67bba57e7cfdf9942bc2c88a4ce484963f9d2 (diff) |
Some work on maybe_uninit & option
Diffstat (limited to 'asl')
-rw-r--r-- | asl/annotations.hpp | 12 | ||||
-rw-r--r-- | asl/maybe_uninit.hpp | 41 | ||||
-rw-r--r-- | asl/maybe_uninit_tests.cpp | 9 | ||||
-rw-r--r-- | asl/option.hpp | 17 | ||||
-rw-r--r-- | asl/option_tests.cpp | 11 |
5 files changed, 65 insertions, 25 deletions
diff --git a/asl/annotations.hpp b/asl/annotations.hpp index c0d8f20..90e603f 100644 --- a/asl/annotations.hpp +++ b/asl/annotations.hpp @@ -9,15 +9,3 @@ #else
#define ASL_NO_UNIQUE_ADDRESS [[no_unique_address]]
#endif
-
-namespace asl
-{
-
-struct unsafe
-{
- unsafe() = delete;
- explicit unsafe(auto&&) {}
-};
-
-} // namespace asl
-
diff --git a/asl/maybe_uninit.hpp b/asl/maybe_uninit.hpp index ffbbb1c..19351d5 100644 --- a/asl/maybe_uninit.hpp +++ b/asl/maybe_uninit.hpp @@ -1,42 +1,61 @@ #pragma once
-#include "asl/annotations.hpp"
#include "asl/layout.hpp"
#include "asl/memory.hpp"
#include "asl/meta.hpp"
+#include "asl/utility.hpp"
namespace asl
{
template<is_object T>
-class alignas(align_of<T>) maybe_uninit
+class maybe_uninit
{
- char m_storage[size_of<T>];
+ union
+ {
+ alignas(align_of<T>) char m_storage[size_of<T>];
+ T m_value;
+ };
public:
- constexpr void* uninit_ptr() const { return m_storage; }
+ constexpr maybe_uninit() {} // NOLINT(*-member-init)
+
+ maybe_uninit(const maybe_uninit&) = delete;
+ maybe_uninit(maybe_uninit&&) = delete;
+
+ maybe_uninit& operator=(const maybe_uninit&) = delete;
+ maybe_uninit& operator=(maybe_uninit&&) = delete;
+
+ constexpr ~maybe_uninit() = default;
+ constexpr ~maybe_uninit() requires (!trivially_destructible<T>) {}
+
+ constexpr void* uninit_ptr() && = delete;
+ constexpr const void* uninit_ptr() const& { return m_storage; }
+ constexpr void* uninit_ptr() & { 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); }
+ constexpr T* init_ptr_unsafe() && = delete;
+ constexpr const T* init_ptr_unsafe() const& { return &m_value; }
+ constexpr T* init_ptr_unsafe() & { return &m_value; }
// @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); }
+ constexpr T& as_init_unsafe() && = delete;
+ constexpr const T& as_init_unsafe() const& { return m_value; }
+ constexpr T& as_init_unsafe() & { return m_value; }
// @Safety Must be called only when in uninitialized state.
template<typename... Args>
- inline void init(unsafe, Args&&... args)
+ constexpr 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)
+ constexpr void uninit_unsafe() &
{
if constexpr (!trivially_destructible<T>)
{
- init_ptr(unsafe("Caller has checked init state"))->~T();
+ init_ptr_unsafe()->~T();
}
}
};
diff --git a/asl/maybe_uninit_tests.cpp b/asl/maybe_uninit_tests.cpp index 7efeff0..7584eea 100644 --- a/asl/maybe_uninit_tests.cpp +++ b/asl/maybe_uninit_tests.cpp @@ -1,7 +1,14 @@ #include "asl/maybe_uninit.hpp"
+#include "asl/test_types.hpp"
static_assert(asl::layout::of<int>() == asl::layout::of<asl::maybe_uninit<int>>());
static_assert(asl::size_of<int> == asl::size_of<asl::maybe_uninit<int>>);
static_assert(asl::align_of<int> == asl::align_of<asl::maybe_uninit<int>>);
-int main() { return 0; }
+static_assert(asl::trivially_destructible<asl::maybe_uninit<TriviallyDestructible>>);
+static_assert(!asl::trivially_destructible<asl::maybe_uninit<HasDestructor>>);
+
+int main()
+{
+ return 0;
+}
diff --git a/asl/option.hpp b/asl/option.hpp index e71eb57..4793830 100644 --- a/asl/option.hpp +++ b/asl/option.hpp @@ -1,13 +1,30 @@ #pragma once
#include "asl/meta.hpp"
+#include "asl/maybe_uninit.hpp"
namespace asl
{
+struct nullopt_t {};
+static constexpr nullopt_t nullopt{};
+
template<is_object T>
class option
{
+ maybe_uninit<T> m_payload;
+ bool m_has_value = false;
+
+public:
+ constexpr option() = default;
+ constexpr option(nullopt_t) {} // NOLINT(*-explicit-conversions)
+
+ constexpr ~option() = default;
+ constexpr ~option() requires (!trivially_destructible<T>)
+ {
+ if (m_has_value) { m_payload.uninit_unsafe(); }
+ }
+
};
} // namespace asl
diff --git a/asl/option_tests.cpp b/asl/option_tests.cpp index 41c67e1..ff63e1a 100644 --- a/asl/option_tests.cpp +++ b/asl/option_tests.cpp @@ -1,3 +1,12 @@ #include "asl/option.hpp"
+#include "asl/test_types.hpp"
-int main() { return 0; }
+static_assert(asl::trivially_destructible<asl::option<TriviallyDestructible>>);
+static_assert(!asl::trivially_destructible<asl::option<HasDestructor>>);
+
+int main()
+{
+ asl::option<HasDestructor> a;
+ asl::option<TriviallyDestructible> b;
+ return 0;
+}
|