lib/choir/src/core/attrs.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 const attribute = @import("attribute.zig");
  3 const Attribute = attribute.Attribute;
  4 const Type = @import("type.zig").Type;
  5 const interfaces = @import("interfaces/root.zig");
  6 
  7 const default_hash_load = std.hash_map.default_max_load_percentage;
  8 
  9 fn hashUpdateU64(hasher: *std.hash.Wyhash, value: u64) void {
 10     var buf: [8]u8 = undefined;
 11     std.mem.writeInt(u64, &buf, value, .little);
 12     hasher.update(&buf);
 13 }
 14 
 15 pub const DialectAttrKey = struct {
 16     attr_id: u32,
 17     payload: []const u8,
 18 };
 19 
 20 const DialectAttrKeyContext = struct {
 21     pub fn hash(_: DialectAttrKeyContext, key: DialectAttrKey) u64 {
 22         var hasher = std.hash.Wyhash.init(0);
 23         hashUpdateU64(&hasher, key.attr_id);
 24         hasher.update(key.payload);
 25         return hasher.final();
 26     }
 27 
 28     pub fn eql(_: DialectAttrKeyContext, a: DialectAttrKey, b: DialectAttrKey) bool {
 29         return a.attr_id == b.attr_id and std.mem.eql(u8, a.payload, b.payload);
 30     }
 31 };
 32 
 33 pub const IntegerAttrKey = struct {
 34     value: i64,
 35     width: u8,
 36     is_signed: bool,
 37 };
 38 
 39 const IntegerAttrKeyContext = struct {
 40     pub fn hash(_: IntegerAttrKeyContext, key: IntegerAttrKey) u64 {
 41         var hasher = std.hash.Wyhash.init(0);
 42         hashUpdateU64(&hasher, @bitCast(key.value));
 43         hasher.update(&[_]u8{key.width});
 44         hasher.update(&[_]u8{if (key.is_signed) 1 else 0});
 45         return hasher.final();
 46     }
 47 
 48     pub fn eql(_: IntegerAttrKeyContext, a: IntegerAttrKey, b: IntegerAttrKey) bool {
 49         return a.value == b.value and a.width == b.width and a.is_signed == b.is_signed;
 50     }
 51 };
 52 
 53 pub const FloatAttrKey = struct {
 54     value_bits: u64,
 55     width: u8,
 56 };
 57 
 58 const FloatAttrKeyContext = struct {
 59     pub fn hash(_: FloatAttrKeyContext, key: FloatAttrKey) u64 {
 60         var hasher = std.hash.Wyhash.init(0);
 61         hashUpdateU64(&hasher, key.value_bits);
 62         hasher.update(&[_]u8{key.width});
 63         return hasher.final();
 64     }
 65 
 66     pub fn eql(_: FloatAttrKeyContext, a: FloatAttrKey, b: FloatAttrKey) bool {
 67         return a.value_bits == b.value_bits and a.width == b.width;
 68     }
 69 };
 70 
 71 pub const StringAttrKey = struct {
 72     value: []const u8,
 73 };
 74 
 75 const StringAttrKeyContext = struct {
 76     pub fn hash(_: StringAttrKeyContext, key: StringAttrKey) u64 {
 77         var hasher = std.hash.Wyhash.init(0);
 78         hasher.update(key.value);
 79         return hasher.final();
 80     }
 81 
 82     pub fn eql(_: StringAttrKeyContext, a: StringAttrKey, b: StringAttrKey) bool {
 83         return std.mem.eql(u8, a.value, b.value);
 84     }
 85 };
 86 
 87 pub const SymbolRefAttrKey = struct {
 88     root_reference: []const u8,
 89     nested_references: []const []const u8,
 90 };
 91 
 92 const SymbolRefAttrKeyContext = struct {
 93     pub fn hash(_: SymbolRefAttrKeyContext, key: SymbolRefAttrKey) u64 {
 94         var hasher = std.hash.Wyhash.init(0);
 95         hashUpdateU64(&hasher, @intCast(key.root_reference.len));
 96         hasher.update(key.root_reference);
 97         hashUpdateU64(&hasher, @intCast(key.nested_references.len));
 98         for (key.nested_references) |nested| {
 99             hashUpdateU64(&hasher, @intCast(nested.len));
100             hasher.update(nested);
101         }
102         return hasher.final();
103     }
104 
105     pub fn eql(_: SymbolRefAttrKeyContext, a: SymbolRefAttrKey, b: SymbolRefAttrKey) bool {
106         if (!std.mem.eql(u8, a.root_reference, b.root_reference)) return false;
107         if (a.nested_references.len != b.nested_references.len) return false;
108         for (a.nested_references, b.nested_references) |lhs, rhs| {
109             if (!std.mem.eql(u8, lhs, rhs)) return false;
110         }
111         return true;
112     }
113 };
114 
115 pub const StringListAttrKey = struct {
116     values: []const []const u8,
117 };
118 
119 const StringListAttrKeyContext = struct {
120     pub fn hash(_: StringListAttrKeyContext, key: StringListAttrKey) u64 {
121         var hasher = std.hash.Wyhash.init(0);
122         for (key.values) |value| {
123             hashUpdateU64(&hasher, @intCast(value.len));
124             hasher.update(value);
125         }
126         return hasher.final();
127     }
128 
129     pub fn eql(_: StringListAttrKeyContext, a: StringListAttrKey, b: StringListAttrKey) bool {
130         if (a.values.len != b.values.len) return false;
131         for (a.values, b.values) |lhs, rhs| {
132             if (!std.mem.eql(u8, lhs, rhs)) return false;
133         }
134         return true;
135     }
136 };
137 
138 pub const TypeListAttrKey = struct {
139     values: []const Type,
140 };
141 
142 const TypeListAttrKeyContext = struct {
143     pub fn hash(_: TypeListAttrKeyContext, key: TypeListAttrKey) u64 {
144         var hasher = std.hash.Wyhash.init(0);
145         for (key.values) |typ| {
146             hashUpdateU64(&hasher, typ.uniqueId());
147         }
148         return hasher.final();
149     }
150 
151     pub fn eql(_: TypeListAttrKeyContext, a: TypeListAttrKey, b: TypeListAttrKey) bool {
152         if (a.values.len != b.values.len) return false;
153         for (a.values, b.values) |lhs, rhs| {
154             if (!lhs.eql(rhs)) return false;
155         }
156         return true;
157     }
158 };
159 
160 pub const ArrayAttrKey = struct {
161     values: []const Attribute,
162 };
163 
164 const ArrayAttrKeyContext = struct {
165     pub fn hash(_: ArrayAttrKeyContext, key: ArrayAttrKey) u64 {
166         var hasher = std.hash.Wyhash.init(0);
167         hashUpdateU64(&hasher, @intCast(key.values.len));
168         for (key.values) |attr| {
169             hashUpdateU64(&hasher, @backingInt(attr.attr_id));
170         }
171         return hasher.final();
172     }
173 
174     pub fn eql(_: ArrayAttrKeyContext, a: ArrayAttrKey, b: ArrayAttrKey) bool {
175         if (a.values.len != b.values.len) return false;
176         for (a.values, b.values) |lhs, rhs| {
177             if (!lhs.eql(rhs)) return false;
178         }
179         return true;
180     }
181 };
182 
183 pub const AttrStorage = struct {
184     dialect_attrs: DialectAttrMap,
185     integer_attrs: IntegerAttrMap,
186     float_attrs: FloatAttrMap,
187     bool_attrs: BoolAttrMap,
188     string_attrs: StringAttrMap,
189     symbol_ref_attrs: SymbolRefAttrMap,
190     string_list_attrs: StringListAttrMap,
191     type_list_attrs: TypeListAttrMap,
192     array_attrs: ArrayAttrMap,
193 
194     const DialectAttrMap: type = std.HashMap(DialectAttrKey, Attribute, DialectAttrKeyContext, default_hash_load);
195     const IntegerAttrMap: type = std.HashMap(IntegerAttrKey, Attribute, IntegerAttrKeyContext, default_hash_load);
196     const FloatAttrMap: type = std.HashMap(FloatAttrKey, Attribute, FloatAttrKeyContext, default_hash_load);
197     const BoolAttrMap: type = std.AutoHashMap(bool, Attribute);
198     const StringAttrMap: type = std.HashMap(StringAttrKey, Attribute, StringAttrKeyContext, default_hash_load);
199     const SymbolRefAttrMap: type = std.HashMap(SymbolRefAttrKey, Attribute, SymbolRefAttrKeyContext, default_hash_load);
200     const StringListAttrMap: type = std.HashMap(StringListAttrKey, Attribute, StringListAttrKeyContext, default_hash_load);
201     const TypeListAttrMap: type = std.HashMap(TypeListAttrKey, Attribute, TypeListAttrKeyContext, default_hash_load);
202     const ArrayAttrMap: type = std.HashMap(ArrayAttrKey, Attribute, ArrayAttrKeyContext, default_hash_load);
203 
204     pub fn init(allocator: std.mem.Allocator) AttrStorage {
205         return .{
206             .dialect_attrs = DialectAttrMap.init(allocator),
207             .integer_attrs = IntegerAttrMap.init(allocator),
208             .float_attrs = FloatAttrMap.init(allocator),
209             .bool_attrs = BoolAttrMap.init(allocator),
210             .string_attrs = StringAttrMap.init(allocator),
211             .symbol_ref_attrs = SymbolRefAttrMap.init(allocator),
212             .string_list_attrs = StringListAttrMap.init(allocator),
213             .type_list_attrs = TypeListAttrMap.init(allocator),
214             .array_attrs = ArrayAttrMap.init(allocator),
215         };
216     }
217 
218     pub fn deinit(self: *AttrStorage, payload_allocator: std.mem.Allocator) void {
219         var dialect_iter = self.dialect_attrs.valueIterator();
220         while (dialect_iter.next()) |attr| {
221             const impl: *Attribute.DialectAttr = @ptrCast(@alignCast(@constCast(attr.impl)));
222             payload_allocator.free(impl.payload);
223             payload_allocator.destroy(impl);
224         }
225         self.dialect_attrs.deinit();
226 
227         var int_iter = self.integer_attrs.valueIterator();
228         while (int_iter.next()) |attr| {
229             const impl: *Attribute.IntegerAttr = @ptrCast(@alignCast(@constCast(attr.impl)));
230             payload_allocator.destroy(impl);
231         }
232         self.integer_attrs.deinit();
233 
234         var float_iter = self.float_attrs.valueIterator();
235         while (float_iter.next()) |attr| {
236             const impl: *Attribute.FloatAttr = @ptrCast(@alignCast(@constCast(attr.impl)));
237             payload_allocator.destroy(impl);
238         }
239         self.float_attrs.deinit();
240 
241         var bool_iter = self.bool_attrs.valueIterator();
242         while (bool_iter.next()) |attr| {
243             const impl: *Attribute.BoolAttr = @ptrCast(@alignCast(@constCast(attr.impl)));
244             payload_allocator.destroy(impl);
245         }
246         self.bool_attrs.deinit();
247 
248         var string_iter = self.string_attrs.valueIterator();
249         while (string_iter.next()) |attr| {
250             const impl: *Attribute.StringAttr = @ptrCast(@alignCast(@constCast(attr.impl)));
251             payload_allocator.free(impl.value);
252             payload_allocator.destroy(impl);
253         }
254         self.string_attrs.deinit();
255 
256         var symbol_ref_iter = self.symbol_ref_attrs.valueIterator();
257         while (symbol_ref_iter.next()) |attr| {
258             const impl: *Attribute.SymbolRefAttr = @ptrCast(@alignCast(@constCast(attr.impl)));
259             payload_allocator.free(impl.root_reference);
260             for (impl.nested_references) |nested| {
261                 payload_allocator.free(nested);
262             }
263             if (impl.nested_references.len > 0) payload_allocator.free(impl.nested_references);
264             payload_allocator.destroy(impl);
265         }
266         self.symbol_ref_attrs.deinit();
267 
268         var string_list_iter = self.string_list_attrs.valueIterator();
269         while (string_list_iter.next()) |attr| {
270             const impl: *Attribute.StringListAttr = @ptrCast(@alignCast(@constCast(attr.impl)));
271             for (impl.values) |value| {
272                 payload_allocator.free(value);
273             }
274             if (impl.values.len > 0) payload_allocator.free(impl.values);
275             payload_allocator.destroy(impl);
276         }
277         self.string_list_attrs.deinit();
278 
279         var type_list_iter = self.type_list_attrs.valueIterator();
280         while (type_list_iter.next()) |attr| {
281             const impl: *Attribute.TypeListAttr = @ptrCast(@alignCast(@constCast(attr.impl)));
282             if (impl.values.len > 0) payload_allocator.free(impl.values);
283             payload_allocator.destroy(impl);
284         }
285         self.type_list_attrs.deinit();
286 
287         var array_iter = self.array_attrs.valueIterator();
288         while (array_iter.next()) |attr| {
289             const impl: *Attribute.ArrayAttr = @ptrCast(@alignCast(@constCast(attr.impl)));
290             if (impl.values.len > 0) payload_allocator.free(impl.values);
291             payload_allocator.destroy(impl);
292         }
293         self.array_attrs.deinit();
294     }
295 };
296 
297 pub const AttributeInterner = struct {
298     storage: AttrStorage,
299     registry: interfaces.AttributeRegistry,
300 
301     pub fn init(
302         table_allocator: std.mem.Allocator,
303         registry_allocator: std.mem.Allocator,
304     ) AttributeInterner {
305         return .{
306             .storage = AttrStorage.init(table_allocator),
307             .registry = interfaces.AttributeRegistry.init(registry_allocator, attribute.Attribute.first_dynamic_attr_id),
308         };
309     }
310 
311     pub fn deinit(self: *AttributeInterner, payload_allocator: std.mem.Allocator) void {
312         self.storage.deinit(payload_allocator);
313         self.registry.deinit();
314     }
315 };