Branch data Line data Source code
1 : : #pragma once
2 : :
3 : : #include <cstring>
4 : : #include <stdexcept>
5 : : #include <type_traits>
6 : :
7 : : namespace ez {
8 : :
9 : : /*
10 : : this class is a string who have a pre defined size and content saved in stack
11 : : faster if all operations are made idnide the pre defiend stack buffer
12 : : when the size grow out of the pre defined size its moving to heap
13 : : */
14 : :
15 : : template <typename TChar, size_t StackChunkSize = 256, size_t HeapChunkSize = StackChunkSize>
16 : : class StackString {
17 : : static_assert(std::is_trivial<TChar>::value, "TChar must be a trivial type");
18 : :
19 : : size_t _heapSize{}; // capacity allocated in _heapData
20 : : size_t _heapLength{}; // actual length used in _heapData
21 : : TChar* _heapData{}; // heap buffer (null if using stack)
22 : : size_t _stackLength{}; // actual length in _stackData
23 : : TChar _stackData[StackChunkSize + 1]{}; // stack buffer (+1 for null terminator)
24 : :
25 : : public:
26 : : static constexpr size_t npos = static_cast<size_t>(-1);
27 : :
28 : : public:
29 : : StackString() = default;
30 : 11 : explicit StackString(const TChar* str) { append(str); }
31 : :
32 : 1 : StackString(const StackString& other) { append(other.c_str()); }
33 : :
34 : 3 : StackString(StackString&& other) noexcept : _heapSize(other._heapSize), _heapLength(other._heapLength), _heapData(other._heapData), _stackLength(other._stackLength) {
35 : 3 : std::memcpy(_stackData, other._stackData, sizeof(_stackData));
36 : 3 : other._heapData = nullptr;
37 : 3 : other._heapSize = 0;
38 : 3 : other._heapLength = 0;
39 : 3 : other._stackLength = 0;
40 : 3 : other._stackData[0] = TChar(0);
41 : 3 : }
42 : :
43 : : StackString& operator=(const StackString& other) {
44 : : if (this != &other) {
45 : : clear();
46 : : append(other.c_str());
47 : : }
48 : : return *this;
49 : : }
50 : :
51 : : StackString& operator=(StackString&& other) {
52 : : if (this != &other) {
53 : : clear();
54 : : delete[] _heapData;
55 : : _heapSize = other._heapSize;
56 : : _heapLength = other._heapLength;
57 : : _heapData = other._heapData;
58 : : _stackLength = other._stackLength;
59 : : std::memcpy(_stackData, other._stackData, sizeof(_stackData));
60 : : other._heapData = nullptr;
61 : : other._heapSize = 0;
62 : : other._heapLength = 0;
63 : : other._stackLength = 0;
64 : : other._stackData[0] = TChar(0);
65 : : }
66 : : return *this;
67 : : }
68 : :
69 : 15 : ~StackString() { delete[] _heapData; }
70 : :
71 : 1 : void clear() {
72 : 1 : _stackLength = 0;
73 : 1 : _stackData[0] = TChar(0);
74 : 1 : delete[] _heapData;
75 : 1 : _heapData = nullptr;
76 : 1 : _heapSize = 0;
77 : 1 : _heapLength = 0;
78 : 1 : }
79 : :
80 : 5 : bool usingHeap() const { return _heapData != nullptr; }
81 [ - + ][ - + ]: 18 : const TChar* c_str() const { return _heapData ? _heapData : _stackData; }
[ + - ][ - + ]
[ + + ]
82 [ - + ][ + + ]: 37 : size_t size() const { return _heapData ? _heapLength : _stackLength; }
[ - + ][ - + ]
[ - + ]
83 : :
84 : 22 : void reserve(size_t newSize) {
85 : 22 : if (HeapChunkSize == 0) {
86 [ # # ][ # # ]: 3 : if (newSize > StackChunkSize) {
[ # # ][ # # ]
[ + + ]
87 : 1 : throw std::runtime_error("Heap allocation disabled");
88 : 1 : }
89 : 2 : return;
90 : 3 : }
91 [ + + ][ - + ]: 19 : if (_heapData) {
[ # # ][ - + ]
[ - + ]
92 [ # # ][ # # ]: 1 : if (newSize <= _heapSize) {
[ # # ][ - + ]
[ # # ]
93 : 0 : return;
94 : 0 : }
95 : 1 : size_t newCap = ((newSize / HeapChunkSize) + 1) * HeapChunkSize;
96 : 1 : TChar* newData = new TChar[newCap + 1];
97 : 1 : std::memcpy(newData, _heapData, _heapLength * sizeof(TChar));
98 : 1 : newData[_heapLength] = TChar(0);
99 : 1 : delete[] _heapData;
100 : 1 : _heapData = newData;
101 : 1 : _heapSize = newCap;
102 : 18 : } else {
103 [ + - ][ + - ]: 18 : if (newSize <= StackChunkSize) {
[ + + ][ # # ]
[ + + ]
104 : 15 : return;
105 : 15 : }
106 : 3 : size_t newCap = ((newSize / HeapChunkSize) + 1) * HeapChunkSize;
107 : 3 : _heapData = new TChar[newCap + 1];
108 : 3 : std::memcpy(_heapData, _stackData, _stackLength * sizeof(TChar));
109 : 3 : _heapLength = _stackLength;
110 : 3 : _heapData[_heapLength] = TChar(0);
111 : 3 : _heapSize = newCap;
112 : 3 : }
113 : 19 : }
114 : :
115 : 22 : void append(const TChar* str) {
116 : 22 : const size_t len = std::char_traits<TChar>::length(str);
117 : 22 : const size_t currentLen = size();
118 : 22 : const size_t totalLen = currentLen + len;
119 : 22 : reserve(totalLen);
120 [ - + ][ - + ]: 22 : if (_heapData) {
[ + + ][ - + ]
[ + + ]
121 : 4 : std::memcpy(_heapData + _heapLength, str, len * sizeof(TChar));
122 : 4 : _heapLength += len;
123 : 4 : _heapData[_heapLength] = TChar(0);
124 : 18 : } else {
125 : 18 : std::memcpy(_stackData + _stackLength, str, len * sizeof(TChar));
126 : 18 : _stackLength += len;
127 : 18 : _stackData[_stackLength] = TChar(0);
128 : 18 : }
129 : 22 : }
130 : :
131 : 2 : void append(TChar c) {
132 : 2 : TChar tmp[2] = {c, TChar(0)};
133 : 2 : append(tmp);
134 : 2 : }
135 : :
136 : 7 : StackString& operator+=(const TChar* str) {
137 : 7 : append(str);
138 : 7 : return *this;
139 : 7 : }
140 : :
141 : 1 : StackString& operator+=(TChar c) {
142 : 1 : append(c);
143 : 1 : return *this;
144 : 1 : }
145 : :
146 : 5 : TChar& operator[](size_t index) {
147 [ + + ]: 5 : if (index >= size()) {
148 : 2 : throw std::out_of_range("StackString index out of range");
149 : 2 : }
150 [ + + ]: 3 : return _heapData ? _heapData[index] : _stackData[index];
151 : 5 : }
152 : :
153 : 4 : const TChar& at(size_t index) const {
154 [ + + ]: 4 : if (index >= size()) {
155 : 2 : throw std::out_of_range("StackString index out of range");
156 : 2 : }
157 [ + + ]: 2 : return _heapData ? _heapData[index] : _stackData[index];
158 : 4 : }
159 : :
160 : 4 : size_t find(const TChar* needle, size_t pos = 0) const {
161 : 4 : const TChar* haystack = c_str();
162 : 4 : const size_t hayLen = size();
163 : 4 : const size_t needleLen = std::char_traits<TChar>::length(needle);
164 [ + + ][ - + ]: 4 : if (needleLen == 0 || pos > hayLen || needleLen > hayLen - pos) {
[ - + ]
165 : 1 : return npos;
166 : 1 : }
167 [ + + ]: 23 : for (size_t i = pos; i <= hayLen - needleLen; ++i) {
168 [ + + ]: 22 : if (std::char_traits<TChar>::compare(haystack + i, needle, needleLen) == 0) {
169 : 2 : return i;
170 : 2 : }
171 : 22 : }
172 : 1 : return npos;
173 : 3 : }
174 : :
175 : 2 : StackString substr(size_t pos, size_t count = npos) const {
176 : 2 : const size_t len = size();
177 [ + + ]: 2 : if (pos > len) {
178 : 1 : throw std::out_of_range("substr position out of range");
179 : 1 : }
180 [ - + ][ - + ]: 1 : size_t actualCount = (count == npos || pos + count > len) ? len - pos : count;
181 : 1 : const TChar* src = c_str() + pos;
182 : 1 : TChar* tmp = new TChar[actualCount + 1];
183 : 1 : std::memcpy(tmp, src, actualCount * sizeof(TChar));
184 : 1 : tmp[actualCount] = TChar(0);
185 : :
186 : 1 : StackString result(tmp);
187 : 1 : delete[] tmp;
188 : 1 : return result;
189 : 2 : }
190 : : };
191 : :
192 : : } // namespace ez
|