Fortune for libexopt's current commit: Future blessing − 末吉boxed_is_boxed_value
parent
ee3893907c
commit
399ba10c25
@ -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;
|
||||
};
|
||||
|
||||
|
||||
}
|
Loading…
Reference in new issue