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;
|
||||
|
||||
public:
|
||||
explicit constexpr box(niche)
|
||||
explicit constexpr box(niche_t)
|
||||
requires default_constructible<Allocator>
|
||||
: m_ptr{nullptr}
|
||||
, m_alloc{}
|
||||
@ -78,7 +78,7 @@ public:
|
||||
return m_ptr;
|
||||
}
|
||||
|
||||
constexpr bool operator==(niche) const
|
||||
constexpr bool operator==(niche_t) const
|
||||
{
|
||||
return m_ptr == nullptr;
|
||||
}
|
||||
|
@ -1,60 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include "asl/layout.hpp"
|
||||
#include "asl/memory.hpp"
|
||||
#include "asl/meta.hpp"
|
||||
#include "asl/utility.hpp"
|
||||
#include "asl/memory.hpp"
|
||||
|
||||
namespace asl
|
||||
{
|
||||
|
||||
template<is_object T>
|
||||
class maybe_uninit
|
||||
union maybe_uninit
|
||||
{
|
||||
union
|
||||
{
|
||||
alignas(align_of<T>) char m_storage[size_of<T>];
|
||||
T m_value;
|
||||
};
|
||||
private:
|
||||
T m_value;
|
||||
|
||||
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>
|
||||
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.
|
||||
constexpr void uninit_unsafe() &
|
||||
// @Safety Value must have been initialized
|
||||
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
|
||||
|
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, 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>;
|
||||
{ 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>;
|
||||
|
||||
struct niche {};
|
||||
struct niche_t {};
|
||||
|
||||
template<typename T>
|
||||
concept has_niche = constructible_from<T, niche> &&
|
||||
requires (const T& value, niche n)
|
||||
{
|
||||
{ value == n } -> same_as<bool>;
|
||||
};
|
||||
concept has_niche = constructible_from<T, niche_t> && equality_comparable_with<T, niche_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
|
||||
|
249
asl/option.hpp
249
asl/option.hpp
@ -22,34 +22,24 @@ namespace option_internal
|
||||
{
|
||||
|
||||
template<typename T, typename U>
|
||||
concept convertible_from_option =
|
||||
convertible_from<T, option<U>&> &&
|
||||
convertible_from<T, const option<U>&> &&
|
||||
convertible_from<T, option<U>&&> &&
|
||||
convertible_from<T, const option<U>&&>;
|
||||
concept not_constructible_from_option =
|
||||
!constructible_from<T, option<U>&> &&
|
||||
!constructible_from<T, const option<U>&> &&
|
||||
!constructible_from<T, option<U>&&> &&
|
||||
!constructible_from<T, const option<U>&&>;
|
||||
|
||||
template<typename T, typename U>
|
||||
concept constructible_from_option =
|
||||
constructible_from<T, option<U>&> &&
|
||||
constructible_from<T, const option<U>&> &&
|
||||
constructible_from<T, option<U>&&> &&
|
||||
constructible_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>;
|
||||
concept not_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_assignable_from_option =
|
||||
convertible_constructible_from_option<T, U> && assignable_from_option<T, U>;
|
||||
concept not_constructible_assignable_from_option =
|
||||
not_constructible_from_option<T, U> &&
|
||||
not_assignable_from_option<T, U>;
|
||||
|
||||
} // namespace option_internal
|
||||
|
||||
@ -65,31 +55,35 @@ class option
|
||||
{
|
||||
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>;
|
||||
|
||||
Storage m_payload;
|
||||
maybe_uninit<T> m_payload{};
|
||||
ASL_NO_UNIQUE_ADDRESS HasValueMarker m_has_value{};
|
||||
|
||||
template<is_object U>
|
||||
friend class option;
|
||||
|
||||
template<typename... Args>
|
||||
constexpr void construct(Args&&... args)
|
||||
{
|
||||
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
|
||||
{
|
||||
m_payload.init_unsafe(ASL_FWD(args)...);
|
||||
}
|
||||
|
||||
if constexpr (!kHasNiche)
|
||||
{
|
||||
m_has_value = true;
|
||||
if constexpr (move_assignable<T>)
|
||||
{
|
||||
m_payload.assign_unsafe(ASL_MOVE(T{ASL_FWD(args)...}));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_payload.destroy_unsafe();
|
||||
m_payload.construct_unsafe(ASL_FWD(args)...);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,119 +91,81 @@ class option
|
||||
constexpr void assign(U&& arg)
|
||||
{
|
||||
ASL_ASSERT(has_value());
|
||||
|
||||
if constexpr (kHasInlinePayload)
|
||||
{
|
||||
m_payload = ASL_FWD(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_payload.as_init_unsafe() = ASL_FWD(arg);
|
||||
}
|
||||
m_payload.assign_unsafe(ASL_FWD(arg));
|
||||
}
|
||||
|
||||
public:
|
||||
using type = T;
|
||||
|
||||
constexpr option() : option(nullopt) {}
|
||||
constexpr option() : option{nullopt} {}
|
||||
|
||||
// NOLINTNEXTLINE(*-explicit-conversions)
|
||||
constexpr option(nullopt_t) requires (!kHasNiche) && trivially_default_constructible<T> {}
|
||||
constexpr option(nullopt_t) requires (!kHasNiche) {}
|
||||
|
||||
// NOLINTNEXTLINE(*-explicit-conversions)
|
||||
constexpr option(nullopt_t) requires (!kHasNiche) && (!trivially_default_constructible<T>)
|
||||
: m_payload{}
|
||||
{}
|
||||
|
||||
// NOLINTNEXTLINE(*-explicit-conversions)
|
||||
constexpr option(nullopt_t) requires kHasNiche
|
||||
: m_payload{niche{}}
|
||||
{}
|
||||
constexpr option(nullopt_t) requires kHasNiche : m_payload{in_place, niche_t{}} {}
|
||||
|
||||
template<typename U = T>
|
||||
constexpr explicit (!convertible_from<T, U&&>)
|
||||
option(U&& value)
|
||||
requires (
|
||||
kHasNiche &&
|
||||
constructible_from<T, U> &&
|
||||
!same_as<un_cvref_t<U>, option> &&
|
||||
!is_niche<U>
|
||||
constructible_from<T, U&&> &&
|
||||
!same_as<un_cvref_t<U>, option>
|
||||
)
|
||||
: m_payload(ASL_FWD(value))
|
||||
: m_payload{in_place, ASL_FWD(value)}
|
||||
{}
|
||||
|
||||
template<typename U = T>
|
||||
constexpr explicit (!convertible_from<T, U&&>)
|
||||
constexpr explicit (!convertible_from<T, U&&>)
|
||||
option(U&& value)
|
||||
requires (
|
||||
kHasInlinePayload &&
|
||||
!kHasNiche &&
|
||||
constructible_from<T, U> &&
|
||||
!same_as<un_cvref_t<U>, option> &&
|
||||
!is_niche<U>
|
||||
constructible_from<T, U&&> &&
|
||||
!is_option<U>
|
||||
)
|
||||
: m_payload(ASL_FWD(value))
|
||||
: m_payload{in_place, ASL_FWD(value)}
|
||||
, 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 explicit (!convertible_from<T, U&&>)
|
||||
option(U&& value)
|
||||
requires (
|
||||
!kHasInlinePayload &&
|
||||
constructible_from<T, U> &&
|
||||
!same_as<un_cvref_t<U>, option> &&
|
||||
!is_niche<U>
|
||||
)
|
||||
: option(nullopt)
|
||||
constexpr option(const option& other)
|
||||
requires copy_constructible<T> && (!trivially_copy_constructible<T>)
|
||||
: option{nullopt}
|
||||
{
|
||||
construct(ASL_FWD(value));
|
||||
if (other.has_value())
|
||||
{
|
||||
construct(other.m_payload.as_init_unsafe());
|
||||
}
|
||||
}
|
||||
|
||||
constexpr option(const option& other)
|
||||
requires copy_constructible<T> && kHasInlinePayload = default;
|
||||
constexpr option(option&& other) requires trivially_move_constructible<T> = default;
|
||||
constexpr option(option&& other) requires (!move_constructible<T>) = delete;
|
||||
|
||||
constexpr option(const option& other)
|
||||
requires copy_constructible<T> && (!kHasInlinePayload)
|
||||
: option(nullopt)
|
||||
constexpr option(option&& other)
|
||||
requires move_constructible<T> && (!trivially_move_constructible<T>)
|
||||
: option{nullopt}
|
||||
{
|
||||
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>
|
||||
constexpr explicit (!convertible_from<T, const U&>)
|
||||
option(const option<U>& other)
|
||||
requires (
|
||||
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())
|
||||
{
|
||||
construct(other.value());
|
||||
construct(other.m_payload.as_init_unsafe());
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,13 +174,13 @@ public:
|
||||
option(option<U>&& other)
|
||||
requires (
|
||||
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())
|
||||
{
|
||||
construct(ASL_MOVE(other.value()));
|
||||
construct(ASL_MOVE(other.m_payload.as_init_unsafe()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,9 +193,9 @@ public:
|
||||
template<typename U = T>
|
||||
constexpr option& operator=(U&& value) &
|
||||
requires (
|
||||
assignable_from<T&, U> &&
|
||||
constructible_from<T, U> &&
|
||||
!same_as<un_cvref_t<U>, option>
|
||||
assignable_from<T&, U&&> &&
|
||||
constructible_from<T, U&&> &&
|
||||
!is_option<U>
|
||||
)
|
||||
{
|
||||
if (has_value())
|
||||
@ -255,13 +211,13 @@ public:
|
||||
}
|
||||
|
||||
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) &
|
||||
requires copy_assignable<T> && copy_constructible<T> && kHasInlinePayload = default;
|
||||
requires trivially_copy_assignable<T> = default;
|
||||
|
||||
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; }
|
||||
|
||||
@ -283,12 +239,15 @@ public:
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
constexpr option& operator=(option&& other) &
|
||||
requires move_assignable<T> && move_constructible<T> && kHasInlinePayload = default;
|
||||
requires (!move_assignable<T>) = delete;
|
||||
|
||||
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; }
|
||||
|
||||
@ -316,18 +275,18 @@ public:
|
||||
requires (
|
||||
constructible_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 (has_value())
|
||||
{
|
||||
assign(other.value());
|
||||
assign(other.m_payload.as_init_unsafe());
|
||||
}
|
||||
else
|
||||
{
|
||||
construct(other.value());
|
||||
construct(other.m_payload.as_init_unsafe());
|
||||
}
|
||||
}
|
||||
else if (has_value())
|
||||
@ -341,20 +300,20 @@ public:
|
||||
template<typename U = T>
|
||||
constexpr option& operator=(option<U>&& other) &
|
||||
requires (
|
||||
constructible_from<T, U> &&
|
||||
assignable_from<T&, U> &&
|
||||
!option_internal::convertible_constructible_assignable_from_option<T, U>
|
||||
constructible_from<T, U&&> &&
|
||||
assignable_from<T&, U&&> &&
|
||||
option_internal::not_constructible_assignable_from_option<T, U>
|
||||
)
|
||||
{
|
||||
if (other.has_value())
|
||||
{
|
||||
if (has_value())
|
||||
{
|
||||
assign(ASL_MOVE(other).value());
|
||||
assign(ASL_MOVE(other.m_payload.as_init_unsafe()));
|
||||
}
|
||||
else
|
||||
{
|
||||
construct(ASL_MOVE(other).value());
|
||||
construct(ASL_MOVE(other.m_payload.as_init_unsafe()));
|
||||
}
|
||||
}
|
||||
else if (has_value())
|
||||
@ -364,8 +323,8 @@ public:
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr ~option() = default;
|
||||
|
||||
constexpr ~option() requires trivially_destructible<T> = default;
|
||||
constexpr ~option() requires (!trivially_destructible<T>)
|
||||
{
|
||||
reset();
|
||||
@ -379,21 +338,18 @@ public:
|
||||
{
|
||||
if constexpr (move_assignable<T>)
|
||||
{
|
||||
m_payload = T(niche{});
|
||||
m_payload.assign_unsafe(ASL_MOVE(T{niche_t{}}));
|
||||
}
|
||||
else
|
||||
{
|
||||
destroy(&m_payload);
|
||||
construct_at<T>(&m_payload, niche{});
|
||||
m_payload.destroy_unsafe();
|
||||
m_payload.construct_unsafe(niche_t{});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_has_value = false;
|
||||
if constexpr (!kHasInlinePayload)
|
||||
{
|
||||
m_payload.uninit_unsafe();
|
||||
}
|
||||
m_payload.destroy_unsafe();
|
||||
}
|
||||
}
|
||||
|
||||
@ -401,7 +357,7 @@ public:
|
||||
{
|
||||
if constexpr (kHasNiche)
|
||||
{
|
||||
return m_payload != niche{};
|
||||
return m_payload.as_init_unsafe() != niche_t{};
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -413,40 +369,19 @@ public:
|
||||
constexpr T&& value() &&
|
||||
{
|
||||
ASL_ASSERT_RELEASE(has_value());
|
||||
if constexpr (kHasInlinePayload)
|
||||
{
|
||||
return ASL_MOVE(m_payload);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ASL_MOVE(m_payload).as_init_unsafe();
|
||||
}
|
||||
return ASL_MOVE(m_payload).as_init_unsafe();
|
||||
}
|
||||
|
||||
constexpr T& value() &
|
||||
{
|
||||
ASL_ASSERT_RELEASE(has_value());
|
||||
if constexpr (kHasInlinePayload)
|
||||
{
|
||||
return m_payload;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_payload.as_init_unsafe();
|
||||
}
|
||||
return m_payload.as_init_unsafe();
|
||||
}
|
||||
|
||||
constexpr const T& value() const&
|
||||
{
|
||||
ASL_ASSERT_RELEASE(has_value());
|
||||
if constexpr (kHasInlinePayload)
|
||||
{
|
||||
return m_payload;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_payload.as_init_unsafe();
|
||||
}
|
||||
return m_payload.as_init_unsafe();
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
|
@ -55,6 +55,8 @@ ASL_TEST(arrow)
|
||||
|
||||
ASL_TEST(niche)
|
||||
{
|
||||
static_assert(sizeof(asl::box<int>) == sizeof(asl::option<asl::box<int>>));
|
||||
|
||||
asl::option<asl::box<int>> opt;
|
||||
ASL_TEST_EXPECT(!opt.has_value());
|
||||
|
||||
@ -66,7 +68,7 @@ ASL_TEST(niche)
|
||||
ASL_TEST_EXPECT(!opt.has_value());
|
||||
|
||||
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(!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::align_of<int> == asl::align_of<asl::maybe_uninit<int>>);
|
||||
|
||||
static_assert(asl::trivially_destructible<asl::maybe_uninit<TrivialType>>);
|
||||
static_assert(!asl::trivially_destructible<asl::maybe_uninit<WithDestructor>>);
|
||||
#define TEST_TYPE_PROPERTIES(PRP) \
|
||||
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);
|
||||
}
|
||||
|
||||
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<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(!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<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<MoveableOnly>>);
|
||||
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<MoveableOnly>>);
|
||||
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<MoveableOnly>>);
|
||||
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<MoveableOnly>>);
|
||||
static_assert(!asl::move_assignable<asl::option<Pinned>>);
|
||||
|
@ -11,6 +11,9 @@
|
||||
namespace asl
|
||||
{
|
||||
|
||||
struct in_place_t {};
|
||||
static constexpr in_place_t in_place{};
|
||||
|
||||
template<moveable T>
|
||||
constexpr void swap(T& a, T& b)
|
||||
{
|
||||
|
Reference in New Issue
Block a user