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().
This commit is contained in:
Steven Dee (Jōshin) 2024-06-18 22:17:26 -07:00
parent d1b6715018
commit e2f19d5173
No known key found for this signature in database
3 changed files with 38 additions and 8 deletions

View file

@ -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();

View file

@ -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

View file

@ -23,9 +23,19 @@
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
using String = ctl::string;
// #include <string>
// 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<const char*>(&s);
}
int
main()
@ -358,15 +368,14 @@ main()
String s;
if constexpr (std::is_same_v<ctl::string, decltype(s)>) {
// 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<ctl::string, decltype(s)>) {
String r(s);
if (issmall(s) || !issmall(r))
return 106;
}
}
CheckForMemoryLeaks();
return 0;
}