ReXGlue SDK
Loading...
Searching...
No Matches
text.h
Go to the documentation of this file.
1
14
15#pragma once
16
17#include <algorithm>
18#include <cstdarg>
19#include <cstddef>
20#include <cstring>
21#include <filesystem>
22#include <format>
23#include <string>
24#include <string.h>
25#include <string_view>
26#include <utility>
27#include <variant>
28#include <vector>
29
30#include <rex/memory/endian.h>
31#include <rex/platform.h>
32#include <rex/types.h>
33
34#if !REX_PLATFORM_WIN32
35#include <strings.h>
36#endif
37
38namespace rex::string {
39
45inline i32 CompareIgnoreCase(const char* string1, const char* string2) {
46#if REX_PLATFORM_WIN32
47 return _stricmp(string1, string2);
48#else
49 return strcasecmp(string1, string2);
50#endif
51}
52
59inline i32 CompareIgnoreCaseN(const char* string1, const char* string2, size_t count) {
60#if REX_PLATFORM_WIN32
61 return _strnicmp(string1, string2, count);
62#else
63 return strncasecmp(string1, string2, count);
64#endif
65}
66
67namespace detail {
68
69template <typename CharT>
70inline constexpr CharT kWhitespaceChars[] = {static_cast<CharT>(' '), static_cast<CharT>('\t'),
71 static_cast<CharT>('\r'), static_cast<CharT>('\n')};
72
73} // namespace detail
74
76template <typename CharT>
77inline constexpr std::basic_string_view<CharT> kWhitespaceOf{detail::kWhitespaceChars<CharT>, 4};
78
80inline constexpr std::string_view kWhitespace = kWhitespaceOf<char>;
81
87template <typename CharT>
88inline std::basic_string_view<CharT> TrimLeft(
89 std::basic_string_view<CharT> sv, std::basic_string_view<CharT> chars = kWhitespaceOf<CharT>) {
90 auto start = sv.find_first_not_of(chars);
91 return start == std::basic_string_view<CharT>::npos ? std::basic_string_view<CharT>{}
92 : sv.substr(start);
93}
94
100template <typename CharT>
101inline std::basic_string_view<CharT> TrimRight(
102 std::basic_string_view<CharT> sv, std::basic_string_view<CharT> chars = kWhitespaceOf<CharT>) {
103 auto end = sv.find_last_not_of(chars);
104 return end == std::basic_string_view<CharT>::npos ? std::basic_string_view<CharT>{}
105 : sv.substr(0, end + 1);
106}
107
113template <typename CharT>
114inline std::basic_string_view<CharT> Trim(
115 std::basic_string_view<CharT> sv, std::basic_string_view<CharT> chars = kWhitespaceOf<CharT>) {
116 return TrimRight(TrimLeft(sv, chars), chars);
117}
118
124inline std::string_view TrimLeft(std::string_view sv, std::string_view chars = kWhitespace) {
125 return TrimLeft<char>(sv, chars);
126}
127
133inline std::string_view TrimRight(std::string_view sv, std::string_view chars = kWhitespace) {
134 return TrimRight<char>(sv, chars);
135}
136
142inline std::string_view Trim(std::string_view sv, std::string_view chars = kWhitespace) {
143 return Trim<char>(sv, chars);
144}
145
151inline std::string TrimString(std::string_view sv, std::string_view chars = kWhitespace) {
152 return std::string(Trim(sv, chars));
153}
154
160inline char* Duplicate(const char* source) {
161#if REX_PLATFORM_WIN32
162 return _strdup(source);
163#else
164 return strdup(source);
165#endif
166}
167
174inline size_t CopyTruncating(char* dest, const std::string_view source, size_t dest_buffer_count) {
175 if (!dest_buffer_count) {
176 return 0;
177 }
178 size_t chars_copied = std::min(source.size(), dest_buffer_count - static_cast<size_t>(1));
179 std::memcpy(dest, source.data(), chars_copied);
180 dest[chars_copied] = '\0';
181 return chars_copied;
182}
183
190inline size_t CopyTruncating(char16_t* dest, const std::u16string_view source,
191 size_t dest_buffer_count) {
192 if (!dest_buffer_count) {
193 return 0;
194 }
195 size_t chars_copied = std::min(source.size(), dest_buffer_count - static_cast<size_t>(1));
196 std::memcpy(dest, source.data(), chars_copied * sizeof(char16_t));
197 dest[chars_copied] = u'\0';
198 return chars_copied;
199}
200
207inline size_t CopyAndSwapTruncating(char16_t* dest, const std::u16string_view source,
208 size_t dest_buffer_count) {
209 if (!dest_buffer_count) {
210 return 0;
211 }
212 size_t chars_copied = std::min(source.size(), dest_buffer_count - static_cast<size_t>(1));
213 const std::u16string_view head = source.substr(0, chars_copied);
214 memory::copy_and_swap(dest, head.data(), head.size());
215 dest[chars_copied] = u'\0';
216 return chars_copied;
217}
218
225inline size_t CopyUnterminated(char* dest, const std::string_view source,
226 size_t dest_buffer_count) {
227 if (!dest_buffer_count) {
228 return 0;
229 }
230 size_t chars_copied = std::min(source.size(), dest_buffer_count);
231 std::memcpy(dest, source.data(), chars_copied);
232 return chars_copied;
233}
234
240REX_API std::string utf8_lower_ascii(const std::string_view view);
241
247REX_API std::string utf8_upper_ascii(const std::string_view view);
248
254REX_API size_t utf8_hash_fnv1a(const std::string_view view);
255
261REX_API size_t utf8_hash_fnv1a_case(const std::string_view view);
262
270REX_API std::vector<std::string_view> utf8_split(const std::string_view haystack,
271 const std::string_view needles,
272 bool remove_empty = false);
273
279REX_API bool utf8_equal_z(const std::string_view left, const std::string_view right);
280
281REX_API bool utf8_equal_case(const std::string_view left, const std::string_view right);
282
288REX_API bool utf8_equal_case_z(const std::string_view left, const std::string_view right);
289
295REX_API std::string_view::size_type utf8_find_any_of(const std::string_view haystack,
296 const std::string_view needles);
297
303REX_API std::string_view::size_type utf8_find_any_of_case(const std::string_view haystack,
304 const std::string_view needles);
305
311REX_API std::string_view::size_type utf8_find_first_of(const std::string_view haystack,
312 const std::string_view needle);
313
319REX_API std::string_view::size_type utf8_find_first_of_case(const std::string_view haystack,
320 const std::string_view needle);
321
327REX_API bool utf8_starts_with(const std::string_view haystack, const std::string_view needle);
328
334REX_API bool utf8_starts_with_case(const std::string_view haystack, const std::string_view needle);
335
341REX_API bool utf8_ends_with(const std::string_view haystack, const std::string_view needle);
342
348REX_API bool utf8_ends_with_case(const std::string_view haystack, const std::string_view needle);
349
356REX_API std::string ToUTF8(const std::u16string_view source);
357
364REX_API std::u16string ToUTF16(const std::string_view source);
365
372REX_API std::wstring ToWideString(const std::string_view source);
373
380REX_API std::string ToUTF8(const std::wstring_view source);
381
389REX_API std::string ShiftJISToUTF8(const std::string_view source);
390
398REX_API std::string UTF8ToShiftJIS(const std::string_view source);
399
405REX_API std::string PathToUTF8(const std::filesystem::path& path);
406
412REX_API std::u16string PathToUTF16(const std::filesystem::path& path);
413
419REX_API std::filesystem::path to_path(const std::string_view source);
420
426REX_API std::filesystem::path to_path(const std::u16string_view source);
427
434REX_API size_t utf8_count(const std::string_view view);
435
438 public:
444 explicit StringBuffer(size_t initial_capacity = 0);
446
448 char* GetBuffer() const { return buffer_; }
449
451 size_t GetLength() const { return length_; }
452
454 void Reset();
455
456 void Append(char c);
457
459 void Append(char c, size_t count);
460
461 void Append(const char* value);
462
463 void Append(const std::string_view value);
464
470 template <typename... Args>
471 void AppendFormat(std::format_string<const Args&...> format, const Args&... args) {
472 Append(std::format(format, args...));
473 }
474
480 void AppendVarargs(const char* format, va_list args);
481
482 void AppendBytes(const u8* buffer, size_t length);
483
484 std::string ToString();
485
487 std::string_view ToStringView() const;
488
494 std::vector<u8> ToBytes() const;
495
496 private:
497 void Grow(size_t additional_length);
498
499 char* buffer_ = nullptr;
500 size_t length_ = 0;
501 size_t buffer_capacity_ = 0;
502};
503
504namespace detail {
505
506struct StringKeyBase {
507 private:
508 std::variant<std::string, std::string_view> value_;
509
510 public:
511 explicit StringKeyBase(const std::string_view value) : value_(value) {}
512 explicit StringKeyBase(std::string value) : value_(std::move(value)) {}
513
514 std::string_view GetView() const {
515 if (const auto* owned = std::get_if<std::string>(&value_)) {
516 return *owned;
517 }
518 const auto* borrowed = std::get_if<std::string_view>(&value_);
519 return borrowed ? *borrowed : std::string_view();
520 }
521};
522
523} // namespace detail
524
526struct StringKey : detail::StringKeyBase {
527 public:
529 explicit StringKey(const std::string_view value) : StringKeyBase(value) {}
530
532 explicit StringKey(std::string value) : StringKeyBase(std::move(value)) {}
533
535 static StringKey Create(const std::string_view value) { return StringKey(std::string(value)); }
536
538 static StringKey Create(std::string value) { return StringKey(std::move(value)); }
539
541 bool operator==(const StringKey& other) const { return other.GetView() == GetView(); }
542
546 size_t hash() const { return rex::string::utf8_hash_fnv1a(GetView()); }
547
548 struct Hash {
549 size_t operator()(const StringKey& t) const { return t.hash(); }
550 };
551};
552
554struct StringKeyIgnoreCase : detail::StringKeyBase {
555 public:
557 explicit StringKeyIgnoreCase(const std::string_view value) : StringKeyBase(value) {}
558
560 explicit StringKeyIgnoreCase(std::string value) : StringKeyBase(std::move(value)) {}
561
563 static StringKeyIgnoreCase Create(const std::string_view value) {
564 return StringKeyIgnoreCase(std::string(value));
565 }
566
568 static StringKeyIgnoreCase Create(std::string value) {
569 return StringKeyIgnoreCase(std::move(value));
570 }
571
573 bool operator==(const StringKeyIgnoreCase& other) const {
574 return rex::string::utf8_equal_case(other.GetView(), GetView());
575 }
576
582 size_t hash() const { return rex::string::utf8_hash_fnv1a_case(GetView()); }
583
584 struct Hash {
585 size_t operator()(const StringKeyIgnoreCase& t) const { return t.hash(); }
586 };
587};
588
589} // namespace rex::string
590
591namespace std {
592template <>
593struct hash<rex::string::StringKey> {
594 std::size_t operator()(const rex::string::StringKey& t) const { return t.hash(); }
595};
596
597template <>
598struct hash<rex::string::StringKeyIgnoreCase> {
599 std::size_t operator()(const rex::string::StringKeyIgnoreCase& t) const { return t.hash(); }
600};
601} // namespace std
void Append(char c, size_t count)
void AppendFormat(std::format_string< const Args &... > format, const Args &... args)
Definition text.h:471
void AppendVarargs(const char *format, va_list args)
StringBuffer(size_t initial_capacity=0)
std::string_view ToStringView() const
std::vector< u8 > ToBytes() const
size_t GetLength() const
Definition text.h:451
char * GetBuffer() const
Definition text.h:448
void copy_and_swap(T *dest, const T *src, size_t count)
Definition endian.h:98
Definition app.h:36
Platform flags, packing macros and export markers.
#define REX_API
Definition platform.h:177
static StringKeyIgnoreCase Create(std::string value)
Definition text.h:568
bool operator==(const StringKeyIgnoreCase &other) const
Definition text.h:573
static StringKeyIgnoreCase Create(const std::string_view value)
Definition text.h:563
StringKeyIgnoreCase(const std::string_view value)
Definition text.h:557
StringKeyIgnoreCase(std::string value)
Definition text.h:560
size_t hash() const
Definition text.h:582
Definition text.h:548
Definition text.h:526
static StringKey Create(std::string value)
Definition text.h:538
static StringKey Create(const std::string_view value)
Definition text.h:535
size_t hash() const
Definition text.h:546
StringKey(const std::string_view value)
Definition text.h:529
StringKey(std::string value)
Definition text.h:532
bool operator==(const StringKey &other) const
Definition text.h:541
bool utf8_equal_case_z(const std::string_view left, const std::string_view right)
size_t utf8_count(const std::string_view view)
size_t CopyTruncating(char *dest, const std::string_view source, size_t dest_buffer_count)
Definition text.h:174
std::string ShiftJISToUTF8(const std::string_view source)
std::string utf8_lower_ascii(const std::string_view view)
std::string ToUTF8(const std::u16string_view source)
std::string PathToUTF8(const std::filesystem::path &path)
constexpr std::basic_string_view< CharT > kWhitespaceOf
Definition text.h:77
std::basic_string_view< CharT > TrimLeft(std::basic_string_view< CharT > sv, std::basic_string_view< CharT > chars=kWhitespaceOf< CharT >)
Definition text.h:88
std::basic_string_view< CharT > Trim(std::basic_string_view< CharT > sv, std::basic_string_view< CharT > chars=kWhitespaceOf< CharT >)
Definition text.h:114
std::filesystem::path to_path(const std::string_view source)
constexpr std::string_view kWhitespace
Definition text.h:80
bool utf8_starts_with_case(const std::string_view haystack, const std::string_view needle)
size_t utf8_hash_fnv1a(const std::string_view view)
std::string_view::size_type utf8_find_any_of(const std::string_view haystack, const std::string_view needles)
bool utf8_starts_with(const std::string_view haystack, const std::string_view needle)
std::string_view::size_type utf8_find_any_of_case(const std::string_view haystack, const std::string_view needles)
i32 CompareIgnoreCase(const char *string1, const char *string2)
Definition text.h:45
std::u16string ToUTF16(const std::string_view source)
std::wstring ToWideString(const std::string_view source)
size_t CopyUnterminated(char *dest, const std::string_view source, size_t dest_buffer_count)
Definition text.h:225
bool utf8_ends_with(const std::string_view haystack, const std::string_view needle)
std::u16string PathToUTF16(const std::filesystem::path &path)
std::string utf8_upper_ascii(const std::string_view view)
size_t utf8_hash_fnv1a_case(const std::string_view view)
std::vector< std::string_view > utf8_split(const std::string_view haystack, const std::string_view needles, bool remove_empty=false)
std::string UTF8ToShiftJIS(const std::string_view source)
bool utf8_ends_with_case(const std::string_view haystack, const std::string_view needle)
char * Duplicate(const char *source)
Definition text.h:160
std::basic_string_view< CharT > TrimRight(std::basic_string_view< CharT > sv, std::basic_string_view< CharT > chars=kWhitespaceOf< CharT >)
Definition text.h:101
size_t CopyAndSwapTruncating(char16_t *dest, const std::u16string_view source, size_t dest_buffer_count)
Definition text.h:207
bool utf8_equal_z(const std::string_view left, const std::string_view right)
std::string_view::size_type utf8_find_first_of(const std::string_view haystack, const std::string_view needle)
std::string TrimString(std::string_view sv, std::string_view chars=kWhitespace)
Definition text.h:151
i32 CompareIgnoreCaseN(const char *string1, const char *string2, size_t count)
Definition text.h:59
std::string_view::size_type utf8_find_first_of_case(const std::string_view haystack, const std::string_view needle)
Integer types, byte order wrappers and size literals.