Fix a few mistakes in option, and make it trivial when possible
This commit is contained in:
@ -16,7 +16,7 @@ class box
|
|||||||
ASL_NO_UNIQUE_ADDRESS Allocator m_alloc;
|
ASL_NO_UNIQUE_ADDRESS Allocator m_alloc;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit constexpr box(niche)
|
explicit constexpr box(niche_t)
|
||||||
requires default_constructible<Allocator>
|
requires default_constructible<Allocator>
|
||||||
: m_ptr{nullptr}
|
: m_ptr{nullptr}
|
||||||
, m_alloc{}
|
, m_alloc{}
|
||||||
@ -78,7 +78,7 @@ public:
|
|||||||
return m_ptr;
|
return m_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool operator==(niche) const
|
constexpr bool operator==(niche_t) const
|
||||||
{
|
{
|
||||||
return m_ptr == nullptr;
|
return m_ptr == nullptr;
|
||||||
}
|
}
|
||||||
|
@ -1,60 +1,72 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "asl/layout.hpp"
|
|
||||||
#include "asl/memory.hpp"
|
|
||||||
#include "asl/meta.hpp"
|
#include "asl/meta.hpp"
|
||||||
#include "asl/utility.hpp"
|
#include "asl/utility.hpp"
|
||||||
|
#include "asl/memory.hpp"
|
||||||
|
|
||||||
namespace asl
|
namespace asl
|
||||||
{
|
{
|
||||||
|
|
||||||
template<is_object T>
|
template<is_object T>
|
||||||
class maybe_uninit
|
union maybe_uninit
|
||||||
{
|
{
|
||||||
union
|
private:
|
||||||
{
|
T m_value;
|
||||||
alignas(align_of<T>) char m_storage[size_of<T>];
|
|
||||||
T m_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr maybe_uninit() {} // NOLINT(*-member-init)
|
constexpr maybe_uninit() requires trivially_default_constructible<T> = default;
|
||||||
|
constexpr maybe_uninit() requires (!trivially_default_constructible<T>) {} // NOLINT
|
||||||
|
|
||||||
maybe_uninit(const maybe_uninit&) = delete;
|
|
||||||
maybe_uninit(maybe_uninit&&) = delete;
|
|
||||||
|
|
||||||
maybe_uninit& operator=(const maybe_uninit&) = delete;
|
|
||||||
maybe_uninit& operator=(maybe_uninit&&) = delete;
|
|
||||||
|
|
||||||
constexpr ~maybe_uninit() = default;
|
|
||||||
constexpr ~maybe_uninit() requires (!trivially_destructible<T>) {}
|
|
||||||
|
|
||||||
constexpr void* uninit_ptr() && = delete;
|
|
||||||
constexpr const void* uninit_ptr() const& { return m_storage; }
|
|
||||||
constexpr void* uninit_ptr() & { return m_storage; }
|
|
||||||
|
|
||||||
// @Safety Pointer must only be accessed when in initialized state.
|
|
||||||
constexpr T* init_ptr_unsafe() && = delete;
|
|
||||||
constexpr const T* init_ptr_unsafe() const& { return &m_value; }
|
|
||||||
constexpr T* init_ptr_unsafe() & { return &m_value; }
|
|
||||||
|
|
||||||
// @Safety Reference must only be accessed when in initialized state.
|
|
||||||
constexpr T&& as_init_unsafe() && { return ASL_MOVE(m_value); }
|
|
||||||
constexpr const T& as_init_unsafe() const& { return m_value; }
|
|
||||||
constexpr T& as_init_unsafe() & { return m_value; }
|
|
||||||
|
|
||||||
// @Safety Must be called only when in uninitialized state.
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
constexpr void init_unsafe(Args&&... args) &
|
explicit constexpr maybe_uninit(in_place_t, Args&&... args)
|
||||||
|
requires constructible_from<T, Args&&...>
|
||||||
|
: m_value{ASL_FWD(args)...}
|
||||||
|
{}
|
||||||
|
|
||||||
|
constexpr maybe_uninit(const maybe_uninit&) requires trivially_copy_constructible<T> = default;
|
||||||
|
constexpr maybe_uninit(const maybe_uninit&) requires (!trivially_copy_constructible<T>) {} // NOLINT
|
||||||
|
|
||||||
|
constexpr maybe_uninit(maybe_uninit&&) requires trivially_move_constructible<T> = default;
|
||||||
|
constexpr maybe_uninit(maybe_uninit&&) requires (!trivially_move_constructible<T>) {} // NOLINT
|
||||||
|
|
||||||
|
constexpr maybe_uninit& operator=(const maybe_uninit&) requires trivially_copy_assignable<T> = default;
|
||||||
|
constexpr maybe_uninit& operator=(const maybe_uninit&) requires (!trivially_copy_assignable<T>) {}
|
||||||
|
|
||||||
|
constexpr maybe_uninit& operator=(maybe_uninit&&) requires trivially_move_assignable<T> = default;
|
||||||
|
constexpr maybe_uninit& operator=(maybe_uninit&&) requires (!trivially_move_assignable<T>) {}
|
||||||
|
|
||||||
|
constexpr ~maybe_uninit() requires trivially_destructible<T> = default;
|
||||||
|
constexpr ~maybe_uninit() requires (!trivially_destructible<T>) {} // NOLINT
|
||||||
|
|
||||||
|
// @Safety Value must not have been initialized yet
|
||||||
|
template<typename... Args>
|
||||||
|
constexpr void construct_unsafe(Args&&... args)
|
||||||
|
requires constructible_from<T, Args&&...>
|
||||||
{
|
{
|
||||||
construct_at<T>(uninit_ptr(), ASL_FWD(args)...);
|
construct_at<T>(&m_value, ASL_FWD(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Safety Must be called only when in initialized state.
|
// @Safety Value must have been initialized
|
||||||
constexpr void uninit_unsafe() &
|
template<typename U>
|
||||||
|
constexpr void assign_unsafe(U&& value)
|
||||||
|
requires assignable_from<T&, U&&>
|
||||||
{
|
{
|
||||||
destroy(init_ptr_unsafe());
|
m_value = ASL_FWD(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Safety Value must have been initialized
|
||||||
|
constexpr void destroy_unsafe()
|
||||||
|
{
|
||||||
|
if constexpr (!trivially_destructible<T>)
|
||||||
|
{
|
||||||
|
destroy(&m_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Safety Value must have been initialized
|
||||||
|
constexpr const T& as_init_unsafe() const& { return m_value; }
|
||||||
|
constexpr T& as_init_unsafe() & { return m_value; }
|
||||||
|
constexpr T&& as_init_unsafe() && { return ASL_MOVE(m_value); }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
12
asl/meta.hpp
12
asl/meta.hpp
@ -190,7 +190,7 @@ template<> struct _is_integer_helper<uint64_t> : true_type {};
|
|||||||
template<typename T> concept is_integer = _is_integer_helper<un_cv_t<T>>::value;
|
template<typename T> concept is_integer = _is_integer_helper<un_cv_t<T>>::value;
|
||||||
|
|
||||||
template<typename T, typename U>
|
template<typename T, typename U>
|
||||||
concept equality_comparable_with = requires (const un_cvref_t<T>& a, const un_cvref_t<T>& b)
|
concept equality_comparable_with = requires (const un_cvref_t<T>& a, const un_cvref_t<U>& b)
|
||||||
{
|
{
|
||||||
{ a == b } -> same_as<bool>;
|
{ a == b } -> same_as<bool>;
|
||||||
{ b == a } -> same_as<bool>;
|
{ b == a } -> same_as<bool>;
|
||||||
@ -200,16 +200,12 @@ concept equality_comparable_with = requires (const un_cvref_t<T>& a, const un_cv
|
|||||||
|
|
||||||
template<typename T> concept equality_comparable = equality_comparable_with<T, T>;
|
template<typename T> concept equality_comparable = equality_comparable_with<T, T>;
|
||||||
|
|
||||||
struct niche {};
|
struct niche_t {};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept has_niche = constructible_from<T, niche> &&
|
concept has_niche = constructible_from<T, niche_t> && equality_comparable_with<T, niche_t>;
|
||||||
requires (const T& value, niche n)
|
|
||||||
{
|
|
||||||
{ value == n } -> same_as<bool>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
concept is_niche = same_as<un_cvref_t<T>, niche>;
|
concept is_niche = same_as<un_cvref_t<T>, niche_t>;
|
||||||
|
|
||||||
} // namespace asl
|
} // namespace asl
|
||||||
|
249
asl/option.hpp
249
asl/option.hpp
@ -22,34 +22,24 @@ namespace option_internal
|
|||||||
{
|
{
|
||||||
|
|
||||||
template<typename T, typename U>
|
template<typename T, typename U>
|
||||||
concept convertible_from_option =
|
concept not_constructible_from_option =
|
||||||
convertible_from<T, option<U>&> &&
|
!constructible_from<T, option<U>&> &&
|
||||||
convertible_from<T, const option<U>&> &&
|
!constructible_from<T, const option<U>&> &&
|
||||||
convertible_from<T, option<U>&&> &&
|
!constructible_from<T, option<U>&&> &&
|
||||||
convertible_from<T, const option<U>&&>;
|
!constructible_from<T, const option<U>&&>;
|
||||||
|
|
||||||
template<typename T, typename U>
|
template<typename T, typename U>
|
||||||
concept constructible_from_option =
|
concept not_assignable_from_option =
|
||||||
constructible_from<T, option<U>&> &&
|
!assignable_from<T&, option<U>&> &&
|
||||||
constructible_from<T, const option<U>&> &&
|
!assignable_from<T&, const option<U>&> &&
|
||||||
constructible_from<T, option<U>&&> &&
|
!assignable_from<T&, option<U>&&> &&
|
||||||
constructible_from<T, const option<U>&&>;
|
!assignable_from<T&, const option<U>&&>;
|
||||||
|
|
||||||
template<typename T, typename U>
|
|
||||||
concept assignable_from_option =
|
|
||||||
assignable_from<T&, option<U>&> &&
|
|
||||||
assignable_from<T&, const option<U>&> &&
|
|
||||||
assignable_from<T&, option<U>&&> &&
|
|
||||||
assignable_from<T&, const option<U>&&>;
|
|
||||||
|
|
||||||
template<typename T, typename U>
|
|
||||||
concept convertible_constructible_from_option =
|
|
||||||
convertible_from_option<T, U> && constructible_from_option<T, U>;
|
|
||||||
|
|
||||||
|
|
||||||
template<typename T, typename U>
|
template<typename T, typename U>
|
||||||
concept convertible_constructible_assignable_from_option =
|
concept not_constructible_assignable_from_option =
|
||||||
convertible_constructible_from_option<T, U> && assignable_from_option<T, U>;
|
not_constructible_from_option<T, U> &&
|
||||||
|
not_assignable_from_option<T, U>;
|
||||||
|
|
||||||
} // namespace option_internal
|
} // namespace option_internal
|
||||||
|
|
||||||
@ -65,31 +55,35 @@ class option
|
|||||||
{
|
{
|
||||||
static constexpr bool kHasNiche = has_niche<T>;
|
static constexpr bool kHasNiche = has_niche<T>;
|
||||||
|
|
||||||
static constexpr bool kHasInlinePayload = default_constructible<T> || kHasNiche;
|
|
||||||
|
|
||||||
using Storage = select_t<kHasInlinePayload, T, maybe_uninit<T>>;
|
|
||||||
using HasValueMarker = select_t<kHasNiche, empty, bool>;
|
using HasValueMarker = select_t<kHasNiche, empty, bool>;
|
||||||
|
|
||||||
Storage m_payload;
|
maybe_uninit<T> m_payload{};
|
||||||
ASL_NO_UNIQUE_ADDRESS HasValueMarker m_has_value{};
|
ASL_NO_UNIQUE_ADDRESS HasValueMarker m_has_value{};
|
||||||
|
|
||||||
|
template<is_object U>
|
||||||
|
friend class option;
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
constexpr void construct(Args&&... args)
|
constexpr void construct(Args&&... args)
|
||||||
{
|
{
|
||||||
ASL_ASSERT(!has_value());
|
ASL_ASSERT(!has_value());
|
||||||
|
|
||||||
if constexpr (kHasInlinePayload)
|
if constexpr (!kHasNiche)
|
||||||
{
|
{
|
||||||
m_payload = T(ASL_FWD(args)...);
|
m_payload.construct_unsafe(ASL_FWD(args)...);
|
||||||
|
m_has_value = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_payload.init_unsafe(ASL_FWD(args)...);
|
if constexpr (move_assignable<T>)
|
||||||
}
|
{
|
||||||
|
m_payload.assign_unsafe(ASL_MOVE(T{ASL_FWD(args)...}));
|
||||||
if constexpr (!kHasNiche)
|
}
|
||||||
{
|
else
|
||||||
m_has_value = true;
|
{
|
||||||
|
m_payload.destroy_unsafe();
|
||||||
|
m_payload.construct_unsafe(ASL_FWD(args)...);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,119 +91,81 @@ class option
|
|||||||
constexpr void assign(U&& arg)
|
constexpr void assign(U&& arg)
|
||||||
{
|
{
|
||||||
ASL_ASSERT(has_value());
|
ASL_ASSERT(has_value());
|
||||||
|
m_payload.assign_unsafe(ASL_FWD(arg));
|
||||||
if constexpr (kHasInlinePayload)
|
|
||||||
{
|
|
||||||
m_payload = ASL_FWD(arg);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_payload.as_init_unsafe() = ASL_FWD(arg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using type = T;
|
using type = T;
|
||||||
|
|
||||||
constexpr option() : option(nullopt) {}
|
constexpr option() : option{nullopt} {}
|
||||||
|
|
||||||
// NOLINTNEXTLINE(*-explicit-conversions)
|
// NOLINTNEXTLINE(*-explicit-conversions)
|
||||||
constexpr option(nullopt_t) requires (!kHasNiche) && trivially_default_constructible<T> {}
|
constexpr option(nullopt_t) requires (!kHasNiche) {}
|
||||||
|
|
||||||
// NOLINTNEXTLINE(*-explicit-conversions)
|
// NOLINTNEXTLINE(*-explicit-conversions)
|
||||||
constexpr option(nullopt_t) requires (!kHasNiche) && (!trivially_default_constructible<T>)
|
constexpr option(nullopt_t) requires kHasNiche : m_payload{in_place, niche_t{}} {}
|
||||||
: m_payload{}
|
|
||||||
{}
|
|
||||||
|
|
||||||
// NOLINTNEXTLINE(*-explicit-conversions)
|
|
||||||
constexpr option(nullopt_t) requires kHasNiche
|
|
||||||
: m_payload{niche{}}
|
|
||||||
{}
|
|
||||||
|
|
||||||
template<typename U = T>
|
template<typename U = T>
|
||||||
constexpr explicit (!convertible_from<T, U&&>)
|
constexpr explicit (!convertible_from<T, U&&>)
|
||||||
option(U&& value)
|
option(U&& value)
|
||||||
requires (
|
requires (
|
||||||
kHasNiche &&
|
kHasNiche &&
|
||||||
constructible_from<T, U> &&
|
constructible_from<T, U&&> &&
|
||||||
!same_as<un_cvref_t<U>, option> &&
|
!same_as<un_cvref_t<U>, option>
|
||||||
!is_niche<U>
|
|
||||||
)
|
)
|
||||||
: m_payload(ASL_FWD(value))
|
: m_payload{in_place, ASL_FWD(value)}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
template<typename U = T>
|
template<typename U = T>
|
||||||
constexpr explicit (!convertible_from<T, U&&>)
|
constexpr explicit (!convertible_from<T, U&&>)
|
||||||
option(U&& value)
|
option(U&& value)
|
||||||
requires (
|
requires (
|
||||||
kHasInlinePayload &&
|
|
||||||
!kHasNiche &&
|
!kHasNiche &&
|
||||||
constructible_from<T, U> &&
|
constructible_from<T, U&&> &&
|
||||||
!same_as<un_cvref_t<U>, option> &&
|
!is_option<U>
|
||||||
!is_niche<U>
|
|
||||||
)
|
)
|
||||||
: m_payload(ASL_FWD(value))
|
: m_payload{in_place, ASL_FWD(value)}
|
||||||
, m_has_value{true}
|
, m_has_value{true}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
constexpr option(const option& other) requires trivially_copy_constructible<T> = default;
|
||||||
|
constexpr option(const option& other) requires (!copy_constructible<T>) = delete;
|
||||||
|
|
||||||
template<typename U = T>
|
constexpr option(const option& other)
|
||||||
constexpr explicit (!convertible_from<T, U&&>)
|
requires copy_constructible<T> && (!trivially_copy_constructible<T>)
|
||||||
option(U&& value)
|
: option{nullopt}
|
||||||
requires (
|
|
||||||
!kHasInlinePayload &&
|
|
||||||
constructible_from<T, U> &&
|
|
||||||
!same_as<un_cvref_t<U>, option> &&
|
|
||||||
!is_niche<U>
|
|
||||||
)
|
|
||||||
: option(nullopt)
|
|
||||||
{
|
{
|
||||||
construct(ASL_FWD(value));
|
if (other.has_value())
|
||||||
|
{
|
||||||
|
construct(other.m_payload.as_init_unsafe());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr option(const option& other)
|
constexpr option(option&& other) requires trivially_move_constructible<T> = default;
|
||||||
requires copy_constructible<T> && kHasInlinePayload = default;
|
constexpr option(option&& other) requires (!move_constructible<T>) = delete;
|
||||||
|
|
||||||
constexpr option(const option& other)
|
constexpr option(option&& other)
|
||||||
requires copy_constructible<T> && (!kHasInlinePayload)
|
requires move_constructible<T> && (!trivially_move_constructible<T>)
|
||||||
: option(nullopt)
|
: option{nullopt}
|
||||||
{
|
{
|
||||||
if (other.has_value())
|
if (other.has_value())
|
||||||
{
|
{
|
||||||
construct(other.value());
|
construct(ASL_MOVE(other.m_payload.as_init_unsafe()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr option(const option& other)
|
|
||||||
requires (!copy_constructible<T>) = delete;
|
|
||||||
|
|
||||||
constexpr option(option&& other)
|
|
||||||
requires move_constructible<T> && kHasInlinePayload = default;
|
|
||||||
|
|
||||||
constexpr option(option&& other)
|
|
||||||
requires move_constructible<T> && (!kHasInlinePayload)
|
|
||||||
: option(nullopt)
|
|
||||||
{
|
|
||||||
if (other.has_value())
|
|
||||||
{
|
|
||||||
construct(ASL_MOVE(other.value()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr option(option&& other)
|
|
||||||
requires (!move_constructible<T>) = delete;
|
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
constexpr explicit (!convertible_from<T, const U&>)
|
constexpr explicit (!convertible_from<T, const U&>)
|
||||||
option(const option<U>& other)
|
option(const option<U>& other)
|
||||||
requires (
|
requires (
|
||||||
constructible_from<T, const U&> &&
|
constructible_from<T, const U&> &&
|
||||||
!option_internal::convertible_constructible_from_option<T, U>
|
option_internal::not_constructible_from_option<T, U>
|
||||||
)
|
)
|
||||||
: option(nullopt)
|
: option{nullopt}
|
||||||
{
|
{
|
||||||
if (other.has_value())
|
if (other.has_value())
|
||||||
{
|
{
|
||||||
construct(other.value());
|
construct(other.m_payload.as_init_unsafe());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,13 +174,13 @@ public:
|
|||||||
option(option<U>&& other)
|
option(option<U>&& other)
|
||||||
requires (
|
requires (
|
||||||
constructible_from<T, U&&> &&
|
constructible_from<T, U&&> &&
|
||||||
!option_internal::convertible_constructible_from_option<T, U>
|
option_internal::not_constructible_from_option<T, U>
|
||||||
)
|
)
|
||||||
: option(nullopt)
|
: option{nullopt}
|
||||||
{
|
{
|
||||||
if (other.has_value())
|
if (other.has_value())
|
||||||
{
|
{
|
||||||
construct(ASL_MOVE(other.value()));
|
construct(ASL_MOVE(other.m_payload.as_init_unsafe()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,9 +193,9 @@ public:
|
|||||||
template<typename U = T>
|
template<typename U = T>
|
||||||
constexpr option& operator=(U&& value) &
|
constexpr option& operator=(U&& value) &
|
||||||
requires (
|
requires (
|
||||||
assignable_from<T&, U> &&
|
assignable_from<T&, U&&> &&
|
||||||
constructible_from<T, U> &&
|
constructible_from<T, U&&> &&
|
||||||
!same_as<un_cvref_t<U>, option>
|
!is_option<U>
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (has_value())
|
if (has_value())
|
||||||
@ -255,13 +211,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr option& operator=(const option& other) &
|
constexpr option& operator=(const option& other) &
|
||||||
requires (!copy_assignable<T> || !copy_constructible<T>) = delete;
|
requires (!copy_assignable<T>) = delete;
|
||||||
|
|
||||||
constexpr option& operator=(const option& other) &
|
constexpr option& operator=(const option& other) &
|
||||||
requires copy_assignable<T> && copy_constructible<T> && kHasInlinePayload = default;
|
requires trivially_copy_assignable<T> = default;
|
||||||
|
|
||||||
constexpr option& operator=(const option& other) &
|
constexpr option& operator=(const option& other) &
|
||||||
requires copy_assignable<T> && copy_constructible<T> && (!kHasInlinePayload)
|
requires copy_assignable<T> && (!trivially_copy_constructible<T>)
|
||||||
{
|
{
|
||||||
if (&other == this) { return *this; }
|
if (&other == this) { return *this; }
|
||||||
|
|
||||||
@ -283,12 +239,15 @@ public:
|
|||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr option& operator=(option&& other) &
|
constexpr option& operator=(option&& other) &
|
||||||
requires move_assignable<T> && move_constructible<T> && kHasInlinePayload = default;
|
requires (!move_assignable<T>) = delete;
|
||||||
|
|
||||||
constexpr option& operator=(option&& other) &
|
constexpr option& operator=(option&& other) &
|
||||||
requires move_assignable<T> && move_constructible<T> && (!kHasInlinePayload)
|
requires trivially_move_assignable<T> = default;
|
||||||
|
|
||||||
|
constexpr option& operator=(option&& other) &
|
||||||
|
requires move_assignable<T> && (!trivially_move_constructible<T>)
|
||||||
{
|
{
|
||||||
if (&other == this) { return *this; }
|
if (&other == this) { return *this; }
|
||||||
|
|
||||||
@ -316,18 +275,18 @@ public:
|
|||||||
requires (
|
requires (
|
||||||
constructible_from<T, const U&> &&
|
constructible_from<T, const U&> &&
|
||||||
assignable_from<T&, const U&> &&
|
assignable_from<T&, const U&> &&
|
||||||
!option_internal::convertible_constructible_assignable_from_option<T, U>
|
option_internal::not_constructible_assignable_from_option<T, U>
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (other.has_value())
|
if (other.has_value())
|
||||||
{
|
{
|
||||||
if (has_value())
|
if (has_value())
|
||||||
{
|
{
|
||||||
assign(other.value());
|
assign(other.m_payload.as_init_unsafe());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
construct(other.value());
|
construct(other.m_payload.as_init_unsafe());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (has_value())
|
else if (has_value())
|
||||||
@ -341,20 +300,20 @@ public:
|
|||||||
template<typename U = T>
|
template<typename U = T>
|
||||||
constexpr option& operator=(option<U>&& other) &
|
constexpr option& operator=(option<U>&& other) &
|
||||||
requires (
|
requires (
|
||||||
constructible_from<T, U> &&
|
constructible_from<T, U&&> &&
|
||||||
assignable_from<T&, U> &&
|
assignable_from<T&, U&&> &&
|
||||||
!option_internal::convertible_constructible_assignable_from_option<T, U>
|
option_internal::not_constructible_assignable_from_option<T, U>
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (other.has_value())
|
if (other.has_value())
|
||||||
{
|
{
|
||||||
if (has_value())
|
if (has_value())
|
||||||
{
|
{
|
||||||
assign(ASL_MOVE(other).value());
|
assign(ASL_MOVE(other.m_payload.as_init_unsafe()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
construct(ASL_MOVE(other).value());
|
construct(ASL_MOVE(other.m_payload.as_init_unsafe()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (has_value())
|
else if (has_value())
|
||||||
@ -364,8 +323,8 @@ public:
|
|||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ~option() = default;
|
constexpr ~option() requires trivially_destructible<T> = default;
|
||||||
constexpr ~option() requires (!trivially_destructible<T>)
|
constexpr ~option() requires (!trivially_destructible<T>)
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
@ -379,21 +338,18 @@ public:
|
|||||||
{
|
{
|
||||||
if constexpr (move_assignable<T>)
|
if constexpr (move_assignable<T>)
|
||||||
{
|
{
|
||||||
m_payload = T(niche{});
|
m_payload.assign_unsafe(ASL_MOVE(T{niche_t{}}));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
destroy(&m_payload);
|
m_payload.destroy_unsafe();
|
||||||
construct_at<T>(&m_payload, niche{});
|
m_payload.construct_unsafe(niche_t{});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_has_value = false;
|
m_has_value = false;
|
||||||
if constexpr (!kHasInlinePayload)
|
m_payload.destroy_unsafe();
|
||||||
{
|
|
||||||
m_payload.uninit_unsafe();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,7 +357,7 @@ public:
|
|||||||
{
|
{
|
||||||
if constexpr (kHasNiche)
|
if constexpr (kHasNiche)
|
||||||
{
|
{
|
||||||
return m_payload != niche{};
|
return m_payload.as_init_unsafe() != niche_t{};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -413,40 +369,19 @@ public:
|
|||||||
constexpr T&& value() &&
|
constexpr T&& value() &&
|
||||||
{
|
{
|
||||||
ASL_ASSERT_RELEASE(has_value());
|
ASL_ASSERT_RELEASE(has_value());
|
||||||
if constexpr (kHasInlinePayload)
|
return ASL_MOVE(m_payload).as_init_unsafe();
|
||||||
{
|
|
||||||
return ASL_MOVE(m_payload);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ASL_MOVE(m_payload).as_init_unsafe();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr T& value() &
|
constexpr T& value() &
|
||||||
{
|
{
|
||||||
ASL_ASSERT_RELEASE(has_value());
|
ASL_ASSERT_RELEASE(has_value());
|
||||||
if constexpr (kHasInlinePayload)
|
return m_payload.as_init_unsafe();
|
||||||
{
|
|
||||||
return m_payload;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return m_payload.as_init_unsafe();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const T& value() const&
|
constexpr const T& value() const&
|
||||||
{
|
{
|
||||||
ASL_ASSERT_RELEASE(has_value());
|
ASL_ASSERT_RELEASE(has_value());
|
||||||
if constexpr (kHasInlinePayload)
|
return m_payload.as_init_unsafe();
|
||||||
{
|
|
||||||
return m_payload;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return m_payload.as_init_unsafe();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
|
@ -55,6 +55,8 @@ ASL_TEST(arrow)
|
|||||||
|
|
||||||
ASL_TEST(niche)
|
ASL_TEST(niche)
|
||||||
{
|
{
|
||||||
|
static_assert(sizeof(asl::box<int>) == sizeof(asl::option<asl::box<int>>));
|
||||||
|
|
||||||
asl::option<asl::box<int>> opt;
|
asl::option<asl::box<int>> opt;
|
||||||
ASL_TEST_EXPECT(!opt.has_value());
|
ASL_TEST_EXPECT(!opt.has_value());
|
||||||
|
|
||||||
@ -66,7 +68,7 @@ ASL_TEST(niche)
|
|||||||
ASL_TEST_EXPECT(!opt.has_value());
|
ASL_TEST_EXPECT(!opt.has_value());
|
||||||
|
|
||||||
bool destroyed = false;
|
bool destroyed = false;
|
||||||
asl::option<asl::box<DestructorObserver>> opt2 = asl::make_box<DestructorObserver>(&destroyed);
|
asl::option opt2 = asl::make_box<DestructorObserver>(&destroyed);
|
||||||
ASL_TEST_EXPECT(opt2.has_value());
|
ASL_TEST_EXPECT(opt2.has_value());
|
||||||
ASL_TEST_EXPECT(!destroyed);
|
ASL_TEST_EXPECT(!destroyed);
|
||||||
|
|
||||||
|
@ -5,6 +5,18 @@ static_assert(asl::layout::of<int>() == asl::layout::of<asl::maybe_uninit<int>>(
|
|||||||
static_assert(asl::size_of<int> == asl::size_of<asl::maybe_uninit<int>>);
|
static_assert(asl::size_of<int> == asl::size_of<asl::maybe_uninit<int>>);
|
||||||
static_assert(asl::align_of<int> == asl::align_of<asl::maybe_uninit<int>>);
|
static_assert(asl::align_of<int> == asl::align_of<asl::maybe_uninit<int>>);
|
||||||
|
|
||||||
static_assert(asl::trivially_destructible<asl::maybe_uninit<TrivialType>>);
|
#define TEST_TYPE_PROPERTIES(PRP) \
|
||||||
static_assert(!asl::trivially_destructible<asl::maybe_uninit<WithDestructor>>);
|
static_assert(asl::PRP<asl::maybe_uninit<TrivialType>> == asl::PRP<TrivialType>); \
|
||||||
|
static_assert(asl::PRP<asl::maybe_uninit<TrivialTypeDefaultValue>> == asl::PRP<TrivialTypeDefaultValue>); \
|
||||||
|
static_assert(asl::PRP<asl::maybe_uninit<WithDestructor>> == asl::PRP<WithDestructor>); \
|
||||||
|
static_assert(asl::PRP<asl::maybe_uninit<Copyable>> == asl::PRP<Copyable>); \
|
||||||
|
static_assert(asl::PRP<asl::maybe_uninit<MoveableOnly>> == asl::PRP<MoveableOnly>); \
|
||||||
|
static_assert(asl::PRP<asl::maybe_uninit<Pinned>> == asl::PRP<Pinned>);
|
||||||
|
|
||||||
|
TEST_TYPE_PROPERTIES(trivially_default_constructible);
|
||||||
|
TEST_TYPE_PROPERTIES(trivially_copy_constructible);
|
||||||
|
TEST_TYPE_PROPERTIES(trivially_move_constructible);
|
||||||
|
TEST_TYPE_PROPERTIES(trivially_copy_assignable);
|
||||||
|
TEST_TYPE_PROPERTIES(trivially_move_assignable);
|
||||||
|
TEST_TYPE_PROPERTIES(trivially_destructible);
|
||||||
|
|
||||||
|
@ -14,14 +14,14 @@ struct NonZero
|
|||||||
ASL_ASSERT(x != 0);
|
ASL_ASSERT(x != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr explicit NonZero(asl::niche) : value(0) {}
|
constexpr explicit NonZero(asl::niche_t) : value(0) {}
|
||||||
|
|
||||||
constexpr bool operator==(asl::niche) const { return value == 0; }
|
constexpr bool operator==(asl::niche_t) const { return value == 0; }
|
||||||
};
|
};
|
||||||
static_assert(asl::has_niche<NonZero>);
|
static_assert(asl::has_niche<NonZero>);
|
||||||
static_assert(!asl::has_niche<int>);
|
static_assert(!asl::has_niche<int>);
|
||||||
|
|
||||||
static_assert(sizeof(asl::option<int>) > sizeof(int));
|
static_assert(sizeof(asl::option<int>) >= sizeof(int));
|
||||||
static_assert(sizeof(asl::option<NonZero>) == sizeof(NonZero));
|
static_assert(sizeof(asl::option<NonZero>) == sizeof(NonZero));
|
||||||
|
|
||||||
static_assert(!asl::is_option<int>);
|
static_assert(!asl::is_option<int>);
|
||||||
@ -31,22 +31,26 @@ static_assert(asl::is_option<const asl::option<int>>);
|
|||||||
static_assert(asl::trivially_destructible<asl::option<TrivialType>>);
|
static_assert(asl::trivially_destructible<asl::option<TrivialType>>);
|
||||||
static_assert(!asl::trivially_destructible<asl::option<WithDestructor>>);
|
static_assert(!asl::trivially_destructible<asl::option<WithDestructor>>);
|
||||||
|
|
||||||
static_assert(asl::copy_constructible<asl::option<int>>);
|
static_assert(asl::trivially_copy_constructible<asl::option<int>>);
|
||||||
|
static_assert(asl::trivially_copy_constructible<asl::option<NonZero>>);
|
||||||
static_assert(asl::copy_constructible<asl::option<Copyable>>);
|
static_assert(asl::copy_constructible<asl::option<Copyable>>);
|
||||||
static_assert(!asl::copy_constructible<asl::option<MoveableOnly>>);
|
static_assert(!asl::copy_constructible<asl::option<MoveableOnly>>);
|
||||||
static_assert(!asl::copy_constructible<asl::option<Pinned>>);
|
static_assert(!asl::copy_constructible<asl::option<Pinned>>);
|
||||||
|
|
||||||
static_assert(asl::move_constructible<asl::option<int>>);
|
static_assert(asl::trivially_move_constructible<asl::option<int>>);
|
||||||
|
static_assert(asl::trivially_move_constructible<asl::option<NonZero>>);
|
||||||
static_assert(asl::move_constructible<asl::option<Copyable>>);
|
static_assert(asl::move_constructible<asl::option<Copyable>>);
|
||||||
static_assert(asl::move_constructible<asl::option<MoveableOnly>>);
|
static_assert(asl::move_constructible<asl::option<MoveableOnly>>);
|
||||||
static_assert(!asl::move_constructible<asl::option<Pinned>>);
|
static_assert(!asl::move_constructible<asl::option<Pinned>>);
|
||||||
|
|
||||||
static_assert(asl::copy_assignable<asl::option<int>>);
|
static_assert(asl::trivially_copy_assignable<asl::option<int>>);
|
||||||
|
static_assert(asl::trivially_copy_assignable<asl::option<NonZero>>);
|
||||||
static_assert(asl::copy_assignable<asl::option<Copyable>>);
|
static_assert(asl::copy_assignable<asl::option<Copyable>>);
|
||||||
static_assert(!asl::copy_assignable<asl::option<MoveableOnly>>);
|
static_assert(!asl::copy_assignable<asl::option<MoveableOnly>>);
|
||||||
static_assert(!asl::copy_assignable<asl::option<Pinned>>);
|
static_assert(!asl::copy_assignable<asl::option<Pinned>>);
|
||||||
|
|
||||||
static_assert(asl::move_assignable<asl::option<int>>);
|
static_assert(asl::trivially_move_assignable<asl::option<int>>);
|
||||||
|
static_assert(asl::trivially_move_assignable<asl::option<NonZero>>);
|
||||||
static_assert(asl::move_assignable<asl::option<Copyable>>);
|
static_assert(asl::move_assignable<asl::option<Copyable>>);
|
||||||
static_assert(asl::move_assignable<asl::option<MoveableOnly>>);
|
static_assert(asl::move_assignable<asl::option<MoveableOnly>>);
|
||||||
static_assert(!asl::move_assignable<asl::option<Pinned>>);
|
static_assert(!asl::move_assignable<asl::option<Pinned>>);
|
||||||
|
@ -11,6 +11,9 @@
|
|||||||
namespace asl
|
namespace asl
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct in_place_t {};
|
||||||
|
static constexpr in_place_t in_place{};
|
||||||
|
|
||||||
template<moveable T>
|
template<moveable T>
|
||||||
constexpr void swap(T& a, T& b)
|
constexpr void swap(T& a, T& b)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user