cerrado @ zig

 1const std = @import("std");
 2const testing = std.testing;
 3
 4pub const GitAllocator = struct {
 5    mutex: std.Thread.Mutex,
 6    alloc: std.mem.Allocator,
 7    allocs: std.AutoArrayHashMap(*anyopaque, []u8) = undefined,
 8
 9    pub fn init(alloc: std.mem.Allocator) GitAllocator {
10        return GitAllocator{
11            .alloc = alloc,
12            .allocs = std.AutoArrayHashMap(*anyopaque, []u8).init(alloc),
13            .mutex = std.Thread.Mutex{},
14        };
15    }
16
17    fn nalloc(self: *GitAllocator, size: usize) ?*anyopaque {
18        const frame = self.alloc.alloc(u8, size) catch return null;
19        self.allocs.put(frame.ptr, frame) catch return null;
20        return frame.ptr;
21    }
22
23    pub fn malloc(self: *GitAllocator, size: usize) ?*anyopaque {
24        self.mutex.lock();
25        defer self.mutex.unlock();
26        return self.nalloc(size);
27    }
28
29    pub fn realloc(self: *GitAllocator, nptr: ?*anyopaque, size: usize) ?*anyopaque {
30        self.mutex.lock();
31        defer self.mutex.unlock();
32
33        const ptr = nptr orelse return self.nalloc(size);
34
35        const frame = self.allocs.get(ptr) orelse return null;
36        if (!self.allocs.swapRemove(ptr)) {
37            @panic("failed to remove");
38        }
39
40        const new_frame = self.alloc.realloc(frame, size) catch return null;
41
42        self.allocs.put(new_frame.ptr, new_frame) catch return null;
43        return new_frame.ptr;
44    }
45
46    pub fn free(self: *GitAllocator, nptr: ?*anyopaque) void {
47        self.mutex.lock();
48        defer self.mutex.unlock();
49
50        const ptr = nptr orelse return;
51
52        const frame = self.allocs.get(ptr) orelse return;
53
54        defer self.alloc.free(frame);
55        if (!self.allocs.swapRemove(ptr)) {
56            @panic("failed to remove");
57        }
58    }
59
60    pub fn deinit(self: *GitAllocator) void {
61        self.allocs.deinit();
62    }
63};
64
65test "test git allocator" {
66    var gitAlloc = GitAllocator.init(testing.allocator);
67    defer gitAlloc.deinit();
68
69    var ptr = gitAlloc.malloc(2_000);
70
71    try testing.expect(ptr != null);
72
73    ptr = gitAlloc.realloc(ptr, 4_000);
74    ptr = gitAlloc.realloc(ptr, 1_000);
75
76    gitAlloc.free(ptr);
77}