diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2026-03-24 13:03:15 +0100 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2026-03-24 13:03:15 +0100 |
| commit | f08512d1cddcf43de64f0b3f8b0e6c9fe31bcaea (patch) | |
| tree | 18f662a6b22ccfeaa4d6c00e702bacc54439c063 /libs | |
| parent | e6733ef652d408ca907a866ad8d6ba87b95fe0e7 (diff) | |
| download | teachos-f08512d1cddcf43de64f0b3f8b0e6c9fe31bcaea.tar.xz teachos-f08512d1cddcf43de64f0b3f8b0e6c9fe31bcaea.zip | |
kstd/vector: add basic insert overloads
Diffstat (limited to 'libs')
| -rw-r--r-- | libs/kstd/include/kstd/vector | 130 | ||||
| -rw-r--r-- | libs/kstd/tests/src/vector.cpp | 160 |
2 files changed, 262 insertions, 28 deletions
diff --git a/libs/kstd/include/kstd/vector b/libs/kstd/include/kstd/vector index 5655854..0d4aac8 100644 --- a/libs/kstd/include/kstd/vector +++ b/libs/kstd/include/kstd/vector @@ -259,7 +259,7 @@ namespace kstd if (capacity() >= other.size()) { auto const overlap = std::min(m_size, other.m_size); - copy_elements(other.begin(), begin(), overlap); + std::ranges::copy(other.begin(), other.begin() + overlap, begin()); if (m_size < other.m_size) { @@ -317,7 +317,7 @@ namespace kstd if (capacity() >= other.size()) { auto const overlap = std::min(size(), other.size()); - move_elements(other.begin(), begin(), overlap); + std::ranges::move(other.begin(), other.begin() + overlap, begin()); if (size() < other.size()) { @@ -590,6 +590,106 @@ namespace kstd m_size = 0; } + //! Insert an element at a given position. + //! + //! @param position The position to insert the element at. + //! @param value The value to insert. + //! @return An iterator to the inserted element. + constexpr auto insert(const_iterator position, value_type const & value) -> iterator + { + auto prefix_size = std::ranges::distance(begin(), position); + auto suffix_size = std::ranges::distance(position, end()); + + if (position == end()) + { + push_back(value); + return begin() + prefix_size; + } + + if (m_capacity == m_size) + { + auto new_capacity = m_capacity == 0 ? 1 : m_capacity * 2; + auto new_data = allocate_n(new_capacity); + auto old_size = size(); + std::allocator_traits<allocator_type>::construct(m_allocator, new_data + prefix_size, value); + uninitialized_move_with_allocator(begin(), new_data, prefix_size); + uninitialized_move_with_allocator(begin() + prefix_size, new_data + prefix_size + 1, suffix_size); + destroy_n(begin(), old_size); + deallocate(); + m_data = new_data; + m_capacity = new_capacity; + m_size = old_size; + } + else if (&value >= begin() && &value < end()) + { + auto value_copy = value; + auto insert_position = begin() + prefix_size; + std::allocator_traits<allocator_type>::construct(m_allocator, end(), std::move(*(end() - 1))); + std::ranges::move_backward(insert_position, end() - 1, end()); + *insert_position = std::move(value_copy); + } + else + { + auto insert_position = begin() + prefix_size; + std::allocator_traits<allocator_type>::construct(m_allocator, end(), std::move(*(end() - 1))); + std::ranges::move_backward(insert_position, end() - 1, end()); + *insert_position = value; + } + + ++m_size; + return begin() + prefix_size; + } + + //! Insert an element at a given position. + //! + //! @param position The position to insert the element at. + //! @param value The value to insert. + //! @return An iterator to the inserted element. + constexpr auto insert(const_iterator position, value_type && value) -> iterator + { + auto prefix_size = std::ranges::distance(begin(), position); + auto suffix_size = std::ranges::distance(position, end()); + + if (position == end()) + { + push_back(std::move(value)); + return begin() + prefix_size; + } + + if (m_capacity == m_size) + { + auto new_capacity = m_capacity == 0 ? 1 : m_capacity * 2; + auto new_data = allocate_n(new_capacity); + auto old_size = size(); + std::allocator_traits<allocator_type>::construct(m_allocator, new_data + prefix_size, std::move(value)); + uninitialized_move_with_allocator(begin(), new_data, prefix_size); + uninitialized_move_with_allocator(begin() + prefix_size, new_data + prefix_size + 1, suffix_size); + destroy_n(begin(), old_size); + deallocate(); + m_data = new_data; + m_capacity = new_capacity; + m_size = old_size; + } + else if (&value >= begin() && &value < end()) + { + auto value_copy = std::move(value); + auto insert_position = begin() + prefix_size; + std::allocator_traits<allocator_type>::construct(m_allocator, end(), std::move(*(end() - 1))); + std::ranges::move_backward(insert_position, end() - 1, end()); + *insert_position = std::move(value_copy); + } + else + { + auto insert_position = begin() + prefix_size; + std::allocator_traits<allocator_type>::construct(m_allocator, end(), std::move(*(end() - 1))); + std::ranges::move_backward(insert_position, end() - 1, end()); + *insert_position = std::move(value); + } + + ++m_size; + return begin() + prefix_size; + } + //! Append a given element to this vector via copy construction. constexpr auto push_back(value_type const & value) -> void { @@ -690,19 +790,6 @@ namespace kstd deallocate(); } - //! Copy a number of elements from one storage location to another. - //! - //! @param from The start of the source range. - //! @param to The start of the target range. - //! @param count The number of element to copy. - constexpr auto static copy_elements(const_iterator from, iterator to, size_type count) -> void - { - for (auto i = 0uz; i < count; ++i) - { - *to++ = *from++; - } - } - //! Release the memory of this vector. constexpr auto deallocate() { @@ -726,19 +813,6 @@ namespace kstd }); } - //! Move a number of elements from one storage location to another. - //! - //! @param from The start of the source range. - //! @param to The start of the target range. - //! @param count The number of element to copy. - constexpr auto static move_elements(iterator from, iterator to, size_t count) - { - for (auto i = 0uz; i < count; ++i) - { - *to++ = std::move(*from++); - } - } - //! Panic the kernel if the given index is out of bounds. //! //! @param index The index to check. diff --git a/libs/kstd/tests/src/vector.cpp b/libs/kstd/tests/src/vector.cpp index d4c5e4f..0735c9a 100644 --- a/libs/kstd/tests/src/vector.cpp +++ b/libs/kstd/tests/src/vector.cpp @@ -462,6 +462,19 @@ SCENARIO("Vector modifiers", "[vector]") REQUIRE(v[1] == 20); } } + + WHEN("inserting an element") + { + auto it = v.insert(v.cbegin(), 42); + + THEN("the size and capacity increase and the element is inserted") + { + REQUIRE(v.size() == 1); + REQUIRE(v.capacity() >= 1); + REQUIRE(v[0] == 42); + REQUIRE(it == v.begin()); + } + } } GIVEN("A populated vector") @@ -538,6 +551,104 @@ SCENARIO("Vector modifiers", "[vector]") REQUIRE(v.capacity() == initial_capacity); } } + + WHEN("inserting at the beginning") + { + auto it = v.insert(v.cbegin(), 5); + + THEN("the element is inserted at the front") + { + REQUIRE(v.size() == 4); + REQUIRE(v[0] == 5); + REQUIRE(v[1] == 10); + REQUIRE(v[2] == 20); + REQUIRE(v[3] == 30); + REQUIRE(it == v.begin()); + } + } + + WHEN("inserting in the middle") + { + auto it = v.insert(v.cbegin() + 1, 15); + + THEN("the element is inserted in the middle") + { + REQUIRE(v.size() == 4); + REQUIRE(v[0] == 10); + REQUIRE(v[1] == 15); + REQUIRE(v[2] == 20); + REQUIRE(v[3] == 30); + REQUIRE(it == v.begin() + 1); + } + } + + WHEN("inserting at the end") + { + auto it = v.insert(v.cend(), 40); + + THEN("the element is inserted at the back") + { + REQUIRE(v.size() == 4); + REQUIRE(v[0] == 10); + REQUIRE(v[1] == 20); + REQUIRE(v[2] == 30); + REQUIRE(v[3] == 40); + REQUIRE(it == v.begin() + 3); + } + } + + WHEN("inserting when capacity is sufficient") + { + v.reserve(10); + auto const capacity = v.capacity(); + + auto it = v.insert(v.cbegin() + 1, 15); + + THEN("the element is added without reallocation") + { + REQUIRE(v.size() == 4); + REQUIRE(v.capacity() == capacity); + REQUIRE(v[0] == 10); + REQUIRE(v[1] == 15); + REQUIRE(v[2] == 20); + REQUIRE(v[3] == 30); + REQUIRE(it == v.begin() + 1); + } + } + + WHEN("inserting a reference to an existing element with reallocation") + { + v.shrink_to_fit(); + REQUIRE(v.capacity() == v.size()); + auto it = v.insert(v.cbegin() + 1, v[2]); + + THEN("the element is correctly copied and inserted") + { + REQUIRE(v.size() == 4); + REQUIRE(v[0] == 10); + REQUIRE(v[1] == 30); + REQUIRE(v[2] == 20); + REQUIRE(v[3] == 30); + REQUIRE(it == v.begin() + 1); + } + } + + WHEN("inserting a reference to an existing element without reallocation") + { + v.reserve(10); + REQUIRE(v.capacity() > v.size()); + auto it = v.insert(v.cbegin() + 1, v[2]); + + THEN("the element is correctly copied and inserted") + { + REQUIRE(v.size() == 4); + REQUIRE(v[0] == 10); + REQUIRE(v[1] == 30); + REQUIRE(v[2] == 20); + REQUIRE(v[3] == 30); + REQUIRE(it == v.begin() + 1); + } + } } } @@ -709,6 +820,55 @@ SCENARIO("Vector modifier move semantics", "[vector]") } } } + + GIVEN("A populated vector of move trackers") + { + auto v = kstd::vector<kstd::tests::move_tracker>{}; + v.reserve(10); + v.emplace_back(10); + v.emplace_back(20); + v.emplace_back(30); + + WHEN("inserting an element in the middle with sufficient capacity") + { + auto const tracker = kstd::tests::move_tracker{15}; + v.insert(v.cbegin() + 1, tracker); + + THEN("the shifted elements are move-assigned and the new element is copy-assigned") + { + REQUIRE(v.size() == 4); + REQUIRE(v[0].value == 10); + REQUIRE_FALSE(v[0].was_moved); + REQUIRE(v[1].value == 15); + REQUIRE(v[1].was_copied); + REQUIRE_FALSE(v[1].was_moved); + REQUIRE(v[2].value == 20); + REQUIRE(v[2].was_moved); + REQUIRE(v[3].value == 30); + REQUIRE(v[3].was_moved); + } + } + + WHEN("inserting an rvalue element in the middle with sufficient capacity") + { + auto tracker = kstd::tests::move_tracker{15}; + v.insert(v.cbegin() + 1, std::move(tracker)); + + THEN("the shifted elements are move-assigned and the new element is move-assigned") + { + REQUIRE(v.size() == 4); + REQUIRE(v[0].value == 10); + REQUIRE_FALSE(v[0].was_moved); + REQUIRE(v[1].value == 15); + REQUIRE_FALSE(v[1].was_copied); + REQUIRE(v[1].was_moved); + REQUIRE(v[2].value == 20); + REQUIRE(v[2].was_moved); + REQUIRE(v[3].value == 30); + REQUIRE(v[3].was_moved); + } + } + } } SCENARIO("Vector advanced construction", "[vector]") |
