Skip to content

Commit

Permalink
make static_vector trivialy copyable for trivialy copyable element types
Browse files Browse the repository at this point in the history
  • Loading branch information
Artur Bać committed Feb 28, 2024
1 parent 1f789c0 commit 367449f
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 19 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.20 FATAL_ERROR )
include(CheckCXXCompilerFlag)

project(small_vectors
VERSION 3.0.2
VERSION 3.0.3
LANGUAGES CXX
HOMEPAGE_URL "https://github.com/arturbac/small_vectors"
)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
C++20,23 utilities library

## features
* static vector is tivialy_copyable for trivialy_copyable element types so it get compiler optimisation with memcpy during copying (since v3.0.3-devel)
* static vectors with in class storage ( static_vector is address independant and may be used in interprocess data exchange)
* small vectors with in class storage and/or dynamic allocated memory with custom size type for small_vector and adjusted minimal size type for static_vector depending on number of elements
* static vector fully constant evaluated for trivial element types
Expand Down
2 changes: 2 additions & 0 deletions include/coll/detail/coll_concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ concept allocate_constraint = requires {
requires sizeof(value_type) != 0;
requires sizeof(value_type) % alignof(value_type) == 0u;
};
template<typename value_type>
concept trivially_copyable = std::is_trivially_copyable_v<value_type>;
} // namespace coll::concepts

namespace coll::detail
Expand Down
25 changes: 21 additions & 4 deletions include/coll/static_vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,22 @@ struct static_vector

constexpr static_vector() noexcept = default;

constexpr static_vector(static_vector && rh) noexcept
requires coll::concepts::trivially_copyable<value_type>
= default;

constexpr static_vector(static_vector const & rh) noexcept
requires coll::concepts::trivially_copyable<value_type>
= default;

constexpr static_vector(static_vector && rh) noexcept(std::is_nothrow_move_constructible_v<value_type>)
requires std::move_constructible<value_type>
requires(std::move_constructible<value_type> && !coll::concepts::trivially_copyable<value_type>)
{
storage_.construct_move(std::move(rh.storage_));
}

constexpr static_vector(static_vector const & rh) noexcept(std::is_nothrow_copy_constructible_v<value_type>)
requires std::copy_constructible<value_type>
requires(std::copy_constructible<value_type> && !coll::concepts::trivially_copyable<value_type>)
{
storage_.construct_copy(rh.storage_);
}
Expand All @@ -110,15 +118,24 @@ struct static_vector
storage_.construct_copy(rh.storage_);
}

// static_vector is address independant which means it is trivialy copyable for trivially_copyable<value_type>
constexpr static_vector & operator=(static_vector && rh) noexcept
requires coll::concepts::trivially_copyable<value_type>
= default;

constexpr static_vector & operator=(static_vector const & rh) noexcept
requires coll::concepts::trivially_copyable<value_type>
= default;

constexpr static_vector & operator=(static_vector && rh) noexcept(std::is_nothrow_move_assignable_v<value_type>)
requires std::movable<value_type>
requires(std::movable<value_type> && !coll::concepts::trivially_copyable<value_type>)
{
storage_.assign_move(std::move(rh.storage_));
return *this;
}

constexpr static_vector & operator=(static_vector const & rh) noexcept(std::is_nothrow_copy_assignable_v<value_type>)
requires std::copyable<value_type>
requires(std::copyable<value_type> && !coll::concepts::trivially_copyable<value_type>)
{
storage_.assign_copy(rh.storage_);
return *this;
Expand Down
54 changes: 40 additions & 14 deletions unit_tests/static_vector_ut.cc
Original file line number Diff line number Diff line change
Expand Up @@ -275,29 +275,50 @@ int main()
result |= run_constexpr_test<traits_list>(fn_tmpl);
result |= run_consteval_test<constexpr_traits_list>(fn_tmpl);
};
auto fn = []
{
using vector_type = static_vector<char, 10>;
vector_type vec{};
emplace_back(vec, 1);
emplace_back(vec, 2);
vec.emplace_back(3);
vector_type vec2{std::move(vec)};
return vec2;
};
static constexpr auto val = fn();
//---------------------------------------------------------------------------------------------------------
"test_static_vector_move"_test = [&result]
{
auto fn_tmpl = []<typename value_type>(value_type const *) -> metatests::test_result
{
auto constexpr elements = 10;
using vector_type = static_vector<value_type, elements>;
vector_type vec;
// we need to profive {} for vec as with tirvialy copyable internal array would not be initialized
// in unoccupied space and current c++ standard treats this as not allowed to happen in consteval
vector_type vec{};
emplace_back(vec, 1);
emplace_back(vec, 2);
vec.emplace_back(3);
auto res = emplace_back(vec, 4);
test_result tr;
tr = constexpr_test(res == vector_outcome_e::no_error) | constexpr_test(size(vec) == 4)
| constexpr_test(std::distance(begin(vec), end(vec)) == size(vec));

constexpr_test(res == vector_outcome_e::no_error);
constexpr_test(size(vec) == 4);
constexpr_test(std::distance(begin(vec), end(vec)) == size(vec));

std::array<value_type, 4> tst{1, 2, 3, 4};
tr |= constexpr_test(equal(vec, tst));
constexpr_test(equal(vec, tst));

vector_type vec2{std::move(vec)};
tr |= constexpr_test(size(vec) == 0) | constexpr_test(size(vec2) == 4) | constexpr_test(equal(vec2, tst));
if constexpr(coll::concepts::trivially_copyable<value_type>)
constexpr_test(
size(vec) == 4
); // unchanged as copied by compiler with memcpy, requirement is to leave in valid state
else
constexpr_test(size(vec) == 0);
constexpr_test(size(vec2) == 4);
constexpr_test(equal(vec2, tst));

return tr;
return {};
};

result |= run_constexpr_test<traits_list>(fn_tmpl);
Expand All @@ -311,23 +332,28 @@ int main()
{
auto constexpr elements = 10;
using vector_type = static_vector<value_type, elements>;
vector_type vec;
// we need to profive {} for vec as with tirvialy copyable internal array would not be initialized
// in unoccupied space and current c++ standard treats this as not allowed to happen in consteval
vector_type vec{};
emplace_back(vec, 1);
emplace_back(vec, 2);
vec.emplace_back(3);
auto res = emplace_back(vec, 4);

test_result tr = constexpr_test(res == vector_outcome_e::no_error) | constexpr_test(size(vec) == 4)
| constexpr_test(std::distance(begin(vec), end(vec)) == size(vec));
constexpr_test(res == vector_outcome_e::no_error);
constexpr_test(size(vec) == 4);
constexpr_test(std::distance(begin(vec), end(vec)) == size(vec));

std::array<value_type, 4> tst{1, 2, 3, 4};
tr |= constexpr_test(equal(vec, tst));
constexpr_test(equal(vec, tst));

vector_type vec2{const_cast<vector_type const &>(vec)};
tr |= constexpr_test(size(vec) == 4) | constexpr_test(size(vec2) == 4) | constexpr_test(equal(vec, tst))
| constexpr_test(equal(vec2, tst));
constexpr_test(size(vec) == 4);
constexpr_test(size(vec2) == 4);
constexpr_test(equal(vec, tst));
constexpr_test(equal(vec2, tst));

return tr;
return {};
};

result |= run_constexpr_test<traits_list>(fn_tmpl);
Expand Down

0 comments on commit 367449f

Please sign in to comment.