tiny.pluck.source_identity
Defined in tiny.pluck.
API (15)
Actions
Public operations.
ContentHash.eqlContentHash.fromExprContentHash.fromSourceDefinitionId.eqlDefinitionId.hashDefinitionId.initSourceThunkId.eqlSourceThunkId.hashSourceThunkId.initSourceThunkId.initQuery
Types and contracts
Public types and contracts.
Source
Source: lib/pluck/src/identity.zig
zig
const std = @import("std");const Allocator = std.mem.Allocator;const pexpr = @import("pexpr.zig");const Symbol = pexpr.Symbol;const PExpr = pexpr.PExpr;pub const DefinitionId = struct { name_hash: u64, name: Symbol, const Self = @This(); pub fn init(name: Symbol) Self { var hasher = std.hash.Wyhash.init(0); hasher.update(name); return Self{ .name_hash = hasher.final(), .name = name, }; } pub fn hash(self: Self) u64 { return self.name_hash; } pub fn eql(a: Self, b: Self) bool { return a.name_hash == b.name_hash and std.mem.eql(u8, a.name, b.name); }};pub const DefinitionIdContext = struct { pub fn hash(_: DefinitionIdContext, key: DefinitionId) u64 { return key.hash(); } pub fn eql(_: DefinitionIdContext, a: DefinitionId, b: DefinitionId) bool { return a.eql(b); }};pub const ContentHash = struct { hash: u64, const Self = @This(); pub fn fromExpr(expr: *const PExpr) Self { var hasher = std.hash.Wyhash.init(0xDEF1717100); hashExprStructure(&hasher, expr); return Self{ .hash = hasher.final() }; } pub fn fromSource(source: []const u8) Self { var hasher = std.hash.Wyhash.init(0xDEF1717100); var prev_was_space = false; for (source) |c| { if (std.ascii.isWhitespace(c)) { if (!prev_was_space) { hasher.update(" "); prev_was_space = true; } } else { hasher.update(&[_]u8{c}); prev_was_space = false; } } return Self{ .hash = hasher.final() }; } pub fn eql(a: Self, b: Self) bool { return a.hash == b.hash; } fn hashExprStructure(hasher: *std.hash.Wyhash, expr: *const PExpr) void { const head_tag = @backingInt(std.meta.activeTag(expr.head)); hasher.update(std.mem.asBytes(&head_tag)); switch (expr.head) { .var_ref => |v| hasher.update(v.name), .defined => |d| hasher.update(d.name), .abs => |a| hasher.update(a.var_name), .construct => |c| hasher.update(c.constructor), .case_of => |c| { for (c.branches) |branch| { hasher.update(branch.constructor); for (branch.args) |arg| { hasher.update(arg); } } }, .type_def => |t| { hasher.update(t.type_name); for (t.constructors) |ctor| { hasher.update(ctor.name); for (ctor.args) |arg| { hasher.update(arg); } } }, .const_native => |n| { switch (n) { .float => |f| { const bits: u64 = @bitCast(f); hasher.update(std.mem.asBytes(&bits)); }, .int => |i| hasher.update(std.mem.asBytes(&i)), .symbol => |s| hasher.update(s), .bool_val => |b| hasher.update(std.mem.asBytes(&b)), } }, .app, .y_combinator, .flip, .factor, .native_eq, .get_args, .get_constructor, .pbool, .get_config, .mk_int, .mk_int_weighted, .int_dist_eq, .print_op, .f_div, .f_mul, .f_add, .f_sub, .error_op, => {}, } for (expr.args) |arg| { hashExprStructure(hasher, arg); } }};pub const SourceThunkId = struct { def_id: DefinitionId, callstack_hash: u64, position_hash: u64, const Self = @This(); pub fn init(def_name: Symbol, callstack: []const i32, expr: *const PExpr) Self { var cs_hasher = std.hash.Wyhash.init(0); cs_hasher.update(std.mem.sliceAsBytes(callstack)); var pos_hasher = std.hash.Wyhash.init(0xB051710); ContentHash.hashExprStructure(&pos_hasher, expr); return Self{ .def_id = DefinitionId.init(def_name), .callstack_hash = cs_hasher.final(), .position_hash = pos_hasher.final(), }; } pub fn initQuery(callstack: []const i32, expr: *const PExpr) Self { return init("__query__", callstack, expr); } pub fn hash(self: Self) u64 { var h = std.hash.Wyhash.init(0); h.update(std.mem.asBytes(&self.def_id.name_hash)); h.update(std.mem.asBytes(&self.callstack_hash)); h.update(std.mem.asBytes(&self.position_hash)); return h.final(); } pub fn eql(a: Self, b: Self) bool { return a.def_id.eql(b.def_id) and a.callstack_hash == b.callstack_hash and a.position_hash == b.position_hash; }};pub const SourceThunkIdContext = struct { pub fn hash(_: SourceThunkIdContext, key: SourceThunkId) u64 { return key.hash(); } pub fn eql(_: SourceThunkIdContext, a: SourceThunkId, b: SourceThunkId) bool { return a.eql(b); }};test "DefinitionId stability" { const id1 = DefinitionId.init("foo"); const id2 = DefinitionId.init("foo"); const id3 = DefinitionId.init("bar"); try std.testing.expect(id1.eql(id2)); try std.testing.expectEqual(id1.hash(), id2.hash()); try std.testing.expect(!id1.eql(id3));}test "ContentHash from expression" { const allocator = std.testing.allocator; const expr1 = try PExpr.init(allocator, .{ .const_native = .{ .float = 42.0 } }); defer expr1.deinit(allocator); const expr2 = try PExpr.init(allocator, .{ .const_native = .{ .float = 42.0 } }); defer expr2.deinit(allocator); const expr3 = try PExpr.init(allocator, .{ .const_native = .{ .float = 43.0 } }); defer expr3.deinit(allocator); const hash1 = ContentHash.fromExpr(expr1); const hash2 = ContentHash.fromExpr(expr2); const hash3 = ContentHash.fromExpr(expr3); try std.testing.expect(hash1.eql(hash2)); try std.testing.expect(!hash1.eql(hash3));}test "SourceThunkId 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, 3 }; const id1 = SourceThunkId.init("mydef", callstack, expr1); const id2 = SourceThunkId.init("mydef", callstack, expr2); try std.testing.expect(id1.eql(id2)); try std.testing.expectEqual(id1.hash(), id2.hash());}Source: lib/pluck/src/root.zig:22
zig
pub const source_identity = @import("identity.zig");Audit
| Definitions | 14 |
|---|---|
| Public names | 14 |
| Members | 6 |
| Version | 26.7.0 |
| Revision | daab053ee433 |