-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfstring.hpp
More file actions
740 lines (645 loc) · 24.5 KB
/
fstring.hpp
File metadata and controls
740 lines (645 loc) · 24.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
#pragma once
#include <concepts>
#include <cstring>
// str_subview definition below
namespace pig {
/** Allows you to compare small portions of a str_view **/
class str_subview {
private:
const char* data;
uint32_t len;
public:
constexpr str_subview(const char* d, uint32_t l) : data(d), len(l) {}
[[nodiscard]] constexpr uint32_t length() const { return len; }
[[nodiscard]] constexpr const char* c_str() const { return data; }
template<uint32_t N>
bool operator==(const char (&str)[N]) const {
if (len != N - 1) return false;
return std::memcmp(data, str, len) == 0;
}
bool operator==(const char* str) const {
for (uint32_t i = 0; i < len; ++i) {
if (data[i] != str[i]) return false;
}
return str[len] == '\0';
}
bool operator==(const str_subview& other) const {
if (len != other.len) return false;
return std::memcmp(data, other.data, len) == 0;
}
};
}
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
// str_view definition below
namespace pig {
/** Allows for memoryless setting of the precision parameter of an fstring **/
template<uint8_t C>
struct precision {
static_assert(C <= 10, "Maximum float precision is 10 digits.");
precision() = default;
};
/** Allows you to send an fstring along a buffer without template information. Very helpful**/
class str_view final {
private:
/// Contains the data of the original fstring
char* data;
/// Contains the length of the original fstring
uint32_t& len;
/// Contains the capacity of the original fstring
uint32_t cap;
/// Contains precision information
uint8_t prec;
public:
/// public constructor for str_view
str_view(char* data, uint32_t& len, uint32_t cap);
// **************
// Utility functions
// **************
// <><><> Getters <><><>
/// Returns the current length of the parent fstring
[[nodiscard]] constexpr uint32_t length() const;
/// Returns the capacity of the parent fstring
[[nodiscard]] constexpr uint32_t capacity() const;
/// Returns the data containing the parent fstring
[[nodiscard]] constexpr const char* c_str() const;
/// Createas a subview of the current view
inline str_subview subview(uint32_t start, uint32_t sub_len) const;
/// Emplaces a text at a position within the parent fstring.
template <uint32_t N>
void emplace(uint32_t index, const char (&str)[N]);
/// Emplaces a text at a position within the parent fstring.
void emplace(uint32_t index, const char* str, uint32_t count);
/// Finds a specific character starting from the provided position
int find(char c, uint32_t pos = 0) const;
// **************
// Operator overloads
// **************
// <><><> Equality <><><>
/// Returns the character at the requested position.
char& operator[](uint32_t index) const;
/// Checks if an fstring and a predefined const character are equal
template<uint32_t N>
bool operator==(const char (&str)[N]);
/// Checks if an fst_view and a const char of undefined length are equal
bool operator==(const char* str) const;
// <><><> Piping Into String <><><>
/// Adds a constant character with a literal into the parent fstring
template<uint32_t N>
str_view& operator<<(const char (&str)[N]);
/// Adds a constant character of unknown length into the current fstring
str_view& operator<<(const char* str);
/// Adds an integer into the current fstring
str_view& operator<<(int num);
/// Converts from generic size to int
str_view& operator<<(size_t num) { return *this << static_cast<int>(num); }
/// Converts from generic type to int
template<std::integral K>
str_view& operator<<(K integer) { return *this << static_cast<int>(integer); }
/// Lets us set the precision for floats
template<uint8_t P>
str_view& operator<<(precision<P> precision);
/// Lets us accept floats as well
str_view& operator<<(float num);
/// Allows for doules as well
str_view& operator<<(double num) { return *this << static_cast<float>(num); }
/// Also characters, because why not
str_view& operator<<(char c);
/// Hexidecimals as well
str_view& operator<<(const void*);
/// Allows you to put in another str_view
str_view& operator<<(const str_view &other);
/// Also allows for booleans
str_view& operator<<(bool b);
};
}
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
// str_view definition below
#include <algorithm>
#include <stdexcept>
#include <charconv>
/** @brief Throws an exception for str_view errors */
static void fstr_view_throw_err(const char err[]) {
//throw std::runtime_error(err);
}
namespace pig {
// **************************************
// Construction
// **************************************
/** @brief Construct a str_view referencing an existing buffer
* @param data Pointer to the buffer
* @param len Reference to the current length
* @param cap Maximum capacity of the buffer (excluding null terminator)
*/
inline str_view::str_view(char* data, uint32_t& len, uint32_t cap)
: data(data), len(len), cap(cap) {}
// **************************************
// Operations
// **************************************
constexpr uint32_t str_view::length() const { return len; }
constexpr uint32_t str_view::capacity() const { return cap; }
/** @brief Get C-style null-terminated string */
constexpr const char* str_view::c_str() const {
if (len < cap) data[len] = '\0';
return data;
}
/** @brief Get a subview of the string */
inline str_subview str_view::subview(uint32_t start, uint32_t sub_len) const {
if (start + sub_len > len)
fstr_view_throw_err("str_view::subview, out-of-bounds access");
return {data + start, sub_len};
}
// **************************************
// Element Access
// **************************************
inline char& str_view::operator[](uint32_t index) const {
if (index >= len)
fstr_view_throw_err("str_view::operator[], access out of bounds memory.");
return data[index];
}
// **************************************
// modification
// ***********************************
template <uint32_t N>
inline void str_view::emplace(uint32_t index, const char(&str)[N]) {
if (index + (N - 1) > cap)
fstr_view_throw_err("str_view::emplace, out-of-bounds memory");
std::memcpy(data + index, str, N - 1);
if (index + (N - 1) > len) len = index + (N - 1);
data[len] = '\0';
}
// ReSharper disable once CppMemberFunctionMayBeConst
inline void str_view::emplace(const uint32_t index, const char* str, const uint32_t count) {
if (!str) return;
if (index + count > cap)
fstr_view_throw_err("str_view::emplace, out-of-bounds memory");
std::memcpy(data + index, str, count);
if (index + count > len) len = index + count;
data[len] = '\0';
}
inline int str_view::find(char c, uint32_t pos) const {
while (pos < len) {
if (data[pos] == c)
return pos;
pos++;
}
return -1;
}
// **************************************
// Equality tests
// **************************************
template<uint32_t N>
inline bool str_view::operator==(const char(&str)[N]) {
if (len != N - 1) return false;
return std::memcmp(data, str, len) == 0;
}
inline bool str_view::operator==(const char* str) const {
for (uint32_t i = 0; i < len; ++i) {
if (data[i] != str[i]) return false;
}
return str[len] == '\0';
}
// **************************************
// Append / stream operators
// **************************************
template<uint32_t N>
inline str_view& str_view::operator<<(const char(&str)[N]) {
const uint32_t bytes = std::min<uint32_t>(N - 1, cap - len);
std::memcpy(data + len, str, bytes);
len += bytes;
data[len] = '\0';
return *this;
}
inline str_view& str_view::operator<<(const char* str) {
if (!str) return (*this) << "nullptr";
const uint32_t bytes = std::min<uint32_t>(std::strlen(str), cap - len);
std::memcpy(data + len, str, bytes);
len += bytes;
data[len] = '\0';
return *this;
}
inline str_view& str_view::operator<<(char c) {
if (len < cap) data[len++] = c;
data[len] = '\0';
return *this;
}
inline str_view& str_view::operator<<(int num) {
auto* start = data + len;
auto* end = data + cap;
auto res = std::to_chars(start, end, num);
len += res.ptr - start;
data[len] = '\0';
return *this;
}
inline str_view& str_view::operator<<(float num) {
auto* start = data + len;
auto* end = data + cap;
auto res = std::to_chars(start, end - 1, num, std::chars_format::fixed, prec);
len += res.ptr - start;
data[len] = '\0';
return *this;
}
template<uint8_t P>
inline str_view& str_view::operator<<(precision<P>) {
prec = P;
return *this;
}
inline str_view& str_view::operator<<(bool b) {
return *this << (b ? "true" : "false");
}
inline str_view& str_view::operator<<(const void* ptr) {
if (!ptr) return (*this) << "nullptr";
auto addr = reinterpret_cast<uintptr_t>(ptr);
*this << "0x";
auto* start = data + len;
auto* end = data + cap;
auto res = std::to_chars(start, end - 1, addr, 16);
len += res.ptr - start;
data[len] = '\0';
return *this;
}
}
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
// fstring declaration below
namespace pig {
/** @brief @code fstring@endcode is a custom string class that is much faster for comparison than std::string, but cannot be resized.
* Create an fstring with @code fstring<size> varName@endcode.
* @details @code fstring@endcode only has two member variables: @code uint_16 len@endcode and @code char arr[len]@endcode.
* Note that this means the maximum length for any fstring is 65534 characters (+1 for null terminator)
*/
template<uint32_t C>
class fstring {
static_assert(C >= 2 && C <= 65533, "fstring capacity must be at least 2, and less than 65533");
private:
/// Current length of the fstring
uint32_t len;
/// Array containing the information of the fstring
char arr[C + 1];
/// Current precision of the array
uint8_t prec = 10;
public:
// **************
// Constructors
// **************
/// Constructor for constant characters
template<uint16_t N>
constexpr fstring(const char (&str)[N]); // NOLINT(*-explicit-constructor)
/// Constructor for constant character without length info
constexpr fstring(const char* str); // NOLINT(*-explicit-constructor)
/// Constructor for a singular character
constexpr explicit fstring(char c);
/// Nothing in the constructor
constexpr fstring();
// **************
// Utility functions
// **************
// <><><> Getters <><><>
/// Returns the current length of the fstring
[[nodiscard]] constexpr uint32_t length() const;
/// Returns the capacity of the fstring
[[nodiscard]] static constexpr uint32_t capacity();
/// Returns the data containing the fstring
[[nodiscard]] const char* c_str();
/// Returns the data in the fstring
[[nodiscard]] char* data();
/// Returns true if the fstring is empty
[[nodiscard]] bool empty() const;
// <><><> Modifiers <><><>
/// Clears out all the data in the fstring
void clear();
/// Pops the entire fstring, setting length to 0 and returning a copy
fstring pop();
/// Wraps up a view for the current fstring
str_view wrap();
/// Resizes such that the fstring is of a certain size
template<size_t N>
requires(N <= C)
void resize();
// <><><> Emplacing <><><>
/// Emplace text at a position within the string
template<uint32_t N>
void emplace(uint32_t index, const char (&str)[N]) requires(index + N - 1 <= C);
/// Does the same but with a specified count
void emplace(uint32_t index, const char *str,uint32_t count)requires(index + count <= C);
/// Gets the substring with @code <N>@endcode elements at index @code uint32_t index@endcode
/// @return @code fstring<N>@endcode, an fstring with @code N@endcode elements.
template<uint32_t N>
[[nodiscard]] constexpr fstring<N> substr(uint32_t index) const;
// **************
// Operator overloads
// **************
// <><><> Equality <><><>
/// Returns the character at the requested position.
constexpr char& operator[](uint32_t index);
/// Checks if an fstring and a predefined const character array are equal
template<uint32_t N>
bool operator==(const char (&str)[N]) const;
/// Checks if an fstring and a const char of undefined length are equal
bool operator==(const char* str) const;
// <><><> Piping Into String <><><>
/// Adds another fstring into the current fstring
template<uint32_t N>
fstring<C>& operator<<(fstring<N>& other);
/// Adds a constant character with a literal into the fstring
template<uint32_t N>
fstring<C>& operator<<(const char (&str)[N]);
/// Adds a constant character of unknown length into the current fstring
fstring<C>& operator<<(const char* str);
// <><><> Specific types <><><>
/// Adds an integer into the current fstring
fstring<C>& operator<<(int num);
/// Adds doubles into the current fstring. Static casts to float first.
fstring<C>& operator<<(double num) { return *this << static_cast<float>(num); }
/// Lets us set the precision for floats
template<uint8_t P>
fstring<C>& operator<<(precision<P> precision);
/// Lets us accept floats as well
fstring<C>& operator<<(float num);
/// Lets us take unsigned integers
template<typename T>
requires(std::is_unsigned_v<T>)
fstring<C>& operator<<(T num) { return *this << static_cast<int>(num); }
/// Also characters, because why not
fstring<C>& operator<<(char c);
/// Hexadecimals as well
fstring<C>& operator<<(const void*);
/// Also boolean reading
fstring<C>& operator<<(bool b);
};
}
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
/* ******************************************************************** */
// fstring implementation below
static inline void fstring_throw_err(const char err[]) {
// throw std::runtime_error(err);
}
// ****************************** -------------------
// Constructors
// ****************************** -------------------
template<uint32_t C>
template<uint16_t N>
constexpr pig::fstring<C>::fstring(const char (&str)[N]) { // NOLINT(*-explicit-constructor, *-pro-type-member-init)
// Gets the length of our string
len = std::min<uint32_t>(N - 1, C - 1);
// Allocate memory for array
std::copy(str, str + len, arr);
// Assign our null character
arr[len] = '\0';
// Assign our precision identifier
prec = 10;
}
/// Constructor for constant character without length info
template<uint32_t C>
constexpr pig::fstring<C>::fstring(const char* str) { // NOLINT(*-pro-type-member-init)
// If there's nothing there
if (!str) {
len = 0;
arr[0] = '\0';
return;
}
// Gets the lenght of our string
len = std::min<uint32_t>(strlen(str), C - 1);
// Allocate memory for array with builtin memcpy
std::memcpy(arr, str, len);
// Assign our null character
arr[len] = '\0';
// Assign our precision identifier
prec = 10;
}
/// Constructor for a singular character
template<uint32_t C>
constexpr pig::fstring<C>::fstring(char c) { // NOLINT(*-pro-type-member-init)
// Length equals one
len = 1;
// Assign the first value
arr[0] = c;
arr[1] = '\0';
// Assign our precision identifier
prec = 10;
}
/// Nothing in the constructor
template<uint32_t C>
constexpr pig::fstring<C>::fstring() { // NOLINT(*-pro-type-member-init)
len = 0;
arr[0] = '\0';
// Assign our precision identifier
prec = 10;
}
// ****************************** -------------------
// Utility functions
// ****************************** -------------------
template<uint32_t C>
constexpr uint32_t pig::fstring<C>::length() const {
return len;
}
template<uint32_t C>
constexpr uint32_t pig::fstring<C>::capacity() {
return C;
}
template<uint32_t C>
const char* pig::fstring<C>::c_str() {
arr[len] = '\0';
return &arr[0];
}
template<uint32_t C>
char* pig::fstring<C>::data() {
arr[len] = '\0';
return &arr[0];
}
template<uint32_t C>
void pig::fstring<C>::clear() {
len = 0;
}
template<uint32_t C>
pig::fstring<C> pig::fstring<C>::pop() {
fstring<C> ret = *this;
clear();
return ret;
}
template<uint32_t C>
pig::str_view pig::fstring<C>::wrap() {
return str_view(arr, len, C);
}
template<uint32_t C>
template<size_t N>
requires(N <= C)
void pig::fstring<C>::resize() {
len = N - 1;
}
template<uint32_t C>
bool pig::fstring<C>::empty() const {
return len == 0;
}
template<uint32_t C> template <uint32_t N>
void pig::fstring<C>::emplace(uint32_t index, const char (&str)[N])
requires(index + N - 1 <= C)
{
memcpy(arr + index, str, N - 1);
if (index + (N - 1) > len) {
len = index + (N - 1);
arr[len] = '\0';
}
}
template<uint32_t C>
void pig::fstring<C>::emplace(uint32_t index, const char* str, uint32_t count)
requires(index + count <= C)
{
if (!str) return; // nothing to copy
std::memcpy(arr + index, str, count);
// Update length if we extended past current len
if (index + count > len) {
len = index + count;
arr[len] = '\0';
}
}
template<uint32_t C>
template<uint32_t N>
constexpr pig::fstring<N> pig::fstring<C>::substr(uint32_t index) const {
if (N > C - index)
fstring_throw_err("fstring<C>::substr, access out of bounds memory.");
return fstring<N>(arr + index, std::min(len - index, N));
}
// ****************************** -------------------
// Operator overloads
// ****************************** -------------------
template<uint32_t C>
constexpr char& pig::fstring<C>::operator[](uint32_t index) {
if (index >= len)
fstring_throw_err("fstring<C>::operator[], access out of bounds memory.");
return arr[index];
}
//<><><><><>
// Equality tests
// <><><><><>
template<uint32_t C>
template<uint32_t N>
bool pig::fstring<C>::operator==(const char(&str)[N]) const {
if (len != N - 1) return false;
return std::memcmp(arr, str, len) == 0;
}
template<uint32_t C>
bool pig::fstring<C>::operator==(const char *str) const{
for (uint_fast32_t i = 0; i < len; i++) {
if (arr[i] != str[i]) return false;
}
return str[len] == '\0';
}
template<uint32_t C>
template<uint32_t N>
pig::fstring<C>& pig::fstring<C>::operator<<(fstring<N> &other) {
const uint32_t bytes = std::min<uint32_t>( other.length(), C - len);
memcpy(arr + len, other.c_str(), bytes);
len += bytes;
return *this;
}
template<uint32_t C>
template<uint32_t N>
pig::fstring<C> & pig::fstring<C>::operator<<(const char(&str)[N]) {
const uint32_t bytes = std::min<uint32_t>( N, C - len);
memcpy(arr + len, str, bytes);
len += bytes;
return *this;
}
template<uint32_t C>
pig::fstring<C> & pig::fstring<C>::operator<<(const char *str) {
if (!str) return (*this) << "null";
const uint32_t bytes = std::min<uint32_t>( strlen(str), C - len);
memcpy(arr + len, str, bytes);
len += bytes;
return *this;
}
template<uint32_t C>
pig::fstring<C>& pig::fstring<C>::operator<<(const int num) {
auto* start = arr + len;
auto res = std::to_chars(start, arr + C, num);
len += res.ptr - start;
return *this;
}
template<uint32_t C>
template<uint8_t P>
pig::fstring<C> & pig::fstring<C>::operator<<(precision<P>) {
arr[C + 1] = P;
return *this;
}
template<uint32_t C>
pig::fstring<C> & pig::fstring<C>::operator<<(float num) {
auto* start = arr + len;
auto* end = arr + C;
auto res = std::to_chars(start, end, num, std::chars_format::fixed, prec);
if (res.ec == std::errc::value_too_large) {
return *this;
}
len += res.ptr - start;
return *this;
}
template<uint32_t C>
pig::fstring<C> & pig::fstring<C>::operator<<(char c) {
if (len != C - 1)
arr[len++] = c;
return *this;
}
template<uint32_t C>
pig::fstring<C>& pig::fstring<C>::operator<<(const void* ptr) {
if (!ptr) return (*this) << "nullptr";
auto addr = reinterpret_cast<uintptr_t>(ptr);
*this << "0x";
auto* start = arr + len;
auto* end = arr + C;
auto res = std::to_chars(start, end, addr, 16);
len += res.ptr - start;
return *this;
}
template<uint32_t C>
pig::fstring<C> & pig::fstring<C>::operator<<(bool b) {
return *this << (b ? "true" : "false");
}
inline pig::str_view& pig::str_view::operator<<(const pig::str_view &other) {
const uint32_t bytes = std::min<uint32_t>( other.length(), cap - len);
std::memmove(data + len, other.c_str(), bytes);
len += bytes;
return *this;
}
template<uint32_t N, uint32_t C>
pig::fstring<N+C> operator+(const pig::fstring<N> self, const pig::fstring<C>& other) {
pig::fstring<N + C> ret;
ret << self << other;
return ret;
}