diff --git a/BUILD.bazel b/BUILD.bazel index 11e3d22c..1a7a1eef 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -251,8 +251,10 @@ cc_library( hdrs = ["include/fixed_containers/fixed_vector.hpp"], includes = ["include"], deps = [ + ":algorithm", ":concepts", ":consteval_compare", + ":integer_range", ":iterator_utils", ":optional_storage", ":preconditions", diff --git a/include/fixed_containers/fixed_vector.hpp b/include/fixed_containers/fixed_vector.hpp index 47085eac..6f93ae7f 100644 --- a/include/fixed_containers/fixed_vector.hpp +++ b/include/fixed_containers/fixed_vector.hpp @@ -1,7 +1,9 @@ #pragma once +#include "fixed_containers/algorithm.hpp" #include "fixed_containers/concepts.hpp" #include "fixed_containers/consteval_compare.hpp" +#include "fixed_containers/integer_range.hpp" #include "fixed_containers/iterator_utils.hpp" #include "fixed_containers/optional_storage.hpp" #include "fixed_containers/preconditions.hpp" @@ -355,7 +357,7 @@ class FixedVectorBase check_not_full(loc); const std::size_t index = this->advance_all_after_iterator_by_n(it, 1); place_at(index, v); - return begin() + static_cast(index); + return create_iterator(index); } constexpr iterator insert( const_iterator it, @@ -365,7 +367,7 @@ class FixedVectorBase check_not_full(loc); const std::size_t index = this->advance_all_after_iterator_by_n(it, 1); place_at(index, std::move(v)); - return begin() + static_cast(index); + return create_iterator(index); } template constexpr iterator insert( @@ -396,7 +398,7 @@ class FixedVectorBase check_not_full(std_transition::source_location::current()); const std::size_t index = this->advance_all_after_iterator_by_n(it, 1); emplace_at(index, std::forward(args)...); - return begin() + static_cast(index); + return create_iterator(index); } /** @@ -449,22 +451,21 @@ class FixedVectorBase const std::size_t read_start = this->index_of(last); const std::size_t write_start = this->index_of(first); - std::size_t entry_count_to_move = size() - read_start; - const std::size_t entry_count_to_remove = read_start - write_start; + const auto entry_count_to_move = static_cast(end() - last); + const auto entry_count_to_remove = static_cast(last - first); // Clean out the gap - destroy_index_range(write_start, write_start + entry_count_to_remove); + destroy_range({.start = write_start, .distance = entry_count_to_remove}); + + auto read_start_it = create_iterator(read_start); + auto read_end_it = create_iterator(read_start + entry_count_to_move); + auto write_start_it = create_iterator(write_start); // Do the move - for (std::size_t i = 0; i < entry_count_to_move; ++i) - { - place_at(write_start + i, - std::move(optional_storage_detail::get(array_unchecked_at(read_start + i)))); - destroy_at(read_start + i); - } + std::move(read_start_it, read_end_it, write_start_it); decrement_size(entry_count_to_remove); - return iterator{this->begin() + static_cast(write_start)}; + return create_iterator(write_start); } /** @@ -482,7 +483,7 @@ class FixedVectorBase */ constexpr FixedVectorBase& clear() noexcept { - destroy_index_range(0, size()); + destroy_range({.start = 0, .distance = size()}); set_size(0); return *this; } @@ -653,14 +654,10 @@ class FixedVectorBase const std::size_t write_start = read_start + n; const std::size_t value_count_to_move = size() - read_start; - const std::size_t read_end = read_start + value_count_to_move - 1; - const std::size_t write_end = write_start + value_count_to_move - 1; - - for (std::size_t i = 0; i < value_count_to_move; i++) - { - place_at(write_end - i, std::move(unchecked_at(read_end - i))); - destroy_at(read_end - i); - } + auto read_start_it = create_iterator(read_start); + auto read_end_it = create_iterator(read_start + value_count_to_move); + auto write_end_it = create_iterator(write_start + value_count_to_move); + algorithm::emplace_move_backward(read_start_it, read_end_it, write_end_it); increment_size(n); @@ -691,11 +688,12 @@ class FixedVectorBase const std::size_t write_index = this->advance_all_after_iterator_by_n(it, entry_count_to_add); - for (std::size_t i = write_index; first != last; std::advance(first, 1), i++) + auto write_it = create_iterator(write_index); + for (auto w_it = write_it; first != last; std::advance(first, 1), std::advance(w_it, 1)) { - place_at(i, *first); + std::construct_at(&*w_it, *first); } - return begin() + static_cast(write_index); + return write_it; } template @@ -705,55 +703,52 @@ class FixedVectorBase InputIt last, const std_transition::source_location& loc) { + const std::size_t original_size = size(); + // Place everything at the end of the vector - std::size_t new_size = size(); - for (; first != last && new_size < max_size(); ++first, ++new_size) + for (; first != last && size() < max_size(); ++first) { - place_at(new_size, *first); + push_back_internal(*first); } if (first != last) // Reached capacity { - // Count excess elements + std::size_t excess_element_count = 0; for (; first != last; ++first) { - new_size++; + excess_element_count++; } - Checking::length_error(new_size, loc); + Checking::length_error(MAXIMUM_SIZE + excess_element_count, loc); } // Rotate into the correct places const std::size_t write_index = this->index_of(it); - std::rotate( - create_iterator(write_index), create_iterator(size()), create_iterator(new_size)); - set_size(new_size); + auto write_it = create_iterator(write_index); + std::rotate({write_it}, create_iterator(original_size), create_iterator(size())); - return begin() + static_cast(write_index); + return write_it; } - constexpr iterator create_iterator(const std::size_t start_index) noexcept + constexpr iterator create_iterator(const std::size_t offset_from_start) noexcept { auto array_it = std::next(std::begin(IMPLEMENTATION_DETAIL_DO_NOT_USE_array_), - static_cast(start_index)); + static_cast(offset_from_start)); return iterator{array_it, Mapper{}}; } - constexpr const_iterator create_const_iterator(const std::size_t start_index) const noexcept + constexpr const_iterator create_const_iterator( + const std::size_t offset_from_start) const noexcept { auto array_it = std::next(std::begin(IMPLEMENTATION_DETAIL_DO_NOT_USE_array_), - static_cast(start_index)); + static_cast(offset_from_start)); return const_iterator{array_it, Mapper{}}; } private: - constexpr std::size_t index_of(iterator it) const - { - return static_cast(it - begin()); - } constexpr std::size_t index_of(const_iterator it) const { - return static_cast(it - cbegin()); + return static_cast(std::distance(cbegin(), it)); } constexpr void check_not_full(const std_transition::source_location& loc) const @@ -812,14 +807,15 @@ class FixedVectorBase array_unchecked_at(i).value.~T(); } - constexpr void destroy_index_range(std::size_t, std::size_t) + constexpr void destroy_range(const StartingIntegerAndDistance&) requires TriviallyDestructible { } - constexpr void destroy_index_range(std::size_t from_inclusive, std::size_t to_exclusive) + constexpr void destroy_range(const StartingIntegerAndDistance& start_and_distance) requires NotTriviallyDestructible { - for (std::size_t i = from_inclusive; i < to_exclusive; i++) + const IntegerRange range = start_and_distance.to_range(); + for (std::size_t i = range.start_inclusive(); i < range.end_exclusive(); i++) { destroy_at(i); } @@ -829,7 +825,6 @@ class FixedVectorBase { std::construct_at(&array_unchecked_at(i), v); } - constexpr void place_at(const std::size_t i, value_type&& v) { std::construct_at(&array_unchecked_at(i), std::move(v)); diff --git a/test/fixed_vector_test.cpp b/test/fixed_vector_test.cpp index ed1ff5c8..1df9e9bf 100644 --- a/test/fixed_vector_test.cpp +++ b/test/fixed_vector_test.cpp @@ -876,7 +876,7 @@ TEST(FixedVector, IteratorAssignment) FixedVector::iterator it; // Default construction FixedVector::const_iterator const_it; // Default construction - const_it = it; // Non-const needs to assignable to const + const_it = it; // Non-const needs to be assignable to const } TEST(FixedVector, TrivialIterators)