Untitled diff
63 linee
const std = @import("std");
const std = @import("std");
// Cache requires a function (lambda) to be called when there's no cache hit and an other function(args_to_u64) that can compute args
// Cache requires a function (lambda) to be called when there's no cache hit and an other function(args_to_u64) that can compute args
// of the function to u64 that becomes the identifier to compare same arguments.
// of the function to u64 that becomes the identifier to compare same arguments.
pub fn Cache(lambda: anytype, args_to_u64: fn (anytype) u64) type {
pub fn Cache(lambda: anytype, args_to_u64: fn (anytype) u64) type {
    const lambda_info = @typeInfo(@TypeOf(lambda));
    const lambda_info = @typeInfo(@TypeOf(lambda));
    if (lambda_info != .@"fn") {
    if (lambda_info != .Fn) {
        @compileError("lambda should be a function type");
        @compileError("lambda should be a function type");
    }
    }
    const return_type = lambda_info.@"fn".return_type orelse @compileError("No return type");
    const return_type = lambda_info.Fn.return_type orelse @compileError("No return type");
    const InnerHashMap = std.HashMap(u64, return_type, struct {
    const InnerHashMap = std.HashMap(u64, return_type, struct {
        pub fn hash(_: @This(), key: u64) u64 {
        pub fn hash(_: @This(), key: u64) u64 {
            return key;
            return key;
        }
        }
        pub fn eql(_: @This(), a: u64, b: u64) bool {
        pub fn eql(_: @This(), a: u64, b: u64) bool {
            return a == b;
            return a == b;
        }
        }
    }, 80);
    }, 80);
    return struct {
    return struct {
        _inner: InnerHashMap,
        _inner: InnerHashMap,
        const Self = @This();
        const Self = @This();
        fn init(allocator: std.mem.Allocator) Cache(lambda, args_to_u64) {
        fn init(allocator: std.mem.Allocator) Self {
            return Self{ ._inner = InnerHashMap.init(allocator) };
            return Self{ ._inner = InnerHashMap.init(allocator) };
        }
        }
        fn get(self: *Self, args: anytype) !return_type {
        fn get(self: *Self, args: anytype) !return_type {
            const key = args_to_u64(args);
            const key = args_to_u64(args);
            if (self._inner.get(key)) |value| {
            if (self._inner.get(key)) |value| {
                std.debug.print("Rertrieving from cache for the key: {d}\n", .{key});
                std.debug.print("Rertrieving from cache for the key: {d}\n", .{key});
                return value;
                return value;
            } else {
            } else {
                std.debug.print("Computing function and storing in cache for the key: {d}\n", .{key});
                std.debug.print("Computing function and storing in cache for the key: {d}\n", .{key});
                const value = @call(.auto, lambda, args);
                const value = @call(.auto, lambda, args);
                try self._inner.put(key, value);
                try self._inner.put(key, value);
                return value;
                return value;
            }
            }
        }
        }
    };
    };
}
}
// Below tests to cache addition of two numbers
// Below tests to cache addition of two numbers
fn _add(a: u64, b: u64) u64 {
fn _add(a: u64, b: u64) u64 {
    return a + b;
    return a + b;
}
}
const HashAdd = struct {
const HashAdd = struct {
    var allocator: std.mem.Allocator = undefined;
    var allocator: std.mem.Allocator = undefined;
    pub fn hash_add(args: anytype) u64 {
    pub fn hash_add(args: anytype) u64 {
        const temp = std.fmt.allocPrint(allocator, "{}:{}", .{ args[0], args[1] }) catch unreachable;
        const temp = std.fmt.allocPrint(allocator, "{}:{}", .{ args[0], args[1] }) catch unreachable;
        defer allocator.free(temp);
        defer allocator.free(temp);
        return std.hash_map.hashString(temp);
        return std.hash_map.hashString(temp);
    }
    }
};
};
test "test_cache" {
test "test_cache" {
    const allocator = std.testing.allocator;
    const allocator = std.testing.allocator;
    HashAdd.allocator = allocator;
    HashAdd.allocator = allocator;
    var cache = Cache(_add, HashAdd.hash_add).init(allocator);
    var cache = Cache(_add, HashAdd.hash_add).init(allocator);
    const value: u64 = try cache.get(.{ 1, 2 });
    const value: u64 = try cache.get(.{ 1, 2 });
    try std.testing.expectEqual(3, value);
    try std.testing.expectEqual(3, value);
    const cache_value: u64 = try cache.get(.{ 1, 2 });
    const cache_value: u64 = try cache.get(.{ 1, 2 });
    try std.testing.expectEqual(3, cache_value);
    try std.testing.expectEqual(3, cache_value);
    cache._inner.deinit();
    cache._inner.deinit();
}
}