diff options
| author | Maxime Coste <mawww@kakoune.org> | 2024-06-12 19:55:34 +1000 |
|---|---|---|
| committer | Maxime Coste <mawww@kakoune.org> | 2024-06-12 19:55:34 +1000 |
| commit | fe8f0f3371f535602dbcd641e78dbe18f449bc87 (patch) | |
| tree | 5ec3c36ec8983b2a034c288fa56ed2c018ad8e66 /src/string.cc | |
| parent | 5a6fb51bdb43f15eafdbe1078183f754b4fecdf6 (diff) | |
| parent | faf83b10e25fe237c9e780d09386420c98110a5e (diff) | |
Merge remote-tracking branch 'Icantjuddle/master'
Diffstat (limited to 'src/string.cc')
| -rw-r--r-- | src/string.cc | 70 |
1 files changed, 54 insertions, 16 deletions
diff --git a/src/string.cc b/src/string.cc index fe763165..a672433b 100644 --- a/src/string.cc +++ b/src/string.cc @@ -1,22 +1,27 @@ #include "string.hh" -#include <cstdio> #include <cstring> +#include "assert.hh" +#include "unit_tests.hh" namespace Kakoune { +namespace +{ +// Avoid including all of <algorithm> just for this. +constexpr auto max(auto lhs, auto rhs) { return lhs > rhs ? lhs : rhs;} +constexpr auto min(auto lhs, auto rhs) { return lhs < rhs ? lhs : rhs;} +} String::Data::Data(const char* data, size_t size, size_t capacity) { if (capacity > Short::capacity) { - if (capacity & 1) - ++capacity; - - kak_assert(capacity < Long::max_capacity); + kak_assert(capacity <= Long::max_capacity); u.l.ptr = Alloc{}.allocate(capacity+1); u.l.size = size; - u.l.capacity = capacity; + u.l.capacity = (capacity & Long::max_capacity); + u.l.mode = Long::active_mask; if (data != nullptr) memcpy(u.l.ptr, data, size); @@ -60,26 +65,28 @@ String::Data& String::Data::operator=(Data&& other) noexcept template<bool copy> void String::Data::reserve(size_t new_capacity) { - if (capacity() != 0 and new_capacity <= capacity()) + auto const current_capacity = capacity(); + if (current_capacity != 0 and new_capacity <= current_capacity) return; - if (is_long()) - new_capacity = std::max(u.l.capacity * 2, new_capacity); + if (!is_long() and new_capacity <= Short::capacity) + return; - if (new_capacity & 1) - ++new_capacity; + kak_assert(new_capacity <= Long::max_capacity); + new_capacity = max(new_capacity, // Do not upgrade new_capacity to be over limit. + min(current_capacity * 2, Long::max_capacity)); - kak_assert(new_capacity < Long::max_capacity); char* new_ptr = Alloc{}.allocate(new_capacity+1); if (copy) { memcpy(new_ptr, data(), size()+1); - u.l.size = size(); } release(); + u.l.size = size(); u.l.ptr = new_ptr; - u.l.capacity = new_capacity; + u.l.capacity = (new_capacity & Long::max_capacity); + u.l.mode = Long::active_mask; } template void String::Data::reserve<true>(size_t); @@ -89,6 +96,7 @@ void String::Data::force_size(size_t new_size) { reserve<false>(new_size); set_size(new_size); + data()[new_size] = 0; } void String::Data::append(const char* str, size_t len) @@ -131,17 +139,47 @@ void String::Data::set_size(size_t size) if (is_long()) u.l.size = size; else - u.s.size = (size << 1) | 1; + u.s.remaining_size = Short::capacity - size; } void String::Data::set_short(const char* data, size_t size) { - u.s.size = (size << 1) | 1; + kak_assert(size <= Short::capacity); + u.s.remaining_size = Short::capacity - size; if (data != nullptr) memcpy(u.s.string, data, size); u.s.string[size] = 0; } +UnitTest test_data{[]{ + using Data = String::Data; + { // Basic data usage. + Data data; + kak_assert(data.size() == 0); + kak_assert(not data.is_long()); + kak_assert(data.capacity() == 23); + + // Should be SSO-ed. + data.append("test", 4); + kak_assert(data.size() == 4); + kak_assert(data.capacity() == 23); + kak_assert(not data.is_long()); + kak_assert(data.data() == StringView("test")); + } + { + char large_buf[2048]; + memset(large_buf, 'x', 2048); + Data data(large_buf, 2048); + kak_assert(data.size() == 2048); + kak_assert(data.capacity() >= 2048); + + data.clear(); + kak_assert(data.size() == 0); + kak_assert(not data.is_long()); + kak_assert(data.capacity() == 23); + } +}}; + const String String::ms_empty; } |
