Logger System 0.1.3
High-performance C++20 thread-safe logging system with asynchronous capabilities
Loading...
Searching...
No Matches
small_string.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
11#pragma once
12
13#include <cstring>
14#include <string>
15#include <string_view>
16#include <algorithm>
17#include <memory>
18#include <utility>
19
20namespace kcenon::logger {
21
31template<size_t SSO_SIZE = 256>
33public:
34 static constexpr size_t SSO_CAPACITY = SSO_SIZE - 1; // Reserve 1 byte for null terminator
35
39 small_string() noexcept : size_(0), is_small_(true) {
40 data_.small[0] = '\0';
41 }
42
46 small_string(const char* str) : small_string() {
47 if (str) {
48 assign(str, std::strlen(str));
49 }
50 }
51
55 small_string(const std::string& str) : small_string() {
56 assign(str.data(), str.size());
57 }
58
62 small_string(std::string_view str) : small_string() {
63 assign(str.data(), str.size());
64 }
65
70 if (other.is_small_) {
71 std::memcpy(data_.small, other.data_.small, other.size_ + 1);
72 size_ = other.size_;
73 is_small_ = true;
74 } else {
75 assign(other.data(), other.size());
76 }
77 }
78
82 small_string(small_string&& other) noexcept
83 : size_(other.size_), is_small_(other.is_small_) {
84 if (is_small_) {
85 std::memcpy(data_.small, other.data_.small, size_ + 1);
86 } else {
87 data_.heap.ptr = other.data_.heap.ptr;
88 data_.heap.capacity = other.data_.heap.capacity;
89 other.data_.heap.ptr = nullptr;
90 other.size_ = 0;
91 other.is_small_ = true;
92 }
93 }
94
99 if (!is_small_ && data_.heap.ptr) {
100 delete[] data_.heap.ptr;
101 }
102 }
103
108 if (this != &other) {
109 assign(other.data(), other.size());
110 }
111 return *this;
112 }
113
118 if (this != &other) {
119 // Clean up current heap allocation if any
120 if (!is_small_ && data_.heap.ptr) {
121 delete[] data_.heap.ptr;
122 }
123
124 size_ = other.size_;
125 is_small_ = other.is_small_;
126
127 if (is_small_) {
128 std::memcpy(data_.small, other.data_.small, size_ + 1);
129 } else {
130 data_.heap.ptr = other.data_.heap.ptr;
131 data_.heap.capacity = other.data_.heap.capacity;
132 other.data_.heap.ptr = nullptr;
133 other.size_ = 0;
134 other.is_small_ = true;
135 }
136 }
137 return *this;
138 }
139
143 void assign(const char* str, size_t len) {
144 if (len <= SSO_CAPACITY) {
145 // Use small string optimization
146 if (!is_small_ && data_.heap.ptr) {
147 delete[] data_.heap.ptr;
148 }
149 std::memcpy(data_.small, str, len);
150 data_.small[len] = '\0';
151 size_ = len;
152 is_small_ = true;
153 } else {
154 // Use heap allocation
155 if (is_small_ || data_.heap.capacity < len + 1) {
156 // Need to allocate new buffer
157 if (!is_small_ && data_.heap.ptr) {
158 delete[] data_.heap.ptr;
159 }
160
161 size_t new_capacity = calculate_capacity(len);
162 data_.heap.ptr = new char[new_capacity];
163 data_.heap.capacity = new_capacity;
164 is_small_ = false;
165 }
166
167 std::memcpy(data_.heap.ptr, str, len);
168 data_.heap.ptr[len] = '\0';
169 size_ = len;
170 }
171 }
172
176 const char* c_str() const noexcept {
177 return data();
178 }
179
183 const char* data() const noexcept {
184 return is_small_ ? data_.small : data_.heap.ptr;
185 }
186
190 size_t size() const noexcept {
191 return size_;
192 }
193
197 size_t length() const noexcept {
198 return size_;
199 }
200
204 bool empty() const noexcept {
205 return size_ == 0;
206 }
207
211 bool is_small() const noexcept {
212 return is_small_;
213 }
214
218 size_t capacity() const noexcept {
220 }
221
225 void clear() noexcept {
226 if (!is_small_ && data_.heap.ptr) {
227 data_.heap.ptr[0] = '\0';
228 } else {
229 data_.small[0] = '\0';
230 }
231 size_ = 0;
232 }
233
237 void reserve(size_t new_capacity) {
238 if (new_capacity <= capacity()) {
239 return;
240 }
241
242 if (new_capacity <= SSO_CAPACITY) {
243 // Already using SSO, no need to reserve
244 return;
245 }
246
247 // Need heap allocation
248 size_t actual_capacity = calculate_capacity(new_capacity);
249 char* new_ptr = new char[actual_capacity];
250
251 // Copy existing data
252 std::memcpy(new_ptr, data(), size_ + 1);
253
254 // Clean up old allocation
255 if (!is_small_ && data_.heap.ptr) {
256 delete[] data_.heap.ptr;
257 }
258
259 data_.heap.ptr = new_ptr;
260 data_.heap.capacity = actual_capacity;
261 is_small_ = false;
262 }
263
267 void append(const char* str, size_t len) {
268 size_t new_size = size_ + len;
269
270 if (new_size <= SSO_CAPACITY && is_small_) {
271 // Can still use SSO
272 std::memcpy(data_.small + size_, str, len);
273 data_.small[new_size] = '\0';
274 size_ = new_size;
275 } else {
276 // Need heap allocation
277 if (is_small_ || data_.heap.capacity < new_size + 1) {
278 // Need to reallocate
279 size_t new_capacity = calculate_capacity(new_size);
280 char* new_ptr = new char[new_capacity];
281
282 // Copy existing data
283 std::memcpy(new_ptr, data(), size_);
284 // Append new data
285 std::memcpy(new_ptr + size_, str, len);
286 new_ptr[new_size] = '\0';
287
288 // Clean up old allocation
289 if (!is_small_ && data_.heap.ptr) {
290 delete[] data_.heap.ptr;
291 }
292
293 data_.heap.ptr = new_ptr;
294 data_.heap.capacity = new_capacity;
295 is_small_ = false;
296 } else {
297 // Existing heap buffer is large enough
298 std::memcpy(data_.heap.ptr + size_, str, len);
299 data_.heap.ptr[new_size] = '\0';
300 }
301 size_ = new_size;
302 }
303 }
304
308 void append(const std::string& str) {
309 append(str.data(), str.size());
310 }
311
315 small_string& operator+=(const char* str) {
316 append(str, std::strlen(str));
317 return *this;
318 }
319
323 small_string& operator+=(const std::string& str) {
324 append(str);
325 return *this;
326 }
327
331 std::string to_string() const {
332 return std::string(data(), size_);
333 }
334
338 operator std::string_view() const noexcept {
339 return std::string_view(data(), size_);
340 }
341
345 bool operator==(const small_string& other) const noexcept {
346 return size_ == other.size_ &&
347 std::memcmp(data(), other.data(), size_) == 0;
348 }
349
353 bool operator!=(const small_string& other) const noexcept {
354 return !(*this == other);
355 }
356
360 bool operator==(const std::string& str) const noexcept {
361 return size_ == str.size() &&
362 std::memcmp(data(), str.data(), size_) == 0;
363 }
364
370 size_t capacity;
374 };
375
377 memory_stats stats;
378 stats.string_size = size_;
379 stats.capacity = capacity();
380 stats.is_small = is_small_;
382 stats.total_bytes = sizeof(*this) + stats.heap_bytes_used;
383 return stats;
384 }
385
386private:
390 static size_t calculate_capacity(size_t required) {
391 // Round up to next power of 2 for better allocation patterns
392 size_t capacity = required + 1; // +1 for null terminator
393 capacity = capacity * 3 / 2; // 1.5x growth factor
394
395 // Align to 16 bytes for better memory alignment
396 return (capacity + 15) & ~15;
397 }
398
399 // Data storage
401 // Small string storage (stack)
402 char small[SSO_SIZE];
403
404 // Heap storage
405 struct {
406 char* ptr;
407 size_t capacity;
409
412
413 size_t size_;
415};
416
417// Type aliases for common sizes
422
423} // namespace kcenon::logger
Small String Optimization (SSO) implementation.
small_string(const char *str)
Construct from C-string.
bool operator!=(const small_string &other) const noexcept
Inequality comparison.
small_string(small_string &&other) noexcept
Move constructor.
small_string & operator+=(const char *str)
Append operator.
void reserve(size_t new_capacity)
Reserve capacity.
small_string & operator=(const small_string &other)
Copy assignment.
const char * c_str() const noexcept
Get C-string pointer.
void assign(const char *str, size_t len)
Assign from string data.
bool operator==(const small_string &other) const noexcept
Equality comparison.
bool operator==(const std::string &str) const noexcept
Comparison with std::string.
small_string(const small_string &other)
Copy constructor.
union kcenon::logger::small_string::data_union data_
const char * data() const noexcept
Get data pointer.
bool empty() const noexcept
Check if empty.
static size_t calculate_capacity(size_t required)
Calculate capacity for heap allocation.
void clear() noexcept
Clear the string.
size_t size() const noexcept
Get size.
memory_stats get_memory_stats() const noexcept
bool is_small() const noexcept
Check if using small string optimization.
void append(const std::string &str)
Append a string.
size_t capacity() const noexcept
Get capacity.
small_string & operator+=(const std::string &str)
Append operator.
small_string(const std::string &str)
Construct from std::string.
size_t length() const noexcept
Get length (same as size)
small_string(std::string_view str)
Construct from string_view.
small_string & operator=(small_string &&other) noexcept
Move assignment.
std::string to_string() const
Convert to std::string.
void append(const char *str, size_t len)
Append a string.
small_string() noexcept
Default constructor.
static constexpr size_t SSO_CAPACITY
struct kcenon::logger::small_string::data_union::@0 heap