optional: Started impl for `null_optimise<Box<T>>::held_type` and `::convert_{to/from}_held()`s

Fortune for libexopt's current commit: Future small blessing − 末小吉
lean
Avril 12 months ago
parent 65c6617627
commit a5cf2c0fef
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -20,7 +20,7 @@ namespace exopt::types { namespace boxed {
template<typename T>
constexpr std::unique_ptr<T> uniq_clone(std::unique_ptr<T> const& c) noexcept(std::is_nothrow_copy_constructible_v<T>) requires(std::is_copy_constructible_v<T>)
{ if(__builtin_expect(bool(c), true)) return std::make_unique<T>(*c); return nullptr; }
{ if(__builtin_expect(bool(c), true)) return std::make_unique<T>(*c); return { nullptr }; }
template<typename T>
constexpr std::unique_ptr<T> uniq_clone_unsafe(std::unique_ptr<T> const& c)
@ -259,6 +259,9 @@ namespace exopt::types { namespace boxed {
constexpr Box(util::exact_type<unsafe_t> auto u, std::unique_ptr<T>&& ptr) noexcept
: m_ptr(std::move(ptr)) { (void)u; }
constexpr Box(util::exact_type<unsafe_t> auto u, Box const& copy) noexcept
: m_ptr(uniq_clone(copy.as_unique(u))) {}
constexpr static Box<T> from_raw_ptr(unsafe_t u, std::unique_ptr<T>&& uniq) noexcept {
return Box{u, std::move(uniq)};
}

@ -39,8 +39,55 @@ namespace exopt::types { namespace optional [[gnu::visibility("internal")]] {
class null_optimise<boxed::Box<T> > {
using boxed::Box;
using box_t = Box<T>;
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<box_t *>(this); }
constexpr box_t const& operator*() const& noexcept { return *static_assert<box_t const*>(this); }
constexpr box_t&& operator*() && noexcept { return std::move(*static_assert<box_t *>(this)); }
constexpr box_t const&& operator*() const&& noexcept { return std::move(*static_assert<box_t const*>(this)); }
constexpr static invariant&& back_conv(box_t&& b) noexcept { return static_cast<invariant&&>(b); }
constexpr static invariant const& back_conv(box_t const& b) noexcept { return static_cast<invariant const&>(b); }
constexpr static invariant& back_conv(box_t& b) noexcept { return static_cast<invariant&>(b); }
constexpr static invariant const&& back_conv(box_t const&& b) noexcept { return static_cast<invariant const&&>(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<T>&& m) noexcept
: box_t(UNSAFE, std::move(m)) {}
constexpr invariant(std::nullptr_t) noexcept
: box_t(UNSAFE, std::unique_ptr<T> { 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, box_t>, "invariant (held_type) does not share layout with viewed type (Box<T>)");
@ -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<T>: 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;

Loading…
Cancel
Save