From 399ba10c25f33010bc2e311383aef988451d1a13 Mon Sep 17 00:00:00 2001 From: Avril Date: Mon, 24 Apr 2023 23:53:11 +0100 Subject: [PATCH] Started `boxed::Box`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fortune for libexopt's current commit: Future blessing − 末吉 --- include/boxed.h | 86 +++++++++++++++++++++++++++++++++++++++++++++++ include/either.hh | 38 +++++++++++++++++++-- include/pointer.h | 2 +- 3 files changed, 122 insertions(+), 4 deletions(-) create mode 100644 include/boxed.h diff --git a/include/boxed.h b/include/boxed.h new file mode 100644 index 0000000..4f65d33 --- /dev/null +++ b/include/boxed.h @@ -0,0 +1,86 @@ + +#pragma once + +#include +#include + +#include "pointer.h" +#include "util.hh" + +#include "exopt.h" + +namespace exopt::types { namespace boxed { + template + struct [[gnu::visibility("internal")]] boxable_value_type { using type = std::conditional_t + + ,std::reference_wrapper > + ,T>; }; + + 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; } + + template + constexpr std::unique_ptr uniq_clone_unsafe(std::unique_ptr const& c) +#ifndef DEBUG + noexcept(std::is_nothrow_copy_constructible_v) +#endif + requires(std::is_copy_constructible_v) + { if(__builtin_expect(!bool(c), false)) +#ifdef DEBUG + throw ptr::NullException{}; +#else + __builtin_unreachable(); +#endif + return std::make_unique(*c); } + + + template + struct Box { + typedef boxable_value_type::type type; + + constexpr Box() noexcept(std::is_nothrow_default_constructible_v) requires(std::is_default_constructible_v) + : m_ptr{std::make_unique()} {} + + template requires(std::is_constructible_v) + constexpr Box(Args&&... ctor) noexcept(std::is_nothrow_constructible_v) + : m_ptr{std::make_unique(std::forward(ctor)...)} {} + + constexpr Box(T&& value) noexcept(std::is_nothrow_constructible_v) + : m_ptr{std::make_unique(std::move(value))} {} + + constexpr Box(Box&&) noexcept = default; + constexpr Box& operator=(Box&&) noexcept = default; + constexpr Box(const Box& copy) noexcept(std::is_nothrow_copy_constructible_v) requires(std::is_copy_constructible_v) + : m_ptr{uniq_clone_unsafe(copy.m_ptr)} {} + constexpr Box& operator=(Box const& copy) noexcept(std::is_nothrow_copy_assignable_v) requires(std::is_copy_assignable_v) + { + if(__builtin_expect(this != std::addressof(copy), true)) { + m_ptr = uniq_clone_unsafe(copy.m_ptr); + } return *this; + } + + //TODO: Accessors, `(explicit?) operator std::unique_ptr const&[&]`?, etc. + + constexpr ~Box() = default; + private: + std::unique_ptr m_ptr; // Unique m_ptr; + }; +} +using boxed::Box; +} + +namespace exopt::types { namespace optional [[gnu::visibility("internal")]] { + template + struct null_optimise > { constexpr static inline bool value = true; + //XXX: Eh.. Idk if Option's lifetime design can make this work... + using held_type = boxed::Box; + using type = boxed::Box&; + constexpr static decltype(auto) convert_to_held(std::add_rvalue_reference_t t) noexcept { return std::move(t); } + constexpr static decltype(auto) convert_from_held(std::add_rvalue_reference_t t) noexcept { return std::forward(t); } + + constexpr static inline T* sentinel = nullptr; + }; + + +} diff --git a/include/either.hh b/include/either.hh index 07aa830..b582c59 100644 --- a/include/either.hh +++ b/include/either.hh @@ -119,7 +119,27 @@ namespace exopt::types { } //TODO: ^ UNLIKELY(is_empty()) null-checks for `*arg`. - constexpr const_pointer_type get() const noexcept { + constexpr reference_type operator*() & noexcept { + return as_ref(); + } + + constexpr move_reference_type operator*() && noexcept { + return as_ref(); + } + + constexpr const_reference_type operator*() const noexcept { + return as_ref(); + } + + constexpr pointer_type operator->() noexcept { + return get(); + } + + constexpr const_pointer_type operator->() noexcept { + return get(); + } + + constexpr const_pointer_type get() const noexcept { return std::visit([](const auto& arg) -> const_pointer_type { using U = std::remove_cvref_t; if constexpr(std::is_same_v) @@ -127,7 +147,8 @@ namespace exopt::types { else return arg; }, m_value); } - constexpr pointer_type get() noexcept { + + constexpr pointer_type get() noexcept { return std::addressof(make_owned()); /* return std::visit([](auto& arg) -> pointer_type { @@ -137,6 +158,7 @@ namespace exopt::types { else return arg; }, m_value);*/ } + constexpr reference_type make_owned() & noexcept(NTWriteable) requires(Writeable) { if(const auto* ct_from = std::visit([&m_value](auto& arg) -> auto* { using U = std::remove_cvref_t; @@ -148,6 +170,7 @@ namespace exopt::types { }, m_value)) return m_value.emplace(*ct_from); //XXX: Do we need to create a temporary here for creating invariants by reading the old invariant? } + constexpr move_reference_type make_owned() && noexcept(NTWriteable) requires(Writeable) { if(const auto* ct_from = std::visit([&m_value](auto&& arg) -> auto* { using U = std::remove_cvref_t; @@ -161,10 +184,10 @@ namespace exopt::types { }, std::move(m_value))) return std::move(m_value.emplace(*ct_from)); //XXX: Do we need to create a temporary here for creating invariants by reading the old invariant? } - //These commented out visits modify the pointee of the borrowed invariant. THIS IS NOT WHAT WE WANT. Instead, we emplace a copy and then copy it again (possibly elided: &) or return it as an rvalue reference (elided: &&) constexpr value_type into_owned() & noexcept(NTWriteable) requires(Writeable) { return make_owned(); + /*return std::visit([](auto&& arg) -> move_reference_type { using U = std::remove_cvref_t; if constexpr(std::is_same_v) @@ -172,6 +195,7 @@ namespace exopt::types { else return std::move(*arg); }, std::move(m_value));*/ } + constexpr move_reference_type into_owned() && noexcept(NTWriteable) requires(Writeable) { return make_owned(); /*return std::move(std::visit([](auto&& arg) -> move_reference_type { @@ -194,6 +218,9 @@ namespace exopt::types { var_t m_value; }; + //template + //TODO: We want it to work: class Cow> : public Cow {}; +#if 0 template class Cow> { using var_t = std::variant< @@ -214,6 +241,7 @@ namespace exopt::types { private: var_t m_value; }; +#endif } /// Manually lifetime managed Cow @@ -222,4 +250,8 @@ namespace exopt::types { /// RC-lifetime managed Cow template using RcCow = Cow>; + + /// Boxed unique Cow + template + using BoxCow = Cow>; } diff --git a/include/pointer.h b/include/pointer.h index be2c384..1604c44 100644 --- a/include/pointer.h +++ b/include/pointer.h @@ -143,7 +143,7 @@ namespace exopt::ptr { }; template requires(!std::is_reference_v) - struct NonNull final { + struct NonNull { using pointer_type = T*; using const_pointer_type = std::remove_cv_t const*;