From a958c515e4cfcd5572ac7e2c3a567e832630a12d Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 1 May 2026 11:34:54 +0200 Subject: kstd/vector: implement append_range --- libs/kstd/include/kstd/bits/concepts.hpp | 15 +++++++ libs/kstd/include/kstd/vector | 69 +++++++++++++++++++++++++++++++- 2 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 libs/kstd/include/kstd/bits/concepts.hpp (limited to 'libs/kstd/include') diff --git a/libs/kstd/include/kstd/bits/concepts.hpp b/libs/kstd/include/kstd/bits/concepts.hpp new file mode 100644 index 0000000..74c25cb --- /dev/null +++ b/libs/kstd/include/kstd/bits/concepts.hpp @@ -0,0 +1,15 @@ +#ifndef KSTD_BITS_CONCEPTS_HPP +#define KSTD_BITS_CONCEPTS_HPP + +#include +#include +namespace kstd::bits +{ + + template + concept container_compatible_range = + std::ranges::input_range && std::convertible_to, ValueType>; + +} + +#endif diff --git a/libs/kstd/include/kstd/vector b/libs/kstd/include/kstd/vector index 97fdffe..2ecb6a8 100644 --- a/libs/kstd/include/kstd/vector +++ b/libs/kstd/include/kstd/vector @@ -2,6 +2,7 @@ #define KSTD_VECTOR_HPP #include +#include #include #include @@ -882,6 +883,68 @@ namespace kstd return this->back(); } + //! Append the elements of a given range to this vector. + //! + //! @param range The range of elements to be appended. + //! @tparam SourceRange A container compatible range type. + template SourceRange> + requires requires(Allocator allocator, pointer destination, SourceRange range) { + std::allocator_traits::construct(allocator, destination, *std::ranges::begin(range)); + } + // NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward, misc-no-recursion) + constexpr auto append_range(SourceRange && range) -> void + { + if constexpr (std::ranges::forward_range || std::ranges::sized_range) + { + auto number_of_elements = static_cast(std::ranges::distance(range)); + + if (!capacity()) + { + reserve(number_of_elements); + } + + if (capacity() - size() >= number_of_elements) + { + uninitialized_copy_with_allocator(std::ranges::begin(range), end(), number_of_elements); + m_size += number_of_elements; + return; + } + + auto new_capacity = m_capacity + std::max(size(), number_of_elements); + auto new_data = allocate_n(new_capacity); + auto old_size = size(); + + uninitialized_move_with_allocator(begin(), new_data, size()); + uninitialized_copy_with_allocator(std::ranges::begin(range), new_data + size(), number_of_elements); + clear_and_deallocate(); + m_data = new_data; + m_capacity = new_capacity; + m_size = old_size + number_of_elements; + return; + } + + auto range_begin = std::ranges::begin(range); + auto range_end = std::ranges::end(range); + + for (auto i = capacity() - size(); i > 0; --i, ++range_begin) + { + emplace_back(*range_begin); + } + + if (range_begin == range_end) + { + return; + } + + auto remainder = vector{get_allocator()}; + for (; range_begin != range_end; ++range_begin) + { + remainder.emplace_back(*static_cast>(range_begin)); + } + reserve(size() + std::max(size(), remainder.size())); + append_range(remainder); + } + //! Remove the last element of this vector. //! //! If this vector is empty, the behavior is undefined. @@ -950,7 +1013,8 @@ namespace kstd //! @param from The start of the source range. //! @param to The start of the target range inside this vector. //! @param count The number of elements to copy - constexpr auto uninitialized_copy_with_allocator(const_iterator from, iterator to, size_type count) + template + constexpr auto uninitialized_copy_with_allocator(SourceIterator from, iterator to, size_type count) { for (auto i = 0uz; i < count; ++i) { @@ -963,7 +1027,8 @@ namespace kstd //! @param from The start of the source range. //! @param to The start of the target range inside this vector. //! @param count The number of elements to copy - constexpr auto uninitialized_move_with_allocator(iterator from, iterator to, size_type count) + template + constexpr auto uninitialized_move_with_allocator(SourceIterator from, iterator to, size_type count) { for (auto i = 0uz; i < count; ++i) { -- cgit v1.2.3