tiny.preserves.containers
Defined in tiny.preserves.
A hash map and a hash set keyed by the package's values.
API (4)
Actions
Public operations.
ValueContext: Returns the hashing context forValue(D)that the standard hash map expects.ValueHashMap: Returns the standard unmanaged hash map type fromValue(D)keys toValue(D)values, keyed throughValueContext(D).ValueSet: Returns the standard unmanaged hash map type withValue(D)keys andvoidvalues, keyed throughValueContext(D).valueEqual: Returns true whenaandbare equal values, the same answera.eql(b)gives.
Source
Source: lib/preserves/src/containers.zig
zig
//! A hash map and a hash set keyed by the package's values. A lookup has to find a key whenever the//! key it is given is an equal value, including a set or dictionary that stores its items in//! another order. Two equal sets can store their items in different orders, and so can two equal//! dictionaries. A hash over the stored order would put such equal keys in different buckets.//!//! `ValueContext` gives the standard hash map the value's own hash and equality, which ignore the//! order in which a set or dictionary stores its items. `ValueHashMap` and `ValueSet` are the//! standard unmanaged hash map with that context, so every call that allocates takes the allocator//! as an argument. The map stores each key and value as given and frees only its own table, so the//! caller keeps every value's memory alive while it sits in the map.const std = @import("std");const value_mod = @import("value.zig");/// Returns the hashing context for `Value(D)` that the standard hash map expects. `ValueHashMap`/// and `ValueSet` pass it to Zig's standard hash map, so the map finds keys by value equality. The/// context holds no state, so every instance behaves the same.pub fn ValueContext(comptime D: type) type { return struct { /// Returns the hash of `v`, the same number `v.hash()` returns. Equal values get equal /// hashes, whatever order a set or dictionary stores its items in. pub fn hash(_: @This(), v: value_mod.Value(D)) u64 { return v.hash(); } /// Returns true when `a` and `b` are equal values, the same answer `a.eql(b)` gives. pub fn eql(_: @This(), a: value_mod.Value(D), b: value_mod.Value(D)) bool { return a.eql(b); } };}/// Returns the standard unmanaged hash map type from `Value(D)` keys to `Value(D)` values, keyed/// through `ValueContext(D)`. Code that maps one Preserves value to another declares one, for/// lookups by value equality. The map grows once it is 80 percent full. A lookup with a set key/// finds an entry stored under an equal set in another order, and the same holds for dictionaries./// The map copies no value memory, and `deinit` frees only the map's table.pub fn ValueHashMap(comptime D: type) type { return std.HashMapUnmanaged(value_mod.Value(D), value_mod.Value(D), ValueContext(D), 80);}/// Returns the standard unmanaged hash map type with `Value(D)` keys and `void` values, keyed/// through `ValueContext(D)`. Code that tracks which values it has seen declares one of these. The/// set grows once it is 80 percent full. Adding an equal value a second time leaves the count/// unchanged. The set copies no value memory, and `deinit` frees only its table.pub fn ValueSet(comptime D: type) type { return std.HashMapUnmanaged(value_mod.Value(D), void, ValueContext(D), 80);}/// Returns true when `a` and `b` are equal values, the same answer `a.eql(b)` gives. Generic code/// that passes equality as a function value calls it, for the method's answer in function form. The/// package root's `valueEqual` is a separate function with the same answer for values whose/// embedded values hold any pointer.pub fn valueEqual(comptime D: type, a: value_mod.Value(D), b: value_mod.Value(D)) bool { return a.eql(b);}test "ValueHashMap stores and looks up by value" { const NoEmbedded = @import("domain.zig").NoEmbedded; const V = value_mod.Value(NoEmbedded); const Map = ValueHashMap(NoEmbedded); const allocator = std.testing.allocator; var map: Map = .{}; defer map.deinit(allocator); const k1 = V.initI128(1); const k2 = V.initI128(2); const v1 = V.initBoolean(true); const v2 = V.initBoolean(false); try map.put(allocator, k1, v1); try map.put(allocator, k2, v2); try std.testing.expectEqual(@as(usize, 2), map.count()); const got1 = map.get(V.initI128(1)).?; try std.testing.expect(got1.eql(v1)); const got2 = map.get(V.initI128(2)).?; try std.testing.expect(got2.eql(v2)); try std.testing.expect(map.get(V.initI128(99)) == null);}test "ValueHashMap finds permutation-equivalent unordered keys" { const NoEmbedded = @import("domain.zig").NoEmbedded; const V = value_mod.Value(NoEmbedded); const Map = ValueHashMap(NoEmbedded); const allocator = std.testing.allocator; var map: Map = .{}; defer map.deinit(allocator); var set_items_a = [_]V{ V.initI128(1), V.initI128(2) }; var set_items_b = [_]V{ V.initI128(2), V.initI128(1) }; const set_a = V.initSet(&set_items_a); const set_b = V.initSet(&set_items_b); try std.testing.expect(set_a.eql(set_b)); try std.testing.expectEqual(std.math.Order.eq, set_a.compare(set_b)); try std.testing.expectEqual(set_a.hash(), set_b.hash()); try map.put(allocator, set_a, V.initBoolean(true)); try std.testing.expect(map.get(set_b) != null); var entries_a = [_]V.DictionaryEntry{ .{ .key = V.initI128(1), .value = V.initBoolean(true) }, .{ .key = V.initI128(2), .value = V.initBoolean(false) }, }; var entries_b = [_]V.DictionaryEntry{ .{ .key = V.initI128(2), .value = V.initBoolean(false) }, .{ .key = V.initI128(1), .value = V.initBoolean(true) }, }; const dictionary_a = V.initDictionary(&entries_a); const dictionary_b = V.initDictionary(&entries_b); try std.testing.expect(dictionary_a.eql(dictionary_b)); try std.testing.expectEqual(std.math.Order.eq, dictionary_a.compare(dictionary_b)); try std.testing.expectEqual(dictionary_a.hash(), dictionary_b.hash()); try map.put(allocator, dictionary_a, V.initBoolean(false)); try std.testing.expect(map.get(dictionary_b) != null);}test "ValueSet tracks presence" { const NoEmbedded = @import("domain.zig").NoEmbedded; const V = value_mod.Value(NoEmbedded); const Set = ValueSet(NoEmbedded); const allocator = std.testing.allocator; var set: Set = .{}; defer set.deinit(allocator); try set.put(allocator, V.initI128(1), {}); try set.put(allocator, V.initI128(2), {}); try set.put(allocator, V.initI128(1), {}); try std.testing.expectEqual(@as(usize, 2), set.count()); try std.testing.expect(set.contains(V.initI128(1))); try std.testing.expect(!set.contains(V.initI128(7)));}test "valueEqual freestanding wrapper matches method form" { const NoEmbedded = @import("domain.zig").NoEmbedded; const V = value_mod.Value(NoEmbedded); try std.testing.expect(valueEqual(NoEmbedded, V.initI128(1), V.initI128(1))); try std.testing.expect(!valueEqual(NoEmbedded, V.initI128(1), V.initI128(2)));}Source: lib/preserves/src/root.zig:111
zig
pub const containers = @import("containers.zig");Audit
| Definitions | 5 |
|---|---|
| Public names | 5 |
| Members | 0 |
| Version | 26.7.0 |
| Revision | daab053ee433 |