tiny.pluck.thunk_registry
Defined in tiny.pluck.
API (46)
Actions
Public operations.
SessionThunkId.eqlSessionThunkId.hashSessionThunkId.initThunkDependencies.addDependencyThunkDependencies.clearAllDirtyThunkDependencies.clearDirtyThunkDependencies.deinitThunkDependencies.dirtyCountThunkDependencies.dirtyIteratorThunkDependencies.getThunksThunkDependencies.getVariablesThunkDependencies.initThunkDependencies.isDirtyThunkDependencies.markDirtyThunkDependencies.removeThunkThunkId.eqlThunkId.hashThunkId.initThunkId.initQueryThunkId.initSessionThunkId.initStructuralThunkRegistry.countThunkRegistry.deinitThunkRegistry.getThunkRegistry.idModeThunkRegistry.initThunkRegistry.initWithModeThunkRegistry.invalidateDefinitionThunkRegistry.invalidateDefinitionsThunkRegistry.iteratorThunkRegistry.refineVariableThunkRegistry.registerThunkRegistry.registerWithContextThunkRegistry.registerWithDefThunkRegistry.resetThunkRegistry.thunkCountForDefThunkRegistry.unregister
Types and contracts
Public types and contracts.
SessionThunkIdSymbolThunkDependenciesThunkIdThunkIdContextThunkIdModeThunkIdSetThunkRegistryWorld
Source
Source: lib/pluck/src/registry.zig
zig
const std = @import("std");const Allocator = std.mem.Allocator;const bdd = @import("bdd.zig");const Bdd = bdd.Bdd;const Manager = bdd.Manager;const VarLabel = bdd.VarLabel;const runtime = @import("runtime.zig");const LazyKCThunk = runtime.LazyKCThunk;const GuardedWorlds = runtime.GuardedWorlds;const pexpr = @import("pexpr.zig");const PExpr = pexpr.PExpr;const source_identity = @import("identity.zig");const SourceThunkId = source_identity.SourceThunkId;pub const World = runtime.GuardedWorld;const hash_mix = 0x517cc1b727220a95;inline fn mixHashWord(h: u64, word: u64) u64 { return (std.math.rotl(u64, h, 5) ^ word) *% hash_mix;}pub const ThunkIdMode = enum { session, structural,};pub const SessionThunkId = struct { expr_ptr: usize, callstack_hash: u64, const Self = @This(); pub fn init(expr: *PExpr, callstack: []const i32) Self { var hasher = std.hash.Wyhash.init(0); hasher.update(std.mem.sliceAsBytes(callstack)); return Self{ .expr_ptr = @intFromPtr(expr), .callstack_hash = hasher.final(), }; } pub fn hash(self: Self) u64 { var h: u64 = 0; h = mixHashWord(h, @as(u64, @intCast(self.expr_ptr))); h = mixHashWord(h, self.callstack_hash); return h; } pub fn eql(a: Self, b: Self) bool { return a.expr_ptr == b.expr_ptr and a.callstack_hash == b.callstack_hash; }};pub const ThunkId = union(enum) { session: SessionThunkId, structural: SourceThunkId, const Self = @This(); pub fn init(expr: *PExpr, callstack: []const i32) Self { return .{ .session = SessionThunkId.init(expr, callstack) }; } pub fn initSession(expr: *PExpr, callstack: []const i32) Self { return .{ .session = SessionThunkId.init(expr, callstack) }; } pub fn initStructural(def_name: Symbol, callstack: []const i32, expr: *const PExpr) Self { return .{ .structural = SourceThunkId.init(def_name, callstack, expr) }; } pub fn initQuery(callstack: []const i32, expr: *const PExpr) Self { return .{ .structural = SourceThunkId.initQuery(callstack, expr) }; } pub fn hash(self: Self) u64 { var h = mixHashWord(0, @backingInt(std.meta.activeTag(self))); switch (self) { .session => |s| { h = mixHashWord(h, @as(u64, @intCast(s.expr_ptr))); h = mixHashWord(h, s.callstack_hash); }, .structural => |s| { h = mixHashWord(h, s.hash()); }, } return h; } pub fn eql(a: Self, b: Self) bool { return switch (a) { .session => |sa| switch (b) { .session => |sb| sa.eql(sb), else => false, }, .structural => |sa| switch (b) { .structural => |sb| sa.eql(sb), else => false, }, }; }};pub const ThunkIdContext = struct { pub fn hash(_: ThunkIdContext, key: ThunkId) u64 { return key.hash(); } pub fn eql(_: ThunkIdContext, a: ThunkId, b: ThunkId) bool { return a.eql(b); }};pub const ThunkIdSet = std.HashMapUnmanaged(ThunkId, void, ThunkIdContext, 80);const VarLabelSet = bdd.VarLabelSet;const VarThunkMap = std.HashMapUnmanaged(VarLabel, ThunkIdSet, bdd.VarLabelHashContext, 80);pub const Symbol = []const u8;pub const ThunkRegistry = struct { thunks: std.HashMapUnmanaged(ThunkId, *LazyKCThunk, ThunkIdContext, 80), def_to_thunks: std.StringHashMapUnmanaged(ThunkIdSet), thunk_to_def: std.HashMapUnmanaged(ThunkId, Symbol, ThunkIdContext, 80), id_mode: ThunkIdMode, allocator: Allocator, const Self = @This(); pub fn init(allocator: Allocator) Self { return initWithMode(allocator, .session); } pub fn initWithMode(allocator: Allocator, mode: ThunkIdMode) Self { return Self{ .thunks = .{}, .def_to_thunks = .{}, .thunk_to_def = .{}, .id_mode = mode, .allocator = allocator, }; } pub fn idMode(self: *const Self) ThunkIdMode { return self.id_mode; } pub fn reset(self: *Self) void { const prev_mode = self.id_mode; const allocator = self.allocator; self.deinit(); self.* = ThunkRegistry.initWithMode(allocator, prev_mode); } pub fn deinit(self: *Self) void { var iter = self.def_to_thunks.valueIterator(); while (iter.next()) |set| { set.deinit(self.allocator); } self.def_to_thunks.deinit(self.allocator); self.thunk_to_def.deinit(self.allocator); self.thunks.deinit(self.allocator); } fn makeId(self: *const Self, expr: *PExpr, callstack: []const i32, def_name: ?Symbol) ThunkId { return switch (self.id_mode) { .session => ThunkId.initSession(expr, callstack), .structural => if (def_name) |name| ThunkId.initStructural(name, callstack, expr) else ThunkId.initQuery(callstack, expr), }; } pub fn registerWithContext(self: *Self, thunk: *LazyKCThunk, expr: *PExpr, callstack: []const i32, def_name: ?Symbol) !void { const id = self.makeId(expr, callstack, def_name); try self.thunks.put(self.allocator, id, thunk); if (def_name) |name| { const entry = try self.def_to_thunks.getOrPut(self.allocator, name); if (!entry.found_existing) { entry.value_ptr.* = .{}; } try entry.value_ptr.put(self.allocator, id, {}); try self.thunk_to_def.put(self.allocator, id, name); } } pub fn registerWithDef(self: *Self, thunk: *LazyKCThunk, expr: *PExpr, callstack: []const i32, def_name: Symbol) !void { try self.registerWithContext(thunk, expr, callstack, def_name); } pub fn register(self: *Self, thunk: *LazyKCThunk, expr: *PExpr, callstack: []const i32) !void { try self.registerWithContext(thunk, expr, callstack, null); } pub fn get(self: *const Self, id: ThunkId) ?*LazyKCThunk { return self.thunks.get(id); } pub fn count(self: *const Self) usize { return self.thunks.count(); } pub fn iterator(self: *Self) std.HashMapUnmanaged(ThunkId, *LazyKCThunk, ThunkIdContext, 80).Iterator { return self.thunks.iterator(); } pub fn refineVariable(self: *Self, manager: *Manager, var_label: VarLabel, value: bool) Allocator.Error!void { var it = self.thunks.iterator(); while (it.next()) |entry| { const thunk = entry.value_ptr.*; var cache_idx: usize = 0; while (cache_idx < thunk.cache.items.len) { const gw = &thunk.cache.items[cache_idx]; const new_validity_guard = try manager.condition(gw.validity_guard, var_label, value); if (new_validity_guard.isFalse()) { const removed = thunk.cache.swapRemove(cache_idx); thunk.allocator.free(removed.worlds); } else { gw.validity_guard = new_validity_guard; for (gw.worlds) |*world| { world.guard = try manager.condition(world.guard, var_label, value); } cache_idx += 1; } } } } pub fn unregister(self: *Self, id: ThunkId) bool { if (self.thunk_to_def.fetchRemove(id)) |kv| { const def_name = kv.value; if (self.def_to_thunks.getPtr(def_name)) |thunk_set| { _ = thunk_set.remove(id); } } return self.thunks.remove(id); } pub fn invalidateDefinition(self: *Self, def_name: Symbol) usize { var invalidated: usize = 0; if (self.def_to_thunks.fetchRemove(def_name)) |kv| { var thunk_set = kv.value; var iter = thunk_set.keyIterator(); while (iter.next()) |thunk_id| { _ = self.thunks.remove(thunk_id.*); _ = self.thunk_to_def.remove(thunk_id.*); invalidated += 1; } thunk_set.deinit(self.allocator); } return invalidated; } pub fn invalidateDefinitions(self: *Self, def_names: anytype) usize { var total: usize = 0; var iter = def_names.keyIterator(); while (iter.next()) |name| { total += self.invalidateDefinition(name.*); } return total; } pub fn thunkCountForDef(self: *const Self, def_name: Symbol) usize { if (self.def_to_thunks.get(def_name)) |set| { return set.count(); } return 0; }};pub const ThunkDependencies = struct { thunk_to_vars: std.HashMapUnmanaged(ThunkId, VarLabelSet, ThunkIdContext, 80), var_to_thunks: VarThunkMap, dirty: ThunkIdSet, allocator: Allocator, const Self = @This(); pub fn init(allocator: Allocator) Self { return Self{ .thunk_to_vars = .{}, .var_to_thunks = .{}, .dirty = .{}, .allocator = allocator, }; } pub fn deinit(self: *Self) void { var thunk_iter = self.thunk_to_vars.iterator(); while (thunk_iter.next()) |entry| { var var_set = entry.value_ptr.*; var_set.deinit(self.allocator); } self.thunk_to_vars.deinit(self.allocator); var var_iter = self.var_to_thunks.iterator(); while (var_iter.next()) |entry| { var thunk_set = entry.value_ptr.*; thunk_set.deinit(self.allocator); } self.var_to_thunks.deinit(self.allocator); self.dirty.deinit(self.allocator); } pub fn addDependency(self: *Self, thunk_id: ThunkId, var_label: VarLabel) !void { const thunk_entry = try self.thunk_to_vars.getOrPut(self.allocator, thunk_id); if (!thunk_entry.found_existing) { thunk_entry.value_ptr.* = .{}; } try thunk_entry.value_ptr.put(self.allocator, var_label, {}); const var_entry = try self.var_to_thunks.getOrPut(self.allocator, var_label); if (!var_entry.found_existing) { var_entry.value_ptr.* = .{}; } try var_entry.value_ptr.put(self.allocator, thunk_id, {}); } pub fn getVariables(self: *const Self, thunk_id: ThunkId) ?*const VarLabelSet { return self.thunk_to_vars.getPtr(thunk_id); } pub fn getThunks(self: *const Self, var_label: VarLabel) ?*const ThunkIdSet { return self.var_to_thunks.getPtr(var_label); } pub fn markDirty(self: *Self, var_label: VarLabel) !void { if (self.var_to_thunks.get(var_label)) |thunk_set| { var it = thunk_set.iterator(); while (it.next()) |entry| { try self.dirty.put(self.allocator, entry.key_ptr.*, {}); } } } pub fn isDirty(self: *const Self, thunk_id: ThunkId) bool { return self.dirty.contains(thunk_id); } pub fn clearDirty(self: *Self, thunk_id: ThunkId) void { _ = self.dirty.remove(thunk_id); } pub fn clearAllDirty(self: *Self) void { self.dirty.clearRetainingCapacity(); } pub fn dirtyCount(self: *const Self) usize { return self.dirty.count(); } pub fn removeThunk(self: *Self, thunk_id: ThunkId) void { _ = self.dirty.remove(thunk_id); if (self.thunk_to_vars.fetchRemove(thunk_id)) |kv| { var var_set = kv.value; var it = var_set.iterator(); while (it.next()) |entry| { if (self.var_to_thunks.getPtr(entry.key_ptr.*)) |thunk_set| { _ = thunk_set.remove(thunk_id); } } var_set.deinit(self.allocator); } } pub fn dirtyIterator(self: *Self) ThunkIdSet.Iterator { return self.dirty.iterator(); }};test "ThunkId stability" { const allocator = std.testing.allocator; const expr = try PExpr.init(allocator, .{ .const_native = .{ .float = 42.0 } }); defer expr.deinit(allocator); const callstack1: []const i32 = &[_]i32{ 1, 2, 3 }; const callstack2: []const i32 = &[_]i32{ 1, 2, 3 }; const id1 = ThunkId.init(expr, callstack1); const id2 = ThunkId.init(expr, callstack2); try std.testing.expect(id1.eql(id2)); try std.testing.expectEqual(id1.hash(), id2.hash()); const callstack3: []const i32 = &[_]i32{ 1, 2, 4 }; const id3 = ThunkId.init(expr, callstack3); try std.testing.expect(!id1.eql(id3));}test "ThunkId structural stability across re-parse" { const allocator = std.testing.allocator; const expr1 = try PExpr.init(allocator, .{ .const_native = .{ .float = 0.5 } }); defer expr1.deinit(allocator); const expr2 = try PExpr.init(allocator, .{ .const_native = .{ .float = 0.5 } }); defer expr2.deinit(allocator); const callstack: []const i32 = &[_]i32{ 1, 2 }; const id1 = ThunkId.initStructural("mydef", callstack, expr1); const id2 = ThunkId.initStructural("mydef", callstack, expr2); try std.testing.expect(id1.eql(id2)); try std.testing.expectEqual(id1.hash(), id2.hash()); const id3 = ThunkId.initStructural("otherdef", callstack, expr2); try std.testing.expect(!id1.eql(id3));}test "ThunkDependencies basic operations" { const allocator = std.testing.allocator; var deps = ThunkDependencies.init(allocator); defer deps.deinit(); const id1 = ThunkId{ .session = .{ .expr_ptr = 0x1000, .callstack_hash = 100 } }; const id2 = ThunkId{ .session = .{ .expr_ptr = 0x2000, .callstack_hash = 200 } }; try deps.addDependency(id1, 0); try deps.addDependency(id1, 1); try deps.addDependency(id2, 1); try deps.addDependency(id2, 2); const vars1 = deps.getVariables(id1).?; try std.testing.expect(vars1.contains(0)); try std.testing.expect(vars1.contains(1)); try std.testing.expect(!vars1.contains(2)); const thunks_for_var1 = deps.getThunks(1).?; try std.testing.expect(thunks_for_var1.contains(id1)); try std.testing.expect(thunks_for_var1.contains(id2)); const thunks_for_var0 = deps.getThunks(0).?; try std.testing.expect(thunks_for_var0.contains(id1)); try std.testing.expect(!thunks_for_var0.contains(id2));}test "ThunkDependencies dirty marking" { const allocator = std.testing.allocator; var deps = ThunkDependencies.init(allocator); defer deps.deinit(); const id1 = ThunkId{ .session = .{ .expr_ptr = 0x1000, .callstack_hash = 100 } }; const id2 = ThunkId{ .session = .{ .expr_ptr = 0x2000, .callstack_hash = 200 } }; try deps.addDependency(id1, 0); try deps.addDependency(id1, 1); try deps.addDependency(id2, 1); try std.testing.expectEqual(@as(usize, 0), deps.dirtyCount()); try std.testing.expect(!deps.isDirty(id1)); try deps.markDirty(0); try std.testing.expectEqual(@as(usize, 1), deps.dirtyCount()); try std.testing.expect(deps.isDirty(id1)); try std.testing.expect(!deps.isDirty(id2)); deps.clearDirty(id1); try std.testing.expectEqual(@as(usize, 0), deps.dirtyCount()); try deps.markDirty(1); try std.testing.expectEqual(@as(usize, 2), deps.dirtyCount()); try std.testing.expect(deps.isDirty(id1)); try std.testing.expect(deps.isDirty(id2)); deps.clearAllDirty(); try std.testing.expectEqual(@as(usize, 0), deps.dirtyCount());}test "ThunkDependencies removeThunk cleans up correctly" { const allocator = std.testing.allocator; var deps = ThunkDependencies.init(allocator); defer deps.deinit(); const id1 = ThunkId{ .session = .{ .expr_ptr = 0x1000, .callstack_hash = 100 } }; const id2 = ThunkId{ .session = .{ .expr_ptr = 0x2000, .callstack_hash = 200 } }; try deps.addDependency(id1, 0); try deps.addDependency(id1, 1); try deps.addDependency(id2, 1); try deps.markDirty(0); try std.testing.expect(deps.isDirty(id1)); deps.removeThunk(id1); try std.testing.expect(deps.getVariables(id1) == null); const thunks_for_var0 = deps.getThunks(0).?; try std.testing.expect(!thunks_for_var0.contains(id1)); const thunks_for_var1 = deps.getThunks(1).?; try std.testing.expect(!thunks_for_var1.contains(id1)); try std.testing.expect(thunks_for_var1.contains(id2)); try std.testing.expect(!deps.isDirty(id1));}test "ThunkRegistry definition-based invalidation" { const allocator = std.testing.allocator; var registry = ThunkRegistry.init(allocator); defer registry.deinit(); const id1 = ThunkId{ .session = .{ .expr_ptr = 0x1000, .callstack_hash = 100 } }; const id2 = ThunkId{ .session = .{ .expr_ptr = 0x2000, .callstack_hash = 200 } }; const id3 = ThunkId{ .session = .{ .expr_ptr = 0x3000, .callstack_hash = 300 } }; { var foo_set = ThunkIdSet{}; try foo_set.put(allocator, id1, {}); try foo_set.put(allocator, id2, {}); try registry.def_to_thunks.put(allocator, "foo", foo_set); try registry.thunk_to_def.put(allocator, id1, "foo"); try registry.thunk_to_def.put(allocator, id2, "foo"); } { var bar_set = ThunkIdSet{}; try bar_set.put(allocator, id3, {}); try registry.def_to_thunks.put(allocator, "bar", bar_set); try registry.thunk_to_def.put(allocator, id3, "bar"); } try std.testing.expectEqual(@as(usize, 2), registry.thunkCountForDef("foo")); try std.testing.expectEqual(@as(usize, 1), registry.thunkCountForDef("bar")); const invalidated = registry.invalidateDefinition("foo"); try std.testing.expectEqual(@as(usize, 2), invalidated); try std.testing.expectEqual(@as(usize, 0), registry.thunkCountForDef("foo")); try std.testing.expectEqual(@as(usize, 1), registry.thunkCountForDef("bar")); try std.testing.expect(registry.thunk_to_def.get(id1) == null); try std.testing.expect(registry.thunk_to_def.get(id2) == null); try std.testing.expect(registry.thunk_to_def.get(id3) != null);}Source: lib/pluck/src/root.zig:24
zig
pub const thunk_registry = @import("registry.zig");Complete caller list for evaluator.ThunkDependencies.addDependency
7 direct callers.
lib.pluck.src.evaluator.test_ThunkDependencies_basic_operations[function] — test source atlib/pluck/src/evaluator.zig:4490in nearest public ownertiny.pluck.evaluatorlib.pluck.src.evaluator.test_ThunkDependencies_dirty_marking[function] — test source atlib/pluck/src/evaluator.zig:4518in nearest public ownertiny.pluck.evaluatorlib.pluck.src.evaluator.test_ThunkDependencies_removeThunk_cleans_up_correctly[function] — test source atlib/pluck/src/evaluator.zig:4551in nearest public ownertiny.pluck.evaluatorlib.pluck.src.profiling.internal.incremental.test_BENCHMARK:_ThunkDependencies_tracking[function] — test source atlib/pluck/src/profiling/internal/incremental.zig:658in nearest public ownerlib.pluck.src.profiling.internal.incrementallib.pluck.src.registry.test_ThunkDependencies_basic_operations[function] — test source atlib/pluck/src/registry.zig:420in nearest public ownertiny.pluck.thunk_registrylib.pluck.src.registry.test_ThunkDependencies_dirty_marking[function] — test source atlib/pluck/src/registry.zig:448in nearest public ownertiny.pluck.thunk_registrylib.pluck.src.registry.test_ThunkDependencies_removeThunk_cleans_up_correctly[function] — test source atlib/pluck/src/registry.zig:481in nearest public ownertiny.pluck.thunk_registry
Complete caller list for evaluator.ThunkDependencies.deinit
7 direct callers.
lib.pluck.src.evaluator.test_ThunkDependencies_basic_operations[function] — test source atlib/pluck/src/evaluator.zig:4490in nearest public ownertiny.pluck.evaluatorlib.pluck.src.evaluator.test_ThunkDependencies_dirty_marking[function] — test source atlib/pluck/src/evaluator.zig:4518in nearest public ownertiny.pluck.evaluatorlib.pluck.src.evaluator.test_ThunkDependencies_removeThunk_cleans_up_correctly[function] — test source atlib/pluck/src/evaluator.zig:4551in nearest public ownertiny.pluck.evaluatorlib.pluck.src.profiling.internal.incremental.test_BENCHMARK:_ThunkDependencies_tracking[function] — test source atlib/pluck/src/profiling/internal/incremental.zig:658in nearest public ownerlib.pluck.src.profiling.internal.incrementallib.pluck.src.registry.test_ThunkDependencies_basic_operations[function] — test source atlib/pluck/src/registry.zig:420in nearest public ownertiny.pluck.thunk_registrylib.pluck.src.registry.test_ThunkDependencies_dirty_marking[function] — test source atlib/pluck/src/registry.zig:448in nearest public ownertiny.pluck.thunk_registrylib.pluck.src.registry.test_ThunkDependencies_removeThunk_cleans_up_correctly[function] — test source atlib/pluck/src/registry.zig:481in nearest public ownertiny.pluck.thunk_registry
Complete caller list for evaluator.ThunkDependencies.init
7 direct callers.
lib.pluck.src.evaluator.test_ThunkDependencies_basic_operations[function] — test source atlib/pluck/src/evaluator.zig:4490in nearest public ownertiny.pluck.evaluatorlib.pluck.src.evaluator.test_ThunkDependencies_dirty_marking[function] — test source atlib/pluck/src/evaluator.zig:4518in nearest public ownertiny.pluck.evaluatorlib.pluck.src.evaluator.test_ThunkDependencies_removeThunk_cleans_up_correctly[function] — test source atlib/pluck/src/evaluator.zig:4551in nearest public ownertiny.pluck.evaluatorlib.pluck.src.profiling.internal.incremental.test_BENCHMARK:_ThunkDependencies_tracking[function] — test source atlib/pluck/src/profiling/internal/incremental.zig:658in nearest public ownerlib.pluck.src.profiling.internal.incrementallib.pluck.src.registry.test_ThunkDependencies_basic_operations[function] — test source atlib/pluck/src/registry.zig:420in nearest public ownertiny.pluck.thunk_registrylib.pluck.src.registry.test_ThunkDependencies_dirty_marking[function] — test source atlib/pluck/src/registry.zig:448in nearest public ownertiny.pluck.thunk_registrylib.pluck.src.registry.test_ThunkDependencies_removeThunk_cleans_up_correctly[function] — test source atlib/pluck/src/registry.zig:481in nearest public ownertiny.pluck.thunk_registry
Audit
| Definitions | 45 |
|---|---|
| Public names | 83 |
| Members | 15 |
| Version | 26.7.0 |
| Revision | daab053ee433 |