Open mountain opened 3 years ago
I made some typo in the above code to remove pointers * in generic declarations, but the compiler still failed.
I couldn't get the original code to compile (since there were a few issues with it, and some interfaces changed for the final 0.9.0 release, e.g. allocgate), but I "modernized it" to the following:
const std = @import("std");
const testing = std.testing;
const trait = std.meta.trait;
const Allocator = std.mem.Allocator;
fn autoFree(allocator: Allocator, value: anytype) void {
const T = @TypeOf(value);
if (comptime trait.isManyItemPtr(T) or trait.isSlice(T)) {
allocator.free(value);
} else if (comptime trait.isSingleItemPtr(T)) {
allocator.destroy(value);
}
}
pub fn ArrayCache(comptime Context: type, comptime E: type, comptime limit: usize) type {
const Cache = std.StringHashMap([]E);
const Registry = std.AutoHashMap(Context, Cache);
return struct {
allocator: Allocator,
registry: Registry,
const Self = @This();
pub fn init(allocator: Allocator) Self {
return .{
.allocator = allocator,
.registry = Registry.init(allocator),
};
}
pub fn deinit(self: *Self) void {
var re_it = self.registry.iterator();
while (re_it.next()) |registry_entry| {
const cache = registry_entry.value_ptr;
var ce_it = cache.iterator();
while (ce_it.next()) |cache_entry| {
autoFree(self.allocator, cache_entry.key_ptr.*);
self.allocator.free(cache_entry.value_ptr.*);
}
autoFree(self.allocator, registry_entry.key_ptr.*);
cache.deinit();
}
self.registry.deinit();
}
pub fn declare(self: *Self, ctx: Context, name: []const u8, size: usize) error{ OutOfMemory, LimitExceeded }![]E {
if (size > limit) return error.LimitExceeded;
var cache = cblk: {
const gop = try self.registry.getOrPut(ctx);
if (!gop.found_existing) gop.value_ptr.* = Cache.init(self.allocator);
break :cblk gop.value_ptr;
};
const key = try std.fmt.allocPrint(self.allocator, "{s}-{d}", .{ name, size });
errdefer self.allocator.free(key);
return rblk: {
const cache_gop = try cache.getOrPut(key);
if (!cache_gop.found_existing) cache_gop.value_ptr.* = try self.allocator.alloc(E, size);
if (cache_gop.found_existing) self.allocator.free(key);
break :rblk cache_gop.value_ptr.*;
};
}
};
}
test "ArrayCache declare" {
var cache = ArrayCache(i32, i32, 15).init(testing.allocator);
defer cache.deinit();
const array = try cache.declare(0, "array", 10);
try testing.expectEqual(@as(usize, 10), array.len);
}
test "ArrayCache limit exceeded" {
var cache = ArrayCache(i32, i32, 15).init(testing.allocator);
defer cache.deinit();
const array = cache.declare(0, "array", 16);
try testing.expectError(error.LimitExceeded, array);
}
test "compile everything" {
std.testing.refAllDecls(ArrayCache(i32, i32, 15));
}
and it seems to work fine here:
$ zig version
0.9.0
$ zig test 9590.zig
All 3 tests passed.
Can you confirm whether this is still an issue for you? Otherwise I'd be inclined to close this as an obsolete report.
We are learning Zig, and wrote a special cache following the generic patterns in HashMap, but failed to compile, and it seemed to be compiler bug, but I am not very sure about it.
The related code is as below:
The OS is Mac, and Zig version is 0.9.0-dev.804+4c9d41730.
Could you check this?