authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-05 21:12:20+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-07-05 21:12:20+00:00
log289eab9177443bdfadfe750afda8f7f32f43be0f
treeddf557298d623e567aefe9a7ace46b0ad63b9a1f
parent0ae1157e4553d6f54e0d489daebb006c402e0f63
parent3a89f214aa672c5844def1704845ad38ea60bdcd
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #5786 from ziglang/std-hash-map

reimplement std.HashMap

16 files changed, 985 insertions(+), 563 deletions(-)

doc/docgen.zig+1-1
......@@ -392,7 +392,7 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
392392 .n = header_stack_size,
393393 },
394394 });
395 if (try urls.put(urlized, tag_token)) |entry| {
395 if (try urls.fetchPut(urlized, tag_token)) |entry| {
396396 parseError(tokenizer, tag_token, "duplicate header url: #{}", .{urlized}) catch {};
397397 parseError(tokenizer, entry.value, "other tag here", .{}) catch {};
398398 return error.ParseError;
doc/langref.html.in+3-11
......@@ -5363,11 +5363,11 @@ const std = @import("std");
53635363const assert = std.debug.assert;
53645364
53655365test "turn HashMap into a set with void" {
5366 var map = std.HashMap(i32, void, hash_i32, eql_i32).init(std.testing.allocator);
5366 var map = std.AutoHashMap(i32, void).init(std.testing.allocator);
53675367 defer map.deinit();
53685368
5369 _ = try map.put(1, {});
5370 _ = try map.put(2, {});
5369 try map.put(1, {});
5370 try map.put(2, {});
53715371
53725372 assert(map.contains(2));
53735373 assert(!map.contains(3));
......@@ -5375,14 +5375,6 @@ test "turn HashMap into a set with void" {
53755375 _ = map.remove(2);
53765376 assert(!map.contains(2));
53775377}
5378
5379fn hash_i32(x: i32) u32 {
5380 return @bitCast(u32, x);
5381}
5382
5383fn eql_i32(a: i32, b: i32) bool {
5384 return a == b;
5385}
53865378 {#code_end#}
53875379 <p>Note that this is different from using a dummy value for the hash map value.
53885380 By using {#syntax#}void{#endsyntax#} as the type of the value, the hash map entry type has no value field, and
lib/std/array_list.zig+16
......@@ -210,6 +210,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
210210 self.capacity = new_len;
211211 }
212212
213 /// Reduce length to `new_len`.
214 /// Invalidates element pointers.
215 /// Keeps capacity the same.
216 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
217 assert(new_len <= self.items.len);
218 self.items.len = new_len;
219 }
220
213221 pub fn ensureCapacity(self: *Self, new_capacity: usize) !void {
214222 var better_capacity = self.capacity;
215223 if (better_capacity >= new_capacity) return;
......@@ -432,6 +440,14 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
432440 self.capacity = new_len;
433441 }
434442
443 /// Reduce length to `new_len`.
444 /// Invalidates element pointers.
445 /// Keeps capacity the same.
446 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
447 assert(new_len <= self.items.len);
448 self.items.len = new_len;
449 }
450
435451 pub fn ensureCapacity(self: *Self, allocator: *Allocator, new_capacity: usize) !void {
436452 var better_capacity = self.capacity;
437453 if (better_capacity >= new_capacity) return;
lib/std/buf_map.zig+7-8
......@@ -33,10 +33,10 @@ pub const BufMap = struct {
3333 pub fn setMove(self: *BufMap, key: []u8, value: []u8) !void {
3434 const get_or_put = try self.hash_map.getOrPut(key);
3535 if (get_or_put.found_existing) {
36 self.free(get_or_put.kv.key);
37 get_or_put.kv.key = key;
36 self.free(get_or_put.entry.key);
37 get_or_put.entry.key = key;
3838 }
39 get_or_put.kv.value = value;
39 get_or_put.entry.value = value;
4040 }
4141
4242 /// `key` and `value` are copied into the BufMap.
......@@ -45,19 +45,18 @@ pub const BufMap = struct {
4545 errdefer self.free(value_copy);
4646 const get_or_put = try self.hash_map.getOrPut(key);
4747 if (get_or_put.found_existing) {
48 self.free(get_or_put.kv.value);
48 self.free(get_or_put.entry.value);
4949 } else {
50 get_or_put.kv.key = self.copy(key) catch |err| {
50 get_or_put.entry.key = self.copy(key) catch |err| {
5151 _ = self.hash_map.remove(key);
5252 return err;
5353 };
5454 }
55 get_or_put.kv.value = value_copy;
55 get_or_put.entry.value = value_copy;
5656 }
5757
5858 pub fn get(self: BufMap, key: []const u8) ?[]const u8 {
59 const entry = self.hash_map.get(key) orelse return null;
60 return entry.value;
59 return self.hash_map.get(key);
6160 }
6261
6362 pub fn delete(self: *BufMap, key: []const u8) void {
lib/std/buf_set.zig+3-5
......@@ -14,14 +14,12 @@ pub const BufSet = struct {
1414 return self;
1515 }
1616
17 pub fn deinit(self: *const BufSet) void {
18 var it = self.hash_map.iterator();
19 while (true) {
20 const entry = it.next() orelse break;
17 pub fn deinit(self: *BufSet) void {
18 for (self.hash_map.items()) |entry| {
2119 self.free(entry.key);
2220 }
23
2421 self.hash_map.deinit();
22 self.* = undefined;
2523 }
2624
2725 pub fn put(self: *BufSet, key: []const u8) !void {
lib/std/build.zig+6-6
......@@ -422,12 +422,12 @@ pub const Builder = struct {
422422 .type_id = type_id,
423423 .description = description,
424424 };
425 if ((self.available_options_map.put(name, available_option) catch unreachable) != null) {
425 if ((self.available_options_map.fetchPut(name, available_option) catch unreachable) != null) {
426426 panic("Option '{}' declared twice", .{name});
427427 }
428428 self.available_options_list.append(available_option) catch unreachable;
429429
430 const entry = self.user_input_options.get(name) orelse return null;
430 const entry = self.user_input_options.getEntry(name) orelse return null;
431431 entry.value.used = true;
432432 switch (type_id) {
433433 TypeId.Bool => switch (entry.value.value) {
......@@ -634,7 +634,7 @@ pub const Builder = struct {
634634 pub fn addUserInputOption(self: *Builder, name: []const u8, value: []const u8) !bool {
635635 const gop = try self.user_input_options.getOrPut(name);
636636 if (!gop.found_existing) {
637 gop.kv.value = UserInputOption{
637 gop.entry.value = UserInputOption{
638638 .name = name,
639639 .value = UserValue{ .Scalar = value },
640640 .used = false,
......@@ -643,7 +643,7 @@ pub const Builder = struct {
643643 }
644644
645645 // option already exists
646 switch (gop.kv.value.value) {
646 switch (gop.entry.value.value) {
647647 UserValue.Scalar => |s| {
648648 // turn it into a list
649649 var list = ArrayList([]const u8).init(self.allocator);
......@@ -675,7 +675,7 @@ pub const Builder = struct {
675675 pub fn addUserInputFlag(self: *Builder, name: []const u8) !bool {
676676 const gop = try self.user_input_options.getOrPut(name);
677677 if (!gop.found_existing) {
678 gop.kv.value = UserInputOption{
678 gop.entry.value = UserInputOption{
679679 .name = name,
680680 .value = UserValue{ .Flag = {} },
681681 .used = false,
......@@ -684,7 +684,7 @@ pub const Builder = struct {
684684 }
685685
686686 // option already exists
687 switch (gop.kv.value.value) {
687 switch (gop.entry.value.value) {
688688 UserValue.Scalar => |s| {
689689 warn("Flag '-D{}' conflicts with option '-D{}={}'.\n", .{ name, name, s });
690690 return true;
lib/std/debug.zig+4-4
......@@ -1132,7 +1132,7 @@ pub const DebugInfo = struct {
11321132 const seg_end = seg_start + segment_cmd.vmsize;
11331133
11341134 if (rebased_address >= seg_start and rebased_address < seg_end) {
1135 if (self.address_map.getValue(base_address)) |obj_di| {
1135 if (self.address_map.get(base_address)) |obj_di| {
11361136 return obj_di;
11371137 }
11381138
......@@ -1204,7 +1204,7 @@ pub const DebugInfo = struct {
12041204 const seg_end = seg_start + info.SizeOfImage;
12051205
12061206 if (address >= seg_start and address < seg_end) {
1207 if (self.address_map.getValue(seg_start)) |obj_di| {
1207 if (self.address_map.get(seg_start)) |obj_di| {
12081208 return obj_di;
12091209 }
12101210
......@@ -1278,7 +1278,7 @@ pub const DebugInfo = struct {
12781278 else => return error.MissingDebugInfo,
12791279 }
12801280
1281 if (self.address_map.getValue(ctx.base_address)) |obj_di| {
1281 if (self.address_map.get(ctx.base_address)) |obj_di| {
12821282 return obj_di;
12831283 }
12841284
......@@ -1441,7 +1441,7 @@ pub const ModuleDebugInfo = switch (builtin.os.tag) {
14411441 const o_file_path = mem.spanZ(self.strings[symbol.ofile.?.n_strx..]);
14421442
14431443 // Check if its debug infos are already in the cache
1444 var o_file_di = self.ofiles.getValue(o_file_path) orelse
1444 var o_file_di = self.ofiles.get(o_file_path) orelse
14451445 (self.loadOFile(o_file_path) catch |err| switch (err) {
14461446 error.FileNotFound,
14471447 error.MissingDebugInfo,
lib/std/hash_map.zig+763-310
......@@ -9,17 +9,15 @@ const autoHash = std.hash.autoHash;
99const Wyhash = std.hash.Wyhash;
1010const Allocator = mem.Allocator;
1111const builtin = @import("builtin");
12
13const want_modification_safety = std.debug.runtime_safety;
14const debug_u32 = if (want_modification_safety) u32 else void;
12const hash_map = @This();
1513
1614pub fn AutoHashMap(comptime K: type, comptime V: type) type {
17 return HashMap(K, V, getAutoHashFn(K), getAutoEqlFn(K));
15 return HashMap(K, V, getAutoHashFn(K), getAutoEqlFn(K), autoEqlIsCheap(K));
1816}
1917
2018/// Builtin hashmap for strings as keys.
2119pub fn StringHashMap(comptime V: type) type {
22 return HashMap([]const u8, V, hashString, eqlString);
20 return HashMap([]const u8, V, hashString, eqlString, true);
2321}
2422
2523pub fn eqlString(a: []const u8, b: []const u8) bool {
......@@ -30,422 +28,859 @@ pub fn hashString(s: []const u8) u32 {
3028 return @truncate(u32, std.hash.Wyhash.hash(0, s));
3129}
3230
33pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u32, comptime eql: fn (a: K, b: K) bool) type {
31/// Insertion order is preserved.
32/// Deletions perform a "swap removal" on the entries list.
33/// Modifying the hash map while iterating is allowed, however one must understand
34/// the (well defined) behavior when mixing insertions and deletions with iteration.
35/// For a hash map that can be initialized directly that does not store an Allocator
36/// field, see `HashMapUnmanaged`.
37/// When `store_hash` is `false`, this data structure is biased towards cheap `eql`
38/// functions. It does not store each item's hash in the table. Setting `store_hash`
39/// to `true` incurs slightly more memory cost by storing each key's hash in the table
40/// but only has to call `eql` for hash collisions.
41pub fn HashMap(
42 comptime K: type,
43 comptime V: type,
44 comptime hash: fn (key: K) u32,
45 comptime eql: fn (a: K, b: K) bool,
46 comptime store_hash: bool,
47) type {
3448 return struct {
35 entries: []Entry,
36 size: usize,
37 max_distance_from_start_index: usize,
49 unmanaged: Unmanaged,
3850 allocator: *Allocator,
3951
40 /// This is used to detect bugs where a hashtable is edited while an iterator is running.
41 modification_count: debug_u32,
42
43 const Self = @This();
44
45 /// A *KV is a mutable pointer into this HashMap's internal storage.
46 /// Modifying the key is undefined behavior.
47 /// Modifying the value is harmless.
48 /// *KV pointers become invalid whenever this HashMap is modified,
49 /// and then any access to the *KV is undefined behavior.
50 pub const KV = struct {
51 key: K,
52 value: V,
53 };
54
55 const Entry = struct {
56 used: bool,
57 distance_from_start_index: usize,
58 kv: KV,
59 };
60
61 pub const GetOrPutResult = struct {
62 kv: *KV,
63 found_existing: bool,
64 };
52 pub const Unmanaged = HashMapUnmanaged(K, V, hash, eql, store_hash);
53 pub const Entry = Unmanaged.Entry;
54 pub const Hash = Unmanaged.Hash;
55 pub const GetOrPutResult = Unmanaged.GetOrPutResult;
6556
57 /// Deprecated. Iterate using `items`.
6658 pub const Iterator = struct {
6759 hm: *const Self,
68 // how many items have we returned
69 count: usize,
70 // iterator through the entry array
60 /// Iterator through the entry array.
7161 index: usize,
72 // used to detect concurrent modification
73 initial_modification_count: debug_u32,
7462
75 pub fn next(it: *Iterator) ?*KV {
76 if (want_modification_safety) {
77 assert(it.initial_modification_count == it.hm.modification_count); // concurrent modification
78 }
79 if (it.count >= it.hm.size) return null;
80 while (it.index < it.hm.entries.len) : (it.index += 1) {
81 const entry = &it.hm.entries[it.index];
82 if (entry.used) {
83 it.index += 1;
84 it.count += 1;
85 return &entry.kv;
86 }
87 }
88 unreachable; // no next item
63 pub fn next(it: *Iterator) ?*Entry {
64 if (it.index >= it.hm.unmanaged.entries.items.len) return null;
65 const result = &it.hm.unmanaged.entries.items[it.index];
66 it.index += 1;
67 return result;
8968 }
9069
91 // Reset the iterator to the initial index
70 /// Reset the iterator to the initial index
9271 pub fn reset(it: *Iterator) void {
93 it.count = 0;
9472 it.index = 0;
95 // Resetting the modification count too
96 it.initial_modification_count = it.hm.modification_count;
9773 }
9874 };
9975
76 const Self = @This();
77 const Index = Unmanaged.Index;
78
10079 pub fn init(allocator: *Allocator) Self {
101 return Self{
102 .entries = &[_]Entry{},
80 return .{
81 .unmanaged = .{},
10382 .allocator = allocator,
104 .size = 0,
105 .max_distance_from_start_index = 0,
106 .modification_count = if (want_modification_safety) 0 else {},
10783 };
10884 }
10985
110 pub fn deinit(hm: Self) void {
111 hm.allocator.free(hm.entries);
86 pub fn deinit(self: *Self) void {
87 self.unmanaged.deinit(self.allocator);
88 self.* = undefined;
11289 }
11390
114 pub fn clear(hm: *Self) void {
115 for (hm.entries) |*entry| {
116 entry.used = false;
117 }
118 hm.size = 0;
119 hm.max_distance_from_start_index = 0;
120 hm.incrementModificationCount();
91 pub fn clearRetainingCapacity(self: *Self) void {
92 return self.unmanaged.clearRetainingCapacity();
12193 }
12294
95 pub fn clearAndFree(self: *Self, allocator: *Allocator) void {
96 return self.unmanaged.clearAndFree(self.allocator);
97 }
98
99 /// Deprecated. Use `items().len`.
123100 pub fn count(self: Self) usize {
124 return self.size;
101 return self.items().len;
102 }
103
104 /// Deprecated. Iterate using `items`.
105 pub fn iterator(self: *const Self) Iterator {
106 return Iterator{
107 .hm = self,
108 .index = 0,
109 };
125110 }
126111
127112 /// If key exists this function cannot fail.
128113 /// If there is an existing item with `key`, then the result
129 /// kv pointer points to it, and found_existing is true.
114 /// `Entry` pointer points to it, and found_existing is true.
130115 /// Otherwise, puts a new item with undefined value, and
131 /// the kv pointer points to it. Caller should then initialize
132 /// the data.
116 /// the `Entry` pointer points to it. Caller should then initialize
117 /// the value (but not the key).
133118 pub fn getOrPut(self: *Self, key: K) !GetOrPutResult {
134 // TODO this implementation can be improved - we should only
135 // have to hash once and find the entry once.
136 if (self.get(key)) |kv| {
137 return GetOrPutResult{
138 .kv = kv,
139 .found_existing = true,
140 };
141 }
142 self.incrementModificationCount();
143 try self.autoCapacity();
144 const put_result = self.internalPut(key);
145 assert(put_result.old_kv == null);
146 return GetOrPutResult{
147 .kv = &put_result.new_entry.kv,
148 .found_existing = false,
149 };
119 return self.unmanaged.getOrPut(self.allocator, key);
150120 }
151121
152 pub fn getOrPutValue(self: *Self, key: K, value: V) !*KV {
153 const res = try self.getOrPut(key);
154 if (!res.found_existing)
155 res.kv.value = value;
122 /// If there is an existing item with `key`, then the result
123 /// `Entry` pointer points to it, and found_existing is true.
124 /// Otherwise, puts a new item with undefined value, and
125 /// the `Entry` pointer points to it. Caller should then initialize
126 /// the value (but not the key).
127 /// If a new entry needs to be stored, this function asserts there
128 /// is enough capacity to store it.
129 pub fn getOrPutAssumeCapacity(self: *Self, key: K) GetOrPutResult {
130 return self.unmanaged.getOrPutAssumeCapacity(key);
131 }
132
133 pub fn getOrPutValue(self: *Self, key: K, value: V) !*Entry {
134 return self.unmanaged.getOrPutValue(self.allocator, key, value);
135 }
136
137 /// Increases capacity, guaranteeing that insertions up until the
138 /// `expected_count` will not cause an allocation, and therefore cannot fail.
139 pub fn ensureCapacity(self: *Self, new_capacity: usize) !void {
140 return self.unmanaged.ensureCapacity(self.allocator, new_capacity);
141 }
142
143 /// Returns the number of total elements which may be present before it is
144 /// no longer guaranteed that no allocations will be performed.
145 pub fn capacity(self: *Self) usize {
146 return self.unmanaged.capacity();
147 }
148
149 /// Clobbers any existing data. To detect if a put would clobber
150 /// existing data, see `getOrPut`.
151 pub fn put(self: *Self, key: K, value: V) !void {
152 return self.unmanaged.put(self.allocator, key, value);
153 }
154
155 /// Inserts a key-value pair into the hash map, asserting that no previous
156 /// entry with the same key is already present
157 pub fn putNoClobber(self: *Self, key: K, value: V) !void {
158 return self.unmanaged.putNoClobber(self.allocator, key, value);
159 }
160
161 /// Asserts there is enough capacity to store the new key-value pair.
162 /// Clobbers any existing data. To detect if a put would clobber
163 /// existing data, see `getOrPutAssumeCapacity`.
164 pub fn putAssumeCapacity(self: *Self, key: K, value: V) void {
165 return self.unmanaged.putAssumeCapacity(key, value);
166 }
167
168 /// Asserts there is enough capacity to store the new key-value pair.
169 /// Asserts that it does not clobber any existing data.
170 /// To detect if a put would clobber existing data, see `getOrPutAssumeCapacity`.
171 pub fn putAssumeCapacityNoClobber(self: *Self, key: K, value: V) void {
172 return self.unmanaged.putAssumeCapacityNoClobber(key, value);
173 }
174
175 /// Inserts a new `Entry` into the hash map, returning the previous one, if any.
176 pub fn fetchPut(self: *Self, key: K, value: V) !?Entry {
177 return self.unmanaged.fetchPut(self.allocator, key, value);
178 }
179
180 /// Inserts a new `Entry` into the hash map, returning the previous one, if any.
181 /// If insertion happuns, asserts there is enough capacity without allocating.
182 pub fn fetchPutAssumeCapacity(self: *Self, key: K, value: V) ?Entry {
183 return self.unmanaged.fetchPutAssumeCapacity(key, value);
184 }
185
186 pub fn getEntry(self: Self, key: K) ?*Entry {
187 return self.unmanaged.getEntry(key);
188 }
189
190 pub fn get(self: Self, key: K) ?V {
191 return self.unmanaged.get(key);
192 }
156193
157 return res.kv;
194 pub fn contains(self: Self, key: K) bool {
195 return self.unmanaged.contains(key);
158196 }
159197
160 fn optimizedCapacity(expected_count: usize) usize {
161 // ensure that the hash map will be at most 60% full if
162 // expected_count items are put into it
163 var optimized_capacity = expected_count * 5 / 3;
164 // an overflow here would mean the amount of memory required would not
165 // be representable in the address space
166 return math.ceilPowerOfTwo(usize, optimized_capacity) catch unreachable;
198 /// If there is an `Entry` with a matching key, it is deleted from
199 /// the hash map, and then returned from this function.
200 pub fn remove(self: *Self, key: K) ?Entry {
201 return self.unmanaged.remove(key);
167202 }
168203
169 /// Increases capacity so that the hash map will be at most
170 /// 60% full when expected_count items are put into it
171 pub fn ensureCapacity(self: *Self, expected_count: usize) !void {
172 if (expected_count == 0) return;
173 const optimized_capacity = optimizedCapacity(expected_count);
174 return self.ensureCapacityExact(optimized_capacity);
204 /// Asserts there is an `Entry` with matching key, deletes it from the hash map,
205 /// and discards it.
206 pub fn removeAssertDiscard(self: *Self, key: K) void {
207 return self.unmanaged.removeAssertDiscard(key);
175208 }
176209
177 /// Sets the capacity to the new capacity if the new
178 /// capacity is greater than the current capacity.
179 /// New capacity must be a power of two.
180 fn ensureCapacityExact(self: *Self, new_capacity: usize) !void {
181 // capacity must always be a power of two to allow for modulo
182 // optimization in the constrainIndex fn
183 assert(math.isPowerOfTwo(new_capacity));
210 pub fn items(self: Self) []Entry {
211 return self.unmanaged.items();
212 }
213
214 pub fn clone(self: Self) !Self {
215 var other = try self.unmanaged.clone(self.allocator);
216 return other.promote(self.allocator);
217 }
218 };
219}
220
221/// General purpose hash table.
222/// Insertion order is preserved.
223/// Deletions perform a "swap removal" on the entries list.
224/// Modifying the hash map while iterating is allowed, however one must understand
225/// the (well defined) behavior when mixing insertions and deletions with iteration.
226/// This type does not store an Allocator field - the Allocator must be passed in
227/// with each function call that requires it. See `HashMap` for a type that stores
228/// an Allocator field for convenience.
229/// Can be initialized directly using the default field values.
230/// This type is designed to have low overhead for small numbers of entries. When
231/// `store_hash` is `false` and the number of entries in the map is less than 9,
232/// the overhead cost of using `HashMapUnmanaged` rather than `std.ArrayList` is
233/// only a single pointer-sized integer.
234/// When `store_hash` is `false`, this data structure is biased towards cheap `eql`
235/// functions. It does not store each item's hash in the table. Setting `store_hash`
236/// to `true` incurs slightly more memory cost by storing each key's hash in the table
237/// but guarantees only one call to `eql` per insertion/deletion.
238pub fn HashMapUnmanaged(
239 comptime K: type,
240 comptime V: type,
241 comptime hash: fn (key: K) u32,
242 comptime eql: fn (a: K, b: K) bool,
243 comptime store_hash: bool,
244) type {
245 return struct {
246 /// It is permitted to access this field directly.
247 entries: std.ArrayListUnmanaged(Entry) = .{},
248
249 /// When entries length is less than `linear_scan_max`, this remains `null`.
250 /// Once entries length grows big enough, this field is allocated. There is
251 /// an IndexHeader followed by an array of Index(I) structs, where I is defined
252 /// by how many total indexes there are.
253 index_header: ?*IndexHeader = null,
254
255 /// Modifying the key is illegal behavior.
256 /// Modifying the value is allowed.
257 /// Entry pointers become invalid whenever this HashMap is modified,
258 /// unless `ensureCapacity` was previously used.
259 pub const Entry = struct {
260 /// This field is `void` if `store_hash` is `false`.
261 hash: Hash,
262 key: K,
263 value: V,
264 };
265
266 pub const Hash = if (store_hash) u32 else void;
267
268 pub const GetOrPutResult = struct {
269 entry: *Entry,
270 found_existing: bool,
271 };
272
273 pub const Managed = HashMap(K, V, hash, eql, store_hash);
274
275 const Self = @This();
276
277 const linear_scan_max = 8;
184278
185 if (new_capacity <= self.entries.len) {
186 return;
279 pub fn promote(self: Self, allocator: *Allocator) Managed {
280 return .{
281 .unmanaged = self,
282 .allocator = allocator,
283 };
284 }
285
286 pub fn deinit(self: *Self, allocator: *Allocator) void {
287 self.entries.deinit(allocator);
288 if (self.index_header) |header| {
289 header.free(allocator);
187290 }
291 self.* = undefined;
292 }
293
294 pub fn clearRetainingCapacity(self: *Self) void {
295 self.entries.items.len = 0;
296 if (self.index_header) |header| {
297 header.max_distance_from_start_index = 0;
298 switch (header.capacityIndexType()) {
299 .u8 => mem.set(Index(u8), header.indexes(u8), Index(u8).empty),
300 .u16 => mem.set(Index(u16), header.indexes(u16), Index(u16).empty),
301 .u32 => mem.set(Index(u32), header.indexes(u32), Index(u32).empty),
302 .usize => mem.set(Index(usize), header.indexes(usize), Index(usize).empty),
303 }
304 }
305 }
306
307 pub fn clearAndFree(self: *Self, allocator: *Allocator) void {
308 self.entries.shrink(allocator, 0);
309 if (self.index_header) |header| {
310 header.free(allocator);
311 self.index_header = null;
312 }
313 }
314
315 /// If key exists this function cannot fail.
316 /// If there is an existing item with `key`, then the result
317 /// `Entry` pointer points to it, and found_existing is true.
318 /// Otherwise, puts a new item with undefined value, and
319 /// the `Entry` pointer points to it. Caller should then initialize
320 /// the value (but not the key).
321 pub fn getOrPut(self: *Self, allocator: *Allocator, key: K) !GetOrPutResult {
322 self.ensureCapacity(allocator, self.entries.items.len + 1) catch |err| {
323 // "If key exists this function cannot fail."
324 return GetOrPutResult{
325 .entry = self.getEntry(key) orelse return err,
326 .found_existing = true,
327 };
328 };
329 return self.getOrPutAssumeCapacity(key);
330 }
188331
189 const old_entries = self.entries;
190 try self.initCapacity(new_capacity);
191 self.incrementModificationCount();
192 if (old_entries.len > 0) {
193 // dump all of the old elements into the new table
194 for (old_entries) |*old_entry| {
195 if (old_entry.used) {
196 self.internalPut(old_entry.kv.key).new_entry.kv.value = old_entry.kv.value;
332 /// If there is an existing item with `key`, then the result
333 /// `Entry` pointer points to it, and found_existing is true.
334 /// Otherwise, puts a new item with undefined value, and
335 /// the `Entry` pointer points to it. Caller should then initialize
336 /// the value (but not the key).
337 /// If a new entry needs to be stored, this function asserts there
338 /// is enough capacity to store it.
339 pub fn getOrPutAssumeCapacity(self: *Self, key: K) GetOrPutResult {
340 const header = self.index_header orelse {
341 // Linear scan.
342 const h = if (store_hash) hash(key) else {};
343 for (self.entries.items) |*item| {
344 if (item.hash == h and eql(key, item.key)) {
345 return GetOrPutResult{
346 .entry = item,
347 .found_existing = true,
348 };
197349 }
198350 }
199 self.allocator.free(old_entries);
351 const new_entry = self.entries.addOneAssumeCapacity();
352 new_entry.* = .{
353 .hash = if (store_hash) h else {},
354 .key = key,
355 .value = undefined,
356 };
357 return GetOrPutResult{
358 .entry = new_entry,
359 .found_existing = false,
360 };
361 };
362
363 switch (header.capacityIndexType()) {
364 .u8 => return self.getOrPutInternal(key, header, u8),
365 .u16 => return self.getOrPutInternal(key, header, u16),
366 .u32 => return self.getOrPutInternal(key, header, u32),
367 .usize => return self.getOrPutInternal(key, header, usize),
368 }
369 }
370
371 pub fn getOrPutValue(self: *Self, allocator: *Allocator, key: K, value: V) !*Entry {
372 const res = try self.getOrPut(allocator, key);
373 if (!res.found_existing)
374 res.entry.value = value;
375
376 return res.entry;
377 }
378
379 /// Increases capacity, guaranteeing that insertions up until the
380 /// `expected_count` will not cause an allocation, and therefore cannot fail.
381 pub fn ensureCapacity(self: *Self, allocator: *Allocator, new_capacity: usize) !void {
382 try self.entries.ensureCapacity(allocator, new_capacity);
383 if (new_capacity <= linear_scan_max) return;
384
385 // Ensure that the indexes will be at most 60% full if
386 // `new_capacity` items are put into it.
387 const needed_len = new_capacity * 5 / 3;
388 if (self.index_header) |header| {
389 if (needed_len > header.indexes_len) {
390 // An overflow here would mean the amount of memory required would not
391 // be representable in the address space.
392 const new_indexes_len = math.ceilPowerOfTwo(usize, needed_len) catch unreachable;
393 const new_header = try IndexHeader.alloc(allocator, new_indexes_len);
394 self.insertAllEntriesIntoNewHeader(new_header);
395 header.free(allocator);
396 self.index_header = new_header;
397 }
398 } else {
399 // An overflow here would mean the amount of memory required would not
400 // be representable in the address space.
401 const new_indexes_len = math.ceilPowerOfTwo(usize, needed_len) catch unreachable;
402 const header = try IndexHeader.alloc(allocator, new_indexes_len);
403 self.insertAllEntriesIntoNewHeader(header);
404 self.index_header = header;
200405 }
201406 }
202407
203 /// Returns the kv pair that was already there.
204 pub fn put(self: *Self, key: K, value: V) !?KV {
205 try self.autoCapacity();
206 return putAssumeCapacity(self, key, value);
408 /// Returns the number of total elements which may be present before it is
409 /// no longer guaranteed that no allocations will be performed.
410 pub fn capacity(self: Self) usize {
411 const entry_cap = self.entries.capacity;
412 const header = self.index_header orelse return math.min(linear_scan_max, entry_cap);
413 const indexes_cap = (header.indexes_len + 1) * 3 / 4;
414 return math.min(entry_cap, indexes_cap);
207415 }
208416
209 /// Calls put() and asserts that no kv pair is clobbered.
210 pub fn putNoClobber(self: *Self, key: K, value: V) !void {
211 assert((try self.put(key, value)) == null);
417 /// Clobbers any existing data. To detect if a put would clobber
418 /// existing data, see `getOrPut`.
419 pub fn put(self: *Self, allocator: *Allocator, key: K, value: V) !void {
420 const result = try self.getOrPut(allocator, key);
421 result.entry.value = value;
212422 }
213423
214 pub fn putAssumeCapacity(self: *Self, key: K, value: V) ?KV {
215 assert(self.count() < self.entries.len);
216 self.incrementModificationCount();
424 /// Inserts a key-value pair into the hash map, asserting that no previous
425 /// entry with the same key is already present
426 pub fn putNoClobber(self: *Self, allocator: *Allocator, key: K, value: V) !void {
427 const result = try self.getOrPut(allocator, key);
428 assert(!result.found_existing);
429 result.entry.value = value;
430 }
217431
218 const put_result = self.internalPut(key);
219 put_result.new_entry.kv.value = value;
220 return put_result.old_kv;
432 /// Asserts there is enough capacity to store the new key-value pair.
433 /// Clobbers any existing data. To detect if a put would clobber
434 /// existing data, see `getOrPutAssumeCapacity`.
435 pub fn putAssumeCapacity(self: *Self, key: K, value: V) void {
436 const result = self.getOrPutAssumeCapacity(key);
437 result.entry.value = value;
221438 }
222439
440 /// Asserts there is enough capacity to store the new key-value pair.
441 /// Asserts that it does not clobber any existing data.
442 /// To detect if a put would clobber existing data, see `getOrPutAssumeCapacity`.
223443 pub fn putAssumeCapacityNoClobber(self: *Self, key: K, value: V) void {
224 assert(self.putAssumeCapacity(key, value) == null);
444 const result = self.getOrPutAssumeCapacity(key);
445 assert(!result.found_existing);
446 result.entry.value = value;
225447 }
226448
227 pub fn get(hm: *const Self, key: K) ?*KV {
228 if (hm.entries.len == 0) {
449 /// Inserts a new `Entry` into the hash map, returning the previous one, if any.
450 pub fn fetchPut(self: *Self, allocator: *Allocator, key: K, value: V) !?Entry {
451 const gop = try self.getOrPut(allocator, key);
452 var result: ?Entry = null;
453 if (gop.found_existing) {
454 result = gop.entry.*;
455 }
456 gop.entry.value = value;
457 return result;
458 }
459
460 /// Inserts a new `Entry` into the hash map, returning the previous one, if any.
461 /// If insertion happens, asserts there is enough capacity without allocating.
462 pub fn fetchPutAssumeCapacity(self: *Self, key: K, value: V) ?Entry {
463 const gop = self.getOrPutAssumeCapacity(key);
464 var result: ?Entry = null;
465 if (gop.found_existing) {
466 result = gop.entry.*;
467 }
468 gop.entry.value = value;
469 return result;
470 }
471
472 pub fn getEntry(self: Self, key: K) ?*Entry {
473 const header = self.index_header orelse {
474 // Linear scan.
475 const h = if (store_hash) hash(key) else {};
476 for (self.entries.items) |*item| {
477 if (item.hash == h and eql(key, item.key)) {
478 return item;
479 }
480 }
229481 return null;
482 };
483
484 switch (header.capacityIndexType()) {
485 .u8 => return self.getInternal(key, header, u8),
486 .u16 => return self.getInternal(key, header, u16),
487 .u32 => return self.getInternal(key, header, u32),
488 .usize => return self.getInternal(key, header, usize),
230489 }
231 return hm.internalGet(key);
232490 }
233491
234 pub fn getValue(hm: *const Self, key: K) ?V {
235 return if (hm.get(key)) |kv| kv.value else null;
492 pub fn get(self: Self, key: K) ?V {
493 return if (self.getEntry(key)) |entry| entry.value else null;
236494 }
237495
238 pub fn contains(hm: *const Self, key: K) bool {
239 return hm.get(key) != null;
496 pub fn contains(self: Self, key: K) bool {
497 return self.getEntry(key) != null;
240498 }
241499
242 /// Returns any kv pair that was removed.
243 pub fn remove(hm: *Self, key: K) ?KV {
244 if (hm.entries.len == 0) return null;
245 hm.incrementModificationCount();
246 const start_index = hm.keyToIndex(key);
247 {
248 var roll_over: usize = 0;
249 while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
250 const index = hm.constrainIndex(start_index + roll_over);
251 var entry = &hm.entries[index];
252
253 if (!entry.used) return null;
254
255 if (!eql(entry.kv.key, key)) continue;
256
257 const removed_kv = entry.kv;
258 while (roll_over < hm.entries.len) : (roll_over += 1) {
259 const next_index = hm.constrainIndex(start_index + roll_over + 1);
260 const next_entry = &hm.entries[next_index];
261 if (!next_entry.used or next_entry.distance_from_start_index == 0) {
262 entry.used = false;
263 hm.size -= 1;
264 return removed_kv;
265 }
266 entry.* = next_entry.*;
267 entry.distance_from_start_index -= 1;
268 entry = next_entry;
500 /// If there is an `Entry` with a matching key, it is deleted from
501 /// the hash map, and then returned from this function.
502 pub fn remove(self: *Self, key: K) ?Entry {
503 const header = self.index_header orelse {
504 // Linear scan.
505 const h = if (store_hash) hash(key) else {};
506 for (self.entries.items) |item, i| {
507 if (item.hash == h and eql(key, item.key)) {
508 return self.entries.swapRemove(i);
269509 }
270 unreachable; // shifting everything in the table
271510 }
511 return null;
512 };
513 switch (header.capacityIndexType()) {
514 .u8 => return self.removeInternal(key, header, u8),
515 .u16 => return self.removeInternal(key, header, u16),
516 .u32 => return self.removeInternal(key, header, u32),
517 .usize => return self.removeInternal(key, header, usize),
272518 }
273 return null;
274519 }
275520
276 /// Calls remove(), asserts that a kv pair is removed, and discards it.
277 pub fn removeAssertDiscard(hm: *Self, key: K) void {
278 assert(hm.remove(key) != null);
521 /// Asserts there is an `Entry` with matching key, deletes it from the hash map,
522 /// and discards it.
523 pub fn removeAssertDiscard(self: *Self, key: K) void {
524 assert(self.remove(key) != null);
279525 }
280526
281 pub fn iterator(hm: *const Self) Iterator {
282 return Iterator{
283 .hm = hm,
284 .count = 0,
285 .index = 0,
286 .initial_modification_count = hm.modification_count,
287 };
527 pub fn items(self: Self) []Entry {
528 return self.entries.items;
288529 }
289530
290 pub fn clone(self: Self) !Self {
291 var other = Self.init(self.allocator);
292 try other.initCapacity(self.entries.len);
293 var it = self.iterator();
294 while (it.next()) |entry| {
295 try other.putNoClobber(entry.key, entry.value);
531 pub fn clone(self: Self, allocator: *Allocator) !Self {
532 // TODO this can be made more efficient by directly allocating
533 // the memory slices and memcpying the elements.
534 var other = Self.init();
535 try other.initCapacity(allocator, self.entries.len);
536 for (self.entries.items) |entry| {
537 other.putAssumeCapacityNoClobber(entry.key, entry.value);
296538 }
297539 return other;
298540 }
299541
300 fn autoCapacity(self: *Self) !void {
301 if (self.entries.len == 0) {
302 return self.ensureCapacityExact(16);
303 }
304 // if we get too full (60%), double the capacity
305 if (self.size * 5 >= self.entries.len * 3) {
306 return self.ensureCapacityExact(self.entries.len * 2);
307 }
308 }
542 fn removeInternal(self: *Self, key: K, header: *IndexHeader, comptime I: type) ?Entry {
543 const indexes = header.indexes(I);
544 const h = hash(key);
545 const start_index = header.constrainIndex(h);
546 var roll_over: usize = 0;
547 while (roll_over <= header.max_distance_from_start_index) : (roll_over += 1) {
548 const index_index = header.constrainIndex(start_index + roll_over);
549 var index = &indexes[index_index];
550 if (index.isEmpty())
551 return null;
552
553 const entry = &self.entries.items[index.entry_index];
554
555 const hash_match = if (store_hash) h == entry.hash else true;
556 if (!hash_match or !eql(key, entry.key))
557 continue;
558
559 const removed_entry = self.entries.swapRemove(index.entry_index);
560 if (self.entries.items.len > 0 and self.entries.items.len != index.entry_index) {
561 // Because of the swap remove, now we need to update the index that was
562 // pointing to the last entry and is now pointing to this removed item slot.
563 self.updateEntryIndex(header, self.entries.items.len, index.entry_index, I, indexes);
564 }
309565
310 fn initCapacity(hm: *Self, capacity: usize) !void {
311 hm.entries = try hm.allocator.alloc(Entry, capacity);
312 hm.size = 0;
313 hm.max_distance_from_start_index = 0;
314 for (hm.entries) |*entry| {
315 entry.used = false;
566 // Now we have to shift over the following indexes.
567 roll_over += 1;
568 while (roll_over < header.indexes_len) : (roll_over += 1) {
569 const next_index_index = header.constrainIndex(start_index + roll_over);
570 const next_index = &indexes[next_index_index];
571 if (next_index.isEmpty() or next_index.distance_from_start_index == 0) {
572 index.setEmpty();
573 return removed_entry;
574 }
575 index.* = next_index.*;
576 index.distance_from_start_index -= 1;
577 index = next_index;
578 }
579 unreachable;
316580 }
581 return null;
317582 }
318583
319 fn incrementModificationCount(hm: *Self) void {
320 if (want_modification_safety) {
321 hm.modification_count +%= 1;
584 fn updateEntryIndex(
585 self: *Self,
586 header: *IndexHeader,
587 old_entry_index: usize,
588 new_entry_index: usize,
589 comptime I: type,
590 indexes: []Index(I),
591 ) void {
592 const h = if (store_hash) self.entries.items[new_entry_index].hash else hash(self.entries.items[new_entry_index].key);
593 const start_index = header.constrainIndex(h);
594 var roll_over: usize = 0;
595 while (roll_over <= header.max_distance_from_start_index) : (roll_over += 1) {
596 const index_index = header.constrainIndex(start_index + roll_over);
597 const index = &indexes[index_index];
598 if (index.entry_index == old_entry_index) {
599 index.entry_index = @intCast(I, new_entry_index);
600 return;
601 }
322602 }
603 unreachable;
323604 }
324605
325 const InternalPutResult = struct {
326 new_entry: *Entry,
327 old_kv: ?KV,
328 };
329
330 /// Returns a pointer to the new entry.
331 /// Asserts that there is enough space for the new item.
332 fn internalPut(self: *Self, orig_key: K) InternalPutResult {
333 var key = orig_key;
334 var value: V = undefined;
335 const start_index = self.keyToIndex(key);
606 /// Must ensureCapacity before calling this.
607 fn getOrPutInternal(self: *Self, key: K, header: *IndexHeader, comptime I: type) GetOrPutResult {
608 const indexes = header.indexes(I);
609 const h = hash(key);
610 const start_index = header.constrainIndex(h);
336611 var roll_over: usize = 0;
337612 var distance_from_start_index: usize = 0;
338 var got_result_entry = false;
339 var result = InternalPutResult{
340 .new_entry = undefined,
341 .old_kv = null,
342 };
343 while (roll_over < self.entries.len) : ({
613 while (roll_over <= header.indexes_len) : ({
344614 roll_over += 1;
345615 distance_from_start_index += 1;
346616 }) {
347 const index = self.constrainIndex(start_index + roll_over);
348 const entry = &self.entries[index];
349
350 if (entry.used and !eql(entry.kv.key, key)) {
351 if (entry.distance_from_start_index < distance_from_start_index) {
352 // robin hood to the rescue
353 const tmp = entry.*;
354 self.max_distance_from_start_index = math.max(self.max_distance_from_start_index, distance_from_start_index);
355 if (!got_result_entry) {
356 got_result_entry = true;
357 result.new_entry = entry;
617 const index_index = header.constrainIndex(start_index + roll_over);
618 const index = indexes[index_index];
619 if (index.isEmpty()) {
620 indexes[index_index] = .{
621 .distance_from_start_index = @intCast(I, distance_from_start_index),
622 .entry_index = @intCast(I, self.entries.items.len),
623 };
624 header.maybeBumpMax(distance_from_start_index);
625 const new_entry = self.entries.addOneAssumeCapacity();
626 new_entry.* = .{
627 .hash = if (store_hash) h else {},
628 .key = key,
629 .value = undefined,
630 };
631 return .{
632 .found_existing = false,
633 .entry = new_entry,
634 };
635 }
636
637 // This pointer survives the following append because we call
638 // entries.ensureCapacity before getOrPutInternal.
639 const entry = &self.entries.items[index.entry_index];
640 const hash_match = if (store_hash) h == entry.hash else true;
641 if (hash_match and eql(key, entry.key)) {
642 return .{
643 .found_existing = true,
644 .entry = entry,
645 };
646 }
647 if (index.distance_from_start_index < distance_from_start_index) {
648 // In this case, we did not find the item. We will put a new entry.
649 // However, we will use this index for the new entry, and move
650 // the previous index down the line, to keep the max_distance_from_start_index
651 // as small as possible.
652 indexes[index_index] = .{
653 .distance_from_start_index = @intCast(I, distance_from_start_index),
654 .entry_index = @intCast(I, self.entries.items.len),
655 };
656 header.maybeBumpMax(distance_from_start_index);
657 const new_entry = self.entries.addOneAssumeCapacity();
658 new_entry.* = .{
659 .hash = if (store_hash) h else {},
660 .key = key,
661 .value = undefined,
662 };
663
664 distance_from_start_index = index.distance_from_start_index;
665 var prev_entry_index = index.entry_index;
666
667 // Find somewhere to put the index we replaced by shifting
668 // following indexes backwards.
669 roll_over += 1;
670 distance_from_start_index += 1;
671 while (roll_over < header.indexes_len) : ({
672 roll_over += 1;
673 distance_from_start_index += 1;
674 }) {
675 const next_index_index = header.constrainIndex(start_index + roll_over);
676 const next_index = indexes[next_index_index];
677 if (next_index.isEmpty()) {
678 header.maybeBumpMax(distance_from_start_index);
679 indexes[next_index_index] = .{
680 .entry_index = prev_entry_index,
681 .distance_from_start_index = @intCast(I, distance_from_start_index),
682 };
683 return .{
684 .found_existing = false,
685 .entry = new_entry,
686 };
687 }
688 if (next_index.distance_from_start_index < distance_from_start_index) {
689 header.maybeBumpMax(distance_from_start_index);
690 indexes[next_index_index] = .{
691 .entry_index = prev_entry_index,
692 .distance_from_start_index = @intCast(I, distance_from_start_index),
693 };
694 distance_from_start_index = next_index.distance_from_start_index;
695 prev_entry_index = next_index.entry_index;
358696 }
359 entry.* = Entry{
360 .used = true,
361 .distance_from_start_index = distance_from_start_index,
362 .kv = KV{
363 .key = key,
364 .value = value,
365 },
366 };
367 key = tmp.kv.key;
368 value = tmp.kv.value;
369 distance_from_start_index = tmp.distance_from_start_index;
370697 }
371 continue;
698 unreachable;
372699 }
700 }
701 unreachable;
702 }
373703
374 if (entry.used) {
375 result.old_kv = entry.kv;
376 } else {
377 // adding an entry. otherwise overwriting old value with
378 // same key
379 self.size += 1;
380 }
704 fn getInternal(self: Self, key: K, header: *IndexHeader, comptime I: type) ?*Entry {
705 const indexes = header.indexes(I);
706 const h = hash(key);
707 const start_index = header.constrainIndex(h);
708 var roll_over: usize = 0;
709 while (roll_over <= header.max_distance_from_start_index) : (roll_over += 1) {
710 const index_index = header.constrainIndex(start_index + roll_over);
711 const index = indexes[index_index];
712 if (index.isEmpty())
713 return null;
714
715 const entry = &self.entries.items[index.entry_index];
716 const hash_match = if (store_hash) h == entry.hash else true;
717 if (hash_match and eql(key, entry.key))
718 return entry;
719 }
720 return null;
721 }
381722
382 self.max_distance_from_start_index = math.max(distance_from_start_index, self.max_distance_from_start_index);
383 if (!got_result_entry) {
384 result.new_entry = entry;
385 }
386 entry.* = Entry{
387 .used = true,
388 .distance_from_start_index = distance_from_start_index,
389 .kv = KV{
390 .key = key,
391 .value = value,
392 },
393 };
394 return result;
723 fn insertAllEntriesIntoNewHeader(self: *Self, header: *IndexHeader) void {
724 switch (header.capacityIndexType()) {
725 .u8 => return self.insertAllEntriesIntoNewHeaderGeneric(header, u8),
726 .u16 => return self.insertAllEntriesIntoNewHeaderGeneric(header, u16),
727 .u32 => return self.insertAllEntriesIntoNewHeaderGeneric(header, u32),
728 .usize => return self.insertAllEntriesIntoNewHeaderGeneric(header, usize),
395729 }
396 unreachable; // put into a full map
397730 }
398731
399 fn internalGet(hm: Self, key: K) ?*KV {
400 const start_index = hm.keyToIndex(key);
401 {
732 fn insertAllEntriesIntoNewHeaderGeneric(self: *Self, header: *IndexHeader, comptime I: type) void {
733 const indexes = header.indexes(I);
734 entry_loop: for (self.entries.items) |entry, i| {
735 const h = if (store_hash) entry.hash else hash(entry.key);
736 const start_index = header.constrainIndex(h);
737 var entry_index = i;
402738 var roll_over: usize = 0;
403 while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {
404 const index = hm.constrainIndex(start_index + roll_over);
405 const entry = &hm.entries[index];
406
407 if (!entry.used) return null;
408 if (eql(entry.kv.key, key)) return &entry.kv;
739 var distance_from_start_index: usize = 0;
740 while (roll_over < header.indexes_len) : ({
741 roll_over += 1;
742 distance_from_start_index += 1;
743 }) {
744 const index_index = header.constrainIndex(start_index + roll_over);
745 const next_index = indexes[index_index];
746 if (next_index.isEmpty()) {
747 header.maybeBumpMax(distance_from_start_index);
748 indexes[index_index] = .{
749 .distance_from_start_index = @intCast(I, distance_from_start_index),
750 .entry_index = @intCast(I, entry_index),
751 };
752 continue :entry_loop;
753 }
754 if (next_index.distance_from_start_index < distance_from_start_index) {
755 header.maybeBumpMax(distance_from_start_index);
756 indexes[index_index] = .{
757 .distance_from_start_index = @intCast(I, distance_from_start_index),
758 .entry_index = @intCast(I, entry_index),
759 };
760 distance_from_start_index = next_index.distance_from_start_index;
761 entry_index = next_index.entry_index;
762 }
409763 }
764 unreachable;
410765 }
411 return null;
412766 }
767 };
768}
769
770const CapacityIndexType = enum { u8, u16, u32, usize };
771
772fn capacityIndexType(indexes_len: usize) CapacityIndexType {
773 if (indexes_len < math.maxInt(u8))
774 return .u8;
775 if (indexes_len < math.maxInt(u16))
776 return .u16;
777 if (indexes_len < math.maxInt(u32))
778 return .u32;
779 return .usize;
780}
413781
414 fn keyToIndex(hm: Self, key: K) usize {
415 return hm.constrainIndex(@as(usize, hash(key)));
782fn capacityIndexSize(indexes_len: usize) usize {
783 switch (capacityIndexType(indexes_len)) {
784 .u8 => return @sizeOf(Index(u8)),
785 .u16 => return @sizeOf(Index(u16)),
786 .u32 => return @sizeOf(Index(u32)),
787 .usize => return @sizeOf(Index(usize)),
788 }
789}
790
791fn Index(comptime I: type) type {
792 return extern struct {
793 entry_index: I,
794 distance_from_start_index: I,
795
796 const Self = @This();
797
798 const empty = Self{
799 .entry_index = math.maxInt(I),
800 .distance_from_start_index = undefined,
801 };
802
803 fn isEmpty(idx: Self) bool {
804 return idx.entry_index == math.maxInt(I);
416805 }
417806
418 fn constrainIndex(hm: Self, i: usize) usize {
419 // this is an optimization for modulo of power of two integers;
420 // it requires hm.entries.len to always be a power of two
421 return i & (hm.entries.len - 1);
807 fn setEmpty(idx: *Self) void {
808 idx.entry_index = math.maxInt(I);
422809 }
423810 };
424811}
425812
813/// This struct is trailed by an array of `Index(I)`, where `I`
814/// and the array length are determined by `indexes_len`.
815const IndexHeader = struct {
816 max_distance_from_start_index: usize,
817 indexes_len: usize,
818
819 fn constrainIndex(header: IndexHeader, i: usize) usize {
820 // This is an optimization for modulo of power of two integers;
821 // it requires `indexes_len` to always be a power of two.
822 return i & (header.indexes_len - 1);
823 }
824
825 fn indexes(header: *IndexHeader, comptime I: type) []Index(I) {
826 const start = @ptrCast([*]Index(I), @ptrCast([*]u8, header) + @sizeOf(IndexHeader));
827 return start[0..header.indexes_len];
828 }
829
830 fn capacityIndexType(header: IndexHeader) CapacityIndexType {
831 return hash_map.capacityIndexType(header.indexes_len);
832 }
833
834 fn maybeBumpMax(header: *IndexHeader, distance_from_start_index: usize) void {
835 if (distance_from_start_index > header.max_distance_from_start_index) {
836 header.max_distance_from_start_index = distance_from_start_index;
837 }
838 }
839
840 fn alloc(allocator: *Allocator, len: usize) !*IndexHeader {
841 const index_size = hash_map.capacityIndexSize(len);
842 const nbytes = @sizeOf(IndexHeader) + index_size * len;
843 const bytes = try allocator.allocAdvanced(u8, @alignOf(IndexHeader), nbytes, .exact);
844 @memset(bytes.ptr + @sizeOf(IndexHeader), 0xff, bytes.len - @sizeOf(IndexHeader));
845 const result = @ptrCast(*IndexHeader, bytes.ptr);
846 result.* = .{
847 .max_distance_from_start_index = 0,
848 .indexes_len = len,
849 };
850 return result;
851 }
852
853 fn free(header: *IndexHeader, allocator: *Allocator) void {
854 const index_size = hash_map.capacityIndexSize(header.indexes_len);
855 const ptr = @ptrCast([*]u8, header);
856 const slice = ptr[0 .. @sizeOf(IndexHeader) + header.indexes_len * index_size];
857 allocator.free(slice);
858 }
859};
860
426861test "basic hash map usage" {
427862 var map = AutoHashMap(i32, i32).init(std.testing.allocator);
428863 defer map.deinit();
429864
430 testing.expect((try map.put(1, 11)) == null);
431 testing.expect((try map.put(2, 22)) == null);
432 testing.expect((try map.put(3, 33)) == null);
433 testing.expect((try map.put(4, 44)) == null);
865 testing.expect((try map.fetchPut(1, 11)) == null);
866 testing.expect((try map.fetchPut(2, 22)) == null);
867 testing.expect((try map.fetchPut(3, 33)) == null);
868 testing.expect((try map.fetchPut(4, 44)) == null);
434869
435870 try map.putNoClobber(5, 55);
436 testing.expect((try map.put(5, 66)).?.value == 55);
437 testing.expect((try map.put(5, 55)).?.value == 66);
871 testing.expect((try map.fetchPut(5, 66)).?.value == 55);
872 testing.expect((try map.fetchPut(5, 55)).?.value == 66);
438873
439874 const gop1 = try map.getOrPut(5);
440875 testing.expect(gop1.found_existing == true);
441 testing.expect(gop1.kv.value == 55);
442 gop1.kv.value = 77;
443 testing.expect(map.get(5).?.value == 77);
876 testing.expect(gop1.entry.value == 55);
877 gop1.entry.value = 77;
878 testing.expect(map.getEntry(5).?.value == 77);
444879
445880 const gop2 = try map.getOrPut(99);
446881 testing.expect(gop2.found_existing == false);
447 gop2.kv.value = 42;
448 testing.expect(map.get(99).?.value == 42);
882 gop2.entry.value = 42;
883 testing.expect(map.getEntry(99).?.value == 42);
449884
450885 const gop3 = try map.getOrPutValue(5, 5);
451886 testing.expect(gop3.value == 77);
......@@ -454,15 +889,15 @@ test "basic hash map usage" {
454889 testing.expect(gop4.value == 41);
455890
456891 testing.expect(map.contains(2));
457 testing.expect(map.get(2).?.value == 22);
458 testing.expect(map.getValue(2).? == 22);
892 testing.expect(map.getEntry(2).?.value == 22);
893 testing.expect(map.get(2).? == 22);
459894
460895 const rmv1 = map.remove(2);
461896 testing.expect(rmv1.?.key == 2);
462897 testing.expect(rmv1.?.value == 22);
463898 testing.expect(map.remove(2) == null);
899 testing.expect(map.getEntry(2) == null);
464900 testing.expect(map.get(2) == null);
465 testing.expect(map.getValue(2) == null);
466901
467902 map.removeAssertDiscard(3);
468903}
......@@ -498,8 +933,8 @@ test "iterator hash map" {
498933 it.reset();
499934
500935 var count: usize = 0;
501 while (it.next()) |kv| : (count += 1) {
502 buffer[@intCast(usize, kv.key)] = kv.value;
936 while (it.next()) |entry| : (count += 1) {
937 buffer[@intCast(usize, entry.key)] = entry.value;
503938 }
504939 testing.expect(count == 3);
505940 testing.expect(it.next() == null);
......@@ -510,8 +945,8 @@ test "iterator hash map" {
510945
511946 it.reset();
512947 count = 0;
513 while (it.next()) |kv| {
514 buffer[@intCast(usize, kv.key)] = kv.value;
948 while (it.next()) |entry| {
949 buffer[@intCast(usize, entry.key)] = entry.value;
515950 count += 1;
516951 if (count >= 2) break;
517952 }
......@@ -531,14 +966,14 @@ test "ensure capacity" {
531966 defer map.deinit();
532967
533968 try map.ensureCapacity(20);
534 const initialCapacity = map.entries.len;
535 testing.expect(initialCapacity >= 20);
969 const initial_capacity = map.capacity();
970 testing.expect(initial_capacity >= 20);
536971 var i: i32 = 0;
537972 while (i < 20) : (i += 1) {
538 testing.expect(map.putAssumeCapacity(i, i + 10) == null);
973 testing.expect(map.fetchPutAssumeCapacity(i, i + 10) == null);
539974 }
540975 // shouldn't resize from putAssumeCapacity
541 testing.expect(initialCapacity == map.entries.len);
976 testing.expect(initial_capacity == map.capacity());
542977}
543978
544979pub fn getHashPtrAddrFn(comptime K: type) (fn (K) u32) {
......@@ -575,6 +1010,24 @@ pub fn getAutoEqlFn(comptime K: type) (fn (K, K) bool) {
5751010 }.eql;
5761011}
5771012
1013pub fn autoEqlIsCheap(comptime K: type) bool {
1014 return switch (@typeInfo(K)) {
1015 .Bool,
1016 .Int,
1017 .Float,
1018 .Pointer,
1019 .ComptimeFloat,
1020 .ComptimeInt,
1021 .Enum,
1022 .Fn,
1023 .ErrorSet,
1024 .AnyFrame,
1025 .EnumLiteral,
1026 => true,
1027 else => false,
1028 };
1029}
1030
5781031pub fn getAutoHashStratFn(comptime K: type, comptime strategy: std.hash.Strategy) (fn (K) u32) {
5791032 return struct {
5801033 fn hash(key: K) u32 {
lib/std/http/headers.zig+35-37
......@@ -118,13 +118,12 @@ pub const Headers = struct {
118118 };
119119 }
120120
121 pub fn deinit(self: Self) void {
121 pub fn deinit(self: *Self) void {
122122 {
123 var it = self.index.iterator();
124 while (it.next()) |kv| {
125 var dex = &kv.value;
123 for (self.index.items()) |*entry| {
124 const dex = &entry.value;
126125 dex.deinit();
127 self.allocator.free(kv.key);
126 self.allocator.free(entry.key);
128127 }
129128 self.index.deinit();
130129 }
......@@ -134,6 +133,7 @@ pub const Headers = struct {
134133 }
135134 self.data.deinit();
136135 }
136 self.* = undefined;
137137 }
138138
139139 pub fn clone(self: Self, allocator: *Allocator) !Self {
......@@ -155,10 +155,10 @@ pub const Headers = struct {
155155 const n = self.data.items.len + 1;
156156 try self.data.ensureCapacity(n);
157157 var entry: HeaderEntry = undefined;
158 if (self.index.get(name)) |kv| {
158 if (self.index.getEntry(name)) |kv| {
159159 entry = try HeaderEntry.init(self.allocator, kv.key, value, never_index);
160160 errdefer entry.deinit();
161 var dex = &kv.value;
161 const dex = &kv.value;
162162 try dex.append(n - 1);
163163 } else {
164164 const name_dup = try self.allocator.dupe(u8, name);
......@@ -195,7 +195,7 @@ pub const Headers = struct {
195195 /// Returns boolean indicating if something was deleted.
196196 pub fn delete(self: *Self, name: []const u8) bool {
197197 if (self.index.remove(name)) |kv| {
198 var dex = &kv.value;
198 const dex = &kv.value;
199199 // iterate backwards
200200 var i = dex.items.len;
201201 while (i > 0) {
......@@ -207,7 +207,7 @@ pub const Headers = struct {
207207 }
208208 dex.deinit();
209209 self.allocator.free(kv.key);
210 self.rebuild_index();
210 self.rebuildIndex();
211211 return true;
212212 } else {
213213 return false;
......@@ -216,45 +216,52 @@ pub const Headers = struct {
216216
217217 /// Removes the element at the specified index.
218218 /// Moves items down to fill the empty space.
219 /// TODO this implementation can be replaced by adding
220 /// orderedRemove to the new hash table implementation as an
221 /// alternative to swapRemove.
219222 pub fn orderedRemove(self: *Self, i: usize) void {
220223 const removed = self.data.orderedRemove(i);
221 const kv = self.index.get(removed.name).?;
222 var dex = &kv.value;
224 const kv = self.index.getEntry(removed.name).?;
225 const dex = &kv.value;
223226 if (dex.items.len == 1) {
224227 // was last item; delete the index
225 _ = self.index.remove(kv.key);
226228 dex.deinit();
227229 removed.deinit();
228 self.allocator.free(kv.key);
230 const key = kv.key;
231 _ = self.index.remove(key); // invalidates `kv` and `dex`
232 self.allocator.free(key);
229233 } else {
230234 dex.shrink(dex.items.len - 1);
231235 removed.deinit();
232236 }
233237 // if it was the last item; no need to rebuild index
234238 if (i != self.data.items.len) {
235 self.rebuild_index();
239 self.rebuildIndex();
236240 }
237241 }
238242
239243 /// Removes the element at the specified index.
240244 /// The empty slot is filled from the end of the list.
245 /// TODO this implementation can be replaced by simply using the
246 /// new hash table which does swap removal.
241247 pub fn swapRemove(self: *Self, i: usize) void {
242248 const removed = self.data.swapRemove(i);
243 const kv = self.index.get(removed.name).?;
244 var dex = &kv.value;
249 const kv = self.index.getEntry(removed.name).?;
250 const dex = &kv.value;
245251 if (dex.items.len == 1) {
246252 // was last item; delete the index
247 _ = self.index.remove(kv.key);
248253 dex.deinit();
249254 removed.deinit();
250 self.allocator.free(kv.key);
255 const key = kv.key;
256 _ = self.index.remove(key); // invalidates `kv` and `dex`
257 self.allocator.free(key);
251258 } else {
252259 dex.shrink(dex.items.len - 1);
253260 removed.deinit();
254261 }
255262 // if it was the last item; no need to rebuild index
256263 if (i != self.data.items.len) {
257 self.rebuild_index();
264 self.rebuildIndex();
258265 }
259266 }
260267
......@@ -266,11 +273,7 @@ pub const Headers = struct {
266273 /// Returns a list of indices containing headers with the given name.
267274 /// The returned list should not be modified by the caller.
268275 pub fn getIndices(self: Self, name: []const u8) ?HeaderIndexList {
269 if (self.index.get(name)) |kv| {
270 return kv.value;
271 } else {
272 return null;
273 }
276 return self.index.get(name);
274277 }
275278
276279 /// Returns a slice containing each header with the given name.
......@@ -325,25 +328,20 @@ pub const Headers = struct {
325328 return buf;
326329 }
327330
328 fn rebuild_index(self: *Self) void {
329 { // clear out the indexes
330 var it = self.index.iterator();
331 while (it.next()) |kv| {
332 var dex = &kv.value;
333 dex.items.len = 0; // keeps capacity available
334 }
331 fn rebuildIndex(self: *Self) void {
332 // clear out the indexes
333 for (self.index.items()) |*entry| {
334 entry.value.shrinkRetainingCapacity(0);
335335 }
336 { // fill up indexes again; we know capacity is fine from before
337 for (self.data.span()) |entry, i| {
338 var dex = &self.index.get(entry.name).?.value;
339 dex.appendAssumeCapacity(i);
340 }
336 // fill up indexes again; we know capacity is fine from before
337 for (self.data.items) |entry, i| {
338 self.index.getEntry(entry.name).?.value.appendAssumeCapacity(i);
341339 }
342340 }
343341
344342 pub fn sort(self: *Self) void {
345343 std.sort.sort(HeaderEntry, self.data.items, {}, HeaderEntry.compare);
346 self.rebuild_index();
344 self.rebuildIndex();
347345 }
348346
349347 pub fn format(
lib/std/json.zig+28-28
......@@ -2149,27 +2149,27 @@ test "json.parser.dynamic" {
21492149
21502150 var root = tree.root;
21512151
2152 var image = root.Object.get("Image").?.value;
2152 var image = root.Object.get("Image").?;
21532153
2154 const width = image.Object.get("Width").?.value;
2154 const width = image.Object.get("Width").?;
21552155 testing.expect(width.Integer == 800);
21562156
2157 const height = image.Object.get("Height").?.value;
2157 const height = image.Object.get("Height").?;
21582158 testing.expect(height.Integer == 600);
21592159
2160 const title = image.Object.get("Title").?.value;
2160 const title = image.Object.get("Title").?;
21612161 testing.expect(mem.eql(u8, title.String, "View from 15th Floor"));
21622162
2163 const animated = image.Object.get("Animated").?.value;
2163 const animated = image.Object.get("Animated").?;
21642164 testing.expect(animated.Bool == false);
21652165
2166 const array_of_object = image.Object.get("ArrayOfObject").?.value;
2166 const array_of_object = image.Object.get("ArrayOfObject").?;
21672167 testing.expect(array_of_object.Array.items.len == 1);
21682168
2169 const obj0 = array_of_object.Array.items[0].Object.get("n").?.value;
2169 const obj0 = array_of_object.Array.items[0].Object.get("n").?;
21702170 testing.expect(mem.eql(u8, obj0.String, "m"));
21712171
2172 const double = image.Object.get("double").?.value;
2172 const double = image.Object.get("double").?;
21732173 testing.expect(double.Float == 1.3412);
21742174}
21752175
......@@ -2217,12 +2217,12 @@ test "write json then parse it" {
22172217 var tree = try parser.parse(fixed_buffer_stream.getWritten());
22182218 defer tree.deinit();
22192219
2220 testing.expect(tree.root.Object.get("f").?.value.Bool == false);
2221 testing.expect(tree.root.Object.get("t").?.value.Bool == true);
2222 testing.expect(tree.root.Object.get("int").?.value.Integer == 1234);
2223 testing.expect(tree.root.Object.get("array").?.value.Array.items[0].Null == {});
2224 testing.expect(tree.root.Object.get("array").?.value.Array.items[1].Float == 12.34);
2225 testing.expect(mem.eql(u8, tree.root.Object.get("str").?.value.String, "hello"));
2220 testing.expect(tree.root.Object.get("f").?.Bool == false);
2221 testing.expect(tree.root.Object.get("t").?.Bool == true);
2222 testing.expect(tree.root.Object.get("int").?.Integer == 1234);
2223 testing.expect(tree.root.Object.get("array").?.Array.items[0].Null == {});
2224 testing.expect(tree.root.Object.get("array").?.Array.items[1].Float == 12.34);
2225 testing.expect(mem.eql(u8, tree.root.Object.get("str").?.String, "hello"));
22262226}
22272227
22282228fn test_parse(arena_allocator: *std.mem.Allocator, json_str: []const u8) !Value {
......@@ -2245,7 +2245,7 @@ test "integer after float has proper type" {
22452245 \\ "ints": [1, 2, 3]
22462246 \\}
22472247 );
2248 std.testing.expect(json.Object.getValue("ints").?.Array.items[0] == .Integer);
2248 std.testing.expect(json.Object.get("ints").?.Array.items[0] == .Integer);
22492249}
22502250
22512251test "escaped characters" {
......@@ -2271,16 +2271,16 @@ test "escaped characters" {
22712271
22722272 const obj = (try test_parse(&arena_allocator.allocator, input)).Object;
22732273
2274 testing.expectEqualSlices(u8, obj.get("backslash").?.value.String, "\\");
2275 testing.expectEqualSlices(u8, obj.get("forwardslash").?.value.String, "/");
2276 testing.expectEqualSlices(u8, obj.get("newline").?.value.String, "\n");
2277 testing.expectEqualSlices(u8, obj.get("carriagereturn").?.value.String, "\r");
2278 testing.expectEqualSlices(u8, obj.get("tab").?.value.String, "\t");
2279 testing.expectEqualSlices(u8, obj.get("formfeed").?.value.String, "\x0C");
2280 testing.expectEqualSlices(u8, obj.get("backspace").?.value.String, "\x08");
2281 testing.expectEqualSlices(u8, obj.get("doublequote").?.value.String, "\"");
2282 testing.expectEqualSlices(u8, obj.get("unicode").?.value.String, "ą");
2283 testing.expectEqualSlices(u8, obj.get("surrogatepair").?.value.String, "😂");
2274 testing.expectEqualSlices(u8, obj.get("backslash").?.String, "\\");
2275 testing.expectEqualSlices(u8, obj.get("forwardslash").?.String, "/");
2276 testing.expectEqualSlices(u8, obj.get("newline").?.String, "\n");
2277 testing.expectEqualSlices(u8, obj.get("carriagereturn").?.String, "\r");
2278 testing.expectEqualSlices(u8, obj.get("tab").?.String, "\t");
2279 testing.expectEqualSlices(u8, obj.get("formfeed").?.String, "\x0C");
2280 testing.expectEqualSlices(u8, obj.get("backspace").?.String, "\x08");
2281 testing.expectEqualSlices(u8, obj.get("doublequote").?.String, "\"");
2282 testing.expectEqualSlices(u8, obj.get("unicode").?.String, "ą");
2283 testing.expectEqualSlices(u8, obj.get("surrogatepair").?.String, "😂");
22842284}
22852285
22862286test "string copy option" {
......@@ -2306,11 +2306,11 @@ test "string copy option" {
23062306 const obj_copy = tree_copy.root.Object;
23072307
23082308 for ([_][]const u8{ "noescape", "simple", "unicode", "surrogatepair" }) |field_name| {
2309 testing.expectEqualSlices(u8, obj_nocopy.getValue(field_name).?.String, obj_copy.getValue(field_name).?.String);
2309 testing.expectEqualSlices(u8, obj_nocopy.get(field_name).?.String, obj_copy.get(field_name).?.String);
23102310 }
23112311
2312 const nocopy_addr = &obj_nocopy.getValue("noescape").?.String[0];
2313 const copy_addr = &obj_copy.getValue("noescape").?.String[0];
2312 const nocopy_addr = &obj_nocopy.get("noescape").?.String[0];
2313 const copy_addr = &obj_copy.get("noescape").?.String[0];
23142314
23152315 var found_nocopy = false;
23162316 for (input) |_, index| {
src-self-hosted/Module.zig+83-114
......@@ -75,7 +75,7 @@ deletion_set: std.ArrayListUnmanaged(*Decl) = .{},
7575
7676keep_source_files_loaded: bool,
7777
78const DeclTable = std.HashMap(Scope.NameHash, *Decl, Scope.name_hash_hash, Scope.name_hash_eql);
78const DeclTable = std.HashMap(Scope.NameHash, *Decl, Scope.name_hash_hash, Scope.name_hash_eql, false);
7979
8080const WorkItem = union(enum) {
8181 /// Write the machine code for a Decl to the output file.
......@@ -795,49 +795,38 @@ pub fn deinit(self: *Module) void {
795795 const allocator = self.allocator;
796796 self.deletion_set.deinit(allocator);
797797 self.work_queue.deinit();
798 {
799 var it = self.decl_table.iterator();
800 while (it.next()) |kv| {
801 kv.value.destroy(allocator);
802 }
803 self.decl_table.deinit();
798
799 for (self.decl_table.items()) |entry| {
800 entry.value.destroy(allocator);
804801 }
805 {
806 var it = self.failed_decls.iterator();
807 while (it.next()) |kv| {
808 kv.value.destroy(allocator);
809 }
810 self.failed_decls.deinit();
802 self.decl_table.deinit();
803
804 for (self.failed_decls.items()) |entry| {
805 entry.value.destroy(allocator);
811806 }
812 {
813 var it = self.failed_files.iterator();
814 while (it.next()) |kv| {
815 kv.value.destroy(allocator);
816 }
817 self.failed_files.deinit();
807 self.failed_decls.deinit();
808
809 for (self.failed_files.items()) |entry| {
810 entry.value.destroy(allocator);
818811 }
819 {
820 var it = self.failed_exports.iterator();
821 while (it.next()) |kv| {
822 kv.value.destroy(allocator);
823 }
824 self.failed_exports.deinit();
812 self.failed_files.deinit();
813
814 for (self.failed_exports.items()) |entry| {
815 entry.value.destroy(allocator);
825816 }
826 {
827 var it = self.decl_exports.iterator();
828 while (it.next()) |kv| {
829 const export_list = kv.value;
830 allocator.free(export_list);
831 }
832 self.decl_exports.deinit();
817 self.failed_exports.deinit();
818
819 for (self.decl_exports.items()) |entry| {
820 const export_list = entry.value;
821 allocator.free(export_list);
833822 }
834 {
835 var it = self.export_owners.iterator();
836 while (it.next()) |kv| {
837 freeExportList(allocator, kv.value);
838 }
839 self.export_owners.deinit();
823 self.decl_exports.deinit();
824
825 for (self.export_owners.items()) |entry| {
826 freeExportList(allocator, entry.value);
840827 }
828 self.export_owners.deinit();
829
841830 self.symbol_exports.deinit();
842831 self.root_scope.destroy(allocator);
843832 self.* = undefined;
......@@ -918,9 +907,9 @@ pub fn makeBinFileWritable(self: *Module) !void {
918907}
919908
920909pub fn totalErrorCount(self: *Module) usize {
921 const total = self.failed_decls.size +
922 self.failed_files.size +
923 self.failed_exports.size;
910 const total = self.failed_decls.items().len +
911 self.failed_files.items().len +
912 self.failed_exports.items().len;
924913 return if (total == 0) @boolToInt(self.link_error_flags.no_entry_point_found) else total;
925914}
926915
......@@ -931,32 +920,23 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
931920 var errors = std.ArrayList(AllErrors.Message).init(self.allocator);
932921 defer errors.deinit();
933922
934 {
935 var it = self.failed_files.iterator();
936 while (it.next()) |kv| {
937 const scope = kv.key;
938 const err_msg = kv.value;
939 const source = try scope.getSource(self);
940 try AllErrors.add(&arena, &errors, scope.subFilePath(), source, err_msg.*);
941 }
923 for (self.failed_files.items()) |entry| {
924 const scope = entry.key;
925 const err_msg = entry.value;
926 const source = try scope.getSource(self);
927 try AllErrors.add(&arena, &errors, scope.subFilePath(), source, err_msg.*);
942928 }
943 {
944 var it = self.failed_decls.iterator();
945 while (it.next()) |kv| {
946 const decl = kv.key;
947 const err_msg = kv.value;
948 const source = try decl.scope.getSource(self);
949 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
950 }
929 for (self.failed_decls.items()) |entry| {
930 const decl = entry.key;
931 const err_msg = entry.value;
932 const source = try decl.scope.getSource(self);
933 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
951934 }
952 {
953 var it = self.failed_exports.iterator();
954 while (it.next()) |kv| {
955 const decl = kv.key.owner_decl;
956 const err_msg = kv.value;
957 const source = try decl.scope.getSource(self);
958 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
959 }
935 for (self.failed_exports.items()) |entry| {
936 const decl = entry.key.owner_decl;
937 const err_msg = entry.value;
938 const source = try decl.scope.getSource(self);
939 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
960940 }
961941
962942 if (errors.items.len == 0 and self.link_error_flags.no_entry_point_found) {
......@@ -1016,7 +996,7 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
1016996 decl.analysis = .dependency_failure;
1017997 },
1018998 else => {
1019 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);
999 try self.failed_decls.ensureCapacity(self.failed_decls.items().len + 1);
10201000 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
10211001 self.allocator,
10221002 decl.src(),
......@@ -1086,7 +1066,7 @@ fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {
10861066 error.OutOfMemory => return error.OutOfMemory,
10871067 error.AnalysisFail => return error.AnalysisFail,
10881068 else => {
1089 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);
1069 try self.failed_decls.ensureCapacity(self.failed_decls.items().len + 1);
10901070 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
10911071 self.allocator,
10921072 decl.src(),
......@@ -1636,7 +1616,7 @@ fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void
16361616fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
16371617 switch (root_scope.status) {
16381618 .never_loaded, .unloaded_success => {
1639 try self.failed_files.ensureCapacity(self.failed_files.size + 1);
1619 try self.failed_files.ensureCapacity(self.failed_files.items().len + 1);
16401620
16411621 const source = try root_scope.getSource(self);
16421622
......@@ -1677,7 +1657,7 @@ fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree {
16771657
16781658 switch (root_scope.status) {
16791659 .never_loaded, .unloaded_success => {
1680 try self.failed_files.ensureCapacity(self.failed_files.size + 1);
1660 try self.failed_files.ensureCapacity(self.failed_files.items().len + 1);
16811661
16821662 const source = try root_scope.getSource(self);
16831663
......@@ -1745,8 +1725,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
17451725 const name = tree.tokenSliceLoc(name_loc);
17461726 const name_hash = root_scope.fullyQualifiedNameHash(name);
17471727 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
1748 if (self.decl_table.get(name_hash)) |kv| {
1749 const decl = kv.value;
1728 if (self.decl_table.get(name_hash)) |decl| {
17501729 // Update the AST Node index of the decl, even if its contents are unchanged, it may
17511730 // have been re-ordered.
17521731 decl.src_index = decl_i;
......@@ -1774,14 +1753,11 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
17741753 // TODO also look for global variable declarations
17751754 // TODO also look for comptime blocks and exported globals
17761755 }
1777 {
1778 // Handle explicitly deleted decls from the source code. Not to be confused
1779 // with when we delete decls because they are no longer referenced.
1780 var it = deleted_decls.iterator();
1781 while (it.next()) |kv| {
1782 //std.debug.warn("noticed '{}' deleted from source\n", .{kv.key.name});
1783 try self.deleteDecl(kv.key);
1784 }
1756 // Handle explicitly deleted decls from the source code. Not to be confused
1757 // with when we delete decls because they are no longer referenced.
1758 for (deleted_decls.items()) |entry| {
1759 //std.debug.warn("noticed '{}' deleted from source\n", .{entry.key.name});
1760 try self.deleteDecl(entry.key);
17851761 }
17861762}
17871763
......@@ -1800,18 +1776,14 @@ fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void {
18001776 // we know which ones have been deleted.
18011777 var deleted_decls = std.AutoHashMap(*Decl, void).init(self.allocator);
18021778 defer deleted_decls.deinit();
1803 try deleted_decls.ensureCapacity(self.decl_table.size);
1804 {
1805 var it = self.decl_table.iterator();
1806 while (it.next()) |kv| {
1807 deleted_decls.putAssumeCapacityNoClobber(kv.value, {});
1808 }
1779 try deleted_decls.ensureCapacity(self.decl_table.items().len);
1780 for (self.decl_table.items()) |entry| {
1781 deleted_decls.putAssumeCapacityNoClobber(entry.value, {});
18091782 }
18101783
18111784 for (src_module.decls) |src_decl, decl_i| {
18121785 const name_hash = root_scope.fullyQualifiedNameHash(src_decl.name);
1813 if (self.decl_table.get(name_hash)) |kv| {
1814 const decl = kv.value;
1786 if (self.decl_table.get(name_hash)) |decl| {
18151787 deleted_decls.removeAssertDiscard(decl);
18161788 //std.debug.warn("'{}' contents: '{}'\n", .{ src_decl.name, src_decl.contents });
18171789 if (!srcHashEql(src_decl.contents_hash, decl.contents_hash)) {
......@@ -1835,14 +1807,11 @@ fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void {
18351807 for (exports_to_resolve.items) |export_decl| {
18361808 _ = try self.resolveZirDecl(&root_scope.base, export_decl);
18371809 }
1838 {
1839 // Handle explicitly deleted decls from the source code. Not to be confused
1840 // with when we delete decls because they are no longer referenced.
1841 var it = deleted_decls.iterator();
1842 while (it.next()) |kv| {
1843 //std.debug.warn("noticed '{}' deleted from source\n", .{kv.key.name});
1844 try self.deleteDecl(kv.key);
1845 }
1810 // Handle explicitly deleted decls from the source code. Not to be confused
1811 // with when we delete decls because they are no longer referenced.
1812 for (deleted_decls.items()) |entry| {
1813 //std.debug.warn("noticed '{}' deleted from source\n", .{entry.key.name});
1814 try self.deleteDecl(entry.key);
18461815 }
18471816}
18481817
......@@ -1888,7 +1857,7 @@ fn deleteDeclExports(self: *Module, decl: *Decl) void {
18881857 const kv = self.export_owners.remove(decl) orelse return;
18891858
18901859 for (kv.value) |exp| {
1891 if (self.decl_exports.get(exp.exported_decl)) |decl_exports_kv| {
1860 if (self.decl_exports.getEntry(exp.exported_decl)) |decl_exports_kv| {
18921861 // Remove exports with owner_decl matching the regenerating decl.
18931862 const list = decl_exports_kv.value;
18941863 var i: usize = 0;
......@@ -1983,7 +1952,7 @@ fn createNewDecl(
19831952 name_hash: Scope.NameHash,
19841953 contents_hash: std.zig.SrcHash,
19851954) !*Decl {
1986 try self.decl_table.ensureCapacity(self.decl_table.size + 1);
1955 try self.decl_table.ensureCapacity(self.decl_table.items().len + 1);
19871956 const new_decl = try self.allocateNewDecl(scope, src_index, contents_hash);
19881957 errdefer self.allocator.destroy(new_decl);
19891958 new_decl.name = try mem.dupeZ(self.allocator, u8, decl_name);
......@@ -2043,7 +2012,7 @@ fn resolveZirDecl(self: *Module, scope: *Scope, src_decl: *zir.Decl) InnerError!
20432012
20442013fn resolveZirDeclHavingIndex(self: *Module, scope: *Scope, src_decl: *zir.Decl, src_index: usize) InnerError!*Decl {
20452014 const name_hash = scope.namespace().fullyQualifiedNameHash(src_decl.name);
2046 const decl = self.decl_table.getValue(name_hash).?;
2015 const decl = self.decl_table.get(name_hash).?;
20472016 decl.src_index = src_index;
20482017 try self.ensureDeclAnalyzed(decl);
20492018 return decl;
......@@ -2148,8 +2117,8 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const
21482117 else => return self.fail(scope, src, "unable to export type '{}'", .{typed_value.ty}),
21492118 }
21502119
2151 try self.decl_exports.ensureCapacity(self.decl_exports.size + 1);
2152 try self.export_owners.ensureCapacity(self.export_owners.size + 1);
2120 try self.decl_exports.ensureCapacity(self.decl_exports.items().len + 1);
2121 try self.export_owners.ensureCapacity(self.export_owners.items().len + 1);
21532122
21542123 const new_export = try self.allocator.create(Export);
21552124 errdefer self.allocator.destroy(new_export);
......@@ -2168,23 +2137,23 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const
21682137 // Add to export_owners table.
21692138 const eo_gop = self.export_owners.getOrPut(owner_decl) catch unreachable;
21702139 if (!eo_gop.found_existing) {
2171 eo_gop.kv.value = &[0]*Export{};
2140 eo_gop.entry.value = &[0]*Export{};
21722141 }
2173 eo_gop.kv.value = try self.allocator.realloc(eo_gop.kv.value, eo_gop.kv.value.len + 1);
2174 eo_gop.kv.value[eo_gop.kv.value.len - 1] = new_export;
2175 errdefer eo_gop.kv.value = self.allocator.shrink(eo_gop.kv.value, eo_gop.kv.value.len - 1);
2142 eo_gop.entry.value = try self.allocator.realloc(eo_gop.entry.value, eo_gop.entry.value.len + 1);
2143 eo_gop.entry.value[eo_gop.entry.value.len - 1] = new_export;
2144 errdefer eo_gop.entry.value = self.allocator.shrink(eo_gop.entry.value, eo_gop.entry.value.len - 1);
21762145
21772146 // Add to exported_decl table.
21782147 const de_gop = self.decl_exports.getOrPut(exported_decl) catch unreachable;
21792148 if (!de_gop.found_existing) {
2180 de_gop.kv.value = &[0]*Export{};
2149 de_gop.entry.value = &[0]*Export{};
21812150 }
2182 de_gop.kv.value = try self.allocator.realloc(de_gop.kv.value, de_gop.kv.value.len + 1);
2183 de_gop.kv.value[de_gop.kv.value.len - 1] = new_export;
2184 errdefer de_gop.kv.value = self.allocator.shrink(de_gop.kv.value, de_gop.kv.value.len - 1);
2151 de_gop.entry.value = try self.allocator.realloc(de_gop.entry.value, de_gop.entry.value.len + 1);
2152 de_gop.entry.value[de_gop.entry.value.len - 1] = new_export;
2153 errdefer de_gop.entry.value = self.allocator.shrink(de_gop.entry.value, de_gop.entry.value.len - 1);
21852154
21862155 if (self.symbol_exports.get(symbol_name)) |_| {
2187 try self.failed_exports.ensureCapacity(self.failed_exports.size + 1);
2156 try self.failed_exports.ensureCapacity(self.failed_exports.items().len + 1);
21882157 self.failed_exports.putAssumeCapacityNoClobber(new_export, try ErrorMsg.create(
21892158 self.allocator,
21902159 src,
......@@ -2197,10 +2166,10 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const
21972166 }
21982167
21992168 try self.symbol_exports.putNoClobber(symbol_name, new_export);
2200 self.bin_file.updateDeclExports(self, exported_decl, de_gop.kv.value) catch |err| switch (err) {
2169 self.bin_file.updateDeclExports(self, exported_decl, de_gop.entry.value) catch |err| switch (err) {
22012170 error.OutOfMemory => return error.OutOfMemory,
22022171 else => {
2203 try self.failed_exports.ensureCapacity(self.failed_exports.size + 1);
2172 try self.failed_exports.ensureCapacity(self.failed_exports.items().len + 1);
22042173 self.failed_exports.putAssumeCapacityNoClobber(new_export, try ErrorMsg.create(
22052174 self.allocator,
22062175 src,
......@@ -2494,7 +2463,7 @@ fn getNextAnonNameIndex(self: *Module) usize {
24942463fn lookupDeclName(self: *Module, scope: *Scope, ident_name: []const u8) ?*Decl {
24952464 const namespace = scope.namespace();
24962465 const name_hash = namespace.fullyQualifiedNameHash(ident_name);
2497 return self.decl_table.getValue(name_hash);
2466 return self.decl_table.get(name_hash);
24982467}
24992468
25002469fn analyzeInstExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) InnerError!*Inst {
......@@ -3489,8 +3458,8 @@ fn failNode(
34893458fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *ErrorMsg) InnerError {
34903459 {
34913460 errdefer err_msg.destroy(self.allocator);
3492 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);
3493 try self.failed_files.ensureCapacity(self.failed_files.size + 1);
3461 try self.failed_decls.ensureCapacity(self.failed_decls.items().len + 1);
3462 try self.failed_files.ensureCapacity(self.failed_files.items().len + 1);
34943463 }
34953464 switch (scope.tag) {
34963465 .decl => {
src-self-hosted/codegen.zig+2-2
......@@ -705,7 +705,7 @@ const Function = struct {
705705 }
706706
707707 fn resolveInst(self: *Function, inst: *ir.Inst) !MCValue {
708 if (self.inst_table.getValue(inst)) |mcv| {
708 if (self.inst_table.get(inst)) |mcv| {
709709 return mcv;
710710 }
711711 if (inst.cast(ir.Inst.Constant)) |const_inst| {
......@@ -713,7 +713,7 @@ const Function = struct {
713713 try self.inst_table.putNoClobber(inst, mcvalue);
714714 return mcvalue;
715715 } else {
716 return self.inst_table.getValue(inst).?;
716 return self.inst_table.get(inst).?;
717717 }
718718 }
719719
src-self-hosted/link.zig+3-3
......@@ -1071,7 +1071,7 @@ pub const ElfFile = struct {
10711071 try self.file.?.pwriteAll(code, file_offset);
10721072
10731073 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
1074 const decl_exports = module.decl_exports.getValue(decl) orelse &[0]*Module.Export{};
1074 const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{};
10751075 return self.updateDeclExports(module, decl, decl_exports);
10761076 }
10771077
......@@ -1093,7 +1093,7 @@ pub const ElfFile = struct {
10931093 for (exports) |exp| {
10941094 if (exp.options.section) |section_name| {
10951095 if (!mem.eql(u8, section_name, ".text")) {
1096 try module.failed_exports.ensureCapacity(module.failed_exports.size + 1);
1096 try module.failed_exports.ensureCapacity(module.failed_exports.items().len + 1);
10971097 module.failed_exports.putAssumeCapacityNoClobber(
10981098 exp,
10991099 try Module.ErrorMsg.create(self.allocator, 0, "Unimplemented: ExportOptions.section", .{}),
......@@ -1111,7 +1111,7 @@ pub const ElfFile = struct {
11111111 },
11121112 .Weak => elf.STB_WEAK,
11131113 .LinkOnce => {
1114 try module.failed_exports.ensureCapacity(module.failed_exports.size + 1);
1114 try module.failed_exports.ensureCapacity(module.failed_exports.items().len + 1);
11151115 module.failed_exports.putAssumeCapacityNoClobber(
11161116 exp,
11171117 try Module.ErrorMsg.create(self.allocator, 0, "Unimplemented: GlobalLinkage.LinkOnce", .{}),
src-self-hosted/main.zig+2-2
......@@ -720,7 +720,7 @@ fn fmtPathDir(
720720 defer dir.close();
721721
722722 const stat = try dir.stat();
723 if (try fmt.seen.put(stat.inode, {})) |_| return;
723 if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
724724
725725 var dir_it = dir.iterate();
726726 while (try dir_it.next()) |entry| {
......@@ -768,7 +768,7 @@ fn fmtPathFile(
768768 defer fmt.gpa.free(source_code);
769769
770770 // Add to set after no longer possible to get error.IsDir.
771 if (try fmt.seen.put(stat.inode, {})) |_| return;
771 if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
772772
773773 const tree = try std.zig.parse(fmt.gpa, source_code);
774774 defer tree.deinit();
src-self-hosted/translate_c.zig+13-14
......@@ -20,7 +20,7 @@ pub const Error = error{OutOfMemory};
2020const TypeError = Error || error{UnsupportedType};
2121const TransError = TypeError || error{UnsupportedTranslation};
2222
23const DeclTable = std.HashMap(usize, []const u8, addrHash, addrEql);
23const DeclTable = std.HashMap(usize, []const u8, addrHash, addrEql, false);
2424
2525fn addrHash(x: usize) u32 {
2626 switch (@typeInfo(usize).Int.bits) {
......@@ -776,8 +776,8 @@ fn checkForBuiltinTypedef(checked_name: []const u8) ?[]const u8 {
776776}
777777
778778fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, top_level_visit: bool) Error!?*ast.Node {
779 if (c.decl_table.get(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)))) |kv|
780 return transCreateNodeIdentifier(c, kv.value); // Avoid processing this decl twice
779 if (c.decl_table.get(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)))) |name|
780 return transCreateNodeIdentifier(c, name); // Avoid processing this decl twice
781781 const rp = makeRestorePoint(c);
782782
783783 const typedef_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, typedef_decl)));
......@@ -818,8 +818,8 @@ fn transCreateNodeTypedef(rp: RestorePoint, typedef_decl: *const ZigClangTypedef
818818}
819819
820820fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node {
821 if (c.decl_table.get(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) |kv|
822 return try transCreateNodeIdentifier(c, kv.value); // Avoid processing this decl twice
821 if (c.decl_table.get(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) |name|
822 return try transCreateNodeIdentifier(c, name); // Avoid processing this decl twice
823823 const record_loc = ZigClangRecordDecl_getLocation(record_decl);
824824
825825 var bare_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, record_decl)));
......@@ -969,7 +969,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
969969
970970fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node {
971971 if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name|
972 return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice
972 return try transCreateNodeIdentifier(c, name); // Avoid processing this decl twice
973973 const rp = makeRestorePoint(c);
974974 const enum_loc = ZigClangEnumDecl_getLocation(enum_decl);
975975
......@@ -2130,7 +2130,7 @@ fn transInitListExprRecord(
21302130 var raw_name = try rp.c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl)));
21312131 if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {
21322132 const name = rp.c.decl_table.get(@ptrToInt(ZigClangFieldDecl_getCanonicalDecl(field_decl))).?;
2133 raw_name = try mem.dupe(rp.c.arena, u8, name.value);
2133 raw_name = try mem.dupe(rp.c.arena, u8, name);
21342134 }
21352135 const field_name_tok = try appendIdentifier(rp.c, raw_name);
21362136
......@@ -2855,7 +2855,7 @@ fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangMemberE
28552855 const field_decl = @ptrCast(*const struct_ZigClangFieldDecl, member_decl);
28562856 if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {
28572857 const name = rp.c.decl_table.get(@ptrToInt(ZigClangFieldDecl_getCanonicalDecl(field_decl))).?;
2858 break :blk try mem.dupe(rp.c.arena, u8, name.value);
2858 break :blk try mem.dupe(rp.c.arena, u8, name);
28592859 }
28602860 }
28612861 const decl = @ptrCast(*const ZigClangNamedDecl, member_decl);
......@@ -6040,8 +6040,8 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
60406040 } else if (node.id == .PrefixOp) {
60416041 return node;
60426042 } else if (node.cast(ast.Node.Identifier)) |ident| {
6043 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |kv| {
6044 if (kv.value.cast(ast.Node.VarDecl)) |var_decl|
6043 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
6044 if (value.cast(ast.Node.VarDecl)) |var_decl|
60456045 return getContainer(c, var_decl.init_node.?);
60466046 }
60476047 } else if (node.cast(ast.Node.InfixOp)) |infix| {
......@@ -6064,8 +6064,8 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
60646064
60656065fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
60666066 if (ref.cast(ast.Node.Identifier)) |ident| {
6067 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |kv| {
6068 if (kv.value.cast(ast.Node.VarDecl)) |var_decl| {
6067 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
6068 if (value.cast(ast.Node.VarDecl)) |var_decl| {
60696069 if (var_decl.type_node) |ty|
60706070 return getContainer(c, ty);
60716071 }
......@@ -6104,8 +6104,7 @@ fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto {
61046104}
61056105
61066106fn addMacros(c: *Context) !void {
6107 var macro_it = c.global_scope.macro_table.iterator();
6108 while (macro_it.next()) |kv| {
6107 for (c.global_scope.macro_table.items()) |kv| {
61096108 if (getFnProto(c, kv.value)) |proto_node| {
61106109 // If a macro aliases a global variable which is a function pointer, we conclude that
61116110 // the macro is intended to represent a function that assumes the function pointer
src-self-hosted/zir.zig+16-18
......@@ -758,7 +758,7 @@ pub const Module = struct {
758758 }
759759
760760 fn writeInstParamToStream(self: Module, stream: var, inst: *Inst, inst_table: *const InstPtrTable) !void {
761 if (inst_table.getValue(inst)) |info| {
761 if (inst_table.get(inst)) |info| {
762762 if (info.index) |i| {
763763 try stream.print("%{}", .{info.index});
764764 } else {
......@@ -843,7 +843,7 @@ const Parser = struct {
843843 skipSpace(self);
844844 const decl = try parseInstruction(self, &body_context, ident);
845845 const ident_index = body_context.instructions.items.len;
846 if (try body_context.name_map.put(ident, decl.inst)) |_| {
846 if (try body_context.name_map.fetchPut(ident, decl.inst)) |_| {
847847 return self.fail("redefinition of identifier '{}'", .{ident});
848848 }
849849 try body_context.instructions.append(decl.inst);
......@@ -929,7 +929,7 @@ const Parser = struct {
929929 skipSpace(self);
930930 const decl = try parseInstruction(self, null, ident);
931931 const ident_index = self.decls.items.len;
932 if (try self.global_name_map.put(ident, decl.inst)) |_| {
932 if (try self.global_name_map.fetchPut(ident, decl.inst)) |_| {
933933 return self.fail("redefinition of identifier '{}'", .{ident});
934934 }
935935 try self.decls.append(self.allocator, decl);
......@@ -1153,7 +1153,7 @@ const Parser = struct {
11531153 else => continue,
11541154 };
11551155 const ident = self.source[name_start..self.i];
1156 const kv = map.get(ident) orelse {
1156 return map.get(ident) orelse {
11571157 const bad_name = self.source[name_start - 1 .. self.i];
11581158 const src = name_start - 1;
11591159 if (local_ref) {
......@@ -1172,7 +1172,6 @@ const Parser = struct {
11721172 return &declval.base;
11731173 }
11741174 };
1175 return kv.value;
11761175 }
11771176
11781177 fn generateName(self: *Parser) ![]u8 {
......@@ -1219,13 +1218,12 @@ const EmitZIR = struct {
12191218 // by the hash table.
12201219 var src_decls = std.ArrayList(*IrModule.Decl).init(self.allocator);
12211220 defer src_decls.deinit();
1222 try src_decls.ensureCapacity(self.old_module.decl_table.size);
1223 try self.decls.ensureCapacity(self.allocator, self.old_module.decl_table.size);
1224 try self.names.ensureCapacity(self.old_module.decl_table.size);
1221 try src_decls.ensureCapacity(self.old_module.decl_table.items().len);
1222 try self.decls.ensureCapacity(self.allocator, self.old_module.decl_table.items().len);
1223 try self.names.ensureCapacity(self.old_module.decl_table.items().len);
12251224
1226 var decl_it = self.old_module.decl_table.iterator();
1227 while (decl_it.next()) |kv| {
1228 const decl = kv.value;
1225 for (self.old_module.decl_table.items()) |entry| {
1226 const decl = entry.value;
12291227 src_decls.appendAssumeCapacity(decl);
12301228 self.names.putAssumeCapacityNoClobber(mem.spanZ(decl.name), {});
12311229 }
......@@ -1248,7 +1246,7 @@ const EmitZIR = struct {
12481246 .codegen_failure,
12491247 .dependency_failure,
12501248 .codegen_failure_retryable,
1251 => if (self.old_module.failed_decls.getValue(ir_decl)) |err_msg| {
1249 => if (self.old_module.failed_decls.get(ir_decl)) |err_msg| {
12521250 const fail_inst = try self.arena.allocator.create(Inst.CompileError);
12531251 fail_inst.* = .{
12541252 .base = .{
......@@ -1270,7 +1268,7 @@ const EmitZIR = struct {
12701268 continue;
12711269 },
12721270 }
1273 if (self.old_module.export_owners.getValue(ir_decl)) |exports| {
1271 if (self.old_module.export_owners.get(ir_decl)) |exports| {
12741272 for (exports) |module_export| {
12751273 const symbol_name = try self.emitStringLiteral(module_export.src, module_export.options.name);
12761274 const export_inst = try self.arena.allocator.create(Inst.Export);
......@@ -1314,7 +1312,7 @@ const EmitZIR = struct {
13141312 try new_body.inst_table.putNoClobber(inst, new_inst);
13151313 return new_inst;
13161314 } else {
1317 return new_body.inst_table.getValue(inst).?;
1315 return new_body.inst_table.get(inst).?;
13181316 }
13191317 }
13201318
......@@ -1424,7 +1422,7 @@ const EmitZIR = struct {
14241422 try self.emitBody(body, &inst_table, &instructions);
14251423 },
14261424 .sema_failure => {
1427 const err_msg = self.old_module.failed_decls.getValue(module_fn.owner_decl).?;
1425 const err_msg = self.old_module.failed_decls.get(module_fn.owner_decl).?;
14281426 const fail_inst = try self.arena.allocator.create(Inst.CompileError);
14291427 fail_inst.* = .{
14301428 .base = .{
......@@ -1841,7 +1839,7 @@ const EmitZIR = struct {
18411839 self.next_auto_name += 1;
18421840 const gop = try self.names.getOrPut(proposed_name);
18431841 if (!gop.found_existing) {
1844 gop.kv.value = {};
1842 gop.entry.value = {};
18451843 return proposed_name;
18461844 }
18471845 }
......@@ -1861,9 +1859,9 @@ const EmitZIR = struct {
18611859 },
18621860 .kw_args = .{},
18631861 };
1864 gop.kv.value = try self.emitUnnamedDecl(&primitive_inst.base);
1862 gop.entry.value = try self.emitUnnamedDecl(&primitive_inst.base);
18651863 }
1866 return gop.kv.value;
1864 return gop.entry.value;
18671865 }
18681866
18691867 fn emitStringLiteral(self: *EmitZIR, src: usize, str: []const u8) !*Decl {