diff options
| -rw-r--r-- | libs/kstd/kstd/bits/basic_string.hpp | 53 | ||||
| -rw-r--r-- | libs/kstd/kstd/bits/basic_string.test.cpp | 86 |
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); + } + } + } +} |
