Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/core/string/ustring.h
20831 views
1
/**************************************************************************/
2
/* ustring.h */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#pragma once
32
33
// Note: _GODOT suffix added to header guard to avoid conflict with ICU header.
34
35
#include "core/string/char_utils.h" // IWYU pragma: export
36
#include "core/templates/cowdata.h"
37
#include "core/templates/hashfuncs.h"
38
#include "core/templates/vector.h"
39
#include "core/typedefs.h"
40
41
class String;
42
template <typename T>
43
class CharStringT;
44
45
/*************************************************************************/
46
/* Utility Functions */
47
/*************************************************************************/
48
49
// Not defined by std.
50
// strlen equivalent function for char16_t * arguments.
51
constexpr size_t strlen(const char16_t *p_str) {
52
const char16_t *ptr = p_str;
53
while (*ptr != 0) {
54
++ptr;
55
}
56
return ptr - p_str;
57
}
58
59
// strlen equivalent function for char32_t * arguments.
60
constexpr size_t strlen(const char32_t *p_str) {
61
const char32_t *ptr = p_str;
62
while (*ptr != 0) {
63
++ptr;
64
}
65
return ptr - p_str;
66
}
67
68
// strlen equivalent function for wchar_t * arguments; depends on the platform.
69
constexpr size_t strlen(const wchar_t *p_str) {
70
// Use static_cast twice because reinterpret_cast is not allowed in constexpr
71
#ifdef WINDOWS_ENABLED
72
// wchar_t is 16-bit
73
return strlen(static_cast<const char16_t *>(static_cast<const void *>(p_str)));
74
#else
75
// wchar_t is 32-bit
76
return strlen(static_cast<const char32_t *>(static_cast<const void *>(p_str)));
77
#endif
78
}
79
80
// strnlen equivalent function for char16_t * arguments.
81
constexpr size_t strnlen(const char16_t *p_str, size_t p_clip_to_len) {
82
size_t len = 0;
83
while (len < p_clip_to_len && *(p_str++) != 0) {
84
len++;
85
}
86
return len;
87
}
88
89
// strnlen equivalent function for char32_t * arguments.
90
constexpr size_t strnlen(const char32_t *p_str, size_t p_clip_to_len) {
91
size_t len = 0;
92
while (len < p_clip_to_len && *(p_str++) != 0) {
93
len++;
94
}
95
return len;
96
}
97
98
// strnlen equivalent function for wchar_t * arguments; depends on the platform.
99
constexpr size_t strnlen(const wchar_t *p_str, size_t p_clip_to_len) {
100
// Use static_cast twice because reinterpret_cast is not allowed in constexpr
101
#ifdef WINDOWS_ENABLED
102
// wchar_t is 16-bit
103
return strnlen(static_cast<const char16_t *>(static_cast<const void *>(p_str)), p_clip_to_len);
104
#else
105
// wchar_t is 32-bit
106
return strnlen(static_cast<const char32_t *>(static_cast<const void *>(p_str)), p_clip_to_len);
107
#endif
108
}
109
110
template <typename L, typename R>
111
constexpr int64_t str_compare(const L *l_ptr, const R *r_ptr) {
112
while (true) {
113
const char32_t l = *l_ptr;
114
const char32_t r = *r_ptr;
115
116
if (l == 0 || l != r) {
117
return static_cast<int64_t>(l) - static_cast<int64_t>(r);
118
}
119
120
l_ptr++;
121
r_ptr++;
122
}
123
}
124
125
/*************************************************************************/
126
/* CharProxy */
127
/*************************************************************************/
128
129
template <typename T>
130
class [[nodiscard]] CharProxy {
131
friend String;
132
friend CharStringT<T>;
133
134
const int _index;
135
CowData<T> &_cowdata;
136
static constexpr T _null = 0;
137
138
_FORCE_INLINE_ CharProxy(const int &p_index, CowData<T> &p_cowdata) :
139
_index(p_index),
140
_cowdata(p_cowdata) {}
141
142
public:
143
_FORCE_INLINE_ CharProxy(const CharProxy<T> &p_other) :
144
_index(p_other._index),
145
_cowdata(p_other._cowdata) {}
146
147
_FORCE_INLINE_ operator T() const {
148
if (unlikely(_index == _cowdata.size())) {
149
return _null;
150
}
151
152
return _cowdata.get(_index);
153
}
154
155
_FORCE_INLINE_ const T *operator&() const {
156
return _cowdata.ptr() + _index;
157
}
158
159
_FORCE_INLINE_ void operator=(const T &p_other) const {
160
_cowdata.set(_index, p_other);
161
}
162
163
_FORCE_INLINE_ void operator=(const CharProxy<T> &p_other) const {
164
_cowdata.set(_index, p_other.operator T());
165
}
166
};
167
168
/*************************************************************************/
169
/* CharStringT */
170
/*************************************************************************/
171
172
template <typename T>
173
class [[nodiscard]] CharStringT {
174
CowData<T> _cowdata;
175
static constexpr T _null = 0;
176
177
public:
178
_FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); }
179
_FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); }
180
_FORCE_INLINE_ const T *get_data() const { return size() ? ptr() : &_null; }
181
182
// Returns the number of characters in the buffer, including the terminating NUL character.
183
// In most cases, length() should be used instead.
184
_FORCE_INLINE_ int size() const { return _cowdata.size(); }
185
// Returns the number of characters in the string (excluding terminating NUL character).
186
_FORCE_INLINE_ int length() const { return size() ? size() - 1 : 0; }
187
_FORCE_INLINE_ bool is_empty() const { return length() == 0; }
188
189
_FORCE_INLINE_ operator Span<T>() const { return Span(ptr(), length()); }
190
_FORCE_INLINE_ Span<T> span() const { return Span(ptr(), length()); }
191
192
/// Resizes the string. The given size must include the null terminator.
193
/// New characters are not initialized, and should be set by the caller.
194
_FORCE_INLINE_ Error resize_uninitialized(int64_t p_size) { return _cowdata.template resize<false>(p_size); }
195
196
_FORCE_INLINE_ T get(int p_index) const { return _cowdata.get(p_index); }
197
_FORCE_INLINE_ void set(int p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); }
198
_FORCE_INLINE_ const T &operator[](int p_index) const {
199
if (unlikely(p_index == _cowdata.size())) {
200
return _null;
201
}
202
return _cowdata.get(p_index);
203
}
204
_FORCE_INLINE_ CharProxy<T> operator[](int p_index) { return CharProxy<T>(p_index, _cowdata); }
205
206
_FORCE_INLINE_ CharStringT() = default;
207
_FORCE_INLINE_ CharStringT(const CharStringT &p_str) = default;
208
_FORCE_INLINE_ CharStringT(CharStringT &&p_str) = default;
209
_FORCE_INLINE_ void operator=(const CharStringT &p_str) { _cowdata = p_str._cowdata; }
210
_FORCE_INLINE_ void operator=(CharStringT &&p_str) { _cowdata = std::move(p_str._cowdata); }
211
_FORCE_INLINE_ CharStringT(const T *p_cstr) { copy_from(p_cstr); }
212
_FORCE_INLINE_ void operator=(const T *p_cstr) { copy_from(p_cstr); }
213
214
_FORCE_INLINE_ bool operator==(const CharStringT<T> &p_other) const { return span() == p_other.span(); }
215
_FORCE_INLINE_ bool operator!=(const CharStringT<T> &p_other) const { return !(*this == p_other); }
216
_FORCE_INLINE_ bool operator<(const CharStringT<T> &p_other) const {
217
if (length() == 0) {
218
return p_other.length() != 0;
219
}
220
return str_compare(get_data(), p_other.get_data()) < 0;
221
}
222
_FORCE_INLINE_ CharStringT<T> &operator+=(T p_char) {
223
const int lhs_len = length();
224
resize_uninitialized(lhs_len + 2);
225
226
T *dst = ptrw();
227
dst[lhs_len] = p_char;
228
dst[lhs_len + 1] = _null;
229
230
return *this;
231
}
232
233
uint32_t hash() const { return hash_djb2(get_data()); }
234
235
protected:
236
void copy_from(const T *p_cstr) {
237
if (!p_cstr) {
238
resize_uninitialized(0);
239
return;
240
}
241
242
size_t len = strlen(p_cstr);
243
if (len == 0) {
244
resize_uninitialized(0);
245
return;
246
}
247
248
Error err = resize_uninitialized(++len); // include terminating null char.
249
250
ERR_FAIL_COND_MSG(err != OK, "Failed to copy C-string.");
251
252
memcpy(ptrw(), p_cstr, len * sizeof(T));
253
}
254
};
255
256
template <typename T>
257
struct is_zero_constructible<CharStringT<T>> : std::true_type {};
258
259
using CharString = CharStringT<char>;
260
using Char16String = CharStringT<char16_t>;
261
262
/*************************************************************************/
263
/* String */
264
/*************************************************************************/
265
266
class [[nodiscard]] String {
267
CowData<char32_t> _cowdata;
268
static constexpr char32_t _null = 0;
269
static constexpr char32_t _replacement_char = 0xfffd;
270
271
// NULL-terminated c string copy - automatically parse the string to find the length.
272
void append_latin1(const char *p_cstr) {
273
append_latin1(Span(p_cstr, p_cstr ? strlen(p_cstr) : 0));
274
}
275
void append_utf32(const char32_t *p_cstr) {
276
append_utf32(Span(p_cstr, p_cstr ? strlen(p_cstr) : 0));
277
}
278
void append_wstring(const wchar_t *p_cstr) {
279
#ifdef WINDOWS_ENABLED
280
// wchar_t is 16-bit, parse as UTF-16
281
append_utf16((const char16_t *)p_cstr);
282
#else
283
// wchar_t is 32-bit, copy directly
284
append_utf32((const char32_t *)p_cstr);
285
#endif
286
}
287
288
bool _base_is_subsequence_of(const String &p_string, bool case_insensitive) const;
289
int _count(const String &p_string, int p_from, int p_to, bool p_case_insensitive) const;
290
int _count(const char *p_string, int p_from, int p_to, bool p_case_insensitive) const;
291
String _separate_compound_words() const;
292
293
public:
294
enum {
295
npos = -1 ///<for "some" compatibility with std::string (npos is a huge value in std::string)
296
};
297
298
_FORCE_INLINE_ char32_t *ptrw() { return _cowdata.ptrw(); }
299
_FORCE_INLINE_ const char32_t *ptr() const { return _cowdata.ptr(); }
300
_FORCE_INLINE_ const char32_t *get_data() const { return size() ? ptr() : &_null; }
301
302
// Returns the number of characters in the buffer, including the terminating NUL character.
303
// In most cases, length() should be used instead.
304
_FORCE_INLINE_ int size() const { return _cowdata.size(); }
305
// Returns the number of characters in the string (excluding terminating NUL character).
306
_FORCE_INLINE_ int length() const { return size() ? size() - 1 : 0; }
307
_FORCE_INLINE_ bool is_empty() const { return length() == 0; }
308
309
_FORCE_INLINE_ operator Span<char32_t>() const { return Span(ptr(), length()); }
310
_FORCE_INLINE_ Span<char32_t> span() const { return Span(ptr(), length()); }
311
312
void remove_at(int p_index) { _cowdata.remove_at(p_index); }
313
314
_FORCE_INLINE_ void clear() { resize_uninitialized(0); }
315
316
_FORCE_INLINE_ char32_t get(int p_index) const { return _cowdata.get(p_index); }
317
_FORCE_INLINE_ void set(int p_index, const char32_t &p_elem) { _cowdata.set(p_index, p_elem); }
318
319
/// Resizes the string. The given size must include the null terminator.
320
/// New characters are not initialized, and should be set by the caller.
321
Error resize_uninitialized(int64_t p_size) { return _cowdata.resize<false>(p_size); }
322
323
Error reserve(int64_t p_size) {
324
ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER);
325
return _cowdata.reserve(p_size);
326
}
327
328
_FORCE_INLINE_ const char32_t &operator[](int p_index) const {
329
if (unlikely(p_index == _cowdata.size())) {
330
return _null;
331
}
332
333
return _cowdata.get(p_index);
334
}
335
_FORCE_INLINE_ CharProxy<char32_t> operator[](int p_index) { return CharProxy<char32_t>(p_index, _cowdata); }
336
337
/* Compatibility Operators */
338
339
bool operator==(const String &p_str) const;
340
bool operator!=(const String &p_str) const;
341
String operator+(const String &p_str) const;
342
String operator+(const char *p_char) const;
343
String operator+(const wchar_t *p_char) const;
344
String operator+(const char32_t *p_char) const;
345
String operator+(char32_t p_char) const;
346
347
String &operator+=(const String &);
348
String &operator+=(char32_t p_char);
349
String &operator+=(const char *p_str);
350
String &operator+=(const wchar_t *p_str);
351
String &operator+=(const char32_t *p_str);
352
353
bool operator==(const char *p_str) const;
354
bool operator==(const wchar_t *p_str) const;
355
bool operator==(const char32_t *p_str) const;
356
bool operator==(const Span<char32_t> &p_str_range) const;
357
358
bool operator!=(const char *p_str) const;
359
bool operator!=(const wchar_t *p_str) const;
360
bool operator!=(const char32_t *p_str) const;
361
362
bool operator<(const char32_t *p_str) const;
363
bool operator<(const char *p_str) const;
364
bool operator<(const wchar_t *p_str) const;
365
366
bool operator<(const String &p_str) const;
367
bool operator<=(const String &p_str) const;
368
bool operator>(const String &p_str) const;
369
bool operator>=(const String &p_str) const;
370
371
signed char casecmp_to(const String &p_str) const;
372
signed char nocasecmp_to(const String &p_str) const;
373
signed char naturalcasecmp_to(const String &p_str) const;
374
signed char naturalnocasecmp_to(const String &p_str) const;
375
// Special sorting for file names. Names starting with `_` are put before all others except those starting with `.`, otherwise natural comparison is used.
376
signed char filecasecmp_to(const String &p_str) const;
377
signed char filenocasecmp_to(const String &p_str) const;
378
379
bool is_valid_string() const;
380
381
/* debug, error messages */
382
void print_unicode_error(const String &p_message, bool p_critical = false) const;
383
384
/* complex helpers */
385
String substr(int p_from, int p_chars = -1) const;
386
int find(const String &p_str, int p_from = 0) const; ///< return <0 if failed
387
int find(const char *p_str, int p_from = 0) const; ///< return <0 if failed
388
int find_char(char32_t p_char, int p_from = 0) const; ///< return <0 if failed
389
int findn(const String &p_str, int p_from = 0) const; ///< return <0 if failed, case insensitive
390
int findn(const char *p_str, int p_from = 0) const; ///< return <0 if failed
391
int rfind(const String &p_str, int p_from = -1) const; ///< return <0 if failed
392
int rfind(const char *p_str, int p_from = -1) const; ///< return <0 if failed
393
int rfind_char(char32_t p_char, int p_from = -1) const; ///< return <0 if failed
394
int rfindn(const String &p_str, int p_from = -1) const; ///< return <0 if failed, case insensitive
395
int rfindn(const char *p_str, int p_from = -1) const; ///< return <0 if failed
396
int findmk(const Vector<String> &p_keys, int p_from = 0, int *r_key = nullptr) const; ///< return <0 if failed
397
bool match(const String &p_wildcard) const;
398
bool matchn(const String &p_wildcard) const;
399
bool begins_with(const String &p_string) const;
400
bool begins_with(const char *p_string) const;
401
bool ends_with(const String &p_string) const;
402
bool ends_with(const char *p_string) const;
403
bool is_enclosed_in(const String &p_string) const;
404
bool is_subsequence_of(const String &p_string) const;
405
bool is_subsequence_ofn(const String &p_string) const;
406
bool is_quoted() const;
407
bool is_lowercase() const;
408
Vector<String> bigrams() const;
409
float similarity(const String &p_string) const;
410
String format(const Variant &values, const String &placeholder = "{_}") const;
411
String replace_first(const String &p_key, const String &p_with) const;
412
String replace_first(const char *p_key, const char *p_with) const;
413
String replace(const String &p_key, const String &p_with) const;
414
String replace(const char *p_key, const char *p_with) const;
415
String replace_char(char32_t p_key, char32_t p_with) const;
416
String replace_chars(const String &p_keys, char32_t p_with) const;
417
String replace_chars(const char *p_keys, char32_t p_with) const;
418
String replacen(const String &p_key, const String &p_with) const;
419
String replacen(const char *p_key, const char *p_with) const;
420
String repeat(int p_count) const;
421
String reverse() const;
422
String insert(int p_at_pos, const String &p_string) const;
423
String erase(int p_pos, int p_chars = 1) const;
424
String remove_char(char32_t p_what) const;
425
String remove_chars(const String &p_chars) const;
426
String remove_chars(const char *p_chars) const;
427
String pad_decimals(int p_digits) const;
428
String pad_zeros(int p_digits) const;
429
String trim_prefix(const String &p_prefix) const;
430
String trim_prefix(const char *p_prefix) const;
431
String trim_suffix(const String &p_suffix) const;
432
String trim_suffix(const char *p_suffix) const;
433
String lpad(int min_length, const String &character = " ") const;
434
String rpad(int min_length, const String &character = " ") const;
435
String sprintf(const Span<Variant> &values, bool *error) const;
436
String quote(const String &quotechar = "\"") const;
437
String unquote() const;
438
static String num(double p_num, int p_decimals = -1);
439
static String num_scientific(double p_num);
440
static String num_scientific(float p_num);
441
static String num_real(double p_num, bool p_trailing = true);
442
static String num_real(float p_num, bool p_trailing = true);
443
static String num_int64(int64_t p_num, int base = 10, bool capitalize_hex = false);
444
static String num_uint64(uint64_t p_num, int base = 10, bool capitalize_hex = false);
445
static String chr(char32_t p_char) {
446
String string;
447
string.append_utf32(Span(&p_char, 1));
448
return string;
449
}
450
static String md5(const uint8_t *p_md5);
451
static String hex_encode_buffer(const uint8_t *p_buffer, int p_len);
452
Vector<uint8_t> hex_decode() const;
453
454
bool is_numeric() const;
455
456
double to_float() const;
457
int64_t hex_to_int() const;
458
int64_t bin_to_int() const;
459
int64_t to_int() const;
460
461
static int64_t to_int(const char *p_str, int p_len = -1);
462
static int64_t to_int(const wchar_t *p_str, int p_len = -1);
463
static int64_t to_int(const char32_t *p_str, int p_len = -1, bool p_clamp = false);
464
465
static double to_float(const char *p_str);
466
static double to_float(const wchar_t *p_str, const wchar_t **r_end = nullptr);
467
static double to_float(const char32_t *p_str, const char32_t **r_end = nullptr);
468
static uint32_t num_characters(int64_t p_int);
469
470
String capitalize() const;
471
String to_camel_case() const;
472
String to_pascal_case() const;
473
String to_snake_case() const;
474
String to_kebab_case() const;
475
476
String get_with_code_lines() const;
477
int get_slice_count(const String &p_splitter) const;
478
int get_slice_count(const char *p_splitter) const;
479
String get_slice(const String &p_splitter, int p_slice) const;
480
String get_slice(const char *p_splitter, int p_slice) const;
481
String get_slicec(char32_t p_splitter, int p_slice) const;
482
483
Vector<String> split(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
484
Vector<String> split(const char *p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
485
Vector<String> rsplit(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
486
Vector<String> rsplit(const char *p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
487
Vector<String> split_spaces(int p_maxsplit = 0) const;
488
Vector<double> split_floats(const String &p_splitter, bool p_allow_empty = true) const;
489
Vector<float> split_floats_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const;
490
Vector<int> split_ints(const String &p_splitter, bool p_allow_empty = true) const;
491
Vector<int> split_ints_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const;
492
493
String join(const Vector<String> &parts) const;
494
495
static char32_t char_uppercase(char32_t p_char);
496
static char32_t char_lowercase(char32_t p_char);
497
String to_upper() const;
498
String to_lower() const;
499
500
int count(const String &p_string, int p_from = 0, int p_to = 0) const;
501
int count(const char *p_string, int p_from = 0, int p_to = 0) const;
502
int countn(const String &p_string, int p_from = 0, int p_to = 0) const;
503
int countn(const char *p_string, int p_from = 0, int p_to = 0) const;
504
505
String left(int p_len) const;
506
String right(int p_len) const;
507
String indent(const String &p_prefix) const;
508
String dedent() const;
509
String strip_edges(bool left = true, bool right = true) const;
510
String strip_escapes() const;
511
String lstrip(const String &p_chars) const;
512
String rstrip(const String &p_chars) const;
513
String get_extension() const;
514
String get_basename() const;
515
String path_join(const String &p_path) const;
516
char32_t unicode_at(int p_idx) const;
517
bool has_extension(const char *p_ext) const { return get_extension().to_lower() == p_ext; }
518
bool has_extension(const String &p_ext) const { return get_extension().to_lower() == p_ext; }
519
520
CharString ascii(bool p_allow_extended = false) const;
521
// Parse an ascii string.
522
// If any character is > 127, an error will be logged, and 0xfffd will be inserted.
523
Error append_ascii(const Span<char> &p_range);
524
static String ascii(const Span<char> &p_range) {
525
String s;
526
s.append_ascii(p_range);
527
return s;
528
}
529
CharString latin1() const { return ascii(true); }
530
void append_latin1(const Span<char> &p_cstr);
531
static String latin1(const Span<char> &p_string) {
532
String string;
533
string.append_latin1(p_string);
534
return string;
535
}
536
537
CharString utf8(Vector<uint8_t> *r_ch_length_map = nullptr) const;
538
Error append_utf8(const char *p_utf8, int p_len = -1);
539
Error append_utf8(const Span<char> &p_range) {
540
return append_utf8(p_range.ptr(), p_range.size());
541
}
542
static String utf8(const char *p_utf8, int p_len = -1) {
543
String ret;
544
ret.append_utf8(p_utf8, p_len);
545
return ret;
546
}
547
static String utf8(const Span<char> &p_range) { return utf8(p_range.ptr(), p_range.size()); }
548
549
Char16String utf16() const;
550
Error append_utf16(const char16_t *p_utf16, int p_len = -1, bool p_default_little_endian = true);
551
Error append_utf16(const Span<char16_t> p_range, bool p_skip_cr = false) {
552
return append_utf16(p_range.ptr(), p_range.size(), p_skip_cr);
553
}
554
static String utf16(const char16_t *p_utf16, int p_len = -1) {
555
String ret;
556
ret.append_utf16(p_utf16, p_len);
557
return ret;
558
}
559
static String utf16(const Span<char16_t> &p_range) { return utf16(p_range.ptr(), p_range.size()); }
560
561
// wchar_t copy_from depends on the platform.
562
Error append_wstring(const Span<wchar_t> &p_cstr) {
563
#ifdef WINDOWS_ENABLED
564
// wchar_t is 16-bit, parse as UTF-16
565
return append_utf16((const char16_t *)p_cstr.ptr(), p_cstr.size());
566
#else
567
// wchar_t is 32-bit, copy directly
568
return append_utf32((Span<char32_t> &)p_cstr);
569
#endif
570
}
571
static String wstring(const Span<wchar_t> &p_string) {
572
String string;
573
string.append_wstring(p_string);
574
return string;
575
}
576
577
Error append_utf32(const Span<char32_t> &p_cstr);
578
static String utf32(const Span<char32_t> &p_span) {
579
String string;
580
string.append_utf32(p_span);
581
return string;
582
}
583
584
// Like append_utf32, but does not check the string for string integrity (and is thus faster).
585
// Prefer this function for conversion from trusted utf32 strings.
586
void append_utf32_unchecked(const Span<char32_t> &p_span);
587
static String utf32_unchecked(const Span<char32_t> &p_string) {
588
String string;
589
string.append_utf32_unchecked(p_string);
590
return string;
591
}
592
593
static uint32_t hash(const char32_t *p_cstr, int p_len); /* hash the string */
594
static uint32_t hash(const char32_t *p_cstr); /* hash the string */
595
static uint32_t hash(const wchar_t *p_cstr, int p_len); /* hash the string */
596
static uint32_t hash(const wchar_t *p_cstr); /* hash the string */
597
static uint32_t hash(const char *p_cstr, int p_len); /* hash the string */
598
static uint32_t hash(const char *p_cstr); /* hash the string */
599
uint32_t hash() const; /* hash the string */
600
uint64_t hash64() const; /* hash the string */
601
String md5_text() const;
602
String sha1_text() const;
603
String sha256_text() const;
604
Vector<uint8_t> md5_buffer() const;
605
Vector<uint8_t> sha1_buffer() const;
606
Vector<uint8_t> sha256_buffer() const;
607
608
_FORCE_INLINE_ bool contains(const char *p_str) const { return find(p_str) != -1; }
609
_FORCE_INLINE_ bool contains(const String &p_str) const { return find(p_str) != -1; }
610
_FORCE_INLINE_ bool contains_char(char32_t p_chr) const { return find_char(p_chr) != -1; }
611
_FORCE_INLINE_ bool containsn(const char *p_str) const { return findn(p_str) != -1; }
612
_FORCE_INLINE_ bool containsn(const String &p_str) const { return findn(p_str) != -1; }
613
614
// path functions
615
bool is_absolute_path() const;
616
bool is_relative_path() const;
617
bool is_resource_file() const;
618
String path_to(const String &p_path) const;
619
String path_to_file(const String &p_path) const;
620
String get_base_dir() const;
621
String get_file() const;
622
static String humanize_size(uint64_t p_size);
623
String simplify_path() const;
624
bool is_network_share_path() const;
625
626
String xml_escape(bool p_escape_quotes = false) const;
627
String xml_unescape() const;
628
String uri_encode() const;
629
String uri_decode() const;
630
String uri_file_decode() const;
631
String c_escape() const;
632
String c_escape_multiline() const;
633
String c_unescape() const;
634
String json_escape() const;
635
Error parse_url(String &r_scheme, String &r_host, int &r_port, String &r_path, String &r_fragment) const;
636
637
String property_name_encode() const;
638
639
// node functions
640
static String get_invalid_node_name_characters(bool p_allow_internal = false);
641
String validate_node_name() const;
642
String validate_ascii_identifier() const;
643
String validate_unicode_identifier() const;
644
String validate_filename() const;
645
646
bool is_valid_ascii_identifier() const;
647
bool is_valid_unicode_identifier() const;
648
bool is_valid_int() const;
649
bool is_valid_float() const;
650
bool is_valid_hex_number(bool p_with_prefix) const;
651
bool is_valid_html_color() const;
652
bool is_valid_ip_address() const;
653
bool is_valid_filename() const;
654
655
// Use `is_valid_ascii_identifier()` instead. Kept for compatibility.
656
bool is_valid_identifier() const { return is_valid_ascii_identifier(); }
657
658
/**
659
* The constructors must not depend on other overloads
660
*/
661
662
_FORCE_INLINE_ String() {}
663
_FORCE_INLINE_ String(const String &p_str) = default;
664
_FORCE_INLINE_ String(String &&p_str) = default;
665
#ifdef SIZE_EXTRA
666
_NO_INLINE_ ~String() {}
667
#endif
668
_FORCE_INLINE_ void operator=(const String &p_str) { _cowdata = p_str._cowdata; }
669
_FORCE_INLINE_ void operator=(String &&p_str) { _cowdata = std::move(p_str._cowdata); }
670
671
Vector<uint8_t> to_ascii_buffer() const;
672
Vector<uint8_t> to_utf8_buffer() const;
673
Vector<uint8_t> to_utf16_buffer() const;
674
Vector<uint8_t> to_utf32_buffer() const;
675
Vector<uint8_t> to_wchar_buffer() const;
676
Vector<uint8_t> to_multibyte_char_buffer(const String &p_encoding = String()) const;
677
678
// Constructors for NULL terminated C strings.
679
String(const char *p_cstr) {
680
append_latin1(p_cstr);
681
}
682
String(const wchar_t *p_cstr) {
683
append_wstring(p_cstr);
684
}
685
String(const char32_t *p_cstr) {
686
append_utf32(p_cstr);
687
}
688
689
// Copy assignment for NULL terminated C strings.
690
void operator=(const char *p_cstr) {
691
clear();
692
append_latin1(p_cstr);
693
}
694
void operator=(const wchar_t *p_cstr) {
695
clear();
696
append_wstring(p_cstr);
697
}
698
void operator=(const char32_t *p_cstr) {
699
clear();
700
append_utf32(p_cstr);
701
}
702
};
703
704
// Zero-constructing String initializes _cowdata.ptr() to nullptr and thus empty.
705
template <>
706
struct is_zero_constructible<String> : std::true_type {};
707
708
bool operator==(const char *p_chr, const String &p_str);
709
bool operator==(const wchar_t *p_chr, const String &p_str);
710
bool operator!=(const char *p_chr, const String &p_str);
711
bool operator!=(const wchar_t *p_chr, const String &p_str);
712
713
String operator+(const char *p_chr, const String &p_str);
714
String operator+(const wchar_t *p_chr, const String &p_str);
715
String operator+(char32_t p_chr, const String &p_str);
716
717
String itos(int64_t p_val);
718
String uitos(uint64_t p_val);
719
String rtos(double p_val);
720
String rtoss(double p_val); //scientific version
721
722
struct NoCaseComparator {
723
bool operator()(const String &p_a, const String &p_b) const {
724
return p_a.nocasecmp_to(p_b) < 0;
725
}
726
};
727
728
struct NaturalNoCaseComparator {
729
bool operator()(const String &p_a, const String &p_b) const {
730
return p_a.naturalnocasecmp_to(p_b) < 0;
731
}
732
};
733
734
struct FileNoCaseComparator {
735
bool operator()(const String &p_a, const String &p_b) const {
736
return p_a.filenocasecmp_to(p_b) < 0;
737
}
738
};
739
740
/* end of namespace */
741
742
// Tool translate (TTR and variants) for the editor UI,
743
// and doc translate for the class reference (DTR).
744
#ifdef TOOLS_ENABLED
745
// Gets parsed.
746
String TTR(const String &p_text, const String &p_context = "");
747
String TTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context = "");
748
String DTR(const String &p_text, const String &p_context = "");
749
String DTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context = "");
750
// Use for C strings.
751
#define TTRC(m_value) (m_value)
752
// Use to avoid parsing (for use later with C strings).
753
#define TTRGET(m_value) TTR(m_value)
754
755
#else
756
#define TTRC(m_value) (m_value)
757
#define TTRGET(m_value) (m_value)
758
#endif
759
760
// Use this to mark property names for editor translation.
761
// Often for dynamic properties defined in _get_property_list().
762
// Property names defined directly inside EDITOR_DEF, GLOBAL_DEF, and ADD_PROPERTY macros don't need this.
763
#define PNAME(m_value) (m_value)
764
765
// Similar to PNAME, but to mark groups, i.e. properties with PROPERTY_USAGE_GROUP.
766
// Groups defined directly inside ADD_GROUP macros don't need this.
767
// The arguments are the same as ADD_GROUP. m_prefix is only used for extraction.
768
#define GNAME(m_value, m_prefix) (m_value)
769
770
// Runtime translate for the public node API.
771
String RTR(const String &p_text, const String &p_context = "");
772
String RTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context = "");
773
774
/**
775
* "Extractable TRanslate". Used for strings that can appear inside an exported
776
* project (such as the ones in nodes like `FileDialog`), which are made possible
777
* to add in the POT generator. A translation context can optionally be specified
778
* to disambiguate between identical source strings in translations.
779
* When placeholders are desired, use vformat(ETR("Example: %s"), some_string)`.
780
* If a string mentions a quantity (and may therefore need a dynamic plural form),
781
* use `ETRN()` instead of `ETR()`.
782
*
783
* NOTE: This function is for string extraction only, and will just return the
784
* string it was given. The translation itself should be done internally by nodes
785
* with `atr()` instead.
786
*/
787
_FORCE_INLINE_ String ETR(const String &p_text, const String &p_context = "") {
788
return p_text;
789
}
790
791
/**
792
* "Extractable TRanslate for N items". Used for strings that can appear inside an
793
* exported project (such as the ones in nodes like `FileDialog`), which are made
794
* possible to add in the POT generator. A translation context can optionally be
795
* specified to disambiguate between identical source strings in translations.
796
* Use `ETR()` if the string doesn't need dynamic plural form. When placeholders
797
* are desired, use `vformat(ETRN("%d item", "%d items", some_integer), some_integer)`.
798
* The placeholder must be present in both strings to avoid run-time warnings in `vformat()`.
799
*
800
* NOTE: This function is for string extraction only, and will just return the
801
* string it was given. The translation itself should be done internally by nodes
802
* with `atr()` instead.
803
*/
804
_FORCE_INLINE_ String ETRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context = "") {
805
if (p_n == 1) {
806
return p_text;
807
}
808
return p_text_plural;
809
}
810
811
template <typename... P>
812
_FORCE_INLINE_ Vector<String> sarray(P... p_args) {
813
return Vector<String>({ String(p_args)... });
814
}
815
816