diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/galloc.zig | 77 | ||||
-rw-r--r-- | src/root.zig | 53 |
2 files changed, 122 insertions, 8 deletions
diff --git a/src/galloc.zig b/src/galloc.zig new file mode 100644 index 0000000..7cb4480 --- /dev/null +++ b/src/galloc.zig @@ -0,0 +1,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); +} diff --git a/src/root.zig b/src/root.zig index 73222be..9552bc5 100644 --- a/src/root.zig +++ b/src/root.zig @@ -1,6 +1,7 @@ const std = @import("std"); const testing = std.testing; const Allocator = std.mem.Allocator; +const galloc = @import("galloc.zig"); const git = @cImport({ @cInclude("git2.h"); @@ -12,7 +13,41 @@ const GitError = error{ OpenError, }; -pub fn initGit() GitError!void { +const git_allocator = extern struct { + gmalloc: ?*const fn (size: usize, payload: ?*anyopaque) callconv(.C) ?*anyopaque, + grealloc: ?*const fn (ptr: ?*anyopaque, size: usize, payload: ?*anyopaque) callconv(.C) ?*anyopaque, + gfree: ?*const fn (ptr: ?*anyopaque) callconv(.C) void, +}; + +pub var alloc: galloc.GitAllocator = undefined; + +fn malloc(size: usize, _: ?*anyopaque) callconv(.C) ?*anyopaque { + std.debug.print("MALLOC {}\n", .{size}); + return alloc.malloc(size); +} + +fn relloc(ptr: ?*anyopaque, size: usize, _: ?*anyopaque) callconv(.C) ?*anyopaque { + std.debug.print("REALLOC {} {?}\n", .{ size, ptr }); + const new_ptr = alloc.realloc(ptr, size); + return new_ptr; +} + +fn free(ptr: ?*anyopaque) callconv(.C) void { + std.debug.print("FREE\n", .{}); + alloc.free(ptr); +} + +pub fn initGit(a: std.mem.Allocator) GitError!void { + alloc = galloc.GitAllocator.init(a); + + const cAlloc = git_allocator{ + .gmalloc = malloc, + .grealloc = relloc, + .gfree = free, + }; + + _ = git.git_libgit2_opts(git.GIT_OPT_SET_ALLOCATOR, &cAlloc); + const code = git.git_libgit2_init(); if (code < 0) { return GitError.InitError; @@ -20,6 +55,7 @@ pub fn initGit() GitError!void { } pub fn deInitGit() !void { + defer alloc.deinit(); const code = git.git_libgit2_shutdown(); if (code < 0) { return GitError.DeinitError; @@ -30,20 +66,20 @@ pub const Repository = struct { allocator: Allocator = undefined, repository: ?*git.git_repository = null, - pub fn init(alloc: Allocator) !Repository { + pub fn init(a: Allocator) !Repository { return Repository{ - .allocator = alloc, + .allocator = a, }; } - pub fn open(self: Repository, path: []const u8) GitError!void { - const code = git.git_repository_open(@constCast(&self.repository), path.ptr); + pub fn open(self: *Repository, path: []const u8) GitError!void { + const code = git.git_repository_open(@ptrCast(&self.repository), path.ptr); if (code < 0) { return GitError.OpenError; } } - pub fn deinit(self: Repository) !void { + pub fn deinit(self: *Repository) void { if (self.repository) |repo| { git.git_repository_free(repo); } @@ -51,15 +87,16 @@ pub const Repository = struct { }; test "init deinit" { - try initGit(); + try initGit(testing.allocator); try deInitGit(); } test "open repository" { - try initGit(); + try initGit(testing.allocator); var repository = try Repository.init(std.testing.allocator); try repository.open("."); + repository.deinit(); try deInitGit(); } |