Rework some metaprogramming stuff

This commit is contained in:
2024-12-27 19:19:40 +01:00
parent 006a093353
commit 5642cba31b
13 changed files with 258 additions and 123 deletions

View File

@ -2,6 +2,7 @@
#include "asl/assert.hpp" #include "asl/assert.hpp"
#include "asl/utility.hpp" #include "asl/utility.hpp"
#include "asl/memory.hpp" #include "asl/memory.hpp"
#include "asl/print.hpp"
#include <cstdlib> #include <cstdlib>
@ -40,6 +41,7 @@ void* asl::GlobalHeap::realloc(void* old_ptr, [[maybe_unused]] const layout& old
void* new_ptr = alloc(new_layout); void* new_ptr = alloc(new_layout);
asl::memcpy(new_ptr, old_ptr, asl::min(old_layout.size, new_layout.size)); asl::memcpy(new_ptr, old_ptr, asl::min(old_layout.size, new_layout.size));
dealloc(old_ptr, old_layout);
return new_ptr; return new_ptr;
#endif #endif
} }

View File

@ -108,13 +108,16 @@ private:
} }
public: public:
constexpr buffer() requires default_constructible<Allocator> = default; constexpr buffer() requires default_constructible<Allocator> = default;
explicit constexpr buffer(Allocator allocator) explicit constexpr buffer(Allocator allocator)
: m_allocator{ASL_MOVE(allocator)} : m_allocator{ASL_MOVE(allocator)}
{} {}
// @Todo Destructor
// @Todo clear
// @Todo Copy/move constructor & assignment
constexpr isize_t size() const constexpr isize_t size() const
{ {
return decode_size(load_size_encoded()); return decode_size(load_size_encoded());
@ -150,7 +153,7 @@ public:
auto old_layout = layout::array<T>(old_capacity); auto old_layout = layout::array<T>(old_capacity);
auto new_layout = layout::array<T>(new_capacity); auto new_layout = layout::array<T>(new_capacity);
if (currently_on_heap && trivially_copyable<T>) if (currently_on_heap && trivially_move_constructible<T>)
{ {
m_data = reinterpret_cast<T*>(m_allocator.realloc(m_data, old_layout, new_layout)); m_data = reinterpret_cast<T*>(m_allocator.realloc(m_data, old_layout, new_layout));
m_capacity = new_capacity; m_capacity = new_capacity;
@ -204,7 +207,18 @@ public:
} }
} }
// @Todo operator[] // @Todo(C++23) Use deducing this
constexpr T& operator[](isize_t i)
{
ASL_ASSERT(i >= 0 && i <= size());
return data()[i];
}
constexpr const T& operator[](isize_t i) const
{
ASL_ASSERT(i >= 0 && i <= size());
return data()[i];
}
}; };
} // namespace asl } // namespace asl

View File

@ -56,24 +56,23 @@ constexpr void destruct_n(T* data, isize_t n)
} }
} }
template<typename T> template<move_constructible T>
constexpr void relocate_uninit_n(T* to, T* from, isize_t n) constexpr void relocate_uninit_n(T* to, T* from, isize_t n)
{ {
if constexpr (trivially_copyable<T>) if constexpr (trivially_move_constructible<T>)
{ {
static_assert(trivially_destructible<T>);
memcpy(to, from, size_of<T> * n); memcpy(to, from, size_of<T> * n);
} }
else else
{ {
static_assert(move_constructible<T>);
for (isize_t i = 0; i < n; ++i) for (isize_t i = 0; i < n; ++i)
{ {
// NOLINTNEXTLINE(*-pointer-arithmetic) // NOLINTNEXTLINE(*-pointer-arithmetic)
construct_at<T>(to + i, ASL_MOVE(from[i])); construct_at<T>(to + i, ASL_MOVE(from[i]));
} }
destruct_n(from, n);
} }
destruct_n(from, n);
} }
} // namespace asl } // namespace asl

View File

@ -67,8 +67,6 @@ template<typename T> concept trivially_move_assignable = trivially_assignable_fr
template<typename T> concept trivially_destructible = __is_trivially_destructible(T); template<typename T> concept trivially_destructible = __is_trivially_destructible(T);
template<typename T> concept trivially_copyable = __is_trivially_copyable(T);
template<typename T> concept copyable = copy_constructible<T> && copy_assignable<T>; template<typename T> concept copyable = copy_constructible<T> && copy_assignable<T>;
template<typename T> concept moveable = move_constructible<T> && move_assignable<T>; template<typename T> concept moveable = move_constructible<T> && move_assignable<T>;

View File

@ -63,23 +63,15 @@ concept is_option = requires
template<is_object T> template<is_object T>
class option class option
{ {
static constexpr bool kIsTrivial =
trivially_default_constructible<T> &&
trivially_copy_constructible<T> &&
trivially_move_constructible<T> &&
trivially_copy_assignable<T> &&
trivially_move_assignable<T> &&
trivially_destructible<T>;
static constexpr bool kHasNiche = has_niche<T>; static constexpr bool kHasNiche = has_niche<T>;
static constexpr bool kHasInlinePayload = kIsTrivial || kHasNiche; static constexpr bool kHasInlinePayload = default_constructible<T> || kHasNiche;
using Storage = select_t<kHasInlinePayload, T, maybe_uninit<T>>; 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{}; Storage m_payload;
ASL_NO_UNIQUE_ADDRESS HasValueMarker m_has_value; ASL_NO_UNIQUE_ADDRESS HasValueMarker m_has_value{};
template<typename... Args> template<typename... Args>
constexpr void construct(Args&&... args) constexpr void construct(Args&&... args)
@ -88,7 +80,7 @@ class option
if constexpr (kHasInlinePayload) if constexpr (kHasInlinePayload)
{ {
construct_at<T>(&m_payload, ASL_FWD(args)...); m_payload = T(ASL_FWD(args)...);
} }
else else
{ {
@ -122,9 +114,11 @@ public:
constexpr option() : option(nullopt) {} constexpr option() : option(nullopt) {}
// NOLINTNEXTLINE(*-explicit-conversions) // NOLINTNEXTLINE(*-explicit-conversions)
constexpr option(nullopt_t) requires (!kHasNiche) constexpr option(nullopt_t) requires (!kHasNiche) && trivially_default_constructible<T> {}
// NOLINTNEXTLINE(*-explicit-conversions)
constexpr option(nullopt_t) requires (!kHasNiche) && (!trivially_default_constructible<T>)
: m_payload{} : m_payload{}
, m_has_value{false}
{} {}
// NOLINTNEXTLINE(*-explicit-conversions) // NOLINTNEXTLINE(*-explicit-conversions)
@ -167,7 +161,7 @@ public:
!same_as<un_cvref_t<U>, option> && !same_as<un_cvref_t<U>, option> &&
!is_niche<U> !is_niche<U>
) )
: option() : option(nullopt)
{ {
construct(ASL_FWD(value)); construct(ASL_FWD(value));
} }
@ -177,7 +171,7 @@ public:
constexpr option(const option& other) constexpr option(const option& other)
requires copy_constructible<T> && (!kHasInlinePayload) requires copy_constructible<T> && (!kHasInlinePayload)
: option() : option(nullopt)
{ {
if (other.has_value()) if (other.has_value())
{ {
@ -193,7 +187,7 @@ public:
constexpr option(option&& other) constexpr option(option&& other)
requires move_constructible<T> && (!kHasInlinePayload) requires move_constructible<T> && (!kHasInlinePayload)
: option() : option(nullopt)
{ {
if (other.has_value()) if (other.has_value())
{ {
@ -211,7 +205,7 @@ public:
constructible_from<T, const U&> && constructible_from<T, const U&> &&
!option_internal::convertible_constructible_from_option<T, U> !option_internal::convertible_constructible_from_option<T, U>
) )
: option() : option(nullopt)
{ {
if (other.has_value()) if (other.has_value())
{ {
@ -226,7 +220,7 @@ public:
constructible_from<T, U&&> && constructible_from<T, U&&> &&
!option_internal::convertible_constructible_from_option<T, U> !option_internal::convertible_constructible_from_option<T, U>
) )
: option() : option(nullopt)
{ {
if (other.has_value()) if (other.has_value())
{ {
@ -415,6 +409,7 @@ public:
} }
} }
// @Todo(C++23) Deducing this
constexpr T&& value() && constexpr T&& value() &&
{ {
ASL_ASSERT_RELEASE(has_value()); ASL_ASSERT_RELEASE(has_value());

View File

@ -1,4 +1,5 @@
#include "asl/buffer.hpp" #include "asl/buffer.hpp"
#include "asl/print.hpp"
#include "asl/testing/testing.hpp" #include "asl/testing/testing.hpp"
@ -77,7 +78,6 @@ ASL_TEST(reserve_capacity)
ASL_TEST_EXPECT(count == 2); ASL_TEST_EXPECT(count == 2);
} }
// NOLINTBEGIN(*-pointer-arithmetic)
ASL_TEST(push) ASL_TEST(push)
{ {
asl::buffer<int32_t> b; asl::buffer<int32_t> b;
@ -85,28 +85,90 @@ ASL_TEST(push)
b.push(1); b.push(1);
ASL_TEST_EXPECT(b.size() == 1); ASL_TEST_EXPECT(b.size() == 1);
ASL_TEST_EXPECT(b.data()[0] == 1); ASL_TEST_EXPECT(b[0] == 1);
b.push(2); b.push(2);
b.push(3); b.push(3);
ASL_TEST_EXPECT(b.size() == 3); ASL_TEST_EXPECT(b.size() == 3);
ASL_TEST_EXPECT(b.data()[0] == 1); ASL_TEST_EXPECT(b[0] == 1);
ASL_TEST_EXPECT(b.data()[1] == 2); ASL_TEST_EXPECT(b[1] == 2);
ASL_TEST_EXPECT(b.data()[2] == 3); ASL_TEST_EXPECT(b[2] == 3);
b.push(4); b.push(4);
b.push(5); b.push(5);
b.push(6); b.push(6);
b.push(7); b.push(7);
ASL_TEST_EXPECT(b.size() == 7); ASL_TEST_EXPECT(b.size() == 7);
ASL_TEST_EXPECT(b.data()[0] == 1); ASL_TEST_EXPECT(b[0] == 1);
ASL_TEST_EXPECT(b.data()[1] == 2); ASL_TEST_EXPECT(b[1] == 2);
ASL_TEST_EXPECT(b.data()[2] == 3); ASL_TEST_EXPECT(b[2] == 3);
ASL_TEST_EXPECT(b.data()[3] == 4); ASL_TEST_EXPECT(b[3] == 4);
ASL_TEST_EXPECT(b.data()[4] == 5); ASL_TEST_EXPECT(b[4] == 5);
ASL_TEST_EXPECT(b.data()[5] == 6); ASL_TEST_EXPECT(b[5] == 6);
ASL_TEST_EXPECT(b.data()[6] == 7); ASL_TEST_EXPECT(b[6] == 7);
}
struct MoveableType
{
int moved{};
int value;
explicit MoveableType(int x) : value{x} {}
MoveableType(const MoveableType&) = delete;
MoveableType(MoveableType&& other) : moved{other.moved + 1}, value{other.value} {}
MoveableType& operator=(const MoveableType&) = delete;
MoveableType& operator=(MoveableType&&) = delete;
};
static_assert(!asl::trivially_copy_constructible<MoveableType>);
static_assert(!asl::trivially_move_constructible<MoveableType>);
static_assert(!asl::copyable<MoveableType>);
static_assert(asl::move_constructible<MoveableType>);
ASL_TEST(push_move)
{
asl::buffer<MoveableType> b;
static_assert(asl::buffer<MoveableType>::kInlineCapacity > 0);
b.push(0);
ASL_TEST_EXPECT(b[0].value == 0);
ASL_TEST_EXPECT(b[0].moved == 0);
b.push(1);
ASL_TEST_EXPECT(b[0].value == 0);
ASL_TEST_EXPECT(b[0].moved == 0);
ASL_TEST_EXPECT(b[1].value == 1);
ASL_TEST_EXPECT(b[1].moved == 0);
b.push(2);
ASL_TEST_EXPECT(b[0].value == 0);
ASL_TEST_EXPECT(b[0].moved == 1);
ASL_TEST_EXPECT(b[1].value == 1);
ASL_TEST_EXPECT(b[1].moved == 1);
ASL_TEST_EXPECT(b[2].value == 2);
ASL_TEST_EXPECT(b[2].moved == 0);
b.push(3);
ASL_TEST_EXPECT(b[0].value == 0);
ASL_TEST_EXPECT(b[0].moved == 1);
ASL_TEST_EXPECT(b[1].value == 1);
ASL_TEST_EXPECT(b[1].moved == 1);
ASL_TEST_EXPECT(b[2].value == 2);
ASL_TEST_EXPECT(b[2].moved == 0);
ASL_TEST_EXPECT(b[3].value == 3);
ASL_TEST_EXPECT(b[3].moved == 0);
b.push(4);
ASL_TEST_EXPECT(b[0].value == 0);
ASL_TEST_EXPECT(b[0].moved == 2);
ASL_TEST_EXPECT(b[1].value == 1);
ASL_TEST_EXPECT(b[1].moved == 2);
ASL_TEST_EXPECT(b[2].value == 2);
ASL_TEST_EXPECT(b[2].moved == 1);
ASL_TEST_EXPECT(b[3].value == 3);
ASL_TEST_EXPECT(b[3].moved == 1);
ASL_TEST_EXPECT(b[4].value == 4);
ASL_TEST_EXPECT(b[4].moved == 0);
} }
// NOLINTEND(*-pointer-arithmetic)
// @Todo Test push with non trivial move (non copy) types // @Todo Test push with non trivial move (non copy) types

View File

@ -5,6 +5,6 @@ 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<TriviallyDestructible>>); static_assert(asl::trivially_destructible<asl::maybe_uninit<TrivialType>>);
static_assert(!asl::trivially_destructible<asl::maybe_uninit<HasDestructor>>); static_assert(!asl::trivially_destructible<asl::maybe_uninit<WithDestructor>>);

View File

@ -13,59 +13,88 @@ static_assert(asl::same_as<asl::select_t<false, int, float>, float>);
static_assert(asl::same_as<asl::select_t<true, int, float>, int>); static_assert(asl::same_as<asl::select_t<true, int, float>, int>);
static_assert(asl::default_constructible<int>); static_assert(asl::default_constructible<int>);
static_assert(asl::default_constructible<TriviallyDefaultConstructible>); static_assert(asl::default_constructible<TrivialType>);
static_assert(asl::default_constructible<DefaultConstructible>); static_assert(asl::default_constructible<TrivialTypeDefaultValue>);
static_assert(!asl::default_constructible<NonDefaultConstructible>);
static_assert(asl::trivially_default_constructible<int>); static_assert(asl::trivially_default_constructible<int>);
static_assert(asl::trivially_default_constructible<TriviallyDefaultConstructible>); static_assert(asl::trivially_default_constructible<TrivialType>);
static_assert(!asl::trivially_default_constructible<DefaultConstructible>); static_assert(!asl::trivially_default_constructible<TrivialTypeDefaultValue>);
static_assert(!asl::trivially_default_constructible<NonDefaultConstructible>);
static_assert(asl::copy_constructible<int>); static_assert(asl::copy_constructible<int>);
static_assert(asl::copy_constructible<TriviallyCopyConstructible>); static_assert(asl::copy_constructible<TrivialType>);
static_assert(asl::copy_constructible<CopyConstructible>); static_assert(asl::copy_constructible<Copyable>);
static_assert(!asl::copy_constructible<NonCopyConstructible>); static_assert(!asl::copy_constructible<MoveableOnly>);
static_assert(!asl::copy_constructible<Pinned>);
static_assert(asl::trivially_copy_constructible<int>); static_assert(asl::trivially_copy_constructible<int>);
static_assert(asl::trivially_copy_constructible<TriviallyCopyConstructible>); static_assert(asl::trivially_copy_constructible<TrivialType>);
static_assert(!asl::trivially_copy_constructible<CopyConstructible>); static_assert(asl::trivially_copy_constructible<TrivialTypeDefaultValue>);
static_assert(!asl::trivially_copy_constructible<NonCopyConstructible>); static_assert(!asl::trivially_copy_constructible<WithDestructor>);
static_assert(!asl::trivially_copy_constructible<Copyable>);
static_assert(!asl::trivially_copy_constructible<MoveableOnly>);
static_assert(!asl::trivially_copy_constructible<Pinned>);
static_assert(asl::move_constructible<int>); static_assert(asl::move_constructible<int>);
static_assert(asl::move_constructible<TriviallyMoveConstructible>); static_assert(asl::move_constructible<TrivialType>);
static_assert(asl::move_constructible<MoveConstructible>); static_assert(asl::move_constructible<Copyable>);
static_assert(asl::move_constructible<CopyConstructible>); static_assert(asl::move_constructible<MoveableOnly>);
static_assert(!asl::move_constructible<NonMoveConstructible>); static_assert(!asl::move_constructible<Pinned>);
static_assert(asl::trivially_move_constructible<int>); static_assert(asl::trivially_move_constructible<int>);
static_assert(asl::trivially_move_constructible<TriviallyMoveConstructible>); static_assert(asl::trivially_move_constructible<TrivialType>);
static_assert(!asl::trivially_move_constructible<MoveConstructible>); static_assert(asl::trivially_move_constructible<TrivialTypeDefaultValue>);
static_assert(!asl::trivially_move_constructible<NonMoveConstructible>); static_assert(!asl::trivially_move_constructible<WithDestructor>);
static_assert(!asl::trivially_move_constructible<Copyable>);
static_assert(!asl::trivially_move_constructible<MoveableOnly>);
static_assert(!asl::trivially_move_constructible<Pinned>);
static_assert(asl::copy_assignable<int>); static_assert(asl::copy_assignable<int>);
static_assert(asl::copy_assignable<CopyAssignable>); static_assert(asl::copy_assignable<TrivialType>);
static_assert(asl::copy_assignable<TriviallyCopyAssignable>); static_assert(asl::copy_assignable<Copyable>);
static_assert(!asl::copy_assignable<NonCopyAssignable>); static_assert(!asl::copy_assignable<MoveableOnly>);
static_assert(!asl::copy_assignable<Pinned>);
static_assert(asl::trivially_copy_assignable<int>); static_assert(asl::trivially_copy_assignable<int>);
static_assert(!asl::trivially_copy_assignable<CopyAssignable>); static_assert(asl::trivially_copy_assignable<TrivialType>);
static_assert(asl::trivially_copy_assignable<TriviallyCopyAssignable>); static_assert(asl::trivially_copy_assignable<TrivialTypeDefaultValue>);
static_assert(!asl::trivially_copy_assignable<NonCopyAssignable>); static_assert(asl::trivially_copy_assignable<WithDestructor>);
static_assert(!asl::trivially_copy_assignable<Copyable>);
static_assert(!asl::trivially_copy_assignable<MoveableOnly>);
static_assert(!asl::trivially_copy_assignable<Pinned>);
static_assert(asl::copyable<int>);
static_assert(asl::copyable<TrivialType>);
static_assert(asl::copyable<Copyable>);
static_assert(!asl::copyable<MoveableOnly>);
static_assert(!asl::copyable<Pinned>);
static_assert(asl::moveable<int>);
static_assert(asl::moveable<TrivialType>);
static_assert(asl::moveable<Copyable>);
static_assert(asl::moveable<MoveableOnly>);
static_assert(!asl::moveable<Pinned>);
static_assert(asl::move_assignable<int>); static_assert(asl::move_assignable<int>);
static_assert(asl::move_assignable<MoveAssignable>); static_assert(asl::move_assignable<TrivialType>);
static_assert(asl::move_assignable<TriviallyMoveAssignable>); static_assert(asl::move_assignable<Copyable>);
static_assert(!asl::move_assignable<NonMoveAssignable>); static_assert(asl::move_assignable<MoveableOnly>);
static_assert(!asl::move_assignable<Pinned>);
static_assert(asl::trivially_move_assignable<int>); static_assert(asl::trivially_move_assignable<int>);
static_assert(!asl::trivially_move_assignable<MoveAssignable>); static_assert(asl::trivially_move_assignable<TrivialType>);
static_assert(asl::trivially_move_assignable<TriviallyMoveAssignable>); static_assert(asl::trivially_move_assignable<TrivialTypeDefaultValue>);
static_assert(!asl::trivially_move_assignable<NonMoveAssignable>); static_assert(asl::trivially_move_assignable<WithDestructor>);
static_assert(!asl::trivially_move_assignable<Copyable>);
static_assert(!asl::trivially_move_assignable<MoveableOnly>);
static_assert(!asl::trivially_move_assignable<Pinned>);
static_assert(asl::trivially_destructible<int>); static_assert(asl::trivially_destructible<int>);
static_assert(asl::trivially_destructible<TriviallyDestructible>); static_assert(asl::trivially_destructible<TrivialType>);
static_assert(!asl::trivially_destructible<HasDestructor>); static_assert(asl::trivially_destructible<TrivialTypeDefaultValue>);
static_assert(!asl::trivially_destructible<WithDestructor>);
static_assert(asl::trivially_destructible<Copyable>);
static_assert(asl::trivially_destructible<MoveableOnly>);
static_assert(asl::trivially_destructible<Pinned>);
static_assert(asl::same_as<int, asl::un_const_t<int>>); static_assert(asl::same_as<int, asl::un_const_t<int>>);
static_assert(asl::same_as<int, asl::un_const_t<const int>>); static_assert(asl::same_as<int, asl::un_const_t<const int>>);
@ -164,12 +193,6 @@ static_assert(asl::types_count<int, int> == 2);
static_assert(asl::types_count<int> == 1); static_assert(asl::types_count<int> == 1);
static_assert(asl::types_count<> == 0); static_assert(asl::types_count<> == 0);
static_assert(asl::trivially_copyable<int>);
static_assert(!asl::trivially_copyable<HasDestructor>);
static_assert(!asl::trivially_copyable<CopyAssignable>);
static_assert(asl::trivially_copyable<DefaultConstructible>);
static_assert(asl::trivially_copyable<TriviallyDefaultConstructible>);
class Base {}; class Base {};
class Derived : public Base {}; class Derived : public Base {};
class C {}; class C {};

View File

@ -28,28 +28,28 @@ static_assert(!asl::is_option<int>);
static_assert(asl::is_option<asl::option<int>>); static_assert(asl::is_option<asl::option<int>>);
static_assert(asl::is_option<const asl::option<int>>); static_assert(asl::is_option<const asl::option<int>>);
static_assert(asl::trivially_destructible<asl::option<TriviallyDestructible>>); static_assert(asl::trivially_destructible<asl::option<TrivialType>>);
static_assert(!asl::trivially_destructible<asl::option<HasDestructor>>); static_assert(!asl::trivially_destructible<asl::option<WithDestructor>>);
static_assert(asl::copy_constructible<asl::option<int>>); static_assert(asl::copy_constructible<asl::option<int>>);
static_assert(asl::copy_constructible<asl::option<CopyConstructible>>); static_assert(asl::copy_constructible<asl::option<Copyable>>);
static_assert(!asl::copy_constructible<asl::option<MoveConstructible>>); static_assert(!asl::copy_constructible<asl::option<MoveableOnly>>);
static_assert(!asl::copy_constructible<asl::option<NonMoveConstructible>>); static_assert(!asl::copy_constructible<asl::option<Pinned>>);
static_assert(asl::move_constructible<asl::option<int>>); static_assert(asl::move_constructible<asl::option<int>>);
static_assert(asl::move_constructible<asl::option<CopyConstructible>>); static_assert(asl::move_constructible<asl::option<Copyable>>);
static_assert(asl::move_constructible<asl::option<MoveConstructible>>); static_assert(asl::move_constructible<asl::option<MoveableOnly>>);
static_assert(!asl::move_constructible<asl::option<NonMoveConstructible>>); static_assert(!asl::move_constructible<asl::option<Pinned>>);
static_assert(asl::copy_assignable<asl::option<int>>); static_assert(asl::copy_assignable<asl::option<int>>);
static_assert(asl::copy_assignable<asl::option<CopyAssignable>>); static_assert(asl::copy_assignable<asl::option<Copyable>>);
static_assert(!asl::copy_assignable<asl::option<MoveAssignable>>); static_assert(!asl::copy_assignable<asl::option<MoveableOnly>>);
static_assert(!asl::copy_assignable<asl::option<NonMoveAssignable>>); static_assert(!asl::copy_assignable<asl::option<Pinned>>);
static_assert(asl::move_assignable<asl::option<int>>); static_assert(asl::move_assignable<asl::option<int>>);
static_assert(asl::move_assignable<asl::option<CopyAssignable>>); static_assert(asl::move_assignable<asl::option<Copyable>>);
static_assert(asl::move_assignable<asl::option<MoveAssignable>>); static_assert(asl::move_assignable<asl::option<MoveableOnly>>);
static_assert(!asl::move_assignable<asl::option<NonMoveAssignable>>); static_assert(!asl::move_assignable<asl::option<Pinned>>);
static_assert(asl::assignable_from<asl::option<Base*>&, asl::option<Derived*>>); static_assert(asl::assignable_from<asl::option<Base*>&, asl::option<Derived*>>);
static_assert(!asl::assignable_from<asl::option<Derived*>&, asl::option<Base*>>); static_assert(!asl::assignable_from<asl::option<Derived*>&, asl::option<Base*>>);
@ -70,16 +70,24 @@ static_assert(!asl::convertible_from<asl::option<ExplicitConversion>, asl::optio
static_assert(asl::convertible_from<asl::option<ImplicitConversion>, asl::option<int>>); static_assert(asl::convertible_from<asl::option<ImplicitConversion>, asl::option<int>>);
static_assert(asl::trivially_copy_constructible<asl::option<int>>); static_assert(asl::trivially_copy_constructible<asl::option<int>>);
static_assert(!asl::trivially_copy_constructible<asl::option<CopyConstructible>>); static_assert(asl::trivially_copy_constructible<asl::option<TrivialType>>);
static_assert(asl::trivially_copy_constructible<asl::option<TrivialTypeDefaultValue>>);
static_assert(!asl::trivially_copy_constructible<asl::option<Copyable>>);
static_assert(asl::trivially_move_constructible<asl::option<int>>); static_assert(asl::trivially_move_constructible<asl::option<int>>);
static_assert(!asl::trivially_move_constructible<asl::option<MoveConstructible>>); static_assert(asl::trivially_move_constructible<asl::option<TrivialType>>);
static_assert(asl::trivially_move_constructible<asl::option<TrivialTypeDefaultValue>>);
static_assert(!asl::trivially_move_constructible<asl::option<MoveableOnly>>);
static_assert(asl::trivially_copy_assignable<asl::option<int>>); static_assert(asl::trivially_copy_assignable<asl::option<int>>);
static_assert(!asl::trivially_copy_assignable<asl::option<CopyAssignable>>); static_assert(asl::trivially_copy_assignable<asl::option<TrivialType>>);
static_assert(asl::trivially_copy_assignable<asl::option<TrivialTypeDefaultValue>>);
static_assert(!asl::trivially_copy_assignable<asl::option<Copyable>>);
static_assert(asl::trivially_move_assignable<asl::option<int>>); static_assert(asl::trivially_move_assignable<asl::option<int>>);
static_assert(!asl::trivially_move_assignable<asl::option<MoveAssignable>>); static_assert(asl::trivially_move_assignable<asl::option<TrivialType>>);
static_assert(asl::trivially_move_assignable<asl::option<TrivialTypeDefaultValue>>);
static_assert(!asl::trivially_move_assignable<asl::option<MoveableOnly>>);
ASL_TEST(make_null) ASL_TEST(make_null)
{ {

View File

@ -3,10 +3,10 @@
#include "asl/tests/test_types.hpp" #include "asl/tests/test_types.hpp"
static_assert(asl::trivially_destructible<asl::span<int>>); static_assert(asl::trivially_destructible<asl::span<int>>);
static_assert(asl::trivially_destructible<asl::span<HasDestructor>>); static_assert(asl::trivially_destructible<asl::span<WithDestructor>>);
static_assert(asl::trivially_copyable<asl::span<int>>); static_assert(asl::trivially_copy_constructible<asl::span<int>>);
static_assert(asl::trivially_copyable<asl::span<NonCopyConstructible>>); static_assert(asl::trivially_copy_constructible<asl::span<Pinned>>);
static_assert(asl::size_of<asl::span<int>> == asl::size_of<void*> * 2); static_assert(asl::size_of<asl::span<int>> == asl::size_of<void*> * 2);
static_assert(asl::size_of<asl::span<int, 2>> == asl::size_of<void*>); static_assert(asl::size_of<asl::span<int, 2>> == asl::size_of<void*>);

View File

@ -2,7 +2,7 @@
#include "asl/testing/testing.hpp" #include "asl/testing/testing.hpp"
static_assert(asl::trivially_destructible<asl::string_view>); static_assert(asl::trivially_destructible<asl::string_view>);
static_assert(asl::trivially_copyable<asl::string_view>); static_assert(asl::trivially_copy_constructible<asl::string_view>);
ASL_TEST(default) ASL_TEST(default)
{ {

View File

@ -2,28 +2,59 @@
#include "asl/utility.hpp" #include "asl/utility.hpp"
struct DefaultConstructible { DefaultConstructible() {} }; struct TrivialType
struct TriviallyDefaultConstructible { TriviallyDefaultConstructible() = default; }; {
struct NonDefaultConstructible { NonDefaultConstructible() = delete; }; int x;
TrivialType() = default;
TrivialType(const TrivialType&) = default;
TrivialType(TrivialType&&) = default;
TrivialType& operator=(const TrivialType&) = default;
TrivialType& operator=(TrivialType&&) = default;
~TrivialType() = default;
};
struct CopyConstructible { CopyConstructible(const CopyConstructible&) {} }; struct TrivialTypeDefaultValue
struct TriviallyCopyConstructible { TriviallyCopyConstructible(const TriviallyCopyConstructible&) = default; }; {
struct NonCopyConstructible { NonCopyConstructible(const NonCopyConstructible&) = delete; }; int x{};
TrivialTypeDefaultValue() = default;
TrivialTypeDefaultValue(const TrivialTypeDefaultValue&) = default;
TrivialTypeDefaultValue(TrivialTypeDefaultValue&&) = default;
TrivialTypeDefaultValue& operator=(const TrivialTypeDefaultValue&) = default;
TrivialTypeDefaultValue& operator=(TrivialTypeDefaultValue&&) = default;
~TrivialTypeDefaultValue() = default;
};
struct MoveConstructible { MoveConstructible(MoveConstructible&&) {} }; struct WithDestructor
struct TriviallyMoveConstructible { TriviallyMoveConstructible(TriviallyMoveConstructible&&) = default; }; {
struct NonMoveConstructible { NonMoveConstructible(NonMoveConstructible&&) = delete; }; WithDestructor() = default;
WithDestructor(const WithDestructor&) = default;
WithDestructor(WithDestructor&&) = default;
WithDestructor& operator=(const WithDestructor&) = default;
WithDestructor& operator=(WithDestructor&&) = default;
~WithDestructor() {} // NOLINT
};
struct CopyAssignable { CopyAssignable(const CopyAssignable&) {} CopyAssignable& operator=(const CopyAssignable&) { return *this; } }; struct Copyable // NOLINT
struct TriviallyCopyAssignable { TriviallyCopyAssignable& operator=(const TriviallyCopyAssignable&) = default; }; {
struct NonCopyAssignable { NonCopyAssignable& operator=(const NonCopyAssignable&) = delete; }; Copyable(const Copyable&) {} // NOLINT
Copyable& operator=(const Copyable&); // NOLINT
};
struct MoveAssignable { MoveAssignable(MoveAssignable&&) {} MoveAssignable& operator=(MoveAssignable&&) { return *this; } }; struct MoveableOnly // NOLINT
struct TriviallyMoveAssignable { TriviallyMoveAssignable& operator=(TriviallyMoveAssignable&&) = default; }; {
struct NonMoveAssignable { NonMoveAssignable& operator=(NonMoveAssignable&&) = delete; }; MoveableOnly(const MoveableOnly&) = delete;
MoveableOnly& operator=(const MoveableOnly&) = delete;
MoveableOnly(MoveableOnly&&);
MoveableOnly& operator=(MoveableOnly&&); // NOLINT
};
struct TriviallyDestructible { ~TriviallyDestructible() = default; }; struct Pinned // NOLINT
struct HasDestructor { ~HasDestructor() {} }; {
Pinned(const Pinned&) = delete;
Pinned& operator=(const Pinned&) = delete;
Pinned(Pinned&&) = delete;
Pinned& operator=(Pinned&&) = delete;
};
struct DestructorObserver struct DestructorObserver
{ {
@ -31,6 +62,9 @@ struct DestructorObserver
explicit DestructorObserver(bool* destroyed_) : destroyed{destroyed_} {} explicit DestructorObserver(bool* destroyed_) : destroyed{destroyed_} {}
DestructorObserver(const DestructorObserver&) = delete;
DestructorObserver& operator=(const DestructorObserver&) = delete;
DestructorObserver(DestructorObserver&& other) DestructorObserver(DestructorObserver&& other)
: destroyed{asl::exchange(other.destroyed, nullptr)} : destroyed{asl::exchange(other.destroyed, nullptr)}
{} {}

View File

@ -19,7 +19,7 @@ T exchange(T& obj, U&& new_value)
return old_value; return old_value;
} }
template<trivially_copyable U, trivially_copyable T> template<trivially_copy_constructible U, trivially_copy_constructible T>
constexpr U bit_cast(T value) requires (size_of<T> == size_of<U>) constexpr U bit_cast(T value) requires (size_of<T> == size_of<U>)
{ {
return __builtin_bit_cast(U, value); return __builtin_bit_cast(U, value);