summaryrefslogtreecommitdiff
path: root/src/string.cc
diff options
context:
space:
mode:
authorBen Judd <bjudd61@gmail.com>2024-06-07 17:33:32 -0700
committerBen Judd <bjudd@nuro.ai>2024-06-07 17:48:07 -0700
commit2754e27cf2a85fd4004dd7daabe052b7df1b425a (patch)
treeccd6d85a2e21620df984ba4c787e1534ae43ad6b /src/string.cc
parentc93cb5c4d8f1c2aec21f8bdeba59dfb8f153499c (diff)
Increase SSO from 22 to 23 chars.
Diffstat (limited to 'src/string.cc')
-rw-r--r--src/string.cc61
1 files changed, 46 insertions, 15 deletions
diff --git a/src/string.cc b/src/string.cc
index fe763165..a6befa13 100644
--- a/src/string.cc
+++ b/src/string.cc
@@ -2,6 +2,8 @@
#include <cstdio>
#include <cstring>
+#include "assert.hh"
+#include "unit_tests.hh"
namespace Kakoune
{
@@ -10,13 +12,10 @@ 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.set_capacity(capacity);
if (data != nullptr)
memcpy(u.l.ptr, data, size);
@@ -60,26 +59,27 @@ 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 = std::max(new_capacity, // Do not upgrade new_capacity to be over limit.
+ std::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.set_capacity(new_capacity);
}
template void String::Data::reserve<true>(size_t);
@@ -89,6 +89,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 +132,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;
}