Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 18 additions & 16 deletions include/beman/inplace_vector/inplace_vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,13 @@ concept container_compatible_range =
std::ranges::input_range<Rng> &&
std::convertible_to<std::ranges::range_reference_t<Rng>, T>;

template <typename T>
concept satisfy_triviality = std::is_trivially_copyable_v<T> &&
std::is_trivially_default_constructible_v<T> &&
std::is_trivially_destructible_v<T>;

template <typename T, std::size_t N>
concept satify_constexpr = N == 0 || std::is_trivial_v<T>;
concept satisfy_constexpr = N == 0 || satisfy_triviality<T>;

template <typename T>
concept lessthan_comparable = requires(const T &a, const T &b) {
Expand Down Expand Up @@ -103,26 +108,23 @@ template <class T> struct zero_sized {

// Storage for trivial types.
template <class T, size_t N> struct trivial {
static_assert(std::is_trivial_v<T>,
static_assert(satisfy_triviality<T>,
"storage::trivial<T, C> requires Trivial<T>");
static_assert(N != size_t{0}, "N == 0, use zero_sized");

protected:
using size_type = smallest_size_t<N>;

private:
// If value_type is const, then const std::array of non-const elements:
using array_based_storage =
std::conditional_t<!std::is_const_v<T>, std::array<T, N>,
const std::array<std::remove_const_t<T>, N>>;
using array_based_storage = std::array<std::remove_const_t<T>, N>;
alignas(alignof(T)) array_based_storage storage_data_{};
size_type storage_size_ = 0;

protected:
constexpr const T *storage_data() const noexcept {
return storage_data_.data();
}
constexpr T *storage_data() noexcept { return storage_data_.data(); }
constexpr auto storage_data() noexcept { return storage_data_.data(); }
constexpr size_type storage_size() const noexcept { return storage_size_; }
constexpr void unsafe_set_size(size_t new_size) noexcept {
IV_EXPECT(size_type(new_size) <= N && "new_size out-of-bounds [0, N]");
Expand Down Expand Up @@ -158,25 +160,25 @@ template <class T, size_t N> struct raw_byte_based_storage {

/// Storage for non-trivial elements.
template <class T, size_t N> struct non_trivial {
static_assert(!std::is_trivial_v<T>,
static_assert(!satisfy_triviality<T>,
"use storage::trivial for Trivial<T> elements");
static_assert(N != size_t{0}, "use storage::zero for N==0");

protected:
using size_type = smallest_size_t<N>;

private:
using byte_based_storage = std::conditional_t<
!std::is_const_v<T>, raw_byte_based_storage<T, N>,
const raw_byte_based_storage<std::remove_const_t<T>, N>>;
using byte_based_storage = raw_byte_based_storage<std::remove_const_t<T>, N>;
byte_based_storage storage_data_{}; // BUGBUG: test SIMD types
size_type storage_size_ = 0;

protected:
constexpr const T *storage_data() const noexcept {
return storage_data_.storage_data(0);
}
constexpr T *storage_data() noexcept { return storage_data_.storage_data(0); }
constexpr auto storage_data() noexcept {
return storage_data_.storage_data(0);
}
constexpr size_type storage_size() const noexcept { return storage_size_; }
constexpr void unsafe_set_size(size_t new_size) noexcept {
IV_EXPECT(size_type(new_size) <= N && "new_size out-of-bounds [0, N)");
Expand All @@ -201,7 +203,7 @@ template <class T, size_t N> struct non_trivial {
// Selects the vector storage.
template <class T, size_t N>
using storage_for = std::conditional_t<
!satify_constexpr<T, N>, non_trivial<T, N>,
!satisfy_constexpr<T, N>, non_trivial<T, N>,
std::conditional_t<N == 0, zero_sized<T>, trivial<T, N>>>;

} // namespace storage
Expand Down Expand Up @@ -312,7 +314,7 @@ struct inplace_vector_base : private storage::storage_for<T, N> {
unsafe_destroy(T *first,
T *last) noexcept(std::is_nothrow_destructible_v<T>) {
assert_iterator_pair_in_range(first, last);
if constexpr (N > 0 && !std::is_trivial_v<T>) {
if constexpr (N > 0 && !std::is_trivially_destructible_v<T>) {
for (; first != last; ++first)
first->~T();
}
Expand All @@ -326,7 +328,7 @@ struct inplace_vector_base : private storage::storage_for<T, N> {
requires(std::constructible_from<T, Args...>)
{
IV_EXPECT(size() < capacity() && "inplace_vector out-of-memory");
std::construct_at(end(), std::forward<Args>(args)...);
std::construct_at(storage_data() + size(), std::forward<Args>(args)...);
unsafe_set_size(size() + size_type(1));
return this->back();
}
Expand Down Expand Up @@ -518,7 +520,7 @@ namespace beman::inplace_vector {

template <typename IV>
concept has_constexpr_support =
details::satify_constexpr<typename IV::value_type, IV::capacity()>;
details::satisfy_constexpr<typename IV::value_type, IV::capacity()>;

/// Dynamically-resizable fixed-N vector with inplace storage.
template <class T, size_t N>
Expand Down
2 changes: 1 addition & 1 deletion tests/beman/inplace_vector/constexpr.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ struct Some {
return val <=> other.val;
}
};
static_assert(std::is_trivial_v<Some>);
static_assert(beman::inplace_vector::details::satisfy_triviality<Some>);

using beman::inplace_vector::has_constexpr_support;
using beman::inplace_vector::inplace_vector;
Expand Down
21 changes: 11 additions & 10 deletions tests/beman/inplace_vector/gtest_setup.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
// clang-format off
/*
| (Trivially default | Trivially | Trivially copy | Trivially move | Trivially copy | Trivially move | Trivial* | Type
| constructible) | destructible | constructible | constructible | assignable | assignable | |
| constructible) | destructible | constructible | constructible | assignable | assignable | *** |
--------+--------------------+--------------+----------------+----------------+----------------+----------------+----------+----------------------------------
Copy | (YES) | - | YES | - | - | - | YES | Trivial
c'tor | (NO) | - | YES | - | - | - | NO | NonTriviallyDefaultConstructible
Expand Down Expand Up @@ -88,14 +88,15 @@ meant | - | YES | - | NO |

*) The values in this column do not vary independently, they are implied by the other properties
**) Implied by "not trivially destructible"
***) is_trivial<T> was deprecated in c++26, we use beman::inplace_vector::details::satisfy_triviality<T>
*/

// A trivial type
struct Trivial {
int value;
friend constexpr bool operator==(Trivial x, Trivial y) = default;
};
static_assert(std::is_trivial_v <Trivial>);
static_assert(beman::inplace_vector::details::satisfy_triviality<Trivial>);
static_assert(std::is_trivially_default_constructible_v<Trivial>);
static_assert(std::is_trivially_copy_constructible_v <Trivial>);
static_assert(std::is_trivially_move_constructible_v <Trivial>);
Expand All @@ -109,7 +110,7 @@ struct NonTriviallyDefaultConstructible {
int value = 0;
friend constexpr bool operator==(NonTriviallyDefaultConstructible x, NonTriviallyDefaultConstructible y) = default;
};
static_assert(not std::is_trivial_v <NonTriviallyDefaultConstructible>);
static_assert(not beman::inplace_vector::details::satisfy_triviality<NonTriviallyDefaultConstructible>);
static_assert(not std::is_trivially_default_constructible_v<NonTriviallyDefaultConstructible>);
static_assert( std::is_default_constructible_v <NonTriviallyDefaultConstructible>);
static_assert( std::is_trivially_copy_constructible_v <NonTriviallyDefaultConstructible>);
Expand All @@ -129,7 +130,7 @@ struct NonTriviallyCopyConstructible {
constexpr NonTriviallyCopyConstructible &operator=(NonTriviallyCopyConstructible const &) noexcept = default;
friend constexpr bool operator==(NonTriviallyCopyConstructible x, NonTriviallyCopyConstructible y) = default;
};
static_assert(not std::is_trivial_v <NonTriviallyCopyConstructible>);
static_assert(not beman::inplace_vector::details::satisfy_triviality<NonTriviallyCopyConstructible>);
static_assert( std::is_trivially_default_constructible_v <NonTriviallyCopyConstructible>);
static_assert(not std::is_trivially_copy_constructible_v <NonTriviallyCopyConstructible>);
static_assert( std::is_copy_constructible_v <NonTriviallyCopyConstructible>);
Expand All @@ -149,7 +150,7 @@ struct NonTriviallyMoveConstructible {
constexpr NonTriviallyMoveConstructible &operator=(NonTriviallyMoveConstructible const &) noexcept = default;
friend constexpr bool operator==(NonTriviallyMoveConstructible x, NonTriviallyMoveConstructible y) = default;
};
static_assert(not std::is_trivial_v <NonTriviallyMoveConstructible>);
static_assert(not beman::inplace_vector::details::satisfy_triviality<NonTriviallyMoveConstructible>);
static_assert( std::is_trivially_default_constructible_v <NonTriviallyMoveConstructible>);
static_assert( std::is_trivially_copy_constructible_v <NonTriviallyMoveConstructible>);
static_assert(not std::is_trivially_move_constructible_v <NonTriviallyMoveConstructible>);
Expand All @@ -174,7 +175,7 @@ struct NonTriviallyCopyAssignable {
constexpr NonTriviallyCopyAssignable &operator=(NonTriviallyCopyAssignable &&) noexcept = default;
friend constexpr bool operator==(NonTriviallyCopyAssignable x, NonTriviallyCopyAssignable y) = default;
};
static_assert(not std::is_trivial_v <NonTriviallyCopyAssignable>);
static_assert(not beman::inplace_vector::details::satisfy_triviality<NonTriviallyCopyAssignable>);
static_assert( std::is_trivially_default_constructible_v<NonTriviallyCopyAssignable>);
static_assert( std::is_trivially_copy_constructible_v <NonTriviallyCopyAssignable>);
static_assert( std::is_trivially_move_constructible_v <NonTriviallyCopyAssignable>);
Expand All @@ -199,7 +200,7 @@ struct NonTriviallyMoveAssignable {

friend constexpr bool operator==(NonTriviallyMoveAssignable x, NonTriviallyMoveAssignable y) = default;
};
static_assert(not std::is_trivial_v <NonTriviallyMoveAssignable>);
static_assert(not beman::inplace_vector::details::satisfy_triviality<NonTriviallyMoveAssignable>);
static_assert( std::is_trivially_default_constructible_v<NonTriviallyMoveAssignable>);
static_assert( std::is_trivially_copy_constructible_v <NonTriviallyMoveAssignable>);
static_assert( std::is_trivially_move_constructible_v <NonTriviallyMoveAssignable>);
Expand All @@ -215,7 +216,7 @@ struct TriviallyAssignable {
constexpr ~TriviallyAssignable() {}
friend constexpr bool operator==(TriviallyAssignable x, TriviallyAssignable y) = default;
};
static_assert(not std::is_trivial_v <TriviallyAssignable>);
static_assert(not beman::inplace_vector::details::satisfy_triviality<TriviallyAssignable>);
static_assert(not std::is_trivially_default_constructible_v<TriviallyAssignable>);
static_assert( std::is_default_constructible_v <TriviallyAssignable>);
static_assert(not std::is_trivially_copy_constructible_v <TriviallyAssignable>);
Expand All @@ -242,7 +243,7 @@ struct TriviallyDestructible {

friend constexpr bool operator==(TriviallyDestructible x, TriviallyDestructible y) = default;
};
static_assert(not std::is_trivial_v <TriviallyDestructible>);
static_assert(not beman::inplace_vector::details::satisfy_triviality<TriviallyDestructible>);
static_assert(not std::is_trivially_default_constructible_v<TriviallyDestructible>);
static_assert( std::is_default_constructible_v <TriviallyDestructible>);
static_assert(not std::is_trivially_copy_constructible_v <TriviallyDestructible>);
Expand Down Expand Up @@ -294,7 +295,7 @@ struct counts_objects<T, std::void_t<decltype(T::num_objects)>>
template<typename T>
inline constexpr bool counts_objects_v = counts_objects<T>::value;

static_assert(not std::is_trivial_v <NonTrivial>);
static_assert(not beman::inplace_vector::details::satisfy_triviality<NonTrivial>);
static_assert(not std::is_trivially_default_constructible_v<NonTrivial>);
static_assert( std::is_default_constructible_v <NonTrivial>);
static_assert(not std::is_trivially_copy_constructible_v <NonTrivial>);
Expand Down
7 changes: 4 additions & 3 deletions tests/beman/inplace_vector/ref_impl.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ struct tint {
explicit operator std::size_t() { return i; }
};

static_assert(std::is_trivial<tint>{} && std::is_copy_constructible<tint>{} &&
static_assert(beman::inplace_vector::details::satisfy_triviality<tint> &&
std::is_copy_constructible<tint>{} &&
std::is_move_constructible<tint>{},
"");

Expand Down Expand Up @@ -135,8 +136,8 @@ struct moint final {
bool operator==(moint b) { return i == b.i; }
};

static_assert(!std::is_trivial<moint>{} and
!std::is_copy_constructible<moint>{} and
static_assert(!beman::inplace_vector::details::satisfy_triviality<moint> &&
!std::is_copy_constructible<moint>{} &&
std::is_move_constructible<moint>{},
"");

Expand Down