-
-
Notifications
You must be signed in to change notification settings - Fork 267
Expand file tree
/
Copy pathfb_string.h
More file actions
979 lines (894 loc) · 26.7 KB
/
fb_string.h
File metadata and controls
979 lines (894 loc) · 26.7 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
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
/*
* PROGRAM: string class definition
* MODULE: fb_string.h
* DESCRIPTION: Provides almost that same functionality,
* that STL::basic_string<char> does,
* but behaves MemoryPools friendly.
*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Alexander Peshkoff
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2004 Alexander Peshkoff <peshkoff@mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#ifndef INCLUDE_FB_STRING_H
#define INCLUDE_FB_STRING_H
#include "firebird.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <utility>
#include <type_traits>
#include "fb_types.h"
#include "fb_exception.h"
#include "../common/classes/alloc.h"
#include "../common/classes/RefCounted.h"
namespace Firebird
{
class MetaString;
class AbstractString : private AutoStorage
{
public:
typedef char char_type;
typedef FB_SIZE_T size_type;
typedef FB_SSIZE_T difference_type;
typedef char* pointer;
typedef const char* const_pointer;
typedef char& reference;
typedef const char& const_reference;
typedef char value_type;
typedef pointer iterator;
typedef const_pointer const_iterator;
static const size_type npos;
enum {INLINE_BUFFER_SIZE = 32, INIT_RESERVE = 16/*, KEEP_SIZE = 512*/};
protected:
typedef ULONG internal_size_type; // 32 bits!
private:
const internal_size_type max_length;
protected:
char_type inlineBuffer[INLINE_BUFFER_SIZE]{};
char_type* stringBuffer;
internal_size_type stringLength, bufferSize;
private:
void checkPos(size_type pos) const
{
if (pos >= length()) {
fatal_exception::raise("Firebird::string - pos out of range");
}
}
void checkLength(size_type len) const
{
if (len > getMaxLength()) {
fatal_exception::raise("Firebird::string - length exceeds predefined limit");
}
}
// Reserve buffer to allow storing at least newLen characters there
// (not including null terminator). Existing contents of our string are preserved.
void reserveBuffer(const size_type newLen)
{
size_type newSize = newLen + 1;
fb_assert(newSize != 0); // This large argument would be a programming error for sure.
if (newSize > bufferSize)
{
// Make sure we do not exceed string length limit
checkLength(newLen);
// Order of assignments below is important in case of low memory conditions
// Grow buffer exponentially to prevent memory fragmentation
if (newSize / 2 < bufferSize)
newSize = size_type(bufferSize) * 2u;
// Do not grow buffer beyond string length limit
const size_type max_length = getMaxLength() + 1;
if (newSize > max_length)
newSize = max_length;
// Allocate new buffer
char_type *newBuffer = FB_NEW_POOL(getPool()) char_type[newSize];
// Carefully copy string data including null terminator
memcpy(newBuffer, stringBuffer, sizeof(char_type) * (stringLength + 1u));
// Deallocate old buffer if needed
if (stringBuffer != inlineBuffer)
delete[] stringBuffer;
stringBuffer = newBuffer;
bufferSize = static_cast<internal_size_type>(newSize);
}
}
// Make sure our buffer is large enough to store at least <length> characters in it
// (not including null terminator). Resulting buffer is not initialized.
// Use it in constructors only when stringBuffer is not assigned yet.
void initialize(const size_type len)
{
if (len < INLINE_BUFFER_SIZE)
{
stringBuffer = inlineBuffer;
bufferSize = INLINE_BUFFER_SIZE;
}
else
{
stringBuffer = NULL; // Be safe in case of exception
checkLength(len);
// Do not grow buffer beyond string length limit
const size_type max_length = getMaxLength() + 1;
// Reserve a few extra bytes in the buffer
const size_type newSize = std::min(len + 1 + INIT_RESERVE, max_length);
// Allocate new buffer
stringBuffer = FB_NEW_POOL(getPool()) char_type[newSize];
bufferSize = static_cast<internal_size_type>(newSize);
}
stringLength = static_cast<internal_size_type>(len);
stringBuffer[stringLength] = 0;
}
void shrinkBuffer() noexcept
{
// Shrink buffer if we decide it is beneficial
}
protected:
AbstractString(const size_type limit, const size_type sizeL, const void* datap);
AbstractString(const size_type limit, const_pointer p1, const size_type n1,
const_pointer p2, const size_type n2);
AbstractString(const size_type limit, const AbstractString& v);
template <class S>
AbstractString(const size_type limit, const S& v)
: max_length(static_cast<internal_size_type>(limit))
{
const FB_SIZE_T l = v.length();
initialize(l);
memcpy(stringBuffer, v.c_str(), l);
}
explicit AbstractString(const size_type limit) noexcept :
max_length(static_cast<internal_size_type>(limit)),
stringBuffer(inlineBuffer), stringLength(0), bufferSize(INLINE_BUFFER_SIZE)
{
stringBuffer[0] = 0;
}
AbstractString(const size_type limit, const size_type sizeL, char_type c);
AbstractString(const size_type limit, MemoryPool& p) noexcept : AutoStorage(p),
max_length(static_cast<internal_size_type>(limit)),
stringBuffer(inlineBuffer), stringLength(0), bufferSize(INLINE_BUFFER_SIZE)
{
stringBuffer[0] = 0;
}
AbstractString(const size_type limit, MemoryPool& p, const AbstractString& v)
: AutoStorage(p), max_length(static_cast<internal_size_type>(limit))
{
initialize(v.length());
memcpy(stringBuffer, v.c_str(), stringLength);
}
AbstractString(const size_type limit, MemoryPool& p, const void* s, const size_type l)
: AutoStorage(p), max_length(static_cast<internal_size_type>(limit))
{
initialize(l);
memcpy(stringBuffer, s, l);
}
AbstractString(const size_type limit, AbstractString&& rhs) :
max_length(static_cast<internal_size_type>(limit))
{
// We can move only string with default pool
if (!baseMove(std::forward<AbstractString>(rhs)))
{
initialize(rhs.length());
memcpy(stringBuffer, rhs.c_str(), stringLength);
}
}
AbstractString(const size_type limit, MemoryPool& p, AbstractString&& rhs)
: AutoStorage(p), max_length(static_cast<internal_size_type>(limit))
{
if (!baseMove(std::forward<AbstractString>(rhs)))
{
initialize(rhs.length());
memcpy(stringBuffer, rhs.c_str(), stringLength);
}
}
pointer modify() noexcept
{
return stringBuffer;
}
// Trim the range making sure that it fits inside specified length
static void adjustRange(const size_type length, size_type& pos, size_type& n) noexcept;
pointer baseAssign(const size_type n);
pointer baseAppend(const size_type n);
pointer baseInsert(const size_type p0, const size_type n);
void baseErase(size_type p0, size_type n) noexcept;
enum TrimType {TrimLeft, TrimRight, TrimBoth};
void baseTrim(const TrimType whereTrim, const_pointer toTrim) noexcept;
bool baseMove(AbstractString&& rhs) noexcept;
size_type getMaxLength() const noexcept
{
return max_length;
}
public:
const_pointer c_str() const noexcept
{
return stringBuffer;
}
size_type length() const noexcept
{
return stringLength;
}
size_type getCount() const noexcept
{
return stringLength;
}
// Almost same as c_str(), but return 0, not "",
// when string has no data. Useful when interacting
// with old code, which does check for NULL.
const_pointer nullStr() const noexcept
{
return stringLength ? stringBuffer : 0;
}
// Call it only when you have worked with at() or operator[]
// in case a null ASCII was inserted in the middle of the string.
size_type recalculate_length() noexcept
{
stringLength = static_cast<internal_size_type>(length(stringBuffer));
return stringLength;
}
void reserve(size_type n = 0);
void resize(const size_type n, char_type c = ' ');
void grow(const size_type n)
{
resize(n);
}
pointer getBuffer(size_type l)
{
return baseAssign(l);
}
size_type find(const AbstractString& str, size_type pos = 0) const noexcept
{
return find(str.c_str(), pos);
}
size_type find(const_pointer s, size_type pos = 0) const noexcept
{
const_pointer p = strstr(c_str() + pos, s);
return p ? p - c_str() : npos;
}
size_type find(char_type c, size_type pos = 0) const noexcept
{
const_pointer p = strchr(c_str() + pos, c);
return p ? p - c_str() : npos;
}
size_type rfind(const AbstractString& str, size_type pos = npos) const noexcept
{
return rfind(str.c_str(), pos);
}
size_type rfind(const_pointer s, const size_type pos = npos) const noexcept;
size_type rfind(char_type c, const size_type pos = npos) const noexcept;
size_type find_first_of(const AbstractString& str, size_type pos = 0) const noexcept
{
return find_first_of(str.c_str(), pos, str.length());
}
size_type find_first_of(const_pointer s, size_type pos, size_type n) const noexcept;
size_type find_first_of(const_pointer s, size_type pos = 0) const noexcept
{
return find_first_of(s, pos, length(s));
}
size_type find_first_of(char_type c, size_type pos = 0) const noexcept
{
return find(c, pos);
}
size_type find_last_of(const AbstractString& str, size_type pos = npos) const noexcept
{
return find_last_of(str.c_str(), pos, str.length());
}
size_type find_last_of(const_pointer s, const size_type pos, size_type n = npos) const noexcept;
size_type find_last_of(const_pointer s, size_type pos = npos) const noexcept
{
return find_last_of(s, pos, length(s));
}
size_type find_last_of(char_type c, size_type pos = npos) const noexcept
{
return rfind(c, pos);
}
size_type find_first_not_of(const AbstractString& str, size_type pos = 0) const noexcept
{
return find_first_not_of(str.c_str(), pos, str.length());
}
size_type find_first_not_of(const_pointer s, size_type pos, size_type n) const noexcept;
size_type find_first_not_of(const_pointer s, size_type pos = 0) const noexcept
{
return find_first_not_of(s, pos, length(s));
}
size_type find_first_not_of(char_type c, size_type pos = 0) const noexcept
{
const char_type s[2] = {c, 0};
return find_first_not_of(s, pos, 1);
}
size_type find_last_not_of(const AbstractString& str, size_type pos = npos) const noexcept
{
return find_last_not_of(str.c_str(), pos, str.length());
}
size_type find_last_not_of(const_pointer s, const size_type pos, size_type n = npos) const noexcept;
size_type find_last_not_of(const_pointer s, size_type pos = npos) const noexcept
{
return find_last_not_of(s, pos, length(s));
}
size_type find_last_not_of(char_type c, size_type pos = npos) const noexcept
{
const char_type s[2] = {c, 0};
return find_last_not_of(s, pos, 1);
}
iterator begin() noexcept
{
return modify();
}
const_iterator begin() const noexcept
{
return c_str();
}
iterator end() noexcept
{
return modify() + length();
}
const_iterator end() const noexcept
{
return c_str() + length();
}
const_reference at(const size_type pos) const
{
checkPos(pos);
return c_str()[pos];
}
reference at(const size_type pos)
{
checkPos(pos);
return modify()[pos];
}
const_reference operator[](size_type pos) const
{
return at(pos);
}
reference operator[](size_type pos)
{
return at(pos);
}
const_pointer data() const noexcept
{
return c_str();
}
size_type size() const noexcept
{
return length();
}
size_type capacity() const noexcept
{
return bufferSize - 1u;
}
bool empty() const noexcept
{
return length() == 0;
}
bool hasData() const noexcept
{
return !empty();
}
// to satisfy both ways to check for empty string
bool isEmpty() const noexcept
{
return empty();
}
void upper();
void lower();
void ltrim(const_pointer ToTrim = " ") noexcept
{
baseTrim(TrimLeft, ToTrim);
}
void rtrim(const_pointer ToTrim = " ") noexcept
{
baseTrim(TrimRight, ToTrim);
}
void trim(const_pointer ToTrim = " ") noexcept
{
baseTrim(TrimBoth, ToTrim);
}
void alltrim(const_pointer ToTrim = " ") noexcept
{
baseTrim(TrimBoth, ToTrim);
}
bool LoadFromFile(FILE* file);
void vprintf(const char* Format, va_list params);
void printf(const char* Format, ...);
size_type copyTo(pointer to, size_type toSize) const noexcept
{
fb_assert(to);
fb_assert(toSize);
if (--toSize > length())
{
toSize = length();
}
memcpy(to, c_str(), toSize);
to[toSize] = 0;
return toSize;
}
static unsigned int hash(const_pointer string, const size_type tableSize) noexcept;
unsigned int hash(size_type tableSize) const noexcept
{
return hash(c_str(), tableSize);
}
bool equalsNoCase(const_pointer string) const noexcept;
AbstractString& append(const AbstractString& str)
{
fb_assert(&str != this);
return append(str.c_str(), str.length());
}
AbstractString& append(const AbstractString& str, size_type pos, size_type n)
{
fb_assert(&str != this);
adjustRange(str.length(), pos, n);
return append(str.c_str() + pos, n);
}
AbstractString& append(const_pointer s, const size_type n)
{
memcpy(baseAppend(n), s, n);
return *this;
}
AbstractString& append(const_pointer s)
{
return append(s, length(s));
}
AbstractString& append(size_type n, char_type c)
{
memset(baseAppend(n), c, n);
return *this;
}
AbstractString& append(const_iterator first, const_iterator last)
{
return append(first, last - first);
}
AbstractString& insert(size_type p0, const AbstractString& str)
{
fb_assert(&str != this);
return insert(p0, str.c_str(), str.length());
}
AbstractString& insert(size_type p0, const AbstractString& str, size_type pos,
size_type n)
{
fb_assert(&str != this);
adjustRange(str.length(), pos, n);
return insert(p0, &str.c_str()[pos], n);
}
AbstractString& insert(size_type p0, const_pointer s, const size_type n)
{
if (p0 >= length()) {
return append(s, n);
}
memcpy(baseInsert(p0, n), s, n);
return *this;
}
AbstractString& insert(size_type p0, const_pointer s)
{
return insert(p0, s, length(s));
}
AbstractString& insert(size_type p0, const size_type n, const char_type c)
{
if (p0 >= length()) {
return append(n, c);
}
memset(baseInsert(p0, n), c, n);
return *this;
}
void insert(iterator it, char_type c)
{
insert(it - c_str(), 1, c);
}
void insert(iterator it, size_type n, char_type c)
{
insert(it - c_str(), n, c);
}
void insert(iterator it, const_iterator first, const_iterator last)
{
insert(it - c_str(), first, last - first);
}
AbstractString& erase(size_type p0 = 0, size_type n = npos) noexcept
{
baseErase(p0, n);
return *this;
}
AbstractString& clear() noexcept
{
erase();
return *this;
}
iterator erase(iterator it) noexcept
{
erase(it - c_str(), 1);
return it;
}
iterator erase(iterator first, iterator last) noexcept
{
erase(first - c_str(), last - first);
return first;
}
AbstractString& replace(size_type p0, size_type n0, const AbstractString& str)
{
fb_assert(&str != this);
return replace(p0, n0, str.c_str(), str.length());
}
AbstractString& replace(const size_type p0, const size_type n0,
const AbstractString& str, size_type pos, size_type n)
{
fb_assert(&str != this);
adjustRange(str.length(), pos, n);
return replace(p0, n0, &str.c_str()[pos], n);
}
AbstractString& replace(const size_type p0, const size_type n0, const_pointer s,
size_type n)
{
erase(p0, n0);
return insert(p0, s, n);
}
AbstractString& replace(size_type p0, size_type n0, const_pointer s)
{
return replace(p0, n0, s, length(s));
}
AbstractString& replace(const size_type p0, const size_type n0, size_type n,
char_type c)
{
erase(p0, n0);
return insert(p0, n, c);
}
AbstractString& replace(iterator first0, iterator last0, const AbstractString& str)
{
fb_assert(&str != this);
return replace(first0 - c_str(), last0 - first0, str);
}
AbstractString& replace(iterator first0, iterator last0, const_pointer s,
size_type n)
{
return replace(first0 - c_str(), last0 - first0, s, n);
}
AbstractString& replace(iterator first0, iterator last0, const_pointer s)
{
return replace(first0 - c_str(), last0 - first0, s);
}
AbstractString& replace(iterator first0, iterator last0, size_type n, char_type c)
{
return replace(first0 - c_str(), last0 - first0, n, c);
}
AbstractString& replace(iterator first0, iterator last0, const_iterator first,
const_iterator last)
{
return replace(first0 - c_str(), last0 - first0, first, last - first);
}
~AbstractString()
{
if (stringBuffer != inlineBuffer)
delete[] stringBuffer;
}
protected:
static inline size_type length(const_pointer s) noexcept
{
return static_cast<size_type>(std::char_traits<char_type>::length(s));
}
};
class StringComparator
{
public:
static int compare(AbstractString::const_pointer s1,
AbstractString::const_pointer s2,
const AbstractString::size_type n) noexcept
{
return memcmp(s1, s2, n);
}
static AbstractString::size_type getMaxLength() noexcept
{
return 0xFFFFFFFEu;
}
};
class PathNameComparator
{
public:
static int compare(AbstractString::const_pointer s1,
AbstractString::const_pointer s2,
const AbstractString::size_type n) noexcept;
static AbstractString::size_type getMaxLength() noexcept
{
return 0xFFFEu;
}
};
class IgnoreCaseComparator
{
public:
static int compare(AbstractString::const_pointer s1,
AbstractString::const_pointer s2,
const AbstractString::size_type n) noexcept;
static AbstractString::size_type getMaxLength() noexcept
{
return 0xFFFFFFFEu;
}
};
template<typename Comparator>
class StringBase : public AbstractString
{
typedef StringBase StringType;
protected:
StringBase(const_pointer p1, size_type n1,
const_pointer p2, size_type n2) :
AbstractString(Comparator::getMaxLength(), p1, n1, p2, n2) {}
private:
StringType add(const_pointer s, size_type n) const
{
return StringBase<Comparator>(c_str(), length(), s, n);
}
public:
StringBase() noexcept : AbstractString(Comparator::getMaxLength()) {}
StringBase(const StringType& v) : AbstractString(Comparator::getMaxLength(), v) {}
StringBase(const void* s, size_type n) : AbstractString(Comparator::getMaxLength(), n, s) {}
StringBase(const_pointer s) :
AbstractString(Comparator::getMaxLength(), s ? length(s) : 0, s) {}
StringBase(std::string_view sv) :
AbstractString(Comparator::getMaxLength(), static_cast<size_type>(sv.length()), sv.data()) {}
explicit StringBase(const unsigned char* s) :
AbstractString(Comparator::getMaxLength(), length((char*) s), (char*) s) {}
StringBase(const MetaString& v) : AbstractString(Comparator::getMaxLength(), v) {}
StringBase(size_type n, char_type c) : AbstractString(Comparator::getMaxLength(), n, c) {}
StringBase(const_iterator first, const_iterator last) :
AbstractString(Comparator::getMaxLength(), last - first, first) {}
explicit StringBase(MemoryPool& p) noexcept : AbstractString(Comparator::getMaxLength(), p) {}
StringBase(MemoryPool& p, const AbstractString& v) : AbstractString(Comparator::getMaxLength(), p, v) {}
StringBase(MemoryPool& p, const_pointer s) :
AbstractString(Comparator::getMaxLength(), p, s, s ? length(s) : 0) {}
StringBase(MemoryPool& p, const char_type* s, size_type l) :
AbstractString(Comparator::getMaxLength(), p, s, l) {}
StringBase(StringType&& rhs) :
AbstractString(Comparator::getMaxLength(), std::forward<AbstractString>(rhs)) {}
StringBase(MemoryPool& p, StringType&& rhs) :
AbstractString(Comparator::getMaxLength(), p, std::forward<AbstractString>(rhs)) {}
static size_type max_length() noexcept
{
return Comparator::getMaxLength();
}
StringType& assign(const StringType& str)
{
fb_assert(&str != this);
return assign(str.c_str(), str.length());
}
StringType& assign(const StringType& str, size_type pos, size_type n)
{
fb_assert(&str != this);
adjustRange(str.length(), pos, n);
return assign(&str.c_str()[pos], n);
}
StringType& assign(const void* s, size_type n)
{
memcpy(baseAssign(n), s, n);
return *this;
}
StringType& assign(const_pointer s)
{
return assign(s, length(s));
}
StringType& assign(size_type n, char_type c)
{
memset(baseAssign(n), c, n);
return *this;
}
StringType& assign(const_iterator first, const_iterator last)
{
return assign(first, last - first);
}
StringType& assign(std::string_view s)
{
return assign(s.data(), static_cast<size_type>(s.length()));
}
StringType& operator=(const StringType& v)
{
if (&v == this)
return *this;
return assign(v);
}
StringType& operator=(const_pointer s)
{
return assign(s, length(s));
}
StringType& operator=(char_type c)
{
return assign(&c, 1);
}
StringType& operator+=(const StringType& v)
{
fb_assert(&v != this);
append(v);
return *this;
}
StringType& operator+=(const_pointer s)
{
append(s);
return *this;
}
StringType& operator+=(char_type c)
{
append(1, c);
return *this;
}
StringType operator+(const StringType& v) const
{
return add(v.c_str(), v.length());
}
StringType operator+(const_pointer s) const
{
return add(s, length(s));
}
StringType operator+(char_type c) const
{
return add(&c, 1);
}
StringType& operator=(StringType&& rhs)
{
// baseMove do not clear the buffer so do it in this method
char_type* backup = nullptr;
if (stringBuffer != inlineBuffer)
backup = stringBuffer;
if (baseMove(std::forward<AbstractString>(rhs)))
{
// The dynamic buffer has been replaced, so clear the old one
delete[] backup;
}
else
{
// Cannot move, do the base assignment
assign(rhs.c_str(), rhs.length());
}
return *this;
}
StringBase<StringComparator> ToString() const
{
return StringBase<StringComparator>(c_str());
}
StringBase<PathNameComparator> ToPathName() const
{
return StringBase<PathNameComparator>(c_str());
}
StringBase<IgnoreCaseComparator> ToNoCaseString() const
{
return StringBase<IgnoreCaseComparator>(c_str());
}
StringType substr(size_type pos = 0, size_type n = npos) const
{
adjustRange(length(), pos, n);
return StringType(&c_str()[pos], n);
}
int compare(const StringType& str) const
{
return compare(str.c_str(), str.length());
}
int compare(size_type p0, size_type n0, const StringType& str)
{
return compare(p0, n0, str.c_str(), str.length());
}
int compare(size_type p0, size_type n0, const StringType& str, size_type pos, size_type n)
{
adjustRange(str.length(), pos, n);
return compare(p0, n0, &str.c_str()[pos], n);
}
int compare(const_pointer s) const
{
return compare(s, length(s));
}
int compare(size_type p0, size_type n0, const_pointer s, const size_type n) const
{
adjustRange(length(), p0, n0);
const size_type ml = n0 < n ? n0 : n;
const int rc = Comparator::compare(&c_str()[p0], s, ml);
return rc ? rc : n0 - n;
}
int compare(const_pointer s, const size_type n) const
{
const size_type ml = length() < n ? length() : n;
const int rc = Comparator::compare(c_str(), s, ml);
if (rc)
{
return rc;
}
const difference_type dl = length() - n;
return (dl < 0) ? -1 : (dl > 0) ? 1 : 0;
}
// These four functions are to speed up the most common comparisons: equality and inequality.
bool equals(const StringType& str) const
{
const size_type n = str.length();
return (length() != n) ? false : (Comparator::compare(c_str(), str.c_str(), n) == 0);
}
bool different(const StringType& str) const
{
const size_type n = str.length();
return (length() != n) ? true : (Comparator::compare(c_str(), str.c_str(), n) != 0);
}
bool equals(const_pointer s) const
{
const size_type n = length(s);
return (length() != n) ? false : (Comparator::compare(c_str(), s, n) == 0);
}
bool different(const_pointer s) const
{
const size_type n = length(s);
return (length() != n) ? true : (Comparator::compare(c_str(), s, n) != 0);
}
bool operator< (const StringType& str) const {return compare(str) < 0;}
bool operator<=(const StringType& str) const {return compare(str) <= 0;}
bool operator==(const StringType& str) const {return equals(str);}
bool operator>=(const StringType& str) const {return compare(str) >= 0;}
bool operator> (const StringType& str) const {return compare(str) > 0;}
bool operator!=(const StringType& str) const {return different(str);}
bool operator< (const char_type* str) const {return compare(str) < 0;}
bool operator<=(const char_type* str) const {return compare(str) <= 0;}
bool operator==(const char_type* str) const {return equals(str);}
bool operator>=(const char_type* str) const {return compare(str) >= 0;}
bool operator> (const char_type* str) const {return compare(str) > 0;}
bool operator!=(const char_type* str) const {return different(str);}
bool getWord(StringType& from, const char* sep)
{
from.alltrim(sep);
size_type p = from.find_first_of(sep);
if (p == npos)
{
if (from.isEmpty())
{
*this = "";
return false;
}
*this = from;
from = "";
return true;
}
*this = from.substr(0, p);
from = from.substr(p);
from.ltrim(sep);
return true;
}
};
typedef StringBase<StringComparator> string;
static inline string operator+(string::const_pointer s, const string& str)
{
string rc(s);
rc += str;
return rc;
}
static inline string operator+(string::char_type c, const string& str)
{
string rc(1, c);
rc += str;
return rc;
}
typedef StringBase<PathNameComparator> PathName;
static inline PathName operator+(PathName::const_pointer s, const PathName& str)
{
PathName rc(s);
rc += str;
return rc;
}
static inline PathName operator+(PathName::char_type c, const PathName& str)
{
PathName rc(1, c);
rc += str;
return rc;
}
typedef StringBase<IgnoreCaseComparator> NoCaseString;
static inline NoCaseString operator+(NoCaseString::const_pointer s, const NoCaseString& str)
{
NoCaseString rc(s);
rc += str;
return rc;
}
static inline NoCaseString operator+(NoCaseString::char_type c, const NoCaseString& str)
{
NoCaseString rc(1, c);
rc += str;
return rc;
}
// reference-counted strings
typedef AnyRef<string> RefString;
typedef RefPtr<RefString> RefStrPtr;
}
#endif // INCLUDE_FB_STRING_H