aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/kstd/include/kstd/flat_map27
-rw-r--r--libs/kstd/include/kstd/vector39
-rw-r--r--libs/kstd/tests/src/vector.cpp45
3 files changed, 111 insertions, 0 deletions
diff --git a/libs/kstd/include/kstd/flat_map b/libs/kstd/include/kstd/flat_map
index 3b13754..f12b1b5 100644
--- a/libs/kstd/include/kstd/flat_map
+++ b/libs/kstd/include/kstd/flat_map
@@ -256,6 +256,33 @@ namespace kstd
};
}
+ //! Try to insert a element for the given key into this map.
+ //!
+ //! This function does nothing if the key is already present.
+ //!
+ //! @param key The key to insert a value for.
+ //! @param args The arguments to use to construct the mapped value.
+ template<typename... Args>
+ auto try_emplace(key_type const & key, Args &&... args) -> std::pair<iterator, bool>
+ {
+ auto found = std::ranges::lower_bound(m_containers.keys, key, m_comparator);
+ if (found != m_containers.keys.cend() && !m_comparator(*found, key) && !m_comparator(key, *found))
+ {
+ return {found, false};
+ }
+
+ auto offset = std::distance(m_containers.keys.cbegin(), found);
+ auto intersertion_point = m_containers.value.begin() + offset;
+
+ auto inserted_key = m_containers.keys.emplace(key);
+ auto inserted_mapped = m_containers.values.emplace(std::forward<Args>(args)...);
+
+ return {
+ iterator{inserted_key, inserted_mapped},
+ true
+ };
+ }
+
//! Find an element with an equivalent key.
//!
//! @param key The key to look up.
diff --git a/libs/kstd/include/kstd/vector b/libs/kstd/include/kstd/vector
index 79593c6..e1b8b38 100644
--- a/libs/kstd/include/kstd/vector
+++ b/libs/kstd/include/kstd/vector
@@ -728,6 +728,45 @@ namespace kstd
return begin() + prefix_size;
}
+ template<typename... Args>
+ constexpr auto emplace(const_iterator position, Args &&... args) -> iterator
+ {
+ auto prefix_size = std::ranges::distance(begin(), position);
+ auto suffix_size = std::ranges::distance(position, end());
+
+ if (position == end())
+ {
+ emplace_back(std::forward<Args>(args)...);
+ 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::forward<Args>(args)...);
+ 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
+ {
+ 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_type{std::forward<Args>(args)...};
+ }
+
+ ++m_size;
+ return begin() + prefix_size;
+ }
+
//! Erase an element at a given position.
//!
//! @note This function will panic if position == end()
diff --git a/libs/kstd/tests/src/vector.cpp b/libs/kstd/tests/src/vector.cpp
index 81bf32f..5faaaff 100644
--- a/libs/kstd/tests/src/vector.cpp
+++ b/libs/kstd/tests/src/vector.cpp
@@ -463,6 +463,33 @@ SCENARIO("Vector modifiers", "[vector]")
}
}
+ WHEN("emplace is called with the end iterator and constructor arguments")
+ {
+ v.emplace(v.end(), 20);
+
+ THEN("the element is appended and the size and capacity increase")
+ {
+ REQUIRE(v.size() == 1);
+ REQUIRE(v.capacity() >= 1);
+ REQUIRE(v.back() == 20);
+ }
+ }
+
+ WHEN("emplace is called while capacity is sufficient")
+ {
+ v.reserve(10);
+ auto const capacity = v.capacity();
+
+ v.emplace(v.end(), 20);
+
+ THEN("the element is appended without reallocation")
+ {
+ REQUIRE(v.size() == 1);
+ REQUIRE(v.capacity() == capacity);
+ REQUIRE(v.back() == 20);
+ }
+ }
+
WHEN("inserting an element")
{
auto it = v.insert(v.cbegin(), 42);
@@ -526,6 +553,24 @@ SCENARIO("Vector modifiers", "[vector]")
}
}
+ WHEN("emplace is called with an iterator and constructor arguments")
+ {
+ auto it = v.emplace(v.begin() + 2, 25);
+
+ THEN("the element is inserted and the size and capacity increase")
+ {
+ REQUIRE(v.size() == 4);
+ REQUIRE(v.capacity() >= initial_capacity);
+ REQUIRE(v.at(2) == 25);
+ }
+
+ THEN("the returned iterator points to the inserted element")
+ {
+ REQUIRE(it == v.cbegin() + 2);
+ REQUIRE(*it == 25);
+ }
+ }
+
WHEN("push_back is called with a reference to an internal element")
{
v.shrink_to_fit();