koffi 2.14.0 → 2.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/README.md +1 -1
  3. package/build/koffi/darwin_arm64/koffi.node +0 -0
  4. package/build/koffi/darwin_x64/koffi.node +0 -0
  5. package/build/koffi/freebsd_arm64/koffi.node +0 -0
  6. package/build/koffi/freebsd_ia32/koffi.node +0 -0
  7. package/build/koffi/freebsd_x64/koffi.node +0 -0
  8. package/build/koffi/linux_arm64/koffi.node +0 -0
  9. package/build/koffi/linux_armhf/koffi.node +0 -0
  10. package/build/koffi/linux_ia32/koffi.node +0 -0
  11. package/build/koffi/linux_loong64/koffi.node +0 -0
  12. package/build/koffi/linux_riscv64d/koffi.node +0 -0
  13. package/build/koffi/linux_x64/koffi.node +0 -0
  14. package/build/koffi/musl_arm64/koffi.node +0 -0
  15. package/build/koffi/musl_x64/koffi.node +0 -0
  16. package/build/koffi/openbsd_ia32/koffi.node +0 -0
  17. package/build/koffi/openbsd_x64/koffi.node +0 -0
  18. package/build/koffi/win32_arm64/koffi.node +0 -0
  19. package/build/koffi/win32_ia32/koffi.node +0 -0
  20. package/build/koffi/win32_x64/koffi.node +0 -0
  21. package/doc/pages/index.md +43 -4
  22. package/doc/pages/platforms.md +8 -19
  23. package/doc/pages.ini +0 -7
  24. package/doc/static/perf_windows.png +0 -0
  25. package/index.js +3 -2
  26. package/indirect.js +3 -2
  27. package/package.json +3 -2
  28. package/src/cnoke/src/builder.js +1 -2
  29. package/src/core/base/base.cc +791 -555
  30. package/src/core/base/base.hh +577 -450
  31. package/src/core/base/crc.inc +1 -1
  32. package/src/core/base/crc_gen.py +1 -1
  33. package/src/core/base/unicode.inc +1 -1
  34. package/src/core/base/unicode_gen.py +1 -1
  35. package/src/koffi/src/abi_arm32.cc +24 -24
  36. package/src/koffi/src/abi_arm64.cc +29 -29
  37. package/src/koffi/src/abi_riscv64.cc +27 -27
  38. package/src/koffi/src/abi_x64_sysv.cc +29 -29
  39. package/src/koffi/src/abi_x64_win.cc +20 -20
  40. package/src/koffi/src/abi_x86.cc +26 -26
  41. package/src/koffi/src/call.cc +82 -236
  42. package/src/koffi/src/call.hh +6 -6
  43. package/src/koffi/src/ffi.cc +60 -60
  44. package/src/koffi/src/ffi.hh +9 -9
  45. package/src/koffi/src/parser.cc +2 -2
  46. package/src/koffi/src/parser.hh +1 -1
  47. package/src/koffi/src/trampolines/prototypes.inc +1 -1
  48. package/src/koffi/src/util.cc +43 -43
  49. package/src/koffi/src/util.hh +5 -5
  50. package/src/koffi/src/win32.cc +5 -5
  51. package/src/koffi/src/win32.hh +1 -1
@@ -75,38 +75,38 @@
75
75
  struct sigaction;
76
76
  struct BrotliEncoderStateStruct;
77
77
 
78
- namespace RG {
78
+ namespace K {
79
79
 
80
80
  // ------------------------------------------------------------------------
81
81
  // Config
82
82
  // ------------------------------------------------------------------------
83
83
 
84
84
  #if !defined(NDEBUG)
85
- #define RG_DEBUG
85
+ #define K_DEBUG
86
86
  #endif
87
87
 
88
- #define RG_DEFAULT_ALLOCATOR MallocAllocator
89
- #define RG_BLOCK_ALLOCATOR_DEFAULT_SIZE Kibibytes(4)
88
+ #define K_DEFAULT_ALLOCATOR MallocAllocator
89
+ #define K_BLOCK_ALLOCATOR_DEFAULT_SIZE Kibibytes(4)
90
90
 
91
- #define RG_HEAPARRAY_BASE_CAPACITY 8
92
- #define RG_HEAPARRAY_GROWTH_FACTOR 2.0
91
+ #define K_HEAPARRAY_BASE_CAPACITY 8
92
+ #define K_HEAPARRAY_GROWTH_FACTOR 2.0
93
93
 
94
94
  // Must be a power-of-two
95
- #define RG_HASHTABLE_BASE_CAPACITY 8
96
- #define RG_HASHTABLE_MAX_LOAD_FACTOR 0.5
95
+ #define K_HASHTABLE_BASE_CAPACITY 8
96
+ #define K_HASHTABLE_MAX_LOAD_FACTOR 0.5
97
97
 
98
- #define RG_FMT_STRING_BASE_CAPACITY 256
99
- #define RG_FMT_STRING_PRINT_BUFFER_SIZE 1024
98
+ #define K_FMT_STRING_BASE_CAPACITY 256
99
+ #define K_FMT_STRING_PRINT_BUFFER_SIZE 1024
100
100
 
101
- #define RG_LINE_READER_STEP_SIZE 65536
101
+ #define K_LINE_READER_STEP_SIZE 65536
102
102
 
103
- #define RG_ASYNC_MAX_THREADS 2048
104
- #define RG_ASYNC_MAX_IDLE_TIME 10000
105
- #define RG_ASYNC_MAX_PENDING_TASKS 2048
103
+ #define K_ASYNC_MAX_THREADS 2048
104
+ #define K_ASYNC_MAX_IDLE_TIME 10000
105
+ #define K_ASYNC_MAX_PENDING_TASKS 2048
106
106
 
107
- #define RG_PROGRESS_MAX_NODES 400
108
- #define RG_PROGRESS_USED_NODES 100
109
- #define RG_PROGRESS_TEXT_SIZE 64
107
+ #define K_PROGRESS_MAX_NODES 400
108
+ #define K_PROGRESS_USED_NODES 100
109
+ #define K_PROGRESS_TEXT_SIZE 64
110
110
 
111
111
  // ------------------------------------------------------------------------
112
112
  // Utility
@@ -125,13 +125,13 @@ extern StreamWriter *const StdErr;
125
125
 
126
126
  #if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) || defined(_M_ARM64) || __riscv_xlen == 64 || defined(__loongarch64)
127
127
  typedef int64_t Size;
128
- #define RG_SIZE_MAX INT64_MAX
128
+ #define K_SIZE_MAX INT64_MAX
129
129
  #elif defined(_WIN32) || defined(__APPLE__) || defined(__unix__)
130
130
  typedef int32_t Size;
131
- #define RG_SIZE_MAX INT32_MAX
131
+ #define K_SIZE_MAX INT32_MAX
132
132
  #elif defined(__thumb__) || defined(__arm__) || defined(__wasm32__)
133
133
  typedef int32_t Size;
134
- #define RG_SIZE_MAX INT32_MAX
134
+ #define K_SIZE_MAX INT32_MAX
135
135
  #else
136
136
  #error Machine architecture not supported
137
137
  #endif
@@ -139,7 +139,7 @@ extern StreamWriter *const StdErr;
139
139
  #if defined(_MSC_VER) || __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
140
140
  // Sane platform
141
141
  #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
142
- #define RG_BIG_ENDIAN
142
+ #define K_BIG_ENDIAN
143
143
  #else
144
144
  #error This code base is not designed to support platforms with crazy endianness
145
145
  #endif
@@ -152,16 +152,16 @@ extern StreamWriter *const StdErr;
152
152
  #endif
153
153
  static_assert(sizeof(double) == 8, "This code base is not designed to support single-precision double floats");
154
154
 
155
- #define RG_STRINGIFY_(a) #a
156
- #define RG_STRINGIFY(a) RG_STRINGIFY_(a)
157
- #define RG_CONCAT_(a, b) a ## b
158
- #define RG_CONCAT(a, b) RG_CONCAT_(a, b)
159
- #define RG_UNIQUE_NAME(prefix) RG_CONCAT(prefix, __LINE__)
160
- #define RG_FORCE_EXPAND(x) x
161
- #define RG_IGNORE (void)!
155
+ #define K_STRINGIFY_(a) #a
156
+ #define K_STRINGIFY(a) K_STRINGIFY_(a)
157
+ #define K_CONCAT_(a, b) a ## b
158
+ #define K_CONCAT(a, b) K_CONCAT_(a, b)
159
+ #define K_UNIQUE_NAME(prefix) K_CONCAT(prefix, __LINE__)
160
+ #define K_FORCE_EXPAND(x) x
161
+ #define K_IGNORE (void)!
162
162
 
163
163
  #if defined(__GNUC__) || defined(__clang__)
164
- #define RG_PUSH_NO_WARNINGS \
164
+ #define K_PUSH_NO_WARNINGS \
165
165
  _Pragma("GCC diagnostic push") \
166
166
  _Pragma("GCC diagnostic ignored \"-Wall\"") \
167
167
  _Pragma("GCC diagnostic ignored \"-Wextra\"") \
@@ -173,7 +173,7 @@ static_assert(sizeof(double) == 8, "This code base is not designed to support si
173
173
  _Pragma("GCC diagnostic ignored \"-Wunused-parameter\"") \
174
174
  _Pragma("GCC diagnostic ignored \"-Wzero-as-null-pointer-constant\"") \
175
175
  _Pragma("GCC diagnostic ignored \"-Winvalid-offsetof\"")
176
- #define RG_POP_NO_WARNINGS \
176
+ #define K_POP_NO_WARNINGS \
177
177
  _Pragma("GCC diagnostic pop")
178
178
 
179
179
  #if !defined(SCNd8)
@@ -186,8 +186,8 @@ static_assert(sizeof(double) == 8, "This code base is not designed to support si
186
186
  #define SCNu8 "hhu"
187
187
  #endif
188
188
  #elif defined(_MSC_VER)
189
- #define RG_PUSH_NO_WARNINGS __pragma(warning(push, 0))
190
- #define RG_POP_NO_WARNINGS __pragma(warning(pop))
189
+ #define K_PUSH_NO_WARNINGS __pragma(warning(push, 0))
190
+ #define K_POP_NO_WARNINGS __pragma(warning(pop))
191
191
 
192
192
  #define __restrict__ __restrict
193
193
  #else
@@ -209,73 +209,73 @@ static_assert(sizeof(double) == 8, "This code base is not designed to support si
209
209
  extern "C" void AssertMessage(const char *filename, int line, const char *cond);
210
210
 
211
211
  #if defined(_MSC_VER)
212
- #define RG_DEBUG_BREAK() __debugbreak()
212
+ #define K_DEBUG_BREAK() __debugbreak()
213
213
  #elif defined(__clang__)
214
- #define RG_DEBUG_BREAK() __builtin_debugtrap()
214
+ #define K_DEBUG_BREAK() __builtin_debugtrap()
215
215
  #elif defined(__i386__) || defined(__x86_64__)
216
- #define RG_DEBUG_BREAK() __asm__ __volatile__("int $0x03")
216
+ #define K_DEBUG_BREAK() __asm__ __volatile__("int $0x03")
217
217
  #elif defined(__thumb__)
218
- #define RG_DEBUG_BREAK() __asm__ __volatile__(".inst 0xde01")
218
+ #define K_DEBUG_BREAK() __asm__ __volatile__(".inst 0xde01")
219
219
  #elif defined(__aarch64__)
220
- #define RG_DEBUG_BREAK() __asm__ __volatile__(".inst 0xd4200000")
220
+ #define K_DEBUG_BREAK() __asm__ __volatile__(".inst 0xd4200000")
221
221
  #elif defined(__arm__)
222
- #define RG_DEBUG_BREAK() __asm__ __volatile__(".inst 0xe7f001f0")
222
+ #define K_DEBUG_BREAK() __asm__ __volatile__(".inst 0xe7f001f0")
223
223
  #elif defined(__riscv)
224
- #define RG_DEBUG_BREAK() __asm__ __volatile__("ebreak")
224
+ #define K_DEBUG_BREAK() __asm__ __volatile__("ebreak")
225
225
  #elif defined(__loongarch64)
226
- #define RG_DEBUG_BREAK() __asm__ __volatile__("break 1")
226
+ #define K_DEBUG_BREAK() __asm__ __volatile__("break 1")
227
227
  #endif
228
228
 
229
229
  #if defined(_MSC_VER) || __EXCEPTIONS
230
- #define RG_BAD_ALLOC() \
230
+ #define K_BAD_ALLOC() \
231
231
  do { \
232
232
  throw std::bad_alloc(); \
233
233
  } while (false)
234
234
  #else
235
- #define RG_BAD_ALLOC() \
235
+ #define K_BAD_ALLOC() \
236
236
  do { \
237
237
  PrintLn(StdErr, "Memory allocation failed"); \
238
238
  abort(); \
239
239
  } while (false);
240
240
  #endif
241
241
 
242
- #define RG_CRITICAL(Cond, ...) \
242
+ #define K_CRITICAL(Cond, ...) \
243
243
  do { \
244
244
  if (!(Cond)) [[unlikely]] { \
245
245
  PrintLn(StdErr, __VA_ARGS__); \
246
246
  abort(); \
247
247
  } \
248
248
  } while (false)
249
- #if defined(RG_DEBUG)
250
- #define RG_ASSERT(Cond) \
249
+ #if defined(K_DEBUG)
250
+ #define K_ASSERT(Cond) \
251
251
  do { \
252
252
  if (!(Cond)) [[unlikely]] { \
253
- RG::AssertMessage(__FILE__, __LINE__, RG_STRINGIFY(Cond)); \
254
- RG_DEBUG_BREAK(); \
253
+ K::AssertMessage(__FILE__, __LINE__, K_STRINGIFY(Cond)); \
254
+ K_DEBUG_BREAK(); \
255
255
  abort(); \
256
256
  } \
257
257
  } while (false)
258
258
  #else
259
- #define RG_ASSERT(Cond) \
259
+ #define K_ASSERT(Cond) \
260
260
  do { \
261
261
  (void)sizeof(Cond); \
262
262
  } while (false)
263
263
  #endif
264
264
 
265
- #if defined(RG_DEBUG)
266
- #define RG_UNREACHABLE() \
265
+ #if defined(K_DEBUG)
266
+ #define K_UNREACHABLE() \
267
267
  do { \
268
- RG::AssertMessage(__FILE__, __LINE__, "Reached code marked as UNREACHABLE"); \
269
- RG_DEBUG_BREAK(); \
268
+ K::AssertMessage(__FILE__, __LINE__, "Reached code marked as UNREACHABLE"); \
269
+ K_DEBUG_BREAK(); \
270
270
  abort(); \
271
271
  } while (false)
272
272
  #elif defined(__GNUC__) || defined(__clang__)
273
- #define RG_UNREACHABLE() __builtin_unreachable()
273
+ #define K_UNREACHABLE() __builtin_unreachable()
274
274
  #else
275
- #define RG_UNREACHABLE() __assume(0)
275
+ #define K_UNREACHABLE() __assume(0)
276
276
  #endif
277
277
 
278
- #define RG_DELETE_COPY(Cls) \
278
+ #define K_DELETE_COPY(Cls) \
279
279
  Cls(const Cls&) = delete; \
280
280
  Cls &operator=(const Cls&) = delete;
281
281
 
@@ -289,11 +289,11 @@ constexpr Size Kibibytes(Size len) { return len * 1024; }
289
289
  constexpr Size Megabytes(Size len) { return len * 1000 * 1000; }
290
290
  constexpr Size Kilobytes(Size len) { return len * 1000; }
291
291
 
292
- #define RG_SIZE(Type) ((RG::Size)sizeof(Type))
292
+ #define K_SIZE(Type) ((K::Size)sizeof(Type))
293
293
  template <typename T, unsigned N>
294
294
  char (&ComputeArraySize(T const (&)[N]))[N];
295
- #define RG_BITS(Type) (8 * RG_SIZE(Type))
296
- #define RG_LEN(Array) RG_SIZE(RG::ComputeArraySize(Array))
295
+ #define K_BITS(Type) (8 * K_SIZE(Type))
296
+ #define K_LEN(Array) K_SIZE(K::ComputeArraySize(Array))
297
297
 
298
298
  static constexpr inline uint16_t ReverseBytes(uint16_t u)
299
299
  {
@@ -328,7 +328,7 @@ static constexpr inline int32_t ReverseBytes(int32_t i)
328
328
  static constexpr inline int64_t ReverseBytes(int64_t i)
329
329
  { return (int64_t)ReverseBytes((uint64_t)i); }
330
330
 
331
- #if defined(RG_BIG_ENDIAN)
331
+ #if defined(K_BIG_ENDIAN)
332
332
  template <typename T>
333
333
  constexpr T LittleEndian(T v) { return ReverseBytes(v); }
334
334
  template <typename T>
@@ -478,9 +478,9 @@ constexpr T BigEndian(T v) { return ReverseBytes(v); }
478
478
  #endif
479
479
 
480
480
  #if __cplusplus >= 202002L && (defined(_MSC_VER) || defined(__clang__) || __GNUC__ >= 11)
481
- #define RG_CONSTINIT constinit
481
+ #define K_CONSTINIT constinit
482
482
  #else
483
- #define RG_CONSTINIT const
483
+ #define K_CONSTINIT const
484
484
  #endif
485
485
 
486
486
  static inline Size AlignLen(Size len, Size align)
@@ -507,7 +507,7 @@ static inline T *AlignDown(T *ptr, Size align)
507
507
  // even if length is 0. This is dumb, work around this.
508
508
  static inline void *MemCpy(void *__restrict__ dest, const void *__restrict__ src, Size len)
509
509
  {
510
- RG_ASSERT(len >= 0);
510
+ K_ASSERT(len >= 0);
511
511
 
512
512
  #if defined(__clang__)
513
513
  // LLVM guarantees sane behavior
@@ -521,7 +521,7 @@ static inline void *MemCpy(void *__restrict__ dest, const void *__restrict__ src
521
521
  }
522
522
  static inline void *MemMove(void *dest, const void *src, Size len)
523
523
  {
524
- RG_ASSERT(len >= 0);
524
+ K_ASSERT(len >= 0);
525
525
 
526
526
  #if defined(__clang__)
527
527
  // LLVM guarantees sane behavior
@@ -535,7 +535,7 @@ static inline void *MemMove(void *dest, const void *src, Size len)
535
535
  }
536
536
  static inline void *MemSet(void *dest, int c, Size len)
537
537
  {
538
- RG_ASSERT(len >= 0);
538
+ K_ASSERT(len >= 0);
539
539
 
540
540
  #if defined(__clang__)
541
541
  // LLVM guarantees sane behavior
@@ -556,8 +556,8 @@ void *MemMem(const void *src, Size src_len, const void *needle, Size needle_len)
556
556
 
557
557
  static inline void *MemMem(const void *src, Size src_len, const void *needle, Size needle_len)
558
558
  {
559
- RG_ASSERT(src_len >= 0);
560
- RG_ASSERT(needle_len > 0);
559
+ K_ASSERT(src_len >= 0);
560
+ K_ASSERT(needle_len > 0);
561
561
 
562
562
  void *ptr = memmem(src, (size_t)src_len, needle, (size_t)needle_len);
563
563
  return ptr;
@@ -565,6 +565,9 @@ static inline void *MemMem(const void *src, Size src_len, const void *needle, Si
565
565
 
566
566
  #endif
567
567
 
568
+ // Implemented for translations, but we need it before we get to this part
569
+ const char *T(const char *key);
570
+
568
571
  template <typename T, typename = typename std::enable_if<std::is_enum<T>::value, T>>
569
572
  typename std::underlying_type<T>::type MaskEnum(T value)
570
573
  {
@@ -574,7 +577,7 @@ typename std::underlying_type<T>::type MaskEnum(T value)
574
577
 
575
578
  template <typename Fun>
576
579
  class DeferGuard {
577
- RG_DELETE_COPY(DeferGuard)
580
+ K_DELETE_COPY(DeferGuard)
578
581
 
579
582
  Fun f;
580
583
  bool enabled;
@@ -610,14 +613,35 @@ DeferGuard<Fun> operator+(DeferGuardHelper, Fun &&f)
610
613
  // Write 'DEFER { code };' to do something at the end of the current scope, you
611
614
  // can use DEFER_N(Name) if you need to disable the guard for some reason, and
612
615
  // DEFER_NC(Name, Captures) if you need to capture values.
613
- #define RG_DEFER \
614
- auto RG_UNIQUE_NAME(defer) = RG::DeferGuardHelper() + [&]()
615
- #define RG_DEFER_N(Name) \
616
- auto Name = RG::DeferGuardHelper() + [&]()
617
- #define RG_DEFER_C(...) \
618
- auto RG_UNIQUE_NAME(defer) = RG::DeferGuardHelper() + [&, __VA_ARGS__]()
619
- #define RG_DEFER_NC(Name, ...) \
620
- auto Name = RG::DeferGuardHelper() + [&, __VA_ARGS__]()
616
+ #define K_DEFER \
617
+ auto K_UNIQUE_NAME(defer) = K::DeferGuardHelper() + [&]()
618
+ #define K_DEFER_N(Name) \
619
+ auto Name = K::DeferGuardHelper() + [&]()
620
+ #define K_DEFER_C(...) \
621
+ auto K_UNIQUE_NAME(defer) = K::DeferGuardHelper() + [&, __VA_ARGS__]()
622
+ #define K_DEFER_NC(Name, ...) \
623
+ auto Name = K::DeferGuardHelper() + [&, __VA_ARGS__]()
624
+
625
+ template <typename T>
626
+ class NoDestroy {
627
+ K_DELETE_COPY(NoDestroy);
628
+
629
+ alignas(T) uint8_t data[K_SIZE(T)];
630
+
631
+ public:
632
+ template <class... Args>
633
+ NoDestroy(Args&&... args) { new (data) T(std::forward<Args>(args)...); }
634
+
635
+ ~NoDestroy() = default;
636
+
637
+ const T *Get() const { return (const T *)(data); }
638
+ T *Get() { return (T*)data; }
639
+
640
+ const T &operator*() const { return *Get(); }
641
+ T& operator*() { return *Get(); }
642
+ const T *operator->() const { return Get(); }
643
+ T *operator->() { return Get(); }
644
+ };
621
645
 
622
646
  // Heavily inspired from FunctionRef in LLVM
623
647
  template<typename Fn> class FunctionRef;
@@ -648,24 +672,6 @@ public:
648
672
  bool IsValid() const { return callback; }
649
673
  };
650
674
 
651
- #define RG_INIT_(ClassName) \
652
- class ClassName { \
653
- public: \
654
- ClassName(); \
655
- }; \
656
- static ClassName RG_UNIQUE_NAME(init); \
657
- ClassName::ClassName()
658
- #define RG_INIT(Name) RG_INIT_(RG_CONCAT(RG_UNIQUE_NAME(InitHelper), Name))
659
-
660
- #define RG_EXIT_(ClassName) \
661
- class ClassName { \
662
- public: \
663
- ~ClassName(); \
664
- }; \
665
- static ClassName RG_UNIQUE_NAME(exit); \
666
- ClassName::~ClassName()
667
- #define RG_EXIT(Name) RG_EXIT_(RG_CONCAT(RG_UNIQUE_NAME(ExitHelper), Name))
668
-
669
675
  template <typename T>
670
676
  T MultiCmp()
671
677
  {
@@ -730,19 +736,19 @@ public:
730
736
 
731
737
  Size operator*() const
732
738
  {
733
- RG_ASSERT(offset <= RG_LEN(bitset->data));
739
+ K_ASSERT(offset <= K_LEN(bitset->data));
734
740
 
735
- if (offset == RG_LEN(bitset->data))
741
+ if (offset == K_LEN(bitset->data))
736
742
  return -1;
737
- return offset * RG_SIZE(size_t) * 8 + ctz;
743
+ return offset * K_SIZE(size_t) * 8 + ctz;
738
744
  }
739
745
 
740
746
  Iterator &operator++()
741
747
  {
742
- RG_ASSERT(offset <= RG_LEN(bitset->data));
748
+ K_ASSERT(offset <= K_LEN(bitset->data));
743
749
 
744
750
  while (!bits) {
745
- if (offset == RG_LEN(bitset->data) - 1)
751
+ if (offset == K_LEN(bitset->data) - 1)
746
752
  return *this;
747
753
  bits = bitset->data[++offset];
748
754
  }
@@ -769,14 +775,14 @@ public:
769
775
  typedef Iterator<Bitset> iterator_type;
770
776
 
771
777
  static constexpr Size Bits = N;
772
- size_t data[(N + RG_BITS(size_t) - 1) / RG_BITS(size_t)] = {};
778
+ size_t data[(N + K_BITS(size_t) - 1) / K_BITS(size_t)] = {};
773
779
 
774
780
  constexpr Bitset() = default;
775
781
  constexpr Bitset(std::initializer_list<Size> bits)
776
782
  {
777
783
  for (Size idx: bits) {
778
- Size offset = idx / (RG_SIZE(size_t) * 8);
779
- size_t mask = (size_t)1 << (idx % (RG_SIZE(size_t) * 8));
784
+ Size offset = idx / (K_SIZE(size_t) * 8);
785
+ size_t mask = (size_t)1 << (idx % (K_SIZE(size_t) * 8));
780
786
 
781
787
  data[offset] |= mask;
782
788
  }
@@ -784,22 +790,22 @@ public:
784
790
 
785
791
  void Clear()
786
792
  {
787
- MemSet(data, 0, RG_SIZE(data));
793
+ MemSet(data, 0, K_SIZE(data));
788
794
  }
789
795
 
790
796
  Iterator<Bitset> begin() { return Iterator<Bitset>(this, 0); }
791
797
  Iterator<const Bitset> begin() const { return Iterator<const Bitset>(this, 0); }
792
- Iterator<Bitset> end() { return Iterator<Bitset>(this, RG_LEN(data)); }
793
- Iterator<const Bitset> end() const { return Iterator<const Bitset>(this, RG_LEN(data)); }
798
+ Iterator<Bitset> end() { return Iterator<Bitset>(this, K_LEN(data)); }
799
+ Iterator<const Bitset> end() const { return Iterator<const Bitset>(this, K_LEN(data)); }
794
800
 
795
801
  Size PopCount() const
796
802
  {
797
803
  Size count = 0;
798
804
  for (size_t bits: data) {
799
- #if RG_SIZE_MAX == INT64_MAX
800
- count += RG::PopCount((uint64_t)bits);
805
+ #if K_SIZE_MAX == INT64_MAX
806
+ count += K::PopCount((uint64_t)bits);
801
807
  #else
802
- count += RG::PopCount((uint32_t)bits);
808
+ count += K::PopCount((uint32_t)bits);
803
809
  #endif
804
810
  }
805
811
  return count;
@@ -807,28 +813,28 @@ public:
807
813
 
808
814
  inline bool Test(Size idx) const
809
815
  {
810
- RG_ASSERT(idx >= 0 && idx < N);
816
+ K_ASSERT(idx >= 0 && idx < N);
811
817
 
812
- Size offset = idx / (RG_SIZE(size_t) * 8);
813
- size_t mask = (size_t)1 << (idx % (RG_SIZE(size_t) * 8));
818
+ Size offset = idx / (K_SIZE(size_t) * 8);
819
+ size_t mask = (size_t)1 << (idx % (K_SIZE(size_t) * 8));
814
820
 
815
821
  return data[offset] & mask;
816
822
  }
817
823
  inline void Set(Size idx, bool value = true)
818
824
  {
819
- RG_ASSERT(idx >= 0 && idx < N);
825
+ K_ASSERT(idx >= 0 && idx < N);
820
826
 
821
- Size offset = idx / (RG_SIZE(size_t) * 8);
822
- size_t mask = (size_t)1 << (idx % (RG_SIZE(size_t) * 8));
827
+ Size offset = idx / (K_SIZE(size_t) * 8);
828
+ size_t mask = (size_t)1 << (idx % (K_SIZE(size_t) * 8));
823
829
 
824
830
  data[offset] = ApplyMask(data[offset], mask, value);
825
831
  }
826
832
  inline bool TestAndSet(Size idx, bool value = true)
827
833
  {
828
- RG_ASSERT(idx >= 0 && idx < N);
834
+ K_ASSERT(idx >= 0 && idx < N);
829
835
 
830
- Size offset = idx / (RG_SIZE(size_t) * 8);
831
- size_t mask = (size_t)1 << (idx % (RG_SIZE(size_t) * 8));
836
+ Size offset = idx / (K_SIZE(size_t) * 8);
837
+ size_t mask = (size_t)1 << (idx % (K_SIZE(size_t) * 8));
832
838
 
833
839
  bool ret = data[offset] & mask;
834
840
  data[offset] = ApplyMask(data[offset], mask, value);
@@ -838,7 +844,7 @@ public:
838
844
 
839
845
  Bitset &operator&=(const Bitset &other)
840
846
  {
841
- for (Size i = 0; i < RG_LEN(data); i++) {
847
+ for (Size i = 0; i < K_LEN(data); i++) {
842
848
  data[i] &= other.data[i];
843
849
  }
844
850
  return *this;
@@ -846,7 +852,7 @@ public:
846
852
  Bitset operator&(const Bitset &other)
847
853
  {
848
854
  Bitset ret;
849
- for (Size i = 0; i < RG_LEN(data); i++) {
855
+ for (Size i = 0; i < K_LEN(data); i++) {
850
856
  ret.data[i] = data[i] & other.data[i];
851
857
  }
852
858
  return ret;
@@ -854,7 +860,7 @@ public:
854
860
 
855
861
  Bitset &operator|=(const Bitset &other)
856
862
  {
857
- for (Size i = 0; i < RG_LEN(data); i++) {
863
+ for (Size i = 0; i < K_LEN(data); i++) {
858
864
  data[i] |= other.data[i];
859
865
  }
860
866
  return *this;
@@ -862,7 +868,7 @@ public:
862
868
  Bitset operator|(const Bitset &other)
863
869
  {
864
870
  Bitset ret;
865
- for (Size i = 0; i < RG_LEN(data); i++) {
871
+ for (Size i = 0; i < K_LEN(data); i++) {
866
872
  ret.data[i] = data[i] | other.data[i];
867
873
  }
868
874
  return ret;
@@ -870,7 +876,7 @@ public:
870
876
 
871
877
  Bitset &operator^=(const Bitset &other)
872
878
  {
873
- for (Size i = 0; i < RG_LEN(data); i++) {
879
+ for (Size i = 0; i < K_LEN(data); i++) {
874
880
  data[i] ^= other.data[i];
875
881
  }
876
882
  return *this;
@@ -878,7 +884,7 @@ public:
878
884
  Bitset operator^(const Bitset &other)
879
885
  {
880
886
  Bitset ret;
881
- for (Size i = 0; i < RG_LEN(data); i++) {
887
+ for (Size i = 0; i < K_LEN(data); i++) {
882
888
  ret.data[i] = data[i] ^ other.data[i];
883
889
  }
884
890
  return ret;
@@ -886,7 +892,7 @@ public:
886
892
 
887
893
  Bitset &Flip()
888
894
  {
889
- for (Size i = 0; i < RG_LEN(data); i++) {
895
+ for (Size i = 0; i < K_LEN(data); i++) {
890
896
  data[i] = ~data[i];
891
897
  }
892
898
  return *this;
@@ -894,7 +900,7 @@ public:
894
900
  Bitset operator~()
895
901
  {
896
902
  Bitset ret;
897
- for (Size i = 0; i < RG_LEN(data); i++) {
903
+ for (Size i = 0; i < K_LEN(data); i++) {
898
904
  ret.data[i] = ~data[i];
899
905
  }
900
906
  return ret;
@@ -936,12 +942,12 @@ struct Span {
936
942
 
937
943
  constexpr T &operator[](Size idx)
938
944
  {
939
- RG_ASSERT(idx >= 0 && idx < len);
945
+ K_ASSERT(idx >= 0 && idx < len);
940
946
  return ptr[idx];
941
947
  }
942
948
  constexpr const T &operator[](Size idx) const
943
949
  {
944
- RG_ASSERT(idx >= 0 && idx < len);
950
+ K_ASSERT(idx >= 0 && idx < len);
945
951
  return ptr[idx];
946
952
  }
947
953
 
@@ -963,8 +969,8 @@ struct Span {
963
969
 
964
970
  constexpr Span Take(Size offset, Size sub_len) const
965
971
  {
966
- RG_ASSERT(sub_len >= 0 && sub_len <= len);
967
- RG_ASSERT(offset >= 0 && offset <= len - sub_len);
972
+ K_ASSERT(sub_len >= 0 && sub_len <= len);
973
+ K_ASSERT(offset >= 0 && offset <= len - sub_len);
968
974
 
969
975
  Span<T> sub = { ptr + offset, sub_len };
970
976
  return sub;
@@ -1005,7 +1011,7 @@ struct Span<const char> {
1005
1011
 
1006
1012
  constexpr char operator[](Size idx) const
1007
1013
  {
1008
- RG_ASSERT(idx >= 0 && idx < len);
1014
+ K_ASSERT(idx >= 0 && idx < len);
1009
1015
  return ptr[idx];
1010
1016
  }
1011
1017
 
@@ -1017,8 +1023,8 @@ struct Span<const char> {
1017
1023
 
1018
1024
  constexpr Span Take(Size offset, Size sub_len) const
1019
1025
  {
1020
- RG_ASSERT(sub_len >= 0 && sub_len <= len);
1021
- RG_ASSERT(offset >= 0 && offset <= len - sub_len);
1026
+ K_ASSERT(sub_len >= 0 && sub_len <= len);
1027
+ K_ASSERT(offset >= 0 && offset <= len - sub_len);
1022
1028
 
1023
1029
  Span<const char> sub = { ptr + offset, sub_len };
1024
1030
  return sub;
@@ -1051,14 +1057,14 @@ public:
1051
1057
  Size stride;
1052
1058
 
1053
1059
  Strider() = default;
1054
- constexpr Strider(T *ptr_) : ptr(ptr_), stride(RG_SIZE(T)) {}
1060
+ constexpr Strider(T *ptr_) : ptr(ptr_), stride(K_SIZE(T)) {}
1055
1061
  constexpr Strider(T *ptr_, Size stride_) : ptr(ptr_), stride(stride_) {}
1056
1062
 
1057
1063
  constexpr bool IsValid() const { return ptr; }
1058
1064
 
1059
1065
  constexpr T &operator[](Size idx) const
1060
1066
  {
1061
- RG_ASSERT(idx >= 0);
1067
+ K_ASSERT(idx >= 0);
1062
1068
  return *(T *)((uint8_t *)ptr + (idx * stride));
1063
1069
  }
1064
1070
  };
@@ -1066,7 +1072,7 @@ public:
1066
1072
  template <typename T>
1067
1073
  static constexpr inline Strider<T> MakeStrider(T *ptr)
1068
1074
  {
1069
- return Strider<T>(ptr, RG_SIZE(T));
1075
+ return Strider<T>(ptr, K_SIZE(T));
1070
1076
  }
1071
1077
  template <typename T>
1072
1078
  static constexpr inline Strider<T> MakeStrider(T *ptr, Size stride)
@@ -1076,7 +1082,7 @@ static constexpr inline Strider<T> MakeStrider(T *ptr, Size stride)
1076
1082
  template <typename T, Size N>
1077
1083
  static constexpr inline Strider<T> MakeStrider(T (&arr)[N])
1078
1084
  {
1079
- return Strider<T>(arr, RG_SIZE(T));
1085
+ return Strider<T>(arr, K_SIZE(T));
1080
1086
  }
1081
1087
 
1082
1088
  enum class AllocFlag {
@@ -1085,7 +1091,7 @@ enum class AllocFlag {
1085
1091
  };
1086
1092
 
1087
1093
  class Allocator {
1088
- RG_DELETE_COPY(Allocator)
1094
+ K_DELETE_COPY(Allocator)
1089
1095
 
1090
1096
  public:
1091
1097
  Allocator() = default;
@@ -1101,7 +1107,7 @@ Allocator *GetNullAllocator();
1101
1107
 
1102
1108
  static inline void *AllocateRaw(Allocator *alloc, Size size, unsigned int flags = 0)
1103
1109
  {
1104
- RG_ASSERT(size >= 0);
1110
+ K_ASSERT(size >= 0);
1105
1111
 
1106
1112
  if (!alloc) {
1107
1113
  alloc = GetDefaultAllocator();
@@ -1118,7 +1124,7 @@ T *AllocateOne(Allocator *alloc, unsigned int flags = 0)
1118
1124
  alloc = GetDefaultAllocator();
1119
1125
  }
1120
1126
 
1121
- Size size = RG_SIZE(T);
1127
+ Size size = K_SIZE(T);
1122
1128
 
1123
1129
  T *ptr = (T *)alloc->Allocate(size, flags);
1124
1130
  return ptr;
@@ -1127,13 +1133,13 @@ T *AllocateOne(Allocator *alloc, unsigned int flags = 0)
1127
1133
  template <typename T>
1128
1134
  Span<T> AllocateSpan(Allocator *alloc, Size len, unsigned int flags = 0)
1129
1135
  {
1130
- RG_ASSERT(len >= 0);
1136
+ K_ASSERT(len >= 0);
1131
1137
 
1132
1138
  if (!alloc) {
1133
1139
  alloc = GetDefaultAllocator();
1134
1140
  }
1135
1141
 
1136
- Size size = len * RG_SIZE(T);
1142
+ Size size = len * K_SIZE(T);
1137
1143
 
1138
1144
  T *ptr = (T *)alloc->Allocate(size, flags);
1139
1145
  return MakeSpan(ptr, len);
@@ -1142,7 +1148,7 @@ Span<T> AllocateSpan(Allocator *alloc, Size len, unsigned int flags = 0)
1142
1148
  static inline void *ResizeRaw(Allocator *alloc, void *ptr, Size old_size, Size new_size,
1143
1149
  unsigned int flags = 0)
1144
1150
  {
1145
- RG_ASSERT(new_size >= 0);
1151
+ K_ASSERT(new_size >= 0);
1146
1152
 
1147
1153
  if (!alloc) {
1148
1154
  alloc = GetDefaultAllocator();
@@ -1156,14 +1162,14 @@ template <typename T>
1156
1162
  Span<T> ResizeSpan(Allocator *alloc, Span<T> mem, Size new_len,
1157
1163
  unsigned int flags = 0)
1158
1164
  {
1159
- RG_ASSERT(new_len >= 0);
1165
+ K_ASSERT(new_len >= 0);
1160
1166
 
1161
1167
  if (!alloc) {
1162
1168
  alloc = GetDefaultAllocator();
1163
1169
  }
1164
1170
 
1165
- Size old_size = mem.len * RG_SIZE(T);
1166
- Size new_size = new_len * RG_SIZE(T);
1171
+ Size old_size = mem.len * K_SIZE(T);
1172
+ Size new_size = new_len * K_SIZE(T);
1167
1173
 
1168
1174
  mem.ptr = (T *)alloc->Resize(mem.ptr, old_size, new_size, flags);
1169
1175
  return MakeSpan(mem.ptr, new_len);
@@ -1185,7 +1191,7 @@ void ReleaseOne(Allocator *alloc, T *ptr)
1185
1191
  alloc = GetDefaultAllocator();
1186
1192
  }
1187
1193
 
1188
- alloc->Release((void *)ptr, RG_SIZE(T));
1194
+ alloc->Release((void *)ptr, K_SIZE(T));
1189
1195
  }
1190
1196
 
1191
1197
  template<typename T>
@@ -1195,7 +1201,7 @@ void ReleaseSpan(Allocator *alloc, Span<T> mem)
1195
1201
  alloc = GetDefaultAllocator();
1196
1202
  }
1197
1203
 
1198
- Size size = mem.len * RG_SIZE(T);
1204
+ Size size = mem.len * K_SIZE(T);
1199
1205
 
1200
1206
  alloc->Release((void *)mem.ptr, size);
1201
1207
  }
@@ -1246,10 +1252,10 @@ class BlockAllocator: public Allocator {
1246
1252
  uint8_t *last_alloc = nullptr;
1247
1253
 
1248
1254
  public:
1249
- BlockAllocator(Size block_size = RG_BLOCK_ALLOCATOR_DEFAULT_SIZE)
1255
+ BlockAllocator(Size block_size = K_BLOCK_ALLOCATOR_DEFAULT_SIZE)
1250
1256
  : block_size(block_size)
1251
1257
  {
1252
- RG_ASSERT(block_size > 0);
1258
+ K_ASSERT(block_size > 0);
1253
1259
  }
1254
1260
 
1255
1261
  BlockAllocator(BlockAllocator &&other) { *this = std::move(other); }
@@ -1288,9 +1294,9 @@ public:
1288
1294
  RetainPtr(T *p, void (*delete_func)(std::remove_const_t<T> *))
1289
1295
  : p(p)
1290
1296
  {
1291
- RG_ASSERT(p);
1292
- RG_ASSERT(delete_func);
1293
- RG_ASSERT(!p->delete_func || delete_func == p->delete_func);
1297
+ K_ASSERT(p);
1298
+ K_ASSERT(delete_func);
1299
+ K_ASSERT(!p->delete_func || delete_func == p->delete_func);
1294
1300
 
1295
1301
  p->Ref();
1296
1302
  p->delete_func = delete_func;
@@ -1299,7 +1305,7 @@ public:
1299
1305
  : p(p)
1300
1306
  {
1301
1307
  if (p) {
1302
- RG_ASSERT(p->delete_func);
1308
+ K_ASSERT(p->delete_func);
1303
1309
 
1304
1310
  if (ref) {
1305
1311
  p->Ref();
@@ -1346,7 +1352,7 @@ public:
1346
1352
 
1347
1353
  T &operator*() const
1348
1354
  {
1349
- RG_ASSERT(p);
1355
+ K_ASSERT(p);
1350
1356
  return *p;
1351
1357
  }
1352
1358
  T *operator->() const { return p; }
@@ -1363,7 +1369,7 @@ public:
1363
1369
  bool Unref() const
1364
1370
  {
1365
1371
  int new_count = --refcount;
1366
- RG_ASSERT(new_count >= 0);
1372
+ K_ASSERT(new_count >= 0);
1367
1373
  return new_count;
1368
1374
  }
1369
1375
 
@@ -1545,7 +1551,6 @@ static inline bool StartsWith(Span<const char> str, Span<const char> prefix)
1545
1551
  return false;
1546
1552
  i++;
1547
1553
  }
1548
-
1549
1554
  return (i == prefix.len);
1550
1555
  }
1551
1556
  static inline bool StartsWith(Span<const char> str, const char *prefix)
@@ -1556,9 +1561,18 @@ static inline bool StartsWith(Span<const char> str, const char *prefix)
1556
1561
  return false;
1557
1562
  i++;
1558
1563
  }
1559
-
1560
1564
  return !prefix[i];
1561
1565
  }
1566
+ static inline bool StartsWith(const char *str, Span<const char> prefix)
1567
+ {
1568
+ Size i = 0;
1569
+ while (str[i] && i < prefix.len) {
1570
+ if (str[i] != prefix[i])
1571
+ return false;
1572
+ i++;
1573
+ }
1574
+ return (i == prefix.len);
1575
+ }
1562
1576
  static inline bool StartsWith(const char *str, const char *prefix)
1563
1577
  {
1564
1578
  Size i = 0;
@@ -1567,14 +1581,14 @@ static inline bool StartsWith(const char *str, const char *prefix)
1567
1581
  return false;
1568
1582
  i++;
1569
1583
  }
1570
-
1571
1584
  return !prefix[i];
1572
1585
  }
1573
1586
 
1574
- static inline bool EndsWith(Span<const char> str, const char *suffix)
1587
+ static inline bool EndsWith(Span<const char> str, Span<const char> suffix)
1575
1588
  {
1576
1589
  Size i = str.len - 1;
1577
- Size j = (Size)strlen(suffix) - 1;
1590
+ Size j = suffix.len - 1;
1591
+
1578
1592
  while (i >= 0 && j >= 0) {
1579
1593
  if (str[i] != suffix[j])
1580
1594
  return false;
@@ -1649,16 +1663,15 @@ static inline Span<const char> SplitStr(Span<const char> str, char split_char, S
1649
1663
  static inline Span<const char> SplitStr(const char *str, char split_char, const char **out_remainder = nullptr)
1650
1664
  { return SplitStr((char *)str, split_char, (char **)out_remainder); }
1651
1665
 
1652
- static inline Span<char> SplitStr(Span<char> str, const char *split_str, Span<char> *out_remainder = nullptr)
1666
+ static inline Span<char> SplitStr(Span<char> str, Span<const char> split, Span<char> *out_remainder = nullptr)
1653
1667
  {
1654
- RG_ASSERT(split_str[0]);
1668
+ K_ASSERT(split.len);
1655
1669
 
1656
1670
  Size part_len = 0;
1657
1671
  while (part_len < str.len) {
1658
- if (StartsWith(str.Take(part_len, str.len - part_len), split_str)) {
1672
+ if (StartsWith(str.Take(part_len, str.len - part_len), split)) {
1659
1673
  if (out_remainder) {
1660
- Size split_len = strlen(split_str);
1661
- *out_remainder = str.Take(part_len + split_len, str.len - part_len - split_len);
1674
+ *out_remainder = str.Take(part_len + split.len, str.len - part_len - split.len);
1662
1675
  }
1663
1676
  return str.Take(0, part_len);
1664
1677
  }
@@ -1670,16 +1683,15 @@ static inline Span<char> SplitStr(Span<char> str, const char *split_str, Span<ch
1670
1683
  }
1671
1684
  return str;
1672
1685
  }
1673
- static inline Span<char> SplitStr(char *str, const char *split_str, char **out_remainder = nullptr)
1686
+ static inline Span<char> SplitStr(char *str, Span<const char> split, char **out_remainder = nullptr)
1674
1687
  {
1675
- RG_ASSERT(split_str[0]);
1688
+ K_ASSERT(split.len);
1676
1689
 
1677
1690
  Size part_len = 0;
1678
1691
  while (str[part_len]) {
1679
- if (StartsWith(str + part_len, split_str)) {
1692
+ if (StartsWith(str + part_len, split)) {
1680
1693
  if (out_remainder) {
1681
- Size split_len = strlen(split_str);
1682
- *out_remainder = str + part_len + split_len;
1694
+ *out_remainder = str + part_len + split.len;
1683
1695
  }
1684
1696
  return MakeSpan(str, part_len);
1685
1697
  }
@@ -1691,10 +1703,10 @@ static inline Span<char> SplitStr(char *str, const char *split_str, char **out_r
1691
1703
  }
1692
1704
  return MakeSpan(str, part_len);
1693
1705
  }
1694
- static inline Span<const char> SplitStr(Span<const char> str, const char *split_str, Span<const char> *out_remainder = nullptr)
1695
- { return SplitStr(MakeSpan((char *)str.ptr, str.len), split_str, (Span<char> *)out_remainder); }
1696
- static inline Span<const char> SplitStr(const char *str, const char *split_str, const char **out_remainder = nullptr)
1697
- { return SplitStr((char *)str, split_str, (char **)out_remainder); }
1706
+ static inline Span<const char> SplitStr(Span<const char> str, Span<const char> split, Span<const char> *out_remainder = nullptr)
1707
+ { return SplitStr(MakeSpan((char *)str.ptr, str.len), split, (Span<char> *)out_remainder); }
1708
+ static inline Span<const char> SplitStr(const char *str, Span<const char> split, const char **out_remainder = nullptr)
1709
+ { return SplitStr((char *)str, split, (char **)out_remainder); }
1698
1710
 
1699
1711
  static inline Span<char> SplitStrLine(Span<char> str, Span<char> *out_remainder = nullptr)
1700
1712
  {
@@ -1890,117 +1902,6 @@ static inline Span<const char> TrimStrRight(Span<const char> str, const char *tr
1890
1902
  static inline Span<const char> TrimStr(Span<const char> str, const char *trim_chars = " \t\r\n")
1891
1903
  { return TrimStr(MakeSpan((char *)str.ptr, str.len), trim_chars); }
1892
1904
 
1893
- static inline int CountUtf8Bytes(char c)
1894
- {
1895
- int ones = CountLeadingZeros((uint32_t)~c << 24);
1896
- return std::min(std::max(ones, 1), 4);
1897
- }
1898
-
1899
- static constexpr inline Size DecodeUtf8(const char *str, int32_t *out_c)
1900
- {
1901
- RG_ASSERT(str[0]);
1902
-
1903
- #define BYTE(Idx) ((uint8_t)str[Idx])
1904
-
1905
- if (BYTE(0) < 0x80) {
1906
- *out_c = BYTE(0);
1907
- return 1;
1908
- } else if (BYTE(0) - 0xC2 > 0xF4 - 0xC2) [[unlikely]] {
1909
- return 0;
1910
- } else if (BYTE(1)) [[likely]] {
1911
- if (BYTE(0) < 0xE0 && (BYTE(1) & 0xC0) == 0x80) {
1912
- *out_c = ((BYTE(0) & 0x1F) << 6) | (BYTE(1) & 0x3F);
1913
- return 2;
1914
- } else if (BYTE(2)) [[likely]] {
1915
- if (BYTE(0) < 0xF0 &&
1916
- (BYTE(1) & 0xC0) == 0x80 &&
1917
- (BYTE(2) & 0xC0) == 0x80) {
1918
- *out_c = ((BYTE(0) & 0xF) << 12) | ((BYTE(1) & 0x3F) << 6) | (BYTE(2) & 0x3F);
1919
- return 3;
1920
- } else if (BYTE(3)) [[likely]] {
1921
- if ((BYTE(1) & 0xC0) == 0x80 &&
1922
- (BYTE(2) & 0xC0) == 0x80 &&
1923
- (BYTE(3) & 0xC0) == 0x80) {
1924
- *out_c = ((BYTE(0) & 0x7) << 18) | ((BYTE(1) & 0x3F) << 12) | ((BYTE(2) & 0x3F) << 6) | (BYTE(3) & 0x3F);
1925
- return 4;
1926
- }
1927
- }
1928
- }
1929
- }
1930
-
1931
- #undef BYTE
1932
-
1933
- return 0;
1934
- }
1935
-
1936
- static constexpr inline Size DecodeUtf8(Span<const char> str, Size offset, int32_t *out_c)
1937
- {
1938
- RG_ASSERT(offset < str.len);
1939
-
1940
- str = str.Take(offset, str.len - offset);
1941
-
1942
- #define BYTE(Idx) ((uint8_t)str[Idx])
1943
-
1944
- if (BYTE(0) < 0x80) {
1945
- *out_c = BYTE(0);
1946
- return 1;
1947
- } else if (BYTE(0) - 0xC2 > 0xF4 - 0xC2) [[unlikely]] {
1948
- return 0;
1949
- } else if (BYTE(0) < 0xE0 && str.len >= 2 && (BYTE(1) & 0xC0) == 0x80) {
1950
- *out_c = ((BYTE(0) & 0x1F) << 6) | (BYTE(1) & 0x3F);
1951
- return 2;
1952
- } else if (BYTE(0) < 0xF0 && str.len >= 3 && (BYTE(1) & 0xC0) == 0x80 &&
1953
- (BYTE(2) & 0xC0) == 0x80) {
1954
- *out_c = ((BYTE(0) & 0xF) << 12) | ((BYTE(1) & 0x3F) << 6) | (BYTE(2) & 0x3F);
1955
- return 3;
1956
- } else if (str.len >= 4 && (BYTE(1) & 0xC0) == 0x80 &&
1957
- (BYTE(2) & 0xC0) == 0x80 &&
1958
- (BYTE(3) & 0xC0) == 0x80) {
1959
- *out_c = ((BYTE(0) & 0x7) << 18) | ((BYTE(1) & 0x3F) << 12) | ((BYTE(2) & 0x3F) << 6) | (BYTE(3) & 0x3F);
1960
- return 4;
1961
- } else {
1962
- return 0;
1963
- }
1964
-
1965
- #undef BYTE
1966
- }
1967
-
1968
- static constexpr inline int32_t DecodeUtf8(const char *str)
1969
- {
1970
- int32_t uc = -1;
1971
- DecodeUtf8(str, &uc);
1972
- return uc;
1973
- }
1974
-
1975
- static inline Size EncodeUtf8(int32_t c, char out_buf[4])
1976
- {
1977
- if (c < 0x80) {
1978
- out_buf[0] = (char)c;
1979
- return 1;
1980
- } else if (c < 0x800) {
1981
- out_buf[0] = (char)(0xC0 | (c >> 6));
1982
- out_buf[1] = (char)(0x80 | (c & 0x3F));
1983
- return 2;
1984
- } else if (c >= 0xD800 && c < 0xE000) {
1985
- return 0;
1986
- } else if (c < 0x10000) {
1987
- out_buf[0] = (char)(0xE0 | (c >> 12));
1988
- out_buf[1] = (char)(0x80 | ((c >> 6) & 0x3F));
1989
- out_buf[2] = (char)(0x80 | (c & 0x3F));
1990
- return 3;
1991
- } else if (c < 0x110000) {
1992
- out_buf[0] = (char)(0xF0 | (c >> 18));
1993
- out_buf[1] = (char)(0x80 | ((c >> 12) & 0x3F));
1994
- out_buf[2] = (char)(0x80 | ((c >> 6) & 0x3F));
1995
- out_buf[3] = (char)(0x80 | (c & 0x3F));
1996
- return 4;
1997
- } else {
1998
- return 0;
1999
- }
2000
- }
2001
-
2002
- bool IsValidUtf8(Span<const char> str);
2003
-
2004
1905
  // ------------------------------------------------------------------------
2005
1906
  // Collections
2006
1907
  // ------------------------------------------------------------------------
@@ -2017,7 +1918,7 @@ public:
2017
1918
  constexpr LocalArray() = default;
2018
1919
  constexpr LocalArray(std::initializer_list<T> l)
2019
1920
  {
2020
- RG_ASSERT(l.size() <= N);
1921
+ K_ASSERT(l.size() <= N);
2021
1922
  for (const T &it: l) {
2022
1923
  data[len++] = it;
2023
1924
  }
@@ -2040,16 +1941,16 @@ public:
2040
1941
  T *end() { return data + len; }
2041
1942
  const T *end() const { return data + len; }
2042
1943
 
2043
- Size Available() const { return RG_LEN(data) - len; }
1944
+ Size Available() const { return K_LEN(data) - len; }
2044
1945
 
2045
1946
  T &operator[](Size idx)
2046
1947
  {
2047
- RG_ASSERT(idx >= 0 && idx < len);
1948
+ K_ASSERT(idx >= 0 && idx < len);
2048
1949
  return data[idx];
2049
1950
  }
2050
1951
  const T &operator[](Size idx) const
2051
1952
  {
2052
- RG_ASSERT(idx >= 0 && idx < len);
1953
+ K_ASSERT(idx >= 0 && idx < len);
2053
1954
  return data[idx];
2054
1955
  }
2055
1956
 
@@ -2069,7 +1970,7 @@ public:
2069
1970
 
2070
1971
  T *AppendDefault(Size count = 1)
2071
1972
  {
2072
- RG_ASSERT(len <= N - count);
1973
+ K_ASSERT(len <= N - count);
2073
1974
 
2074
1975
  T *first = data + len;
2075
1976
  if constexpr(!std::is_trivial<T>::value) {
@@ -2078,7 +1979,7 @@ public:
2078
1979
  len++;
2079
1980
  }
2080
1981
  } else {
2081
- MemSet(first, 0, count * RG_SIZE(T));
1982
+ MemSet(first, 0, count * K_SIZE(T));
2082
1983
  len += count;
2083
1984
  }
2084
1985
 
@@ -2087,7 +1988,7 @@ public:
2087
1988
 
2088
1989
  T *Append(const T &value)
2089
1990
  {
2090
- RG_ASSERT(len < N);
1991
+ K_ASSERT(len < N);
2091
1992
 
2092
1993
  T *it = data + len;
2093
1994
  *it = value;
@@ -2097,7 +1998,7 @@ public:
2097
1998
  }
2098
1999
  T *Append(T &&value)
2099
2000
  {
2100
- RG_ASSERT(len < N);
2001
+ K_ASSERT(len < N);
2101
2002
 
2102
2003
  T *it = data + len;
2103
2004
  *it = std::move(value);
@@ -2107,7 +2008,7 @@ public:
2107
2008
  }
2108
2009
  T *Append(Span<const T> values)
2109
2010
  {
2110
- RG_ASSERT(values.len <= N - len);
2011
+ K_ASSERT(values.len <= N - len);
2111
2012
 
2112
2013
  T *it = data + len;
2113
2014
  for (Size i = 0; i < values.len; i++) {
@@ -2120,7 +2021,7 @@ public:
2120
2021
 
2121
2022
  void RemoveFrom(Size first)
2122
2023
  {
2123
- RG_ASSERT(first >= 0 && first <= len);
2024
+ K_ASSERT(first >= 0 && first <= len);
2124
2025
 
2125
2026
  for (Size i = first; i < len; i++) {
2126
2027
  data[i] = T();
@@ -2129,7 +2030,7 @@ public:
2129
2030
  }
2130
2031
  void RemoveLast(Size count = 1)
2131
2032
  {
2132
- RG_ASSERT(count >= 0 && count <= len);
2033
+ K_ASSERT(count >= 0 && count <= len);
2133
2034
  RemoveFrom(len - count);
2134
2035
  }
2135
2036
 
@@ -2171,8 +2072,8 @@ public:
2171
2072
  HeapArray &operator=(HeapArray &&other)
2172
2073
  {
2173
2074
  Clear();
2174
- MemMove(this, &other, RG_SIZE(other));
2175
- MemSet(&other, 0, RG_SIZE(other));
2075
+ MemMove(this, &other, K_SIZE(other));
2076
+ MemSet(&other, 0, K_SIZE(other));
2176
2077
  return *this;
2177
2078
  }
2178
2079
  HeapArray(const HeapArray &other) { *this = other; }
@@ -2185,7 +2086,7 @@ public:
2185
2086
  ptr[i] = other.ptr[i];
2186
2087
  }
2187
2088
  } else {
2188
- MemCpy(ptr, other.ptr, other.len * RG_SIZE(*ptr));
2089
+ MemCpy(ptr, other.ptr, other.len * K_SIZE(*ptr));
2189
2090
  }
2190
2091
  len = other.len;
2191
2092
  return *this;
@@ -2209,12 +2110,12 @@ public:
2209
2110
 
2210
2111
  T &operator[](Size idx)
2211
2112
  {
2212
- RG_ASSERT(idx >= 0 && idx < len);
2113
+ K_ASSERT(idx >= 0 && idx < len);
2213
2114
  return ptr[idx];
2214
2115
  }
2215
2116
  const T &operator[](Size idx) const
2216
2117
  {
2217
- RG_ASSERT(idx >= 0 && idx < len);
2118
+ K_ASSERT(idx >= 0 && idx < len);
2218
2119
  return ptr[idx];
2219
2120
  }
2220
2121
 
@@ -2234,7 +2135,7 @@ public:
2234
2135
 
2235
2136
  void SetCapacity(Size new_capacity)
2236
2137
  {
2237
- RG_ASSERT(new_capacity >= 0);
2138
+ K_ASSERT(new_capacity >= 0);
2238
2139
 
2239
2140
  if (new_capacity != capacity) {
2240
2141
  if (len > new_capacity) {
@@ -2244,7 +2145,7 @@ public:
2244
2145
  len = new_capacity;
2245
2146
  }
2246
2147
 
2247
- ptr = (T *)ResizeRaw(allocator, ptr, capacity * RG_SIZE(T), new_capacity * RG_SIZE(T));
2148
+ ptr = (T *)ResizeRaw(allocator, ptr, capacity * K_SIZE(T), new_capacity * K_SIZE(T));
2248
2149
  capacity = new_capacity;
2249
2150
  }
2250
2151
  }
@@ -2258,18 +2159,18 @@ public:
2258
2159
 
2259
2160
  T *Grow(Size reserve_capacity = 1)
2260
2161
  {
2261
- RG_ASSERT(capacity >= 0);
2262
- RG_ASSERT(reserve_capacity >= 0);
2263
- RG_ASSERT((size_t)capacity + (size_t)reserve_capacity <= RG_SIZE_MAX);
2162
+ K_ASSERT(capacity >= 0);
2163
+ K_ASSERT(reserve_capacity >= 0);
2164
+ K_ASSERT((size_t)capacity + (size_t)reserve_capacity <= K_SIZE_MAX);
2264
2165
 
2265
2166
  if (reserve_capacity > capacity - len) {
2266
2167
  Size needed = capacity + reserve_capacity;
2267
2168
 
2268
2169
  Size new_capacity;
2269
- if (needed <= RG_HEAPARRAY_BASE_CAPACITY) {
2270
- new_capacity = RG_HEAPARRAY_BASE_CAPACITY;
2170
+ if (needed <= K_HEAPARRAY_BASE_CAPACITY) {
2171
+ new_capacity = K_HEAPARRAY_BASE_CAPACITY;
2271
2172
  } else {
2272
- new_capacity = (Size)((double)(needed - 1) * RG_HEAPARRAY_GROWTH_FACTOR);
2173
+ new_capacity = (Size)((double)(needed - 1) * K_HEAPARRAY_GROWTH_FACTOR);
2273
2174
  }
2274
2175
 
2275
2176
  SetCapacity(new_capacity);
@@ -2291,7 +2192,7 @@ public:
2291
2192
  len++;
2292
2193
  }
2293
2194
  } else {
2294
- MemSet(first, 0, count * RG_SIZE(T));
2195
+ MemSet(first, 0, count * K_SIZE(T));
2295
2196
  len += count;
2296
2197
  }
2297
2198
 
@@ -2336,7 +2237,7 @@ public:
2336
2237
 
2337
2238
  void RemoveFrom(Size first)
2338
2239
  {
2339
- RG_ASSERT(first >= 0 && first <= len);
2240
+ K_ASSERT(first >= 0 && first <= len);
2340
2241
 
2341
2242
  if constexpr(!std::is_trivial<T>::value) {
2342
2243
  for (Size i = first; i < len; i++) {
@@ -2347,7 +2248,7 @@ public:
2347
2248
  }
2348
2249
  void RemoveLast(Size count = 1)
2349
2250
  {
2350
- RG_ASSERT(count >= 0 && count <= len);
2251
+ K_ASSERT(count >= 0 && count <= len);
2351
2252
  RemoveFrom(len - count);
2352
2253
  }
2353
2254
 
@@ -2377,7 +2278,7 @@ public:
2377
2278
 
2378
2279
  template <typename T, Size BucketSize = 64, typename AllocatorType = BlockAllocator>
2379
2280
  class BucketArray {
2380
- RG_DELETE_COPY(BucketArray)
2281
+ K_DELETE_COPY(BucketArray)
2381
2282
 
2382
2283
  public:
2383
2284
  struct Bucket {
@@ -2495,8 +2396,8 @@ public:
2495
2396
  BucketArray &operator=(BucketArray &&other)
2496
2397
  {
2497
2398
  ClearBucketsAndValues();
2498
- MemMove(this, &other, RG_SIZE(other));
2499
- MemSet(&other, 0, RG_SIZE(other));
2399
+ MemMove(this, &other, K_SIZE(other));
2400
+ MemSet(&other, 0, K_SIZE(other));
2500
2401
  return *this;
2501
2402
  }
2502
2403
 
@@ -2529,7 +2430,7 @@ public:
2529
2430
 
2530
2431
  const T &operator[](Size idx) const
2531
2432
  {
2532
- RG_ASSERT(idx >= 0 && idx < count);
2433
+ K_ASSERT(idx >= 0 && idx < count);
2533
2434
 
2534
2435
  idx += offset;
2535
2436
  Size bucket_idx = idx / BucketSize;
@@ -2547,7 +2448,7 @@ public:
2547
2448
  if (bucket_idx >= buckets.len) {
2548
2449
  Bucket *new_bucket = AllocateOne<Bucket>(buckets.allocator);
2549
2450
  new (&new_bucket->allocator) AllocatorType();
2550
- new_bucket->values = (T *)AllocateRaw(&new_bucket->allocator, BucketSize * RG_SIZE(T));
2451
+ new_bucket->values = (T *)AllocateRaw(&new_bucket->allocator, BucketSize * K_SIZE(T));
2551
2452
 
2552
2453
  buckets.Append(new_bucket);
2553
2454
  }
@@ -2572,7 +2473,7 @@ public:
2572
2473
 
2573
2474
  void RemoveFrom(Size from)
2574
2475
  {
2575
- RG_ASSERT(from >= 0 && from <= count);
2476
+ K_ASSERT(from >= 0 && from <= count);
2576
2477
 
2577
2478
  if (from == count)
2578
2479
  return;
@@ -2598,13 +2499,13 @@ public:
2598
2499
  }
2599
2500
  void RemoveLast(Size n = 1)
2600
2501
  {
2601
- RG_ASSERT(n >= 0 && n <= count);
2502
+ K_ASSERT(n >= 0 && n <= count);
2602
2503
  RemoveFrom(count - n);
2603
2504
  }
2604
2505
 
2605
2506
  void RemoveFirst(Size n = 1)
2606
2507
  {
2607
- RG_ASSERT(n >= 0 && n <= count);
2508
+ K_ASSERT(n >= 0 && n <= count);
2608
2509
 
2609
2510
  if (n == count) {
2610
2511
  Clear();
@@ -2623,7 +2524,7 @@ public:
2623
2524
  DeleteBucket(buckets[i]);
2624
2525
  }
2625
2526
  MemMove(&buckets[0], &buckets[end_bucket_idx],
2626
- (buckets.len - end_bucket_idx) * RG_SIZE(Bucket *));
2527
+ (buckets.len - end_bucket_idx) * K_SIZE(Bucket *));
2627
2528
  buckets.RemoveLast(end_bucket_idx);
2628
2529
  }
2629
2530
 
@@ -2650,7 +2551,7 @@ public:
2650
2551
 
2651
2552
  count = (it.bucket_idx * BucketSize) + it.bucket_offset - offset;
2652
2553
 
2653
- RG_ASSERT(it == end());
2554
+ K_ASSERT(it == end());
2654
2555
  }
2655
2556
  void RemoveFrom(const Iterator<const BucketArray<T, BucketSize>> &it) { return RemoveFrom((iterator_type)it); }
2656
2557
 
@@ -2670,7 +2571,7 @@ public:
2670
2571
  DeleteBucket(buckets[i]);
2671
2572
  }
2672
2573
  MemMove(&buckets[0], &buckets[it.bucket_idx],
2673
- (buckets.len - it.bucket_idx) * RG_SIZE(Bucket *));
2574
+ (buckets.len - it.bucket_idx) * K_SIZE(Bucket *));
2674
2575
  buckets.RemoveLast(it.bucket_idx);
2675
2576
  }
2676
2577
 
@@ -2736,18 +2637,18 @@ public:
2736
2637
 
2737
2638
  ValueType &operator*()
2738
2639
  {
2739
- RG_ASSERT(!table->IsEmpty(offset));
2640
+ K_ASSERT(!table->IsEmpty(offset));
2740
2641
  return table->data[offset];
2741
2642
  }
2742
2643
  const ValueType &operator*() const
2743
2644
  {
2744
- RG_ASSERT(!table->IsEmpty(offset));
2645
+ K_ASSERT(!table->IsEmpty(offset));
2745
2646
  return table->data[offset];
2746
2647
  }
2747
2648
 
2748
2649
  Iterator &operator++()
2749
2650
  {
2750
- RG_ASSERT(offset < table->capacity);
2651
+ K_ASSERT(offset < table->capacity);
2751
2652
  while (++offset < table->capacity && table->IsEmpty(offset));
2752
2653
  return *this;
2753
2654
  }
@@ -2793,8 +2694,8 @@ public:
2793
2694
  HashTable &operator=(HashTable &&other)
2794
2695
  {
2795
2696
  Clear();
2796
- MemMove(this, &other, RG_SIZE(other));
2797
- MemSet(&other, 0, RG_SIZE(other));
2697
+ MemMove(this, &other, K_SIZE(other));
2698
+ MemSet(&other, 0, K_SIZE(other));
2798
2699
  return *this;
2799
2700
  }
2800
2701
  HashTable(const HashTable &other) { *this = other; }
@@ -2829,7 +2730,7 @@ public:
2829
2730
 
2830
2731
  count = 0;
2831
2732
  if (used) {
2832
- size_t len = (size_t)(capacity + (RG_SIZE(size_t) * 8) - 1) / RG_SIZE(size_t);
2733
+ size_t len = (size_t)(capacity + (K_SIZE(size_t) * 8) - 1) / K_SIZE(size_t);
2833
2734
  MemSet(used, 0, len);
2834
2735
  }
2835
2736
  }
@@ -2923,7 +2824,7 @@ public:
2923
2824
  return;
2924
2825
 
2925
2826
  Size clear_idx = it - data;
2926
- RG_ASSERT(!IsEmpty(clear_idx));
2827
+ K_ASSERT(!IsEmpty(clear_idx));
2927
2828
 
2928
2829
  it->~ValueType();
2929
2830
  count--;
@@ -2943,7 +2844,7 @@ public:
2943
2844
 
2944
2845
  MarkUsed(clear_idx);
2945
2846
  MarkEmpty(idx);
2946
- MemMove(&data[clear_idx], &data[idx], RG_SIZE(*data));
2847
+ MemMove(&data[clear_idx], &data[idx], K_SIZE(*data));
2947
2848
 
2948
2849
  clear_idx = idx;
2949
2850
  }
@@ -2958,9 +2859,9 @@ public:
2958
2859
  if (count) {
2959
2860
  Size new_capacity = (Size)1 << (64 - CountLeadingZeros((uint64_t)count));
2960
2861
 
2961
- if (new_capacity < RG_HASHTABLE_BASE_CAPACITY) {
2962
- new_capacity = RG_HASHTABLE_BASE_CAPACITY;
2963
- } else if (count > (double)new_capacity * RG_HASHTABLE_MAX_LOAD_FACTOR) {
2862
+ if (new_capacity < K_HASHTABLE_BASE_CAPACITY) {
2863
+ new_capacity = K_HASHTABLE_BASE_CAPACITY;
2864
+ } else if (count > (double)new_capacity * K_HASHTABLE_MAX_LOAD_FACTOR) {
2964
2865
  new_capacity *= 2;
2965
2866
  }
2966
2867
 
@@ -3004,7 +2905,7 @@ private:
3004
2905
  Size idx = HashToIndex(hash);
3005
2906
  ValueType *it = Find(&idx, key);
3006
2907
  if (!it) {
3007
- if (count >= (Size)((double)capacity * RG_HASHTABLE_MAX_LOAD_FACTOR)) {
2908
+ if (count >= (Size)((double)capacity * K_HASHTABLE_MAX_LOAD_FACTOR)) {
3008
2909
  Rehash(capacity << 1);
3009
2910
  idx = HashToIndex(hash);
3010
2911
  while (!IsEmpty(idx)) {
@@ -3021,7 +2922,7 @@ private:
3021
2922
  return it;
3022
2923
  }
3023
2924
  } else {
3024
- Rehash(RG_HASHTABLE_BASE_CAPACITY);
2925
+ Rehash(K_HASHTABLE_BASE_CAPACITY);
3025
2926
 
3026
2927
  Size idx = HashToIndex(hash);
3027
2928
  count++;
@@ -3036,7 +2937,7 @@ private:
3036
2937
  {
3037
2938
  if (new_capacity == capacity)
3038
2939
  return;
3039
- RG_ASSERT(count <= new_capacity);
2940
+ K_ASSERT(count <= new_capacity);
3040
2941
 
3041
2942
  size_t *old_used = used;
3042
2943
  ValueType *old_data = data;
@@ -3044,9 +2945,9 @@ private:
3044
2945
 
3045
2946
  if (new_capacity) {
3046
2947
  used = (size_t *)AllocateRaw(allocator,
3047
- (new_capacity + (RG_SIZE(size_t) * 8) - 1) / RG_SIZE(size_t),
2948
+ (new_capacity + (K_SIZE(size_t) * 8) - 1) / K_SIZE(size_t),
3048
2949
  (int)AllocFlag::Zero);
3049
- data = (ValueType *)AllocateRaw(allocator, new_capacity * RG_SIZE(ValueType));
2950
+ data = (ValueType *)AllocateRaw(allocator, new_capacity * K_SIZE(ValueType));
3050
2951
  for (Size i = 0; i < new_capacity; i++) {
3051
2952
  new (&data[i]) ValueType();
3052
2953
  }
@@ -3068,22 +2969,22 @@ private:
3068
2969
  capacity = 0;
3069
2970
  }
3070
2971
 
3071
- ReleaseRaw(allocator, old_used, (old_capacity + (RG_SIZE(size_t) * 8) - 1) / RG_SIZE(size_t));
3072
- ReleaseRaw(allocator, old_data, old_capacity * RG_SIZE(ValueType));
2972
+ ReleaseRaw(allocator, old_used, (old_capacity + (K_SIZE(size_t) * 8) - 1) / K_SIZE(size_t));
2973
+ ReleaseRaw(allocator, old_data, old_capacity * K_SIZE(ValueType));
3073
2974
  }
3074
2975
 
3075
2976
  inline void MarkUsed(Size idx)
3076
2977
  {
3077
- used[idx / (RG_SIZE(size_t) * 8)] |= (1ull << (idx % (RG_SIZE(size_t) * 8)));
2978
+ used[idx / (K_SIZE(size_t) * 8)] |= (1ull << (idx % (K_SIZE(size_t) * 8)));
3078
2979
  }
3079
2980
  inline void MarkEmpty(Size idx)
3080
2981
  {
3081
- used[idx / (RG_SIZE(size_t) * 8)] &= ~(1ull << (idx % (RG_SIZE(size_t) * 8)));
2982
+ used[idx / (K_SIZE(size_t) * 8)] &= ~(1ull << (idx % (K_SIZE(size_t) * 8)));
3082
2983
  }
3083
2984
 
3084
2985
  inline bool IsEmpty(size_t *used, Size idx) const
3085
2986
  {
3086
- bool empty = !(used[idx / (RG_SIZE(size_t) * 8)] & (1ull << (idx % (RG_SIZE(size_t) * 8))));
2987
+ bool empty = !(used[idx / (K_SIZE(size_t) * 8)] & (1ull << (idx % (K_SIZE(size_t) * 8))));
3087
2988
  return empty;
3088
2989
  }
3089
2990
  inline bool IsEmpty(Size idx) const { return IsEmpty(used, idx); }
@@ -3167,7 +3068,7 @@ DEFINE_INTEGER_HASH_TRAITS_32(unsigned int, constexpr);
3167
3068
  #endif
3168
3069
  DEFINE_INTEGER_HASH_TRAITS_64(long long, constexpr);
3169
3070
  DEFINE_INTEGER_HASH_TRAITS_64(unsigned long long, constexpr);
3170
- #if RG_SIZE_MAX == INT64_MAX
3071
+ #if K_SIZE_MAX == INT64_MAX
3171
3072
  DEFINE_INTEGER_HASH_TRAITS_64(void *);
3172
3073
  DEFINE_INTEGER_HASH_TRAITS_64(const void *);
3173
3074
  #else
@@ -3194,7 +3095,7 @@ static constexpr inline uint64_t HashStr(Span<const char> str)
3194
3095
  } :
3195
3096
  #endif
3196
3097
  [](const char *p) {
3197
- #if defined(RG_BIG_ENDIAN)
3098
+ #if defined(K_BIG_ENDIAN)
3198
3099
  uint64_t result = ((uint64_t)p[0] << 56) |
3199
3100
  ((uint64_t)p[1] << 48) |
3200
3101
  ((uint64_t)p[2] << 40) |
@@ -3275,7 +3176,7 @@ public:
3275
3176
  static constexpr bool Test(Span<const char> key1, const char * key2) { return key1 == key2; }
3276
3177
  };
3277
3178
 
3278
- #define RG_HASHTABLE_HANDLER_EX_N(Name, ValueType, KeyType, KeyMember, HashFunc, TestFunc) \
3179
+ #define K_HASHTABLE_HANDLER_EX_N(Name, ValueType, KeyType, KeyMember, HashFunc, TestFunc) \
3279
3180
  class Name { \
3280
3181
  public: \
3281
3182
  static constexpr KeyType GetKey(const ValueType &value) \
@@ -3289,16 +3190,16 @@ public:
3289
3190
  static constexpr bool TestKeys(KeyType key1, TestKey key2) \
3290
3191
  { return TestFunc((key1), (key2)); } \
3291
3192
  }
3292
- #define RG_HASHTABLE_HANDLER_EX(ValueType, KeyType, KeyMember, HashFunc, TestFunc) \
3293
- RG_HASHTABLE_HANDLER_EX_N(HashHandler, ValueType, KeyType, KeyMember, HashFunc, TestFunc)
3294
- #define RG_HASHTABLE_HANDLER(ValueType, KeyMember) \
3295
- RG_HASHTABLE_HANDLER_EX(ValueType, decltype(ValueType::KeyMember), KeyMember, HashTraits<decltype(ValueType::KeyMember)>::Hash, HashTraits<decltype(ValueType::KeyMember)>::Test)
3296
- #define RG_HASHTABLE_HANDLER_N(Name, ValueType, KeyMember) \
3297
- RG_HASHTABLE_HANDLER_EX_N(Name, ValueType, decltype(ValueType::KeyMember), KeyMember, HashTraits<decltype(ValueType::KeyMember)>::Hash, HashTraits<decltype(ValueType::KeyMember)>::Test)
3298
- #define RG_HASHTABLE_HANDLER_T(ValueType, KeyType, KeyMember) \
3299
- RG_HASHTABLE_HANDLER_EX(ValueType, KeyType, KeyMember, HashTraits<KeyType>::Hash, HashTraits<KeyType>::Test)
3300
- #define RG_HASHTABLE_HANDLER_NT(Name, ValueType, KeyType, KeyMember) \
3301
- RG_HASHTABLE_HANDLER_EX_N(Name, ValueType, KeyType, KeyMember, HashTraits<KeyType>::Hash, HashTraits<KeyType>::Test)
3193
+ #define K_HASHTABLE_HANDLER_EX(ValueType, KeyType, KeyMember, HashFunc, TestFunc) \
3194
+ K_HASHTABLE_HANDLER_EX_N(HashHandler, ValueType, KeyType, KeyMember, HashFunc, TestFunc)
3195
+ #define K_HASHTABLE_HANDLER(ValueType, KeyMember) \
3196
+ K_HASHTABLE_HANDLER_EX(ValueType, decltype(ValueType::KeyMember), KeyMember, HashTraits<decltype(ValueType::KeyMember)>::Hash, HashTraits<decltype(ValueType::KeyMember)>::Test)
3197
+ #define K_HASHTABLE_HANDLER_N(Name, ValueType, KeyMember) \
3198
+ K_HASHTABLE_HANDLER_EX_N(Name, ValueType, decltype(ValueType::KeyMember), KeyMember, HashTraits<decltype(ValueType::KeyMember)>::Hash, HashTraits<decltype(ValueType::KeyMember)>::Test)
3199
+ #define K_HASHTABLE_HANDLER_T(ValueType, KeyType, KeyMember) \
3200
+ K_HASHTABLE_HANDLER_EX(ValueType, KeyType, KeyMember, HashTraits<KeyType>::Hash, HashTraits<KeyType>::Test)
3201
+ #define K_HASHTABLE_HANDLER_NT(Name, ValueType, KeyType, KeyMember) \
3202
+ K_HASHTABLE_HANDLER_EX_N(Name, ValueType, KeyType, KeyMember, HashTraits<KeyType>::Hash, HashTraits<KeyType>::Test)
3302
3203
 
3303
3204
  template <typename KeyType, typename ValueType>
3304
3205
  class HashMap {
@@ -3307,7 +3208,7 @@ public:
3307
3208
  KeyType key;
3308
3209
  ValueType value;
3309
3210
 
3310
- RG_HASHTABLE_HANDLER(Bucket, key);
3211
+ K_HASHTABLE_HANDLER(Bucket, key);
3311
3212
  };
3312
3213
 
3313
3214
  HashTable<KeyType, Bucket> table;
@@ -3436,13 +3337,13 @@ public:
3436
3337
  ValueType value;
3437
3338
  };
3438
3339
 
3439
- size_t used[(N + (RG_SIZE(size_t) * 8) - 1) / RG_SIZE(size_t)] = {};
3340
+ size_t used[(N + (K_SIZE(size_t) * 8) - 1) / K_SIZE(size_t)] = {};
3440
3341
  Bucket data[N] = {};
3441
3342
  Size count = 0;
3442
3343
 
3443
3344
  constexpr ConstMap(std::initializer_list<Bucket> l)
3444
3345
  {
3445
- RG_CRITICAL(l.size() <= N, "ConstMap<%1> cannot be store %2 values", N, l.size());
3346
+ K_CRITICAL(l.size() <= N, "ConstMap<%1> cannot be store %2 values", N, l.size());
3446
3347
 
3447
3348
  for (const Bucket &it: l) {
3448
3349
  Bucket *bucket = Insert(it.key);
@@ -3516,11 +3417,11 @@ private:
3516
3417
 
3517
3418
  constexpr void MarkUsed(Size idx)
3518
3419
  {
3519
- used[idx / (RG_SIZE(size_t) * 8)] |= (1ull << (idx % (RG_SIZE(size_t) * 8)));
3420
+ used[idx / (K_SIZE(size_t) * 8)] |= (1ull << (idx % (K_SIZE(size_t) * 8)));
3520
3421
  }
3521
3422
  constexpr bool IsEmpty(Size idx) const
3522
3423
  {
3523
- bool empty = !(used[idx / (RG_SIZE(size_t) * 8)] & (1ull << (idx % (RG_SIZE(size_t) * 8))));
3424
+ bool empty = !(used[idx / (K_SIZE(size_t) * 8)] & (1ull << (idx % (K_SIZE(size_t) * 8))));
3524
3425
  return empty;
3525
3426
  }
3526
3427
 
@@ -3537,7 +3438,7 @@ private:
3537
3438
  union LocalDate {
3538
3439
  int32_t value;
3539
3440
  struct {
3540
- #if defined(RG_BIG_ENDIAN)
3441
+ #if defined(K_BIG_ENDIAN)
3541
3442
  int16_t year;
3542
3443
  int8_t month;
3543
3444
  int8_t day;
@@ -3549,12 +3450,12 @@ union LocalDate {
3549
3450
  } st;
3550
3451
 
3551
3452
  LocalDate() = default;
3552
- #if defined(RG_BIG_ENDIAN)
3453
+ #if defined(K_BIG_ENDIAN)
3553
3454
  LocalDate(int16_t year, int8_t month, int8_t day)
3554
- : st({ year, month, day }) { RG_ASSERT(IsValid()); }
3455
+ : st({ year, month, day }) { K_ASSERT(IsValid()); }
3555
3456
  #else
3556
3457
  LocalDate(int16_t year, int8_t month, int8_t day)
3557
- : st({ day, month, year }) { RG_ASSERT(IsValid()); }
3458
+ : st({ day, month, year }) { K_ASSERT(IsValid()); }
3558
3459
  #endif
3559
3460
 
3560
3461
  static inline bool IsLeapYear(int16_t year)
@@ -3733,7 +3634,7 @@ public:
3733
3634
  template <typename T>
3734
3635
  explicit FmtCustom(const T &obj)
3735
3636
  {
3736
- static_assert(RG_SIZE(*this) <= RG_SIZE(raw));
3637
+ static_assert(K_SIZE(*this) <= K_SIZE(raw));
3737
3638
  new (raw) Concrete<T>(&obj, &FmtTraits<T>::Format);
3738
3639
  }
3739
3640
 
@@ -3840,7 +3741,7 @@ static inline FmtArg FmtOctal(uint64_t u)
3840
3741
  }
3841
3742
  static inline FmtArg FmtHex(uint64_t u, FmtType type = FmtType::BigHex)
3842
3743
  {
3843
- RG_ASSERT(type == FmtType::BigHex || type == FmtType::SmallHex);
3744
+ K_ASSERT(type == FmtType::BigHex || type == FmtType::SmallHex);
3844
3745
 
3845
3746
  FmtArg arg;
3846
3747
  arg.type = type;
@@ -3907,7 +3808,7 @@ static inline FmtArg FmtTimeNice(TimeSpec spec, bool ms = false)
3907
3808
 
3908
3809
  static inline FmtArg FmtRandom(Size len, const char *chars = nullptr)
3909
3810
  {
3910
- RG_ASSERT(len < 256);
3811
+ K_ASSERT(len < 256);
3911
3812
  len = std::min(len, (Size)256);
3912
3813
 
3913
3814
  FmtArg arg;
@@ -3943,7 +3844,7 @@ FmtArg FmtSpan(Span<T> arr, FmtType type, const char *sep = ", ")
3943
3844
  FmtArg arg;
3944
3845
  arg.type = FmtType::Span;
3945
3846
  arg.u.span.type = type;
3946
- arg.u.span.type_len = RG_SIZE(T);
3847
+ arg.u.span.type_len = K_SIZE(T);
3947
3848
  arg.u.span.ptr = (const void *)arr.ptr;
3948
3849
  arg.u.span.len = arr.len;
3949
3850
  arg.u.span.separator = sep;
@@ -3956,6 +3857,12 @@ FmtArg FmtSpan(T (&arr)[N], FmtType type, const char *sep = ", ") { return FmtSp
3956
3857
  template <typename T, Size N>
3957
3858
  FmtArg FmtSpan(T (&arr)[N], const char *sep = ", ") { return FmtSpan(MakeSpan(arr), sep); }
3958
3859
 
3860
+ static inline FmtArg FmtHex(Span<const uint8_t> buf, FmtType type = FmtType::BigHex)
3861
+ {
3862
+ K_ASSERT(type == FmtType::BigHex || type == FmtType::SmallHex);
3863
+ return FmtSpan(buf, type, "").Pad0(-2);
3864
+ }
3865
+
3959
3866
  class FmtUpperAscii {
3960
3867
  Span<const char> str;
3961
3868
 
@@ -4101,7 +4008,7 @@ static inline void Log(LogLevel level, const char *ctx, const char *fmt, Args...
4101
4008
  LogFmt(level, ctx, fmt, fmt_args);
4102
4009
  }
4103
4010
 
4104
- #if defined(RG_DEBUG) && __cplusplus >= 202002L && __has_include(<source_location>)
4011
+ #if defined(K_DEBUG) && __cplusplus >= 202002L && __has_include(<source_location>)
4105
4012
  struct LogContext {
4106
4013
  const char *fmt;
4107
4014
  char str[56] = {};
@@ -4157,7 +4064,7 @@ static inline void Log(LogLevel level, const char *ctx, const char *fmt, Args...
4157
4064
  template <typename... Args>
4158
4065
  static inline void LogError(LogContext ctx, Args... args) { Log(LogLevel::Error, ctx.str, ctx.fmt, args...); }
4159
4066
  #else
4160
- #if defined(RG_DEBUG)
4067
+ #if defined(K_DEBUG)
4161
4068
  template <typename... Args>
4162
4069
  static inline void LogDebug(Args... args) { Log(LogLevel::Debug, "Debug: ", args...); }
4163
4070
  #else
@@ -4167,9 +4074,9 @@ static inline void Log(LogLevel level, const char *ctx, const char *fmt, Args...
4167
4074
  template <typename... Args>
4168
4075
  static inline void LogInfo(Args... args) { Log(LogLevel::Info, nullptr, args...); }
4169
4076
  template <typename... Args>
4170
- static inline void LogWarning(Args... args) { Log(LogLevel::Warning, "Warning: ", args...); }
4077
+ static inline void LogWarning(Args... args) { Log(LogLevel::Warning, T("Warning: "), args...); }
4171
4078
  template <typename... Args>
4172
- static inline void LogError(Args... args) { Log(LogLevel::Error, "Error: ", args...); }
4079
+ static inline void LogError(Args... args) { Log(LogLevel::Error, T("Error: "), args...); }
4173
4080
  #endif
4174
4081
 
4175
4082
  void SetLogHandler(const std::function<LogFunc> &func, bool vt100);
@@ -4202,7 +4109,7 @@ struct ProgressInfo {
4202
4109
  typedef void ProgressFunc(Span<const ProgressInfo> states);
4203
4110
 
4204
4111
  class ProgressHandle {
4205
- char text[RG_PROGRESS_TEXT_SIZE] = {};
4112
+ char text[K_PROGRESS_TEXT_SIZE] = {};
4206
4113
 
4207
4114
  std::atomic<ProgressNode *> node = nullptr;
4208
4115
 
@@ -4222,7 +4129,7 @@ public:
4222
4129
  template<typename... Args>
4223
4130
  void SetFmt(int64_t value, int64_t min, int64_t max, const char *fmt, Args... args)
4224
4131
  {
4225
- char buf[RG_PROGRESS_TEXT_SIZE];
4132
+ char buf[K_PROGRESS_TEXT_SIZE];
4226
4133
  Fmt(buf, fmt, args...);
4227
4134
 
4228
4135
  Set(value, min, max, (const char *)buf);
@@ -4240,7 +4147,7 @@ public:
4240
4147
 
4241
4148
  private:
4242
4149
  ProgressNode *AcquireNode();
4243
- void CopyText(Span<const char> text, char out[RG_PROGRESS_TEXT_SIZE]);
4150
+ void CopyText(Span<const char> text, char out[K_PROGRESS_TEXT_SIZE]);
4244
4151
  };
4245
4152
 
4246
4153
  void SetProgressHandler(const std::function<ProgressFunc> &func);
@@ -4253,15 +4160,15 @@ void DefaultProgressHandler(Span<const ProgressInfo> bars);
4253
4160
  // ------------------------------------------------------------------------
4254
4161
 
4255
4162
  #if defined(_WIN32)
4256
- #define RG_PATH_SEPARATORS "\\/"
4257
- #define RG_PATH_DELIMITER ';'
4258
- #define RG_EXECUTABLE_EXTENSION ".exe"
4259
- #define RG_SHARED_LIBRARY_EXTENSION ".dll"
4163
+ #define K_PATH_SEPARATORS "\\/"
4164
+ #define K_PATH_DELIMITER ';'
4165
+ #define K_EXECUTABLE_EXTENSION ".exe"
4166
+ #define K_SHARED_LIBRARY_EXTENSION ".dll"
4260
4167
  #else
4261
- #define RG_PATH_SEPARATORS "/"
4262
- #define RG_PATH_DELIMITER ':'
4263
- #define RG_EXECUTABLE_EXTENSION ""
4264
- #define RG_SHARED_LIBRARY_EXTENSION ".so"
4168
+ #define K_PATH_SEPARATORS "/"
4169
+ #define K_PATH_DELIMITER ':'
4170
+ #define K_EXECUTABLE_EXTENSION ""
4171
+ #define K_SHARED_LIBRARY_EXTENSION ".so"
4265
4172
  #endif
4266
4173
 
4267
4174
  #if defined(_WIN32)
@@ -4587,18 +4494,40 @@ void WaitDelay(int64_t delay);
4587
4494
 
4588
4495
  #if !defined(__wasi__)
4589
4496
 
4590
- enum class WaitForResult {
4591
- Exit,
4497
+ enum class WaitResult {
4498
+ Ready,
4499
+ Timeout,
4592
4500
  Interrupt,
4593
4501
  Message,
4594
- Timeout
4502
+ Exit,
4503
+ Error
4504
+ };
4505
+
4506
+ #if defined(_WIN32)
4507
+ typedef void * WaitHandle; // HANDLE
4508
+ #else
4509
+ typedef int WaitHandle;
4510
+ #endif
4511
+
4512
+ struct WaitSource {
4513
+ #if defined(_WIN32)
4514
+ // Special-cased on Windows: set to NULL to wait for the Win32 message pump too
4515
+ void *handle; // HANDLE
4516
+ #else
4517
+ int fd;
4518
+ int events;
4519
+ #endif
4520
+
4521
+ int timeout;
4595
4522
  };
4596
4523
 
4597
- // After WaitForInterrupt() has been called once (even with timeout 0), a few
4598
- // signals (such as SIGINT, SIGHUP) and their Windows equivalent will be permanently ignored.
4524
+ // After WaitEvents() has been called once (even with timeout 0), a few signals (such as SIGINT, SIGHUP)
4525
+ // and their Windows equivalent will be permanently ignored.
4599
4526
  // Beware, on Unix platforms, this may not work correctly if not called from the main thread.
4600
- WaitForResult WaitForInterrupt(int64_t timeout = -1);
4601
- void SignalWaitFor();
4527
+ WaitResult WaitEvents(Span<const WaitSource> sources, int64_t timeout, uint64_t *out_ready = nullptr);
4528
+ WaitResult WaitEvents(int64_t timeout);
4529
+
4530
+ void InterruptWait();
4602
4531
 
4603
4532
  #endif
4604
4533
 
@@ -4613,19 +4542,72 @@ bool DropRootIdentity();
4613
4542
  bool NotifySystemd();
4614
4543
  #endif
4615
4544
 
4616
- #define RG_RESTART_EINTR(CallCode, ErrorCond) \
4545
+ #define K_RESTART_EINTR(CallCode, ErrorCond) \
4617
4546
  ([&]() { \
4618
4547
  decltype(CallCode) ret; \
4619
4548
  while ((ret = (CallCode)) ErrorCond && errno == EINTR); \
4620
4549
  return ret; \
4621
4550
  })()
4622
4551
 
4552
+ class InitHelper {
4553
+ public:
4554
+ const char *name;
4555
+ InitHelper *next = nullptr;
4556
+
4557
+ InitHelper(const char *name);
4558
+ virtual void Run() = 0;
4559
+ };
4560
+
4561
+ class FinalizeHelper {
4562
+ public:
4563
+ const char *name;
4564
+ FinalizeHelper *next = nullptr;
4565
+
4566
+ FinalizeHelper(const char *name);
4567
+ virtual void Run() = 0;
4568
+ };
4569
+
4570
+ #define K_INIT_(ClassName, Name) \
4571
+ class ClassName: public InitHelper { \
4572
+ public: \
4573
+ ClassName(): InitHelper(Name) {} \
4574
+ void Run() override; \
4575
+ }; \
4576
+ static ClassName K_UNIQUE_NAME(init); \
4577
+ void ClassName::Run()
4578
+ #define K_INIT(Name) K_INIT_(K_CONCAT(K_UNIQUE_NAME(InitHelper), Name), K_STRINGIFY(Name))
4579
+
4580
+ #define K_FINALIZE_(ClassName, Name) \
4581
+ class ClassName: public FinalizeHelper { \
4582
+ public: \
4583
+ ClassName(): FinalizeHelper(Name) {} \
4584
+ void Run() override; \
4585
+ }; \
4586
+ static ClassName K_UNIQUE_NAME(finalize); \
4587
+ void ClassName::Run()
4588
+ #define K_FINALIZE(Name) K_FINALIZE_(K_CONCAT(K_UNIQUE_NAME(FinalizeHelper), Name), K_STRINGIFY(Name))
4589
+
4590
+ #define K_EXIT_(ClassName) \
4591
+ class ClassName { \
4592
+ public: \
4593
+ ~ClassName(); \
4594
+ }; \
4595
+ static ClassName K_UNIQUE_NAME(exit); \
4596
+ ClassName::~ClassName()
4597
+ #define K_EXIT(Name) K_EXIT_(K_CONCAT(K_UNIQUE_NAME(ExitHelper), Name))
4598
+
4623
4599
  void InitApp();
4600
+ void ExitApp();
4601
+
4624
4602
  int Main(int argc, char **argv);
4625
4603
 
4626
4604
  static inline int RunApp(int argc, char **argv)
4627
4605
  {
4606
+ K_CRITICAL(argc >= 1, "First argument is missing");
4607
+
4628
4608
  InitApp();
4609
+ K_DEFER { ExitApp(); };
4610
+
4629
4611
  return Main(argc, argv);
4630
4612
  }
4631
4613
 
@@ -4661,10 +4643,10 @@ enum class ParseFlag {
4661
4643
  Validate = 1 << 1,
4662
4644
  End = 1 << 2
4663
4645
  };
4664
- #define RG_DEFAULT_PARSE_FLAGS ((int)ParseFlag::Log | (int)ParseFlag::Validate | (int)ParseFlag::End)
4646
+ #define K_DEFAULT_PARSE_FLAGS ((int)ParseFlag::Log | (int)ParseFlag::Validate | (int)ParseFlag::End)
4665
4647
 
4666
4648
  template <typename T>
4667
- bool ParseInt(Span<const char> str, T *out_value, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
4649
+ bool ParseInt(Span<const char> str, T *out_value, unsigned int flags = K_DEFAULT_PARSE_FLAGS,
4668
4650
  Span<const char> *out_remaining = nullptr)
4669
4651
  {
4670
4652
  if (!str.len) [[unlikely]] {
@@ -4723,20 +4705,20 @@ overflow:
4723
4705
  return false;
4724
4706
  }
4725
4707
 
4726
- bool ParseBool(Span<const char> str, bool *out_value, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
4708
+ bool ParseBool(Span<const char> str, bool *out_value, unsigned int flags = K_DEFAULT_PARSE_FLAGS,
4727
4709
  Span<const char> *out_remaining = nullptr);
4728
4710
 
4729
- bool ParseSize(Span<const char> str, int64_t *out_size, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
4711
+ bool ParseSize(Span<const char> str, int64_t *out_size, unsigned int flags = K_DEFAULT_PARSE_FLAGS,
4730
4712
  Span<const char> *out_remaining = nullptr);
4731
- #if RG_SIZE_MAX < INT64_MAX
4713
+ #if K_SIZE_MAX < INT64_MAX
4732
4714
  static inline bool ParseSize(Span<const char> str, Size *out_size,
4733
- unsigned int flags = RG_DEFAULT_PARSE_FLAGS, Span<const char> *out_remaining = nullptr)
4715
+ unsigned int flags = K_DEFAULT_PARSE_FLAGS, Span<const char> *out_remaining = nullptr)
4734
4716
  {
4735
4717
  int64_t size = 0;
4736
4718
  if (!ParseSize(str, &size, flags, out_remaining))
4737
4719
  return false;
4738
4720
 
4739
- if (size > RG_SIZE_MAX) [[unlikely]] {
4721
+ if (size > K_SIZE_MAX) [[unlikely]] {
4740
4722
  if (flags & (int)ParseFlag::Log) {
4741
4723
  LogError("Size value is too high");
4742
4724
  }
@@ -4748,13 +4730,13 @@ static inline bool ParseSize(Span<const char> str, Size *out_size,
4748
4730
  }
4749
4731
  #endif
4750
4732
 
4751
- bool ParseDate(Span<const char> date_str, LocalDate *out_date, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
4733
+ bool ParseDate(Span<const char> date_str, LocalDate *out_date, unsigned int flags = K_DEFAULT_PARSE_FLAGS,
4752
4734
  Span<const char> *out_remaining = nullptr);
4753
4735
 
4754
- bool ParseDuration(Span<const char> str, int64_t *out_duration, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
4736
+ bool ParseDuration(Span<const char> str, int64_t *out_duration, unsigned int flags = K_DEFAULT_PARSE_FLAGS,
4755
4737
  Span<const char> *out_remaining = nullptr);
4756
4738
  static inline bool ParseDuration(Span<const char> str, int *out_duration,
4757
- unsigned int flags = RG_DEFAULT_PARSE_FLAGS, Span<const char> *out_remaining = nullptr)
4739
+ unsigned int flags = K_DEFAULT_PARSE_FLAGS, Span<const char> *out_remaining = nullptr)
4758
4740
  {
4759
4741
  int64_t duration = 0;
4760
4742
  if (!ParseDuration(str, &duration, flags, out_remaining))
@@ -4772,12 +4754,15 @@ static inline bool ParseDuration(Span<const char> str, int *out_duration,
4772
4754
  }
4773
4755
 
4774
4756
  bool ParseVersion(Span<const char> str, int parts, int multiplier, int64_t *out_duration,
4775
- unsigned int flags = RG_DEFAULT_PARSE_FLAGS, Span<const char> *out_remaining = nullptr);
4757
+ unsigned int flags = K_DEFAULT_PARSE_FLAGS, Span<const char> *out_remaining = nullptr);
4776
4758
 
4777
4759
  // ------------------------------------------------------------------------
4778
4760
  // Random
4779
4761
  // ------------------------------------------------------------------------
4780
4762
 
4763
+ void InitChaCha20(uint32_t state[16], const uint8_t key[32], const uint8_t iv[8], const uint8_t counter[8] = nullptr);
4764
+ void RunChaCha20(uint32_t state[16], uint8_t out_buf[64]);
4765
+
4781
4766
  void FillRandomSafe(void *buf, Size len);
4782
4767
  static inline void FillRandomSafe(Span<uint8_t> buf) { FillRandomSafe(buf.ptr, buf.len); }
4783
4768
 
@@ -4788,14 +4773,13 @@ public:
4788
4773
  FastRandom();
4789
4774
  FastRandom(uint64_t seed);
4790
4775
 
4776
+ uint64_t Next();
4777
+
4791
4778
  void Fill(void *buf, Size len);
4792
4779
  void Fill(Span<uint8_t> buf) { Fill(buf.ptr, buf.len); }
4793
4780
 
4794
4781
  int GetInt(int min, int max);
4795
4782
  int64_t GetInt64(int64_t min, int64_t max);
4796
-
4797
- private:
4798
- uint64_t Next();
4799
4783
  };
4800
4784
 
4801
4785
  template <typename T>
@@ -4811,11 +4795,12 @@ public:
4811
4795
  T operator()()
4812
4796
  {
4813
4797
  T value;
4814
- rng.Fill(&value, RG_SIZE(value));
4798
+ rng.Fill(&value, K_SIZE(value));
4815
4799
  return value;
4816
4800
  }
4817
4801
  };
4818
4802
 
4803
+ uint64_t GetRandom();
4819
4804
  int GetRandomInt(int min, int max);
4820
4805
  int64_t GetRandomInt64(int64_t min, int64_t max);
4821
4806
 
@@ -4868,7 +4853,7 @@ void CloseSocket(int fd);
4868
4853
  // ------------------------------------------------------------------------
4869
4854
 
4870
4855
  class Async {
4871
- RG_DELETE_COPY(Async)
4856
+ K_DELETE_COPY(Async)
4872
4857
 
4873
4858
  #if !defined(__wasi__)
4874
4859
  std::atomic_bool success { true };
@@ -4913,8 +4898,12 @@ enum class CompressionSpeed {
4913
4898
  class StreamDecoder;
4914
4899
  class StreamEncoder;
4915
4900
 
4901
+ enum class StreamReaderFlag {
4902
+ LazyFill = 1 << 0
4903
+ };
4904
+
4916
4905
  class StreamReader {
4917
- RG_DELETE_COPY(StreamReader)
4906
+ K_DELETE_COPY(StreamReader)
4918
4907
 
4919
4908
  enum class SourceType {
4920
4909
  Memory,
@@ -4923,6 +4912,7 @@ class StreamReader {
4923
4912
  };
4924
4913
 
4925
4914
  const char *filename = nullptr;
4915
+ bool lazy = false;
4926
4916
  bool error = true;
4927
4917
 
4928
4918
  int64_t read_total = 0;
@@ -4962,29 +4952,30 @@ class StreamReader {
4962
4952
 
4963
4953
  public:
4964
4954
  StreamReader() { Close(true); }
4965
- StreamReader(Span<const uint8_t> buf, const char *filename = nullptr,
4955
+ StreamReader(Span<const uint8_t> buf, const char *filename, unsigned int flags = 0,
4966
4956
  CompressionType compression_type = CompressionType::None)
4967
- : StreamReader() { Open(buf, filename, compression_type); }
4968
- StreamReader(int fd, const char *filename,
4957
+ : StreamReader() { Open(buf, filename, flags, compression_type); }
4958
+ StreamReader(int fd, const char *filename, unsigned int flags = 0,
4969
4959
  CompressionType compression_type = CompressionType::None)
4970
- : StreamReader() { Open(fd, filename, compression_type); }
4971
- StreamReader(const char *filename,
4960
+ : StreamReader() { Open(fd, filename, flags, compression_type); }
4961
+ StreamReader(const char *filename, unsigned int flags = 0,
4972
4962
  CompressionType compression_type = CompressionType::None)
4973
- : StreamReader() { Open(filename, compression_type); }
4974
- StreamReader(const std::function<Size(Span<uint8_t>)> &func, const char *filename = nullptr,
4963
+ : StreamReader() { Open(filename, flags, compression_type); }
4964
+ StreamReader(const std::function<Size(Span<uint8_t>)> &func, const char *filename, unsigned int flags = 0,
4975
4965
  CompressionType compression_type = CompressionType::None)
4976
- : StreamReader() { Open(func, filename, compression_type); }
4966
+ : StreamReader() { Open(func, filename, flags, compression_type); }
4977
4967
  ~StreamReader() { Close(true); }
4978
4968
 
4979
4969
  // Call before Open. Takes ownership and deletes the decoder at the end.
4980
4970
  void SetDecoder(StreamDecoder *decoder);
4981
4971
 
4982
- bool Open(Span<const uint8_t> buf, const char *filename = nullptr,
4972
+ bool Open(Span<const uint8_t> buf, const char *filename, unsigned int flags = 0,
4983
4973
  CompressionType compression_type = CompressionType::None);
4984
- bool Open(int fd, const char *filename,
4974
+ bool Open(int fd, const char *filename, unsigned int flags = 0,
4985
4975
  CompressionType compression_type = CompressionType::None);
4986
- OpenResult Open(const char *filename, CompressionType compression_type = CompressionType::None);
4987
- bool Open(const std::function<Size(Span<uint8_t>)> &func, const char *filename = nullptr,
4976
+ OpenResult Open(const char *filename, unsigned int flags = 0,
4977
+ CompressionType compression_type = CompressionType::None);
4978
+ bool Open(const std::function<Size(Span<uint8_t>)> &func, const char *filename, unsigned int flags = 0,
4988
4979
  CompressionType compression_type = CompressionType::None);
4989
4980
  bool Close() { return Close(false); }
4990
4981
 
@@ -5071,16 +5062,16 @@ public:
5071
5062
  StreamDecompressorHelper(CompressionType type, CreateDecompressorFunc *func);
5072
5063
  };
5073
5064
 
5074
- #define RG_REGISTER_DECOMPRESSOR(Type, Cls) \
5075
- static StreamDecoder *RG_UNIQUE_NAME(CreateDecompressor)(StreamReader *reader, CompressionType type) \
5065
+ #define K_REGISTER_DECOMPRESSOR(Type, Cls) \
5066
+ static StreamDecoder *K_UNIQUE_NAME(CreateDecompressor)(StreamReader *reader, CompressionType type) \
5076
5067
  { \
5077
5068
  StreamDecoder *decompressor = new Cls(reader, type); \
5078
5069
  return decompressor; \
5079
5070
  } \
5080
- static StreamDecompressorHelper RG_UNIQUE_NAME(CreateDecompressorHelper)((Type), RG_UNIQUE_NAME(CreateDecompressor))
5071
+ static StreamDecompressorHelper K_UNIQUE_NAME(CreateDecompressorHelper)((Type), K_UNIQUE_NAME(CreateDecompressor))
5081
5072
 
5082
5073
  class LineReader {
5083
- RG_DELETE_COPY(LineReader)
5074
+ K_DELETE_COPY(LineReader)
5084
5075
 
5085
5076
  HeapArray<char> buf;
5086
5077
  Span<char> view = {};
@@ -5107,14 +5098,14 @@ public:
5107
5098
  };
5108
5099
 
5109
5100
  enum class StreamWriterFlag {
5110
- Exclusive = 1 << 0,
5111
- Atomic = 1 << 1,
5112
- NoBuffer = 1 << 2,
5113
- LineBuffer = 1 << 3
5101
+ Exclusive = 1 << 0, // Only for files
5102
+ Atomic = 1 << 1, // Only for files
5103
+ NoBuffer = 1 << 2, // Only for files and descriptors
5104
+ LineBuffer = 1 << 3 // Only for files and descriptors
5114
5105
  };
5115
5106
 
5116
5107
  class StreamWriter {
5117
- RG_DELETE_COPY(StreamWriter)
5108
+ K_DELETE_COPY(StreamWriter)
5118
5109
 
5119
5110
  enum class DestinationType {
5120
5111
  Memory,
@@ -5167,14 +5158,14 @@ class StreamWriter {
5167
5158
 
5168
5159
  public:
5169
5160
  StreamWriter() { Close(true); }
5170
- StreamWriter(HeapArray<uint8_t> *mem, const char *filename = nullptr,
5161
+ StreamWriter(HeapArray<uint8_t> *mem, const char *filename, unsigned int flags = 0,
5171
5162
  CompressionType compression_type = CompressionType::None,
5172
5163
  CompressionSpeed compression_speed = CompressionSpeed::Default)
5173
- : StreamWriter() { Open(mem, filename, compression_type, compression_speed); }
5174
- StreamWriter(HeapArray<char> *mem, const char *filename = nullptr,
5164
+ : StreamWriter() { Open(mem, filename, flags, compression_type, compression_speed); }
5165
+ StreamWriter(HeapArray<char> *mem, const char *filename, unsigned int flags = 0,
5175
5166
  CompressionType compression_type = CompressionType::None,
5176
5167
  CompressionSpeed compression_speed = CompressionSpeed::Default)
5177
- : StreamWriter() { Open(mem, filename, compression_type, compression_speed); }
5168
+ : StreamWriter() { Open(mem, filename, flags, compression_type, compression_speed); }
5178
5169
  StreamWriter(int fd, const char *filename, unsigned int flags = 0,
5179
5170
  CompressionType compression_type = CompressionType::None,
5180
5171
  CompressionSpeed compression_speed = CompressionSpeed::Default)
@@ -5183,29 +5174,29 @@ public:
5183
5174
  CompressionType compression_type = CompressionType::None,
5184
5175
  CompressionSpeed compression_speed = CompressionSpeed::Default)
5185
5176
  : StreamWriter() { Open(filename, flags, compression_type, compression_speed); }
5186
- StreamWriter(const std::function<bool(Span<const uint8_t>)> &func, const char *filename = nullptr,
5177
+ StreamWriter(const std::function<bool(Span<const uint8_t>)> &func, const char *filename, unsigned int flags = 0,
5187
5178
  CompressionType compression_type = CompressionType::None,
5188
5179
  CompressionSpeed compression_speed = CompressionSpeed::Default)
5189
- : StreamWriter() { Open(func, filename, compression_type, compression_speed); }
5180
+ : StreamWriter() { Open(func, filename, flags, compression_type, compression_speed); }
5190
5181
  ~StreamWriter() { Close(true); }
5191
5182
 
5192
5183
  // Call before Open. Takes ownership and deletes the encoder at the end.
5193
5184
  void SetEncoder(StreamEncoder *encoder);
5194
5185
 
5195
- bool Open(HeapArray<uint8_t> *mem, const char *filename = nullptr,
5186
+ bool Open(HeapArray<uint8_t> *mem, const char *filename, unsigned int flags = 0,
5196
5187
  CompressionType compression_type = CompressionType::None,
5197
5188
  CompressionSpeed compression_speed = CompressionSpeed::Default);
5198
- bool Open(HeapArray<char> *mem, const char *filename = nullptr,
5189
+ bool Open(HeapArray<char> *mem, const char *filename, unsigned int flags = 0,
5199
5190
  CompressionType compression_type = CompressionType::None,
5200
5191
  CompressionSpeed compression_speed = CompressionSpeed::Default)
5201
- { return Open((HeapArray<uint8_t> *)mem, filename, compression_type, compression_speed); }
5192
+ { return Open((HeapArray<uint8_t> *)mem, filename, flags, compression_type, compression_speed); }
5202
5193
  bool Open(int fd, const char *filename, unsigned int flags = 0,
5203
5194
  CompressionType compression_type = CompressionType::None,
5204
5195
  CompressionSpeed compression_speed = CompressionSpeed::Default);
5205
5196
  bool Open(const char *filename, unsigned int flags = 0,
5206
5197
  CompressionType compression_type = CompressionType::None,
5207
5198
  CompressionSpeed compression_speed = CompressionSpeed::Default);
5208
- bool Open(const std::function<bool(Span<const uint8_t>)> &func, const char *filename = nullptr,
5199
+ bool Open(const std::function<bool(Span<const uint8_t>)> &func, const char *filename, unsigned int flags = 0,
5209
5200
  CompressionType compression_type = CompressionType::None,
5210
5201
  CompressionSpeed compression_speed = CompressionSpeed::Default);
5211
5202
  bool Close() { return Close(false); }
@@ -5283,13 +5274,13 @@ public:
5283
5274
  StreamCompressorHelper(CompressionType type, CreateCompressorFunc *func);
5284
5275
  };
5285
5276
 
5286
- #define RG_REGISTER_COMPRESSOR(Type, Cls) \
5287
- static StreamEncoder *RG_UNIQUE_NAME(CreateCompressor)(StreamWriter *writer, CompressionType type, CompressionSpeed speed) \
5277
+ #define K_REGISTER_COMPRESSOR(Type, Cls) \
5278
+ static StreamEncoder *K_UNIQUE_NAME(CreateCompressor)(StreamWriter *writer, CompressionType type, CompressionSpeed speed) \
5288
5279
  { \
5289
5280
  StreamEncoder *compressor = new Cls(writer, type, speed); \
5290
5281
  return compressor; \
5291
5282
  } \
5292
- static StreamCompressorHelper RG_UNIQUE_NAME(CreateCompressorHelper)((Type), RG_UNIQUE_NAME(CreateCompressor))
5283
+ static StreamCompressorHelper K_UNIQUE_NAME(CreateCompressorHelper)((Type), K_UNIQUE_NAME(CreateCompressor))
5293
5284
 
5294
5285
  bool SpliceStream(StreamReader *reader, int64_t max_len, StreamWriter *writer, Span<uint8_t> buf,
5295
5286
  FunctionRef<void(int64_t, int64_t)> progress = [](int64_t, int64_t) {});
@@ -5322,7 +5313,7 @@ struct IniProperty {
5322
5313
  };
5323
5314
 
5324
5315
  class IniParser {
5325
- RG_DELETE_COPY(IniParser)
5316
+ K_DELETE_COPY(IniParser)
5326
5317
 
5327
5318
  HeapArray<char> current_section;
5328
5319
 
@@ -5362,7 +5353,7 @@ struct AssetInfo {
5362
5353
  CompressionType compression_type;
5363
5354
  Span<const uint8_t> data;
5364
5355
 
5365
- RG_HASHTABLE_HANDLER(AssetInfo, name);
5356
+ K_HASHTABLE_HANDLER(AssetInfo, name);
5366
5357
  };
5367
5358
 
5368
5359
  #if defined(FELIX_HOT_ASSETS)
@@ -5415,6 +5406,29 @@ Span<const uint8_t> PatchFile(const AssetInfo &asset, Allocator *alloc,
5415
5406
  Span<const char> PatchFile(Span<const char> data, Allocator *alloc,
5416
5407
  FunctionRef<void(Span<const char> key, StreamWriter *)> func);
5417
5408
 
5409
+ // ------------------------------------------------------------------------
5410
+ // Translations
5411
+ // ------------------------------------------------------------------------
5412
+
5413
+ struct TranslationTable {
5414
+ struct Pair {
5415
+ const char *key;
5416
+ const char *value;
5417
+ };
5418
+
5419
+ const char *language;
5420
+ Span<Pair> messages;
5421
+
5422
+ K_HASHTABLE_HANDLER(TranslationTable, language);
5423
+ };
5424
+
5425
+ extern "C" const Span<const TranslationTable> TranslationTables;
5426
+
5427
+ void InitLocales(Span<const TranslationTable> tables);
5428
+
5429
+ // Resets the localgale to the process default if lang is NULL or is unknown
5430
+ void ChangeThreadLocale(const char *name);
5431
+
5418
5432
  // ------------------------------------------------------------------------
5419
5433
  // Options
5420
5434
  // ------------------------------------------------------------------------
@@ -5437,7 +5451,7 @@ enum class OptionType {
5437
5451
  };
5438
5452
 
5439
5453
  class OptionParser {
5440
- RG_DELETE_COPY(OptionParser)
5454
+ K_DELETE_COPY(OptionParser)
5441
5455
 
5442
5456
  Span<const char *> args;
5443
5457
  OptionMode mode;
@@ -5516,6 +5530,8 @@ bool OptionToEnum(Span<const OptionDesc> options, Span<const char> str, T *out_v
5516
5530
  template <typename T>
5517
5531
  bool OptionToEnumI(Span<const char *const> options, Span<const char> str, T *out_value)
5518
5532
  {
5533
+ static_assert(std::is_enum<T>::value);
5534
+
5519
5535
  for (Size i = 0; i < options.len; i++) {
5520
5536
  const char *opt = options[i];
5521
5537
 
@@ -5531,6 +5547,8 @@ bool OptionToEnumI(Span<const char *const> options, Span<const char> str, T *out
5531
5547
  template <typename T>
5532
5548
  bool OptionToEnumI(Span<const OptionDesc> options, Span<const char> str, T *out_value)
5533
5549
  {
5550
+ static_assert(std::is_enum<T>::value);
5551
+
5534
5552
  for (Size i = 0; i < options.len; i++) {
5535
5553
  const OptionDesc &desc = options[i];
5536
5554
 
@@ -5631,7 +5649,7 @@ class ConsolePrompter {
5631
5649
  #endif
5632
5650
 
5633
5651
  public:
5634
- const char *prompt = ">>> ";
5652
+ const char *prompt = ">>>";
5635
5653
  const char *mask = nullptr;
5636
5654
 
5637
5655
  HeapArray<char> str;
@@ -5667,8 +5685,6 @@ private:
5667
5685
  Vec2<int> GetConsoleSize();
5668
5686
  int32_t ReadChar();
5669
5687
 
5670
- int ComputeWidth(Span<const char> str);
5671
-
5672
5688
  void EnsureNulTermination();
5673
5689
  };
5674
5690
 
@@ -5691,7 +5707,118 @@ bool CanCompressFile(const char *filename);
5691
5707
  // Unicode
5692
5708
  // ------------------------------------------------------------------------
5693
5709
 
5694
- int ComputeCharacterWidth(int32_t uc);
5710
+ static inline int CountUtf8Bytes(char c)
5711
+ {
5712
+ int ones = CountLeadingZeros((uint32_t)~c << 24);
5713
+ return std::min(std::max(ones, 1), 4);
5714
+ }
5715
+
5716
+ static constexpr inline Size DecodeUtf8(const char *str, int32_t *out_c)
5717
+ {
5718
+ K_ASSERT(str[0]);
5719
+
5720
+ #define BYTE(Idx) ((uint8_t)str[Idx])
5721
+
5722
+ if (BYTE(0) < 0x80) {
5723
+ *out_c = BYTE(0);
5724
+ return 1;
5725
+ } else if (BYTE(0) - 0xC2 > 0xF4 - 0xC2) [[unlikely]] {
5726
+ return 0;
5727
+ } else if (BYTE(1)) [[likely]] {
5728
+ if (BYTE(0) < 0xE0 && (BYTE(1) & 0xC0) == 0x80) {
5729
+ *out_c = ((BYTE(0) & 0x1F) << 6) | (BYTE(1) & 0x3F);
5730
+ return 2;
5731
+ } else if (BYTE(2)) [[likely]] {
5732
+ if (BYTE(0) < 0xF0 &&
5733
+ (BYTE(1) & 0xC0) == 0x80 &&
5734
+ (BYTE(2) & 0xC0) == 0x80) {
5735
+ *out_c = ((BYTE(0) & 0xF) << 12) | ((BYTE(1) & 0x3F) << 6) | (BYTE(2) & 0x3F);
5736
+ return 3;
5737
+ } else if (BYTE(3)) [[likely]] {
5738
+ if ((BYTE(1) & 0xC0) == 0x80 &&
5739
+ (BYTE(2) & 0xC0) == 0x80 &&
5740
+ (BYTE(3) & 0xC0) == 0x80) {
5741
+ *out_c = ((BYTE(0) & 0x7) << 18) | ((BYTE(1) & 0x3F) << 12) | ((BYTE(2) & 0x3F) << 6) | (BYTE(3) & 0x3F);
5742
+ return 4;
5743
+ }
5744
+ }
5745
+ }
5746
+ }
5747
+
5748
+ #undef BYTE
5749
+
5750
+ return 0;
5751
+ }
5752
+
5753
+ static constexpr inline Size DecodeUtf8(Span<const char> str, Size offset, int32_t *out_c)
5754
+ {
5755
+ K_ASSERT(offset < str.len);
5756
+
5757
+ str = str.Take(offset, str.len - offset);
5758
+
5759
+ #define BYTE(Idx) ((uint8_t)str[Idx])
5760
+
5761
+ if (BYTE(0) < 0x80) {
5762
+ *out_c = BYTE(0);
5763
+ return 1;
5764
+ } else if (BYTE(0) - 0xC2 > 0xF4 - 0xC2) [[unlikely]] {
5765
+ return 0;
5766
+ } else if (BYTE(0) < 0xE0 && str.len >= 2 && (BYTE(1) & 0xC0) == 0x80) {
5767
+ *out_c = ((BYTE(0) & 0x1F) << 6) | (BYTE(1) & 0x3F);
5768
+ return 2;
5769
+ } else if (BYTE(0) < 0xF0 && str.len >= 3 && (BYTE(1) & 0xC0) == 0x80 &&
5770
+ (BYTE(2) & 0xC0) == 0x80) {
5771
+ *out_c = ((BYTE(0) & 0xF) << 12) | ((BYTE(1) & 0x3F) << 6) | (BYTE(2) & 0x3F);
5772
+ return 3;
5773
+ } else if (str.len >= 4 && (BYTE(1) & 0xC0) == 0x80 &&
5774
+ (BYTE(2) & 0xC0) == 0x80 &&
5775
+ (BYTE(3) & 0xC0) == 0x80) {
5776
+ *out_c = ((BYTE(0) & 0x7) << 18) | ((BYTE(1) & 0x3F) << 12) | ((BYTE(2) & 0x3F) << 6) | (BYTE(3) & 0x3F);
5777
+ return 4;
5778
+ } else {
5779
+ return 0;
5780
+ }
5781
+
5782
+ #undef BYTE
5783
+ }
5784
+
5785
+ static constexpr inline int32_t DecodeUtf8(const char *str)
5786
+ {
5787
+ int32_t uc = -1;
5788
+ DecodeUtf8(str, &uc);
5789
+ return uc;
5790
+ }
5791
+
5792
+ static inline Size EncodeUtf8(int32_t c, char out_buf[4])
5793
+ {
5794
+ if (c < 0x80) {
5795
+ out_buf[0] = (char)c;
5796
+ return 1;
5797
+ } else if (c < 0x800) {
5798
+ out_buf[0] = (char)(0xC0 | (c >> 6));
5799
+ out_buf[1] = (char)(0x80 | (c & 0x3F));
5800
+ return 2;
5801
+ } else if (c >= 0xD800 && c < 0xE000) {
5802
+ return 0;
5803
+ } else if (c < 0x10000) {
5804
+ out_buf[0] = (char)(0xE0 | (c >> 12));
5805
+ out_buf[1] = (char)(0x80 | ((c >> 6) & 0x3F));
5806
+ out_buf[2] = (char)(0x80 | (c & 0x3F));
5807
+ return 3;
5808
+ } else if (c < 0x110000) {
5809
+ out_buf[0] = (char)(0xF0 | (c >> 18));
5810
+ out_buf[1] = (char)(0x80 | ((c >> 12) & 0x3F));
5811
+ out_buf[2] = (char)(0x80 | ((c >> 6) & 0x3F));
5812
+ out_buf[3] = (char)(0x80 | (c & 0x3F));
5813
+ return 4;
5814
+ } else {
5815
+ return 0;
5816
+ }
5817
+ }
5818
+
5819
+ bool IsValidUtf8(Span<const char> str);
5820
+
5821
+ int ComputeUnicodeWidth(Span<const char> str);
5695
5822
 
5696
5823
  bool IsXidStart(int32_t uc);
5697
5824
  bool IsXidContinue(int32_t uc);