/
string.h
832 lines (704 loc) · 29 KB
/
string.h
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
/*
* The Doomsday Engine Project -- libcore
*
* Copyright © 2004-2017 Jaakko Keränen <jaakko.keranen@iki.fi>
*
* @par License
* LGPL: http://www.gnu.org/licenses/lgpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details. You should have received a copy of
* the GNU Lesser General Public License along with this program; if not, see:
* http://www.gnu.org/licenses</small>
*/
#ifndef LIBCORE_STRING_H
#define LIBCORE_STRING_H
#include "../libcore.h"
#include "../Block"
#include "../List"
#include <c_plus/string.h>
#include <ostream>
namespace de {
template <typename T> struct Range;
class RegExp;
class CString;
class Path;
enum CaseSensitivity { CaseInsensitive, CaseSensitive };
struct DE_PUBLIC Sensitivity
{
CaseSensitivity cs;
inline Sensitivity(CaseSensitivity cs = CaseSensitive) : cs(cs) {}
inline operator CaseSensitivity() const { return cs; }
inline operator const iStringComparison *() const {
return cs == CaseSensitive ? &iCaseSensitive : &iCaseInsensitive;
}
};
/**
* The String class extends the QString class with Block conversion and
* other convenience methods.
*
* The default codec when converting strings from C strings is UTF-8 (e.g.,
* constructor that takes a <code>const char *</code> as the only argument).
*
* @ingroup types
*/
class DE_PUBLIC String : public IByteArray
{
public:
/// Error related to String operations (note: shadows de::Error). @ingroup errors
DE_ERROR(Error);
/// Encoding conversion failed. @ingroup errors
DE_SUB_ERROR(Error, ConversionError);
/// An error was encountered in string pattern replacement. @ingroup errors
DE_SUB_ERROR(Error, IllegalPatternError);
/// Invalid record member name. @ingroup errors
DE_SUB_ERROR(Error, InvalidMemberError);
/**
* Data argument for the pattern formatter.
* @see String::patternFormat()
*/
class IPatternArg
{
public:
/// An incompatible type is requested in asText() or asNumber(). @ingroup errors
DE_ERROR(TypeError);
public:
virtual ~IPatternArg() {}
/// Returns the value of the argument as a text string.
virtual String asText() const = 0;
/// Returns the value of the argument as a number.
virtual ddouble asNumber() const = 0;
};
typedef List<const IPatternArg *> PatternArgs;
/**
* Comparator for case-insensitive container keys.
*/
struct DE_PUBLIC InsensitiveLessThan
{
inline bool operator()(const String &a, const String &b) const
{
return a.compareWithoutCase(b) < 0;
}
};
public:
using SingleChar = char[2];
using size_type = dsize;
static size_type const npos;
struct BytePos {
dsize index;
explicit BytePos(dsize i = npos)
: index(i)
{}
explicit operator bool() const { return index != npos; }
bool operator==(dsize i) const { return index == i; }
bool operator!=(dsize i) const { return index != i; }
bool operator<(dsize i) const { return index < i; }
bool operator<(BytePos p) const { return index < p.index; }
bool operator>(dsize i) const { return index > i; }
bool operator>(BytePos p) const { return index > p.index; }
bool operator<=(dsize i) const { return index <= i; }
bool operator>=(dsize i) const { return index >= i; }
bool operator>=(BytePos p) const { return index >= p.index; }
BytePos operator-(int sub) const { return BytePos{index - sub}; }
BytePos operator+(int sub) const { return BytePos{index + sub}; }
BytePos operator++(int) { BytePos p = *this; index++; return p; }
BytePos &operator++() { index++; return *this; }
BytePos operator--(int) { BytePos p = *this; index--; return p; }
BytePos &operator--() { index--; return *this; }
BytePos operator-(BytePos p) const { return BytePos(index - p.index); }
};
using ByteRange = Range<BytePos>;
struct CharPos {
dsize index;
explicit CharPos(dsize i = npos)
: index(i)
{}
explicit operator bool() const { return index != npos; }
bool operator==(dsize i) const { return index == i; }
bool operator!=(dsize i) const { return index != i; }
bool operator<(dsize i) const { return index < i; }
bool operator<(CharPos i) const { return index < i.index; }
bool operator>(dsize i) const { return index > i; }
bool operator>(CharPos i) const { return index > i.index; }
bool operator<=(dsize i) const { return index <= i; }
bool operator>=(dsize i) const { return index >= i; }
CharPos operator-(int sub) const { return CharPos{index - sub}; }
CharPos operator+(int sub) const { return CharPos{index + sub}; }
CharPos operator++(int) { CharPos p = *this; index++; return p; }
CharPos &operator++() { index++; return *this; }
CharPos operator--(int) { CharPos p = *this; index--; return p; }
CharPos &operator--() { index--; return *this; }
CharPos operator-(CharPos p) const { return CharPos(index - p.index); }
};
using CharRange = Range<CharPos>;
public:
String();
String(const String &other);
String(String &&moved);
String(const Block &bytes);
String(const iBlock *bytes);
String(const iString *other);
String(const std::string &text);
String(const std::wstring &text);
String(const char *nullTerminatedCStr);
String(const wchar_t *nullTerminatedWideStr);
String(const char *cStr, int length);
String(const char *cStr, dsize length);
String(dsize length, char ch);
String(dsize length, Char ch);
String(const char *start, const char *end);
String(const Range<const char *> &range);
String(const CString &cstr);
String(const std::string &str, dsize index, dsize length);
template <typename Iterator>
inline String(Iterator start, Iterator end)
{
init_String(&_str);
for (Iterator i = start; i != end; ++i)
{
push_back(*i);
}
}
~String();
inline String &operator=(const String &other)
{
set_String(&_str, &other._str);
return *this;
}
inline String &operator=(String &&moved)
{
if (_str.chars.i)
{
deinit_String(&_str);
}
_str = moved._str;
zap(moved._str);
return *this;
}
inline BytePos sizeb() const { return BytePos{size_String(&_str)}; }
inline CharPos sizec() const { return CharPos(length_String(&_str)); }
inline dint sizei() const { return dint(size_String(&_str)); }
inline dsize sizeu() const { return size_String(&_str); }
void resize(size_t newSize);
/// Determines whether the string is empty.
inline bool empty() const { return sizeu() == 0; }
inline bool isEmpty() const { return empty(); }
inline explicit operator bool() const { return !empty(); }
inline const char *c_str() const { return cstr_String(&_str); }
inline const char *data() const { return c_str(); }
inline operator iRangecc() const { return iRangecc{data(), data() + size()}; }
inline operator const char *() const { return c_str(); }
inline operator const iString *() const { return &_str; }
inline operator iString *() { return &_str; }
inline operator std::string() const { return toStdString(); }
inline std::string toStdString() const
{
return {constBegin_String(&_str), constEnd_String(&_str)};
}
std::wstring toWideString() const;
CString toCString() const;
void clear();
/// Returns the first character of the string.
Char first() const;
/// Returns the last character of the string.
Char last() const;
bool contains(char c) const;
bool contains(const char *cStr) const;
int count(char ch) const;
bool beginsWith(const String &s, Sensitivity cs = CaseSensitive) const
{
return startsWithSc_String(&_str, s, cs);
}
bool beginsWith(char ch, Sensitivity cs = CaseSensitive) const
{
return beginsWith(SingleChar{ch, 0}, cs);
}
bool beginsWith(const char *cstr, Sensitivity cs = CaseSensitive) const
{
return startsWithSc_String(&_str, cstr, cs);
}
bool beginsWith(Char ch, Sensitivity cs = CaseSensitive) const;
bool endsWith(char ch, Sensitivity cs = CaseSensitive) const
{
return endsWith(SingleChar{ch, 0}, cs);
}
bool endsWith(const char *cstr, Sensitivity cs = CaseSensitive) const
{
return endsWithSc_String(&_str, cstr, cs);
}
inline char operator[](BytePos pos) const { return c_str()[pos.index]; }
char at(BytePos pos) const { DE_ASSERT(pos < sizeu()); return c_str()[pos.index]; }
inline String mid(CharPos pos, dsize charCount = npos) const { return substr(pos, charCount); }
String substr(CharPos pos, dsize charCount = npos) const;
String substr(const Range<CharPos> &charRange) const;
String substr(BytePos pos, dsize charCount = npos) const;
String substr(const Range<BytePos> &byteRange) const;
String left(BytePos count) const { return substr(BytePos{0}, count.index); }
String left(CharPos count) const { return substr(CharPos{0}, count.index); }
String right(BytePos count) const { return substr(sizeb() - count); }
String right(CharPos count) const;
String remove(BytePos count) const { return substr(count); }
String remove(CharPos count) const { return substr(count); }
void remove(BytePos start, dsize count);
void truncate(BytePos pos);
List<String> split(const char *separator) const;
List<String> split(Char ch) const;
List<String> split(const String &separator) const { return split(separator.c_str()); }
List<String> split(const RegExp ®Exp) const;
List<CString> splitRef(const char *separator) const;
List<CString> splitRef(Char ch) const;
String operator+(const char *) const;
String operator+(const CString &) const;
String operator+(const std::string &s) const;
inline String operator+(const String &other) const { return *this + static_cast<const char *>(other); }
String &operator+=(char ch);
String &operator+=(Char ch);
String &operator+=(const char *);
String &operator+=(const CString &);
String &operator+=(const String &);
String &append(char ch) { return *this += ch; }
String &append(Char ch) { return *this += ch; }
String &append(const char *s) { return *this += s; }
String &append(const String &s) { return *this += s; }
inline void push_back(Char ch) { append(ch); }
void insert(BytePos pos, const char *cStr);
void insert(BytePos pos, const String &str);
String &replace(Char before, Char after);
String &replace(const CString &before, const CString &after);
String &replace(const RegExp &before, const CString &after);
/**
* Does a path concatenation on this string and the argument. Note that if
* @a path is an absolute path (starts with @a dirChar), the result of the
* concatenation is just @a path.
*
* @param path Path to concatenate.
* @param dirChar Directory/folder separator character.
*/
String concatenatePath(const String &path, Char dirChar = '/') const;
String concatenateRelativePath(const String &path, Char dirChar = '/') const;
/**
* Does a path concatenation on this string and the argument. Note that if
* @a path is an absolute path (starts with '/'), the result of the
* concatenation is just @a path.
*
* @param path Path to concatenate.
*/
String operator/(const String &path) const;
String operator/(const CString &path) const;
String operator/(const char *path) const;
String operator/(const Path &path) const;
/**
* Applies pattern formatting using the string as a format string.
*
* @param args List of arguments.
*
* @return String with placeholders replaced using the arguments.
* @see patternFormat()
*/
String operator%(const PatternArgs &args) const;
/**
* Does a record member concatenation on a variable name. Record members
* use '.' as the separator character.
*
* @param member Identifier to append to this string.
*/
String concatenateMember(const String &member) const;
/// Removes whitespace from the beginning and end of the string.
/// @return Copy of the string without whitespace.
String strip() const;
/// Removes whitespace from the beginning of the string.
/// @return Copy of the string without whitespace.
String leftStrip() const;
/// Removes whitespace from the end of the string.
/// @return Copy of the string without whitespace.
String rightStrip() const;
/// Replaces all sequences of whitespace with single space characters.
String normalizeWhitespace() const;
/// Returns a copy of the string with matches removed.
String removed(const RegExp &expr) const;
/// Returns a lower-case version of the string.
String lower() const;
/// Returns an upper-case version of the string.
String upper() const;
/// Returns a version of the string where the first character is in uppercase.
String upperFirstChar() const;
/// Extracts the base name from the string (includes extension).
CString fileName(Char dirChar = '/') const;
/// Extracts the base name from the string (does not include extension).
CString fileNameWithoutExtension() const;
/**
* Extracts the file name extension from a path. A valid extension
* is the part of a file name after a period where the file name
* itself is at least one character long. For instance:
* with "a.ext" the extension is ".ext", but with ".ext" there is
* no extension.
*
* @return The extension, including the period in the beginning.
* An empty string is returned if the string contains no period.
*/
CString fileNameExtension() const;
/// Extracts the path of the string.
CString fileNamePath(Char dirChar = '/') const;
/// Extracts everything but the extension from string.
String fileNameAndPathWithoutExtension(Char dirChar = '/') const;
BytePos indexOf(char ch) const { return BytePos{indexOf_String(&_str, ch)}; }
BytePos indexOf(Char ch) const { return BytePos{indexOf_String(&_str, ch)}; }
BytePos indexOf(const char *cstr) const { return BytePos{indexOfCStr_String(&_str, cstr)}; }
BytePos indexOf(const char *cstr, BytePos from) const { return BytePos{indexOfCStrFrom_String(&_str, cstr, from.index)}; }
BytePos lastIndexOf(char ch) const { return BytePos{lastIndexOf_String(&_str, ch)}; }
BytePos lastIndexOf(Char ch) const { return BytePos{lastIndexOf_String(&_str, ch)}; }
BytePos lastIndexOf(const char *cstr) const { return BytePos{lastIndexOfCStr_String(&_str, cstr)}; }
bool containsWord(const String &word) const;
inline bool operator==(const char *cstr) const { return compare(cstr) == 0; }
inline bool operator!=(const char *cstr) const { return compare(cstr) != 0; }
inline bool operator< (const char *cstr) const { return compare(cstr) < 0; }
inline bool operator> (const char *cstr) const { return compare(cstr) > 0; }
inline bool operator<=(const char *cstr) const { return compare(cstr) <= 0; }
inline bool operator>=(const char *cstr) const { return compare(cstr) >= 0; }
inline int compare(const char *cstr) const { return cmp_String(&_str, cstr); }
int compare(const CString &str, Sensitivity cs = CaseSensitive) const;
inline int compare(const String &s, Sensitivity cs = CaseSensitive) const {
return cmpStringSc_String(&_str, &s._str, cs);
}
/**
* Compare two strings (case sensitive).
*
* @return 0, if @a a and @a b are identical. Positive, if @a a > @a b.
* Negative, if @a a < @a b.
*/
dint compareWithCase(const String &str) const;
/**
* Compare two strings (case insensitive).
*
* @return 0, if @a a and @a b are identical. Positive, if @a a > @a b.
* Negative, if @a a < @a b.
*/
dint compareWithoutCase(const String &str) const;
/**
* Compare two strings (case insensitive), but only up to @a n characters.
* @param str Other string.
* @param n Maximum length to compare up to.
* @return 0, if @a a and @a b are identical. Positive, if @a a > @a b.
* Negative, if @a a < @a b.
*/
dint compareWithoutCase(const String &str, int n) const;
/**
* Compares two strings to see how many characters they have in common
* starting from the left.
*
* @param str String.
* @param sensitivity Case sensitivity.
*
* @return Number of characters the two strings have in common from the left.
*/
int commonPrefixLength(const String &str, Sensitivity sensitivity = CaseSensitive) const;
/**
* Converts the string to UTF-8 and returns it as a byte block.
*/
Block toUtf8() const;
/**
* Converts the string to Latin1 and returns it as a byte block.
*/
Block toLatin1() const;
/**
* Flags for controlling how string-to-integer conversion works.
* See de::String::toInt().
*/
enum IntConversionFlag { AllowOnlyWhitespace = 0x0, AllowSuffix = 0x1 };
/**
* Converts the string to an integer. The default behavior is identical to
* QString::toInt(). With the @a flags parameter the conversion behavior can
* be modified.
*
* Whitespace at the beginning of the string is always ignored.
*
* With the @c AllowSuffix conversion flag, the conversion emulates the
* behavior of the standard C library's @c atoi(): the number is converted
* successfully even when it is followed by characters that do not parse
* into a valid number (a non-digit and non-sign character).
*
* @param ok @c true is returned via this pointer if the conversion was
* successful.
* @param base Base for the number.
* @param flags Conversion flags, see de::String::IntConversionFlag.
*
* @return Integer parsed from the string (@c *ok set to true). @c 0 if
* the conversion fails (@c *ok set to @c false).
*/
dint toInt(bool *ok = nullptr, int base = 10, duint flags = AllowOnlyWhitespace) const;
/**
* Converts the string to a 32-bit unsigned integer. The behavior is the same as
* QString::toUInt(), with the exception that the default is to autodetect the
* base of the number.
*
* @param ok @c true is returned via this pointer if the conversion was
* successful.
* @param base Base for the number.
*
* @return 32-bit unsigned integer parsed from the string (@c *ok set to true).
* @c 0 if the conversion fails (@c *ok set to @c false).
*/
duint32 toUInt32(bool *ok = nullptr, int base = 0) const;
long toLong(bool *ok = nullptr, int base = 0) const;
dfloat toFloat() const;
ddouble toDouble() const;
/**
* Adds a prefix to each line in the text.
*
* @param prefix Prefix text.
*
* @return Prefixed text.
*/
String addLinePrefix(const String &prefix) const;
/**
* Prefixes double quotes and backslashes with a backslash.
*/
String escaped() const;
String truncateWithEllipsis(dsize maxLength) const;
Block toPercentEncoding() const;
// Implements IByteArray.
Size size() const { return size_String(&_str); }
void get(Offset at, Byte *values, Size count) const;
void set(Offset at, const Byte *values, Size count);
public:
// Iterators:
struct const_iterator
{
iStringConstIterator iter;
operator const char *() const { return iter.pos; }
operator Char() const { return iter.value; }
Char operator*() const { return iter.value; }
const_iterator &operator++()
{
next_StringConstIterator(&iter);
return *this;
}
const_iterator operator++(int)
{
const_iterator prior = *this;
next_StringConstIterator(&iter);
return prior;
}
const_iterator operator+(int count) const
{
const_iterator i = *this;
while (count-- > 0) i++;
return i;
}
const_iterator &operator+=(int count)
{
while (count-- > 0) next_StringConstIterator(&iter);
return *this;
}
bool operator<(const const_iterator &other) const {
return iter.pos < other.iter.pos;
}
bool operator>=(const const_iterator &other) const {
return iter.pos >= other.iter.pos;
}
bool operator==(const const_iterator &other) const {
return iter.str == other.iter.str && iter.pos == other.iter.pos;
}
bool operator!=(const const_iterator &other) const { return !(*this == other); }
BytePos bytePos() const { return BytePos(iter.pos - cstr_String(iter.str)); }
};
struct const_reverse_iterator
{
iStringReverseConstIterator iter;
operator const char *() { return iter.pos; }
operator Char() const { return iter.value; }
Char operator*() const { return iter.value; }
const_reverse_iterator &operator++()
{
next_StringReverseConstIterator(&iter);
return *this;
}
const_reverse_iterator operator++(int)
{
const_reverse_iterator prior = *this;
next_StringReverseConstIterator(&iter);
return prior;
}
bool operator==(const const_reverse_iterator &other) const
{
return iter.str == other.iter.str && iter.pos == other.iter.pos;
}
bool operator!=(const const_reverse_iterator &other) const { return !(*this == other); }
BytePos bytePos() const { return BytePos(iter.pos - cstr_String(iter.str)); }
};
const_iterator begin() const;
const_iterator cbegin() const { return begin(); }
const_reverse_iterator rbegin() const;
const_reverse_iterator crbegin() const { return rbegin(); }
const_iterator end() const;
const_iterator cend() const { return end(); }
const_reverse_iterator rend() const;
const_reverse_iterator crend() const { return rend(); }
public:
static String take(iString *str);
/**
* Builds a String out of an array of bytes that contains a UTF-8 string.
*/
static String fromUtf8(const IByteArray &byteArray);
// static String fromUtf8(const QByteArray &byteArray);
static String fromUtf8(const Block &block);
static String fromUtf8(const char *nullTerminatedCStr);
/**
* Builds a String out of an array of bytes that contains a Latin1 string.
*/
static String fromLatin1(const IByteArray &byteArray);
/**
* Builds a String out of an array of bytes using the IBM PC character set
* (DOS code page 437).
*
* @param byteArray Characters to convert.
*
* @return Converted string.
*/
static String fromCP437(const IByteArray &byteArray);
static String fromPercentEncoding(const Block &percentEncoded);
// static dint compareWithCase(const QChar *a, const QChar *b, dsize count);
/**
* Checks if two strings are the same (case sensitive), up to @a count characters.
* If the strings are longer than @a count, the remainder will be ignored in the
* check.
*
* No deep copying occurs in this method.
*
* @param a Null-terminated string.
* @param b Null-terminated string.
* @param count Maximum number of characters to check.
*
* @return @c true, if the strings are equal (excluding the part that is longer
* than @a count).
*/
// static bool equals(const QChar *a, const QChar *b, dsize count);
/**
* Advances the iterator until a nonspace character is encountered.
*
* @param i Iterator to advance.
* @param end End of the string. Will not advance past this.
*/
static void skipSpace(const_iterator &i, const const_iterator &end);
/**
* Formats a string using standard printf() formatting.
*
* @param format Format string.
*
* @return Formatted output.
*/
static String format(const char *format, ...);
static String asText(dint8 value) { return String::format("%d", value); }
static String asText(dint16 value) { return String::format("%d", value); }
static String asText(dint32 value) { return String::format("%d", value); }
static String asText(dint64 value) { return String::format("%lld", value); }
static String asText(duint8 value) { return String::format("%u", value); }
static String asText(duint16 value) { return String::format("%u", value); }
static String asText(duint32 value) { return String::format("%u", value); }
static String asText(duint64 value) { return String::format("%llu", value); }
static String asText(dsize value) { return String::format("%zu", value); }
static String asText(dfloat value) { return String::format("%f", value); }
static String asText(ddouble value) { return String::format("%f", value); }
static String asText(char value) { return String::format("%c", value); }
static String asText(Char value)
{
iMultibyteChar mb;
init_MultibyteChar(&mb, value);
return asText(mb.bytes);
}
static String asText(const char *value) { return String::format("%s", value); }
/**
* Formats data according to formatting instructions. Outputs a
* string containing the formatted data.
*
* Note that the behavior is different than the standard C printf() formatting.
* For example, "%b" will format the number argument as boolean "True" or "False".
* Use String::format() for normal printf() formatting.
*
* @param formatIter Will be moved past the formatting instructions.
* After the call, will remain past the end of
* the formatting characters.
* @param formatEnd Iterator to the end of the format string.
* @param arg Argument to format.
*
* @return Formatted argument as a string.
*/
static String patternFormat(const_iterator &formatIter,
const const_iterator &formatEnd,
const IPatternArg &arg);
static void advanceFormat(const_iterator &i,
const const_iterator &end);
static String join(const List<String> &stringList, const char *sep = "");
private:
iString _str;
};
using StringList = List<String>;
inline StringList makeList(int count, const char * const *strings)
{
StringList list;
for (int i = 0; i < count; ++i)
{
list << String(strings[i]);
}
return list;
}
inline String operator+(Char ch, const String &s)
{
return String(1, ch) + s;
}
inline String operator+(const char *left, const String &right)
{
return String(left) + right;
}
inline const char *operator+(const char *cStr, const String::BytePos &offset)
{
return cStr + offset.index;
}
inline String operator/(const char *cStr, const String &str)
{
return String(cStr) / str;
}
inline std::ostream &operator<<(std::ostream &os, const String &str)
{
os.write(str, str.sizei());
return os;
}
struct DE_PUBLIC mb_iterator
{
const char *i;
const char *start;
mutable mbstate_t mb{};
mutable dsize curCharLen = 0;
mb_iterator() : i{nullptr}, start{nullptr} {}
mb_iterator(const char *p) : i{p}, start{i} {}
mb_iterator(const String &str) : i{str.c_str()}, start{i} {}
operator const char *() const { return i; }
Char operator*() const;
mb_iterator &operator++();
mb_iterator operator++(int);
mb_iterator operator+(int offset) const;
mb_iterator &operator+=(int offset);
bool operator==(const char *ptr) const { return i == ptr; }
bool operator==(const mb_iterator &other) const { return i == other.i; }
bool operator!=(const mb_iterator &other) const { return !(*this == other); }
bool operator!=(const char *ptr) const { return i != ptr; }
explicit operator bool() const { return i != nullptr; }
String::BytePos pos() const { return String::BytePos(i - start); }
Char decode() const;
};
} // namespace de
namespace std
{
template<>
struct hash<de::String> {
std::size_t operator()(const de::String &key) const {
return hash<std::string>()(key.toStdString());
}
};
}
#endif // LIBCORE_STRING_H