@zigc/lib 0.16.0 → 0.17.0-dev.131

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 (155) hide show
  1. package/c/fcntl.zig +6 -1
  2. package/c/inttypes.zig +0 -10
  3. package/c/math.zig +46 -122
  4. package/c/pthread.zig +57 -0
  5. package/c/search.zig +1 -27
  6. package/c/stdlib/drand48.zig +0 -57
  7. package/c/stdlib.zig +0 -100
  8. package/c/string.zig +20 -7
  9. package/c/strings.zig +0 -38
  10. package/c/unistd.zig +27 -26
  11. package/c/wchar.zig +10 -0
  12. package/c.zig +2 -2
  13. package/compiler/aro/aro/CodeGen.zig +5 -6
  14. package/compiler/aro/aro/Compilation.zig +17 -14
  15. package/compiler/aro/aro/Driver.zig +14 -13
  16. package/compiler/aro/aro/Parser.zig +20 -15
  17. package/compiler/aro/aro/Pragma.zig +3 -2
  18. package/compiler/aro/aro/Preprocessor.zig +9 -6
  19. package/compiler/aro/aro/pragmas/message.zig +3 -2
  20. package/compiler/aro/aro/text_literal.zig +3 -2
  21. package/compiler/aro/assembly_backend/x86_64.zig +4 -4
  22. package/compiler/build_runner.zig +0 -2
  23. package/compiler/reduce/Walk.zig +7 -7
  24. package/compiler/test_runner.zig +2 -2
  25. package/compiler/translate-c/Translator.zig +6 -2
  26. package/compiler/translate-c/main.zig +1 -1
  27. package/compiler_rt/cos.zig +0 -2
  28. package/compiler_rt/divmodei4.zig +40 -17
  29. package/compiler_rt/exp.zig +1 -6
  30. package/compiler_rt/exp2.zig +1 -6
  31. package/compiler_rt/exp_f128.zig +377 -0
  32. package/compiler_rt/fabs.zig +0 -2
  33. package/compiler_rt/fma.zig +0 -2
  34. package/compiler_rt/fmax.zig +0 -2
  35. package/compiler_rt/fmin.zig +0 -2
  36. package/compiler_rt/fmod.zig +0 -2
  37. package/compiler_rt/limb64.zig +876 -15
  38. package/compiler_rt/log.zig +0 -2
  39. package/compiler_rt/log10.zig +0 -2
  40. package/compiler_rt/log2.zig +0 -2
  41. package/compiler_rt/mulXi3.zig +1 -1
  42. package/compiler_rt/round.zig +0 -2
  43. package/compiler_rt/sin.zig +0 -2
  44. package/compiler_rt/sincos.zig +0 -2
  45. package/compiler_rt/sqrt.zig +0 -2
  46. package/compiler_rt/ssp.zig +1 -1
  47. package/compiler_rt/tan.zig +0 -2
  48. package/compiler_rt/trunc.zig +0 -2
  49. package/compiler_rt/udivmodei4.zig +28 -0
  50. package/fuzzer.zig +2 -0
  51. package/libc/musl/arch/mipsn32/syscall_arch.h +35 -32
  52. package/package.json +1 -1
  53. package/std/Build/Cache.zig +6 -6
  54. package/std/Build/Step/Compile.zig +0 -1
  55. package/std/Build/Step/Run.zig +2 -2
  56. package/std/Build/Step.zig +2 -4
  57. package/std/Build/WebServer.zig +2 -2
  58. package/std/Build.zig +0 -3
  59. package/std/Io/Dir.zig +7 -2
  60. package/std/Io/Dispatch.zig +3 -13
  61. package/std/Io/File/Writer.zig +8 -6
  62. package/std/Io/Reader.zig +8 -9
  63. package/std/Io/Semaphore.zig +112 -17
  64. package/std/Io/Terminal.zig +1 -1
  65. package/std/Io/Threaded.zig +171 -37
  66. package/std/Io/Uring.zig +13 -15
  67. package/std/Io/Writer.zig +46 -42
  68. package/std/Io/net.zig +11 -11
  69. package/std/Io.zig +90 -26
  70. package/std/SemanticVersion.zig +1 -1
  71. package/std/Target/Query.zig +2 -2
  72. package/std/Target.zig +50 -5
  73. package/std/array_hash_map.zig +9 -18
  74. package/std/builtin.zig +4 -0
  75. package/std/c/haiku.zig +3 -0
  76. package/std/c/serenity.zig +1 -6
  77. package/std/c.zig +89 -7
  78. package/std/compress/flate/Decompress.zig +2 -3
  79. package/std/compress/zstd/Decompress.zig +2 -4
  80. package/std/crypto/Certificate.zig +13 -1
  81. package/std/crypto/ascon.zig +75 -33
  82. package/std/crypto/codecs/asn1/Oid.zig +12 -1
  83. package/std/crypto/codecs/base64_hex_ct.zig +2 -4
  84. package/std/crypto/ml_kem.zig +2 -9
  85. package/std/crypto/tls/Client.zig +79 -4
  86. package/std/crypto/tls.zig +1 -1
  87. package/std/crypto.zig +1 -0
  88. package/std/debug/Pdb.zig +1 -1
  89. package/std/debug.zig +4 -3
  90. package/std/fmt.zig +8 -3
  91. package/std/fs/path.zig +6 -4
  92. package/std/heap/BufferFirstAllocator.zig +165 -0
  93. package/std/heap.zig +2 -126
  94. package/std/http/Client.zig +21 -24
  95. package/std/http.zig +3 -4
  96. package/std/json/Scanner.zig +2 -2
  97. package/std/os/emscripten.zig +1 -1
  98. package/std/os/linux/IoUring.zig +2 -0
  99. package/std/os/linux/aarch64.zig +41 -12
  100. package/std/os/linux/arc.zig +173 -0
  101. package/std/os/linux/arm.zig +41 -12
  102. package/std/os/linux/hexagon.zig +33 -11
  103. package/std/os/linux/loongarch32.zig +41 -13
  104. package/std/os/linux/loongarch64.zig +41 -12
  105. package/std/os/linux/m68k.zig +41 -13
  106. package/std/os/linux/mips.zig +67 -36
  107. package/std/os/linux/mips64.zig +60 -29
  108. package/std/os/linux/mipsn32.zig +60 -29
  109. package/std/os/linux/or1k.zig +41 -12
  110. package/std/os/linux/powerpc.zig +41 -12
  111. package/std/os/linux/powerpc64.zig +41 -12
  112. package/std/os/linux/riscv32.zig +41 -12
  113. package/std/os/linux/riscv64.zig +41 -12
  114. package/std/os/linux/s390x.zig +44 -7
  115. package/std/os/linux/sparc64.zig +83 -52
  116. package/std/os/linux/thumb.zig +52 -36
  117. package/std/os/linux/x32.zig +41 -12
  118. package/std/os/linux/x86.zig +42 -13
  119. package/std/os/linux/x86_64.zig +41 -12
  120. package/std/os/linux.zig +412 -436
  121. package/std/os/uefi/tables/boot_services.zig +9 -8
  122. package/std/os.zig +41 -0
  123. package/std/process.zig +1 -1
  124. package/std/sort.zig +3 -3
  125. package/std/zig/Ast/Render.zig +3 -3
  126. package/std/zig/AstGen.zig +44 -98
  127. package/std/zig/AstRlAnnotate.zig +0 -11
  128. package/std/zig/BuiltinFn.zig +0 -32
  129. package/std/zig/LibCInstallation.zig +4 -3
  130. package/std/zig/Parse.zig +7 -7
  131. package/std/zig/WindowsSdk.zig +13 -13
  132. package/std/zig/Zir.zig +50 -63
  133. package/std/zig/ZonGen.zig +6 -5
  134. package/std/zig/llvm/Builder.zig +12 -12
  135. package/std/zig.zig +1 -10
  136. package/std/zip.zig +5 -5
  137. package/zig.h +340 -1
  138. package/libc/mingw/math/fdiml.c +0 -24
  139. package/libc/mingw/winpthreads/spinlock.c +0 -82
  140. package/libc/musl/src/linux/tee.c +0 -8
  141. package/libc/musl/src/math/fdimf.c +0 -10
  142. package/libc/musl/src/math/fdiml.c +0 -18
  143. package/libc/musl/src/string/strdup.c +0 -10
  144. package/libc/musl/src/string/strndup.c +0 -12
  145. package/libc/musl/src/string/wcsdup.c +0 -10
  146. package/libc/musl/src/thread/pthread_spin_destroy.c +0 -6
  147. package/libc/musl/src/thread/pthread_spin_init.c +0 -6
  148. package/libc/musl/src/thread/pthread_spin_lock.c +0 -8
  149. package/libc/musl/src/thread/pthread_spin_trylock.c +0 -7
  150. package/libc/musl/src/thread/pthread_spin_unlock.c +0 -7
  151. package/libc/musl/src/unistd/dup2.c +0 -20
  152. package/libc/musl/src/unistd/dup3.c +0 -26
  153. package/libc/wasi/thread-stub/pthread_spin_lock.c +0 -8
  154. package/libc/wasi/thread-stub/pthread_spin_trylock.c +0 -8
  155. package/libc/wasi/thread-stub/pthread_spin_unlock.c +0 -7
@@ -353,7 +353,7 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client
353
353
  if (record_len > tls.max_ciphertext_len) return error.TlsRecordOverflow;
354
354
  const record_buffer = input.take(record_len) catch |err| switch (err) {
355
355
  error.EndOfStream => return error.TlsConnectionTruncated,
356
- error.ReadFailed => return error.ReadFailed,
356
+ error.ReadFailed => |e| return e,
357
357
  };
358
358
  var record_decoder: tls.Decoder = .fromTheirSlice(record_buffer);
359
359
  var ctd, const ct = content: switch (cipher_state) {
@@ -382,7 +382,9 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client
382
382
  P.AEAD.decrypt(cleartext, ciphertext, auth_tag, record_header, nonce, pv.server_handshake_key) catch
383
383
  return error.TlsBadRecordMac;
384
384
  // TODO use scalar, non-slice version
385
- cleartext_fragment_end += mem.trimEnd(u8, cleartext, "\x00").len;
385
+ const trimmed_len = mem.trimEnd(u8, cleartext, "\x00").len;
386
+ if (trimmed_len == 0) return error.TlsDecodeError;
387
+ cleartext_fragment_end += trimmed_len;
386
388
  },
387
389
  }
388
390
  read_seq += 1;
@@ -1155,7 +1157,7 @@ fn readIndirect(c: *Client) Reader.Error!usize {
1155
1157
  return failRead(c, error.TlsConnectionTruncated);
1156
1158
  }
1157
1159
  },
1158
- error.ReadFailed => return error.ReadFailed,
1160
+ error.ReadFailed => |e| return e,
1159
1161
  };
1160
1162
  const ct: tls.ContentType = @enumFromInt(record_header[0]);
1161
1163
  const legacy_version = mem.readInt(u16, record_header[1..][0..2], .big);
@@ -1166,7 +1168,7 @@ fn readIndirect(c: *Client) Reader.Error!usize {
1166
1168
  if (record_end > input.buffered().len) {
1167
1169
  input.fillMore() catch |err| switch (err) {
1168
1170
  error.EndOfStream => return failRead(c, error.TlsConnectionTruncated),
1169
- error.ReadFailed => return error.ReadFailed,
1171
+ error.ReadFailed => |e| return e,
1170
1172
  };
1171
1173
  if (record_end > input.buffered().len) return 0;
1172
1174
  }
@@ -1176,6 +1178,7 @@ fn readIndirect(c: *Client) Reader.Error!usize {
1176
1178
  .tls_1_3 => {
1177
1179
  const pv = &p.tls_1_3;
1178
1180
  const P = @TypeOf(p.*);
1181
+ if (record_len < P.AEAD.tag_length) return failRead(c, error.TlsRecordOverflow);
1179
1182
  const ad = input.take(tls.record_header_len) catch unreachable; // already peeked
1180
1183
  const ciphertext_len = record_len - P.AEAD.tag_length;
1181
1184
  const ciphertext = input.take(ciphertext_len) catch unreachable; // already peeked
@@ -1192,6 +1195,7 @@ fn readIndirect(c: *Client) Reader.Error!usize {
1192
1195
  return failRead(c, error.TlsBadRecordMac);
1193
1196
  // TODO use scalar, non-slice version
1194
1197
  const msg = mem.trimEnd(u8, cleartext, "\x00");
1198
+ if (msg.len == 0) return failRead(c, error.TlsDecodeError);
1195
1199
  break :cleartext .{ msg.len - 1, @enumFromInt(msg[msg.len - 1]) };
1196
1200
  },
1197
1201
  .tls_1_2 => {
@@ -1668,3 +1672,74 @@ else
1668
1672
  .AES_256_GCM_SHA384,
1669
1673
  .ECDHE_RSA_WITH_AES_256_GCM_SHA384,
1670
1674
  });
1675
+
1676
+ fn testReadError(input_buf: []const u8, cipher: tls.ApplicationCipher) ReadError {
1677
+ var input_reader: Reader = .fixed(input_buf);
1678
+ var read_buf: [tls.max_ciphertext_record_len]u8 = undefined;
1679
+ var c: Client = .{
1680
+ .input = &input_reader,
1681
+ .reader = .{
1682
+ .buffer = &read_buf,
1683
+ .vtable = &.{ .stream = stream, .readVec = readVec },
1684
+ .seek = 0,
1685
+ .end = 0,
1686
+ },
1687
+ .output = undefined,
1688
+ .writer = undefined,
1689
+ .tls_version = .tls_1_3,
1690
+ .read_seq = 0,
1691
+ .write_seq = 0,
1692
+ .received_close_notify = false,
1693
+ .allow_truncation_attacks = false,
1694
+ .application_cipher = cipher,
1695
+ .ssl_key_log = null,
1696
+ };
1697
+ var w: Writer = .failing;
1698
+ std.testing.expectError(error.ReadFailed, c.reader.stream(&w, .unlimited)) catch
1699
+ @panic("expected ReadFailed");
1700
+ return c.read_err.?;
1701
+ }
1702
+
1703
+ test "empty inner plaintext" {
1704
+ const AEAD = crypto.aead.chacha_poly.ChaCha20Poly1305;
1705
+ const key: [AEAD.key_length]u8 = @splat(0);
1706
+ const iv: [AEAD.nonce_length]u8 = @splat(0);
1707
+
1708
+ const plaintext = [1]u8{0x00};
1709
+ var ciphertext: [plaintext.len]u8 = undefined;
1710
+ var tag: [AEAD.tag_length]u8 = undefined;
1711
+ const content_len: u16 = plaintext.len + AEAD.tag_length;
1712
+ const record_header = [_]u8{ 0x17, 0x03, 0x03 } ++ mem.toBytes(big(content_len));
1713
+ AEAD.encrypt(&ciphertext, &tag, &plaintext, &record_header, iv, key);
1714
+
1715
+ try std.testing.expectEqual(error.TlsDecodeError, testReadError(
1716
+ &record_header ++ ciphertext ++ tag,
1717
+ .{ .CHACHA20_POLY1305_SHA256 = .{ .tls_1_3 = .{
1718
+ .server_key = key,
1719
+ .server_iv = iv,
1720
+ .client_secret = undefined,
1721
+ .server_secret = undefined,
1722
+ .client_key = undefined,
1723
+ .client_iv = undefined,
1724
+ } } },
1725
+ ));
1726
+ }
1727
+
1728
+ test "record shorter than tag" {
1729
+ const AEAD = crypto.aead.chacha_poly.ChaCha20Poly1305;
1730
+ const record_len: u16 = AEAD.tag_length - 1;
1731
+ const header = [_]u8{ 0x17, 0x03, 0x03 } ++ mem.toBytes(big(record_len));
1732
+ const wire = header ++ @as([record_len]u8, @splat(0));
1733
+
1734
+ try std.testing.expectEqual(error.TlsRecordOverflow, testReadError(
1735
+ &wire,
1736
+ .{ .CHACHA20_POLY1305_SHA256 = .{ .tls_1_3 = .{
1737
+ .server_key = undefined,
1738
+ .server_iv = undefined,
1739
+ .client_secret = undefined,
1740
+ .server_secret = undefined,
1741
+ .client_key = undefined,
1742
+ .client_iv = undefined,
1743
+ } } },
1744
+ ));
1745
+ }
@@ -666,7 +666,7 @@ pub const Decoder = struct {
666
666
  if (request_amt > dest.len) return error.TlsRecordOverflow;
667
667
  stream.readSlice(dest[0..request_amt]) catch |err| switch (err) {
668
668
  error.EndOfStream => return error.TlsConnectionTruncated,
669
- error.ReadFailed => return error.ReadFailed,
669
+ error.ReadFailed => |e| return e,
670
670
  };
671
671
  d.cap += request_amt;
672
672
  }
package/std/crypto.zig CHANGED
@@ -367,6 +367,7 @@ test {
367
367
  _ = ff;
368
368
  _ = errors;
369
369
  _ = tls;
370
+ _ = tls.Client;
370
371
  _ = Certificate;
371
372
  _ = codecs;
372
373
  }
package/std/debug/Pdb.zig CHANGED
@@ -138,7 +138,7 @@ pub fn parseDbiStream(self: *Pdb) !void {
138
138
  if (section_contrib_size != 0) {
139
139
  const version = reader.takeEnum(pdb.SectionContrSubstreamVersion, .little) catch |err| switch (err) {
140
140
  error.InvalidEnumTag, error.EndOfStream => return error.InvalidDebugInfo,
141
- error.ReadFailed => return error.ReadFailed,
141
+ error.ReadFailed => |e| return e,
142
142
  };
143
143
  _ = version;
144
144
  sect_cont_offset += @sizeOf(u32);
package/std/debug.zig CHANGED
@@ -1197,8 +1197,9 @@ fn printSourceAtAddress(
1197
1197
 
1198
1198
  // Initialize the symbol array with space for at least one element, allocating this on the stack
1199
1199
  // in the common case where only one element is needed
1200
- var symbol_fallback_allocator = std.heap.stackFallback(@sizeOf(Symbol) + @alignOf(Symbol) - 1, getDebugInfoAllocator());
1201
- const symbol_allocator = symbol_fallback_allocator.get();
1200
+ var buf: [1]Symbol = undefined;
1201
+ var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&buf), getDebugInfoAllocator());
1202
+ const symbol_allocator = bfa.allocator();
1202
1203
  var symbols = std.ArrayList(Symbol).initCapacity(symbol_allocator, 1) catch unreachable;
1203
1204
  defer symbols.deinit(symbol_allocator);
1204
1205
 
@@ -1576,12 +1577,12 @@ fn handleSegfaultPosix(sig: posix.SIG, info: *const posix.siginfo_t, ctx_ptr: ?*
1576
1577
  .tvos,
1577
1578
  .visionos,
1578
1579
  .watchos,
1580
+ .haiku,
1579
1581
  => @intFromPtr(info.addr),
1580
1582
  .linux,
1581
1583
  => @intFromPtr(info.fields.sigfault.addr),
1582
1584
  .netbsd,
1583
1585
  => @intFromPtr(info.info.reason.fault.addr),
1584
- .haiku,
1585
1586
  .openbsd,
1586
1587
  => @intFromPtr(info.data.fault.addr),
1587
1588
  .illumos,
package/std/fmt.zig CHANGED
@@ -542,7 +542,7 @@ pub fn parseIntSizeSuffix(buf: []const u8, digit_base: u8) ParseIntError!usize {
542
542
  }
543
543
  const multiplier = math.powi(usize, magnitude_base, orders_of_magnitude) catch |err| switch (err) {
544
544
  error.Underflow => unreachable,
545
- error.Overflow => return error.Overflow,
545
+ error.Overflow => |e| return e,
546
546
  };
547
547
  const number = try std.fmt.parseInt(usize, without_suffix, digit_base);
548
548
  return math.mul(usize, number, multiplier);
@@ -1342,9 +1342,9 @@ pub const hex_charset = "0123456789abcdef";
1342
1342
 
1343
1343
  /// Converts an unsigned integer of any multiple of u8 to an array of lowercase
1344
1344
  /// hex bytes, little endian.
1345
- pub fn hex(x: anytype) [@sizeOf(@TypeOf(x)) * 2]u8 {
1345
+ pub fn hex(x: anytype) [@typeInfo(@TypeOf(x)).int.bits / 4]u8 {
1346
1346
  comptime assert(@typeInfo(@TypeOf(x)).int.signedness == .unsigned);
1347
- var result: [@sizeOf(@TypeOf(x)) * 2]u8 = undefined;
1347
+ var result: [@typeInfo(@TypeOf(x)).int.bits / 4]u8 = undefined;
1348
1348
  var i: usize = 0;
1349
1349
  while (i < result.len / 2) : (i += 1) {
1350
1350
  const byte: u8 = @truncate(x >> @intCast(8 * i));
@@ -1360,6 +1360,11 @@ test hex {
1360
1360
  try std.testing.expect(x.len == 8);
1361
1361
  try std.testing.expectEqualStrings("efbeadde", &x);
1362
1362
  }
1363
+ {
1364
+ const s = "[" ++ hex(@as(u48, 0x12345678_abcd)) ++ "]";
1365
+ try std.testing.expect(s.len == 14);
1366
+ try std.testing.expectEqualStrings("[cdab78563412]", s);
1367
+ }
1363
1368
  {
1364
1369
  const s = "[" ++ hex(@as(u64, 0x12345678_abcdef00)) ++ "]";
1365
1370
  try std.testing.expect(s.len == 18);
package/std/fs/path.zig CHANGED
@@ -894,8 +894,9 @@ pub fn resolve(allocator: Allocator, paths: []const []const u8) Allocator.Error!
894
894
  pub fn resolveWindows(allocator: Allocator, paths: []const []const u8) Allocator.Error![]u8 {
895
895
  // Avoid heap allocation when paths.len is <= @bitSizeOf(usize) * 2
896
896
  // (we use `* 3` because stackFallback uses 1 usize as a length)
897
- var bit_set_allocator_state = std.heap.stackFallback(@sizeOf(usize) * 3, allocator);
898
- const bit_set_allocator = bit_set_allocator_state.get();
897
+ var buf: [3]usize = undefined;
898
+ var bit_set_allocator_state: std.heap.BufferFirstAllocator = .init(@ptrCast(&buf), allocator);
899
+ const bit_set_allocator = bit_set_allocator_state.allocator();
899
900
  var relevant_paths = try std.bit_set.DynamicBitSetUnmanaged.initEmpty(bit_set_allocator, paths.len);
900
901
  defer relevant_paths.deinit(bit_set_allocator);
901
902
 
@@ -1642,7 +1643,8 @@ fn windowsResolveAgainstCwd(
1642
1643
  parsed: WindowsPath2(u8),
1643
1644
  ) ![]u8 {
1644
1645
  // Space for 256 WTF-16 code units; potentially 3 WTF-8 bytes per WTF-16 code unit
1645
- var temp_allocator_state = std.heap.stackFallback(256 * 3, gpa);
1646
+ var buf: [256 * 3]u8 = undefined;
1647
+ var temp_allocator_state: std.heap.BufferFirstAllocator = .init(&buf, gpa);
1646
1648
  return switch (parsed.kind) {
1647
1649
  .drive_absolute,
1648
1650
  .unc_absolute,
@@ -1668,7 +1670,7 @@ fn windowsResolveAgainstCwd(
1668
1670
  }
1669
1671
  },
1670
1672
  .drive_relative => blk: {
1671
- const temp_allocator = temp_allocator_state.get();
1673
+ const temp_allocator = temp_allocator_state.allocator();
1672
1674
  const drive_cwd = drive_cwd: {
1673
1675
  const parsed_cwd = parsePathWindows(u8, cwd);
1674
1676
 
@@ -0,0 +1,165 @@
1
+ //! An allocator that attempts to allocate from the given buffer, falling back to
2
+ //! `fallback_allocator` if this fails.
3
+
4
+ const std = @import("../std.zig");
5
+ const heap = std.heap;
6
+ const testing = std.testing;
7
+
8
+ const Alignment = std.mem.Alignment;
9
+ const Allocator = std.mem.Allocator;
10
+ const FixedBufferAllocator = std.heap.FixedBufferAllocator;
11
+
12
+ const BufferFirstAllocator = @This();
13
+
14
+ fallback_allocator: Allocator,
15
+ fixed_buffer_allocator: FixedBufferAllocator,
16
+
17
+ pub fn init(buffer: []u8, fallback_allocator: Allocator) BufferFirstAllocator {
18
+ return .{
19
+ .fallback_allocator = fallback_allocator,
20
+ .fixed_buffer_allocator = .init(buffer),
21
+ };
22
+ }
23
+
24
+ pub fn allocator(self: *BufferFirstAllocator) Allocator {
25
+ return .{
26
+ .ptr = self,
27
+ .vtable = &.{
28
+ .alloc = alloc,
29
+ .resize = resize,
30
+ .remap = remap,
31
+ .free = free,
32
+ },
33
+ };
34
+ }
35
+
36
+ fn alloc(
37
+ ctx: *anyopaque,
38
+ len: usize,
39
+ alignment: Alignment,
40
+ ra: usize,
41
+ ) ?[*]u8 {
42
+ const self: *BufferFirstAllocator = @ptrCast(@alignCast(ctx));
43
+ return FixedBufferAllocator.alloc(&self.fixed_buffer_allocator, len, alignment, ra) orelse
44
+ return self.fallback_allocator.rawAlloc(len, alignment, ra);
45
+ }
46
+
47
+ fn resize(
48
+ ctx: *anyopaque,
49
+ buf: []u8,
50
+ alignment: Alignment,
51
+ new_len: usize,
52
+ ra: usize,
53
+ ) bool {
54
+ const self: *BufferFirstAllocator = @ptrCast(@alignCast(ctx));
55
+ if (self.fixed_buffer_allocator.ownsPtr(buf.ptr)) {
56
+ return FixedBufferAllocator.resize(&self.fixed_buffer_allocator, buf, alignment, new_len, ra);
57
+ } else {
58
+ return self.fallback_allocator.rawResize(buf, alignment, new_len, ra);
59
+ }
60
+ }
61
+
62
+ fn remap(
63
+ context: *anyopaque,
64
+ memory: []u8,
65
+ alignment: Alignment,
66
+ new_len: usize,
67
+ return_address: usize,
68
+ ) ?[*]u8 {
69
+ const self: *BufferFirstAllocator = @ptrCast(@alignCast(context));
70
+ if (self.fixed_buffer_allocator.ownsPtr(memory.ptr)) {
71
+ return FixedBufferAllocator.remap(&self.fixed_buffer_allocator, memory, alignment, new_len, return_address);
72
+ } else {
73
+ return self.fallback_allocator.rawRemap(memory, alignment, new_len, return_address);
74
+ }
75
+ }
76
+
77
+ fn free(
78
+ ctx: *anyopaque,
79
+ buf: []u8,
80
+ alignment: Alignment,
81
+ ra: usize,
82
+ ) void {
83
+ const self: *BufferFirstAllocator = @ptrCast(@alignCast(ctx));
84
+ if (self.fixed_buffer_allocator.ownsPtr(buf.ptr)) {
85
+ return FixedBufferAllocator.free(&self.fixed_buffer_allocator, buf, alignment, ra);
86
+ } else {
87
+ return self.fallback_allocator.rawFree(buf, alignment, ra);
88
+ }
89
+ }
90
+
91
+ test "BufferFirstAllocator" {
92
+ // Buffer first specific tests
93
+ {
94
+ var buffer: [10]u8 = undefined;
95
+ var bfa_state: BufferFirstAllocator = .init(&buffer, std.testing.allocator);
96
+ const bfa = bfa_state.allocator();
97
+
98
+ // We're under the limit, so we should be allocated in the buffer
99
+ const txt0 = "hellowrld";
100
+ const buf0 = try bfa.create(@TypeOf(txt0.*));
101
+ buf0.* = txt0.*;
102
+ try testing.expect(bfa_state.fixed_buffer_allocator.ownsPtr(buf0.ptr));
103
+
104
+ // We're now over the limit, so we should be allocated from the fallback
105
+ const txt1 = "test!";
106
+ const buf1 = try bfa.create(@TypeOf(txt1.*));
107
+ buf1.* = txt1.*;
108
+ try testing.expect(!bfa_state.fixed_buffer_allocator.ownsPtr(buf1.ptr));
109
+
110
+ // Free the allocation that took up space in the buffer
111
+ try testing.expectEqualStrings(txt0, buf0);
112
+ bfa.destroy(buf0);
113
+
114
+ // The next allocation would go in the buffer, but it's too big so it doesn't
115
+ const txt2 = "qwertyqwerty";
116
+ const buf2 = try bfa.create(@TypeOf(txt2.*));
117
+ buf2.* = txt2.*;
118
+ try testing.expect(!bfa_state.fixed_buffer_allocator.ownsPtr(buf2.ptr));
119
+
120
+ // The next allocation is smaller and fits in the buffer
121
+ const txt3 = "dvorak";
122
+ const buf3 = try bfa.create(@TypeOf(txt3.*));
123
+ buf3.* = txt3.*;
124
+ try testing.expect(bfa_state.fixed_buffer_allocator.ownsPtr(buf3.ptr));
125
+
126
+ // The remainder in the buffer is too small for the following allocation so it falls back
127
+ const txt4 = "moretext";
128
+ const buf4 = try bfa.create(@TypeOf(txt4.*));
129
+ buf4.* = txt4.*;
130
+ try testing.expect(!bfa_state.fixed_buffer_allocator.ownsPtr(buf4.ptr));
131
+
132
+ // Check equality on the remaining buffers and free them
133
+ try testing.expectEqualStrings(txt1, buf1);
134
+ bfa.destroy(buf1);
135
+ try testing.expectEqualStrings(txt2, buf2);
136
+ bfa.destroy(buf2);
137
+ try testing.expectEqualStrings(txt3, buf3);
138
+ bfa.destroy(buf3);
139
+ try testing.expectEqualStrings(txt4, buf4);
140
+ bfa.destroy(buf4);
141
+
142
+ try testing.expectEqual(0, bfa_state.fixed_buffer_allocator.end_index);
143
+ }
144
+
145
+ // Standard allocator tests
146
+ {
147
+ var buf: [4096]u8 = undefined;
148
+ {
149
+ var bfa: BufferFirstAllocator = .init(&buf, std.testing.allocator);
150
+ try heap.testAllocator(bfa.allocator());
151
+ }
152
+ {
153
+ var bfa: BufferFirstAllocator = .init(&buf, std.testing.allocator);
154
+ try heap.testAllocatorAligned(bfa.allocator());
155
+ }
156
+ {
157
+ var bfa: BufferFirstAllocator = .init(&buf, std.testing.allocator);
158
+ try heap.testAllocatorLargeAlignment(bfa.allocator());
159
+ }
160
+ {
161
+ var bfa: BufferFirstAllocator = .init(&buf, std.testing.allocator);
162
+ try heap.testAllocatorAlignedShrink(bfa.allocator());
163
+ }
164
+ }
165
+ }
package/std/heap.zig CHANGED
@@ -12,6 +12,7 @@ const Alignment = std.mem.Alignment;
12
12
  pub const ArenaAllocator = @import("heap/ArenaAllocator.zig");
13
13
  pub const SmpAllocator = @import("heap/SmpAllocator.zig");
14
14
  pub const FixedBufferAllocator = @import("heap/FixedBufferAllocator.zig");
15
+ pub const BufferFirstAllocator = @import("heap/BufferFirstAllocator.zig");
15
16
  pub const PageAllocator = @import("heap/PageAllocator.zig");
16
17
  pub const WasmAllocator = if (builtin.single_threaded) BrkAllocator else @compileError("unimplemented");
17
18
  pub const BrkAllocator = @import("heap/BrkAllocator.zig");
@@ -367,113 +368,6 @@ pub const brk_allocator: Allocator = .{
367
368
  .vtable = &BrkAllocator.vtable,
368
369
  };
369
370
 
370
- /// Returns a `StackFallbackAllocator` allocating using either a
371
- /// `FixedBufferAllocator` on an array of size `size` and falling back to
372
- /// `fallback_allocator` if that fails.
373
- pub fn stackFallback(comptime size: usize, fallback_allocator: Allocator) StackFallbackAllocator(size) {
374
- return StackFallbackAllocator(size){
375
- .buffer = undefined,
376
- .fallback_allocator = fallback_allocator,
377
- .fixed_buffer_allocator = undefined,
378
- };
379
- }
380
-
381
- /// An allocator that attempts to allocate using a
382
- /// `FixedBufferAllocator` using an array of size `size`. If the
383
- /// allocation fails, it will fall back to using
384
- /// `fallback_allocator`. Easily created with `stackFallback`.
385
- pub fn StackFallbackAllocator(comptime size: usize) type {
386
- return struct {
387
- const Self = @This();
388
-
389
- buffer: [size]u8,
390
- fallback_allocator: Allocator,
391
- fixed_buffer_allocator: FixedBufferAllocator,
392
- get_called: if (std.debug.runtime_safety) bool else void =
393
- if (std.debug.runtime_safety) false else {},
394
-
395
- /// This function both fetches a `Allocator` interface to this
396
- /// allocator *and* resets the internal buffer allocator.
397
- pub fn get(self: *Self) Allocator {
398
- if (std.debug.runtime_safety) {
399
- assert(!self.get_called); // `get` called multiple times; instead use `const allocator = stackFallback(N).get();`
400
- self.get_called = true;
401
- }
402
- self.fixed_buffer_allocator = FixedBufferAllocator.init(self.buffer[0..]);
403
- return .{
404
- .ptr = self,
405
- .vtable = &.{
406
- .alloc = alloc,
407
- .resize = resize,
408
- .remap = remap,
409
- .free = free,
410
- },
411
- };
412
- }
413
-
414
- /// Unlike most std allocators `StackFallbackAllocator` modifies
415
- /// its internal state before returning an implementation of
416
- /// the`Allocator` interface and therefore also doesn't use
417
- /// the usual `.allocator()` method.
418
- pub const allocator = @compileError("use 'const allocator = stackFallback(N).get();' instead");
419
-
420
- fn alloc(
421
- ctx: *anyopaque,
422
- len: usize,
423
- alignment: Alignment,
424
- ra: usize,
425
- ) ?[*]u8 {
426
- const self: *Self = @ptrCast(@alignCast(ctx));
427
- return FixedBufferAllocator.alloc(&self.fixed_buffer_allocator, len, alignment, ra) orelse
428
- return self.fallback_allocator.rawAlloc(len, alignment, ra);
429
- }
430
-
431
- fn resize(
432
- ctx: *anyopaque,
433
- buf: []u8,
434
- alignment: Alignment,
435
- new_len: usize,
436
- ra: usize,
437
- ) bool {
438
- const self: *Self = @ptrCast(@alignCast(ctx));
439
- if (self.fixed_buffer_allocator.ownsPtr(buf.ptr)) {
440
- return FixedBufferAllocator.resize(&self.fixed_buffer_allocator, buf, alignment, new_len, ra);
441
- } else {
442
- return self.fallback_allocator.rawResize(buf, alignment, new_len, ra);
443
- }
444
- }
445
-
446
- fn remap(
447
- context: *anyopaque,
448
- memory: []u8,
449
- alignment: Alignment,
450
- new_len: usize,
451
- return_address: usize,
452
- ) ?[*]u8 {
453
- const self: *Self = @ptrCast(@alignCast(context));
454
- if (self.fixed_buffer_allocator.ownsPtr(memory.ptr)) {
455
- return FixedBufferAllocator.remap(&self.fixed_buffer_allocator, memory, alignment, new_len, return_address);
456
- } else {
457
- return self.fallback_allocator.rawRemap(memory, alignment, new_len, return_address);
458
- }
459
- }
460
-
461
- fn free(
462
- ctx: *anyopaque,
463
- buf: []u8,
464
- alignment: Alignment,
465
- ra: usize,
466
- ) void {
467
- const self: *Self = @ptrCast(@alignCast(ctx));
468
- if (self.fixed_buffer_allocator.ownsPtr(buf.ptr)) {
469
- return FixedBufferAllocator.free(&self.fixed_buffer_allocator, buf, alignment, ra);
470
- } else {
471
- return self.fallback_allocator.rawFree(buf, alignment, ra);
472
- }
473
- }
474
- };
475
- }
476
-
477
371
  test c_allocator {
478
372
  if (builtin.link_libc) {
479
373
  try testAllocator(c_allocator);
@@ -524,25 +418,6 @@ test ArenaAllocator {
524
418
  try testAllocatorAlignedShrink(allocator);
525
419
  }
526
420
 
527
- test "StackFallbackAllocator" {
528
- {
529
- var stack_allocator = stackFallback(4096, std.testing.allocator);
530
- try testAllocator(stack_allocator.get());
531
- }
532
- {
533
- var stack_allocator = stackFallback(4096, std.testing.allocator);
534
- try testAllocatorAligned(stack_allocator.get());
535
- }
536
- {
537
- var stack_allocator = stackFallback(4096, std.testing.allocator);
538
- try testAllocatorLargeAlignment(stack_allocator.get());
539
- }
540
- {
541
- var stack_allocator = stackFallback(4096, std.testing.allocator);
542
- try testAllocatorAlignedShrink(stack_allocator.get());
543
- }
544
- }
545
-
546
421
  /// This one should not try alignments that exceed what C malloc can handle.
547
422
  pub fn testAllocator(base_allocator: mem.Allocator) !void {
548
423
  var validationAllocator = mem.validationWrap(base_allocator);
@@ -1011,6 +886,7 @@ test {
1011
886
  _ = ArenaAllocator;
1012
887
  _ = DebugAllocator(.{});
1013
888
  _ = FixedBufferAllocator;
889
+ _ = BufferFirstAllocator;
1014
890
  if (builtin.single_threaded) {
1015
891
  if (builtin.cpu.arch.isWasm() or (builtin.os.tag == .linux and !builtin.link_libc)) {
1016
892
  _ = brk_allocator;