diff options
| author | Maxime Coste <mawww@kakoune.org> | 2021-07-20 19:53:06 +1000 |
|---|---|---|
| committer | Maxime Coste <mawww@kakoune.org> | 2021-07-20 22:30:41 +1000 |
| commit | a4dd89f214e72005f551cd071d7642652c2922c5 (patch) | |
| tree | bbbd8e27bce9ade970e1082ac389a830ca7f1ede /src/string.hh | |
| parent | c643cd446712a9f9db05081786b5bc0daf2a96d7 (diff) | |
Improve code-generation for Strings
Make String::Data use trivial copy of the short/long union to avoid
unnecessary branching there, inline release() as it can be elided by
the compiler on moved-from Strings.
Diffstat (limited to 'src/string.hh')
| -rw-r--r-- | src/string.hh | 65 |
1 files changed, 38 insertions, 27 deletions
diff --git a/src/string.hh b/src/string.hh index 1a3568e0..6fa425e5 100644 --- a/src/string.hh +++ b/src/string.hh @@ -156,45 +156,28 @@ public: // capacity must be pair, on little endian systems that means the allocated // capacity cannot use its most significant byte, so we effectively limit // capacity to 2^24 on 32bit arch, and 2^60 on 64. - union Data + struct Data { using Alloc = Allocator<char, MemoryDomain::String>; - struct Long - { - static constexpr size_t max_capacity = - (size_t)1 << 8 * (sizeof(size_t) - 1); - - char* ptr; - size_t size; - size_t capacity; - } l; - - struct Short - { - static constexpr size_t capacity = sizeof(Long) - 2; - char string[capacity+1]; - unsigned char size; - } s; - Data() { set_empty(); } - Data(NoCopy, const char* data, size_t size) : l{const_cast<char*>(data), size, 0} {} + Data(NoCopy, const char* data, size_t size) : u{Long{const_cast<char*>(data), size, 0}} {} Data(const char* data, size_t size, size_t capacity); Data(const char* data, size_t size) : Data(data, size, size) {} Data(const Data& other) : Data{other.data(), other.size()} {} ~Data() { release(); } - Data(Data&& other) noexcept; + Data(Data&& other) noexcept : u{other.u} { other.set_empty(); } Data& operator=(const Data& other); Data& operator=(Data&& other) noexcept; - bool is_long() const { return (s.size & 1) == 0; } - size_t size() const { return is_long() ? l.size : (s.size >> 1); } - size_t capacity() const { return is_long() ? l.capacity : Short::capacity; } + bool is_long() const { return (u.s.size & 1) == 0; } + size_t size() const { return is_long() ? u.l.size : (u.s.size >> 1); } + size_t capacity() const { return is_long() ? u.l.capacity : Short::capacity; } - const char* data() const { return is_long() ? l.ptr : s.string; } - char* data() { return is_long() ? l.ptr : s.string; } + const char* data() const { return is_long() ? u.l.ptr : u.s.string; } + char* data() { return is_long() ? u.l.ptr : u.s.string; } template<bool copy = true> void reserve(size_t new_capacity); @@ -204,8 +187,36 @@ public: void clear(); private: - void release(); - void set_empty() { s.size = 1; s.string[0] = 0; } + struct Long + { + static constexpr size_t max_capacity = + (size_t)1 << 8 * (sizeof(size_t) - 1); + + char* ptr; + size_t size; + size_t capacity; + }; + + struct Short + { + static constexpr size_t capacity = sizeof(Long) - 2; + char string[capacity+1]; + unsigned char size; + }; + + union + { + Long l; + Short s; + } u; + + void release() + { + if (is_long() and u.l.capacity != 0) + Alloc{}.deallocate(u.l.ptr, u.l.capacity+1); + } + + void set_empty() { u.s.size = 1; u.s.string[0] = 0; } void set_short(const char* data, size_t size); }; |
