#pragma once #include #include #include #include #include #include #include #include template struct View { size_t size; T* data; // owns its memory public: View() : size(0), data(nullptr) {} // Deep copy constructor View(const T* src, size_t count) : size(count) { if (count == 0) { data = nullptr; return; } data = static_cast(::operator new[](count * sizeof(T))); for (size_t i = 0; i < count; ++i) new (&data[i]) T(src[i]); // copy-construct } // Copy constructor View(const View& other) : View(other.data, other.size) {} // Move constructor View(View&& other) noexcept : size(other.size), data(other.data) { other.size = 0; other.data = nullptr; } View &operator=(const View &other) { if (this != &other) { // free old memory for (size_t i = 0; i < size; ++i) data[i].~T(); ::operator delete[](data); // deep copy size = other.size; data = static_cast(::operator new[](size * sizeof(T))); for (size_t i = 0; i < size; ++i) new (&data[i]) T(other.data[i]); } return *this; } // Destructor ~View() { for (size_t i = 0; i < size; ++i) data[i].~T(); ::operator delete[](data); } const T* begin() const { return data; } const T* end() const { return data + size; } }; // using StringView = View; class StringView final : public View { public: StringView() : View() {} // Construct from C-string — deep copy, including null terminator StringView(const char* s) : View(s, strlen(s) + 1) {} // Construct from View — ensure null termination StringView(const View& v) : View(v) { if (size == 0 || data[size - 1] != '\0') { // Reallocate and append null terminator size_t newSize = size + 1; char* newData = static_cast(::operator new[](newSize * sizeof(char))); for (size_t i = 0; i < size; ++i) newData[i] = data[i]; newData[newSize - 1] = '\0'; // destroy old // for (size_t i = 0; i < size; ++i) // data[i].~char(); ::operator delete[](data); data = newData; size = newSize; } } const char* c_str() const { return data; } }; namespace std { template<> struct hash { size_t operator()(const StringView& sv) const noexcept { // FNV-1a hash (simple, fast, good enough) constexpr size_t fnv_offset = 14695981039346656037ull; constexpr size_t fnv_prime = 1099511628211ull; size_t hash = fnv_offset; // Exclude the null terminator if present size_t len = (sv.size > 0 && sv.data[sv.size - 1] == '\0') ? sv.size - 1 : sv.size; for (size_t i = 0; i < len; ++i) { hash ^= static_cast(sv.data[i]); hash *= fnv_prime; } return hash; } }; } inline bool operator==(const StringView& a, const StringView& b) { // Sizes include null terminator; logical string length is size-1 if (a.size != b.size) return false; if (a.size == 0) return true; return std::memcmp(a.data, b.data, a.size) == 0; } inline bool operator!=(const StringView& a, const StringView& b) { return !(a == b); } template struct Builder { size_t size = 0; size_t capacity = 8; T* data; public: Builder() { data = static_cast(::operator new[](capacity * sizeof(T))); } ~Builder() { clear(); ::operator delete[](data); } protected: void grow(size_t newSize) { if (newSize <= capacity) return; size_t newCap = capacity; while (newCap < newSize) newCap += newCap / 2; T* newData = static_cast(::operator new[](newCap * sizeof(T))); // Move-construct into the new buffer for (size_t i = 0; i < size; ++i) new (&newData[i]) T(std::move(data[i])); // Destroy old items for (size_t i = 0; i < size; ++i) data[i].~T(); ::operator delete[](data); data = newData; capacity = newCap; } public: void Push(const T& value) { grow(size + 1); new (&data[size]) T(value); size++; } void Push(T&& value) { grow(size + 1); new (&data[size]) T(std::move(value)); size++; } // Clear Builder storage but keep capacity void clear() { for (size_t i = 0; i < size; ++i) data[i].~T(); size = 0; } // ALWAYS produce a deep-copied View View view() const { return View(data, size); } }; // using StringBuilder = Builder; class StringBuilder final : public Builder { public: StringBuilder() : Builder() {} // Ensure there is room for `n` more characters (not counting terminator) void ensure_extra(size_t n) { // grow size + n (but not including terminator) this->grow(this->size + n); } // Append raw C string (WITHOUT copying terminator) void Extend(const char* str) { if (!str) return; size_t len = strlen(str); ensure_extra(len); for (size_t i = 0; i < len; ++i) this->Push(str[i]); } // Append a single char void Append(char c) { this->Push(c); } void AppendIndent(int indent) { grow(size + indent); memset(data + size, ' ', indent); size += indent; } void VAppendFormat(const char* fmt, va_list args) { // Make a copy because vsnprintf consumes the va_list va_list argsCopy; va_copy(argsCopy, args); int len = std::vsnprintf(nullptr, 0, fmt, argsCopy); va_end(argsCopy); if (len <= 0) return; this->grow(this->size + len + 1); std::vsnprintf(this->data + this->size, len + 1, fmt, args); this->size += len; } void AppendFormat(const char* fmt, ...) { va_list args; va_start(args, fmt); // 1) compute length (excluding terminator) va_list argsCopy; va_copy(argsCopy, args); int len = std::vsnprintf(nullptr, 0, fmt, argsCopy); va_end(argsCopy); if (len <= 0) { va_end(args); return; } // 2) reserve space this->grow(this->size + len + 1); // 3) write formatted string std::vsnprintf(this->data + this->size, len + 1, fmt, args); this->size += len; va_end(args); } // Return a null-terminated string pointer owned by builder const char* c_str() { // ensure space for terminator this->grow(this->size + 1); // add terminator (overwrite or place it at end) if (this->size == 0 || this->data[this->size - 1] != '\0') { // If already ended with \0, fine this->Push('\0'); } return this->data; } // Produce a deep-copied StringView StringView view() { return StringView(this->c_str()); } // streaming operators StringBuilder& operator<<(const char* s) { Extend(s); return *this; } StringBuilder& operator<<(const StringView& sv) { Extend(sv.c_str()); return *this; } StringBuilder& operator<<(char c) { Append(c); return *this; } StringBuilder& operator<<(int v) { char buf[32]; snprintf(buf, sizeof(buf), "%d", v); Extend(buf); return *this; } StringBuilder& operator<<(long v) { char buf[32]; snprintf(buf, sizeof(buf), "%ld", v); Extend(buf); return *this; } StringBuilder& operator<<(unsigned int v) { char buf[32]; snprintf(buf, sizeof(buf), "%d", v); Extend(buf); return *this; } };