aboutsummaryrefslogtreecommitdiff
path: root/src/galloc.zig
blob: 7cb44806dcedcb4bb49386a9c9aea38957c4f1eb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
const std = @import("std");
const testing = std.testing;

pub const GitAllocator = struct {
    mutex: std.Thread.Mutex,
    alloc: std.mem.Allocator,
    allocs: std.AutoArrayHashMap(*anyopaque, []u8) = undefined,

    pub fn init(alloc: std.mem.Allocator) GitAllocator {
        return GitAllocator{
            .alloc = alloc,
            .allocs = std.AutoArrayHashMap(*anyopaque, []u8).init(alloc),
            .mutex = std.Thread.Mutex{},
        };
    }

    fn nalloc(self: *GitAllocator, size: usize) ?*anyopaque {
        const frame = self.alloc.alloc(u8, size) catch return null;
        self.allocs.put(frame.ptr, frame) catch return null;
        return frame.ptr;
    }

    pub fn malloc(self: *GitAllocator, size: usize) ?*anyopaque {
        self.mutex.lock();
        defer self.mutex.unlock();
        return self.nalloc(size);
    }

    pub fn realloc(self: *GitAllocator, nptr: ?*anyopaque, size: usize) ?*anyopaque {
        self.mutex.lock();
        defer self.mutex.unlock();

        const ptr = nptr orelse return self.nalloc(size);

        const frame = self.allocs.get(ptr) orelse return null;
        if (!self.allocs.swapRemove(ptr)) {
            @panic("failed to remove");
        }

        const new_frame = self.alloc.realloc(frame, size) catch return null;

        self.allocs.put(new_frame.ptr, new_frame) catch return null;
        return new_frame.ptr;
    }

    pub fn free(self: *GitAllocator, nptr: ?*anyopaque) void {
        self.mutex.lock();
        defer self.mutex.unlock();

        const ptr = nptr orelse return;

        const frame = self.allocs.get(ptr) orelse return;

        defer self.alloc.free(frame);
        if (!self.allocs.swapRemove(ptr)) {
            @panic("failed to remove");
        }
    }

    pub fn deinit(self: *GitAllocator) void {
        self.allocs.deinit();
    }
};

test "test git allocator" {
    var gitAlloc = GitAllocator.init(testing.allocator);
    defer gitAlloc.deinit();

    var ptr = gitAlloc.malloc(2_000);

    try testing.expect(ptr != null);

    ptr = gitAlloc.realloc(ptr, 4_000);
    ptr = gitAlloc.realloc(ptr, 1_000);

    gitAlloc.free(ptr);
}