diff --git a/include/boxed.h b/include/boxed.h index be33ea5..3ac9697 100644 --- a/include/boxed.h +++ b/include/boxed.h @@ -20,7 +20,7 @@ namespace exopt::types { namespace boxed { template constexpr std::unique_ptr uniq_clone(std::unique_ptr const& c) noexcept(std::is_nothrow_copy_constructible_v) requires(std::is_copy_constructible_v) - { if(__builtin_expect(bool(c), true)) return std::make_unique(*c); return nullptr; } + { if(__builtin_expect(bool(c), true)) return std::make_unique(*c); return { nullptr }; } template constexpr std::unique_ptr uniq_clone_unsafe(std::unique_ptr const& c) @@ -259,6 +259,9 @@ namespace exopt::types { namespace boxed { constexpr Box(util::exact_type auto u, std::unique_ptr&& ptr) noexcept : m_ptr(std::move(ptr)) { (void)u; } + constexpr Box(util::exact_type auto u, Box const& copy) noexcept + : m_ptr(uniq_clone(copy.as_unique(u))) {} + constexpr static Box from_raw_ptr(unsafe_t u, std::unique_ptr&& uniq) noexcept { return Box{u, std::move(uniq)}; } diff --git a/include/optional.h b/include/optional.h index fef68cc..4048b27 100644 --- a/include/optional.h +++ b/include/optional.h @@ -39,8 +39,55 @@ namespace exopt::types { namespace optional [[gnu::visibility("internal")]] { class null_optimise > { using boxed::Box; using box_t = Box; - struct /*XXX: Shouldn't be needed alignas(box_t)*/ invariant : box_t { + class /*XXX: Shouldn't be needed alignas(box_t)*/ invariant : box_t { //TODO: See phone notes. + using box_t::UNSAFE; + public: + constexpr box_t& operator*() & noexcept { return *static_assert(this); } + constexpr box_t const& operator*() const& noexcept { return *static_assert(this); } + constexpr box_t&& operator*() && noexcept { return std::move(*static_assert(this)); } + constexpr box_t const&& operator*() const&& noexcept { return std::move(*static_assert(this)); } + + constexpr static invariant&& back_conv(box_t&& b) noexcept { return static_cast(b); } + constexpr static invariant const& back_conv(box_t const& b) noexcept { return static_cast(b); } + + constexpr static invariant& back_conv(box_t& b) noexcept { return static_cast(b); } + constexpr static invariant const&& back_conv(box_t const&& b) noexcept { return static_cast(b); } + + constexpr invariant(box_t&& m) noexcept + : box_t(UNSAFE, std::move(std::move(m).as_unique(UNSAFE))) {} + constexpr invariant(box_t const& m) noexcept + : box_t(UNSAFE, m) {} + + constexpr invariant(std::unique_ptr&& m) noexcept + : box_t(UNSAFE, std::move(m)) {} + + constexpr invariant(std::nullptr_t) noexcept + : box_t(UNSAFE, std::unique_ptr { nullptr } ) {} + + constexpr friend auto operator<=>(invariant const& a, invariant const& b) noexcept { return (*a).as_unsafe_ptr(UNSAFE) <=> (*b).as_unsafe_ptr(UNSAFE); } + constexpr friend auto operator<=>(invariant const& a, box_t const& b) noexcept { return (*a).as_unsafe_ptr(UNSAFE) <=> b.as_unsafe_ptr(UNSAFE); } + constexpr friend auto operator<=>(invariant const& a, T const* p) noexcept { return (*a).as_unsafe_ptr(UNSAFE) <=> p; } + constexpr friend auto operator<=>(invariant const& a, std::nullptr_t) noexcept { return (*a).as_unsafe_ptr(UNSAFE) <=> nullptr; } + + constexpr invariant& operator=(box_t &&) noexcept = delete; + constexpr invariant& operator=(box_t const&) = delete; + + constexpr invariant& operator=(invariant &&) noexcept = default; + constexpr invariant& operator=(invariant const&) = default; + + + constexpr invariant& operator=(std::nullptr_t) + { box_t::as_unique(UNSAFE).reset(); return *this; } + + constexpr invariant& operator=(T* const&& p) + { box_t::as_unique(UNSAFE).reset(p); return *this; } + + constexpr invariant(invariant&& m) noexcept + : invariant( std::move((*std::move(m)).as_unique(UNSAFE)) ) {} + constexpr invariant(invariant const& m) noexcept + : box_t(UNSAFE, (*m).as_unique(UNSAFE)) {} + constexpr ~invariant() = default; }; static_assert(util::shares_layout, "invariant (held_type) does not share layout with viewed type (Box)"); @@ -48,6 +95,16 @@ namespace exopt::types { namespace optional [[gnu::visibility("internal")]] { typedef invariant held_type; // invariant ^: Held internal type. using type = box_t; // Box: API seen & operated on type + constexpr static decltype(auto) convert_to_held(type ty) noexcept { return held_type{std::move(ty)}; } + constexpr static decltype(auto) convert_to_held(type& ty) noexcept { return held_type::back_conv(ty); } + constexpr static decltype(auto) convert_to_held(type&& ty) noexcept { return held_type::back_conv(std::move(ty)); } + constexpr static decltype(auto) convert_to_held(type const& ty) noexcept { return held_type::back_conv(ty); } + constexpr static decltype(auto) convert_to_held(type const&& ty) noexcept { return held_type::back_conv(std::move(ty)); } + + constexpr static type& convert_from_held(held_type& ty) noexcept { return *ty; } + constexpr static type const&& convert_from_held(held_type const&& ty) noexcept { return std::move(*std::move(ty)); } + constexpr static type&& convert_from_held(held_type&& ty) noexcept { return std::move(*std::move(ty)); } + constexpr static type const& convert_from_held(held_type const& ty) noexcept { return *ty; } //TODO: See phone notes. constexpr static inline auto sentinel = nullptr;