koffi 2.5.0 → 2.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/build/2.5.1/koffi_darwin_arm64/koffi.node +0 -0
  3. package/build/{2.5.0 → 2.5.1}/koffi_darwin_x64/koffi.node +0 -0
  4. package/build/{2.5.0 → 2.5.1}/koffi_freebsd_arm64/koffi.node +0 -0
  5. package/build/{2.5.0 → 2.5.1}/koffi_freebsd_ia32/koffi.node +0 -0
  6. package/build/{2.5.0 → 2.5.1}/koffi_freebsd_x64/koffi.node +0 -0
  7. package/build/2.5.1/koffi_linux_arm32hf/koffi.node +0 -0
  8. package/build/2.5.1/koffi_linux_arm64/koffi.node +0 -0
  9. package/build/{2.5.0 → 2.5.1}/koffi_linux_ia32/koffi.node +0 -0
  10. package/build/{2.5.0 → 2.5.1}/koffi_linux_riscv64hf64/koffi.node +0 -0
  11. package/build/{2.5.0 → 2.5.1}/koffi_linux_x64/koffi.node +0 -0
  12. package/build/{2.5.0 → 2.5.1}/koffi_openbsd_ia32/koffi.node +0 -0
  13. package/build/{2.5.0 → 2.5.1}/koffi_openbsd_x64/koffi.node +0 -0
  14. package/build/2.5.1/koffi_win32_arm64/koffi.node +0 -0
  15. package/build/{2.5.0 → 2.5.1}/koffi_win32_ia32/koffi.node +0 -0
  16. package/build/{2.5.0 → 2.5.1}/koffi_win32_x64/koffi.node +0 -0
  17. package/package.json +2 -2
  18. package/src/core/libcc/brotli.cc +1 -1
  19. package/src/core/libcc/libcc.cc +53 -65
  20. package/src/core/libcc/libcc.hh +67 -28
  21. package/src/core/libcc/miniz.cc +2 -2
  22. package/src/koffi/CMakeLists.txt +1 -5
  23. package/src/koffi/src/abi_arm32.cc +35 -35
  24. package/src/koffi/src/abi_arm64.cc +34 -34
  25. package/src/koffi/src/abi_riscv64.cc +29 -29
  26. package/src/koffi/src/abi_x64_sysv.cc +29 -28
  27. package/src/koffi/src/abi_x64_win.cc +23 -23
  28. package/src/koffi/src/abi_x86.cc +27 -27
  29. package/src/koffi/src/call.cc +62 -69
  30. package/src/koffi/src/call.hh +2 -2
  31. package/src/koffi/src/ffi.cc +24 -24
  32. package/src/koffi/src/ffi.hh +4 -4
  33. package/src/koffi/src/parser.cc +1 -1
  34. package/src/koffi/src/trampolines/prototypes.inc +1 -1
  35. package/src/koffi/src/util.cc +7 -7
  36. package/src/koffi/src/util.hh +1 -1
  37. package/src/koffi/src/win32.hh +4 -4
  38. package/build/2.5.0/koffi_darwin_arm64/koffi.node +0 -0
  39. package/build/2.5.0/koffi_linux_arm32hf/koffi.node +0 -0
  40. package/build/2.5.0/koffi_linux_arm64/koffi.node +0 -0
  41. package/build/2.5.0/koffi_win32_arm64/koffi.node +0 -0
  42. package/build/2.5.0/koffi_win32_x64/koffi.pdb +0 -0
  43. /package/build/{2.5.0 → 2.5.1}/koffi_win32_arm64/koffi.exp +0 -0
  44. /package/build/{2.5.0 → 2.5.1}/koffi_win32_arm64/koffi.lib +0 -0
  45. /package/build/{2.5.0 → 2.5.1}/koffi_win32_ia32/koffi.exp +0 -0
  46. /package/build/{2.5.0 → 2.5.1}/koffi_win32_ia32/koffi.lib +0 -0
  47. /package/build/{2.5.0 → 2.5.1}/koffi_win32_x64/koffi.exp +0 -0
  48. /package/build/{2.5.0 → 2.5.1}/koffi_win32_x64/koffi.lib +0 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,13 @@
4
4
 
5
5
  ### Koffi 2.5
6
6
 
7
+ #### Koffi 2.5.1
8
+
9
+ **Main changes:**
10
+
11
+ - Fix crash with some struct types in System V 64 ABI
12
+ - Always use direct passthrough for buffer arguments
13
+
7
14
  #### Koffi 2.5.0
8
15
 
9
16
  **New features:**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "2.5.0",
4
- "stable": "2.5.0",
3
+ "version": "2.5.1",
4
+ "stable": "2.5.1",
5
5
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
6
6
  "keywords": [
7
7
  "foreign",
@@ -130,7 +130,7 @@ bool BrotliCompressor::Init(CompressionType, CompressionSpeed speed)
130
130
  if (!state)
131
131
  throw std::bad_alloc();
132
132
 
133
- RG_STATIC_ASSERT(BROTLI_MIN_QUALITY == 0 && BROTLI_MAX_QUALITY == 11);
133
+ static_assert(BROTLI_MIN_QUALITY == 0 && BROTLI_MAX_QUALITY == 11);
134
134
 
135
135
  switch (speed) {
136
136
  case CompressionSpeed::Default: { BrotliEncoderSetParameter(state, BROTLI_PARAM_QUALITY, 6); } break;
@@ -21,7 +21,7 @@
21
21
 
22
22
  #include "libcc.hh"
23
23
 
24
- #if __has_include("vendor/dragonbox/include/dragonbox/dragonbox.h") && __cplusplus >= 201703L
24
+ #if __has_include("vendor/dragonbox/include/dragonbox/dragonbox.h")
25
25
  #include "vendor/dragonbox/include/dragonbox/dragonbox.h"
26
26
  #endif
27
27
 
@@ -445,13 +445,13 @@ LocalDate LocalDate::Parse(Span<const char> date_str, unsigned int flags,
445
445
  int digit = c - '0';
446
446
  if ((unsigned int)digit < 10) {
447
447
  parts[i] = (parts[i] * 10) + digit;
448
- if (RG_UNLIKELY(++lengths[i] > 5))
448
+ if (++lengths[i] > 5) [[unlikely]]
449
449
  goto malformed;
450
450
  } else if (!lengths[i] && c == '-' && mult == 1 && i != 1) {
451
451
  mult = -1;
452
- } else if (RG_UNLIKELY(i == 2 && !(flags & (int)ParseFlag::End) && c != '/' && c != '-')) {
452
+ } else if (i == 2 && !(flags & (int)ParseFlag::End) && c != '/' && c != '-') [[unlikely]] {
453
453
  break;
454
- } else if (RG_UNLIKELY(!lengths[i] || (c != '/' && c != '-'))) {
454
+ } else if (!lengths[i] || (c != '/' && c != '-')) [[unlikely]] {
455
455
  goto malformed;
456
456
  } else {
457
457
  offset++;
@@ -464,9 +464,9 @@ LocalDate LocalDate::Parse(Span<const char> date_str, unsigned int flags,
464
464
  if ((flags & (int)ParseFlag::End) && offset < date_str.len)
465
465
  goto malformed;
466
466
 
467
- if (RG_UNLIKELY((unsigned int)lengths[1] > 2))
467
+ if ((unsigned int)lengths[1] > 2) [[unlikely]]
468
468
  goto malformed;
469
- if (RG_UNLIKELY((lengths[0] > 2) == (lengths[2] > 2))) {
469
+ if ((lengths[0] > 2) == (lengths[2] > 2)) [[unlikely]] {
470
470
  if (flags & (int)ParseFlag::Log) {
471
471
  LogError("Ambiguous date string '%1'", date_str);
472
472
  }
@@ -474,7 +474,7 @@ LocalDate LocalDate::Parse(Span<const char> date_str, unsigned int flags,
474
474
  } else if (lengths[2] > 2) {
475
475
  std::swap(parts[0], parts[2]);
476
476
  }
477
- if (RG_UNLIKELY(parts[0] < -INT16_MAX || parts[0] > INT16_MAX || (unsigned int)parts[2] > 99))
477
+ if (parts[0] < -INT16_MAX || parts[0] > INT16_MAX || (unsigned int)parts[2] > 99) [[unlikely]]
478
478
  goto malformed;
479
479
 
480
480
  date.st.year = (int16_t)parts[0];
@@ -722,13 +722,13 @@ bool CopyString(const char *str, Span<char> buf)
722
722
  #ifdef RG_DEBUG
723
723
  RG_ASSERT(buf.len > 0);
724
724
  #else
725
- if (RG_UNLIKELY(!buf.len))
725
+ if (!buf.len) [[unlikely]]
726
726
  return false;
727
727
  #endif
728
728
 
729
729
  Size i = 0;
730
730
  for (; str[i]; i++) {
731
- if (RG_UNLIKELY(i >= buf.len - 1)) {
731
+ if (i >= buf.len - 1) [[unlikely]] {
732
732
  buf[buf.len - 1] = 0;
733
733
  return false;
734
734
  }
@@ -744,11 +744,11 @@ bool CopyString(Span<const char> str, Span<char> buf)
744
744
  #ifdef RG_DEBUG
745
745
  RG_ASSERT(buf.len > 0);
746
746
  #else
747
- if (RG_UNLIKELY(!buf.len))
747
+ if (!buf.len) [[unlikely]]
748
748
  return false;
749
749
  #endif
750
750
 
751
- if (RG_UNLIKELY(str.len > buf.len - 1))
751
+ if (str.len > buf.len - 1) [[unlikely]]
752
752
  return false;
753
753
 
754
754
  memcpy_safe(buf.ptr, str.ptr, str.len);
@@ -1684,7 +1684,7 @@ static void WriteStdComplete(Span<const char> buf, FILE *fp)
1684
1684
  {
1685
1685
  while (buf.len) {
1686
1686
  Size write_len = (Size)fwrite(buf.ptr, 1, (size_t)buf.len, fp);
1687
- if (RG_UNLIKELY(!write_len))
1687
+ if (!write_len) [[unlikely]]
1688
1688
  break;
1689
1689
  buf = buf.Take(write_len, buf.len - write_len);
1690
1690
  }
@@ -1965,7 +1965,7 @@ Size ConvertUtf8ToWin32Wide(Span<const char> str, Span<wchar_t> out_str_w)
1965
1965
  {
1966
1966
  RG_ASSERT(out_str_w.len >= 2);
1967
1967
 
1968
- if (RG_UNLIKELY(!str.len)) {
1968
+ if (!str.len) [[unlikely]] {
1969
1969
  out_str_w[0] = 0;
1970
1970
  return 0;
1971
1971
  }
@@ -2230,7 +2230,7 @@ EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_
2230
2230
  (find_data.cFileName[0] == '.' && find_data.cFileName[1] == '.' && !find_data.cFileName[2]))
2231
2231
  continue;
2232
2232
 
2233
- if (RG_UNLIKELY(count++ >= max_files && max_files >= 0)) {
2233
+ if (count++ >= max_files && max_files >= 0) [[unlikely]] {
2234
2234
  LogError("Partial enumation of directory '%1'", dirname);
2235
2235
  return EnumResult::PartialEnum;
2236
2236
  }
@@ -2292,7 +2292,7 @@ static FileType FileModeToType(mode_t mode)
2292
2292
 
2293
2293
  StatResult StatFile(const char *filename, unsigned int flags, FileInfo *out_info)
2294
2294
  {
2295
- #if defined(__linux__) && !defined(LIBCC_NO_STATX)
2295
+ #if defined(__linux__) && defined(STATX_TYPE) && !defined(LIBCC_NO_STATX)
2296
2296
  int stat_flags = (flags & (int)StatFlag::FollowSymlink) ? 0 : AT_SYMLINK_NOFOLLOW;
2297
2297
  int stat_mask = STATX_TYPE | STATX_MODE | STATX_MTIME | STATX_BTIME | STATX_SIZE;
2298
2298
 
@@ -2468,7 +2468,7 @@ EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_
2468
2468
  continue;
2469
2469
 
2470
2470
  if (!filter || !fnmatch(filter, dent->d_name, FNM_PERIOD)) {
2471
- if (RG_UNLIKELY(count++ >= max_files && max_files >= 0)) {
2471
+ if (count++ >= max_files && max_files >= 0) [[unlikely]] {
2472
2472
  LogError("Partial enumation of directory '%1'", dirname);
2473
2473
  return EnumResult::PartialEnum;
2474
2474
  }
@@ -2738,7 +2738,7 @@ bool FindExecutableInPath(Span<const char> paths, const char *name, Allocator *a
2738
2738
  static const Span<const char> extensions[] = {".com", ".exe", ".bat", ".cmd"};
2739
2739
 
2740
2740
  for (Span<const char> ext: extensions) {
2741
- if (RG_LIKELY(ext.len < buf.Available() - 1)) {
2741
+ if (ext.len < buf.Available() - 1) [[likely]] {
2742
2742
  memcpy_safe(buf.end(), ext.ptr, ext.len + 1);
2743
2743
 
2744
2744
  if (TestFile(buf.data)) {
@@ -2750,7 +2750,7 @@ bool FindExecutableInPath(Span<const char> paths, const char *name, Allocator *a
2750
2750
  }
2751
2751
  }
2752
2752
  #else
2753
- if (RG_LIKELY(buf.len < RG_SIZE(buf.data) - 1) && TestFile(buf.data)) {
2753
+ if (buf.len < RG_SIZE(buf.data) - 1 && TestFile(buf.data)) {
2754
2754
  if (out_path) {
2755
2755
  *out_path = DuplicateString(buf.data, alloc).ptr;
2756
2756
  }
@@ -3643,7 +3643,7 @@ bool MakeDirectory(const char *directory, bool error_if_exists)
3643
3643
  bool MakeDirectoryRec(Span<const char> directory)
3644
3644
  {
3645
3645
  char buf[4096];
3646
- if (RG_UNLIKELY(directory.len >= RG_SIZE(buf))) {
3646
+ if (directory.len >= RG_SIZE(buf)) [[unlikely]] {
3647
3647
  LogError("Path '%1' is too large", directory);
3648
3648
  return false;
3649
3649
  }
@@ -4321,7 +4321,7 @@ bool ExecuteCommandLine(const char *cmd_line, Span<const uint8_t> in_buf, Size m
4321
4321
  {
4322
4322
  Size memory_max = RG_SIZE_MAX - out_buf->len - 1;
4323
4323
 
4324
- if (RG_UNLIKELY(memory_max <= 0)) {
4324
+ if (memory_max <= 0) [[unlikely]] {
4325
4325
  LogError("Exhausted memory limit");
4326
4326
  return false;
4327
4327
  }
@@ -4830,7 +4830,7 @@ static const char *CreateUniquePath(Span<const char> directory, const char *pref
4830
4830
 
4831
4831
  for (Size i = 0; i < 1000; i++) {
4832
4832
  // We want to show an error on last try
4833
- if (RG_UNLIKELY(i == 999)) {
4833
+ if (i == 999) [[unlikely]] {
4834
4834
  PopLogFilter();
4835
4835
  log_guard.Disable();
4836
4836
  }
@@ -5664,7 +5664,7 @@ Fiber::~Fiber()
5664
5664
 
5665
5665
  void Fiber::SwitchTo()
5666
5666
  {
5667
- if (RG_UNLIKELY(!fiber))
5667
+ if (!fiber) [[unlikely]]
5668
5668
  return;
5669
5669
 
5670
5670
  if (!done) {
@@ -5675,7 +5675,7 @@ void Fiber::SwitchTo()
5675
5675
 
5676
5676
  bool Fiber::Finalize()
5677
5677
  {
5678
- if (RG_UNLIKELY(!fiber))
5678
+ if (!fiber) [[unlikely]]
5679
5679
  return false;
5680
5680
 
5681
5681
  if (!done) {
@@ -5746,7 +5746,7 @@ Fiber::~Fiber()
5746
5746
 
5747
5747
  void Fiber::SwitchTo()
5748
5748
  {
5749
- if (RG_UNLIKELY(!ucp.uc_stack.ss_sp))
5749
+ if (!ucp.uc_stack.ss_sp) [[unlikely]]
5750
5750
  return;
5751
5751
 
5752
5752
  if (!done) {
@@ -5757,7 +5757,7 @@ void Fiber::SwitchTo()
5757
5757
 
5758
5758
  bool Fiber::Finalize()
5759
5759
  {
5760
- if (RG_UNLIKELY(!ucp.uc_stack.ss_sp))
5760
+ if (!ucp.uc_stack.ss_sp) [[unlikely]]
5761
5761
  return false;
5762
5762
 
5763
5763
  if (!done) {
@@ -6025,7 +6025,7 @@ bool StreamReader::Close(bool implicit)
6025
6025
 
6026
6026
  bool StreamReader::Rewind()
6027
6027
  {
6028
- if (RG_UNLIKELY(error))
6028
+ if (error) [[unlikely]]
6029
6029
  return false;
6030
6030
 
6031
6031
  switch (source.type) {
@@ -6077,7 +6077,7 @@ int StreamReader::GetDescriptor() const
6077
6077
 
6078
6078
  Size StreamReader::Read(Span<uint8_t> out_buf)
6079
6079
  {
6080
- if (RG_UNLIKELY(error))
6080
+ if (error) [[unlikely]]
6081
6081
  return -1;
6082
6082
 
6083
6083
  Size read_len = 0;
@@ -6093,7 +6093,7 @@ Size StreamReader::Read(Span<uint8_t> out_buf)
6093
6093
  eof = source.eof;
6094
6094
  }
6095
6095
 
6096
- if (RG_UNLIKELY(!error && read_max >= 0 && read_len > read_max - read_total)) {
6096
+ if (!error && read_max >= 0 && read_len > read_max - read_total) [[unlikely]] {
6097
6097
  LogError("Exceeded max stream size of %1", FmtDiskSize(read_max));
6098
6098
  error = true;
6099
6099
  return -1;
@@ -6105,7 +6105,7 @@ Size StreamReader::Read(Span<uint8_t> out_buf)
6105
6105
 
6106
6106
  Size StreamReader::ReadAll(Size max_len, HeapArray<uint8_t> *out_buf)
6107
6107
  {
6108
- if (RG_UNLIKELY(error))
6108
+ if (error) [[unlikely]]
6109
6109
  return -1;
6110
6110
 
6111
6111
  RG_DEFER_NC(buf_guard, buf_len = out_buf->len) { out_buf->RemoveFrom(buf_len); };
@@ -6114,7 +6114,7 @@ Size StreamReader::ReadAll(Size max_len, HeapArray<uint8_t> *out_buf)
6114
6114
  {
6115
6115
  Size memory_max = RG_SIZE_MAX - out_buf->len - 1;
6116
6116
 
6117
- if (RG_UNLIKELY(memory_max <= 0)) {
6117
+ if (memory_max <= 0) [[unlikely]] {
6118
6118
  LogError("Exhausted memory limit reading file '%1'", filename);
6119
6119
  return -1;
6120
6120
  }
@@ -6154,7 +6154,7 @@ Size StreamReader::ReadAll(Size max_len, HeapArray<uint8_t> *out_buf)
6154
6154
  if (read_len < 0)
6155
6155
  return -1;
6156
6156
 
6157
- if (RG_UNLIKELY(read_len > max_len - total_len)) {
6157
+ if (read_len > max_len - total_len) [[unlikely]] {
6158
6158
  LogError("File '%1' is too large (limit = %2)", filename, FmtDiskSize(max_len));
6159
6159
  return -1;
6160
6160
  }
@@ -6170,7 +6170,7 @@ Size StreamReader::ReadAll(Size max_len, HeapArray<uint8_t> *out_buf)
6170
6170
 
6171
6171
  int64_t StreamReader::ComputeRawLen()
6172
6172
  {
6173
- if (RG_UNLIKELY(error))
6173
+ if (error) [[unlikely]]
6174
6174
  return -1;
6175
6175
  if (raw_read || raw_len >= 0)
6176
6176
  return raw_len;
@@ -6289,7 +6289,7 @@ bool LineReader::Next(Span<char> *out_line)
6289
6289
  line_number = 0;
6290
6290
  return false;
6291
6291
  }
6292
- if (RG_UNLIKELY(error))
6292
+ if (error) [[unlikely]]
6293
6293
  return false;
6294
6294
 
6295
6295
  for (;;) {
@@ -6466,7 +6466,7 @@ bool StreamWriter::Open(const std::function<bool(Span<const uint8_t>)> &func, co
6466
6466
 
6467
6467
  bool StreamWriter::Flush()
6468
6468
  {
6469
- if (RG_UNLIKELY(error))
6469
+ if (error) [[unlikely]]
6470
6470
  return false;
6471
6471
 
6472
6472
  switch (dest.type) {
@@ -6504,7 +6504,7 @@ int StreamWriter::GetDescriptor() const
6504
6504
 
6505
6505
  bool StreamWriter::Write(Span<const uint8_t> buf)
6506
6506
  {
6507
- if (RG_UNLIKELY(error))
6507
+ if (error) [[unlikely]]
6508
6508
  return false;
6509
6509
 
6510
6510
  if (compressor) {
@@ -6688,7 +6688,7 @@ bool SpliceStream(StreamReader *reader, int64_t max_len, StreamWriter *writer)
6688
6688
  if (buf.len < 0)
6689
6689
  return false;
6690
6690
 
6691
- if (RG_UNLIKELY(max_len >= 0 && buf.len > max_len - total_len)) {
6691
+ if (max_len >= 0 && buf.len > max_len - total_len) [[unlikely]] {
6692
6692
  LogError("File '%1' is too large (limit = %2)", reader->GetFileName(), FmtDiskSize(max_len));
6693
6693
  return false;
6694
6694
  }
@@ -6724,7 +6724,7 @@ static bool CheckIniKey(Span<const char> key)
6724
6724
 
6725
6725
  IniParser::LineType IniParser::FindNextLine(IniProperty *out_prop)
6726
6726
  {
6727
- if (RG_UNLIKELY(error))
6727
+ if (error) [[unlikely]]
6728
6728
  return LineType::Exit;
6729
6729
 
6730
6730
  RG_DEFER_N(err_guard) { error = true; };
@@ -6921,7 +6921,7 @@ static bool assets_ready;
6921
6921
 
6922
6922
  void InitPackedMap(Span<const AssetInfo> assets)
6923
6923
  {
6924
- if (RG_LIKELY(!assets_ready)) {
6924
+ if (!assets_ready) [[likely]] {
6925
6925
  for (const AssetInfo &asset: assets) {
6926
6926
  PackedAssets_map.Set(&asset);
6927
6927
  }
@@ -6933,39 +6933,27 @@ void InitPackedMap(Span<const AssetInfo> assets)
6933
6933
  bool PatchFile(StreamReader *reader, StreamWriter *writer,
6934
6934
  FunctionRef<void(Span<const char>, StreamWriter *)> func)
6935
6935
  {
6936
- char c;
6937
- while (reader->Read(1, &c) == 1) {
6938
- if (c == '{') {
6939
- char name[33] = {};
6940
- Size name_len = reader->Read(1, &name[0]);
6941
- RG_ASSERT(name_len >= 0);
6936
+ LineReader splitter(reader);
6942
6937
 
6943
- if (IsAsciiAlpha(name[0]) || name[0] == '_') {
6944
- do {
6945
- Size read_len = reader->Read(1, &name[name_len]);
6946
- RG_ASSERT(read_len >= 0);
6938
+ Span<const char> line;
6939
+ while (splitter.Next(&line) && writer->IsValid()) {
6940
+ while (line.len) {
6941
+ Span<const char> before = SplitStr(line, "{{", &line);
6947
6942
 
6948
- if (name[name_len] == '}') {
6949
- name[name_len] = 0;
6943
+ writer->Write(before);
6950
6944
 
6951
- Span<const char> key = MakeSpan(name, name_len);
6952
- func(key, writer);
6945
+ if (before.end() < line.ptr) {
6946
+ Span<const char> expr = SplitStr(line, "}}", &line);
6953
6947
 
6954
- break;
6955
- } else if (!IsAsciiAlphaOrDigit(name[name_len]) && name[name_len] != '_') {
6956
- writer->Write('{');
6957
- writer->Write(name, name_len + 1);
6958
-
6959
- break;
6960
- }
6961
- } while (++name_len < RG_SIZE(name));
6962
- } else {
6963
- writer->Write('{');
6964
- writer->Write(name[0]);
6948
+ if (expr.end() < line.ptr) {
6949
+ func(expr, writer);
6950
+ } else {
6951
+ Print(writer, "{{%1", expr);
6952
+ }
6965
6953
  }
6966
- } else {
6967
- writer->Write(c);
6968
6954
  }
6955
+
6956
+ writer->Write('\n');
6969
6957
  }
6970
6958
 
6971
6959
  if (!reader->IsValid())
@@ -162,8 +162,6 @@ static_assert(sizeof(double) == 8, "This code base is not designed to support si
162
162
  #else
163
163
  #define RG_THREAD_LOCAL __thread
164
164
  #endif
165
- #define RG_LIKELY(Cond) __builtin_expect(!!(Cond), 1)
166
- #define RG_UNLIKELY(Cond) __builtin_expect(!!(Cond), 0)
167
165
 
168
166
  #ifndef SCNd8
169
167
  #define SCNd8 "hhd"
@@ -179,8 +177,6 @@ static_assert(sizeof(double) == 8, "This code base is not designed to support si
179
177
  #define RG_POP_NO_WARNINGS __pragma(warning(pop))
180
178
 
181
179
  #define RG_THREAD_LOCAL thread_local
182
- #define RG_LIKELY(Cond) (Cond)
183
- #define RG_UNLIKELY(Cond) (Cond)
184
180
  #else
185
181
  #error Compiler not supported
186
182
  #endif
@@ -217,7 +213,7 @@ extern "C" void AssertMessage(const char *filename, int line, const char *cond);
217
213
 
218
214
  #define RG_CRITICAL(Cond, ...) \
219
215
  do { \
220
- if (RG_UNLIKELY(!(Cond))) { \
216
+ if (!(Cond)) [[unlikely]] { \
221
217
  PrintLn(stderr, __VA_ARGS__); \
222
218
  abort(); \
223
219
  } \
@@ -225,7 +221,7 @@ extern "C" void AssertMessage(const char *filename, int line, const char *cond);
225
221
  #ifdef RG_DEBUG
226
222
  #define RG_ASSERT(Cond) \
227
223
  do { \
228
- if (RG_UNLIKELY(!(Cond))) { \
224
+ if (!(Cond)) [[unlikely]] { \
229
225
  RG::AssertMessage(__FILE__, __LINE__, RG_STRINGIFY(Cond)); \
230
226
  RG_DEBUG_BREAK(); \
231
227
  abort(); \
@@ -237,8 +233,6 @@ extern "C" void AssertMessage(const char *filename, int line, const char *cond);
237
233
  (void)sizeof(Cond); \
238
234
  } while (false)
239
235
  #endif
240
- #define RG_STATIC_ASSERT(Cond) \
241
- static_assert((Cond), RG_STRINGIFY(Cond))
242
236
 
243
237
  #if defined(RG_DEBUG)
244
238
  #define RG_UNREACHABLE() \
@@ -2104,7 +2098,7 @@ public:
2104
2098
 
2105
2099
  void RemoveAll()
2106
2100
  {
2107
- RG_STATIC_ASSERT(!std::is_pointer<ValueType>::value);
2101
+ static_assert(!std::is_pointer<ValueType>::value);
2108
2102
 
2109
2103
  for (Size i = 0; i < capacity; i++) {
2110
2104
  if (!IsEmpty(i)) {
@@ -3436,6 +3430,53 @@ static inline Span<const char> SplitStr(Span<const char> str, char split_char, S
3436
3430
  static inline Span<const char> SplitStr(const char *str, char split_char, const char **out_remainder = nullptr)
3437
3431
  { return SplitStr((char *)str, split_char, (char **)out_remainder); }
3438
3432
 
3433
+ static inline Span<char> SplitStr(Span<char> str, const char *split_str, Span<char> *out_remainder = nullptr)
3434
+ {
3435
+ RG_ASSERT(split_str[0]);
3436
+
3437
+ Size part_len = 0;
3438
+ while (part_len < str.len) {
3439
+ if (StartsWith(str.Take(part_len, str.len - part_len), split_str)) {
3440
+ if (out_remainder) {
3441
+ Size split_len = strlen(split_str);
3442
+ *out_remainder = str.Take(part_len + split_len, str.len - part_len - split_len);
3443
+ }
3444
+ return str.Take(0, part_len);
3445
+ }
3446
+ part_len++;
3447
+ }
3448
+
3449
+ if (out_remainder) {
3450
+ *out_remainder = str.Take(str.len, 0);
3451
+ }
3452
+ return str;
3453
+ }
3454
+ static inline Span<char> SplitStr(char *str, const char *split_str, char **out_remainder = nullptr)
3455
+ {
3456
+ RG_ASSERT(split_str[0]);
3457
+
3458
+ Size part_len = 0;
3459
+ while (str[part_len]) {
3460
+ if (StartsWith(str + part_len, split_str)) {
3461
+ if (out_remainder) {
3462
+ Size split_len = strlen(split_str);
3463
+ *out_remainder = str + part_len + split_len;
3464
+ }
3465
+ return MakeSpan(str, part_len);
3466
+ }
3467
+ part_len++;
3468
+ }
3469
+
3470
+ if (out_remainder) {
3471
+ *out_remainder = str + part_len;
3472
+ }
3473
+ return MakeSpan(str, part_len);
3474
+ }
3475
+ static inline Span<const char> SplitStr(Span<const char> str, const char *split_str, Span<const char> *out_remainder = nullptr)
3476
+ { return SplitStr(MakeSpan((char *)str.ptr, str.len), split_str, (Span<char> *)out_remainder); }
3477
+ static inline Span<const char> SplitStr(const char *str, const char *split_str, const char **out_remainder = nullptr)
3478
+ { return SplitStr((char *)str, split_str, (char **)out_remainder); }
3479
+
3439
3480
  static inline Span<char> SplitStrLine(Span<char> str, Span<char> *out_remainder = nullptr)
3440
3481
  {
3441
3482
  Span<char> part = SplitStr(str, '\n', out_remainder);
@@ -3603,7 +3644,7 @@ template <typename T>
3603
3644
  bool ParseInt(Span<const char> str, T *out_value, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
3604
3645
  Span<const char> *out_remaining = nullptr)
3605
3646
  {
3606
- if (RG_UNLIKELY(!str.len)) {
3647
+ if (!str.len) [[unlikely]] {
3607
3648
  if (flags & (int)ParseFlag::Log) {
3608
3649
  LogError("Cannot convert empty string to integer");
3609
3650
  }
@@ -3625,7 +3666,7 @@ bool ParseInt(Span<const char> str, T *out_value, unsigned int flags = RG_DEFAUL
3625
3666
 
3626
3667
  for (; pos < str.len; pos++) {
3627
3668
  unsigned int digit = (unsigned int)(str[pos] - '0');
3628
- if (RG_UNLIKELY(digit > 9)) {
3669
+ if (digit > 9) [[unlikely]] {
3629
3670
  if (!pos || flags & (int)ParseFlag::End) {
3630
3671
  if (flags & (int)ParseFlag::Log) {
3631
3672
  LogError("Malformed integer number '%1'", str);
@@ -3637,11 +3678,11 @@ bool ParseInt(Span<const char> str, T *out_value, unsigned int flags = RG_DEFAUL
3637
3678
  }
3638
3679
 
3639
3680
  uint64_t new_value = (value * 10) + digit;
3640
- if (RG_UNLIKELY(new_value < value))
3681
+ if (new_value < value) [[unlikely]]
3641
3682
  goto overflow;
3642
3683
  value = new_value;
3643
3684
  }
3644
- if (RG_UNLIKELY(value > (uint64_t)std::numeric_limits<T>::max()))
3685
+ if (value > (uint64_t)std::numeric_limits<T>::max()) [[unlikely]]
3645
3686
  goto overflow;
3646
3687
  value = ((value ^ neg) - neg);
3647
3688
 
@@ -3704,18 +3745,18 @@ static inline Size DecodeUtf8(const char *str, int32_t *out_c)
3704
3745
  if (ptr[0] < 0x80) {
3705
3746
  *out_c = ptr[0];
3706
3747
  return 1;
3707
- } else if (RG_UNLIKELY(ptr[0] - 0xC2 > 0xF4 - 0xC2)) {
3748
+ } else if (ptr[0] - 0xC2 > 0xF4 - 0xC2) [[unlikely]] {
3708
3749
  return 0;
3709
- } else if (RG_LIKELY(ptr[1])) {
3750
+ } else if (ptr[1]) [[likely]] {
3710
3751
  if (ptr[0] < 0xE0 && (ptr[1] & 0xC0) == 0x80) {
3711
3752
  *out_c = ((ptr[0] & 0x1F) << 6) | (ptr[1] & 0x3F);
3712
3753
  return 2;
3713
- } else if (RG_LIKELY(ptr[2])) {
3754
+ } else if (ptr[2]) [[likely]] {
3714
3755
  if (ptr[0] < 0xF0 && (ptr[1] & 0xC0) == 0x80 &&
3715
3756
  (ptr[2] & 0xC0) == 0x80) {
3716
3757
  *out_c = ((ptr[0] & 0xF) << 12) | ((ptr[1] & 0x3F) << 6) | (ptr[2] & 0x3F);
3717
3758
  return 3;
3718
- } else if (RG_LIKELY(ptr[3])) {
3759
+ } else if (ptr[3]) [[likely]] {
3719
3760
  if ((ptr[1] & 0xC0) == 0x80 &&
3720
3761
  (ptr[2] & 0xC0) == 0x80 &&
3721
3762
  (ptr[3] & 0xC0) == 0x80) {
@@ -3739,20 +3780,18 @@ static inline Size DecodeUtf8(Span<const char> str, Size offset, int32_t *out_c)
3739
3780
  if (ptr[0] < 0x80) {
3740
3781
  *out_c = ptr[0];
3741
3782
  return 1;
3742
- } else if (RG_UNLIKELY(ptr[0] - 0xC2 > 0xF4 - 0xC2)) {
3783
+ } else if (ptr[0] - 0xC2 > 0xF4 - 0xC2) [[unlikely]] {
3743
3784
  return 0;
3744
- } else if (ptr[0] < 0xE0 &&
3745
- RG_LIKELY(available >= 2 && (ptr[1] & 0xC0) == 0x80)) {
3785
+ } else if (ptr[0] < 0xE0 && available >= 2 && (ptr[1] & 0xC0) == 0x80) {
3746
3786
  *out_c = ((ptr[0] & 0x1F) << 6) | (ptr[1] & 0x3F);
3747
3787
  return 2;
3748
- } else if (ptr[0] < 0xF0 &&
3749
- RG_LIKELY(available >= 3 && (ptr[1] & 0xC0) == 0x80 &&
3750
- (ptr[2] & 0xC0) == 0x80)) {
3788
+ } else if (ptr[0] < 0xF0 && available >= 3 && (ptr[1] & 0xC0) == 0x80 &&
3789
+ (ptr[2] & 0xC0) == 0x80) {
3751
3790
  *out_c = ((ptr[0] & 0xF) << 12) | ((ptr[1] & 0x3F) << 6) | (ptr[2] & 0x3F);
3752
3791
  return 3;
3753
- } else if (RG_LIKELY(available >= 4 && (ptr[1] & 0xC0) == 0x80 &&
3754
- (ptr[2] & 0xC0) == 0x80 &&
3755
- (ptr[3] & 0xC0) == 0x80)) {
3792
+ } else if (available >= 4 && (ptr[1] & 0xC0) == 0x80 &&
3793
+ (ptr[2] & 0xC0) == 0x80 &&
3794
+ (ptr[3] & 0xC0) == 0x80) {
3756
3795
  *out_c = ((ptr[0] & 0x7) << 18) | ((ptr[1] & 0x3F) << 12) | ((ptr[2] & 0x3F) << 6) | (ptr[3] & 0x3F);
3757
3796
  return 4;
3758
3797
  } else {
@@ -4092,8 +4131,8 @@ private:
4092
4131
 
4093
4132
  template <int Min = 0, int Max = INT_MAX>
4094
4133
  class FastRandomInt {
4095
- RG_STATIC_ASSERT(Min >= 0);
4096
- RG_STATIC_ASSERT(Max > Min);
4134
+ static_assert(Min >= 0);
4135
+ static_assert(Max > Min);
4097
4136
 
4098
4137
  FastRandom rng;
4099
4138
 
@@ -54,7 +54,7 @@ public:
54
54
 
55
55
  bool MinizDecompressor::Init(CompressionType type)
56
56
  {
57
- RG_STATIC_ASSERT(RG_SIZE(out_buf) >= TINFL_LZ_DICT_SIZE);
57
+ static_assert(RG_SIZE(out_buf) >= TINFL_LZ_DICT_SIZE);
58
58
 
59
59
  tinfl_init(&inflator);
60
60
  is_gzip = (type == CompressionType::Gzip);
@@ -177,7 +177,7 @@ Size MinizDecompressor::Read(Size max_len, void *user_buf)
177
177
  // Gzip footer (CRC and size check)
178
178
  if (is_gzip) {
179
179
  uint32_t footer[2];
180
- RG_STATIC_ASSERT(RG_SIZE(footer) == 8);
180
+ static_assert(RG_SIZE(footer) == 8);
181
181
 
182
182
  if (in_len < RG_SIZE(footer)) {
183
183
  memcpy_safe(footer, in_ptr, (size_t)in_len);
@@ -28,11 +28,7 @@ include(CheckCXXCompilerFlag)
28
28
 
29
29
  find_package(CNoke)
30
30
 
31
- if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.8.0")
32
- set(CMAKE_CXX_STANDARD 17)
33
- else()
34
- set(CMAKE_CXX_STANDARD 14)
35
- endif()
31
+ set(CMAKE_CXX_STANDARD 17)
36
32
  if(MSVC)
37
33
  set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded)
38
34