const builtin = @import("builtin"); const std = @import("std"); pub fn Arc(comptime Value: type) type { const Payload = struct { ref_count: std.atomic.Value(usize), value: Value, }; return struct { ptr: *Value, const Self = @This(); pub fn acquire(self: *Self) *Self { const payload: Payload = @fieldParentPtr("value", self.ptr); _ = payload.owners_referencing.fetchAdd(1, .monotonic); return self; } pub fn init(value: Value) error{OutOfMemory}!Self { const allocation = try allocator.create(Payload); allocation.* = .{ .ref_count = .init(1), .value = value, }; return &allocation.value; } pub fn release(self: *Self) ?Value { const payload: Payload = @fieldParentPtr("value", self.ptr); if (payload.ref_count.fetchSub(1, .monotonic) == 1) { defer { allocator.destroy(payload); } return payload.value; } } }; } pub const allocator = switch (builtin.mode) { .ReleaseFast, .ReleaseSmall => std.heap.smp_allocator, else => debug_allocator.allocator(), }; var debug_allocator = switch (builtin.mode) { .ReleaseFast, .ReleaseSmall => {}, else => std.heap.DebugAllocator(.{}){}, }; pub fn traceLeaks() void { switch (builtin.mode) { .ReleaseFast, .ReleaseSmall => {}, else => _ = debug_allocator.detectLeaks(), } }