mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
ctl::string cleanup (#1215)
We now fully initialize a ctl::string’s memory, so that it is always set to a well-defined value, thus making it always safe to memcpy out of it. This incidentally makes our string::swap function legal, which it wasn’t before. This also saves us a store in string::reserve. Now that we have made both big_string and small_string POD, I believe it is safe to elide the launder calls, and have done so, thus cleaning up a lot of the blob-related code. I also got rid of set_big_capacity and replaced it with a set_big_string that leaves us in a well-defined state afterwards. This function also is able to be somewhat simpler; rather than delicate bit-twiddling, it just reaches straight into blob and rewrites it wholesale. Overall, this shaves about 1–2ns off of most benchmarks, and adds 1ns to only one of them - creating a string from a char *.
This commit is contained in:
parent
d9b4f647d8
commit
8e37ee2598
2 changed files with 19 additions and 28 deletions
|
@ -91,16 +91,13 @@ string::reserve(size_t c2) noexcept
|
|||
if (!isbig()) {
|
||||
if (!(p2 = (char*)malloc(c2)))
|
||||
__builtin_trap();
|
||||
memcpy(p2, data(), size());
|
||||
p2[size()] = 0;
|
||||
memcpy(p2, data(), __::string_size);
|
||||
} else {
|
||||
if (!(p2 = (char*)realloc(big()->p, c2)))
|
||||
__builtin_trap();
|
||||
}
|
||||
std::atomic_signal_fence(std::memory_order_seq_cst);
|
||||
set_big_capacity(c2);
|
||||
big()->n = n;
|
||||
big()->p = p2;
|
||||
set_big_string(p2, n, c2);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
40
ctl/string.h
40
ctl/string.h
|
@ -81,28 +81,23 @@ class string
|
|||
|
||||
string() noexcept
|
||||
{
|
||||
set_small_size(0);
|
||||
#if 0
|
||||
small()->buf[0] = 0;
|
||||
#endif
|
||||
__builtin_memset(blob, 0, sizeof(size_t) * 2);
|
||||
// equivalent to set_small_size(0) but also zeroes memory
|
||||
*(((size_t *)blob) + 2) = __::sso_max << (sizeof(size_t) - 1) * 8;
|
||||
}
|
||||
|
||||
void swap(string& s) noexcept
|
||||
{
|
||||
char tmp[__::string_size];
|
||||
__builtin_memcpy(tmp, __builtin_launder(blob), sizeof(tmp));
|
||||
__builtin_memcpy(
|
||||
__builtin_launder(blob), __builtin_launder(s.blob), sizeof(tmp));
|
||||
__builtin_memcpy(__builtin_launder(s.blob), tmp, sizeof(tmp));
|
||||
__builtin_memcpy(tmp, blob, __::string_size);
|
||||
__builtin_memcpy(blob, s.blob, __::string_size);
|
||||
__builtin_memcpy(s.blob, tmp, __::string_size);
|
||||
}
|
||||
|
||||
string(string&& s) noexcept
|
||||
{
|
||||
__builtin_memcpy(blob, __builtin_launder(s.blob), sizeof(blob));
|
||||
__builtin_memcpy(blob, s.blob, __::string_size);
|
||||
s.set_small_size(0);
|
||||
#if 0
|
||||
s.small()->buf[0] = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void clear() noexcept
|
||||
|
@ -288,52 +283,51 @@ class string
|
|||
private:
|
||||
inline bool isbig() const noexcept
|
||||
{
|
||||
return *(__builtin_launder(blob) + __::sso_max) & 0x80;
|
||||
return *(blob + __::sso_max) & 0x80;
|
||||
}
|
||||
|
||||
inline void set_small_size(size_t size) noexcept
|
||||
{
|
||||
if (size > __::sso_max)
|
||||
__builtin_trap();
|
||||
*(__builtin_launder(blob) + __::sso_max) = (__::sso_max - size);
|
||||
*(blob + __::sso_max) = (__::sso_max - size);
|
||||
}
|
||||
|
||||
inline void set_big_capacity(size_t c2) noexcept
|
||||
inline void set_big_string(char *p, size_t n, size_t c2) noexcept
|
||||
{
|
||||
if (c2 > __::big_mask)
|
||||
__builtin_trap();
|
||||
*(__builtin_launder(blob) + __::sso_max) = 0x80;
|
||||
big()->c &= ~__::big_mask;
|
||||
big()->c |= c2;
|
||||
*(char **)blob = p;
|
||||
*(((size_t *)blob) + 1) = n;
|
||||
*(((size_t *)blob) + 2) = c2 | ~__::big_mask;
|
||||
}
|
||||
|
||||
inline __::small_string* small() noexcept
|
||||
{
|
||||
if (isbig())
|
||||
__builtin_trap();
|
||||
return __builtin_launder(reinterpret_cast<__::small_string*>(blob));
|
||||
return reinterpret_cast<__::small_string*>(blob);
|
||||
}
|
||||
|
||||
inline const __::small_string* small() const noexcept
|
||||
{
|
||||
if (isbig())
|
||||
__builtin_trap();
|
||||
return __builtin_launder(
|
||||
reinterpret_cast<const __::small_string*>(blob));
|
||||
return reinterpret_cast<const __::small_string*>(blob);
|
||||
}
|
||||
|
||||
inline __::big_string* big() noexcept
|
||||
{
|
||||
if (!isbig())
|
||||
__builtin_trap();
|
||||
return __builtin_launder(reinterpret_cast<__::big_string*>(blob));
|
||||
return reinterpret_cast<__::big_string*>(blob);
|
||||
}
|
||||
|
||||
inline const __::big_string* big() const noexcept
|
||||
{
|
||||
if (!isbig())
|
||||
__builtin_trap();
|
||||
return __builtin_launder(reinterpret_cast<const __::big_string*>(blob));
|
||||
return reinterpret_cast<const __::big_string*>(blob);
|
||||
}
|
||||
|
||||
friend string strcat(const string_view, const string_view);
|
||||
|
|
Loading…
Reference in a new issue