From e2f19d51731053ab4f509f98c479bf860536aaaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steven=20Dee=20=28J=C5=8Dshin=29?= Date: Tue, 18 Jun 2024 22:17:26 -0700 Subject: [PATCH] Copy constructor makes small strings when it can We create a small string whenever it will fit, instead of only when r is small. This is safe because we always memcpy the whole blob when we call reserve, and optimizes the case when r has been truncated. This also reworks the test to follow the idiom adopted elsewhere re stl, and adds a helper function to tell if a string is small based on data(). --- ctl/string.cc | 4 ++++ ctl/string.h | 8 +++++--- test/ctl/string_test.cc | 34 +++++++++++++++++++++++++++++----- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/ctl/string.cc b/ctl/string.cc index 9732bd3a2..4e292a188 100644 --- a/ctl/string.cc +++ b/ctl/string.cc @@ -42,6 +42,10 @@ void string::init_big(const string& s) noexcept { char* p2; +#ifndef NDEBUG + if (!s.isbig()) + __builtin_trap(); +#endif if (s.size() >= s.capacity() >> 1) { if (!(p2 = (char*)malloc(s.capacity()))) __builtin_trap(); diff --git a/ctl/string.h b/ctl/string.h index 61d5a07c2..dca15b753 100644 --- a/ctl/string.h +++ b/ctl/string.h @@ -84,10 +84,12 @@ class string string(const string& r) noexcept { - if (r.isbig()) + if (r.size() <= __::sso_max) { + __builtin_memcpy(blob, r.data(), __::string_size); + set_small_size(r.size()); + } else { init_big(r); - else - __builtin_memcpy(blob, r.blob, __::string_size); + } } string(const char* const p, const size_t n) noexcept diff --git a/test/ctl/string_test.cc b/test/ctl/string_test.cc index 22cc0d6e9..67fcf625e 100644 --- a/test/ctl/string_test.cc +++ b/test/ctl/string_test.cc @@ -23,9 +23,19 @@ #include "libc/runtime/runtime.h" #include "libc/str/str.h" -using String = ctl::string; // #include -// using String = std::string; +// #define ctl std + +using String = ctl::string; + +#undef ctl + +inline bool +issmall(const String& s) +{ + return s.capacity() == sizeof(s) && + s.data() == reinterpret_cast(&s); +} int main() @@ -358,15 +368,14 @@ main() String s; if constexpr (std::is_same_v) { // tests the small-string optimization on ctl::string - char* d = s.data(); for (int i = 0; i < 23; ++i) { s.append("a"); - if (s.data() != d) { + if (!issmall(s)) { return 79 + i; } } s.append("a"); - if (s.data() == d) { + if (issmall(s)) { return 103; } } else { @@ -380,6 +389,21 @@ main() } } + { + String s("arst", 4); + for (int i = 0; i < 30; ++i) { + s.append("a"); + } + s.resize(4); + if (s != "arst") + return 105; + if constexpr (std::is_same_v) { + String r(s); + if (issmall(s) || !issmall(r)) + return 106; + } + } + CheckForMemoryLeaks(); return 0; }