aboutsummaryrefslogtreecommitdiff
path: root/libs/kstd/include
diff options
context:
space:
mode:
Diffstat (limited to 'libs/kstd/include')
-rw-r--r--libs/kstd/include/kstd/vector73
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
{