mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-27 19:09:47 +03:00
std.enums: remove IndexedMap, IndexedArray, IndexedSet
Searching GitHub indicated that the only use of these types in the wild is support in getty-zig, and testing for that support. This eliminates 3 more uses of usingnamespace from the standard library, and removes some unnecessarily complex generic code.
This commit is contained in:
+429
-533
@@ -241,27 +241,174 @@ test nameCast {
|
||||
/// to dense indices. This type does no dynamic allocation and
|
||||
/// can be copied by value.
|
||||
pub fn EnumSet(comptime E: type) type {
|
||||
const mixin = struct {
|
||||
fn EnumSetExt(comptime Self: type) type {
|
||||
const Indexer = Self.Indexer;
|
||||
return struct {
|
||||
/// Initializes the set using a struct of bools
|
||||
pub fn init(init_values: EnumFieldStruct(E, bool, false)) Self {
|
||||
var result = Self{};
|
||||
comptime var i: usize = 0;
|
||||
inline while (i < Self.len) : (i += 1) {
|
||||
const key = comptime Indexer.keyForIndex(i);
|
||||
const tag = comptime @tagName(key);
|
||||
if (@field(init_values, tag)) {
|
||||
result.bits.set(i);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
/// The indexing rules for converting between keys and indices.
|
||||
pub const Indexer = EnumIndexer(E);
|
||||
/// The element type for this set.
|
||||
pub const Key = Indexer.Key;
|
||||
|
||||
const BitSet = std.StaticBitSet(Indexer.count);
|
||||
|
||||
/// The maximum number of items in this set.
|
||||
pub const len = Indexer.count;
|
||||
|
||||
bits: BitSet = BitSet.initEmpty(),
|
||||
|
||||
/// Initializes the set using a struct of bools
|
||||
pub fn init(init_values: EnumFieldStruct(E, bool, false)) Self {
|
||||
var result: Self = .{};
|
||||
inline for (0..Self.len) |i| {
|
||||
const key = comptime Indexer.keyForIndex(i);
|
||||
const tag = @tagName(key);
|
||||
if (@field(init_values, tag)) {
|
||||
result.bits.set(i);
|
||||
}
|
||||
};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Returns a set containing no keys.
|
||||
pub fn initEmpty() Self {
|
||||
return .{ .bits = BitSet.initEmpty() };
|
||||
}
|
||||
|
||||
/// Returns a set containing all possible keys.
|
||||
pub fn initFull() Self {
|
||||
return .{ .bits = BitSet.initFull() };
|
||||
}
|
||||
|
||||
/// Returns a set containing multiple keys.
|
||||
pub fn initMany(keys: []const Key) Self {
|
||||
var set = initEmpty();
|
||||
for (keys) |key| set.insert(key);
|
||||
return set;
|
||||
}
|
||||
|
||||
/// Returns a set containing a single key.
|
||||
pub fn initOne(key: Key) Self {
|
||||
return initMany(&[_]Key{key});
|
||||
}
|
||||
|
||||
/// Returns the number of keys in the set.
|
||||
pub fn count(self: Self) usize {
|
||||
return self.bits.count();
|
||||
}
|
||||
|
||||
/// Checks if a key is in the set.
|
||||
pub fn contains(self: Self, key: Key) bool {
|
||||
return self.bits.isSet(Indexer.indexOf(key));
|
||||
}
|
||||
|
||||
/// Puts a key in the set.
|
||||
pub fn insert(self: *Self, key: Key) void {
|
||||
self.bits.set(Indexer.indexOf(key));
|
||||
}
|
||||
|
||||
/// Removes a key from the set.
|
||||
pub fn remove(self: *Self, key: Key) void {
|
||||
self.bits.unset(Indexer.indexOf(key));
|
||||
}
|
||||
|
||||
/// Changes the presence of a key in the set to match the passed bool.
|
||||
pub fn setPresent(self: *Self, key: Key, present: bool) void {
|
||||
self.bits.setValue(Indexer.indexOf(key), present);
|
||||
}
|
||||
|
||||
/// Toggles the presence of a key in the set. If the key is in
|
||||
/// the set, removes it. Otherwise adds it.
|
||||
pub fn toggle(self: *Self, key: Key) void {
|
||||
self.bits.toggle(Indexer.indexOf(key));
|
||||
}
|
||||
|
||||
/// Toggles the presence of all keys in the passed set.
|
||||
pub fn toggleSet(self: *Self, other: Self) void {
|
||||
self.bits.toggleSet(other.bits);
|
||||
}
|
||||
|
||||
/// Toggles all possible keys in the set.
|
||||
pub fn toggleAll(self: *Self) void {
|
||||
self.bits.toggleAll();
|
||||
}
|
||||
|
||||
/// Adds all keys in the passed set to this set.
|
||||
pub fn setUnion(self: *Self, other: Self) void {
|
||||
self.bits.setUnion(other.bits);
|
||||
}
|
||||
|
||||
/// Removes all keys which are not in the passed set.
|
||||
pub fn setIntersection(self: *Self, other: Self) void {
|
||||
self.bits.setIntersection(other.bits);
|
||||
}
|
||||
|
||||
/// Returns true iff both sets have the same keys.
|
||||
pub fn eql(self: Self, other: Self) bool {
|
||||
return self.bits.eql(other.bits);
|
||||
}
|
||||
|
||||
/// Returns true iff all the keys in this set are
|
||||
/// in the other set. The other set may have keys
|
||||
/// not found in this set.
|
||||
pub fn subsetOf(self: Self, other: Self) bool {
|
||||
return self.bits.subsetOf(other.bits);
|
||||
}
|
||||
|
||||
/// Returns true iff this set contains all the keys
|
||||
/// in the other set. This set may have keys not
|
||||
/// found in the other set.
|
||||
pub fn supersetOf(self: Self, other: Self) bool {
|
||||
return self.bits.supersetOf(other.bits);
|
||||
}
|
||||
|
||||
/// Returns a set with all the keys not in this set.
|
||||
pub fn complement(self: Self) Self {
|
||||
return .{ .bits = self.bits.complement() };
|
||||
}
|
||||
|
||||
/// Returns a set with keys that are in either this
|
||||
/// set or the other set.
|
||||
pub fn unionWith(self: Self, other: Self) Self {
|
||||
return .{ .bits = self.bits.unionWith(other.bits) };
|
||||
}
|
||||
|
||||
/// Returns a set with keys that are in both this
|
||||
/// set and the other set.
|
||||
pub fn intersectWith(self: Self, other: Self) Self {
|
||||
return .{ .bits = self.bits.intersectWith(other.bits) };
|
||||
}
|
||||
|
||||
/// Returns a set with keys that are in either this
|
||||
/// set or the other set, but not both.
|
||||
pub fn xorWith(self: Self, other: Self) Self {
|
||||
return .{ .bits = self.bits.xorWith(other.bits) };
|
||||
}
|
||||
|
||||
/// Returns a set with keys that are in this set
|
||||
/// except for keys in the other set.
|
||||
pub fn differenceWith(self: Self, other: Self) Self {
|
||||
return .{ .bits = self.bits.differenceWith(other.bits) };
|
||||
}
|
||||
|
||||
/// Returns an iterator over this set, which iterates in
|
||||
/// index order. Modifications to the set during iteration
|
||||
/// may or may not be observed by the iterator, but will
|
||||
/// not invalidate it.
|
||||
pub fn iterator(self: *const Self) Iterator {
|
||||
return .{ .inner = self.bits.iterator(.{}) };
|
||||
}
|
||||
|
||||
pub const Iterator = struct {
|
||||
inner: BitSet.Iterator(.{}),
|
||||
|
||||
pub fn next(self: *Iterator) ?Key {
|
||||
return if (self.inner.next()) |index|
|
||||
Indexer.keyForIndex(index)
|
||||
else
|
||||
null;
|
||||
}
|
||||
};
|
||||
};
|
||||
return IndexedSet(EnumIndexer(E), mixin.EnumSetExt);
|
||||
}
|
||||
|
||||
/// A map keyed by an enum, backed by a bitfield and a dense array.
|
||||
@@ -269,58 +416,211 @@ pub fn EnumSet(comptime E: type) type {
|
||||
/// enum values to dense indices. This type does no dynamic
|
||||
/// allocation and can be copied by value.
|
||||
pub fn EnumMap(comptime E: type, comptime V: type) type {
|
||||
const mixin = struct {
|
||||
fn EnumMapExt(comptime Self: type) type {
|
||||
const Indexer = Self.Indexer;
|
||||
return struct {
|
||||
/// Initializes the map using a sparse struct of optionals
|
||||
pub fn init(init_values: EnumFieldStruct(E, ?V, @as(?V, null))) Self {
|
||||
var result = Self{};
|
||||
comptime var i: usize = 0;
|
||||
inline while (i < Self.len) : (i += 1) {
|
||||
const key = comptime Indexer.keyForIndex(i);
|
||||
const tag = comptime @tagName(key);
|
||||
if (@field(init_values, tag)) |*v| {
|
||||
result.bits.set(i);
|
||||
result.values[i] = v.*;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/// Initializes a full mapping with all keys set to value.
|
||||
/// Consider using EnumArray instead if the map will remain full.
|
||||
pub fn initFull(value: V) Self {
|
||||
var result = Self{
|
||||
.bits = Self.BitSet.initFull(),
|
||||
.values = undefined,
|
||||
};
|
||||
@memset(&result.values, value);
|
||||
return result;
|
||||
}
|
||||
/// Initializes a full mapping with supplied values.
|
||||
/// Consider using EnumArray instead if the map will remain full.
|
||||
pub fn initFullWith(init_values: EnumFieldStruct(E, V, @as(?V, null))) Self {
|
||||
return initFullWithDefault(@as(?V, null), init_values);
|
||||
}
|
||||
/// Initializes a full mapping with a provided default.
|
||||
/// Consider using EnumArray instead if the map will remain full.
|
||||
pub fn initFullWithDefault(comptime default: ?V, init_values: EnumFieldStruct(E, V, default)) Self {
|
||||
var result = Self{
|
||||
.bits = Self.BitSet.initFull(),
|
||||
.values = undefined,
|
||||
};
|
||||
comptime var i: usize = 0;
|
||||
inline while (i < Self.len) : (i += 1) {
|
||||
const key = comptime Indexer.keyForIndex(i);
|
||||
const tag = comptime @tagName(key);
|
||||
result.values[i] = @field(init_values, tag);
|
||||
}
|
||||
return result;
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
/// The index mapping for this map
|
||||
pub const Indexer = EnumIndexer(E);
|
||||
/// The key type used to index this map
|
||||
pub const Key = Indexer.Key;
|
||||
/// The value type stored in this map
|
||||
pub const Value = V;
|
||||
/// The number of possible keys in the map
|
||||
pub const len = Indexer.count;
|
||||
|
||||
const BitSet = std.StaticBitSet(Indexer.count);
|
||||
|
||||
/// Bits determining whether items are in the map
|
||||
bits: BitSet = BitSet.initEmpty(),
|
||||
/// Values of items in the map. If the associated
|
||||
/// bit is zero, the value is undefined.
|
||||
values: [Indexer.count]Value = undefined,
|
||||
|
||||
/// Initializes the map using a sparse struct of optionals
|
||||
pub fn init(init_values: EnumFieldStruct(E, ?Value, null)) Self {
|
||||
var result: Self = .{};
|
||||
inline for (0..Self.len) |i| {
|
||||
const key = comptime Indexer.keyForIndex(i);
|
||||
const tag = @tagName(key);
|
||||
if (@field(init_values, tag)) |*v| {
|
||||
result.bits.set(i);
|
||||
result.values[i] = v.*;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes a full mapping with all keys set to value.
|
||||
/// Consider using EnumArray instead if the map will remain full.
|
||||
pub fn initFull(value: Value) Self {
|
||||
var result: Self = .{
|
||||
.bits = Self.BitSet.initFull(),
|
||||
.values = undefined,
|
||||
};
|
||||
@memset(&result.values, value);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Initializes a full mapping with supplied values.
|
||||
/// Consider using EnumArray instead if the map will remain full.
|
||||
pub fn initFullWith(init_values: EnumFieldStruct(E, Value, null)) Self {
|
||||
return initFullWithDefault(null, init_values);
|
||||
}
|
||||
|
||||
/// Initializes a full mapping with a provided default.
|
||||
/// Consider using EnumArray instead if the map will remain full.
|
||||
pub fn initFullWithDefault(comptime default: ?Value, init_values: EnumFieldStruct(E, Value, default)) Self {
|
||||
var result: Self = .{
|
||||
.bits = Self.BitSet.initFull(),
|
||||
.values = undefined,
|
||||
};
|
||||
inline for (0..Self.len) |i| {
|
||||
const key = comptime Indexer.keyForIndex(i);
|
||||
const tag = @tagName(key);
|
||||
result.values[i] = @field(init_values, tag);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// The number of items in the map.
|
||||
pub fn count(self: Self) usize {
|
||||
return self.bits.count();
|
||||
}
|
||||
|
||||
/// Checks if the map contains an item.
|
||||
pub fn contains(self: Self, key: Key) bool {
|
||||
return self.bits.isSet(Indexer.indexOf(key));
|
||||
}
|
||||
|
||||
/// Gets the value associated with a key.
|
||||
/// If the key is not in the map, returns null.
|
||||
pub fn get(self: Self, key: Key) ?Value {
|
||||
const index = Indexer.indexOf(key);
|
||||
return if (self.bits.isSet(index)) self.values[index] else null;
|
||||
}
|
||||
|
||||
/// Gets the value associated with a key, which must
|
||||
/// exist in the map.
|
||||
pub fn getAssertContains(self: Self, key: Key) Value {
|
||||
const index = Indexer.indexOf(key);
|
||||
assert(self.bits.isSet(index));
|
||||
return self.values[index];
|
||||
}
|
||||
|
||||
/// Gets the address of the value associated with a key.
|
||||
/// If the key is not in the map, returns null.
|
||||
pub fn getPtr(self: *Self, key: Key) ?*Value {
|
||||
const index = Indexer.indexOf(key);
|
||||
return if (self.bits.isSet(index)) &self.values[index] else null;
|
||||
}
|
||||
|
||||
/// Gets the address of the const value associated with a key.
|
||||
/// If the key is not in the map, returns null.
|
||||
pub fn getPtrConst(self: *const Self, key: Key) ?*const Value {
|
||||
const index = Indexer.indexOf(key);
|
||||
return if (self.bits.isSet(index)) &self.values[index] else null;
|
||||
}
|
||||
|
||||
/// Gets the address of the value associated with a key.
|
||||
/// The key must be present in the map.
|
||||
pub fn getPtrAssertContains(self: *Self, key: Key) *Value {
|
||||
const index = Indexer.indexOf(key);
|
||||
assert(self.bits.isSet(index));
|
||||
return &self.values[index];
|
||||
}
|
||||
|
||||
/// Gets the address of the const value associated with a key.
|
||||
/// The key must be present in the map.
|
||||
pub fn getPtrConstAssertContains(self: *const Self, key: Key) *const Value {
|
||||
const index = Indexer.indexOf(key);
|
||||
assert(self.bits.isSet(index));
|
||||
return &self.values[index];
|
||||
}
|
||||
|
||||
/// Adds the key to the map with the supplied value.
|
||||
/// If the key is already in the map, overwrites the value.
|
||||
pub fn put(self: *Self, key: Key, value: Value) void {
|
||||
const index = Indexer.indexOf(key);
|
||||
self.bits.set(index);
|
||||
self.values[index] = value;
|
||||
}
|
||||
|
||||
/// Adds the key to the map with an undefined value.
|
||||
/// If the key is already in the map, the value becomes undefined.
|
||||
/// A pointer to the value is returned, which should be
|
||||
/// used to initialize the value.
|
||||
pub fn putUninitialized(self: *Self, key: Key) *Value {
|
||||
const index = Indexer.indexOf(key);
|
||||
self.bits.set(index);
|
||||
self.values[index] = undefined;
|
||||
return &self.values[index];
|
||||
}
|
||||
|
||||
/// Sets the value associated with the key in the map,
|
||||
/// and returns the old value. If the key was not in
|
||||
/// the map, returns null.
|
||||
pub fn fetchPut(self: *Self, key: Key, value: Value) ?Value {
|
||||
const index = Indexer.indexOf(key);
|
||||
const result: ?Value = if (self.bits.isSet(index)) self.values[index] else null;
|
||||
self.bits.set(index);
|
||||
self.values[index] = value;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Removes a key from the map. If the key was not in the map,
|
||||
/// does nothing.
|
||||
pub fn remove(self: *Self, key: Key) void {
|
||||
const index = Indexer.indexOf(key);
|
||||
self.bits.unset(index);
|
||||
self.values[index] = undefined;
|
||||
}
|
||||
|
||||
/// Removes a key from the map, and returns the old value.
|
||||
/// If the key was not in the map, returns null.
|
||||
pub fn fetchRemove(self: *Self, key: Key) ?Value {
|
||||
const index = Indexer.indexOf(key);
|
||||
const result: ?Value = if (self.bits.isSet(index)) self.values[index] else null;
|
||||
self.bits.unset(index);
|
||||
self.values[index] = undefined;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Returns an iterator over the map, which visits items in index order.
|
||||
/// Modifications to the underlying map may or may not be observed by
|
||||
/// the iterator, but will not invalidate it.
|
||||
pub fn iterator(self: *Self) Iterator {
|
||||
return .{
|
||||
.inner = self.bits.iterator(.{}),
|
||||
.values = &self.values,
|
||||
};
|
||||
}
|
||||
|
||||
/// An entry in the map.
|
||||
pub const Entry = struct {
|
||||
/// The key associated with this entry.
|
||||
/// Modifying this key will not change the map.
|
||||
key: Key,
|
||||
|
||||
/// A pointer to the value in the map associated
|
||||
/// with this key. Modifications through this
|
||||
/// pointer will modify the underlying data.
|
||||
value: *Value,
|
||||
};
|
||||
|
||||
pub const Iterator = struct {
|
||||
inner: BitSet.Iterator(.{}),
|
||||
values: *[Indexer.count]Value,
|
||||
|
||||
pub fn next(self: *Iterator) ?Entry {
|
||||
return if (self.inner.next()) |index|
|
||||
Entry{
|
||||
.key = Indexer.keyForIndex(index),
|
||||
.value = &self.values[index],
|
||||
}
|
||||
else
|
||||
null;
|
||||
}
|
||||
};
|
||||
};
|
||||
return IndexedMap(EnumIndexer(E), V, mixin.EnumMapExt);
|
||||
}
|
||||
|
||||
/// A multiset of enum elements up to a count of usize. Backed
|
||||
@@ -724,197 +1024,98 @@ test EnumMultiset {
|
||||
/// enum values to dense indices. This type does no dynamic
|
||||
/// allocation and can be copied by value.
|
||||
pub fn EnumArray(comptime E: type, comptime V: type) type {
|
||||
const mixin = struct {
|
||||
fn EnumArrayExt(comptime Self: type) type {
|
||||
const Indexer = Self.Indexer;
|
||||
return struct {
|
||||
/// Initializes all values in the enum array
|
||||
pub fn init(init_values: EnumFieldStruct(E, V, @as(?V, null))) Self {
|
||||
return initDefault(@as(?V, null), init_values);
|
||||
}
|
||||
|
||||
/// Initializes values in the enum array, with the specified default.
|
||||
pub fn initDefault(comptime default: ?V, init_values: EnumFieldStruct(E, V, default)) Self {
|
||||
var result = Self{ .values = undefined };
|
||||
comptime var i: usize = 0;
|
||||
inline while (i < Self.len) : (i += 1) {
|
||||
const key = comptime Indexer.keyForIndex(i);
|
||||
const tag = @tagName(key);
|
||||
result.values[i] = @field(init_values, tag);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
return IndexedArray(EnumIndexer(E), V, mixin.EnumArrayExt);
|
||||
}
|
||||
|
||||
fn NoExtension(comptime Self: type) type {
|
||||
_ = Self;
|
||||
return NoExt;
|
||||
}
|
||||
const NoExt = struct {};
|
||||
|
||||
/// A set type with an Indexer mapping from keys to indices.
|
||||
/// Presence or absence is stored as a dense bitfield. This
|
||||
/// type does no allocation and can be copied by value.
|
||||
pub fn IndexedSet(comptime I: type, comptime Ext: ?fn (type) type) type {
|
||||
comptime ensureIndexer(I);
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
pub usingnamespace (Ext orelse NoExtension)(Self);
|
||||
|
||||
/// The indexing rules for converting between keys and indices.
|
||||
pub const Indexer = I;
|
||||
/// The element type for this set.
|
||||
/// The index mapping for this map
|
||||
pub const Indexer = EnumIndexer(E);
|
||||
/// The key type used to index this map
|
||||
pub const Key = Indexer.Key;
|
||||
|
||||
const BitSet = std.StaticBitSet(Indexer.count);
|
||||
|
||||
/// The maximum number of items in this set.
|
||||
/// The value type stored in this map
|
||||
pub const Value = V;
|
||||
/// The number of possible keys in the map
|
||||
pub const len = Indexer.count;
|
||||
|
||||
bits: BitSet = BitSet.initEmpty(),
|
||||
values: [Indexer.count]Value,
|
||||
|
||||
/// Returns a set containing no keys.
|
||||
pub fn initEmpty() Self {
|
||||
return .{ .bits = BitSet.initEmpty() };
|
||||
pub fn init(init_values: EnumFieldStruct(E, Value, null)) Self {
|
||||
return initDefault(null, init_values);
|
||||
}
|
||||
|
||||
/// Returns a set containing all possible keys.
|
||||
pub fn initFull() Self {
|
||||
return .{ .bits = BitSet.initFull() };
|
||||
/// Initializes values in the enum array, with the specified default.
|
||||
pub fn initDefault(comptime default: ?Value, init_values: EnumFieldStruct(E, Value, default)) Self {
|
||||
var result: Self = .{ .values = undefined };
|
||||
inline for (0..Self.len) |i| {
|
||||
const key = comptime Indexer.keyForIndex(i);
|
||||
const tag = @tagName(key);
|
||||
result.values[i] = @field(init_values, tag);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Returns a set containing multiple keys.
|
||||
pub fn initMany(keys: []const Key) Self {
|
||||
var set = initEmpty();
|
||||
for (keys) |key| set.insert(key);
|
||||
return set;
|
||||
pub fn initUndefined() Self {
|
||||
return Self{ .values = undefined };
|
||||
}
|
||||
|
||||
/// Returns a set containing a single key.
|
||||
pub fn initOne(key: Key) Self {
|
||||
return initMany(&[_]Key{key});
|
||||
pub fn initFill(v: Value) Self {
|
||||
var self: Self = undefined;
|
||||
@memset(&self.values, v);
|
||||
return self;
|
||||
}
|
||||
|
||||
/// Returns the number of keys in the set.
|
||||
pub fn count(self: Self) usize {
|
||||
return self.bits.count();
|
||||
/// Returns the value in the array associated with a key.
|
||||
pub fn get(self: Self, key: Key) Value {
|
||||
return self.values[Indexer.indexOf(key)];
|
||||
}
|
||||
|
||||
/// Checks if a key is in the set.
|
||||
pub fn contains(self: Self, key: Key) bool {
|
||||
return self.bits.isSet(Indexer.indexOf(key));
|
||||
/// Returns a pointer to the slot in the array associated with a key.
|
||||
pub fn getPtr(self: *Self, key: Key) *Value {
|
||||
return &self.values[Indexer.indexOf(key)];
|
||||
}
|
||||
|
||||
/// Puts a key in the set.
|
||||
pub fn insert(self: *Self, key: Key) void {
|
||||
self.bits.set(Indexer.indexOf(key));
|
||||
/// Returns a const pointer to the slot in the array associated with a key.
|
||||
pub fn getPtrConst(self: *const Self, key: Key) *const Value {
|
||||
return &self.values[Indexer.indexOf(key)];
|
||||
}
|
||||
|
||||
/// Removes a key from the set.
|
||||
pub fn remove(self: *Self, key: Key) void {
|
||||
self.bits.unset(Indexer.indexOf(key));
|
||||
/// Sets the value in the slot associated with a key.
|
||||
pub fn set(self: *Self, key: Key, value: Value) void {
|
||||
self.values[Indexer.indexOf(key)] = value;
|
||||
}
|
||||
|
||||
/// Changes the presence of a key in the set to match the passed bool.
|
||||
pub fn setPresent(self: *Self, key: Key, present: bool) void {
|
||||
self.bits.setValue(Indexer.indexOf(key), present);
|
||||
/// Iterates over the items in the array, in index order.
|
||||
pub fn iterator(self: *Self) Iterator {
|
||||
return .{
|
||||
.values = &self.values,
|
||||
};
|
||||
}
|
||||
|
||||
/// Toggles the presence of a key in the set. If the key is in
|
||||
/// the set, removes it. Otherwise adds it.
|
||||
pub fn toggle(self: *Self, key: Key) void {
|
||||
self.bits.toggle(Indexer.indexOf(key));
|
||||
}
|
||||
/// An entry in the array.
|
||||
pub const Entry = struct {
|
||||
/// The key associated with this entry.
|
||||
/// Modifying this key will not change the array.
|
||||
key: Key,
|
||||
|
||||
/// Toggles the presence of all keys in the passed set.
|
||||
pub fn toggleSet(self: *Self, other: Self) void {
|
||||
self.bits.toggleSet(other.bits);
|
||||
}
|
||||
|
||||
/// Toggles all possible keys in the set.
|
||||
pub fn toggleAll(self: *Self) void {
|
||||
self.bits.toggleAll();
|
||||
}
|
||||
|
||||
/// Adds all keys in the passed set to this set.
|
||||
pub fn setUnion(self: *Self, other: Self) void {
|
||||
self.bits.setUnion(other.bits);
|
||||
}
|
||||
|
||||
/// Removes all keys which are not in the passed set.
|
||||
pub fn setIntersection(self: *Self, other: Self) void {
|
||||
self.bits.setIntersection(other.bits);
|
||||
}
|
||||
|
||||
/// Returns true iff both sets have the same keys.
|
||||
pub fn eql(self: Self, other: Self) bool {
|
||||
return self.bits.eql(other.bits);
|
||||
}
|
||||
|
||||
/// Returns true iff all the keys in this set are
|
||||
/// in the other set. The other set may have keys
|
||||
/// not found in this set.
|
||||
pub fn subsetOf(self: Self, other: Self) bool {
|
||||
return self.bits.subsetOf(other.bits);
|
||||
}
|
||||
|
||||
/// Returns true iff this set contains all the keys
|
||||
/// in the other set. This set may have keys not
|
||||
/// found in the other set.
|
||||
pub fn supersetOf(self: Self, other: Self) bool {
|
||||
return self.bits.supersetOf(other.bits);
|
||||
}
|
||||
|
||||
/// Returns a set with all the keys not in this set.
|
||||
pub fn complement(self: Self) Self {
|
||||
return .{ .bits = self.bits.complement() };
|
||||
}
|
||||
|
||||
/// Returns a set with keys that are in either this
|
||||
/// set or the other set.
|
||||
pub fn unionWith(self: Self, other: Self) Self {
|
||||
return .{ .bits = self.bits.unionWith(other.bits) };
|
||||
}
|
||||
|
||||
/// Returns a set with keys that are in both this
|
||||
/// set and the other set.
|
||||
pub fn intersectWith(self: Self, other: Self) Self {
|
||||
return .{ .bits = self.bits.intersectWith(other.bits) };
|
||||
}
|
||||
|
||||
/// Returns a set with keys that are in either this
|
||||
/// set or the other set, but not both.
|
||||
pub fn xorWith(self: Self, other: Self) Self {
|
||||
return .{ .bits = self.bits.xorWith(other.bits) };
|
||||
}
|
||||
|
||||
/// Returns a set with keys that are in this set
|
||||
/// except for keys in the other set.
|
||||
pub fn differenceWith(self: Self, other: Self) Self {
|
||||
return .{ .bits = self.bits.differenceWith(other.bits) };
|
||||
}
|
||||
|
||||
/// Returns an iterator over this set, which iterates in
|
||||
/// index order. Modifications to the set during iteration
|
||||
/// may or may not be observed by the iterator, but will
|
||||
/// not invalidate it.
|
||||
pub fn iterator(self: *const Self) Iterator {
|
||||
return .{ .inner = self.bits.iterator(.{}) };
|
||||
}
|
||||
/// A pointer to the value in the array associated
|
||||
/// with this key. Modifications through this
|
||||
/// pointer will modify the underlying data.
|
||||
value: *Value,
|
||||
};
|
||||
|
||||
pub const Iterator = struct {
|
||||
inner: BitSet.Iterator(.{}),
|
||||
index: usize = 0,
|
||||
values: *[Indexer.count]Value,
|
||||
|
||||
pub fn next(self: *Iterator) ?Key {
|
||||
return if (self.inner.next()) |index|
|
||||
Indexer.keyForIndex(index)
|
||||
else
|
||||
null;
|
||||
pub fn next(self: *Iterator) ?Entry {
|
||||
const index = self.index;
|
||||
if (index < Indexer.count) {
|
||||
self.index += 1;
|
||||
return Entry{
|
||||
.key = Indexer.keyForIndex(index),
|
||||
.value = &self.values[index],
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -1012,305 +1213,6 @@ test "EnumSet const iterator" {
|
||||
try testing.expect(result.eql(diag_move));
|
||||
}
|
||||
|
||||
/// A map from keys to values, using an index lookup. Uses a
|
||||
/// bitfield to track presence and a dense array of values.
|
||||
/// This type does no allocation and can be copied by value.
|
||||
pub fn IndexedMap(comptime I: type, comptime V: type, comptime Ext: ?fn (type) type) type {
|
||||
comptime ensureIndexer(I);
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
pub usingnamespace (Ext orelse NoExtension)(Self);
|
||||
|
||||
/// The index mapping for this map
|
||||
pub const Indexer = I;
|
||||
/// The key type used to index this map
|
||||
pub const Key = Indexer.Key;
|
||||
/// The value type stored in this map
|
||||
pub const Value = V;
|
||||
/// The number of possible keys in the map
|
||||
pub const len = Indexer.count;
|
||||
|
||||
const BitSet = std.StaticBitSet(Indexer.count);
|
||||
|
||||
/// Bits determining whether items are in the map
|
||||
bits: BitSet = BitSet.initEmpty(),
|
||||
/// Values of items in the map. If the associated
|
||||
/// bit is zero, the value is undefined.
|
||||
values: [Indexer.count]Value = undefined,
|
||||
|
||||
/// The number of items in the map.
|
||||
pub fn count(self: Self) usize {
|
||||
return self.bits.count();
|
||||
}
|
||||
|
||||
/// Checks if the map contains an item.
|
||||
pub fn contains(self: Self, key: Key) bool {
|
||||
return self.bits.isSet(Indexer.indexOf(key));
|
||||
}
|
||||
|
||||
/// Gets the value associated with a key.
|
||||
/// If the key is not in the map, returns null.
|
||||
pub fn get(self: Self, key: Key) ?Value {
|
||||
const index = Indexer.indexOf(key);
|
||||
return if (self.bits.isSet(index)) self.values[index] else null;
|
||||
}
|
||||
|
||||
/// Gets the value associated with a key, which must
|
||||
/// exist in the map.
|
||||
pub fn getAssertContains(self: Self, key: Key) Value {
|
||||
const index = Indexer.indexOf(key);
|
||||
assert(self.bits.isSet(index));
|
||||
return self.values[index];
|
||||
}
|
||||
|
||||
/// Gets the address of the value associated with a key.
|
||||
/// If the key is not in the map, returns null.
|
||||
pub fn getPtr(self: *Self, key: Key) ?*Value {
|
||||
const index = Indexer.indexOf(key);
|
||||
return if (self.bits.isSet(index)) &self.values[index] else null;
|
||||
}
|
||||
|
||||
/// Gets the address of the const value associated with a key.
|
||||
/// If the key is not in the map, returns null.
|
||||
pub fn getPtrConst(self: *const Self, key: Key) ?*const Value {
|
||||
const index = Indexer.indexOf(key);
|
||||
return if (self.bits.isSet(index)) &self.values[index] else null;
|
||||
}
|
||||
|
||||
/// Gets the address of the value associated with a key.
|
||||
/// The key must be present in the map.
|
||||
pub fn getPtrAssertContains(self: *Self, key: Key) *Value {
|
||||
const index = Indexer.indexOf(key);
|
||||
assert(self.bits.isSet(index));
|
||||
return &self.values[index];
|
||||
}
|
||||
|
||||
/// Gets the address of the const value associated with a key.
|
||||
/// The key must be present in the map.
|
||||
pub fn getPtrConstAssertContains(self: *const Self, key: Key) *const Value {
|
||||
const index = Indexer.indexOf(key);
|
||||
assert(self.bits.isSet(index));
|
||||
return &self.values[index];
|
||||
}
|
||||
|
||||
/// Adds the key to the map with the supplied value.
|
||||
/// If the key is already in the map, overwrites the value.
|
||||
pub fn put(self: *Self, key: Key, value: Value) void {
|
||||
const index = Indexer.indexOf(key);
|
||||
self.bits.set(index);
|
||||
self.values[index] = value;
|
||||
}
|
||||
|
||||
/// Adds the key to the map with an undefined value.
|
||||
/// If the key is already in the map, the value becomes undefined.
|
||||
/// A pointer to the value is returned, which should be
|
||||
/// used to initialize the value.
|
||||
pub fn putUninitialized(self: *Self, key: Key) *Value {
|
||||
const index = Indexer.indexOf(key);
|
||||
self.bits.set(index);
|
||||
self.values[index] = undefined;
|
||||
return &self.values[index];
|
||||
}
|
||||
|
||||
/// Sets the value associated with the key in the map,
|
||||
/// and returns the old value. If the key was not in
|
||||
/// the map, returns null.
|
||||
pub fn fetchPut(self: *Self, key: Key, value: Value) ?Value {
|
||||
const index = Indexer.indexOf(key);
|
||||
const result: ?Value = if (self.bits.isSet(index)) self.values[index] else null;
|
||||
self.bits.set(index);
|
||||
self.values[index] = value;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Removes a key from the map. If the key was not in the map,
|
||||
/// does nothing.
|
||||
pub fn remove(self: *Self, key: Key) void {
|
||||
const index = Indexer.indexOf(key);
|
||||
self.bits.unset(index);
|
||||
self.values[index] = undefined;
|
||||
}
|
||||
|
||||
/// Removes a key from the map, and returns the old value.
|
||||
/// If the key was not in the map, returns null.
|
||||
pub fn fetchRemove(self: *Self, key: Key) ?Value {
|
||||
const index = Indexer.indexOf(key);
|
||||
const result: ?Value = if (self.bits.isSet(index)) self.values[index] else null;
|
||||
self.bits.unset(index);
|
||||
self.values[index] = undefined;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Returns an iterator over the map, which visits items in index order.
|
||||
/// Modifications to the underlying map may or may not be observed by
|
||||
/// the iterator, but will not invalidate it.
|
||||
pub fn iterator(self: *Self) Iterator {
|
||||
return .{
|
||||
.inner = self.bits.iterator(.{}),
|
||||
.values = &self.values,
|
||||
};
|
||||
}
|
||||
|
||||
/// An entry in the map.
|
||||
pub const Entry = struct {
|
||||
/// The key associated with this entry.
|
||||
/// Modifying this key will not change the map.
|
||||
key: Key,
|
||||
|
||||
/// A pointer to the value in the map associated
|
||||
/// with this key. Modifications through this
|
||||
/// pointer will modify the underlying data.
|
||||
value: *Value,
|
||||
};
|
||||
|
||||
pub const Iterator = struct {
|
||||
inner: BitSet.Iterator(.{}),
|
||||
values: *[Indexer.count]Value,
|
||||
|
||||
pub fn next(self: *Iterator) ?Entry {
|
||||
return if (self.inner.next()) |index|
|
||||
Entry{
|
||||
.key = Indexer.keyForIndex(index),
|
||||
.value = &self.values[index],
|
||||
}
|
||||
else
|
||||
null;
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/// A dense array of values, using an indexed lookup.
|
||||
/// This type does no allocation and can be copied by value.
|
||||
pub fn IndexedArray(comptime I: type, comptime V: type, comptime Ext: ?fn (type) type) type {
|
||||
comptime ensureIndexer(I);
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
pub usingnamespace (Ext orelse NoExtension)(Self);
|
||||
|
||||
/// The index mapping for this map
|
||||
pub const Indexer = I;
|
||||
/// The key type used to index this map
|
||||
pub const Key = Indexer.Key;
|
||||
/// The value type stored in this map
|
||||
pub const Value = V;
|
||||
/// The number of possible keys in the map
|
||||
pub const len = Indexer.count;
|
||||
|
||||
values: [Indexer.count]Value,
|
||||
|
||||
pub fn initUndefined() Self {
|
||||
return Self{ .values = undefined };
|
||||
}
|
||||
|
||||
pub fn initFill(v: Value) Self {
|
||||
var self: Self = undefined;
|
||||
@memset(&self.values, v);
|
||||
return self;
|
||||
}
|
||||
|
||||
/// Returns the value in the array associated with a key.
|
||||
pub fn get(self: Self, key: Key) Value {
|
||||
return self.values[Indexer.indexOf(key)];
|
||||
}
|
||||
|
||||
/// Returns a pointer to the slot in the array associated with a key.
|
||||
pub fn getPtr(self: *Self, key: Key) *Value {
|
||||
return &self.values[Indexer.indexOf(key)];
|
||||
}
|
||||
|
||||
/// Returns a const pointer to the slot in the array associated with a key.
|
||||
pub fn getPtrConst(self: *const Self, key: Key) *const Value {
|
||||
return &self.values[Indexer.indexOf(key)];
|
||||
}
|
||||
|
||||
/// Sets the value in the slot associated with a key.
|
||||
pub fn set(self: *Self, key: Key, value: Value) void {
|
||||
self.values[Indexer.indexOf(key)] = value;
|
||||
}
|
||||
|
||||
/// Iterates over the items in the array, in index order.
|
||||
pub fn iterator(self: *Self) Iterator {
|
||||
return .{
|
||||
.values = &self.values,
|
||||
};
|
||||
}
|
||||
|
||||
/// An entry in the array.
|
||||
pub const Entry = struct {
|
||||
/// The key associated with this entry.
|
||||
/// Modifying this key will not change the array.
|
||||
key: Key,
|
||||
|
||||
/// A pointer to the value in the array associated
|
||||
/// with this key. Modifications through this
|
||||
/// pointer will modify the underlying data.
|
||||
value: *Value,
|
||||
};
|
||||
|
||||
pub const Iterator = struct {
|
||||
index: usize = 0,
|
||||
values: *[Indexer.count]Value,
|
||||
|
||||
pub fn next(self: *Iterator) ?Entry {
|
||||
const index = self.index;
|
||||
if (index < Indexer.count) {
|
||||
self.index += 1;
|
||||
return Entry{
|
||||
.key = Indexer.keyForIndex(index),
|
||||
.value = &self.values[index],
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/// Verifies that a type is a valid Indexer, providing a helpful
|
||||
/// compile error if not. An Indexer maps a comptime-known set
|
||||
/// of keys to a dense set of zero-based indices.
|
||||
/// The indexer interface must look like this:
|
||||
/// ```
|
||||
/// struct {
|
||||
/// /// The key type which this indexer converts to indices
|
||||
/// pub const Key: type,
|
||||
/// /// The number of indexes in the dense mapping
|
||||
/// pub const count: comptime_int,
|
||||
/// /// Converts from a key to an index
|
||||
/// pub fn indexOf(Key) usize;
|
||||
/// /// Converts from an index to a key
|
||||
/// pub fn keyForIndex(usize) Key;
|
||||
/// }
|
||||
/// ```
|
||||
pub fn ensureIndexer(comptime T: type) void {
|
||||
comptime {
|
||||
if (!@hasDecl(T, "Key")) @compileError("Indexer must have decl Key: type.");
|
||||
if (@TypeOf(T.Key) != type) @compileError("Indexer.Key must be a type.");
|
||||
if (!@hasDecl(T, "count")) @compileError("Indexer must have decl count: comptime_int.");
|
||||
if (@TypeOf(T.count) != comptime_int) @compileError("Indexer.count must be a comptime_int.");
|
||||
if (!@hasDecl(T, "indexOf")) @compileError("Indexer.indexOf must be a fn (Key) usize.");
|
||||
if (@TypeOf(T.indexOf) != fn (T.Key) usize) @compileError("Indexer must have decl indexOf: fn (Key) usize.");
|
||||
if (!@hasDecl(T, "keyForIndex")) @compileError("Indexer must have decl keyForIndex: fn (usize) Key.");
|
||||
if (@TypeOf(T.keyForIndex) != fn (usize) T.Key) @compileError("Indexer.keyForIndex must be a fn (usize) Key.");
|
||||
}
|
||||
}
|
||||
|
||||
test ensureIndexer {
|
||||
ensureIndexer(struct {
|
||||
pub const Key = u32;
|
||||
pub const count: comptime_int = 8;
|
||||
pub fn indexOf(k: Key) usize {
|
||||
return @as(usize, @intCast(k));
|
||||
}
|
||||
pub fn keyForIndex(index: usize) Key {
|
||||
return @as(Key, @intCast(index));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn EnumIndexer(comptime E: type) type {
|
||||
if (!@typeInfo(E).Enum.is_exhaustive) {
|
||||
const BackingInt = @typeInfo(E).Enum.tag_type;
|
||||
@@ -1438,7 +1340,6 @@ test "EnumIndexer non-exhaustive" {
|
||||
_,
|
||||
};
|
||||
const Indexer = EnumIndexer(E);
|
||||
ensureIndexer(Indexer);
|
||||
|
||||
const min_tag: E = @enumFromInt(std.math.minInt(BackingInt));
|
||||
const max_tag: E = @enumFromInt(std.math.maxInt(BackingInt));
|
||||
@@ -1466,7 +1367,6 @@ test "EnumIndexer non-exhaustive" {
|
||||
test "EnumIndexer dense zeroed" {
|
||||
const E = enum(u2) { b = 1, a = 0, c = 2 };
|
||||
const Indexer = EnumIndexer(E);
|
||||
ensureIndexer(Indexer);
|
||||
try testing.expectEqual(E, Indexer.Key);
|
||||
try testing.expectEqual(3, Indexer.count);
|
||||
|
||||
@@ -1482,7 +1382,6 @@ test "EnumIndexer dense zeroed" {
|
||||
test "EnumIndexer dense positive" {
|
||||
const E = enum(u4) { c = 6, a = 4, b = 5 };
|
||||
const Indexer = EnumIndexer(E);
|
||||
ensureIndexer(Indexer);
|
||||
try testing.expectEqual(E, Indexer.Key);
|
||||
try testing.expectEqual(3, Indexer.count);
|
||||
|
||||
@@ -1498,7 +1397,6 @@ test "EnumIndexer dense positive" {
|
||||
test "EnumIndexer dense negative" {
|
||||
const E = enum(i4) { a = -6, c = -4, b = -5 };
|
||||
const Indexer = EnumIndexer(E);
|
||||
ensureIndexer(Indexer);
|
||||
try testing.expectEqual(E, Indexer.Key);
|
||||
try testing.expectEqual(3, Indexer.count);
|
||||
|
||||
@@ -1514,7 +1412,6 @@ test "EnumIndexer dense negative" {
|
||||
test "EnumIndexer sparse" {
|
||||
const E = enum(i4) { a = -2, c = 6, b = 4 };
|
||||
const Indexer = EnumIndexer(E);
|
||||
ensureIndexer(Indexer);
|
||||
try testing.expectEqual(E, Indexer.Key);
|
||||
try testing.expectEqual(3, Indexer.count);
|
||||
|
||||
@@ -1530,7 +1427,6 @@ test "EnumIndexer sparse" {
|
||||
test "EnumIndexer empty" {
|
||||
const E = enum {};
|
||||
const Indexer = EnumIndexer(E);
|
||||
ensureIndexer(Indexer);
|
||||
try testing.expectEqual(E, Indexer.Key);
|
||||
try testing.expectEqual(0, Indexer.count);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user