koffi 2.14.0 → 2.15.0

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 (105) hide show
  1. package/CHANGELOG.md +26 -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/assets.ini +2 -1
  22. package/doc/build.sh +9 -0
  23. package/doc/pages/404.md +17 -0
  24. package/doc/pages/index.md +43 -4
  25. package/doc/pages/misc.md +16 -11
  26. package/doc/pages/platforms.md +8 -19
  27. package/doc/pages.ini +4 -7
  28. package/doc/static/highlight.js +2 -14
  29. package/doc/static/koffi.css +3 -15
  30. package/doc/static/perf_windows.png +0 -0
  31. package/doc/static/print.css +2 -14
  32. package/index.d.ts +29 -24
  33. package/index.js +10 -9
  34. package/indirect.js +10 -9
  35. package/{src/core → lib/native}/base/base.cc +1753 -1089
  36. package/{src/core → lib/native}/base/base.hh +868 -572
  37. package/{src/core → lib/native}/base/crc.inc +3 -21
  38. package/lib/native/base/crc_gen.py +72 -0
  39. package/{src/core → lib/native}/base/mimetypes.inc +2 -20
  40. package/{src/core → lib/native}/base/mimetypes_gen.py +2 -21
  41. package/lib/native/base/tower.cc +821 -0
  42. package/lib/native/base/tower.hh +81 -0
  43. package/{src/core → lib/native}/base/unicode.inc +3 -21
  44. package/{src/core → lib/native}/base/unicode_gen.py +5 -42
  45. package/package.json +3 -2
  46. package/src/cnoke/assets/FindCNoke.cmake +8 -20
  47. package/src/cnoke/assets/win_delay_hook.c +2 -20
  48. package/src/cnoke/cnoke.js +2 -21
  49. package/src/cnoke/src/builder.js +3 -22
  50. package/src/cnoke/src/index.js +2 -20
  51. package/src/cnoke/src/tools.js +2 -20
  52. package/src/koffi/CMakeLists.txt +19 -22
  53. package/src/koffi/cmake/raylib.cmake +5 -22
  54. package/src/koffi/cmake/sqlite3.cmake +2 -20
  55. package/src/koffi/src/abi_arm32.cc +31 -49
  56. package/src/koffi/src/abi_arm32_asm.S +2 -20
  57. package/src/koffi/src/abi_arm64.cc +36 -54
  58. package/src/koffi/src/abi_arm64_asm.S +2 -20
  59. package/src/koffi/src/abi_arm64_asm.asm +2 -20
  60. package/src/koffi/src/abi_loong64.cc +2 -20
  61. package/src/koffi/src/abi_loong64_asm.S +2 -20
  62. package/src/koffi/src/abi_riscv64.cc +34 -52
  63. package/src/koffi/src/abi_riscv64_asm.S +2 -20
  64. package/src/koffi/src/abi_x64_sysv.cc +36 -54
  65. package/src/koffi/src/abi_x64_sysv_asm.S +2 -20
  66. package/src/koffi/src/abi_x64_win.cc +32 -50
  67. package/src/koffi/src/abi_x64_win_asm.asm +2 -20
  68. package/src/koffi/src/abi_x86.cc +33 -51
  69. package/src/koffi/src/abi_x86_asm.S +2 -20
  70. package/src/koffi/src/abi_x86_asm.asm +2 -20
  71. package/src/koffi/src/call.cc +107 -281
  72. package/src/koffi/src/call.hh +9 -27
  73. package/src/koffi/src/errno.inc +2 -20
  74. package/src/koffi/src/ffi.cc +121 -121
  75. package/src/koffi/src/ffi.hh +23 -38
  76. package/src/koffi/src/init.js +2 -20
  77. package/src/koffi/src/parser.cc +15 -29
  78. package/src/koffi/src/parser.hh +4 -22
  79. package/src/koffi/src/trampolines/armasm.inc +0 -21
  80. package/src/koffi/src/trampolines/gnu.inc +0 -21
  81. package/src/koffi/src/trampolines/masm32.inc +0 -21
  82. package/src/koffi/src/trampolines/masm64.inc +0 -21
  83. package/src/koffi/src/trampolines/prototypes.inc +1 -22
  84. package/src/koffi/src/util.cc +87 -102
  85. package/src/koffi/src/util.hh +11 -29
  86. package/src/koffi/src/uv.cc +193 -0
  87. package/src/koffi/src/uv.def +10 -0
  88. package/src/koffi/src/uv.hh +40 -0
  89. package/src/koffi/src/win32.cc +7 -25
  90. package/src/koffi/src/win32.hh +4 -22
  91. package/vendor/node-api-headers/include/uv/aix.h +32 -0
  92. package/vendor/node-api-headers/include/uv/bsd.h +34 -0
  93. package/vendor/node-api-headers/include/uv/darwin.h +61 -0
  94. package/vendor/node-api-headers/include/uv/errno.h +483 -0
  95. package/vendor/node-api-headers/include/uv/linux.h +34 -0
  96. package/vendor/node-api-headers/include/uv/os390.h +33 -0
  97. package/vendor/node-api-headers/include/uv/posix.h +31 -0
  98. package/vendor/node-api-headers/include/uv/sunos.h +44 -0
  99. package/vendor/node-api-headers/include/uv/threadpool.h +37 -0
  100. package/vendor/node-api-headers/include/uv/tree.h +521 -0
  101. package/vendor/node-api-headers/include/uv/unix.h +512 -0
  102. package/vendor/node-api-headers/include/uv/version.h +43 -0
  103. package/vendor/node-api-headers/include/uv/win.h +698 -0
  104. package/vendor/node-api-headers/include/uv.h +1990 -0
  105. package/src/core/base/crc_gen.py +0 -109
@@ -1,23 +1,5 @@
1
- // Copyright (C) 2025 Niels Martignène <niels.martignene@protonmail.com>
2
-
3
- // Permission is hereby granted, free of charge, to any person obtaining a copy of
4
- // this software and associated documentation files (the “Software”), to deal in
5
- // the Software without restriction, including without limitation the rights to use,
6
- // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
7
- // Software, and to permit persons to whom the Software is furnished to do so,
8
- // subject to the following conditions:
9
-
10
- // The above copyright notice and this permission notice shall be included in all
11
- // copies or substantial portions of the Software.
12
-
13
- // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
14
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15
- // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17
- // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
- // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
- // OTHER DEALINGS IN THE SOFTWARE.
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: 2025 Niels Martignène <niels.martignene@protonmail.com>
21
3
 
22
4
  #pragma once
23
5
 
@@ -75,38 +57,40 @@
75
57
  struct sigaction;
76
58
  struct BrotliEncoderStateStruct;
77
59
 
78
- namespace RG {
60
+ namespace K {
79
61
 
80
62
  // ------------------------------------------------------------------------
81
63
  // Config
82
64
  // ------------------------------------------------------------------------
83
65
 
84
66
  #if !defined(NDEBUG)
85
- #define RG_DEBUG
67
+ #define K_DEBUG
86
68
  #endif
87
69
 
88
- #define RG_DEFAULT_ALLOCATOR MallocAllocator
89
- #define RG_BLOCK_ALLOCATOR_DEFAULT_SIZE Kibibytes(4)
70
+ #define K_DEFAULT_ALLOCATOR MallocAllocator
71
+ #define K_BLOCK_ALLOCATOR_DEFAULT_SIZE Kibibytes(4)
90
72
 
91
- #define RG_HEAPARRAY_BASE_CAPACITY 8
92
- #define RG_HEAPARRAY_GROWTH_FACTOR 2.0
73
+ #define K_HEAPARRAY_BASE_CAPACITY 8
74
+ #define K_HEAPARRAY_GROWTH_FACTOR 2.0
93
75
 
94
76
  // Must be a power-of-two
95
- #define RG_HASHTABLE_BASE_CAPACITY 8
96
- #define RG_HASHTABLE_MAX_LOAD_FACTOR 0.5
77
+ #define K_HASHTABLE_BASE_CAPACITY 8
78
+ #define K_HASHTABLE_MAX_LOAD_FACTOR 0.5
97
79
 
98
- #define RG_FMT_STRING_BASE_CAPACITY 256
99
- #define RG_FMT_STRING_PRINT_BUFFER_SIZE 1024
80
+ #define K_FMT_STRING_BASE_CAPACITY 256
81
+ #define K_FMT_STRING_PRINT_BUFFER_SIZE 1024
100
82
 
101
- #define RG_LINE_READER_STEP_SIZE 65536
83
+ #define K_LINE_READER_STEP_SIZE 65536
102
84
 
103
- #define RG_ASYNC_MAX_THREADS 2048
104
- #define RG_ASYNC_MAX_IDLE_TIME 10000
105
- #define RG_ASYNC_MAX_PENDING_TASKS 2048
85
+ #define K_ASYNC_MAX_THREADS 2048
86
+ #define K_ASYNC_MAX_IDLE_TIME 10000
87
+ #define K_ASYNC_MAX_PENDING_TASKS 2048
106
88
 
107
- #define RG_PROGRESS_MAX_NODES 400
108
- #define RG_PROGRESS_USED_NODES 100
109
- #define RG_PROGRESS_TEXT_SIZE 64
89
+ #define K_PROGRESS_MAX_NODES 400
90
+ #define K_PROGRESS_USED_NODES 100
91
+ #define K_PROGRESS_TEXT_SIZE 64
92
+
93
+ #define K_COMPLETE_PATH_LIMIT 256
110
94
 
111
95
  // ------------------------------------------------------------------------
112
96
  // Utility
@@ -125,13 +109,13 @@ extern StreamWriter *const StdErr;
125
109
 
126
110
  #if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) || defined(_M_ARM64) || __riscv_xlen == 64 || defined(__loongarch64)
127
111
  typedef int64_t Size;
128
- #define RG_SIZE_MAX INT64_MAX
112
+ #define K_SIZE_MAX INT64_MAX
129
113
  #elif defined(_WIN32) || defined(__APPLE__) || defined(__unix__)
130
114
  typedef int32_t Size;
131
- #define RG_SIZE_MAX INT32_MAX
115
+ #define K_SIZE_MAX INT32_MAX
132
116
  #elif defined(__thumb__) || defined(__arm__) || defined(__wasm32__)
133
117
  typedef int32_t Size;
134
- #define RG_SIZE_MAX INT32_MAX
118
+ #define K_SIZE_MAX INT32_MAX
135
119
  #else
136
120
  #error Machine architecture not supported
137
121
  #endif
@@ -139,7 +123,7 @@ extern StreamWriter *const StdErr;
139
123
  #if defined(_MSC_VER) || __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
140
124
  // Sane platform
141
125
  #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
142
- #define RG_BIG_ENDIAN
126
+ #define K_BIG_ENDIAN
143
127
  #else
144
128
  #error This code base is not designed to support platforms with crazy endianness
145
129
  #endif
@@ -152,16 +136,16 @@ extern StreamWriter *const StdErr;
152
136
  #endif
153
137
  static_assert(sizeof(double) == 8, "This code base is not designed to support single-precision double floats");
154
138
 
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)!
139
+ #define K_STRINGIFY_(a) #a
140
+ #define K_STRINGIFY(a) K_STRINGIFY_(a)
141
+ #define K_CONCAT_(a, b) a ## b
142
+ #define K_CONCAT(a, b) K_CONCAT_(a, b)
143
+ #define K_UNIQUE_NAME(prefix) K_CONCAT(prefix, __LINE__)
144
+ #define K_FORCE_EXPAND(x) x
145
+ #define K_IGNORE (void)!
162
146
 
163
147
  #if defined(__GNUC__) || defined(__clang__)
164
- #define RG_PUSH_NO_WARNINGS \
148
+ #define K_PUSH_NO_WARNINGS \
165
149
  _Pragma("GCC diagnostic push") \
166
150
  _Pragma("GCC diagnostic ignored \"-Wall\"") \
167
151
  _Pragma("GCC diagnostic ignored \"-Wextra\"") \
@@ -173,7 +157,7 @@ static_assert(sizeof(double) == 8, "This code base is not designed to support si
173
157
  _Pragma("GCC diagnostic ignored \"-Wunused-parameter\"") \
174
158
  _Pragma("GCC diagnostic ignored \"-Wzero-as-null-pointer-constant\"") \
175
159
  _Pragma("GCC diagnostic ignored \"-Winvalid-offsetof\"")
176
- #define RG_POP_NO_WARNINGS \
160
+ #define K_POP_NO_WARNINGS \
177
161
  _Pragma("GCC diagnostic pop")
178
162
 
179
163
  #if !defined(SCNd8)
@@ -186,8 +170,8 @@ static_assert(sizeof(double) == 8, "This code base is not designed to support si
186
170
  #define SCNu8 "hhu"
187
171
  #endif
188
172
  #elif defined(_MSC_VER)
189
- #define RG_PUSH_NO_WARNINGS __pragma(warning(push, 0))
190
- #define RG_POP_NO_WARNINGS __pragma(warning(pop))
173
+ #define K_PUSH_NO_WARNINGS __pragma(warning(push, 0))
174
+ #define K_POP_NO_WARNINGS __pragma(warning(pop))
191
175
 
192
176
  #define __restrict__ __restrict
193
177
  #else
@@ -209,73 +193,73 @@ static_assert(sizeof(double) == 8, "This code base is not designed to support si
209
193
  extern "C" void AssertMessage(const char *filename, int line, const char *cond);
210
194
 
211
195
  #if defined(_MSC_VER)
212
- #define RG_DEBUG_BREAK() __debugbreak()
196
+ #define K_DEBUG_BREAK() __debugbreak()
213
197
  #elif defined(__clang__)
214
- #define RG_DEBUG_BREAK() __builtin_debugtrap()
198
+ #define K_DEBUG_BREAK() __builtin_debugtrap()
215
199
  #elif defined(__i386__) || defined(__x86_64__)
216
- #define RG_DEBUG_BREAK() __asm__ __volatile__("int $0x03")
200
+ #define K_DEBUG_BREAK() __asm__ __volatile__("int $0x03")
217
201
  #elif defined(__thumb__)
218
- #define RG_DEBUG_BREAK() __asm__ __volatile__(".inst 0xde01")
202
+ #define K_DEBUG_BREAK() __asm__ __volatile__(".inst 0xde01")
219
203
  #elif defined(__aarch64__)
220
- #define RG_DEBUG_BREAK() __asm__ __volatile__(".inst 0xd4200000")
204
+ #define K_DEBUG_BREAK() __asm__ __volatile__(".inst 0xd4200000")
221
205
  #elif defined(__arm__)
222
- #define RG_DEBUG_BREAK() __asm__ __volatile__(".inst 0xe7f001f0")
206
+ #define K_DEBUG_BREAK() __asm__ __volatile__(".inst 0xe7f001f0")
223
207
  #elif defined(__riscv)
224
- #define RG_DEBUG_BREAK() __asm__ __volatile__("ebreak")
208
+ #define K_DEBUG_BREAK() __asm__ __volatile__("ebreak")
225
209
  #elif defined(__loongarch64)
226
- #define RG_DEBUG_BREAK() __asm__ __volatile__("break 1")
210
+ #define K_DEBUG_BREAK() __asm__ __volatile__("break 1")
227
211
  #endif
228
212
 
229
213
  #if defined(_MSC_VER) || __EXCEPTIONS
230
- #define RG_BAD_ALLOC() \
214
+ #define K_BAD_ALLOC() \
231
215
  do { \
232
216
  throw std::bad_alloc(); \
233
217
  } while (false)
234
218
  #else
235
- #define RG_BAD_ALLOC() \
219
+ #define K_BAD_ALLOC() \
236
220
  do { \
237
221
  PrintLn(StdErr, "Memory allocation failed"); \
238
222
  abort(); \
239
223
  } while (false);
240
224
  #endif
241
225
 
242
- #define RG_CRITICAL(Cond, ...) \
226
+ #define K_CRITICAL(Cond, ...) \
243
227
  do { \
244
228
  if (!(Cond)) [[unlikely]] { \
245
229
  PrintLn(StdErr, __VA_ARGS__); \
246
230
  abort(); \
247
231
  } \
248
232
  } while (false)
249
- #if defined(RG_DEBUG)
250
- #define RG_ASSERT(Cond) \
233
+ #if defined(K_DEBUG)
234
+ #define K_ASSERT(Cond) \
251
235
  do { \
252
236
  if (!(Cond)) [[unlikely]] { \
253
- RG::AssertMessage(__FILE__, __LINE__, RG_STRINGIFY(Cond)); \
254
- RG_DEBUG_BREAK(); \
237
+ K::AssertMessage(__FILE__, __LINE__, K_STRINGIFY(Cond)); \
238
+ K_DEBUG_BREAK(); \
255
239
  abort(); \
256
240
  } \
257
241
  } while (false)
258
242
  #else
259
- #define RG_ASSERT(Cond) \
243
+ #define K_ASSERT(Cond) \
260
244
  do { \
261
245
  (void)sizeof(Cond); \
262
246
  } while (false)
263
247
  #endif
264
248
 
265
- #if defined(RG_DEBUG)
266
- #define RG_UNREACHABLE() \
249
+ #if defined(K_DEBUG)
250
+ #define K_UNREACHABLE() \
267
251
  do { \
268
- RG::AssertMessage(__FILE__, __LINE__, "Reached code marked as UNREACHABLE"); \
269
- RG_DEBUG_BREAK(); \
252
+ K::AssertMessage(__FILE__, __LINE__, "Reached code marked as UNREACHABLE"); \
253
+ K_DEBUG_BREAK(); \
270
254
  abort(); \
271
255
  } while (false)
272
256
  #elif defined(__GNUC__) || defined(__clang__)
273
- #define RG_UNREACHABLE() __builtin_unreachable()
257
+ #define K_UNREACHABLE() __builtin_unreachable()
274
258
  #else
275
- #define RG_UNREACHABLE() __assume(0)
259
+ #define K_UNREACHABLE() __assume(0)
276
260
  #endif
277
261
 
278
- #define RG_DELETE_COPY(Cls) \
262
+ #define K_DELETE_COPY(Cls) \
279
263
  Cls(const Cls&) = delete; \
280
264
  Cls &operator=(const Cls&) = delete;
281
265
 
@@ -289,11 +273,11 @@ constexpr Size Kibibytes(Size len) { return len * 1024; }
289
273
  constexpr Size Megabytes(Size len) { return len * 1000 * 1000; }
290
274
  constexpr Size Kilobytes(Size len) { return len * 1000; }
291
275
 
292
- #define RG_SIZE(Type) ((RG::Size)sizeof(Type))
276
+ #define K_SIZE(Type) ((K::Size)sizeof(Type))
293
277
  template <typename T, unsigned N>
294
278
  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))
279
+ #define K_BITS(Type) (8 * K_SIZE(Type))
280
+ #define K_LEN(Array) K_SIZE(K::ComputeArraySize(Array))
297
281
 
298
282
  static constexpr inline uint16_t ReverseBytes(uint16_t u)
299
283
  {
@@ -328,7 +312,7 @@ static constexpr inline int32_t ReverseBytes(int32_t i)
328
312
  static constexpr inline int64_t ReverseBytes(int64_t i)
329
313
  { return (int64_t)ReverseBytes((uint64_t)i); }
330
314
 
331
- #if defined(RG_BIG_ENDIAN)
315
+ #if defined(K_BIG_ENDIAN)
332
316
  template <typename T>
333
317
  constexpr T LittleEndian(T v) { return ReverseBytes(v); }
334
318
  template <typename T>
@@ -478,9 +462,9 @@ constexpr T BigEndian(T v) { return ReverseBytes(v); }
478
462
  #endif
479
463
 
480
464
  #if __cplusplus >= 202002L && (defined(_MSC_VER) || defined(__clang__) || __GNUC__ >= 11)
481
- #define RG_CONSTINIT constinit
465
+ #define K_CONSTINIT constinit
482
466
  #else
483
- #define RG_CONSTINIT const
467
+ #define K_CONSTINIT const
484
468
  #endif
485
469
 
486
470
  static inline Size AlignLen(Size len, Size align)
@@ -507,7 +491,7 @@ static inline T *AlignDown(T *ptr, Size align)
507
491
  // even if length is 0. This is dumb, work around this.
508
492
  static inline void *MemCpy(void *__restrict__ dest, const void *__restrict__ src, Size len)
509
493
  {
510
- RG_ASSERT(len >= 0);
494
+ K_ASSERT(len >= 0);
511
495
 
512
496
  #if defined(__clang__)
513
497
  // LLVM guarantees sane behavior
@@ -521,7 +505,7 @@ static inline void *MemCpy(void *__restrict__ dest, const void *__restrict__ src
521
505
  }
522
506
  static inline void *MemMove(void *dest, const void *src, Size len)
523
507
  {
524
- RG_ASSERT(len >= 0);
508
+ K_ASSERT(len >= 0);
525
509
 
526
510
  #if defined(__clang__)
527
511
  // LLVM guarantees sane behavior
@@ -535,7 +519,7 @@ static inline void *MemMove(void *dest, const void *src, Size len)
535
519
  }
536
520
  static inline void *MemSet(void *dest, int c, Size len)
537
521
  {
538
- RG_ASSERT(len >= 0);
522
+ K_ASSERT(len >= 0);
539
523
 
540
524
  #if defined(__clang__)
541
525
  // LLVM guarantees sane behavior
@@ -556,8 +540,8 @@ void *MemMem(const void *src, Size src_len, const void *needle, Size needle_len)
556
540
 
557
541
  static inline void *MemMem(const void *src, Size src_len, const void *needle, Size needle_len)
558
542
  {
559
- RG_ASSERT(src_len >= 0);
560
- RG_ASSERT(needle_len > 0);
543
+ K_ASSERT(src_len >= 0);
544
+ K_ASSERT(needle_len > 0);
561
545
 
562
546
  void *ptr = memmem(src, (size_t)src_len, needle, (size_t)needle_len);
563
547
  return ptr;
@@ -565,6 +549,9 @@ static inline void *MemMem(const void *src, Size src_len, const void *needle, Si
565
549
 
566
550
  #endif
567
551
 
552
+ // Implemented for translations, but we need it before we get to this part
553
+ const char *T(const char *key);
554
+
568
555
  template <typename T, typename = typename std::enable_if<std::is_enum<T>::value, T>>
569
556
  typename std::underlying_type<T>::type MaskEnum(T value)
570
557
  {
@@ -574,7 +561,7 @@ typename std::underlying_type<T>::type MaskEnum(T value)
574
561
 
575
562
  template <typename Fun>
576
563
  class DeferGuard {
577
- RG_DELETE_COPY(DeferGuard)
564
+ K_DELETE_COPY(DeferGuard)
578
565
 
579
566
  Fun f;
580
567
  bool enabled;
@@ -610,14 +597,35 @@ DeferGuard<Fun> operator+(DeferGuardHelper, Fun &&f)
610
597
  // Write 'DEFER { code };' to do something at the end of the current scope, you
611
598
  // can use DEFER_N(Name) if you need to disable the guard for some reason, and
612
599
  // 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__]()
600
+ #define K_DEFER \
601
+ auto K_UNIQUE_NAME(defer) = K::DeferGuardHelper() + [&]()
602
+ #define K_DEFER_N(Name) \
603
+ auto Name = K::DeferGuardHelper() + [&]()
604
+ #define K_DEFER_C(...) \
605
+ auto K_UNIQUE_NAME(defer) = K::DeferGuardHelper() + [&, __VA_ARGS__]()
606
+ #define K_DEFER_NC(Name, ...) \
607
+ auto Name = K::DeferGuardHelper() + [&, __VA_ARGS__]()
608
+
609
+ template <typename T>
610
+ class NoDestroy {
611
+ K_DELETE_COPY(NoDestroy);
612
+
613
+ alignas(T) uint8_t data[K_SIZE(T)];
614
+
615
+ public:
616
+ template <class... Args>
617
+ NoDestroy(Args&&... args) { new (data) T(std::forward<Args>(args)...); }
618
+
619
+ ~NoDestroy() = default;
620
+
621
+ const T *Get() const { return (const T *)(data); }
622
+ T *Get() { return (T*)data; }
623
+
624
+ const T &operator*() const { return *Get(); }
625
+ T& operator*() { return *Get(); }
626
+ const T *operator->() const { return Get(); }
627
+ T *operator->() { return Get(); }
628
+ };
621
629
 
622
630
  // Heavily inspired from FunctionRef in LLVM
623
631
  template<typename Fn> class FunctionRef;
@@ -648,24 +656,6 @@ public:
648
656
  bool IsValid() const { return callback; }
649
657
  };
650
658
 
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
659
  template <typename T>
670
660
  T MultiCmp()
671
661
  {
@@ -730,19 +720,19 @@ public:
730
720
 
731
721
  Size operator*() const
732
722
  {
733
- RG_ASSERT(offset <= RG_LEN(bitset->data));
723
+ K_ASSERT(offset <= K_LEN(bitset->data));
734
724
 
735
- if (offset == RG_LEN(bitset->data))
725
+ if (offset == K_LEN(bitset->data))
736
726
  return -1;
737
- return offset * RG_SIZE(size_t) * 8 + ctz;
727
+ return offset * K_SIZE(size_t) * 8 + ctz;
738
728
  }
739
729
 
740
730
  Iterator &operator++()
741
731
  {
742
- RG_ASSERT(offset <= RG_LEN(bitset->data));
732
+ K_ASSERT(offset <= K_LEN(bitset->data));
743
733
 
744
734
  while (!bits) {
745
- if (offset == RG_LEN(bitset->data) - 1)
735
+ if (offset == K_LEN(bitset->data) - 1)
746
736
  return *this;
747
737
  bits = bitset->data[++offset];
748
738
  }
@@ -769,14 +759,14 @@ public:
769
759
  typedef Iterator<Bitset> iterator_type;
770
760
 
771
761
  static constexpr Size Bits = N;
772
- size_t data[(N + RG_BITS(size_t) - 1) / RG_BITS(size_t)] = {};
762
+ size_t data[(N + K_BITS(size_t) - 1) / K_BITS(size_t)] = {};
773
763
 
774
764
  constexpr Bitset() = default;
775
765
  constexpr Bitset(std::initializer_list<Size> bits)
776
766
  {
777
767
  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));
768
+ Size offset = idx / (K_SIZE(size_t) * 8);
769
+ size_t mask = (size_t)1 << (idx % (K_SIZE(size_t) * 8));
780
770
 
781
771
  data[offset] |= mask;
782
772
  }
@@ -784,22 +774,22 @@ public:
784
774
 
785
775
  void Clear()
786
776
  {
787
- MemSet(data, 0, RG_SIZE(data));
777
+ MemSet(data, 0, K_SIZE(data));
788
778
  }
789
779
 
790
780
  Iterator<Bitset> begin() { return Iterator<Bitset>(this, 0); }
791
781
  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)); }
782
+ Iterator<Bitset> end() { return Iterator<Bitset>(this, K_LEN(data)); }
783
+ Iterator<const Bitset> end() const { return Iterator<const Bitset>(this, K_LEN(data)); }
794
784
 
795
785
  Size PopCount() const
796
786
  {
797
787
  Size count = 0;
798
788
  for (size_t bits: data) {
799
- #if RG_SIZE_MAX == INT64_MAX
800
- count += RG::PopCount((uint64_t)bits);
789
+ #if K_SIZE_MAX == INT64_MAX
790
+ count += K::PopCount((uint64_t)bits);
801
791
  #else
802
- count += RG::PopCount((uint32_t)bits);
792
+ count += K::PopCount((uint32_t)bits);
803
793
  #endif
804
794
  }
805
795
  return count;
@@ -807,28 +797,28 @@ public:
807
797
 
808
798
  inline bool Test(Size idx) const
809
799
  {
810
- RG_ASSERT(idx >= 0 && idx < N);
800
+ K_ASSERT(idx >= 0 && idx < N);
811
801
 
812
- Size offset = idx / (RG_SIZE(size_t) * 8);
813
- size_t mask = (size_t)1 << (idx % (RG_SIZE(size_t) * 8));
802
+ Size offset = idx / (K_SIZE(size_t) * 8);
803
+ size_t mask = (size_t)1 << (idx % (K_SIZE(size_t) * 8));
814
804
 
815
805
  return data[offset] & mask;
816
806
  }
817
807
  inline void Set(Size idx, bool value = true)
818
808
  {
819
- RG_ASSERT(idx >= 0 && idx < N);
809
+ K_ASSERT(idx >= 0 && idx < N);
820
810
 
821
- Size offset = idx / (RG_SIZE(size_t) * 8);
822
- size_t mask = (size_t)1 << (idx % (RG_SIZE(size_t) * 8));
811
+ Size offset = idx / (K_SIZE(size_t) * 8);
812
+ size_t mask = (size_t)1 << (idx % (K_SIZE(size_t) * 8));
823
813
 
824
814
  data[offset] = ApplyMask(data[offset], mask, value);
825
815
  }
826
816
  inline bool TestAndSet(Size idx, bool value = true)
827
817
  {
828
- RG_ASSERT(idx >= 0 && idx < N);
818
+ K_ASSERT(idx >= 0 && idx < N);
829
819
 
830
- Size offset = idx / (RG_SIZE(size_t) * 8);
831
- size_t mask = (size_t)1 << (idx % (RG_SIZE(size_t) * 8));
820
+ Size offset = idx / (K_SIZE(size_t) * 8);
821
+ size_t mask = (size_t)1 << (idx % (K_SIZE(size_t) * 8));
832
822
 
833
823
  bool ret = data[offset] & mask;
834
824
  data[offset] = ApplyMask(data[offset], mask, value);
@@ -838,7 +828,7 @@ public:
838
828
 
839
829
  Bitset &operator&=(const Bitset &other)
840
830
  {
841
- for (Size i = 0; i < RG_LEN(data); i++) {
831
+ for (Size i = 0; i < K_LEN(data); i++) {
842
832
  data[i] &= other.data[i];
843
833
  }
844
834
  return *this;
@@ -846,7 +836,7 @@ public:
846
836
  Bitset operator&(const Bitset &other)
847
837
  {
848
838
  Bitset ret;
849
- for (Size i = 0; i < RG_LEN(data); i++) {
839
+ for (Size i = 0; i < K_LEN(data); i++) {
850
840
  ret.data[i] = data[i] & other.data[i];
851
841
  }
852
842
  return ret;
@@ -854,7 +844,7 @@ public:
854
844
 
855
845
  Bitset &operator|=(const Bitset &other)
856
846
  {
857
- for (Size i = 0; i < RG_LEN(data); i++) {
847
+ for (Size i = 0; i < K_LEN(data); i++) {
858
848
  data[i] |= other.data[i];
859
849
  }
860
850
  return *this;
@@ -862,7 +852,7 @@ public:
862
852
  Bitset operator|(const Bitset &other)
863
853
  {
864
854
  Bitset ret;
865
- for (Size i = 0; i < RG_LEN(data); i++) {
855
+ for (Size i = 0; i < K_LEN(data); i++) {
866
856
  ret.data[i] = data[i] | other.data[i];
867
857
  }
868
858
  return ret;
@@ -870,7 +860,7 @@ public:
870
860
 
871
861
  Bitset &operator^=(const Bitset &other)
872
862
  {
873
- for (Size i = 0; i < RG_LEN(data); i++) {
863
+ for (Size i = 0; i < K_LEN(data); i++) {
874
864
  data[i] ^= other.data[i];
875
865
  }
876
866
  return *this;
@@ -878,7 +868,7 @@ public:
878
868
  Bitset operator^(const Bitset &other)
879
869
  {
880
870
  Bitset ret;
881
- for (Size i = 0; i < RG_LEN(data); i++) {
871
+ for (Size i = 0; i < K_LEN(data); i++) {
882
872
  ret.data[i] = data[i] ^ other.data[i];
883
873
  }
884
874
  return ret;
@@ -886,7 +876,7 @@ public:
886
876
 
887
877
  Bitset &Flip()
888
878
  {
889
- for (Size i = 0; i < RG_LEN(data); i++) {
879
+ for (Size i = 0; i < K_LEN(data); i++) {
890
880
  data[i] = ~data[i];
891
881
  }
892
882
  return *this;
@@ -894,7 +884,7 @@ public:
894
884
  Bitset operator~()
895
885
  {
896
886
  Bitset ret;
897
- for (Size i = 0; i < RG_LEN(data); i++) {
887
+ for (Size i = 0; i < K_LEN(data); i++) {
898
888
  ret.data[i] = ~data[i];
899
889
  }
900
890
  return ret;
@@ -936,12 +926,12 @@ struct Span {
936
926
 
937
927
  constexpr T &operator[](Size idx)
938
928
  {
939
- RG_ASSERT(idx >= 0 && idx < len);
929
+ K_ASSERT(idx >= 0 && idx < len);
940
930
  return ptr[idx];
941
931
  }
942
932
  constexpr const T &operator[](Size idx) const
943
933
  {
944
- RG_ASSERT(idx >= 0 && idx < len);
934
+ K_ASSERT(idx >= 0 && idx < len);
945
935
  return ptr[idx];
946
936
  }
947
937
 
@@ -963,8 +953,8 @@ struct Span {
963
953
 
964
954
  constexpr Span Take(Size offset, Size sub_len) const
965
955
  {
966
- RG_ASSERT(sub_len >= 0 && sub_len <= len);
967
- RG_ASSERT(offset >= 0 && offset <= len - sub_len);
956
+ K_ASSERT(sub_len >= 0 && sub_len <= len);
957
+ K_ASSERT(offset >= 0 && offset <= len - sub_len);
968
958
 
969
959
  Span<T> sub = { ptr + offset, sub_len };
970
960
  return sub;
@@ -1005,7 +995,7 @@ struct Span<const char> {
1005
995
 
1006
996
  constexpr char operator[](Size idx) const
1007
997
  {
1008
- RG_ASSERT(idx >= 0 && idx < len);
998
+ K_ASSERT(idx >= 0 && idx < len);
1009
999
  return ptr[idx];
1010
1000
  }
1011
1001
 
@@ -1017,8 +1007,8 @@ struct Span<const char> {
1017
1007
 
1018
1008
  constexpr Span Take(Size offset, Size sub_len) const
1019
1009
  {
1020
- RG_ASSERT(sub_len >= 0 && sub_len <= len);
1021
- RG_ASSERT(offset >= 0 && offset <= len - sub_len);
1010
+ K_ASSERT(sub_len >= 0 && sub_len <= len);
1011
+ K_ASSERT(offset >= 0 && offset <= len - sub_len);
1022
1012
 
1023
1013
  Span<const char> sub = { ptr + offset, sub_len };
1024
1014
  return sub;
@@ -1051,14 +1041,14 @@ public:
1051
1041
  Size stride;
1052
1042
 
1053
1043
  Strider() = default;
1054
- constexpr Strider(T *ptr_) : ptr(ptr_), stride(RG_SIZE(T)) {}
1044
+ constexpr Strider(T *ptr_) : ptr(ptr_), stride(K_SIZE(T)) {}
1055
1045
  constexpr Strider(T *ptr_, Size stride_) : ptr(ptr_), stride(stride_) {}
1056
1046
 
1057
1047
  constexpr bool IsValid() const { return ptr; }
1058
1048
 
1059
1049
  constexpr T &operator[](Size idx) const
1060
1050
  {
1061
- RG_ASSERT(idx >= 0);
1051
+ K_ASSERT(idx >= 0);
1062
1052
  return *(T *)((uint8_t *)ptr + (idx * stride));
1063
1053
  }
1064
1054
  };
@@ -1066,7 +1056,7 @@ public:
1066
1056
  template <typename T>
1067
1057
  static constexpr inline Strider<T> MakeStrider(T *ptr)
1068
1058
  {
1069
- return Strider<T>(ptr, RG_SIZE(T));
1059
+ return Strider<T>(ptr, K_SIZE(T));
1070
1060
  }
1071
1061
  template <typename T>
1072
1062
  static constexpr inline Strider<T> MakeStrider(T *ptr, Size stride)
@@ -1076,7 +1066,7 @@ static constexpr inline Strider<T> MakeStrider(T *ptr, Size stride)
1076
1066
  template <typename T, Size N>
1077
1067
  static constexpr inline Strider<T> MakeStrider(T (&arr)[N])
1078
1068
  {
1079
- return Strider<T>(arr, RG_SIZE(T));
1069
+ return Strider<T>(arr, K_SIZE(T));
1080
1070
  }
1081
1071
 
1082
1072
  enum class AllocFlag {
@@ -1085,7 +1075,7 @@ enum class AllocFlag {
1085
1075
  };
1086
1076
 
1087
1077
  class Allocator {
1088
- RG_DELETE_COPY(Allocator)
1078
+ K_DELETE_COPY(Allocator)
1089
1079
 
1090
1080
  public:
1091
1081
  Allocator() = default;
@@ -1101,7 +1091,7 @@ Allocator *GetNullAllocator();
1101
1091
 
1102
1092
  static inline void *AllocateRaw(Allocator *alloc, Size size, unsigned int flags = 0)
1103
1093
  {
1104
- RG_ASSERT(size >= 0);
1094
+ K_ASSERT(size >= 0);
1105
1095
 
1106
1096
  if (!alloc) {
1107
1097
  alloc = GetDefaultAllocator();
@@ -1118,7 +1108,7 @@ T *AllocateOne(Allocator *alloc, unsigned int flags = 0)
1118
1108
  alloc = GetDefaultAllocator();
1119
1109
  }
1120
1110
 
1121
- Size size = RG_SIZE(T);
1111
+ Size size = K_SIZE(T);
1122
1112
 
1123
1113
  T *ptr = (T *)alloc->Allocate(size, flags);
1124
1114
  return ptr;
@@ -1127,13 +1117,13 @@ T *AllocateOne(Allocator *alloc, unsigned int flags = 0)
1127
1117
  template <typename T>
1128
1118
  Span<T> AllocateSpan(Allocator *alloc, Size len, unsigned int flags = 0)
1129
1119
  {
1130
- RG_ASSERT(len >= 0);
1120
+ K_ASSERT(len >= 0);
1131
1121
 
1132
1122
  if (!alloc) {
1133
1123
  alloc = GetDefaultAllocator();
1134
1124
  }
1135
1125
 
1136
- Size size = len * RG_SIZE(T);
1126
+ Size size = len * K_SIZE(T);
1137
1127
 
1138
1128
  T *ptr = (T *)alloc->Allocate(size, flags);
1139
1129
  return MakeSpan(ptr, len);
@@ -1142,7 +1132,7 @@ Span<T> AllocateSpan(Allocator *alloc, Size len, unsigned int flags = 0)
1142
1132
  static inline void *ResizeRaw(Allocator *alloc, void *ptr, Size old_size, Size new_size,
1143
1133
  unsigned int flags = 0)
1144
1134
  {
1145
- RG_ASSERT(new_size >= 0);
1135
+ K_ASSERT(new_size >= 0);
1146
1136
 
1147
1137
  if (!alloc) {
1148
1138
  alloc = GetDefaultAllocator();
@@ -1156,14 +1146,14 @@ template <typename T>
1156
1146
  Span<T> ResizeSpan(Allocator *alloc, Span<T> mem, Size new_len,
1157
1147
  unsigned int flags = 0)
1158
1148
  {
1159
- RG_ASSERT(new_len >= 0);
1149
+ K_ASSERT(new_len >= 0);
1160
1150
 
1161
1151
  if (!alloc) {
1162
1152
  alloc = GetDefaultAllocator();
1163
1153
  }
1164
1154
 
1165
- Size old_size = mem.len * RG_SIZE(T);
1166
- Size new_size = new_len * RG_SIZE(T);
1155
+ Size old_size = mem.len * K_SIZE(T);
1156
+ Size new_size = new_len * K_SIZE(T);
1167
1157
 
1168
1158
  mem.ptr = (T *)alloc->Resize(mem.ptr, old_size, new_size, flags);
1169
1159
  return MakeSpan(mem.ptr, new_len);
@@ -1185,7 +1175,7 @@ void ReleaseOne(Allocator *alloc, T *ptr)
1185
1175
  alloc = GetDefaultAllocator();
1186
1176
  }
1187
1177
 
1188
- alloc->Release((void *)ptr, RG_SIZE(T));
1178
+ alloc->Release((void *)ptr, K_SIZE(T));
1189
1179
  }
1190
1180
 
1191
1181
  template<typename T>
@@ -1195,7 +1185,7 @@ void ReleaseSpan(Allocator *alloc, Span<T> mem)
1195
1185
  alloc = GetDefaultAllocator();
1196
1186
  }
1197
1187
 
1198
- Size size = mem.len * RG_SIZE(T);
1188
+ Size size = mem.len * K_SIZE(T);
1199
1189
 
1200
1190
  alloc->Release((void *)mem.ptr, size);
1201
1191
  }
@@ -1246,10 +1236,10 @@ class BlockAllocator: public Allocator {
1246
1236
  uint8_t *last_alloc = nullptr;
1247
1237
 
1248
1238
  public:
1249
- BlockAllocator(Size block_size = RG_BLOCK_ALLOCATOR_DEFAULT_SIZE)
1239
+ BlockAllocator(Size block_size = K_BLOCK_ALLOCATOR_DEFAULT_SIZE)
1250
1240
  : block_size(block_size)
1251
1241
  {
1252
- RG_ASSERT(block_size > 0);
1242
+ K_ASSERT(block_size > 0);
1253
1243
  }
1254
1244
 
1255
1245
  BlockAllocator(BlockAllocator &&other) { *this = std::move(other); }
@@ -1288,9 +1278,9 @@ public:
1288
1278
  RetainPtr(T *p, void (*delete_func)(std::remove_const_t<T> *))
1289
1279
  : p(p)
1290
1280
  {
1291
- RG_ASSERT(p);
1292
- RG_ASSERT(delete_func);
1293
- RG_ASSERT(!p->delete_func || delete_func == p->delete_func);
1281
+ K_ASSERT(p);
1282
+ K_ASSERT(delete_func);
1283
+ K_ASSERT(!p->delete_func || delete_func == p->delete_func);
1294
1284
 
1295
1285
  p->Ref();
1296
1286
  p->delete_func = delete_func;
@@ -1299,7 +1289,7 @@ public:
1299
1289
  : p(p)
1300
1290
  {
1301
1291
  if (p) {
1302
- RG_ASSERT(p->delete_func);
1292
+ K_ASSERT(p->delete_func);
1303
1293
 
1304
1294
  if (ref) {
1305
1295
  p->Ref();
@@ -1346,7 +1336,7 @@ public:
1346
1336
 
1347
1337
  T &operator*() const
1348
1338
  {
1349
- RG_ASSERT(p);
1339
+ K_ASSERT(p);
1350
1340
  return *p;
1351
1341
  }
1352
1342
  T *operator->() const { return p; }
@@ -1363,7 +1353,7 @@ public:
1363
1353
  bool Unref() const
1364
1354
  {
1365
1355
  int new_count = --refcount;
1366
- RG_ASSERT(new_count >= 0);
1356
+ K_ASSERT(new_count >= 0);
1367
1357
  return new_count;
1368
1358
  }
1369
1359
 
@@ -1545,7 +1535,6 @@ static inline bool StartsWith(Span<const char> str, Span<const char> prefix)
1545
1535
  return false;
1546
1536
  i++;
1547
1537
  }
1548
-
1549
1538
  return (i == prefix.len);
1550
1539
  }
1551
1540
  static inline bool StartsWith(Span<const char> str, const char *prefix)
@@ -1556,9 +1545,18 @@ static inline bool StartsWith(Span<const char> str, const char *prefix)
1556
1545
  return false;
1557
1546
  i++;
1558
1547
  }
1559
-
1560
1548
  return !prefix[i];
1561
1549
  }
1550
+ static inline bool StartsWith(const char *str, Span<const char> prefix)
1551
+ {
1552
+ Size i = 0;
1553
+ while (str[i] && i < prefix.len) {
1554
+ if (str[i] != prefix[i])
1555
+ return false;
1556
+ i++;
1557
+ }
1558
+ return (i == prefix.len);
1559
+ }
1562
1560
  static inline bool StartsWith(const char *str, const char *prefix)
1563
1561
  {
1564
1562
  Size i = 0;
@@ -1567,14 +1565,55 @@ static inline bool StartsWith(const char *str, const char *prefix)
1567
1565
  return false;
1568
1566
  i++;
1569
1567
  }
1568
+ return !prefix[i];
1569
+ }
1570
1570
 
1571
+ static inline bool StartsWithI(Span<const char> str, Span<const char> prefix)
1572
+ {
1573
+ Size i = 0;
1574
+ while (i < str.len && i < prefix.len) {
1575
+ if (LowerAscii(str[i]) != LowerAscii(prefix[i]))
1576
+ return false;
1577
+ i++;
1578
+ }
1579
+ return (i == prefix.len);
1580
+ }
1581
+ static inline bool StartsWithI(Span<const char> str, const char *prefix)
1582
+ {
1583
+ Size i = 0;
1584
+ while (i < str.len && prefix[i]) {
1585
+ if (LowerAscii(str[i]) != LowerAscii(prefix[i]))
1586
+ return false;
1587
+ i++;
1588
+ }
1589
+ return !prefix[i];
1590
+ }
1591
+ static inline bool StartsWithI(const char *str, Span<const char> prefix)
1592
+ {
1593
+ Size i = 0;
1594
+ while (str[i] && i < prefix.len) {
1595
+ if (LowerAscii(str[i]) != LowerAscii(prefix[i]))
1596
+ return false;
1597
+ i++;
1598
+ }
1599
+ return (i == prefix.len);
1600
+ }
1601
+ static inline bool StartsWithI(const char *str, const char *prefix)
1602
+ {
1603
+ Size i = 0;
1604
+ while (str[i] && prefix[i]) {
1605
+ if (LowerAscii(str[i]) != LowerAscii(prefix[i]))
1606
+ return false;
1607
+ i++;
1608
+ }
1571
1609
  return !prefix[i];
1572
1610
  }
1573
1611
 
1574
- static inline bool EndsWith(Span<const char> str, const char *suffix)
1612
+ static inline bool EndsWith(Span<const char> str, Span<const char> suffix)
1575
1613
  {
1576
1614
  Size i = str.len - 1;
1577
- Size j = (Size)strlen(suffix) - 1;
1615
+ Size j = suffix.len - 1;
1616
+
1578
1617
  while (i >= 0 && j >= 0) {
1579
1618
  if (str[i] != suffix[j])
1580
1619
  return false;
@@ -1585,6 +1624,21 @@ static inline bool EndsWith(Span<const char> str, const char *suffix)
1585
1624
 
1586
1625
  return j < 0;
1587
1626
  }
1627
+ static inline bool EndsWithI(Span<const char> str, Span<const char> suffix)
1628
+ {
1629
+ Size i = str.len - 1;
1630
+ Size j = suffix.len - 1;
1631
+
1632
+ while (i >= 0 && j >= 0) {
1633
+ if (LowerAscii(str[i]) != LowerAscii(suffix[j]))
1634
+ return false;
1635
+
1636
+ i--;
1637
+ j--;
1638
+ }
1639
+
1640
+ return j < 0;
1641
+ }
1588
1642
 
1589
1643
  static inline Size FindStr(Span<const char> str, Span<const char> needle)
1590
1644
  {
@@ -1649,16 +1703,15 @@ static inline Span<const char> SplitStr(Span<const char> str, char split_char, S
1649
1703
  static inline Span<const char> SplitStr(const char *str, char split_char, const char **out_remainder = nullptr)
1650
1704
  { return SplitStr((char *)str, split_char, (char **)out_remainder); }
1651
1705
 
1652
- static inline Span<char> SplitStr(Span<char> str, const char *split_str, Span<char> *out_remainder = nullptr)
1706
+ static inline Span<char> SplitStr(Span<char> str, Span<const char> split, Span<char> *out_remainder = nullptr)
1653
1707
  {
1654
- RG_ASSERT(split_str[0]);
1708
+ K_ASSERT(split.len);
1655
1709
 
1656
1710
  Size part_len = 0;
1657
1711
  while (part_len < str.len) {
1658
- if (StartsWith(str.Take(part_len, str.len - part_len), split_str)) {
1712
+ if (StartsWith(str.Take(part_len, str.len - part_len), split)) {
1659
1713
  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);
1714
+ *out_remainder = str.Take(part_len + split.len, str.len - part_len - split.len);
1662
1715
  }
1663
1716
  return str.Take(0, part_len);
1664
1717
  }
@@ -1670,16 +1723,15 @@ static inline Span<char> SplitStr(Span<char> str, const char *split_str, Span<ch
1670
1723
  }
1671
1724
  return str;
1672
1725
  }
1673
- static inline Span<char> SplitStr(char *str, const char *split_str, char **out_remainder = nullptr)
1726
+ static inline Span<char> SplitStr(char *str, Span<const char> split, char **out_remainder = nullptr)
1674
1727
  {
1675
- RG_ASSERT(split_str[0]);
1728
+ K_ASSERT(split.len);
1676
1729
 
1677
1730
  Size part_len = 0;
1678
1731
  while (str[part_len]) {
1679
- if (StartsWith(str + part_len, split_str)) {
1732
+ if (StartsWith(str + part_len, split)) {
1680
1733
  if (out_remainder) {
1681
- Size split_len = strlen(split_str);
1682
- *out_remainder = str + part_len + split_len;
1734
+ *out_remainder = str + part_len + split.len;
1683
1735
  }
1684
1736
  return MakeSpan(str, part_len);
1685
1737
  }
@@ -1691,10 +1743,10 @@ static inline Span<char> SplitStr(char *str, const char *split_str, char **out_r
1691
1743
  }
1692
1744
  return MakeSpan(str, part_len);
1693
1745
  }
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); }
1746
+ static inline Span<const char> SplitStr(Span<const char> str, Span<const char> split, Span<const char> *out_remainder = nullptr)
1747
+ { return SplitStr(MakeSpan((char *)str.ptr, str.len), split, (Span<char> *)out_remainder); }
1748
+ static inline Span<const char> SplitStr(const char *str, Span<const char> split, const char **out_remainder = nullptr)
1749
+ { return SplitStr((char *)str, split, (char **)out_remainder); }
1698
1750
 
1699
1751
  static inline Span<char> SplitStrLine(Span<char> str, Span<char> *out_remainder = nullptr)
1700
1752
  {
@@ -1890,116 +1942,8 @@ static inline Span<const char> TrimStrRight(Span<const char> str, const char *tr
1890
1942
  static inline Span<const char> TrimStr(Span<const char> str, const char *trim_chars = " \t\r\n")
1891
1943
  { return TrimStr(MakeSpan((char *)str.ptr, str.len), trim_chars); }
1892
1944
 
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);
1945
+ int CmpNatural(Span<const char> str1, Span<const char> str2);
1946
+ int CmpNaturalI(Span<const char> str1, Span<const char> str2);
2003
1947
 
2004
1948
  // ------------------------------------------------------------------------
2005
1949
  // Collections
@@ -2017,7 +1961,7 @@ public:
2017
1961
  constexpr LocalArray() = default;
2018
1962
  constexpr LocalArray(std::initializer_list<T> l)
2019
1963
  {
2020
- RG_ASSERT(l.size() <= N);
1964
+ K_ASSERT(l.size() <= N);
2021
1965
  for (const T &it: l) {
2022
1966
  data[len++] = it;
2023
1967
  }
@@ -2040,16 +1984,16 @@ public:
2040
1984
  T *end() { return data + len; }
2041
1985
  const T *end() const { return data + len; }
2042
1986
 
2043
- Size Available() const { return RG_LEN(data) - len; }
1987
+ Size Available() const { return K_LEN(data) - len; }
2044
1988
 
2045
1989
  T &operator[](Size idx)
2046
1990
  {
2047
- RG_ASSERT(idx >= 0 && idx < len);
1991
+ K_ASSERT(idx >= 0 && idx < len);
2048
1992
  return data[idx];
2049
1993
  }
2050
1994
  const T &operator[](Size idx) const
2051
1995
  {
2052
- RG_ASSERT(idx >= 0 && idx < len);
1996
+ K_ASSERT(idx >= 0 && idx < len);
2053
1997
  return data[idx];
2054
1998
  }
2055
1999
 
@@ -2069,7 +2013,7 @@ public:
2069
2013
 
2070
2014
  T *AppendDefault(Size count = 1)
2071
2015
  {
2072
- RG_ASSERT(len <= N - count);
2016
+ K_ASSERT(len <= N - count);
2073
2017
 
2074
2018
  T *first = data + len;
2075
2019
  if constexpr(!std::is_trivial<T>::value) {
@@ -2078,7 +2022,7 @@ public:
2078
2022
  len++;
2079
2023
  }
2080
2024
  } else {
2081
- MemSet(first, 0, count * RG_SIZE(T));
2025
+ MemSet(first, 0, count * K_SIZE(T));
2082
2026
  len += count;
2083
2027
  }
2084
2028
 
@@ -2087,7 +2031,7 @@ public:
2087
2031
 
2088
2032
  T *Append(const T &value)
2089
2033
  {
2090
- RG_ASSERT(len < N);
2034
+ K_ASSERT(len < N);
2091
2035
 
2092
2036
  T *it = data + len;
2093
2037
  *it = value;
@@ -2097,7 +2041,7 @@ public:
2097
2041
  }
2098
2042
  T *Append(T &&value)
2099
2043
  {
2100
- RG_ASSERT(len < N);
2044
+ K_ASSERT(len < N);
2101
2045
 
2102
2046
  T *it = data + len;
2103
2047
  *it = std::move(value);
@@ -2107,7 +2051,7 @@ public:
2107
2051
  }
2108
2052
  T *Append(Span<const T> values)
2109
2053
  {
2110
- RG_ASSERT(values.len <= N - len);
2054
+ K_ASSERT(values.len <= N - len);
2111
2055
 
2112
2056
  T *it = data + len;
2113
2057
  for (Size i = 0; i < values.len; i++) {
@@ -2120,7 +2064,7 @@ public:
2120
2064
 
2121
2065
  void RemoveFrom(Size first)
2122
2066
  {
2123
- RG_ASSERT(first >= 0 && first <= len);
2067
+ K_ASSERT(first >= 0 && first <= len);
2124
2068
 
2125
2069
  for (Size i = first; i < len; i++) {
2126
2070
  data[i] = T();
@@ -2129,7 +2073,7 @@ public:
2129
2073
  }
2130
2074
  void RemoveLast(Size count = 1)
2131
2075
  {
2132
- RG_ASSERT(count >= 0 && count <= len);
2076
+ K_ASSERT(count >= 0 && count <= len);
2133
2077
  RemoveFrom(len - count);
2134
2078
  }
2135
2079
 
@@ -2171,8 +2115,8 @@ public:
2171
2115
  HeapArray &operator=(HeapArray &&other)
2172
2116
  {
2173
2117
  Clear();
2174
- MemMove(this, &other, RG_SIZE(other));
2175
- MemSet(&other, 0, RG_SIZE(other));
2118
+ MemMove(this, &other, K_SIZE(other));
2119
+ MemSet(&other, 0, K_SIZE(other));
2176
2120
  return *this;
2177
2121
  }
2178
2122
  HeapArray(const HeapArray &other) { *this = other; }
@@ -2185,7 +2129,7 @@ public:
2185
2129
  ptr[i] = other.ptr[i];
2186
2130
  }
2187
2131
  } else {
2188
- MemCpy(ptr, other.ptr, other.len * RG_SIZE(*ptr));
2132
+ MemCpy(ptr, other.ptr, other.len * K_SIZE(*ptr));
2189
2133
  }
2190
2134
  len = other.len;
2191
2135
  return *this;
@@ -2209,12 +2153,12 @@ public:
2209
2153
 
2210
2154
  T &operator[](Size idx)
2211
2155
  {
2212
- RG_ASSERT(idx >= 0 && idx < len);
2156
+ K_ASSERT(idx >= 0 && idx < len);
2213
2157
  return ptr[idx];
2214
2158
  }
2215
2159
  const T &operator[](Size idx) const
2216
2160
  {
2217
- RG_ASSERT(idx >= 0 && idx < len);
2161
+ K_ASSERT(idx >= 0 && idx < len);
2218
2162
  return ptr[idx];
2219
2163
  }
2220
2164
 
@@ -2234,7 +2178,7 @@ public:
2234
2178
 
2235
2179
  void SetCapacity(Size new_capacity)
2236
2180
  {
2237
- RG_ASSERT(new_capacity >= 0);
2181
+ K_ASSERT(new_capacity >= 0);
2238
2182
 
2239
2183
  if (new_capacity != capacity) {
2240
2184
  if (len > new_capacity) {
@@ -2244,7 +2188,7 @@ public:
2244
2188
  len = new_capacity;
2245
2189
  }
2246
2190
 
2247
- ptr = (T *)ResizeRaw(allocator, ptr, capacity * RG_SIZE(T), new_capacity * RG_SIZE(T));
2191
+ ptr = (T *)ResizeRaw(allocator, ptr, capacity * K_SIZE(T), new_capacity * K_SIZE(T));
2248
2192
  capacity = new_capacity;
2249
2193
  }
2250
2194
  }
@@ -2258,18 +2202,18 @@ public:
2258
2202
 
2259
2203
  T *Grow(Size reserve_capacity = 1)
2260
2204
  {
2261
- RG_ASSERT(capacity >= 0);
2262
- RG_ASSERT(reserve_capacity >= 0);
2263
- RG_ASSERT((size_t)capacity + (size_t)reserve_capacity <= RG_SIZE_MAX);
2205
+ K_ASSERT(capacity >= 0);
2206
+ K_ASSERT(reserve_capacity >= 0);
2207
+ K_ASSERT((size_t)capacity + (size_t)reserve_capacity <= K_SIZE_MAX);
2264
2208
 
2265
2209
  if (reserve_capacity > capacity - len) {
2266
2210
  Size needed = capacity + reserve_capacity;
2267
2211
 
2268
2212
  Size new_capacity;
2269
- if (needed <= RG_HEAPARRAY_BASE_CAPACITY) {
2270
- new_capacity = RG_HEAPARRAY_BASE_CAPACITY;
2213
+ if (needed <= K_HEAPARRAY_BASE_CAPACITY) {
2214
+ new_capacity = K_HEAPARRAY_BASE_CAPACITY;
2271
2215
  } else {
2272
- new_capacity = (Size)((double)(needed - 1) * RG_HEAPARRAY_GROWTH_FACTOR);
2216
+ new_capacity = (Size)((double)(needed - 1) * K_HEAPARRAY_GROWTH_FACTOR);
2273
2217
  }
2274
2218
 
2275
2219
  SetCapacity(new_capacity);
@@ -2291,7 +2235,7 @@ public:
2291
2235
  len++;
2292
2236
  }
2293
2237
  } else {
2294
- MemSet(first, 0, count * RG_SIZE(T));
2238
+ MemSet(first, 0, count * K_SIZE(T));
2295
2239
  len += count;
2296
2240
  }
2297
2241
 
@@ -2336,7 +2280,7 @@ public:
2336
2280
 
2337
2281
  void RemoveFrom(Size first)
2338
2282
  {
2339
- RG_ASSERT(first >= 0 && first <= len);
2283
+ K_ASSERT(first >= 0 && first <= len);
2340
2284
 
2341
2285
  if constexpr(!std::is_trivial<T>::value) {
2342
2286
  for (Size i = first; i < len; i++) {
@@ -2347,7 +2291,7 @@ public:
2347
2291
  }
2348
2292
  void RemoveLast(Size count = 1)
2349
2293
  {
2350
- RG_ASSERT(count >= 0 && count <= len);
2294
+ K_ASSERT(count >= 0 && count <= len);
2351
2295
  RemoveFrom(len - count);
2352
2296
  }
2353
2297
 
@@ -2377,7 +2321,7 @@ public:
2377
2321
 
2378
2322
  template <typename T, Size BucketSize = 64, typename AllocatorType = BlockAllocator>
2379
2323
  class BucketArray {
2380
- RG_DELETE_COPY(BucketArray)
2324
+ K_DELETE_COPY(BucketArray)
2381
2325
 
2382
2326
  public:
2383
2327
  struct Bucket {
@@ -2495,8 +2439,8 @@ public:
2495
2439
  BucketArray &operator=(BucketArray &&other)
2496
2440
  {
2497
2441
  ClearBucketsAndValues();
2498
- MemMove(this, &other, RG_SIZE(other));
2499
- MemSet(&other, 0, RG_SIZE(other));
2442
+ MemMove(this, &other, K_SIZE(other));
2443
+ MemSet(&other, 0, K_SIZE(other));
2500
2444
  return *this;
2501
2445
  }
2502
2446
 
@@ -2529,7 +2473,7 @@ public:
2529
2473
 
2530
2474
  const T &operator[](Size idx) const
2531
2475
  {
2532
- RG_ASSERT(idx >= 0 && idx < count);
2476
+ K_ASSERT(idx >= 0 && idx < count);
2533
2477
 
2534
2478
  idx += offset;
2535
2479
  Size bucket_idx = idx / BucketSize;
@@ -2547,7 +2491,7 @@ public:
2547
2491
  if (bucket_idx >= buckets.len) {
2548
2492
  Bucket *new_bucket = AllocateOne<Bucket>(buckets.allocator);
2549
2493
  new (&new_bucket->allocator) AllocatorType();
2550
- new_bucket->values = (T *)AllocateRaw(&new_bucket->allocator, BucketSize * RG_SIZE(T));
2494
+ new_bucket->values = (T *)AllocateRaw(&new_bucket->allocator, BucketSize * K_SIZE(T));
2551
2495
 
2552
2496
  buckets.Append(new_bucket);
2553
2497
  }
@@ -2572,7 +2516,7 @@ public:
2572
2516
 
2573
2517
  void RemoveFrom(Size from)
2574
2518
  {
2575
- RG_ASSERT(from >= 0 && from <= count);
2519
+ K_ASSERT(from >= 0 && from <= count);
2576
2520
 
2577
2521
  if (from == count)
2578
2522
  return;
@@ -2598,13 +2542,13 @@ public:
2598
2542
  }
2599
2543
  void RemoveLast(Size n = 1)
2600
2544
  {
2601
- RG_ASSERT(n >= 0 && n <= count);
2545
+ K_ASSERT(n >= 0 && n <= count);
2602
2546
  RemoveFrom(count - n);
2603
2547
  }
2604
2548
 
2605
2549
  void RemoveFirst(Size n = 1)
2606
2550
  {
2607
- RG_ASSERT(n >= 0 && n <= count);
2551
+ K_ASSERT(n >= 0 && n <= count);
2608
2552
 
2609
2553
  if (n == count) {
2610
2554
  Clear();
@@ -2623,7 +2567,7 @@ public:
2623
2567
  DeleteBucket(buckets[i]);
2624
2568
  }
2625
2569
  MemMove(&buckets[0], &buckets[end_bucket_idx],
2626
- (buckets.len - end_bucket_idx) * RG_SIZE(Bucket *));
2570
+ (buckets.len - end_bucket_idx) * K_SIZE(Bucket *));
2627
2571
  buckets.RemoveLast(end_bucket_idx);
2628
2572
  }
2629
2573
 
@@ -2650,7 +2594,7 @@ public:
2650
2594
 
2651
2595
  count = (it.bucket_idx * BucketSize) + it.bucket_offset - offset;
2652
2596
 
2653
- RG_ASSERT(it == end());
2597
+ K_ASSERT(it == end());
2654
2598
  }
2655
2599
  void RemoveFrom(const Iterator<const BucketArray<T, BucketSize>> &it) { return RemoveFrom((iterator_type)it); }
2656
2600
 
@@ -2670,7 +2614,7 @@ public:
2670
2614
  DeleteBucket(buckets[i]);
2671
2615
  }
2672
2616
  MemMove(&buckets[0], &buckets[it.bucket_idx],
2673
- (buckets.len - it.bucket_idx) * RG_SIZE(Bucket *));
2617
+ (buckets.len - it.bucket_idx) * K_SIZE(Bucket *));
2674
2618
  buckets.RemoveLast(it.bucket_idx);
2675
2619
  }
2676
2620
 
@@ -2736,18 +2680,18 @@ public:
2736
2680
 
2737
2681
  ValueType &operator*()
2738
2682
  {
2739
- RG_ASSERT(!table->IsEmpty(offset));
2683
+ K_ASSERT(!table->IsEmpty(offset));
2740
2684
  return table->data[offset];
2741
2685
  }
2742
2686
  const ValueType &operator*() const
2743
2687
  {
2744
- RG_ASSERT(!table->IsEmpty(offset));
2688
+ K_ASSERT(!table->IsEmpty(offset));
2745
2689
  return table->data[offset];
2746
2690
  }
2747
2691
 
2748
2692
  Iterator &operator++()
2749
2693
  {
2750
- RG_ASSERT(offset < table->capacity);
2694
+ K_ASSERT(offset < table->capacity);
2751
2695
  while (++offset < table->capacity && table->IsEmpty(offset));
2752
2696
  return *this;
2753
2697
  }
@@ -2793,8 +2737,8 @@ public:
2793
2737
  HashTable &operator=(HashTable &&other)
2794
2738
  {
2795
2739
  Clear();
2796
- MemMove(this, &other, RG_SIZE(other));
2797
- MemSet(&other, 0, RG_SIZE(other));
2740
+ MemMove(this, &other, K_SIZE(other));
2741
+ MemSet(&other, 0, K_SIZE(other));
2798
2742
  return *this;
2799
2743
  }
2800
2744
  HashTable(const HashTable &other) { *this = other; }
@@ -2829,7 +2773,7 @@ public:
2829
2773
 
2830
2774
  count = 0;
2831
2775
  if (used) {
2832
- size_t len = (size_t)(capacity + (RG_SIZE(size_t) * 8) - 1) / RG_SIZE(size_t);
2776
+ size_t len = (size_t)(capacity + (K_SIZE(size_t) * 8) - 1) / K_SIZE(size_t);
2833
2777
  MemSet(used, 0, len);
2834
2778
  }
2835
2779
  }
@@ -2886,7 +2830,7 @@ public:
2886
2830
  return ptr;
2887
2831
  }
2888
2832
 
2889
- ValueType *TrySet(const ValueType &value, bool *out_inserted = nullptr)
2833
+ ValueType *InsertOrGet(const ValueType &value, bool *out_inserted = nullptr)
2890
2834
  {
2891
2835
  const KeyType &key = Handler::GetKey(value);
2892
2836
 
@@ -2902,7 +2846,7 @@ public:
2902
2846
  }
2903
2847
  return ptr;
2904
2848
  }
2905
- ValueType *TrySetDefault(const KeyType &key, bool *out_inserted = nullptr)
2849
+ ValueType *InsertOrGetDefault(const KeyType &key, bool *out_inserted = nullptr)
2906
2850
  {
2907
2851
  bool inserted;
2908
2852
  ValueType *ptr = Insert(key, &inserted);
@@ -2923,7 +2867,7 @@ public:
2923
2867
  return;
2924
2868
 
2925
2869
  Size clear_idx = it - data;
2926
- RG_ASSERT(!IsEmpty(clear_idx));
2870
+ K_ASSERT(!IsEmpty(clear_idx));
2927
2871
 
2928
2872
  it->~ValueType();
2929
2873
  count--;
@@ -2943,7 +2887,7 @@ public:
2943
2887
 
2944
2888
  MarkUsed(clear_idx);
2945
2889
  MarkEmpty(idx);
2946
- MemMove(&data[clear_idx], &data[idx], RG_SIZE(*data));
2890
+ MemMove(&data[clear_idx], &data[idx], K_SIZE(*data));
2947
2891
 
2948
2892
  clear_idx = idx;
2949
2893
  }
@@ -2958,9 +2902,9 @@ public:
2958
2902
  if (count) {
2959
2903
  Size new_capacity = (Size)1 << (64 - CountLeadingZeros((uint64_t)count));
2960
2904
 
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) {
2905
+ if (new_capacity < K_HASHTABLE_BASE_CAPACITY) {
2906
+ new_capacity = K_HASHTABLE_BASE_CAPACITY;
2907
+ } else if (count > (double)new_capacity * K_HASHTABLE_MAX_LOAD_FACTOR) {
2964
2908
  new_capacity *= 2;
2965
2909
  }
2966
2910
 
@@ -3004,7 +2948,7 @@ private:
3004
2948
  Size idx = HashToIndex(hash);
3005
2949
  ValueType *it = Find(&idx, key);
3006
2950
  if (!it) {
3007
- if (count >= (Size)((double)capacity * RG_HASHTABLE_MAX_LOAD_FACTOR)) {
2951
+ if (count >= (Size)((double)capacity * K_HASHTABLE_MAX_LOAD_FACTOR)) {
3008
2952
  Rehash(capacity << 1);
3009
2953
  idx = HashToIndex(hash);
3010
2954
  while (!IsEmpty(idx)) {
@@ -3021,7 +2965,7 @@ private:
3021
2965
  return it;
3022
2966
  }
3023
2967
  } else {
3024
- Rehash(RG_HASHTABLE_BASE_CAPACITY);
2968
+ Rehash(K_HASHTABLE_BASE_CAPACITY);
3025
2969
 
3026
2970
  Size idx = HashToIndex(hash);
3027
2971
  count++;
@@ -3036,7 +2980,7 @@ private:
3036
2980
  {
3037
2981
  if (new_capacity == capacity)
3038
2982
  return;
3039
- RG_ASSERT(count <= new_capacity);
2983
+ K_ASSERT(count <= new_capacity);
3040
2984
 
3041
2985
  size_t *old_used = used;
3042
2986
  ValueType *old_data = data;
@@ -3044,9 +2988,9 @@ private:
3044
2988
 
3045
2989
  if (new_capacity) {
3046
2990
  used = (size_t *)AllocateRaw(allocator,
3047
- (new_capacity + (RG_SIZE(size_t) * 8) - 1) / RG_SIZE(size_t),
2991
+ (new_capacity + (K_SIZE(size_t) * 8) - 1) / K_SIZE(size_t),
3048
2992
  (int)AllocFlag::Zero);
3049
- data = (ValueType *)AllocateRaw(allocator, new_capacity * RG_SIZE(ValueType));
2993
+ data = (ValueType *)AllocateRaw(allocator, new_capacity * K_SIZE(ValueType));
3050
2994
  for (Size i = 0; i < new_capacity; i++) {
3051
2995
  new (&data[i]) ValueType();
3052
2996
  }
@@ -3068,22 +3012,22 @@ private:
3068
3012
  capacity = 0;
3069
3013
  }
3070
3014
 
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));
3015
+ ReleaseRaw(allocator, old_used, (old_capacity + (K_SIZE(size_t) * 8) - 1) / K_SIZE(size_t));
3016
+ ReleaseRaw(allocator, old_data, old_capacity * K_SIZE(ValueType));
3073
3017
  }
3074
3018
 
3075
3019
  inline void MarkUsed(Size idx)
3076
3020
  {
3077
- used[idx / (RG_SIZE(size_t) * 8)] |= (1ull << (idx % (RG_SIZE(size_t) * 8)));
3021
+ used[idx / (K_SIZE(size_t) * 8)] |= (1ull << (idx % (K_SIZE(size_t) * 8)));
3078
3022
  }
3079
3023
  inline void MarkEmpty(Size idx)
3080
3024
  {
3081
- used[idx / (RG_SIZE(size_t) * 8)] &= ~(1ull << (idx % (RG_SIZE(size_t) * 8)));
3025
+ used[idx / (K_SIZE(size_t) * 8)] &= ~(1ull << (idx % (K_SIZE(size_t) * 8)));
3082
3026
  }
3083
3027
 
3084
3028
  inline bool IsEmpty(size_t *used, Size idx) const
3085
3029
  {
3086
- bool empty = !(used[idx / (RG_SIZE(size_t) * 8)] & (1ull << (idx % (RG_SIZE(size_t) * 8))));
3030
+ bool empty = !(used[idx / (K_SIZE(size_t) * 8)] & (1ull << (idx % (K_SIZE(size_t) * 8))));
3087
3031
  return empty;
3088
3032
  }
3089
3033
  inline bool IsEmpty(Size idx) const { return IsEmpty(used, idx); }
@@ -3167,7 +3111,7 @@ DEFINE_INTEGER_HASH_TRAITS_32(unsigned int, constexpr);
3167
3111
  #endif
3168
3112
  DEFINE_INTEGER_HASH_TRAITS_64(long long, constexpr);
3169
3113
  DEFINE_INTEGER_HASH_TRAITS_64(unsigned long long, constexpr);
3170
- #if RG_SIZE_MAX == INT64_MAX
3114
+ #if K_SIZE_MAX == INT64_MAX
3171
3115
  DEFINE_INTEGER_HASH_TRAITS_64(void *);
3172
3116
  DEFINE_INTEGER_HASH_TRAITS_64(const void *);
3173
3117
  #else
@@ -3194,7 +3138,7 @@ static constexpr inline uint64_t HashStr(Span<const char> str)
3194
3138
  } :
3195
3139
  #endif
3196
3140
  [](const char *p) {
3197
- #if defined(RG_BIG_ENDIAN)
3141
+ #if defined(K_BIG_ENDIAN)
3198
3142
  uint64_t result = ((uint64_t)p[0] << 56) |
3199
3143
  ((uint64_t)p[1] << 48) |
3200
3144
  ((uint64_t)p[2] << 40) |
@@ -3275,7 +3219,7 @@ public:
3275
3219
  static constexpr bool Test(Span<const char> key1, const char * key2) { return key1 == key2; }
3276
3220
  };
3277
3221
 
3278
- #define RG_HASHTABLE_HANDLER_EX_N(Name, ValueType, KeyType, KeyMember, HashFunc, TestFunc) \
3222
+ #define K_HASHTABLE_HANDLER_EX_N(Name, ValueType, KeyType, KeyMember, HashFunc, TestFunc) \
3279
3223
  class Name { \
3280
3224
  public: \
3281
3225
  static constexpr KeyType GetKey(const ValueType &value) \
@@ -3289,16 +3233,16 @@ public:
3289
3233
  static constexpr bool TestKeys(KeyType key1, TestKey key2) \
3290
3234
  { return TestFunc((key1), (key2)); } \
3291
3235
  }
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)
3236
+ #define K_HASHTABLE_HANDLER_EX(ValueType, KeyType, KeyMember, HashFunc, TestFunc) \
3237
+ K_HASHTABLE_HANDLER_EX_N(HashHandler, ValueType, KeyType, KeyMember, HashFunc, TestFunc)
3238
+ #define K_HASHTABLE_HANDLER(ValueType, KeyMember) \
3239
+ K_HASHTABLE_HANDLER_EX(ValueType, decltype(ValueType::KeyMember), KeyMember, HashTraits<decltype(ValueType::KeyMember)>::Hash, HashTraits<decltype(ValueType::KeyMember)>::Test)
3240
+ #define K_HASHTABLE_HANDLER_N(Name, ValueType, KeyMember) \
3241
+ K_HASHTABLE_HANDLER_EX_N(Name, ValueType, decltype(ValueType::KeyMember), KeyMember, HashTraits<decltype(ValueType::KeyMember)>::Hash, HashTraits<decltype(ValueType::KeyMember)>::Test)
3242
+ #define K_HASHTABLE_HANDLER_T(ValueType, KeyType, KeyMember) \
3243
+ K_HASHTABLE_HANDLER_EX(ValueType, KeyType, KeyMember, HashTraits<KeyType>::Hash, HashTraits<KeyType>::Test)
3244
+ #define K_HASHTABLE_HANDLER_NT(Name, ValueType, KeyType, KeyMember) \
3245
+ K_HASHTABLE_HANDLER_EX_N(Name, ValueType, KeyType, KeyMember, HashTraits<KeyType>::Hash, HashTraits<KeyType>::Test)
3302
3246
 
3303
3247
  template <typename KeyType, typename ValueType>
3304
3248
  class HashMap {
@@ -3307,7 +3251,7 @@ public:
3307
3251
  KeyType key;
3308
3252
  ValueType value;
3309
3253
 
3310
- RG_HASHTABLE_HANDLER(Bucket, key);
3254
+ K_HASHTABLE_HANDLER(Bucket, key);
3311
3255
  };
3312
3256
 
3313
3257
  HashTable<KeyType, Bucket> table;
@@ -3346,15 +3290,15 @@ public:
3346
3290
  return table_it;
3347
3291
  }
3348
3292
 
3349
- ValueType *TrySet(const KeyType &key, const ValueType &value, bool *out_inserted = nullptr)
3293
+ ValueType *InsertOrGet(const KeyType &key, const ValueType &value, bool *out_inserted = nullptr)
3350
3294
  {
3351
- Bucket *ptr = table.TrySet({ key, value }, out_inserted);
3295
+ Bucket *ptr = table.InsertOrGet({ key, value }, out_inserted);
3352
3296
  return &ptr->value;
3353
3297
  }
3354
- Bucket *TrySetDefault(const KeyType &key, bool *out_inserted = nullptr)
3298
+ Bucket *InsertOrGetDefault(const KeyType &key, bool *out_inserted = nullptr)
3355
3299
  {
3356
3300
  bool inserted;
3357
- Bucket *ptr = table.TrySetDefault(key, &inserted);
3301
+ Bucket *ptr = table.InsertOrGetDefault(key, &inserted);
3358
3302
 
3359
3303
  if (inserted) {
3360
3304
  ptr->key = key;
@@ -3417,14 +3361,23 @@ public:
3417
3361
  { return table.FindValue(value, default_value); }
3418
3362
 
3419
3363
  ValueType *Set(const ValueType &value) { return table.Set(value); }
3420
- ValueType *TrySet(const ValueType &value, bool *out_inserted = nullptr)
3421
- { return table.TrySet(value, out_inserted); }
3364
+
3365
+ ValueType *InsertOrGet(const ValueType &value, bool *out_inserted = nullptr)
3366
+ { return table.InsertOrGet(value, out_inserted); }
3367
+ bool InsertOrFail(const ValueType &value)
3368
+ {
3369
+ bool inserted;
3370
+ InsertOrGet(value, &inserted);
3371
+ return inserted;
3372
+ }
3422
3373
 
3423
3374
  void Remove(ValueType *it) { table.Remove(it); }
3424
3375
  template <typename T = ValueType>
3425
3376
  void Remove(const T &value) { Remove(Find(value)); }
3426
3377
 
3427
3378
  void Trim() { table.Trim(); }
3379
+
3380
+ private:
3428
3381
  };
3429
3382
 
3430
3383
  // XXX: Switch to perfect hashing later on
@@ -3436,13 +3389,13 @@ public:
3436
3389
  ValueType value;
3437
3390
  };
3438
3391
 
3439
- size_t used[(N + (RG_SIZE(size_t) * 8) - 1) / RG_SIZE(size_t)] = {};
3392
+ size_t used[(N + (K_SIZE(size_t) * 8) - 1) / K_SIZE(size_t)] = {};
3440
3393
  Bucket data[N] = {};
3441
3394
  Size count = 0;
3442
3395
 
3443
3396
  constexpr ConstMap(std::initializer_list<Bucket> l)
3444
3397
  {
3445
- RG_CRITICAL(l.size() <= N, "ConstMap<%1> cannot be store %2 values", N, l.size());
3398
+ K_CRITICAL(l.size() <= N, "ConstMap<%1> cannot be store %2 values", N, l.size());
3446
3399
 
3447
3400
  for (const Bucket &it: l) {
3448
3401
  Bucket *bucket = Insert(it.key);
@@ -3516,11 +3469,11 @@ private:
3516
3469
 
3517
3470
  constexpr void MarkUsed(Size idx)
3518
3471
  {
3519
- used[idx / (RG_SIZE(size_t) * 8)] |= (1ull << (idx % (RG_SIZE(size_t) * 8)));
3472
+ used[idx / (K_SIZE(size_t) * 8)] |= (1ull << (idx % (K_SIZE(size_t) * 8)));
3520
3473
  }
3521
3474
  constexpr bool IsEmpty(Size idx) const
3522
3475
  {
3523
- bool empty = !(used[idx / (RG_SIZE(size_t) * 8)] & (1ull << (idx % (RG_SIZE(size_t) * 8))));
3476
+ bool empty = !(used[idx / (K_SIZE(size_t) * 8)] & (1ull << (idx % (K_SIZE(size_t) * 8))));
3524
3477
  return empty;
3525
3478
  }
3526
3479
 
@@ -3537,7 +3490,7 @@ private:
3537
3490
  union LocalDate {
3538
3491
  int32_t value;
3539
3492
  struct {
3540
- #if defined(RG_BIG_ENDIAN)
3493
+ #if defined(K_BIG_ENDIAN)
3541
3494
  int16_t year;
3542
3495
  int8_t month;
3543
3496
  int8_t day;
@@ -3549,12 +3502,12 @@ union LocalDate {
3549
3502
  } st;
3550
3503
 
3551
3504
  LocalDate() = default;
3552
- #if defined(RG_BIG_ENDIAN)
3505
+ #if defined(K_BIG_ENDIAN)
3553
3506
  LocalDate(int16_t year, int8_t month, int8_t day)
3554
- : st({ year, month, day }) { RG_ASSERT(IsValid()); }
3507
+ : st({ year, month, day }) { K_ASSERT(IsValid()); }
3555
3508
  #else
3556
3509
  LocalDate(int16_t year, int8_t month, int8_t day)
3557
- : st({ day, month, year }) { RG_ASSERT(IsValid()); }
3510
+ : st({ day, month, year }) { K_ASSERT(IsValid()); }
3558
3511
  #endif
3559
3512
 
3560
3513
  static inline bool IsLeapYear(int16_t year)
@@ -3651,6 +3604,13 @@ static inline int64_t GetClockCounter()
3651
3604
  int64_t counter = ((int64_t)counter_high << 32) | counter_low;
3652
3605
  return counter;
3653
3606
  }
3607
+ #elif defined(__aarch64__)
3608
+ static inline int64_t GetClockCounter()
3609
+ {
3610
+ uint64_t counter;
3611
+ __asm__ __volatile__ ("mrs %0, cntvct_el0" : "=r" (counter));
3612
+ return counter;
3613
+ }
3654
3614
  #endif
3655
3615
 
3656
3616
  struct TimeSpec {
@@ -3676,10 +3636,11 @@ int64_t ComposeTimeUTC(const TimeSpec &spec);
3676
3636
  // ------------------------------------------------------------------------
3677
3637
 
3678
3638
  enum class FmtType {
3679
- Str1,
3680
- Str2,
3681
- Buffer,
3639
+ Str,
3640
+ PadStr,
3641
+ RepeatStr,
3682
3642
  Char,
3643
+ Buffer,
3683
3644
  Custom,
3684
3645
  Bool,
3685
3646
  Integer,
@@ -3690,15 +3651,19 @@ enum class FmtType {
3690
3651
  Octal,
3691
3652
  BigHex,
3692
3653
  SmallHex,
3654
+ BigBytes,
3655
+ SmallBytes,
3693
3656
  MemorySize,
3694
3657
  DiskSize,
3695
3658
  Date,
3696
3659
  TimeISO,
3697
3660
  TimeNice,
3698
- Random,
3661
+ List,
3699
3662
  FlagNames,
3700
3663
  FlagOptions,
3701
- Span
3664
+ Random,
3665
+ SafeStr,
3666
+ SafeChar
3702
3667
  };
3703
3668
 
3704
3669
  template <typename T>
@@ -3733,7 +3698,7 @@ public:
3733
3698
  template <typename T>
3734
3699
  explicit FmtCustom(const T &obj)
3735
3700
  {
3736
- static_assert(RG_SIZE(*this) <= RG_SIZE(raw));
3701
+ static_assert(K_SIZE(*this) <= K_SIZE(raw));
3737
3702
  new (raw) Concrete<T>(&obj, &FmtTraits<T>::Format);
3738
3703
  }
3739
3704
 
@@ -3748,14 +3713,18 @@ class FmtArg {
3748
3713
  public:
3749
3714
  FmtType type;
3750
3715
  union {
3751
- const char *str1;
3752
- Span<const char> str2;
3716
+ Span<const char> str;
3717
+ struct {
3718
+ const char *str;
3719
+ int count;
3720
+ } repeat;
3753
3721
  char buf[32];
3754
3722
  char ch;
3755
3723
  FmtCustom custom;
3756
3724
  bool b;
3757
3725
  int64_t i;
3758
3726
  uint64_t u;
3727
+ Span<const uint8_t> hex;
3759
3728
  struct {
3760
3729
  float value;
3761
3730
  int min_prec;
@@ -3783,68 +3752,123 @@ public:
3783
3752
  Span<const struct OptionDesc> options;
3784
3753
  } u;
3785
3754
  const char *separator;
3786
- } flags;
3787
-
3788
- struct {
3789
- FmtType type;
3790
- int type_len;
3791
- const void *ptr;
3792
- Size len;
3793
- const char *separator;
3794
- } span;
3755
+ } list;
3795
3756
  } u;
3796
3757
 
3797
- int repeat = 1;
3798
- int pad_len = 0;
3799
- char pad_char = 0;
3758
+ int pad = 0;
3759
+ char padding = 0;
3800
3760
 
3801
3761
  FmtArg() = default;
3802
- FmtArg(std::nullptr_t) : type(FmtType::Str1) { u.str1 = "(null)"; }
3803
- FmtArg(const char *str) : type(FmtType::Str1) { u.str1 = str ? str : "(null)"; }
3804
- FmtArg(Span<const char> str) : type(FmtType::Str2) { u.str2 = str; }
3805
- FmtArg(char c) : type(FmtType::Char) { u.ch = c; }
3806
- FmtArg(const FmtCustom &custom) : type(FmtType::Custom) { u.custom = custom; }
3807
- FmtArg(bool b) : type(FmtType::Bool) { u.b = b; }
3808
- FmtArg(unsigned char i) : type(FmtType::Unsigned) { u.u = i; }
3809
- FmtArg(short i) : type(FmtType::Integer) { u.i = i; }
3810
- FmtArg(unsigned short i) : type(FmtType::Unsigned) { u.u = i; }
3811
- FmtArg(int i) : type(FmtType::Integer) { u.i = i; }
3812
- FmtArg(unsigned int i) : type(FmtType::Unsigned) { u.u = i; }
3813
- FmtArg(long i) : type(FmtType::Integer) { u.i = i; }
3814
- FmtArg(unsigned long i) : type(FmtType::Unsigned) { u.u = i; }
3815
- FmtArg(long long i) : type(FmtType::Integer) { u.i = i; }
3816
- FmtArg(unsigned long long i) : type(FmtType::Unsigned) { u.u = i; }
3817
- FmtArg(float f) : type(FmtType::Float) { u.f = { f, 0, INT_MAX }; }
3818
- FmtArg(double d) : type(FmtType::Double) { u.d = { d, 0, INT_MAX }; }
3819
- FmtArg(const void *ptr) : type(FmtType::BigHex) { u.u = (uint64_t)ptr; }
3820
- FmtArg(const LocalDate &date) : type(FmtType::Date) { u.date = date; }
3821
-
3822
- FmtArg &Repeat(int new_repeat) { repeat = new_repeat; return *this; }
3823
- FmtArg &Pad(int len, char c = ' ') { pad_char = c; pad_len = len; return *this; }
3824
- FmtArg &Pad0(int len) { return Pad(len, '0'); }
3762
+ FmtArg(const FmtArg &other) = default;
3763
+ FmtArg(std::nullptr_t) : FmtArg(FmtType::Str) { u.str = "(null)"; }
3764
+ FmtArg(const char *str) : FmtArg(FmtType::Str) { u.str = str ? str : "(null)"; }
3765
+ FmtArg(Span<const char> str) : FmtArg(FmtType::Str) { u.str = str; }
3766
+ FmtArg(char c) : FmtArg(FmtType::Char) { u.ch = c; }
3767
+ FmtArg(const FmtCustom &custom) : FmtArg(FmtType::Custom) { u.custom = custom; }
3768
+ FmtArg(bool b) : FmtArg(FmtType::Bool) { u.b = b; }
3769
+ FmtArg(unsigned char i) : FmtArg(FmtType::Unsigned) { u.u = i; }
3770
+ FmtArg(short i) : FmtArg(FmtType::Integer) { u.i = i; }
3771
+ FmtArg(unsigned short i) : FmtArg(FmtType::Unsigned) { u.u = i; }
3772
+ FmtArg(int i) : FmtArg(FmtType::Integer) { u.i = i; }
3773
+ FmtArg(unsigned int i) : FmtArg(FmtType::Unsigned) { u.u = i; }
3774
+ FmtArg(long i) : FmtArg(FmtType::Integer) { u.i = i; }
3775
+ FmtArg(unsigned long i) : FmtArg(FmtType::Unsigned) { u.u = i; }
3776
+ FmtArg(long long i) : FmtArg(FmtType::Integer) { u.i = i; }
3777
+ FmtArg(unsigned long long i) : FmtArg(FmtType::Unsigned) { u.u = i; }
3778
+ FmtArg(float f) : FmtArg(FmtType::Float) { u.f = { f, 0, INT_MAX }; }
3779
+ FmtArg(double d) : FmtArg(FmtType::Double) { u.d = { d, 0, INT_MAX }; }
3780
+ FmtArg(const void *ptr) : FmtArg(FmtType::BigHex) { u.u = (uint64_t)ptr; }
3781
+ FmtArg(const LocalDate &date) : FmtArg(FmtType::Date) { u.date = date; }
3782
+
3783
+ protected:
3784
+ FmtArg(FmtType type) : type(type) {}
3785
+ };
3786
+
3787
+ class FmtSafe: public FmtArg {
3788
+ public:
3789
+ FmtSafe() = default;
3790
+ FmtSafe(FmtArg arg) : FmtArg(arg) {}
3791
+ FmtSafe(std::nullptr_t) : FmtArg(FmtType::Str) { u.str = "(null)"; }
3792
+ FmtSafe(const char *str) : FmtArg(FmtType::SafeStr) { u.str = str ? str : "(null)"; } // safe
3793
+ FmtSafe(Span<const char> str) : FmtArg(FmtType::SafeStr) { u.str = str; } // safe
3794
+ FmtSafe(char c) : FmtArg(FmtType::SafeChar) { u.ch = c; } // safe
3795
+ FmtSafe(const FmtCustom &custom) : FmtArg(custom) {}
3796
+ FmtSafe(bool b) : FmtArg(b) {}
3797
+ FmtSafe(unsigned char i) : FmtArg(i) {}
3798
+ FmtSafe(short i) : FmtArg(i) {}
3799
+ FmtSafe(unsigned short i) : FmtArg(i) {}
3800
+ FmtSafe(int i) : FmtArg(i) {}
3801
+ FmtSafe(unsigned int i) : FmtArg(i) {}
3802
+ FmtSafe(long i) : FmtArg(i) {}
3803
+ FmtSafe(unsigned long i) : FmtArg(i) {}
3804
+ FmtSafe(long long i) : FmtArg(i) {}
3805
+ FmtSafe(unsigned long long i) : FmtArg(i) {}
3806
+ FmtSafe(float f) : FmtArg(f) {}
3807
+ FmtSafe(double d) : FmtArg(d) {}
3808
+ FmtSafe(const void *ptr) : FmtArg(ptr) {}
3809
+ FmtSafe(const LocalDate &date) : FmtArg(date) {}
3825
3810
  };
3826
3811
 
3827
- static inline FmtArg FmtBin(uint64_t u)
3812
+ static inline FmtArg FmtInt(long long i, int pad = 0, char padding = '0')
3813
+ {
3814
+ FmtArg arg;
3815
+ arg.type = FmtType::Integer;
3816
+ arg.u.i = i;
3817
+ arg.pad = pad;
3818
+ arg.padding = padding;
3819
+ return arg;
3820
+ }
3821
+ static inline FmtArg FmtInt(unsigned long long u, int pad = 0, char padding = '0')
3822
+ {
3823
+ FmtArg arg;
3824
+ arg.type = FmtType::Unsigned;
3825
+ arg.u.u = u;
3826
+ arg.pad = pad;
3827
+ arg.padding = padding;
3828
+ return arg;
3829
+ }
3830
+ static inline FmtArg FmtInt(unsigned char u, int pad = 0, char padding = '0') { return FmtInt((unsigned long long)u, pad, padding); }
3831
+ static inline FmtArg FmtInt(short i, int pad = 0, char padding = '0') { return FmtInt((long long)i, pad, padding); }
3832
+ static inline FmtArg FmtInt(unsigned short u, int pad = 0, char padding = '0') { return FmtInt((unsigned long long)u, pad, padding); }
3833
+ static inline FmtArg FmtInt(int i, int pad = 0, char padding = '0') { return FmtInt((long long)i, pad, padding); }
3834
+ static inline FmtArg FmtInt(unsigned int u, int pad = 0, char padding = '0') { return FmtInt((unsigned long long)u, pad, padding); }
3835
+ static inline FmtArg FmtInt(long i, int pad = 0, char padding = '0') { return FmtInt((long long)i, pad, padding); }
3836
+ static inline FmtArg FmtInt(unsigned long u, int pad = 0, char padding = '0') { return FmtInt((unsigned long long)u, pad, padding); }
3837
+
3838
+ static inline FmtArg FmtBin(uint64_t u, int pad = 0, char padding = '0')
3828
3839
  {
3829
3840
  FmtArg arg;
3830
3841
  arg.type = FmtType::Binary;
3831
3842
  arg.u.u = u;
3843
+ arg.pad = pad;
3844
+ arg.padding = padding;
3832
3845
  return arg;
3833
3846
  }
3834
- static inline FmtArg FmtOctal(uint64_t u)
3847
+ static inline FmtArg FmtOctal(uint64_t u, int pad = 0, char padding = '0')
3835
3848
  {
3836
3849
  FmtArg arg;
3837
3850
  arg.type = FmtType::Octal;
3838
3851
  arg.u.u = u;
3852
+ arg.pad = pad;
3853
+ arg.padding = padding;
3839
3854
  return arg;
3840
3855
  }
3841
- static inline FmtArg FmtHex(uint64_t u, FmtType type = FmtType::BigHex)
3856
+ static inline FmtArg FmtHex(uint64_t u, int pad = 0, char padding = '0')
3842
3857
  {
3843
- RG_ASSERT(type == FmtType::BigHex || type == FmtType::SmallHex);
3844
-
3845
3858
  FmtArg arg;
3846
- arg.type = type;
3859
+ arg.type = FmtType::BigHex;
3847
3860
  arg.u.u = u;
3861
+ arg.pad = pad;
3862
+ arg.padding = padding;
3863
+ return arg;
3864
+ }
3865
+ static inline FmtArg FmtHexSmall(uint64_t u, int pad = 0, char padding = '0')
3866
+ {
3867
+ FmtArg arg;
3868
+ arg.type = FmtType::SmallHex;
3869
+ arg.u.u = u;
3870
+ arg.pad = pad;
3871
+ arg.padding = padding;
3848
3872
  return arg;
3849
3873
  }
3850
3874
 
@@ -3905,56 +3929,77 @@ static inline FmtArg FmtTimeNice(TimeSpec spec, bool ms = false)
3905
3929
  return arg;
3906
3930
  }
3907
3931
 
3908
- static inline FmtArg FmtRandom(Size len, const char *chars = nullptr)
3932
+ static inline FmtArg FmtList(Span<const char *const> names, const char *sep = ", ")
3909
3933
  {
3910
- RG_ASSERT(len < 256);
3911
- len = std::min(len, (Size)256);
3912
-
3913
3934
  FmtArg arg;
3914
- arg.type = FmtType::Random;
3915
- arg.u.random.len = len;
3916
- arg.u.random.chars = chars;
3935
+ arg.type = FmtType::List;
3936
+ arg.u.list.u.names = names;
3937
+ arg.u.list.separator = sep;
3917
3938
  return arg;
3918
3939
  }
3919
-
3920
3940
  static inline FmtArg FmtFlags(uint64_t flags, Span<const char *const> names, const char *sep = ", ")
3921
3941
  {
3922
3942
  FmtArg arg;
3923
3943
  arg.type = FmtType::FlagNames;
3924
- arg.u.flags.flags = flags & ((1ull << names.len) - 1);
3925
- arg.u.flags.u.names = names;
3926
- arg.u.flags.separator = sep;
3944
+ arg.u.list.flags = flags & ((1ull << names.len) - 1);
3945
+ arg.u.list.u.names = names;
3946
+ arg.u.list.separator = sep;
3927
3947
  return arg;
3928
3948
  }
3929
-
3930
3949
  static inline FmtArg FmtFlags(uint64_t flags, Span<const struct OptionDesc> options, const char *sep = ", ")
3931
3950
  {
3932
3951
  FmtArg arg;
3933
3952
  arg.type = FmtType::FlagOptions;
3934
- arg.u.flags.flags = flags & ((1ull << options.len) - 1);
3935
- arg.u.flags.u.options = options;
3936
- arg.u.flags.separator = sep;
3953
+ arg.u.list.flags = flags & ((1ull << options.len) - 1);
3954
+ arg.u.list.u.options = options;
3955
+ arg.u.list.separator = sep;
3937
3956
  return arg;
3938
3957
  }
3939
3958
 
3940
- template <typename T>
3941
- FmtArg FmtSpan(Span<T> arr, FmtType type, const char *sep = ", ")
3959
+ static inline FmtArg FmtPad(Span<const char> str, int pad, char padding = ' ')
3942
3960
  {
3943
3961
  FmtArg arg;
3944
- arg.type = FmtType::Span;
3945
- arg.u.span.type = type;
3946
- arg.u.span.type_len = RG_SIZE(T);
3947
- arg.u.span.ptr = (const void *)arr.ptr;
3948
- arg.u.span.len = arr.len;
3949
- arg.u.span.separator = sep;
3962
+ arg.type = FmtType::PadStr;
3963
+ arg.u.str = str;
3964
+ arg.pad = pad;
3965
+ arg.padding = padding;
3966
+ return arg;
3967
+ }
3968
+ static inline FmtArg FmtRepeat(const char *str, int count)
3969
+ {
3970
+ FmtArg arg;
3971
+ arg.type = FmtType::RepeatStr;
3972
+ arg.u.repeat.str = str;
3973
+ arg.u.repeat.count = count;
3974
+ return arg;
3975
+ }
3976
+
3977
+ static inline FmtArg FmtHex(Span<const uint8_t> buf)
3978
+ {
3979
+ FmtArg arg;
3980
+ arg.type = FmtType::BigBytes;
3981
+ arg.u.hex = buf;
3982
+ return arg;
3983
+ }
3984
+ static inline FmtArg FmtHexSmall(Span<const uint8_t> buf)
3985
+ {
3986
+ FmtArg arg;
3987
+ arg.type = FmtType::SmallBytes;
3988
+ arg.u.hex = buf;
3989
+ return arg;
3990
+ }
3991
+
3992
+ static inline FmtArg FmtRandom(Size len, const char *chars = nullptr)
3993
+ {
3994
+ K_ASSERT(len < 256);
3995
+ len = std::min(len, (Size)256);
3996
+
3997
+ FmtArg arg;
3998
+ arg.type = FmtType::Random;
3999
+ arg.u.random.len = len;
4000
+ arg.u.random.chars = chars;
3950
4001
  return arg;
3951
4002
  }
3952
- template <typename T>
3953
- FmtArg FmtSpan(Span<T> arr, const char *sep = ", ") { return FmtSpan(arr, FmtArg(T()).type, sep); }
3954
- template <typename T, Size N>
3955
- FmtArg FmtSpan(T (&arr)[N], FmtType type, const char *sep = ", ") { return FmtSpan(MakeSpan(arr), type, sep); }
3956
- template <typename T, Size N>
3957
- FmtArg FmtSpan(T (&arr)[N], const char *sep = ", ") { return FmtSpan(MakeSpan(arr), sep); }
3958
4003
 
3959
4004
  class FmtUpperAscii {
3960
4005
  Span<const char> str;
@@ -3976,23 +4021,34 @@ public:
3976
4021
  operator FmtArg() const { return FmtCustom(*this); }
3977
4022
  };
3978
4023
 
3979
- class FmtEscape {
4024
+ class FmtUrlSafe {
4025
+ Span<const char> str;
4026
+ const char *passthrough;
4027
+
4028
+ public:
4029
+ FmtUrlSafe(Span<const char> str, const char *passthrough)
4030
+ : str(str), passthrough(passthrough) {}
4031
+
4032
+ void Format(FunctionRef<void(Span<const char>)> append) const;
4033
+ operator FmtArg() const { return FmtCustom(*this); }
4034
+ };
4035
+
4036
+ class FmtHtmlSafe {
3980
4037
  Span<const char> str;
3981
4038
 
3982
4039
  public:
3983
- FmtEscape(Span<const char> str) : str(str) {}
4040
+ FmtHtmlSafe(Span<const char> str) : str(str) {}
3984
4041
 
3985
4042
  void Format(FunctionRef<void(Span<const char>)> append) const;
3986
4043
  operator FmtArg() const { return FmtCustom(*this); }
3987
4044
  };
3988
4045
 
3989
- class FmtUrlSafe {
4046
+ class FmtEscape {
3990
4047
  Span<const char> str;
3991
- const char *passthrough;
4048
+ char quote;
3992
4049
 
3993
4050
  public:
3994
- FmtUrlSafe(Span<const char> str, const char *passthrough)
3995
- : str(str), passthrough(passthrough) {}
4051
+ FmtEscape(Span<const char> str, char quote) : str(str), quote(quote) {}
3996
4052
 
3997
4053
  void Format(FunctionRef<void(Span<const char>)> append) const;
3998
4054
  operator FmtArg() const { return FmtCustom(*this); }
@@ -4097,11 +4153,11 @@ static inline void Log(LogLevel level, const char *ctx, const char *fmt)
4097
4153
  template <typename... Args>
4098
4154
  static inline void Log(LogLevel level, const char *ctx, const char *fmt, Args... args)
4099
4155
  {
4100
- const FmtArg fmt_args[] = { FmtArg(args)... };
4156
+ const FmtArg fmt_args[] = { FmtSafe(args)... };
4101
4157
  LogFmt(level, ctx, fmt, fmt_args);
4102
4158
  }
4103
4159
 
4104
- #if defined(RG_DEBUG) && __cplusplus >= 202002L && __has_include(<source_location>)
4160
+ #if defined(K_DEBUG) && __cplusplus >= 202002L && __has_include(<source_location>)
4105
4161
  struct LogContext {
4106
4162
  const char *fmt;
4107
4163
  char str[56] = {};
@@ -4157,7 +4213,7 @@ static inline void Log(LogLevel level, const char *ctx, const char *fmt, Args...
4157
4213
  template <typename... Args>
4158
4214
  static inline void LogError(LogContext ctx, Args... args) { Log(LogLevel::Error, ctx.str, ctx.fmt, args...); }
4159
4215
  #else
4160
- #if defined(RG_DEBUG)
4216
+ #if defined(K_DEBUG)
4161
4217
  template <typename... Args>
4162
4218
  static inline void LogDebug(Args... args) { Log(LogLevel::Debug, "Debug: ", args...); }
4163
4219
  #else
@@ -4167,9 +4223,9 @@ static inline void Log(LogLevel level, const char *ctx, const char *fmt, Args...
4167
4223
  template <typename... Args>
4168
4224
  static inline void LogInfo(Args... args) { Log(LogLevel::Info, nullptr, args...); }
4169
4225
  template <typename... Args>
4170
- static inline void LogWarning(Args... args) { Log(LogLevel::Warning, "Warning: ", args...); }
4226
+ static inline void LogWarning(Args... args) { Log(LogLevel::Warning, T("Warning: "), args...); }
4171
4227
  template <typename... Args>
4172
- static inline void LogError(Args... args) { Log(LogLevel::Error, "Error: ", args...); }
4228
+ static inline void LogError(Args... args) { Log(LogLevel::Error, T("Error: "), args...); }
4173
4229
  #endif
4174
4230
 
4175
4231
  void SetLogHandler(const std::function<LogFunc> &func, bool vt100);
@@ -4202,7 +4258,7 @@ struct ProgressInfo {
4202
4258
  typedef void ProgressFunc(Span<const ProgressInfo> states);
4203
4259
 
4204
4260
  class ProgressHandle {
4205
- char text[RG_PROGRESS_TEXT_SIZE] = {};
4261
+ char text[K_PROGRESS_TEXT_SIZE] = {};
4206
4262
 
4207
4263
  std::atomic<ProgressNode *> node = nullptr;
4208
4264
 
@@ -4222,7 +4278,7 @@ public:
4222
4278
  template<typename... Args>
4223
4279
  void SetFmt(int64_t value, int64_t min, int64_t max, const char *fmt, Args... args)
4224
4280
  {
4225
- char buf[RG_PROGRESS_TEXT_SIZE];
4281
+ char buf[K_PROGRESS_TEXT_SIZE];
4226
4282
  Fmt(buf, fmt, args...);
4227
4283
 
4228
4284
  Set(value, min, max, (const char *)buf);
@@ -4240,7 +4296,7 @@ public:
4240
4296
 
4241
4297
  private:
4242
4298
  ProgressNode *AcquireNode();
4243
- void CopyText(Span<const char> text, char out[RG_PROGRESS_TEXT_SIZE]);
4299
+ void CopyText(Span<const char> text, char out[K_PROGRESS_TEXT_SIZE]);
4244
4300
  };
4245
4301
 
4246
4302
  void SetProgressHandler(const std::function<ProgressFunc> &func);
@@ -4253,15 +4309,15 @@ void DefaultProgressHandler(Span<const ProgressInfo> bars);
4253
4309
  // ------------------------------------------------------------------------
4254
4310
 
4255
4311
  #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"
4312
+ #define K_PATH_SEPARATORS "\\/"
4313
+ #define K_PATH_DELIMITER ';'
4314
+ #define K_EXECUTABLE_EXTENSION ".exe"
4315
+ #define K_SHARED_LIBRARY_EXTENSION ".dll"
4260
4316
  #else
4261
- #define RG_PATH_SEPARATORS "/"
4262
- #define RG_PATH_DELIMITER ':'
4263
- #define RG_EXECUTABLE_EXTENSION ""
4264
- #define RG_SHARED_LIBRARY_EXTENSION ".so"
4317
+ #define K_PATH_SEPARATORS "/"
4318
+ #define K_PATH_DELIMITER ':'
4319
+ #define K_EXECUTABLE_EXTENSION ""
4320
+ #define K_SHARED_LIBRARY_EXTENSION ".so"
4265
4321
  #endif
4266
4322
 
4267
4323
  #if defined(_WIN32)
@@ -4308,11 +4364,11 @@ static const char *const CompressionTypeExtensions[] = {
4308
4364
  Span<const char> GetPathDirectory(Span<const char> filename);
4309
4365
  Span<const char> GetPathExtension(Span<const char> filename,
4310
4366
  CompressionType *out_compression_type = nullptr);
4311
- CompressionType GetPathCompression(Span<const char> filename);
4312
4367
 
4313
4368
  enum class NormalizeFlag {
4314
4369
  EndWithSeparator = 1 << 0,
4315
- ForceSlash = 1 << 1
4370
+ ForceSlash = 1 << 1,
4371
+ NoExpansion = 1 << 2
4316
4372
  };
4317
4373
 
4318
4374
  Span<char> NormalizePath(Span<const char> path, Span<const char> root_directory, unsigned int flags, Allocator *alloc);
@@ -4326,6 +4382,7 @@ static inline Span<char> NormalizePath(Span<const char> path, Allocator *alloc)
4326
4382
  bool PathIsAbsolute(const char *path);
4327
4383
  bool PathIsAbsolute(Span<const char> path);
4328
4384
  bool PathContainsDotDot(const char *path);
4385
+ bool PathContainsDotDot(Span<const char> path);
4329
4386
 
4330
4387
  enum class StatFlag {
4331
4388
  SilentMissing = 1 << 0,
@@ -4398,7 +4455,20 @@ static inline RenameResult RenameFile(const char *src_filename, const char *dest
4398
4455
  { return RenameFile(src_filename, dest_filename, 0, flags); }
4399
4456
 
4400
4457
  bool ResizeFile(int fd, const char *filename, int64_t len);
4401
- bool SetFileMetaData(int fd, const char *filename, int64_t mtime, int64_t ctime, uint32_t mode);
4458
+
4459
+ #if !defined(_WIN32)
4460
+ bool SetFileMode(int fd, const char *filename, uint32_t mode);
4461
+ static inline bool SetFileMode(const char *filename, uint32_t mode)
4462
+ { return SetFileMode(-1, filename, mode); }
4463
+
4464
+ bool SetFileOwner(int fd, const char *filename, uint32_t uid, uint32_t gid);
4465
+ static inline bool SetFileOwner(const char *filename, uint32_t uid, uint32_t gid)
4466
+ { return SetFileOwner(-1, filename, uid, gid); }
4467
+ #endif
4468
+
4469
+ bool SetFileTimes(int fd, const char *filename, int64_t mtime, int64_t ctime);
4470
+ static inline bool SetFileTimes(const char *filename, int64_t mtime, int64_t ctime)
4471
+ { return SetFileTimes(-1, filename, mtime, ctime); }
4402
4472
 
4403
4473
  struct VolumeInfo {
4404
4474
  int64_t total;
@@ -4523,7 +4593,7 @@ void CloseHandleSafe(void **handle_ptr); // HANDLE
4523
4593
  #else
4524
4594
  void SetSignalHandler(int signal, void (*func)(int), struct sigaction *prev = nullptr);
4525
4595
 
4526
- bool CreatePipe(int pfd[2]);
4596
+ bool CreatePipe(bool block, int out_pfd[2]);
4527
4597
  void CloseDescriptorSafe(int *fd_ptr);
4528
4598
  #endif
4529
4599
 
@@ -4547,7 +4617,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
4547
4617
  HeapArray<uint8_t> *out_buf, int *out_code);
4548
4618
 
4549
4619
  // Simple variants
4550
- static inline bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,int *out_code)
4620
+ static inline bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info, int *out_code)
4551
4621
  { return ExecuteCommandLine(cmd_line, info, {}, {}, out_code); }
4552
4622
  static inline bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
4553
4623
  Span<const uint8_t> in_buf,
@@ -4587,18 +4657,34 @@ void WaitDelay(int64_t delay);
4587
4657
 
4588
4658
  #if !defined(__wasi__)
4589
4659
 
4590
- enum class WaitForResult {
4591
- Exit,
4660
+ enum class WaitResult {
4661
+ Ready,
4662
+ Timeout,
4592
4663
  Interrupt,
4593
4664
  Message,
4594
- Timeout
4665
+ Exit
4666
+ };
4667
+
4668
+ struct WaitSource {
4669
+ #if defined(_WIN32)
4670
+ // Special-cased on Windows: set to NULL to wait for the Win32 message pump too
4671
+ void *handle; // HANDLE
4672
+ int timeout;
4673
+ #else
4674
+ int fd;
4675
+ int timeout;
4676
+ int events = 0;
4677
+ #endif
4595
4678
  };
4596
4679
 
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.
4599
- // 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();
4680
+ // After WaitEvents() has been called once (even with timeout 0), a few signals (such as SIGINT, SIGHUP)
4681
+ // and their Windows equivalent will be permanently ignored.
4682
+ // Only the main thread (running main) will get WaitResult::Message events (and SIGUSR1).
4683
+ WaitResult WaitEvents(Span<const WaitSource> sources, int64_t timeout, uint64_t *out_ready = nullptr);
4684
+ WaitResult WaitEvents(int64_t timeout);
4685
+
4686
+ void PostWaitMessage();
4687
+ void PostTerminate();
4602
4688
 
4603
4689
  #endif
4604
4690
 
@@ -4613,19 +4699,72 @@ bool DropRootIdentity();
4613
4699
  bool NotifySystemd();
4614
4700
  #endif
4615
4701
 
4616
- #define RG_RESTART_EINTR(CallCode, ErrorCond) \
4702
+ #define K_RESTART_EINTR(CallCode, ErrorCond) \
4617
4703
  ([&]() { \
4618
4704
  decltype(CallCode) ret; \
4619
4705
  while ((ret = (CallCode)) ErrorCond && errno == EINTR); \
4620
4706
  return ret; \
4621
4707
  })()
4622
4708
 
4709
+ class InitHelper {
4710
+ public:
4711
+ const char *name;
4712
+ InitHelper *next = nullptr;
4713
+
4714
+ InitHelper(const char *name);
4715
+ virtual void Run() = 0;
4716
+ };
4717
+
4718
+ class FinalizeHelper {
4719
+ public:
4720
+ const char *name;
4721
+ FinalizeHelper *next = nullptr;
4722
+
4723
+ FinalizeHelper(const char *name);
4724
+ virtual void Run() = 0;
4725
+ };
4726
+
4727
+ #define K_INIT_(ClassName, Name) \
4728
+ class ClassName: public InitHelper { \
4729
+ public: \
4730
+ ClassName(): InitHelper(Name) {} \
4731
+ void Run() override; \
4732
+ }; \
4733
+ static ClassName K_UNIQUE_NAME(init); \
4734
+ void ClassName::Run()
4735
+ #define K_INIT(Name) K_INIT_(K_CONCAT(K_UNIQUE_NAME(InitHelper), Name), K_STRINGIFY(Name))
4736
+
4737
+ #define K_FINALIZE_(ClassName, Name) \
4738
+ class ClassName: public FinalizeHelper { \
4739
+ public: \
4740
+ ClassName(): FinalizeHelper(Name) {} \
4741
+ void Run() override; \
4742
+ }; \
4743
+ static ClassName K_UNIQUE_NAME(finalize); \
4744
+ void ClassName::Run()
4745
+ #define K_FINALIZE(Name) K_FINALIZE_(K_CONCAT(K_UNIQUE_NAME(FinalizeHelper), Name), K_STRINGIFY(Name))
4746
+
4747
+ #define K_EXIT_(ClassName) \
4748
+ class ClassName { \
4749
+ public: \
4750
+ ~ClassName(); \
4751
+ }; \
4752
+ static ClassName K_UNIQUE_NAME(exit); \
4753
+ ClassName::~ClassName()
4754
+ #define K_EXIT(Name) K_EXIT_(K_CONCAT(K_UNIQUE_NAME(ExitHelper), Name))
4755
+
4623
4756
  void InitApp();
4757
+ void ExitApp();
4758
+
4624
4759
  int Main(int argc, char **argv);
4625
4760
 
4626
4761
  static inline int RunApp(int argc, char **argv)
4627
4762
  {
4763
+ K_CRITICAL(argc >= 1, "First argument is missing");
4764
+
4628
4765
  InitApp();
4766
+ K_DEFER { ExitApp(); };
4767
+
4629
4768
  return Main(argc, argv);
4630
4769
  }
4631
4770
 
@@ -4661,10 +4800,10 @@ enum class ParseFlag {
4661
4800
  Validate = 1 << 1,
4662
4801
  End = 1 << 2
4663
4802
  };
4664
- #define RG_DEFAULT_PARSE_FLAGS ((int)ParseFlag::Log | (int)ParseFlag::Validate | (int)ParseFlag::End)
4803
+ #define K_DEFAULT_PARSE_FLAGS ((int)ParseFlag::Log | (int)ParseFlag::Validate | (int)ParseFlag::End)
4665
4804
 
4666
4805
  template <typename T>
4667
- bool ParseInt(Span<const char> str, T *out_value, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
4806
+ bool ParseInt(Span<const char> str, T *out_value, unsigned int flags = K_DEFAULT_PARSE_FLAGS,
4668
4807
  Span<const char> *out_remaining = nullptr)
4669
4808
  {
4670
4809
  if (!str.len) [[unlikely]] {
@@ -4723,20 +4862,20 @@ overflow:
4723
4862
  return false;
4724
4863
  }
4725
4864
 
4726
- bool ParseBool(Span<const char> str, bool *out_value, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
4865
+ bool ParseBool(Span<const char> str, bool *out_value, unsigned int flags = K_DEFAULT_PARSE_FLAGS,
4727
4866
  Span<const char> *out_remaining = nullptr);
4728
4867
 
4729
- bool ParseSize(Span<const char> str, int64_t *out_size, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
4868
+ bool ParseSize(Span<const char> str, int64_t *out_size, unsigned int flags = K_DEFAULT_PARSE_FLAGS,
4730
4869
  Span<const char> *out_remaining = nullptr);
4731
- #if RG_SIZE_MAX < INT64_MAX
4870
+ #if K_SIZE_MAX < INT64_MAX
4732
4871
  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)
4872
+ unsigned int flags = K_DEFAULT_PARSE_FLAGS, Span<const char> *out_remaining = nullptr)
4734
4873
  {
4735
4874
  int64_t size = 0;
4736
4875
  if (!ParseSize(str, &size, flags, out_remaining))
4737
4876
  return false;
4738
4877
 
4739
- if (size > RG_SIZE_MAX) [[unlikely]] {
4878
+ if (size > K_SIZE_MAX) [[unlikely]] {
4740
4879
  if (flags & (int)ParseFlag::Log) {
4741
4880
  LogError("Size value is too high");
4742
4881
  }
@@ -4748,13 +4887,13 @@ static inline bool ParseSize(Span<const char> str, Size *out_size,
4748
4887
  }
4749
4888
  #endif
4750
4889
 
4751
- bool ParseDate(Span<const char> date_str, LocalDate *out_date, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
4890
+ bool ParseDate(Span<const char> date_str, LocalDate *out_date, unsigned int flags = K_DEFAULT_PARSE_FLAGS,
4752
4891
  Span<const char> *out_remaining = nullptr);
4753
4892
 
4754
- bool ParseDuration(Span<const char> str, int64_t *out_duration, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
4893
+ bool ParseDuration(Span<const char> str, int64_t *out_duration, unsigned int flags = K_DEFAULT_PARSE_FLAGS,
4755
4894
  Span<const char> *out_remaining = nullptr);
4756
4895
  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)
4896
+ unsigned int flags = K_DEFAULT_PARSE_FLAGS, Span<const char> *out_remaining = nullptr)
4758
4897
  {
4759
4898
  int64_t duration = 0;
4760
4899
  if (!ParseDuration(str, &duration, flags, out_remaining))
@@ -4772,12 +4911,15 @@ static inline bool ParseDuration(Span<const char> str, int *out_duration,
4772
4911
  }
4773
4912
 
4774
4913
  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);
4914
+ unsigned int flags = K_DEFAULT_PARSE_FLAGS, Span<const char> *out_remaining = nullptr);
4776
4915
 
4777
4916
  // ------------------------------------------------------------------------
4778
4917
  // Random
4779
4918
  // ------------------------------------------------------------------------
4780
4919
 
4920
+ void InitChaCha20(uint32_t state[16], const uint8_t key[32], const uint8_t iv[8], const uint8_t counter[8] = nullptr);
4921
+ void RunChaCha20(uint32_t state[16], uint8_t out_buf[64]);
4922
+
4781
4923
  void FillRandomSafe(void *buf, Size len);
4782
4924
  static inline void FillRandomSafe(Span<uint8_t> buf) { FillRandomSafe(buf.ptr, buf.len); }
4783
4925
 
@@ -4788,14 +4930,13 @@ public:
4788
4930
  FastRandom();
4789
4931
  FastRandom(uint64_t seed);
4790
4932
 
4933
+ uint64_t Next();
4934
+
4791
4935
  void Fill(void *buf, Size len);
4792
4936
  void Fill(Span<uint8_t> buf) { Fill(buf.ptr, buf.len); }
4793
4937
 
4794
4938
  int GetInt(int min, int max);
4795
4939
  int64_t GetInt64(int64_t min, int64_t max);
4796
-
4797
- private:
4798
- uint64_t Next();
4799
4940
  };
4800
4941
 
4801
4942
  template <typename T>
@@ -4811,11 +4952,12 @@ public:
4811
4952
  T operator()()
4812
4953
  {
4813
4954
  T value;
4814
- rng.Fill(&value, RG_SIZE(value));
4955
+ rng.Fill(&value, K_SIZE(value));
4815
4956
  return value;
4816
4957
  }
4817
4958
  };
4818
4959
 
4960
+ uint64_t GetRandom();
4819
4961
  int GetRandomInt(int min, int max);
4820
4962
  int64_t GetRandomInt64(int64_t min, int64_t max);
4821
4963
 
@@ -4848,12 +4990,10 @@ bool InitWinsock();
4848
4990
 
4849
4991
  int CreateSocket(SocketType type, int flags);
4850
4992
 
4851
- bool BindIPSocket(int sock, SocketType type, int port);
4993
+ bool BindIPSocket(int sock, SocketType type, const char *addr, int port);
4852
4994
  bool BindUnixSocket(int sock, const char *path);
4853
-
4854
- int OpenIPSocket(SocketType type, int port, int flags);
4855
- int OpenUnixSocket(const char *path, int flags);
4856
- int ConnectToUnixSocket(const char *path, int flags);
4995
+ bool ConnectIPSocket(int sock, const char *addr, int port);
4996
+ bool ConnectUnixSocket(int sock, const char *path);
4857
4997
 
4858
4998
  // Only for sockets on Windows
4859
4999
  void SetDescriptorNonBlock(int fd, bool enable);
@@ -4868,7 +5008,7 @@ void CloseSocket(int fd);
4868
5008
  // ------------------------------------------------------------------------
4869
5009
 
4870
5010
  class Async {
4871
- RG_DELETE_COPY(Async)
5011
+ K_DELETE_COPY(Async)
4872
5012
 
4873
5013
  #if !defined(__wasi__)
4874
5014
  std::atomic_bool success { true };
@@ -4914,7 +5054,7 @@ class StreamDecoder;
4914
5054
  class StreamEncoder;
4915
5055
 
4916
5056
  class StreamReader {
4917
- RG_DELETE_COPY(StreamReader)
5057
+ K_DELETE_COPY(StreamReader)
4918
5058
 
4919
5059
  enum class SourceType {
4920
5060
  Memory,
@@ -4962,16 +5102,13 @@ class StreamReader {
4962
5102
 
4963
5103
  public:
4964
5104
  StreamReader() { Close(true); }
4965
- StreamReader(Span<const uint8_t> buf, const char *filename = nullptr,
4966
- CompressionType compression_type = CompressionType::None)
5105
+ StreamReader(Span<const uint8_t> buf, const char *filename, CompressionType compression_type = CompressionType::None)
4967
5106
  : StreamReader() { Open(buf, filename, compression_type); }
4968
- StreamReader(int fd, const char *filename,
4969
- CompressionType compression_type = CompressionType::None)
5107
+ StreamReader(int fd, const char *filename, CompressionType compression_type = CompressionType::None)
4970
5108
  : StreamReader() { Open(fd, filename, compression_type); }
4971
- StreamReader(const char *filename,
4972
- CompressionType compression_type = CompressionType::None)
5109
+ StreamReader(const char *filename, CompressionType compression_type = CompressionType::None)
4973
5110
  : StreamReader() { Open(filename, compression_type); }
4974
- StreamReader(const std::function<Size(Span<uint8_t>)> &func, const char *filename = nullptr,
5111
+ StreamReader(const std::function<Size(Span<uint8_t>)> &func, const char *filename,
4975
5112
  CompressionType compression_type = CompressionType::None)
4976
5113
  : StreamReader() { Open(func, filename, compression_type); }
4977
5114
  ~StreamReader() { Close(true); }
@@ -4979,12 +5116,10 @@ public:
4979
5116
  // Call before Open. Takes ownership and deletes the decoder at the end.
4980
5117
  void SetDecoder(StreamDecoder *decoder);
4981
5118
 
4982
- bool Open(Span<const uint8_t> buf, const char *filename = nullptr,
4983
- CompressionType compression_type = CompressionType::None);
4984
- bool Open(int fd, const char *filename,
4985
- CompressionType compression_type = CompressionType::None);
5119
+ bool Open(Span<const uint8_t> buf, const char *filename, CompressionType compression_type = CompressionType::None);
5120
+ bool Open(int fd, const char *filename, CompressionType compression_type = CompressionType::None);
4986
5121
  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,
5122
+ bool Open(const std::function<Size(Span<uint8_t>)> &func, const char *filename,
4988
5123
  CompressionType compression_type = CompressionType::None);
4989
5124
  bool Close() { return Close(false); }
4990
5125
 
@@ -5004,7 +5139,11 @@ public:
5004
5139
  // Thread safe methods
5005
5140
  Size Read(Span<uint8_t> out_buf);
5006
5141
  Size Read(Span<char> out_buf) { return Read(out_buf.As<uint8_t>()); }
5007
- Size Read(Size buf_len, void *out_buf) { return Read(MakeSpan((uint8_t *)out_buf, buf_len)); }
5142
+
5143
+ // Thread safe methods
5144
+ Size ReadFill(Span<uint8_t> out_buf);
5145
+ Size ReadFill(Span<char> out_buf) { return ReadFill(out_buf.As<uint8_t>()); }
5146
+ Size ReadFill(Size buf_len, void *out_buf) { return ReadFill(MakeSpan((uint8_t *)out_buf, buf_len)); }
5008
5147
 
5009
5148
  Size ReadAll(Size max_len, HeapArray<uint8_t> *out_buf);
5010
5149
  Size ReadAll(Size max_len, HeapArray<char> *out_buf)
@@ -5026,12 +5165,12 @@ private:
5026
5165
  static inline Size ReadFile(const char *filename, Span<uint8_t> out_buf)
5027
5166
  {
5028
5167
  StreamReader st(filename);
5029
- return st.Read(out_buf);
5168
+ return st.ReadFill(out_buf);
5030
5169
  }
5031
5170
  static inline Size ReadFile(const char *filename, Span<char> out_buf)
5032
5171
  {
5033
5172
  StreamReader st(filename);
5034
- return st.Read(out_buf);
5173
+ return st.ReadFill(out_buf);
5035
5174
  }
5036
5175
  static inline Size ReadFile(const char *filename, Size max_len, HeapArray<uint8_t> *out_buf)
5037
5176
  {
@@ -5071,16 +5210,16 @@ public:
5071
5210
  StreamDecompressorHelper(CompressionType type, CreateDecompressorFunc *func);
5072
5211
  };
5073
5212
 
5074
- #define RG_REGISTER_DECOMPRESSOR(Type, Cls) \
5075
- static StreamDecoder *RG_UNIQUE_NAME(CreateDecompressor)(StreamReader *reader, CompressionType type) \
5213
+ #define K_REGISTER_DECOMPRESSOR(Type, Cls) \
5214
+ static StreamDecoder *K_UNIQUE_NAME(CreateDecompressor)(StreamReader *reader, CompressionType type) \
5076
5215
  { \
5077
5216
  StreamDecoder *decompressor = new Cls(reader, type); \
5078
5217
  return decompressor; \
5079
5218
  } \
5080
- static StreamDecompressorHelper RG_UNIQUE_NAME(CreateDecompressorHelper)((Type), RG_UNIQUE_NAME(CreateDecompressor))
5219
+ static StreamDecompressorHelper K_UNIQUE_NAME(CreateDecompressorHelper)((Type), K_UNIQUE_NAME(CreateDecompressor))
5081
5220
 
5082
5221
  class LineReader {
5083
- RG_DELETE_COPY(LineReader)
5222
+ K_DELETE_COPY(LineReader)
5084
5223
 
5085
5224
  HeapArray<char> buf;
5086
5225
  Span<char> view = {};
@@ -5107,14 +5246,14 @@ public:
5107
5246
  };
5108
5247
 
5109
5248
  enum class StreamWriterFlag {
5110
- Exclusive = 1 << 0,
5111
- Atomic = 1 << 1,
5112
- NoBuffer = 1 << 2,
5113
- LineBuffer = 1 << 3
5249
+ Exclusive = 1 << 0, // Only for files
5250
+ Atomic = 1 << 1, // Only for files
5251
+ NoBuffer = 1 << 2, // Only for files and descriptors
5252
+ LineBuffer = 1 << 3 // Only for files and descriptors
5114
5253
  };
5115
5254
 
5116
5255
  class StreamWriter {
5117
- RG_DELETE_COPY(StreamWriter)
5256
+ K_DELETE_COPY(StreamWriter)
5118
5257
 
5119
5258
  enum class DestinationType {
5120
5259
  Memory,
@@ -5167,14 +5306,14 @@ class StreamWriter {
5167
5306
 
5168
5307
  public:
5169
5308
  StreamWriter() { Close(true); }
5170
- StreamWriter(HeapArray<uint8_t> *mem, const char *filename = nullptr,
5309
+ StreamWriter(HeapArray<uint8_t> *mem, const char *filename, unsigned int flags = 0,
5171
5310
  CompressionType compression_type = CompressionType::None,
5172
5311
  CompressionSpeed compression_speed = CompressionSpeed::Default)
5173
- : StreamWriter() { Open(mem, filename, compression_type, compression_speed); }
5174
- StreamWriter(HeapArray<char> *mem, const char *filename = nullptr,
5312
+ : StreamWriter() { Open(mem, filename, flags, compression_type, compression_speed); }
5313
+ StreamWriter(HeapArray<char> *mem, const char *filename, unsigned int flags = 0,
5175
5314
  CompressionType compression_type = CompressionType::None,
5176
5315
  CompressionSpeed compression_speed = CompressionSpeed::Default)
5177
- : StreamWriter() { Open(mem, filename, compression_type, compression_speed); }
5316
+ : StreamWriter() { Open(mem, filename, flags, compression_type, compression_speed); }
5178
5317
  StreamWriter(int fd, const char *filename, unsigned int flags = 0,
5179
5318
  CompressionType compression_type = CompressionType::None,
5180
5319
  CompressionSpeed compression_speed = CompressionSpeed::Default)
@@ -5183,29 +5322,29 @@ public:
5183
5322
  CompressionType compression_type = CompressionType::None,
5184
5323
  CompressionSpeed compression_speed = CompressionSpeed::Default)
5185
5324
  : StreamWriter() { Open(filename, flags, compression_type, compression_speed); }
5186
- StreamWriter(const std::function<bool(Span<const uint8_t>)> &func, const char *filename = nullptr,
5325
+ StreamWriter(const std::function<bool(Span<const uint8_t>)> &func, const char *filename, unsigned int flags = 0,
5187
5326
  CompressionType compression_type = CompressionType::None,
5188
5327
  CompressionSpeed compression_speed = CompressionSpeed::Default)
5189
- : StreamWriter() { Open(func, filename, compression_type, compression_speed); }
5328
+ : StreamWriter() { Open(func, filename, flags, compression_type, compression_speed); }
5190
5329
  ~StreamWriter() { Close(true); }
5191
5330
 
5192
5331
  // Call before Open. Takes ownership and deletes the encoder at the end.
5193
5332
  void SetEncoder(StreamEncoder *encoder);
5194
5333
 
5195
- bool Open(HeapArray<uint8_t> *mem, const char *filename = nullptr,
5334
+ bool Open(HeapArray<uint8_t> *mem, const char *filename, unsigned int flags = 0,
5196
5335
  CompressionType compression_type = CompressionType::None,
5197
5336
  CompressionSpeed compression_speed = CompressionSpeed::Default);
5198
- bool Open(HeapArray<char> *mem, const char *filename = nullptr,
5337
+ bool Open(HeapArray<char> *mem, const char *filename, unsigned int flags = 0,
5199
5338
  CompressionType compression_type = CompressionType::None,
5200
5339
  CompressionSpeed compression_speed = CompressionSpeed::Default)
5201
- { return Open((HeapArray<uint8_t> *)mem, filename, compression_type, compression_speed); }
5340
+ { return Open((HeapArray<uint8_t> *)mem, filename, flags, compression_type, compression_speed); }
5202
5341
  bool Open(int fd, const char *filename, unsigned int flags = 0,
5203
5342
  CompressionType compression_type = CompressionType::None,
5204
5343
  CompressionSpeed compression_speed = CompressionSpeed::Default);
5205
5344
  bool Open(const char *filename, unsigned int flags = 0,
5206
5345
  CompressionType compression_type = CompressionType::None,
5207
5346
  CompressionSpeed compression_speed = CompressionSpeed::Default);
5208
- bool Open(const std::function<bool(Span<const uint8_t>)> &func, const char *filename = nullptr,
5347
+ bool Open(const std::function<bool(Span<const uint8_t>)> &func, const char *filename, unsigned int flags = 0,
5209
5348
  CompressionType compression_type = CompressionType::None,
5210
5349
  CompressionSpeed compression_speed = CompressionSpeed::Default);
5211
5350
  bool Close() { return Close(false); }
@@ -5283,13 +5422,13 @@ public:
5283
5422
  StreamCompressorHelper(CompressionType type, CreateCompressorFunc *func);
5284
5423
  };
5285
5424
 
5286
- #define RG_REGISTER_COMPRESSOR(Type, Cls) \
5287
- static StreamEncoder *RG_UNIQUE_NAME(CreateCompressor)(StreamWriter *writer, CompressionType type, CompressionSpeed speed) \
5425
+ #define K_REGISTER_COMPRESSOR(Type, Cls) \
5426
+ static StreamEncoder *K_UNIQUE_NAME(CreateCompressor)(StreamWriter *writer, CompressionType type, CompressionSpeed speed) \
5288
5427
  { \
5289
5428
  StreamEncoder *compressor = new Cls(writer, type, speed); \
5290
5429
  return compressor; \
5291
5430
  } \
5292
- static StreamCompressorHelper RG_UNIQUE_NAME(CreateCompressorHelper)((Type), RG_UNIQUE_NAME(CreateCompressor))
5431
+ static StreamCompressorHelper K_UNIQUE_NAME(CreateCompressorHelper)((Type), K_UNIQUE_NAME(CreateCompressor))
5293
5432
 
5294
5433
  bool SpliceStream(StreamReader *reader, int64_t max_len, StreamWriter *writer, Span<uint8_t> buf,
5295
5434
  FunctionRef<void(int64_t, int64_t)> progress = [](int64_t, int64_t) {});
@@ -5322,7 +5461,7 @@ struct IniProperty {
5322
5461
  };
5323
5462
 
5324
5463
  class IniParser {
5325
- RG_DELETE_COPY(IniParser)
5464
+ K_DELETE_COPY(IniParser)
5326
5465
 
5327
5466
  HeapArray<char> current_section;
5328
5467
 
@@ -5362,7 +5501,7 @@ struct AssetInfo {
5362
5501
  CompressionType compression_type;
5363
5502
  Span<const uint8_t> data;
5364
5503
 
5365
- RG_HASHTABLE_HANDLER(AssetInfo, name);
5504
+ K_HASHTABLE_HANDLER(AssetInfo, name);
5366
5505
  };
5367
5506
 
5368
5507
  #if defined(FELIX_HOT_ASSETS)
@@ -5415,6 +5554,29 @@ Span<const uint8_t> PatchFile(const AssetInfo &asset, Allocator *alloc,
5415
5554
  Span<const char> PatchFile(Span<const char> data, Allocator *alloc,
5416
5555
  FunctionRef<void(Span<const char> key, StreamWriter *)> func);
5417
5556
 
5557
+ // ------------------------------------------------------------------------
5558
+ // Translations
5559
+ // ------------------------------------------------------------------------
5560
+
5561
+ struct TranslationTable {
5562
+ struct Pair {
5563
+ const char *key;
5564
+ const char *value;
5565
+ };
5566
+
5567
+ const char *language;
5568
+ Span<Pair> messages;
5569
+
5570
+ K_HASHTABLE_HANDLER(TranslationTable, language);
5571
+ };
5572
+
5573
+ extern "C" const Span<const TranslationTable> TranslationTables;
5574
+
5575
+ void InitLocales(Span<const TranslationTable> tables);
5576
+
5577
+ // Resets the localgale to the process default if lang is NULL or is unknown
5578
+ void ChangeThreadLocale(const char *name);
5579
+
5418
5580
  // ------------------------------------------------------------------------
5419
5581
  // Options
5420
5582
  // ------------------------------------------------------------------------
@@ -5437,7 +5599,7 @@ enum class OptionType {
5437
5599
  };
5438
5600
 
5439
5601
  class OptionParser {
5440
- RG_DELETE_COPY(OptionParser)
5602
+ K_DELETE_COPY(OptionParser)
5441
5603
 
5442
5604
  Span<const char *> args;
5443
5605
  OptionMode mode;
@@ -5516,6 +5678,8 @@ bool OptionToEnum(Span<const OptionDesc> options, Span<const char> str, T *out_v
5516
5678
  template <typename T>
5517
5679
  bool OptionToEnumI(Span<const char *const> options, Span<const char> str, T *out_value)
5518
5680
  {
5681
+ static_assert(std::is_enum<T>::value);
5682
+
5519
5683
  for (Size i = 0; i < options.len; i++) {
5520
5684
  const char *opt = options[i];
5521
5685
 
@@ -5531,6 +5695,8 @@ bool OptionToEnumI(Span<const char *const> options, Span<const char> str, T *out
5531
5695
  template <typename T>
5532
5696
  bool OptionToEnumI(Span<const OptionDesc> options, Span<const char> str, T *out_value)
5533
5697
  {
5698
+ static_assert(std::is_enum<T>::value);
5699
+
5534
5700
  for (Size i = 0; i < options.len; i++) {
5535
5701
  const OptionDesc &desc = options[i];
5536
5702
 
@@ -5608,10 +5774,23 @@ bool OptionToFlagI(Span<const OptionDesc> options, Span<const char> str, T *out_
5608
5774
  // ------------------------------------------------------------------------
5609
5775
 
5610
5776
  struct PromptChoice {
5611
- char c;
5612
5777
  const char *str;
5778
+ char c;
5779
+ };
5780
+
5781
+ enum class CompleteResult {
5782
+ Success,
5783
+ TooMany,
5784
+ Error
5613
5785
  };
5614
5786
 
5787
+ struct CompleteChoice {
5788
+ const char *name;
5789
+ const char *value;
5790
+ };
5791
+
5792
+ typedef CompleteResult CompleteFunc(Span<const char> value, Allocator *alloc, HeapArray<CompleteChoice> *out_choices);
5793
+
5615
5794
  class ConsolePrompter {
5616
5795
  int prompt_columns = 0;
5617
5796
 
@@ -5631,8 +5810,9 @@ class ConsolePrompter {
5631
5810
  #endif
5632
5811
 
5633
5812
  public:
5634
- const char *prompt = ">>> ";
5813
+ const char *prompt = ">>>";
5635
5814
  const char *mask = nullptr;
5815
+ std::function<CompleteFunc> complete = {};
5636
5816
 
5637
5817
  HeapArray<char> str;
5638
5818
 
@@ -5667,8 +5847,6 @@ private:
5667
5847
  Vec2<int> GetConsoleSize();
5668
5848
  int32_t ReadChar();
5669
5849
 
5670
- int ComputeWidth(Span<const char> str);
5671
-
5672
5850
  void EnsureNulTermination();
5673
5851
  };
5674
5852
 
@@ -5679,6 +5857,13 @@ static inline const char *Prompt(const char *prompt, Allocator *alloc)
5679
5857
  Size PromptEnum(const char *prompt, Span<const PromptChoice> choices, Size value = 0);
5680
5858
  Size PromptEnum(const char *prompt, Span<const char *const> strings, Size value = 0);
5681
5859
 
5860
+ // Returns -1 if cancelled, otherwise it's 1 for Yes and or 0 for No
5861
+ int PromptYN(const char *prompt);
5862
+
5863
+ const char *PromptPath(const char *prompt, const char *default_path, Span<const char> root_directory, Allocator *alloc);
5864
+ static inline const char *PromptPath(const char *prompt, Allocator *alloc)
5865
+ { return PromptPath(prompt, nullptr, GetWorkingDirectory(), alloc); }
5866
+
5682
5867
  // ------------------------------------------------------------------------
5683
5868
  // Mime types
5684
5869
  // ------------------------------------------------------------------------
@@ -5691,7 +5876,118 @@ bool CanCompressFile(const char *filename);
5691
5876
  // Unicode
5692
5877
  // ------------------------------------------------------------------------
5693
5878
 
5694
- int ComputeCharacterWidth(int32_t uc);
5879
+ static inline int CountUtf8Bytes(char c)
5880
+ {
5881
+ int ones = CountLeadingZeros((uint32_t)~c << 24);
5882
+ return std::min(std::max(ones, 1), 4);
5883
+ }
5884
+
5885
+ static constexpr inline Size DecodeUtf8(const char *str, int32_t *out_c)
5886
+ {
5887
+ K_ASSERT(str[0]);
5888
+
5889
+ #define BYTE(Idx) ((uint8_t)str[Idx])
5890
+
5891
+ if (BYTE(0) < 0x80) {
5892
+ *out_c = BYTE(0);
5893
+ return 1;
5894
+ } else if (BYTE(0) - 0xC2 > 0xF4 - 0xC2) [[unlikely]] {
5895
+ return 0;
5896
+ } else if (BYTE(1)) [[likely]] {
5897
+ if (BYTE(0) < 0xE0 && (BYTE(1) & 0xC0) == 0x80) {
5898
+ *out_c = ((BYTE(0) & 0x1F) << 6) | (BYTE(1) & 0x3F);
5899
+ return 2;
5900
+ } else if (BYTE(2)) [[likely]] {
5901
+ if (BYTE(0) < 0xF0 &&
5902
+ (BYTE(1) & 0xC0) == 0x80 &&
5903
+ (BYTE(2) & 0xC0) == 0x80) {
5904
+ *out_c = ((BYTE(0) & 0xF) << 12) | ((BYTE(1) & 0x3F) << 6) | (BYTE(2) & 0x3F);
5905
+ return 3;
5906
+ } else if (BYTE(3)) [[likely]] {
5907
+ if ((BYTE(1) & 0xC0) == 0x80 &&
5908
+ (BYTE(2) & 0xC0) == 0x80 &&
5909
+ (BYTE(3) & 0xC0) == 0x80) {
5910
+ *out_c = ((BYTE(0) & 0x7) << 18) | ((BYTE(1) & 0x3F) << 12) | ((BYTE(2) & 0x3F) << 6) | (BYTE(3) & 0x3F);
5911
+ return 4;
5912
+ }
5913
+ }
5914
+ }
5915
+ }
5916
+
5917
+ #undef BYTE
5918
+
5919
+ return 0;
5920
+ }
5921
+
5922
+ static constexpr inline Size DecodeUtf8(Span<const char> str, Size offset, int32_t *out_c)
5923
+ {
5924
+ K_ASSERT(offset < str.len);
5925
+
5926
+ str = str.Take(offset, str.len - offset);
5927
+
5928
+ #define BYTE(Idx) ((uint8_t)str[Idx])
5929
+
5930
+ if (BYTE(0) < 0x80) {
5931
+ *out_c = BYTE(0);
5932
+ return 1;
5933
+ } else if (BYTE(0) - 0xC2 > 0xF4 - 0xC2) [[unlikely]] {
5934
+ return 0;
5935
+ } else if (BYTE(0) < 0xE0 && str.len >= 2 && (BYTE(1) & 0xC0) == 0x80) {
5936
+ *out_c = ((BYTE(0) & 0x1F) << 6) | (BYTE(1) & 0x3F);
5937
+ return 2;
5938
+ } else if (BYTE(0) < 0xF0 && str.len >= 3 && (BYTE(1) & 0xC0) == 0x80 &&
5939
+ (BYTE(2) & 0xC0) == 0x80) {
5940
+ *out_c = ((BYTE(0) & 0xF) << 12) | ((BYTE(1) & 0x3F) << 6) | (BYTE(2) & 0x3F);
5941
+ return 3;
5942
+ } else if (str.len >= 4 && (BYTE(1) & 0xC0) == 0x80 &&
5943
+ (BYTE(2) & 0xC0) == 0x80 &&
5944
+ (BYTE(3) & 0xC0) == 0x80) {
5945
+ *out_c = ((BYTE(0) & 0x7) << 18) | ((BYTE(1) & 0x3F) << 12) | ((BYTE(2) & 0x3F) << 6) | (BYTE(3) & 0x3F);
5946
+ return 4;
5947
+ } else {
5948
+ return 0;
5949
+ }
5950
+
5951
+ #undef BYTE
5952
+ }
5953
+
5954
+ static constexpr inline int32_t DecodeUtf8(const char *str)
5955
+ {
5956
+ int32_t uc = -1;
5957
+ DecodeUtf8(str, &uc);
5958
+ return uc;
5959
+ }
5960
+
5961
+ static inline Size EncodeUtf8(int32_t c, char out_buf[4])
5962
+ {
5963
+ if (c < 0x80) {
5964
+ out_buf[0] = (char)c;
5965
+ return 1;
5966
+ } else if (c < 0x800) {
5967
+ out_buf[0] = (char)(0xC0 | (c >> 6));
5968
+ out_buf[1] = (char)(0x80 | (c & 0x3F));
5969
+ return 2;
5970
+ } else if (c >= 0xD800 && c < 0xE000) {
5971
+ return 0;
5972
+ } else if (c < 0x10000) {
5973
+ out_buf[0] = (char)(0xE0 | (c >> 12));
5974
+ out_buf[1] = (char)(0x80 | ((c >> 6) & 0x3F));
5975
+ out_buf[2] = (char)(0x80 | (c & 0x3F));
5976
+ return 3;
5977
+ } else if (c < 0x110000) {
5978
+ out_buf[0] = (char)(0xF0 | (c >> 18));
5979
+ out_buf[1] = (char)(0x80 | ((c >> 12) & 0x3F));
5980
+ out_buf[2] = (char)(0x80 | ((c >> 6) & 0x3F));
5981
+ out_buf[3] = (char)(0x80 | (c & 0x3F));
5982
+ return 4;
5983
+ } else {
5984
+ return 0;
5985
+ }
5986
+ }
5987
+
5988
+ bool IsValidUtf8(Span<const char> str);
5989
+
5990
+ int ComputeUnicodeWidth(Span<const char> str);
5695
5991
 
5696
5992
  bool IsXidStart(int32_t uc);
5697
5993
  bool IsXidContinue(int32_t uc);