mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 18:38:55 +00:00
* Define a generic allocator interface to enable static polymorphism for allocators (see `GenericAllocator` in `src/allocators.zig`). Note that `std.mem.Allocator` itself is considered a generic allocator. * Add utilities to `bun.allocators` for working with generic allocators. * Add a new namespace, `bun.memory`, with basic utilities for working with memory and objects (`create`, `destroy`, `initDefault`, `deinit`). * Add `bun.DefaultAllocator`, a zero-sized generic allocator type whose `allocator` method simply returns `bun.default_allocator`. * Implement the generic allocator interface in `AllocationScope` and `MimallocArena`. * Improve `bun.threading.GuardedValue` (now `bun.threading.Guarded`). * Improve `bun.safety.AllocPtr` (now `bun.safety.CheckedAllocator`). (For internal tracking: fixes STAB-1085, STAB-1086, STAB-1087, STAB-1088, STAB-1089, STAB-1090, STAB-1091)
84 lines
2.8 KiB
Zig
84 lines
2.8 KiB
Zig
//! Basic utilities for working with memory and objects.
|
|
|
|
/// Allocates memory for a value of type `T` using the provided allocator, and initializes the
|
|
/// memory with `value`.
|
|
///
|
|
/// If `allocator` is `bun.default_allocator`, this will internally use `bun.tryNew` to benefit from
|
|
/// the added assertions.
|
|
pub fn create(comptime T: type, allocator: std.mem.Allocator, value: T) bun.OOM!*T {
|
|
if ((comptime Environment.allow_assert) and isDefault(allocator)) {
|
|
return bun.tryNew(T, value);
|
|
}
|
|
const ptr = try allocator.create(T);
|
|
ptr.* = value;
|
|
return ptr;
|
|
}
|
|
|
|
/// Frees memory previously allocated by `create`.
|
|
///
|
|
/// The memory must have been allocated by the `create` function in this namespace, not
|
|
/// directly by `allocator.create`.
|
|
pub fn destroy(allocator: std.mem.Allocator, ptr: anytype) void {
|
|
if ((comptime Environment.allow_assert) and isDefault(allocator)) {
|
|
bun.destroy(ptr);
|
|
} else {
|
|
allocator.destroy(ptr);
|
|
}
|
|
}
|
|
|
|
/// Default-initializes a value of type `T`.
|
|
///
|
|
/// This method tries the following, in order:
|
|
///
|
|
/// * `.initDefault()`, if a method with that name exists
|
|
/// * `.init()`, if a method with that name exists
|
|
/// * `.{}`, otherwise
|
|
pub fn initDefault(comptime T: type) T {
|
|
return if (comptime std.meta.hasFn(T, "initDefault"))
|
|
.initDefault()
|
|
else if (comptime std.meta.hasFn(T, "init"))
|
|
.init()
|
|
else
|
|
.{};
|
|
}
|
|
|
|
/// Calls `deinit` on `ptr_or_slice`, or on every element of `ptr_or_slice`, if such a `deinit`
|
|
/// method exists.
|
|
///
|
|
/// This function first does the following:
|
|
///
|
|
/// * If `ptr_or_slice` is a single-item pointer, calls `ptr_or_slice.deinit()`, if that method
|
|
/// exists.
|
|
/// * If `ptr_or_slice` is a slice, calls `deinit` on every element of the slice, if the slice
|
|
/// elements have a `deinit` method.
|
|
///
|
|
/// Then, if `ptr_or_slice` is non-const, this function also sets all memory referenced by the
|
|
/// pointer to `undefined`.
|
|
///
|
|
/// This method does not free `ptr_or_slice` itself.
|
|
pub fn deinit(ptr_or_slice: anytype) void {
|
|
const ptr_info = @typeInfo(@TypeOf(ptr_or_slice));
|
|
const Child = ptr_info.pointer.child;
|
|
const mutable = !ptr_info.pointer.is_const;
|
|
if (comptime std.meta.hasFn(Child, "deinit")) {
|
|
switch (comptime ptr_info.pointer.size) {
|
|
.one => {
|
|
ptr_or_slice.deinit();
|
|
if (comptime mutable) ptr_or_slice.* = undefined;
|
|
},
|
|
.slice => for (ptr_or_slice) |*elem| {
|
|
elem.deinit();
|
|
if (comptime mutable) elem.* = undefined;
|
|
},
|
|
else => @compileError("unsupported pointer type"),
|
|
}
|
|
}
|
|
}
|
|
|
|
const std = @import("std");
|
|
const Allocator = std.mem.Allocator;
|
|
|
|
const bun = @import("bun");
|
|
const Environment = bun.Environment;
|
|
const isDefault = bun.allocators.isDefault;
|