koffi 1.3.12 → 2.1.0-beta.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 (104) hide show
  1. package/CMakeLists.txt +8 -10
  2. package/ChangeLog.md +48 -16
  3. package/README.md +6 -0
  4. package/benchmark/atoi_koffi.js +12 -8
  5. package/benchmark/atoi_napi.js +12 -8
  6. package/benchmark/atoi_node_ffi.js +11 -10
  7. package/benchmark/raylib_cc.cc +12 -9
  8. package/benchmark/raylib_koffi.js +15 -13
  9. package/benchmark/raylib_node_ffi.js +15 -13
  10. package/benchmark/raylib_node_raylib.js +14 -11
  11. package/build/qemu/2.1.0-beta.1/koffi_darwin_arm64.tar.gz +0 -0
  12. package/build/qemu/2.1.0-beta.1/koffi_darwin_x64.tar.gz +0 -0
  13. package/build/qemu/2.1.0-beta.1/koffi_freebsd_arm64.tar.gz +0 -0
  14. package/build/qemu/2.1.0-beta.1/koffi_freebsd_ia32.tar.gz +0 -0
  15. package/build/qemu/2.1.0-beta.1/koffi_freebsd_x64.tar.gz +0 -0
  16. package/build/qemu/2.1.0-beta.1/koffi_linux_arm32hf.tar.gz +0 -0
  17. package/build/qemu/2.1.0-beta.1/koffi_linux_arm64.tar.gz +0 -0
  18. package/build/qemu/2.1.0-beta.1/koffi_linux_ia32.tar.gz +0 -0
  19. package/build/qemu/2.1.0-beta.1/koffi_linux_riscv64hf64.tar.gz +0 -0
  20. package/build/qemu/2.1.0-beta.1/koffi_linux_x64.tar.gz +0 -0
  21. package/build/qemu/2.1.0-beta.1/koffi_openbsd_ia32.tar.gz +0 -0
  22. package/build/qemu/2.1.0-beta.1/koffi_openbsd_x64.tar.gz +0 -0
  23. package/build/qemu/2.1.0-beta.1/koffi_win32_arm64.tar.gz +0 -0
  24. package/build/qemu/2.1.0-beta.1/koffi_win32_ia32.tar.gz +0 -0
  25. package/build/qemu/2.1.0-beta.1/koffi_win32_x64.tar.gz +0 -0
  26. package/doc/changes.md +160 -1
  27. package/doc/conf.py +14 -1
  28. package/doc/contribute.md +0 -1
  29. package/doc/dist/doctrees/benchmarks.doctree +0 -0
  30. package/doc/dist/doctrees/changes.doctree +0 -0
  31. package/doc/dist/doctrees/environment.pickle +0 -0
  32. package/doc/dist/doctrees/functions.doctree +0 -0
  33. package/doc/dist/doctrees/index.doctree +0 -0
  34. package/doc/dist/doctrees/types.doctree +0 -0
  35. package/doc/dist/html/.buildinfo +1 -1
  36. package/doc/dist/html/_sources/benchmarks.md.txt +2 -2
  37. package/doc/dist/html/_sources/changes.md.txt +160 -1
  38. package/doc/dist/html/_sources/functions.md.txt +17 -13
  39. package/doc/dist/html/_sources/types.md.txt +87 -35
  40. package/doc/dist/html/benchmarks.html +7 -3
  41. package/doc/dist/html/changes.html +241 -14
  42. package/doc/dist/html/contribute.html +5 -1
  43. package/doc/dist/html/functions.html +30 -23
  44. package/doc/dist/html/genindex.html +5 -1
  45. package/doc/dist/html/index.html +13 -19
  46. package/doc/dist/html/memory.html +7 -3
  47. package/doc/dist/html/objects.inv +0 -0
  48. package/doc/dist/html/platforms.html +6 -2
  49. package/doc/dist/html/search.html +5 -1
  50. package/doc/dist/html/searchindex.js +1 -1
  51. package/doc/dist/html/start.html +5 -1
  52. package/doc/dist/html/types.html +104 -43
  53. package/doc/functions.md +139 -15
  54. package/doc/templates/badges.html +5 -0
  55. package/doc/types.md +108 -40
  56. package/package.json +2 -2
  57. package/qemu/qemu.js +1 -1
  58. package/qemu/registry/machines.json +5 -5
  59. package/qemu/registry/sha256sum.txt +16 -16
  60. package/src/abi_arm32.cc +91 -19
  61. package/src/abi_arm32_fwd.S +121 -57
  62. package/src/abi_arm64.cc +91 -19
  63. package/src/abi_arm64_fwd.S +96 -0
  64. package/src/abi_arm64_fwd.asm +128 -0
  65. package/src/abi_riscv64.cc +89 -19
  66. package/src/abi_riscv64_fwd.S +96 -0
  67. package/src/abi_x64_sysv.cc +94 -22
  68. package/src/abi_x64_sysv_fwd.S +96 -0
  69. package/src/abi_x64_win.cc +89 -19
  70. package/src/abi_x64_win_fwd.asm +128 -0
  71. package/src/abi_x86.cc +94 -19
  72. package/src/abi_x86_fwd.S +96 -0
  73. package/src/abi_x86_fwd.asm +128 -0
  74. package/src/call.cc +128 -78
  75. package/src/call.hh +17 -4
  76. package/src/ffi.cc +514 -145
  77. package/src/ffi.hh +30 -9
  78. package/src/index.js +4 -2
  79. package/src/parser.cc +19 -44
  80. package/src/util.cc +160 -27
  81. package/src/util.hh +7 -2
  82. package/test/async.js +1 -2
  83. package/test/callbacks.js +56 -11
  84. package/test/misc.c +50 -15
  85. package/test/raylib.js +2 -2
  86. package/test/sqlite.js +27 -19
  87. package/test/sync.js +71 -35
  88. package/vendor/libcc/libcc.cc +18 -5
  89. package/vendor/libcc/libcc.hh +70 -23
  90. package/build/qemu/1.3.12/koffi_darwin_arm64.tar.gz +0 -0
  91. package/build/qemu/1.3.12/koffi_darwin_x64.tar.gz +0 -0
  92. package/build/qemu/1.3.12/koffi_freebsd_arm64.tar.gz +0 -0
  93. package/build/qemu/1.3.12/koffi_freebsd_ia32.tar.gz +0 -0
  94. package/build/qemu/1.3.12/koffi_freebsd_x64.tar.gz +0 -0
  95. package/build/qemu/1.3.12/koffi_linux_arm32hf.tar.gz +0 -0
  96. package/build/qemu/1.3.12/koffi_linux_arm64.tar.gz +0 -0
  97. package/build/qemu/1.3.12/koffi_linux_ia32.tar.gz +0 -0
  98. package/build/qemu/1.3.12/koffi_linux_riscv64hf64.tar.gz +0 -0
  99. package/build/qemu/1.3.12/koffi_linux_x64.tar.gz +0 -0
  100. package/build/qemu/1.3.12/koffi_openbsd_ia32.tar.gz +0 -0
  101. package/build/qemu/1.3.12/koffi_openbsd_x64.tar.gz +0 -0
  102. package/build/qemu/1.3.12/koffi_win32_arm64.tar.gz +0 -0
  103. package/build/qemu/1.3.12/koffi_win32_ia32.tar.gz +0 -0
  104. package/build/qemu/1.3.12/koffi_win32_x64.tar.gz +0 -0
package/test/misc.c CHANGED
@@ -90,7 +90,7 @@ typedef struct IJK8 { int64_t i; int64_t j; int64_t k; } IJK8;
90
90
 
91
91
  typedef struct BFG {
92
92
  int8_t a;
93
- int64_t b;
93
+ char _pad1[15]; int64_t b;
94
94
  signed char c;
95
95
  const char *d;
96
96
  short e;
@@ -399,6 +399,15 @@ EXPORT PackedBFG FASTCALL MakePackedBFG(int x, double y, PackedBFG *p, const cha
399
399
  return bfg;
400
400
  }
401
401
 
402
+ EXPORT void MakePolymorphBFG(int type, int x, double y, const char *str, void *p)
403
+ {
404
+ if (type == 0) {
405
+ MakeBFG(p, x, y, str);
406
+ } else if (type == 1) {
407
+ MakePackedBFG(x, y, p, str);
408
+ }
409
+ }
410
+
402
411
  #ifdef _WIN32
403
412
  // Exported by DEF file
404
413
  const char *ReturnBigString(const char *str)
@@ -406,24 +415,21 @@ const char *ReturnBigString(const char *str)
406
415
  EXPORT const char *ReturnBigString(const char *str)
407
416
  #endif
408
417
  {
409
- static char buf[16 * 1024 * 1024];
410
-
411
- size_t len = strlen(str);
412
- memcpy(buf, str, len + 1);
413
-
414
- return buf;
418
+ const char *copy = strdup(str);
419
+ return copy;
415
420
  }
416
421
 
417
422
  EXPORT const char *PrintFmt(const char *fmt, ...)
418
423
  {
419
- static char buf[256];
424
+ const int size = 256;
425
+ char *ptr = malloc(size);
420
426
 
421
427
  va_list ap;
422
428
  va_start(ap, fmt);
423
- vsnprintf(buf, sizeof(buf), fmt, ap);
429
+ vsnprintf(ptr, size, fmt, ap);
424
430
  va_end(ap);
425
431
 
426
- return buf;
432
+ return ptr;
427
433
  }
428
434
 
429
435
  size_t Length16(const char16_t *str)
@@ -437,16 +443,17 @@ size_t Length16(const char16_t *str)
437
443
 
438
444
  EXPORT const char16_t *Concat16(const char16_t *str1, const char16_t *str2)
439
445
  {
440
- static char16_t buf[1024];
446
+ const int size = 1024;
447
+ char16_t *ptr = malloc(size * 2);
441
448
 
442
449
  size_t len1 = Length16(str1);
443
450
  size_t len2 = Length16(str2);
444
451
 
445
- memcpy(buf, str1, len1 * 2);
446
- memcpy(buf + len1, str2, len2 * 2);
447
- buf[(len1 + len2) * 2] = 0;
452
+ memcpy(ptr, str1, len1 * 2);
453
+ memcpy(ptr + len1, str2, len2 * 2);
454
+ ptr[len1 + len2] = 0;
448
455
 
449
- return buf;
456
+ return ptr;
450
457
  }
451
458
 
452
459
  EXPORT FixedString ReturnFixedStr(FixedString str)
@@ -549,6 +556,11 @@ EXPORT BFG ModifyBFG(int x, double y, const char *str, BFG (*func)(BFG bfg), BFG
549
556
  return bfg;
550
557
  }
551
558
 
559
+ EXPORT void Recurse8(int i, void (*func)(int i, int v1, double v2, int v3, int v4, int v5, int v6, float v7, int v8))
560
+ {
561
+ func(i, i, (double)(i * 2), i + 1, i * 2 + 1, 3 - i, 100 + i, (float)(i % 2), -i - 1);
562
+ }
563
+
552
564
  EXPORT int ApplyStd(int a, int b, int c, ApplyCallback *func)
553
565
  {
554
566
  int ret = func(a, b, c);
@@ -618,3 +630,26 @@ EXPORT int ApplyStruct(int x, StructCallbacks callbacks)
618
630
 
619
631
  return x;
620
632
  }
633
+
634
+ static IntCallback *callback;
635
+
636
+ EXPORT void SetCallback(IntCallback *cb)
637
+ {
638
+ callback = cb;
639
+ }
640
+
641
+ EXPORT int CallCallback(int x)
642
+ {
643
+ return callback(x);
644
+ }
645
+
646
+ EXPORT void ReverseBytes(void *p, int len)
647
+ {
648
+ uint8_t *bytes = (uint8_t *)p;
649
+
650
+ for (int i = 0; i < len / 2; i++) {
651
+ uint8_t tmp = bytes[i];
652
+ bytes[i] = bytes[len - i - 1];
653
+ bytes[len - i - 1] = tmp;
654
+ }
655
+ }
package/test/raylib.js CHANGED
@@ -55,7 +55,7 @@ const Rectangle = koffi.struct('Rectangle', {
55
55
  });
56
56
 
57
57
  const Texture = koffi.struct('Texture', {
58
- id: 'uint',
58
+ id: 'unsigned int', // Extra space is on purpose, leave it!
59
59
  width: 'int',
60
60
  height: 'int',
61
61
  mipmaps: 'int',
@@ -83,7 +83,7 @@ async function main() {
83
83
  }
84
84
 
85
85
  async function test() {
86
- let lib_filename = path.dirname(__filename) + '/build/raylib' + koffi.extension;
86
+ let lib_filename = __dirname + '/build/raylib' + koffi.extension;
87
87
  let lib = koffi.load(lib_filename);
88
88
 
89
89
  const InitWindow = lib.func('InitWindow', 'void', ['int', 'int', 'str']);
package/test/sqlite.js CHANGED
@@ -20,8 +20,8 @@ const fs = require('fs');
20
20
  const os = require('os');
21
21
  const path = require('path');
22
22
 
23
- const sqlite3_db = koffi.handle('sqlite3_db');
24
- const sqlite3_stmt = koffi.handle('sqlite3_stmt');
23
+ const sqlite3 = koffi.opaque('sqlite3');
24
+ const sqlite3_stmt = koffi.opaque('sqlite3_stmt');
25
25
 
26
26
  main();
27
27
 
@@ -36,20 +36,20 @@ async function main() {
36
36
  }
37
37
 
38
38
  async function test() {
39
- let lib_filename = path.dirname(__filename) + '/build/sqlite3' + koffi.extension;
39
+ let lib_filename = __dirname + '/build/sqlite3' + koffi.extension;
40
40
  let lib = koffi.load(lib_filename);
41
41
 
42
- const sqlite3_open_v2 = lib.func('sqlite3_open_v2', 'int', ['str', koffi.out(koffi.pointer(sqlite3_db)), 'int', 'str']);
43
- const sqlite3_exec = lib.func('sqlite3_exec', 'int', [sqlite3_db, 'str', 'void *', 'void *', 'void *']);
44
- const sqlite3_prepare_v2 = lib.func('sqlite3_prepare_v2', 'int', [sqlite3_db, 'str', 'int', koffi.out(koffi.pointer(sqlite3_stmt)), 'string']);
45
- const sqlite3_reset = lib.func('sqlite3_reset', 'int', [sqlite3_stmt]);
46
- const sqlite3_bind_text = lib.func('sqlite3_bind_text', 'int', [sqlite3_stmt, 'int', 'str', 'int', 'void *']);
47
- const sqlite3_bind_int = lib.func('sqlite3_bind_int', 'int', [sqlite3_stmt, 'int', 'int']);
48
- const sqlite3_column_text = lib.func('sqlite3_column_text', 'str', [sqlite3_stmt, 'int']);
49
- const sqlite3_column_int = lib.func('sqlite3_column_int', 'int', [sqlite3_stmt, 'int']);
50
- const sqlite3_step = lib.func('sqlite3_step', 'int', [sqlite3_stmt]);
51
- const sqlite3_finalize = lib.func('sqlite3_finalize', 'int', [sqlite3_stmt]);
52
- const sqlite3_close_v2 = lib.func('sqlite3_close_v2', 'int', [sqlite3_db]);
42
+ const sqlite3_open_v2 = lib.func('sqlite3_open_v2', 'int', ['str', koffi.out(koffi.pointer(sqlite3, 2)), 'int', 'str']);
43
+ const sqlite3_exec = lib.func('sqlite3_exec', 'int', [koffi.pointer(sqlite3), 'str', 'void *', 'void *', 'void *']);
44
+ const sqlite3_prepare_v2 = lib.func('sqlite3_prepare_v2', 'int', [koffi.pointer(sqlite3), 'str', 'int', koffi.out(koffi.pointer(sqlite3_stmt, 2)), 'string']);
45
+ const sqlite3_reset = lib.func('sqlite3_reset', 'int', [koffi.pointer(sqlite3_stmt)]);
46
+ const sqlite3_bind_text = lib.func('sqlite3_bind_text', 'int', [koffi.pointer(sqlite3_stmt), 'int', 'str', 'int', 'void *']);
47
+ const sqlite3_bind_int = lib.func('sqlite3_bind_int', 'int', [koffi.pointer(sqlite3_stmt), 'int', 'int']);
48
+ const sqlite3_column_text = lib.func('sqlite3_column_text', 'str', [koffi.pointer(sqlite3_stmt), 'int']);
49
+ const sqlite3_column_int = lib.func('sqlite3_column_int', 'int', [koffi.pointer(sqlite3_stmt), 'int']);
50
+ const sqlite3_step = lib.func('sqlite3_step', 'int', [koffi.pointer(sqlite3_stmt)]);
51
+ const sqlite3_finalize = lib.func('sqlite3_finalize', 'int', [koffi.pointer(sqlite3_stmt)]);
52
+ const sqlite3_close_v2 = lib.func('sqlite3_close_v2', 'int', [koffi.pointer(sqlite3)]);
53
53
 
54
54
  const SQLITE_OPEN_READWRITE = 0x2;
55
55
  const SQLITE_OPEN_CREATE = 0x4;
@@ -57,20 +57,27 @@ async function test() {
57
57
  const SQLITE_DONE = 101;
58
58
 
59
59
  let filename = await create_temporary_file(path.join(os.tmpdir(), 'test_sqlite'));
60
- let db = {};
60
+ let db = null;
61
61
 
62
62
  let expected = Array.from(Array(200).keys()).map(i => [`TXT ${i}`, i % 7]);
63
63
 
64
64
  try {
65
- if (sqlite3_open_v2(filename, db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, null) != 0)
65
+ let ptr = [null];
66
+
67
+ // Open database
68
+ if (sqlite3_open_v2(filename, ptr, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, null) != 0)
66
69
  throw new Error('Failed to open database');
70
+ db = ptr[0];
71
+
67
72
  if (sqlite3_exec(db, 'CREATE TABLE foo (id INTEGER PRIMARY KEY, bar TEXT, value INT);', null, null, null) != 0)
68
73
  throw new Error('Failed to create table');
69
74
 
70
- let stmt = {};
75
+ let stmt = null;
71
76
 
72
- if (sqlite3_prepare_v2(db, "INSERT INTO foo (bar, value) VALUES (?1, ?2)", -1, stmt, null) != 0)
77
+ if (sqlite3_prepare_v2(db, "INSERT INTO foo (bar, value) VALUES (?1, ?2)", -1, ptr, null) != 0)
73
78
  throw new Error('Failed to prepare insert statement for table foo');
79
+ stmt = ptr[0];
80
+
74
81
  for (let it of expected) {
75
82
  sqlite3_reset(stmt);
76
83
 
@@ -82,8 +89,9 @@ async function test() {
82
89
  }
83
90
  sqlite3_finalize(stmt);
84
91
 
85
- if (sqlite3_prepare_v2(db, "SELECT id, bar, value FROM foo ORDER BY id", -1, stmt, null) != 0)
92
+ if (sqlite3_prepare_v2(db, "SELECT id, bar, value FROM foo ORDER BY id", -1, ptr, null) != 0)
86
93
  throw new Error('Failed to prepare select statement for table foo');
94
+ stmt = ptr[0];
87
95
  for (let i = 0; i < expected.length; i++) {
88
96
  let it = expected[i];
89
97
 
package/test/sync.js CHANGED
@@ -15,7 +15,6 @@
15
15
 
16
16
  const koffi = require('./build/koffi.node');
17
17
  const assert = require('assert');
18
- const path = require('path');
19
18
 
20
19
  const Pack1 = koffi.struct('Pack1', {
21
20
  a: 'int'
@@ -62,9 +61,9 @@ const IntFloat = koffi.struct('IntFloat', {
62
61
 
63
62
  const BFG = koffi.struct('BFG', {
64
63
  a: 'int8_t',
65
- b: 'int64_t',
64
+ b: [16, 'int64_t'],
66
65
  c: 'char',
67
- d: 'str',
66
+ d: 'const char *',
68
67
  e: 'short',
69
68
  inner: koffi.struct({
70
69
  f: 'float',
@@ -75,13 +74,14 @@ const PackedBFG = koffi.pack('PackedBFG', {
75
74
  a: 'int8_t',
76
75
  b: 'int64_t',
77
76
  c: 'char',
78
- d: 'str',
77
+ d: 'char *',
79
78
  e: 'short',
80
79
  inner: koffi.pack({
81
80
  f: 'float',
82
81
  g: 'double'
83
82
  })
84
83
  });
84
+ const AliasBFG = koffi.alias('AliasBFG', PackedBFG);
85
85
 
86
86
  const FixedString = koffi.struct('FixedString', {
87
87
  buf: koffi.array('int8', 64)
@@ -106,9 +106,12 @@ const IntContainer = koffi.struct('IntContainer', {
106
106
  len: 'int'
107
107
  });
108
108
 
109
+ const StrFree = koffi.disposable('str_free', koffi.types.str, koffi.free);
110
+ const Str16Free = koffi.disposable('str16_free', 'str16');
111
+
109
112
  const StrStruct = koffi.struct('StrStruct', {
110
113
  str: 'str',
111
- str16: 'str16'
114
+ str16: koffi.types.string16
112
115
  });
113
116
 
114
117
  main();
@@ -124,7 +127,7 @@ async function main() {
124
127
  }
125
128
 
126
129
  async function test() {
127
- let lib_filename = path.dirname(__filename) + '/build/misc' + koffi.extension;
130
+ let lib_filename = __dirname + '/build/misc' + koffi.extension;
128
131
  let lib = koffi.load(lib_filename);
129
132
 
130
133
  const GetMinusOne1 = lib.func('int8_t GetMinusOne1(void)');
@@ -155,12 +158,13 @@ async function test() {
155
158
  const ConcatenateToStr4 = lib.func('ConcatenateToStr4', 'str', [...Array(8).fill('int32_t'), koffi.pointer(koffi.struct('IJK4', {i: 'int32_t', j: 'int32_t', k: 'int32_t'})), 'int32_t']);
156
159
  const ConcatenateToStr8 = lib.func('ConcatenateToStr8', 'str', [...Array(8).fill('int64_t'), koffi.struct('IJK8', {i: 'int64_t', j: 'int64_t', k: 'int64_t'}), 'int64_t']);
157
160
  const MakeBFG = lib.func('BFG __stdcall MakeBFG(_Out_ BFG *p, int x, double y, const char *str)');
158
- const MakePackedBFG = lib.func('PackedBFG __fastcall MakePackedBFG(int x, double y, _Out_ PackedBFG *p, const char *str)');
161
+ const MakePackedBFG = lib.func('AliasBFG __fastcall MakePackedBFG(int x, double y, _Out_ PackedBFG *p, const char *str)');
162
+ const MakePolymorphBFG = lib.func('void MakePolymorphBFG(int type, int x, double y, const char *str, _Out_ void *p)');
159
163
  const ReturnBigString = process.platform == 'win32' ?
160
- lib.stdcall(1, 'str', ['str']) :
164
+ lib.stdcall(1, koffi.disposable('str', koffi.free), ['str']) :
161
165
  lib.func('const char * __stdcall ReturnBigString(const char *str)');
162
- const PrintFmt = lib.func('const char *PrintFmt(const char *fmt, ...)');
163
- const Concat16 = lib.func('const char16_t *Concat16(const char16_t *str1, const char16_t *str2)')
166
+ const PrintFmt = lib.func('str_free PrintFmt(const char *fmt, ...)');
167
+ const Concat16 = lib.func('const char16_t *! Concat16(const char16_t *str1, const char16_t *str2)')
164
168
  const ReturnFixedStr = lib.func('FixedString ReturnFixedStr(FixedString str)');
165
169
  const ReturnFixedStr2 = lib.func('FixedString2 ReturnFixedStr(FixedString2 str)');
166
170
  const ReturnFixedWide = lib.func('FixedWide ReturnFixedWide(FixedWide str)');
@@ -182,6 +186,7 @@ async function test() {
182
186
  const MultiplyIntegers = lib.func('void MultiplyIntegers(int multiplier, _Inout_ int *values, int len)');
183
187
  const ThroughStr = lib.func('str ThroughStr(StrStruct s)');
184
188
  const ThroughStr16 = lib.func('str16 ThroughStr16(StrStruct s)');
189
+ const ReverseBytes = lib.func('void ReverseBytes(_Inout_ void *array, int len)');
185
190
 
186
191
  // Simple signed value returns
187
192
  assert.equal(GetMinusOne1(), -1);
@@ -291,6 +296,17 @@ async function test() {
291
296
  assert.deepEqual(out, bfg);
292
297
  }
293
298
 
299
+ // Polymorph pointer
300
+ {
301
+ let bfg = {};
302
+
303
+ MakePolymorphBFG(0, 2, 7, 'boo', koffi.as(bfg, 'BFG *'));
304
+ assert.deepEqual(bfg, { a: 2, b: 4, c: -25, d: 'X/boo/X', e: 54, inner: { f: 14, g: 5 }});
305
+
306
+ MakePolymorphBFG(1, 2, 7, 'bies', koffi.as(bfg, 'PackedBFG *'));
307
+ assert.deepEqual(bfg, { a: 2, b: 4, c: -25, d: 'X/bies/X', e: 54, inner: { f: 14, g: 5 }});
308
+ }
309
+
294
310
  // Big string
295
311
  {
296
312
  let str = 'fooBAR!'.repeat(1024 * 1024);
@@ -320,30 +336,36 @@ async function test() {
320
336
 
321
337
  // Big numbers
322
338
  {
323
- assert.equal(ThroughUInt32UU(4294967284), 4294967284);
324
- assert.deepEqual(ThroughUInt32SS({ v: 4294967284 }), { v: 4294967284 });
325
- assert.deepEqual(ThroughUInt32SU(4294967284), { v: 4294967284 });
326
- assert.equal(ThroughUInt32US({ v: 4294967284 }), 4294967284);
327
-
328
- assert.equal(ThroughUInt64UU(9007199254740989), 9007199254740989);
329
- assert.deepEqual(ThroughUInt64SS({ v: 9007199254740989 }), { v: 9007199254740989 });
330
- assert.deepEqual(ThroughUInt64SU(9007199254740989), { v: 9007199254740989 });
331
- assert.equal(ThroughUInt64US({ v: 9007199254740989 }), 9007199254740989);
332
-
333
- assert.equal(ThroughUInt64UU(18446744073709551598n), 18446744073709551598n);
334
- assert.deepEqual(ThroughUInt64SS({ v: 18446744073709551598n }), { v: 18446744073709551598n });
335
- assert.deepEqual(ThroughUInt64SU(18446744073709551598n), { v: 18446744073709551598n });
336
- assert.equal(ThroughUInt64US({ v: 18446744073709551598n }), 18446744073709551598n);
337
-
338
- assert.equal(ThroughInt64II(-9007199254740989), -9007199254740989);
339
- assert.deepEqual(ThroughInt64SS({ v: -9007199254740989 }), { v: -9007199254740989 });
340
- assert.deepEqual(ThroughInt64SI(-9007199254740989), { v: -9007199254740989 });
341
- assert.equal(ThroughInt64IS({ v: -9007199254740989 }), -9007199254740989);
342
-
343
- assert.equal(ThroughInt64II(-9223372036854775803n), -9223372036854775803n);
344
- assert.deepEqual(ThroughInt64SS({ v: -9223372036854775803n }), { v: -9223372036854775803n });
345
- assert.deepEqual(ThroughInt64SI(-9223372036854775803n), { v: -9223372036854775803n });
346
- assert.equal(ThroughInt64IS({ v: -9223372036854775803n }), -9223372036854775803n);
339
+ assert.strictEqual(ThroughUInt32UU(4294967284), 4294967284);
340
+ assert.deepStrictEqual(ThroughUInt32SS({ v: 4294967284 }), { v: 4294967284 });
341
+ assert.deepStrictEqual(ThroughUInt32SU(4294967284), { v: 4294967284 });
342
+ assert.strictEqual(ThroughUInt32US({ v: 4294967284 }), 4294967284);
343
+
344
+ assert.strictEqual(ThroughUInt64UU(9007199254740992n), 9007199254740992);
345
+ assert.deepStrictEqual(ThroughUInt64SS({ v: 9007199254740992n }), { v: 9007199254740992 });
346
+ assert.deepStrictEqual(ThroughUInt64SU(9007199254740992n), { v: 9007199254740992 });
347
+ assert.strictEqual(ThroughUInt64US({ v: 9007199254740992n }), 9007199254740992);
348
+ assert.strictEqual(ThroughUInt64UU(9007199254740993n), 9007199254740993n);
349
+ assert.deepStrictEqual(ThroughUInt64SS({ v: 9007199254740993n }), { v: 9007199254740993n });
350
+ assert.deepStrictEqual(ThroughUInt64SU(9007199254740993n), { v: 9007199254740993n });
351
+ assert.strictEqual(ThroughUInt64US({ v: 9007199254740993n }), 9007199254740993n);
352
+ assert.strictEqual(ThroughUInt64UU(18446744073709551598n), 18446744073709551598n);
353
+ assert.deepStrictEqual(ThroughUInt64SS({ v: 18446744073709551598n }), { v: 18446744073709551598n });
354
+ assert.deepStrictEqual(ThroughUInt64SU(18446744073709551598n), { v: 18446744073709551598n });
355
+ assert.strictEqual(ThroughUInt64US({ v: 18446744073709551598n }), 18446744073709551598n);
356
+
357
+ assert.strictEqual(ThroughInt64II(-9007199254740992), -9007199254740992);
358
+ assert.deepStrictEqual(ThroughInt64SS({ v: -9007199254740992 }), { v: -9007199254740992 });
359
+ assert.deepStrictEqual(ThroughInt64SI(-9007199254740992), { v: -9007199254740992 });
360
+ assert.strictEqual(ThroughInt64IS({ v: -9007199254740992 }), -9007199254740992);
361
+ assert.strictEqual(ThroughInt64II(-9007199254740993n), -9007199254740993n);
362
+ assert.deepStrictEqual(ThroughInt64SS({ v: -9007199254740993n }), { v: -9007199254740993n });
363
+ assert.deepStrictEqual(ThroughInt64SI(-9007199254740993n), { v: -9007199254740993n });
364
+ assert.strictEqual(ThroughInt64IS({ v: -9007199254740993n }), -9007199254740993n);
365
+ assert.strictEqual(ThroughInt64II(-9223372036854775803n), -9223372036854775803n);
366
+ assert.deepStrictEqual(ThroughInt64SS({ v: -9223372036854775803n }), { v: -9223372036854775803n });
367
+ assert.deepStrictEqual(ThroughInt64SI(-9223372036854775803n), { v: -9223372036854775803n });
368
+ assert.strictEqual(ThroughInt64IS({ v: -9223372036854775803n }), -9223372036854775803n);
347
369
  }
348
370
 
349
371
  // Array pointers as input
@@ -362,10 +384,12 @@ async function test() {
362
384
  let out1 = Array(10);
363
385
  let out2 = new Int32Array(10);
364
386
  let mult = -3;
387
+ let ret = null;
365
388
 
366
389
  FillRange(2, 7, out1, out1.length);
367
- FillRange(13, 3, out2, out2.length);
390
+ ret = FillRange(13, 3, out2, out2.length);
368
391
 
392
+ assert.strictEqual(ret, undefined);
369
393
  assert.deepEqual(out1, [2, 9, 16, 23, 30, 37, 44, 51, 58, 65]);
370
394
  assert.deepEqual(out2, new Int32Array([13, 16, 19, 22, 25, 28, 31, 34, 37, 40]));
371
395
 
@@ -382,4 +406,16 @@ async function test() {
382
406
  assert.equal(ThroughStr16({ str: null, str16: 'World!' }), 'World!');
383
407
  assert.equal(ThroughStr16({ str: 'World!', str16: null }), null);
384
408
  }
409
+
410
+ // Transparent typed arrays for void pointers
411
+ {
412
+ let arr8 = Uint8Array.from([1, 2, 3, 4, 5]);
413
+ let arr16 = Int16Array.from([1, 2, 3, 4, 5]);
414
+
415
+ ReverseBytes(arr8, arr8.byteLength);
416
+ assert.deepEqual(arr8, Uint8Array.from([5, 4, 3, 2, 1]));
417
+
418
+ ReverseBytes(arr16, arr16.byteLength);
419
+ assert.deepEqual(arr16, Int16Array.from([1280, 1024, 768, 512, 256]));
420
+ }
385
421
  }
@@ -136,7 +136,7 @@ extern "C" void AssertMessage(const char *filename, int line, const char *cond)
136
136
 
137
137
  class MallocAllocator: public Allocator {
138
138
  protected:
139
- void *Allocate(Size size, unsigned int flags = 0) override
139
+ void *Allocate(Size size, unsigned int flags) override
140
140
  {
141
141
  void *ptr = malloc((size_t)size);
142
142
  RG_CRITICAL(ptr, "Failed to allocate %1 of memory", FmtMemSize(size));
@@ -148,7 +148,7 @@ protected:
148
148
  return ptr;
149
149
  }
150
150
 
151
- void Resize(void **ptr, Size old_size, Size new_size, unsigned int flags = 0) override
151
+ void Resize(void **ptr, Size old_size, Size new_size, unsigned int flags) override
152
152
  {
153
153
  if (!new_size) {
154
154
  Release(*ptr, old_size);
@@ -172,12 +172,25 @@ protected:
172
172
  }
173
173
  };
174
174
 
175
+ class NullAllocator: public Allocator {
176
+ protected:
177
+ void *Allocate(Size, unsigned int) override { RG_UNREACHABLE(); }
178
+ void Resize(void **, Size, Size, unsigned int) override { RG_UNREACHABLE(); }
179
+ void Release(void *, Size) override {}
180
+ };
181
+
175
182
  Allocator *GetDefaultAllocator()
176
183
  {
177
184
  static Allocator *default_allocator = new RG_DEFAULT_ALLOCATOR;
178
185
  return default_allocator;
179
186
  }
180
187
 
188
+ Allocator *GetNullAllocator()
189
+ {
190
+ static Allocator *null_allocator = new NullAllocator;
191
+ return null_allocator;
192
+ }
193
+
181
194
  LinkedAllocator& LinkedAllocator::operator=(LinkedAllocator &&other)
182
195
  {
183
196
  ReleaseAll();
@@ -639,13 +652,13 @@ TimeSpec DecomposeTime(int64_t time, TimeMode mode)
639
652
  #ifdef _WIN32
640
653
  __time64_t time64 = time / 1000;
641
654
 
642
- struct tm ti = {0};
655
+ struct tm ti = {};
643
656
  int offset = INT_MAX;
644
657
  switch (mode) {
645
658
  case TimeMode::Local: {
646
659
  _localtime64_s(&ti, &time64);
647
660
 
648
- struct tm utc = {0};
661
+ struct tm utc = {};
649
662
  _gmtime64_s(&utc, &time64);
650
663
 
651
664
  offset = (int)(_mktime64(&ti) - _mktime64(&utc) + (3600 * ti.tm_isdst));
@@ -660,7 +673,7 @@ TimeSpec DecomposeTime(int64_t time, TimeMode mode)
660
673
  #else
661
674
  time_t time64 = time / 1000;
662
675
 
663
- struct tm ti = {0};
676
+ struct tm ti = {};
664
677
  int offset = 0;
665
678
  switch (mode) {
666
679
  case TimeMode::Local: {