From 0f2d186fbd4cc637a359b1d62370174aebd2b80f Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Tue, 1 Oct 2024 23:38:01 +0200 Subject: Some work on maybe_uninit & option --- asl/annotations.hpp | 12 ------------ asl/maybe_uninit.hpp | 41 ++++++++++++++++++++++++++++++----------- asl/maybe_uninit_tests.cpp | 9 ++++++++- asl/option.hpp | 17 +++++++++++++++++ asl/option_tests.cpp | 11 ++++++++++- 5 files changed, 65 insertions(+), 25 deletions(-) (limited to 'asl') 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 -class alignas(align_of) maybe_uninit +class maybe_uninit { - char m_storage[size_of]; + union + { + alignas(align_of) char m_storage[size_of]; + 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) {} + + 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(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(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 - 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) { - 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() == asl::layout::of>()); static_assert(asl::size_of == asl::size_of>); static_assert(asl::align_of == asl::align_of>); -int main() { return 0; } +static_assert(asl::trivially_destructible>); +static_assert(!asl::trivially_destructible>); + +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 class option { + maybe_uninit 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) + { + 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>); +static_assert(!asl::trivially_destructible>); + +int main() +{ + asl::option a; + asl::option b; + return 0; +} -- cgit