aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/kstd/kstd/bits/basic_string.hpp53
-rw-r--r--libs/kstd/kstd/bits/basic_string.test.cpp86
2 files changed, 137 insertions, 2 deletions
diff --git a/libs/kstd/kstd/bits/basic_string.hpp b/libs/kstd/kstd/bits/basic_string.hpp
index e55bfbb..5d2eecd 100644
--- a/libs/kstd/kstd/bits/basic_string.hpp
+++ b/libs/kstd/kstd/bits/basic_string.hpp
@@ -635,6 +635,49 @@ namespace kstd
return std::numeric_limits<size_type>::max() / sizeof(value_type) - 1;
}
+ //! Reserve at least the given amount of memory.
+ //!
+ //! @param new_capacity The new, minimum, target capacity.
+ constexpr auto reserve(size_type new_capacity) -> void
+ {
+ if (new_capacity > max_size())
+ {
+ os::panic("Tried to allocate more memory than possible");
+ }
+
+ if (new_capacity <= capacity())
+ {
+ return;
+ }
+
+ auto new_buffer = allocate_buffer(new_capacity);
+ traits_type::copy(new_buffer.data(), data(), length() + 1);
+ update_data(new_buffer);
+ }
+
+ //! Shrink the buffer of this vector to fit the current content.
+ constexpr auto shrink_to_fit() -> void
+ {
+ if (in_sso_state())
+ {
+ return;
+ }
+ else if (length() <= sso_length)
+ {
+ auto old_capacity = m_heap_capacity;
+ traits_type::copy(m_sso_buffer, m_data, m_length + 1);
+ std::allocator_traits<allocator_type>::deallocate(m_allocator, m_data, old_capacity);
+ m_data = m_sso_buffer;
+ }
+ else
+ {
+ auto new_buffer = allocate_buffer(m_length + 1);
+ traits_type::copy(new_buffer.data(), m_data, m_length + 1);
+ release_buffer();
+ update_data(new_buffer);
+ }
+ }
+
//! Get the currently allocated capacity of this string
//!
//! @return the number of elements that can be stored in this string without causing a reallocation.
@@ -885,7 +928,7 @@ namespace kstd
}
else
{
- auto temporary_buffer = std::array<value_type, 15 / sizeof(value_type) + 1>{};
+ auto temporary_buffer = std::array<value_type, sso_capacity>{};
traits_type::copy(temporary_buffer.data(), m_data, m_length + 1);
traits_type::copy(m_data, other.m_data, other.m_length + 1);
@@ -1138,6 +1181,12 @@ namespace kstd
}
private:
+ //! The size of the SSO buffer.
+ constexpr auto static inline sso_capacity = 15 / sizeof(value_type) + 1;
+
+ //! The maximum string length that fits in the SSO buffer.
+ constexpr auto static inline sso_length = sso_capacity - 1;
+
//! Allocate a buffer for the data.
//!
//! @param count The of character to reserve space for, excluding the termininating null.
@@ -1338,7 +1387,7 @@ namespace kstd
//! The SSO buffer, or the capacity of this string if SSO is not active.
union
{
- value_type m_sso_buffer[15 / sizeof(value_type) + 1]; // NOLINT(modernize-avoid-c-arrays)
+ value_type m_sso_buffer[sso_capacity]; // NOLINT(modernize-avoid-c-arrays)
size_type m_heap_capacity;
};
};
diff --git a/libs/kstd/kstd/bits/basic_string.test.cpp b/libs/kstd/kstd/bits/basic_string.test.cpp
index dba0ea0..8f3a00d 100644
--- a/libs/kstd/kstd/bits/basic_string.test.cpp
+++ b/libs/kstd/kstd/bits/basic_string.test.cpp
@@ -1874,3 +1874,89 @@ SCENARIO("Basic string assignment", "[string]")
}
}
}
+
+SCENARIO("Basic string of char modifiers", "[string]")
+{
+ GIVEN("A short string")
+ {
+ auto s = char_string{"abcd"};
+ auto old_capacity = s.capacity();
+ auto old_size = s.size();
+ auto old_data = s.data();
+
+ WHEN("reserving a smaller capacity")
+ {
+ s.reserve(1);
+
+ THEN("the capacity does not change")
+ {
+ REQUIRE(s.capacity() == old_capacity);
+ }
+
+ THEN("the content stays the same")
+ {
+ REQUIRE(s == "abcd");
+ }
+
+ THEN("the size stays the same")
+ {
+ REQUIRE(s.size() == old_size);
+ }
+
+ THEN("the data pointer stays the same")
+ {
+ REQUIRE(s.data() == old_data);
+ }
+ }
+
+ WHEN("reserving equal capacity")
+ {
+ s.reserve(old_capacity);
+
+ THEN("the capacity does not change")
+ {
+ REQUIRE(s.capacity() == old_capacity);
+ }
+
+ THEN("the content stays the same")
+ {
+ REQUIRE(s == "abcd");
+ }
+
+ THEN("the size stays the same")
+ {
+ REQUIRE(s.size() == old_size);
+ }
+
+ THEN("the data pointer stays the same")
+ {
+ REQUIRE(static_cast<void const *>(s.data()) == static_cast<void const *>(old_data));
+ }
+ }
+
+ WHEN("reserving larger capacity")
+ {
+ s.reserve(old_capacity + 1);
+
+ THEN("the capacity increases")
+ {
+ REQUIRE(s.capacity() >= old_capacity + 1);
+ }
+
+ THEN("the content stays the same")
+ {
+ REQUIRE(s == "abcd");
+ }
+
+ THEN("the size stays the same")
+ {
+ REQUIRE(s.size() == old_size);
+ }
+
+ THEN("the data pointer changes")
+ {
+ REQUIRE(s.data() != old_data);
+ }
+ }
+ }
+}