diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2026-05-01 17:22:53 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2026-05-01 17:22:53 +0200 |
| commit | 2773e457773e3c88c212d6403950cef1fc96f880 (patch) | |
| tree | 173f3e5c91ac5e85c8bb2f72bf53e710149a5153 /libs/kstd/include | |
| parent | 338d9b2b6fc517df2135089699234232495324d6 (diff) | |
| download | kernel-2773e457773e3c88c212d6403950cef1fc96f880.tar.xz kernel-2773e457773e3c88c212d6403950cef1fc96f880.zip | |
kstd/vector: implement insert_range
Diffstat (limited to 'libs/kstd/include')
| -rw-r--r-- | libs/kstd/include/kstd/vector | 73 |
1 files changed, 71 insertions, 2 deletions
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<typename Range> - requires(std::ranges::input_range<Range> && std::ranges::sized_range<Range> && - std::convertible_to<std::ranges::range_reference_t<Range>, ValueType>) + requires((std::ranges::forward_range<Range> || std::ranges::sized_range<Range>) && + kstd::bits::container_compatible_range<Range, value_type>) 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<typename SourceRange> + requires requires(allocator_type allocator, pointer destination, SourceRange range) { + requires kstd::bits::container_compatible_range<SourceRange, ValueType>; + requires std::move_constructible<value_type>; + requires std::is_move_assignable_v<value_type>; + requires std::swappable<value_type>; + std::allocator_traits<allocator_type>::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<SourceRange>(range)); + return begin() + prefix_size; + } + + if constexpr (std::ranges::forward_range<SourceRange> || std::ranges::sized_range<SourceRange>) + { + auto number_of_elements = static_cast<size_type>(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<size_type>(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<std::ranges::iterator_t<SourceRange>>(range_begin)); + } + reserve(size() + std::max(size(), remainder.size())); + + return insert_range(begin() + prefix_size, remainder); + } + template<typename... Args> constexpr auto emplace(const_iterator position, Args &&... args) -> iterator { |
