Started `boxed::Box<T>`.

Fortune for libexopt's current commit: Future blessing − 末吉
boxed_is_boxed_value
Avril 2 years ago
parent ee3893907c
commit 399ba10c25
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -0,0 +1,86 @@
#pragma once
#include <memory>
#include <utility>
#include "pointer.h"
#include "util.hh"
#include "exopt.h"
namespace exopt::types { namespace boxed {
template<typename T>
struct [[gnu::visibility("internal")]] boxable_value_type { using type = std::conditional_t
<std::is_reference_v<T>
,std::reference_wrapper<std::remove_cvref_t<T> >
,T>; };
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; }
template<typename T>
constexpr std::unique_ptr<T> uniq_clone_unsafe(std::unique_ptr<T> const& c)
#ifndef DEBUG
noexcept(std::is_nothrow_copy_constructible_v<T>)
#endif
requires(std::is_copy_constructible_v<T>)
{ if(__builtin_expect(!bool(c), false))
#ifdef DEBUG
throw ptr::NullException{};
#else
__builtin_unreachable();
#endif
return std::make_unique<T>(*c); }
template<typename T>
struct Box {
typedef boxable_value_type<T>::type type;
constexpr Box() noexcept(std::is_nothrow_default_constructible_v<T>) requires(std::is_default_constructible_v<T>)
: m_ptr{std::make_unique<T>()} {}
template<typename... Args> requires(std::is_constructible_v<T, Args...>)
constexpr Box(Args&&... ctor) noexcept(std::is_nothrow_constructible_v<T, Args...>)
: m_ptr{std::make_unique<T>(std::forward<Args>(ctor)...)} {}
constexpr Box(T&& value) noexcept(std::is_nothrow_constructible_v<T>)
: m_ptr{std::make_unique<T>(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<T>) requires(std::is_copy_constructible_v<T>)
: m_ptr{uniq_clone_unsafe(copy.m_ptr)} {}
constexpr Box& operator=(Box const& copy) noexcept(std::is_nothrow_copy_assignable_v<T>) requires(std::is_copy_assignable_v<T>)
{
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<T> const&[&]`?, etc.
constexpr ~Box() = default;
private:
std::unique_ptr<T> m_ptr; // Unique<T> m_ptr;
};
}
using boxed::Box;
}
namespace exopt::types { namespace optional [[gnu::visibility("internal")]] {
template<typename T>
struct null_optimise<boxed::Box<T> > { constexpr static inline bool value = true;
//XXX: Eh.. Idk if Option<T>'s lifetime design can make this work...
using held_type = boxed::Box<T>;
using type = boxed::Box<T>&;
constexpr static decltype(auto) convert_to_held(std::add_rvalue_reference_t<type> t) noexcept { return std::move(t); }
constexpr static decltype(auto) convert_from_held(std::add_rvalue_reference_t<held_type> t) noexcept { return std::forward<type>(t); }
constexpr static inline T* sentinel = nullptr;
};
}

@ -119,6 +119,26 @@ namespace exopt::types {
} }
//TODO: ^ UNLIKELY(is_empty()) null-checks for `*arg`. //TODO: ^ UNLIKELY(is_empty()) null-checks for `*arg`.
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 { constexpr const_pointer_type get() const noexcept {
return std::visit([](const auto& arg) -> const_pointer_type { return std::visit([](const auto& arg) -> const_pointer_type {
using U = std::remove_cvref_t<decltype(arg)>; using U = std::remove_cvref_t<decltype(arg)>;
@ -127,6 +147,7 @@ namespace exopt::types {
else return arg; else return arg;
}, m_value); }, m_value);
} }
constexpr pointer_type get() noexcept { constexpr pointer_type get() noexcept {
return std::addressof(make_owned()); return std::addressof(make_owned());
/* /*
@ -137,6 +158,7 @@ namespace exopt::types {
else return arg; else return arg;
}, m_value);*/ }, m_value);*/
} }
constexpr reference_type make_owned() & noexcept(NTWriteable) requires(Writeable) { constexpr reference_type make_owned() & noexcept(NTWriteable) requires(Writeable) {
if(const auto* ct_from = std::visit([&m_value](auto& arg) -> auto* { if(const auto* ct_from = std::visit([&m_value](auto& arg) -> auto* {
using U = std::remove_cvref_t<decltype(arg)>; using U = std::remove_cvref_t<decltype(arg)>;
@ -148,6 +170,7 @@ namespace exopt::types {
}, m_value)) return m_value.emplace<value_type>(*ct_from); //XXX: Do we need to create a temporary here for creating invariants by reading the old invariant? }, m_value)) return m_value.emplace<value_type>(*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) { constexpr move_reference_type make_owned() && noexcept(NTWriteable) requires(Writeable) {
if(const auto* ct_from = std::visit([&m_value](auto&& arg) -> auto* { if(const auto* ct_from = std::visit([&m_value](auto&& arg) -> auto* {
using U = std::remove_cvref_t<decltype(arg)>; using U = std::remove_cvref_t<decltype(arg)>;
@ -161,10 +184,10 @@ namespace exopt::types {
}, std::move(m_value))) return std::move(m_value.emplace<value_type>(*ct_from)); //XXX: Do we need to create a temporary here for creating invariants by reading the old invariant? }, std::move(m_value))) return std::move(m_value.emplace<value_type>(*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: &&) //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) { constexpr value_type into_owned() & noexcept(NTWriteable) requires(Writeable) {
return make_owned(); return make_owned();
/*return std::visit([](auto&& arg) -> move_reference_type { /*return std::visit([](auto&& arg) -> move_reference_type {
using U = std::remove_cvref_t<decltype(arg)>; using U = std::remove_cvref_t<decltype(arg)>;
if constexpr(std::is_same_v<U, value_type>) if constexpr(std::is_same_v<U, value_type>)
@ -172,6 +195,7 @@ namespace exopt::types {
else return std::move(*arg); else return std::move(*arg);
}, std::move(m_value));*/ }, std::move(m_value));*/
} }
constexpr move_reference_type into_owned() && noexcept(NTWriteable) requires(Writeable) { constexpr move_reference_type into_owned() && noexcept(NTWriteable) requires(Writeable) {
return make_owned(); return make_owned();
/*return std::move(std::visit([](auto&& arg) -> move_reference_type { /*return std::move(std::visit([](auto&& arg) -> move_reference_type {
@ -194,6 +218,9 @@ namespace exopt::types {
var_t m_value; var_t m_value;
}; };
//template<typename T>
//TODO: We want it to work: class Cow<std::unique_ptr<T>> : public Cow<T> {};
#if 0
template<typename T> template<typename T>
class Cow<std::shared_ptr<T>> { class Cow<std::shared_ptr<T>> {
using var_t = std::variant< using var_t = std::variant<
@ -214,6 +241,7 @@ namespace exopt::types {
private: private:
var_t m_value; var_t m_value;
}; };
#endif
} }
/// Manually lifetime managed Cow<T> /// Manually lifetime managed Cow<T>
@ -222,4 +250,8 @@ namespace exopt::types {
/// RC-lifetime managed Cow<T> /// RC-lifetime managed Cow<T>
template<typename T> template<typename T>
using RcCow = Cow<std::shared_ptr<T>>; using RcCow = Cow<std::shared_ptr<T>>;
/// Boxed unique Cow<T>
template<typename T>
using BoxCow = Cow<std::unique_ptr<T>>;
} }

@ -143,7 +143,7 @@ namespace exopt::ptr {
}; };
template<typename T> requires(!std::is_reference_v<T>) template<typename T> requires(!std::is_reference_v<T>)
struct NonNull final { struct NonNull {
using pointer_type = T*; using pointer_type = T*;
using const_pointer_type = std::remove_cv_t<T> const*; using const_pointer_type = std::remove_cv_t<T> const*;

Loading…
Cancel
Save