CDT  v4.2.0
инструменты разработчика
string.hpp
См. документацию.
1
6#pragma once
7
8#include <cstring> // memcpy, memset, strlen
9#include <algorithm> // std::swap
10#include <memory> // std::unique_ptr
11#include <variant> // std::variant
12#include <vector> // std::vector
13
14#include "datastream.hpp" // eosio::datastream
15#include "varint.hpp" // eosio::unsigned_int
16
17namespace eosio {
18
19 class string {
20 public:
21 static constexpr size_t npos = -1;
22
23 template <size_t N>
24 constexpr string(const char (&str)[N])
25 : _size{N-1}
26 , _capacity{_size}
27 , _begin{str}
28 {
29 }
30
31 constexpr string()
32 : _size{0}
33 , _capacity{0}
34 , _begin{""}
35 {
36 }
37
38 constexpr string(const char* str, const size_t n)
39 : _size{n}
40 , _capacity{_size*2}
41 {
42 char* begin{new char[_capacity]};
43 memcpy(begin, str, _size);
44 _begin = begin;
45 }
46
47 constexpr string(const size_t n, const char c)
48 : _size{n}
49 , _capacity{_size*2}
50 {
51 char* begin{new char[_capacity]};
52 memset(begin, c, _size);
53 _begin = begin;
54 }
55
56 constexpr string(const string& str, const size_t pos, const size_t n)
57 : _size{n}
58 , _capacity{_size*2}
59 {
60 if (n == string::npos || str._size < pos+n) {
61 _size = str._size;
62 _capacity = _size*2;
63 }
64
65 clone(_size, _capacity, str.data()+pos);
66 }
67
68 constexpr string(const string& str)
69 : _size{str._size}
70 , _capacity{str._capacity}
71 {
72 if (str.is_literal())
73 _begin = std::get<const char*>(str._begin);
74 else
75 clone(str._size, str._capacity, str.data());
76 }
77
78 constexpr string(string&& str)
79 : _size{str._size}
80 , _capacity{str._capacity}
81 {
82 if (str.is_literal())
83 _begin = std::get<const char*>(str._begin);
84 else
85 _begin = std::move(std::get<uptr>(str._begin));
86 }
87
88 string& operator=(const string& str) {
89 if (&str == this)
90 return *this;
91
92 _size = str._size;
93 _capacity = str._capacity;
94
95 if (str.is_literal())
96 _begin = std::get<const char*>(str._begin);
97 else
98 clone(_size, _capacity, str.data());
99
100 return *this;
101 }
102
103 string& operator=(string&& str) {
104 if (&str == this)
105 return *this;
106
107 _size = str._size;
108 _capacity = str._capacity;
109
110 if (str.is_literal())
111 _begin = std::get<const char*>(str._begin);
112 else
113 _begin = std::move(std::get<uptr>(str._begin));
114
115 return *this;
116 }
117
118 string& operator=(const char* str) {
119 _size = strlen(str);
120 _capacity = _size;
121 _begin = str;
122
123 return *this;
124 }
125
126 char& operator[](const size_t n) {
127 if (is_literal())
128 clone(_size, _capacity, std::get<const char*>(_begin));
129 return std::get<uptr>(_begin).get()[n];
130 }
131
132 const char operator[](const size_t n) const {
133 return (is_literal()) ? std::get<const char*>(_begin)[n] : std::get<uptr>(_begin).get()[n];
134 }
135
136 char& at(const size_t n) {
137 eosio::check(0 <= n && n < _size, "eosio::string::at");
138 return operator[](n);
139 }
140
141 const char at(const size_t n) const {
142 eosio::check(0 <= n && n < _size, "eosio::string::at const");
143 return operator[](n);
144 }
145
146 char& front() {
147 return at(0);
148 }
149
150 const char front() const {
151 return at(0);
152 }
153
154 char& back() {
155 return at(_size-1);
156 }
157
158 const char back() const {
159 return at(_size-1);
160 }
161
162 char* data() {
163 return begin();
164 }
165
166 const char* data() const {
167 return cbegin();
168 }
169
170 const char* c_str() const {
171 static size_t prev_size{0};
172 char* raw_ptr{nullptr};
173
174 if (is_literal())
175 return std::get<const char*>(_begin);
176
177 if (_size == prev_size)
178 return std::get<uptr>(_begin).get();
179 else if (_size < prev_size)
180 raw_ptr = std::get<uptr>(_begin).get();
181 else {
182 uptr tmp = std::make_unique<char[]>(_size+1);
183 raw_ptr = tmp.get();
184 prev_size = _size;
185 memcpy(raw_ptr, std::get<uptr>(_begin).get(), _size);
186 }
187
188 raw_ptr[_size+1] = '\0';
189 return raw_ptr;
190 }
191
192 char* begin() {
193 if (is_literal()) {
194 _capacity *= 2;
195 clone(_size, _capacity, std::get<const char*>(_begin));
196 }
197
198 return std::get<uptr>(_begin).get();
199 }
200
201 const char* cbegin() const {
202 return (is_literal()) ? std::get<const char*>(_begin) : std::get<uptr>(_begin).get();
203 }
204
205 char* end() {
206 return begin()+_size;
207 }
208
209 const char* cend() const {
210 return cbegin()+_size;
211 }
212
213 bool empty() const {
214 return !_size;
215 }
216
217 size_t size() const {
218 return _size;
219 }
220
221 size_t length() const {
222 return _size;
223 }
224
225 size_t capacity() const {
226 return _capacity;
227 }
228
229 size_t max_size() const {
230 return npos;
231 }
232
233 void reserve(const size_t n) {
234 if (_capacity < n) {
235 _capacity = n;
236
237 const char* tmp{(is_literal()) ? std::get<const char*>(_begin) : std::get<uptr>(_begin).get()};
238 clone(_size, _capacity, tmp);
239 }
240 else
241 return;
242 }
243
245 _capacity = _size;
246 }
247
248 void clear() {
249 _size = 0;
250
251 if (is_literal())
252 clone(_size, _capacity, std::get<const char*>(_begin));
253 std::get<uptr>(_begin).get()[0] = '\0';
254 }
255
256 void resize(const size_t n) {
257 if (is_literal())
258 clone(n, _capacity, std::get<const char*>(_begin));
259 else {
260 _size = n;
261 if (n <= _capacity)
262 memset(std::get<uptr>(_begin).get()+_size, '\0', _capacity-_size);
263 else {
264 _capacity = _size*2;
265 clone(_size, _capacity, std::get<uptr>(_begin).get());
266 }
267 }
268 }
269
270 void swap(string& str) {
271 std::swap(*this, str);
272 }
273
274 void push_back(const char c) {
275 *this += c;
276 }
277
278 void pop_back() {
279 if (_size == 0)
280 return;
281 resize(--_size);
282 }
283
284 string substr(size_t pos = 0, size_t len = npos) const {
285 return string(*this, pos, len);
286 }
287
288 size_t copy(char* s, size_t len, size_t pos = 0) const {
289 eosio::check(pos <= _size, "eosio::string::copy");
290 len = (_size < pos+len) ? _size : len;
291
292 const char* tmp{(is_literal()) ? std::get<const char*>(_begin) : std::get<uptr>(_begin).get()};
293 memcpy(s, tmp+pos, len);
294
295 return (_size < pos+len) ? _size-pos : len;
296 }
297
298 string& insert(const size_t pos, const char* str) {
299 return insert(pos, str, strlen(str));
300 }
301
302 string& insert(const size_t pos, const char* str, const size_t len) {
303 eosio::check((str != nullptr) && (0 <= pos && pos <= _size), "eosio::string::insert");
304
305 if (_capacity < (_size+len)) {
306 _size += len;
307 _capacity = _size*2;
308
309 uptr begin{std::make_unique<char[]>(_capacity)};
310 const char* tmp{(is_literal()) ? std::get<const char*>(_begin) : std::get<uptr>(_begin).get()};
311
312 memcpy(begin.get(), tmp, pos);
313 memcpy(begin.get()+pos, str, len);
314 memcpy(begin.get()+len+pos, tmp+pos, _size-len-pos);
315
316 _begin = std::move(begin);
317 }
318 else {
319 if(is_literal())
320 clone(_size, _capacity, std::get<const char*>(_begin));
321 _size += len;
322 memmove(std::get<uptr>(_begin).get()+pos+len, std::get<uptr>(_begin).get()+pos, _size-pos);
323 memcpy(std::get<uptr>(_begin).get()+pos, str, len);
324 }
325
326 return *this;
327 }
328
329 string& insert(const size_t pos, const string& str) {
330 insert(pos, str.c_str());
331 return *this;
332 }
333
334 string& erase(size_t pos = 0, size_t len = npos) {
335 eosio::check(0 <= pos && pos <= _size, "eosio::string::erase");
336
337 if (len == string::npos)
338 len = _size-pos;
339
340 _size -= len;
341
342 if (is_literal())
343 clone(_size, _capacity, std::get<const char*>(_begin));
344 memmove(std::get<uptr>(_begin).get()+pos+len, std::get<uptr>(_begin).get(), len);
345 resize(_size);
346
347 return *this;
348 }
349
350 string& append(const char* str) {
351 eosio::check(str != nullptr, "eosio::string::append");
352 insert(_size, str);
353
354 return *this;
355 }
356
357 string& append(const string& str) {
358 insert(_size, str);
359 return *this;
360 }
361
362 string& operator+=(const char c) {
363 if (_capacity == 0) {
364 _size = 1;
365 _capacity = 2;
366 clone(1, _capacity, &c);
367 }
368 else if (_size == _capacity) {
369 _capacity = ++_size*2;
370
371 const char* tmp{(is_literal()) ? std::get<const char*>(_begin) : std::get<uptr>(_begin).get()};
372 clone(_size, _capacity, tmp);
373 std::get<uptr>(_begin).get()[_size-1] = c;
374 }
375 else
376 std::get<uptr>(_begin).get()[_size++] = c;
377
378 return *this;
379 }
380
381 string& operator+=(const char* rhs) {
382 append(rhs);
383 return *this;
384 }
385
386 string& operator+=(const string& rhs) {
387 append(rhs);
388 return *this;
389 }
390
391 inline void print() const {
392 const char* tmp{(is_literal()) ? std::get<const char*>(_begin) : std::get<uptr>(_begin).get()};
393 internal_use_do_not_use::prints_l(tmp, _size);
394 }
395
396 friend bool operator< (const string& lhs, const string& rhs);
397 friend bool operator> (const string& lhs, const string& rhs);
398 friend bool operator<=(const string& lhs, const string& rhs);
399 friend bool operator>=(const string& lhs, const string& rhs);
400 friend bool operator==(const string& lhs, const string& rhs);
401 friend bool operator!=(const string& lhs, const string& rhs);
402
403 friend string operator+ (const string& lhs, const string& rhs);
404
405 private:
406 using uptr = std::unique_ptr<char[]>;
407 using sso_str = std::variant<const char*, uptr>;
408
409 size_t _size = 0;
410 size_t _capacity = 0;
411 sso_str _begin = nullptr;
412
413 void clone(size_t size, size_t capacity, const char* str) {
414 _size = size;
415 _capacity = capacity;
416
417 uptr begin{std::make_unique<char[]>(capacity)};
418 memcpy(begin.get(), str, size);
419 _begin = std::move(begin);
420 }
421
422 constexpr bool is_literal() const {
423 return (std::holds_alternative<const char*>(_begin)) ? true : false;
424 }
425 };
426
427 inline bool operator< (const string& lhs, const string& rhs) {
428 const char* beg_lhs{lhs.cbegin()}; const char* end_lhs{lhs.cend()};
429 const char* beg_rhs{rhs.cbegin()}; const char* end_rhs{rhs.cend()};
430
431 for(; beg_lhs != end_lhs && beg_rhs != end_rhs; ++beg_lhs, ++beg_rhs) {
432 if (*beg_lhs < *beg_rhs)
433 return true;
434 if (*beg_rhs < *beg_lhs)
435 return false;
436 }
437
438 return beg_lhs == end_lhs && beg_rhs != end_rhs;
439 }
440
441 inline bool operator> (const string& lhs, const string& rhs) {
442 return (rhs < lhs);
443 }
444
445 inline bool operator<=(const string& lhs, const string& rhs) {
446 return !(rhs < lhs);
447 }
448
449 inline bool operator>=(const string& lhs, const string& rhs) {
450 return !(lhs < rhs);
451 }
452
453 inline bool operator==(const string& lhs, const string& rhs) {
454 return !(lhs < rhs) && !(rhs < lhs);
455 }
456
457 inline bool operator!=(const string& lhs, const string& rhs) {
458 return !(lhs == rhs);
459 }
460
461 inline string operator+(const string& lhs, const string& rhs) {
462 string res{lhs};
463 res += rhs;
464 return res;
465 }
466
467 template<typename DataStream>
468 DataStream& operator<<(DataStream& ds, const string& str) {
469 ds << unsigned_int(str.size());
470 if (str.size())
471 ds.write(str.data(), str.size());
472 return ds;
473 }
474
475 template<typename DataStream>
476 DataStream& operator>>(DataStream& ds, string& str) {
477 std::vector<char> tmp;
478 ds >> tmp;
479 str = (tmp.size()) ? string(tmp.data(), tmp.size()) : string();
480 return ds;
481 }
482
483} // namespace eosio