diff options
author | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2025-01-05 15:25:45 +0100 |
---|---|---|
committer | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2025-01-05 15:25:45 +0100 |
commit | 8607772d4f9e21f53c1abfd9379737403b97f430 (patch) | |
tree | fcd5a5030bb1cc0ba4dd4069a0d7174a67791c03 /asl | |
parent | b53fc9038f4579974c9eea28e82b693a7fd66522 (diff) |
Fix a few mistakes in option, and make it trivial when possible
Diffstat (limited to 'asl')
-rw-r--r-- | asl/box.hpp | 4 | ||||
-rw-r--r-- | asl/maybe_uninit.hpp | 82 | ||||
-rw-r--r-- | asl/meta.hpp | 12 | ||||
-rw-r--r-- | asl/option.hpp | 243 | ||||
-rw-r--r-- | asl/tests/box_tests.cpp | 4 | ||||
-rw-r--r-- | asl/tests/maybe_uninit_tests.cpp | 16 | ||||
-rw-r--r-- | asl/tests/option_tests.cpp | 18 | ||||
-rw-r--r-- | asl/utility.hpp | 3 |
8 files changed, 173 insertions, 209 deletions
diff --git a/asl/box.hpp b/asl/box.hpp index 491338f..d018c03 100644 --- a/asl/box.hpp +++ b/asl/box.hpp @@ -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;
}
diff --git a/asl/maybe_uninit.hpp b/asl/maybe_uninit.hpp index e59cfe0..4f60e4d 100644 --- a/asl/maybe_uninit.hpp +++ b/asl/maybe_uninit.hpp @@ -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;
+ template<typename... Args>
+ explicit constexpr maybe_uninit(in_place_t, Args&&... args)
+ requires constructible_from<T, Args&&...>
+ : m_value{ASL_FWD(args)...}
+ {}
- constexpr ~maybe_uninit() = default;
- constexpr ~maybe_uninit() requires (!trivially_destructible<T>) {}
+ 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 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; }
+ 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 Must be called only when in uninitialized state.
+ // @Safety Value must not have been initialized yet
template<typename... Args>
- constexpr void init_unsafe(Args&&... 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
diff --git a/asl/meta.hpp b/asl/meta.hpp index 43bd7cc..84616f4 100644 --- a/asl/meta.hpp +++ b/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
diff --git a/asl/option.hpp b/asl/option.hpp index b87a5ab..8c0a573 100644 --- a/asl/option.hpp +++ b/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>&&>;
+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 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>
-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) {}
-
- // NOLINTNEXTLINE(*-explicit-conversions)
- constexpr option(nullopt_t) requires (!kHasNiche) && trivially_default_constructible<T> {}
+ constexpr option() : option{nullopt} {}
// NOLINTNEXTLINE(*-explicit-conversions)
- constexpr option(nullopt_t) requires (!kHasNiche) && (!trivially_default_constructible<T>)
- : m_payload{}
- {}
+ constexpr option(nullopt_t) requires (!kHasNiche) {}
// 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}
{}
-
- 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)
- {
- construct(ASL_FWD(value));
- }
- constexpr option(const option& other)
- requires copy_constructible<T> && kHasInlinePayload = default;
+ constexpr option(const option& other) requires trivially_copy_constructible<T> = default;
+ constexpr option(const option& other) requires (!copy_constructible<T>) = delete;
- constexpr option(const option& other)
- requires copy_constructible<T> && (!kHasInlinePayload)
- : option(nullopt)
+ constexpr option(const option& other)
+ requires copy_constructible<T> && (!trivially_copy_constructible<T>)
+ : option{nullopt}
{
if (other.has_value())
{
- construct(other.value());
+ construct(other.m_payload.as_init_unsafe());
}
}
+
+ 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>) = delete;
-
- constexpr option(option&& other)
- requires move_constructible<T> && kHasInlinePayload = default;
-
- constexpr option(option&& other)
- requires move_constructible<T> && (!kHasInlinePayload)
- : option(nullopt)
+ constexpr option(option&& other)
+ requires move_constructible<T> && (!trivially_move_constructible<T>)
+ : option{nullopt}
{
if (other.has_value())
{
- construct(ASL_MOVE(other.value()));
+ construct(ASL_MOVE(other.m_payload.as_init_unsafe()));
}
}
- 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>
diff --git a/asl/tests/box_tests.cpp b/asl/tests/box_tests.cpp index 53b6dda..0395e5f 100644 --- a/asl/tests/box_tests.cpp +++ b/asl/tests/box_tests.cpp @@ -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);
diff --git a/asl/tests/maybe_uninit_tests.cpp b/asl/tests/maybe_uninit_tests.cpp index 92999a2..524a10b 100644 --- a/asl/tests/maybe_uninit_tests.cpp +++ b/asl/tests/maybe_uninit_tests.cpp @@ -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);
diff --git a/asl/tests/option_tests.cpp b/asl/tests/option_tests.cpp index 557e2fe..20ee756 100644 --- a/asl/tests/option_tests.cpp +++ b/asl/tests/option_tests.cpp @@ -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>>);
diff --git a/asl/utility.hpp b/asl/utility.hpp index 69838e5..4f27017 100644 --- a/asl/utility.hpp +++ b/asl/utility.hpp @@ -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)
{
|