From 2773e457773e3c88c212d6403950cef1fc96f880 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Fri, 1 May 2026 17:22:53 +0200 Subject: kstd/vector: implement insert_range --- libs/kstd/include/kstd/vector | 73 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 2 deletions(-) (limited to 'libs/kstd/include') diff --git a/libs/kstd/include/kstd/vector b/libs/kstd/include/kstd/vector index 2ecb6a8..c714957 100644 --- a/libs/kstd/include/kstd/vector +++ b/libs/kstd/include/kstd/vector @@ -147,8 +147,8 @@ namespace kstd //! //! template - requires(std::ranges::input_range && std::ranges::sized_range && - std::convertible_to, ValueType>) + requires((std::ranges::forward_range || std::ranges::sized_range) && + kstd::bits::container_compatible_range) constexpr vector(kstd::from_range_t, Range && range, allocator_type const & allocator = allocator_type{}) : m_allocator{allocator} , m_size{std::ranges::size(range)} @@ -729,6 +729,75 @@ namespace kstd return begin() + prefix_size; } + //! Insert the element of a given range into the vector at a given position. + //! + //! @param range The source range to insert elements from. + //! @tparam SourceRange A container compatible range type. + template + requires requires(allocator_type allocator, pointer destination, SourceRange range) { + requires kstd::bits::container_compatible_range; + requires std::move_constructible; + requires std::is_move_assignable_v; + requires std::swappable; + std::allocator_traits::construct(allocator, destination, *std::ranges::begin(range)); + } + // NOLINTNEXTLINE(misc-no-recursion) + constexpr auto insert_range(const_iterator position, SourceRange && range) -> iterator + { + auto prefix_size = std::ranges::distance(begin(), position); + + if (position == end()) + { + append_range(std::forward(range)); + return begin() + prefix_size; + } + + if constexpr (std::ranges::forward_range || std::ranges::sized_range) + { + auto number_of_elements = static_cast(std::ranges::distance(range)); + if (!number_of_elements) + { + return begin() + prefix_size; + } + + if (capacity() - size() < number_of_elements) + { + reserve(size() + std::max(size(), number_of_elements)); + } + + auto insert_position = begin() + prefix_size; + auto suffix_size = static_cast(std::ranges::distance(insert_position, end())); + + if (number_of_elements >= suffix_size) + { + uninitialized_move_with_allocator(insert_position, insert_position + number_of_elements, suffix_size); + auto result = std::ranges::copy_n(std::ranges::begin(range), suffix_size, insert_position); + uninitialized_copy_with_allocator(std::move(result.in), end(), number_of_elements - suffix_size); + } + else + { + uninitialized_move_with_allocator(end() - number_of_elements, end(), number_of_elements); + std::ranges::move_backward(insert_position, end() - number_of_elements, end()); + std::ranges::copy_n(std::ranges::begin(range), number_of_elements, insert_position); + } + + m_size += number_of_elements; + return insert_position; + } + + auto range_begin = std::ranges::begin(range); + auto range_end = std::ranges::end(range); + + 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())); + + return insert_range(begin() + prefix_size, remainder); + } + template constexpr auto emplace(const_iterator position, Args &&... args) -> iterator { -- cgit v1.2.3