From d6356a6d6b757bdebae627a43af7778354a87f14 Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 4 Jun 2020 19:19:34 -0700 Subject: [PATCH] new cache --- zig-ecs/src/resources/cache.zig | 88 +++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 zig-ecs/src/resources/cache.zig diff --git a/zig-ecs/src/resources/cache.zig b/zig-ecs/src/resources/cache.zig new file mode 100644 index 0000000..08614a7 --- /dev/null +++ b/zig-ecs/src/resources/cache.zig @@ -0,0 +1,88 @@ +const std = @import("std"); + +/// Simple cache for resources of a given type. TLoader should be a struct that implements a single +/// method: load(args: var) *T. If any resource has a deinit method it will be called when clear +/// or remove is called. +pub fn Cache(comptime T: type, TLoader: type) type { + return struct { + loader: TLoader, + resources: std.AutoHashMap(u16, *T), + + pub fn init(allocator: *std.mem.Allocator, comptime loader: TLoader) @This() { + return .{ + .loader = loader, + .resources = std.AutoHashMap(u16, *T).init(allocator), + }; + } + + pub fn deinit(self: @This()) void { + self.resources.deinit(); + } + + pub fn load(self: *@This(), id: u16, args: var) *T { + if (self.resources.getValue(id)) |resource| { + return resource; + } + + var resource = self.loader.load(args); + _ = self.resources.put(id, resource) catch unreachable; + return resource; + } + + pub fn contains(self: *@This(), id: u16) bool { + return self.resources.contains(id); + } + + pub fn remove(self: *@This(), id: u16) void { + if (self.resources.remove(id)) |kv| { + if (@hasDecl(T, "deinit")) { + @call(.{ .modifier = .always_inline }, @field(kv.value, "deinit"), .{}); + } + } + } + + pub fn clear(self: *@This()) void { + // optionally deinit any resources that have a deinit method + if (@hasDecl(T, "deinit")) { + var iter = self.resources.iterator(); + while (iter.next()) |kv| { + @call(.{ .modifier = .always_inline }, @field(kv.value, "deinit"), .{}); + } + } + self.resources.clear(); + } + + pub fn size(self: @This()) usize { + return self.resources.size; + } + }; +} + +test "cache" { + const Thing = struct { + fart: i32, + + pub fn deinit(self: *@This()) void { + std.testing.allocator.destroy(self); + } + }; + + const ThingLoader = struct { + pub fn load(self: @This(), args: var) *Thing { + return std.testing.allocator.create(Thing) catch unreachable; + } + }; + + var cache = Cache(Thing, ThingLoader).init(std.testing.allocator, ThingLoader{}); + defer cache.deinit(); + + var thing = cache.load(6, .{}); + var thing2 = cache.load(2, .{}); + std.testing.expectEqual(cache.size(), 2); + + cache.remove(2); + std.testing.expectEqual(cache.size(), 1); + + cache.clear(); + std.testing.expectEqual(cache.size(), 0); +} \ No newline at end of file