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 {...@@ -392,7 +392,7 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc {
392 .n = header_stack_size,392 .n = header_stack_size,
393 },393 },
394 });394 });
395 if (try urls.put(urlized, tag_token)) |entry| {395 if (try urls.fetchPut(urlized, tag_token)) |entry| {
396 parseError(tokenizer, tag_token, "duplicate header url: #{}", .{urlized}) catch {};396 parseError(tokenizer, tag_token, "duplicate header url: #{}", .{urlized}) catch {};
397 parseError(tokenizer, entry.value, "other tag here", .{}) catch {};397 parseError(tokenizer, entry.value, "other tag here", .{}) catch {};
398 return error.ParseError;398 return error.ParseError;
doc/langref.html.in+3-11
...@@ -5363,11 +5363,11 @@ const std = @import("std");...@@ -5363,11 +5363,11 @@ const std = @import("std");
5363const assert = std.debug.assert;5363const assert = std.debug.assert;
53645364
5365test "turn HashMap into a set with void" {5365test "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);
5367 defer map.deinit();5367 defer map.deinit();
53685368
5369 _ = try map.put(1, {});5369 try map.put(1, {});
5370 _ = try map.put(2, {});5370 try map.put(2, {});
53715371
5372 assert(map.contains(2));5372 assert(map.contains(2));
5373 assert(!map.contains(3));5373 assert(!map.contains(3));
...@@ -5375,14 +5375,6 @@ test "turn HashMap into a set with void" {...@@ -5375,14 +5375,6 @@ test "turn HashMap into a set with void" {
5375 _ = map.remove(2);5375 _ = map.remove(2);
5376 assert(!map.contains(2));5376 assert(!map.contains(2));
5377}5377}
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}
5386 {#code_end#}5378 {#code_end#}
5387 <p>Note that this is different from using a dummy value for the hash map value.5379 <p>Note that this is different from using a dummy value for the hash map value.
5388 By using {#syntax#}void{#endsyntax#} as the type of the value, the hash map entry type has no value field, and5380 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 {...@@ -210,6 +210,14 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
210 self.capacity = new_len;210 self.capacity = new_len;
211 }211 }
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
213 pub fn ensureCapacity(self: *Self, new_capacity: usize) !void {221 pub fn ensureCapacity(self: *Self, new_capacity: usize) !void {
214 var better_capacity = self.capacity;222 var better_capacity = self.capacity;
215 if (better_capacity >= new_capacity) return;223 if (better_capacity >= new_capacity) return;
...@@ -432,6 +440,14 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -432,6 +440,14 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
432 self.capacity = new_len;440 self.capacity = new_len;
433 }441 }
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
435 pub fn ensureCapacity(self: *Self, allocator: *Allocator, new_capacity: usize) !void {451 pub fn ensureCapacity(self: *Self, allocator: *Allocator, new_capacity: usize) !void {
436 var better_capacity = self.capacity;452 var better_capacity = self.capacity;
437 if (better_capacity >= new_capacity) return;453 if (better_capacity >= new_capacity) return;
lib/std/buf_map.zig+7-8
...@@ -33,10 +33,10 @@ pub const BufMap = struct {...@@ -33,10 +33,10 @@ pub const BufMap = struct {
33 pub fn setMove(self: *BufMap, key: []u8, value: []u8) !void {33 pub fn setMove(self: *BufMap, key: []u8, value: []u8) !void {
34 const get_or_put = try self.hash_map.getOrPut(key);34 const get_or_put = try self.hash_map.getOrPut(key);
35 if (get_or_put.found_existing) {35 if (get_or_put.found_existing) {
36 self.free(get_or_put.kv.key);36 self.free(get_or_put.entry.key);
37 get_or_put.kv.key = key;37 get_or_put.entry.key = key;
38 }38 }
39 get_or_put.kv.value = value;39 get_or_put.entry.value = value;
40 }40 }
4141
42 /// `key` and `value` are copied into the BufMap.42 /// `key` and `value` are copied into the BufMap.
...@@ -45,19 +45,18 @@ pub const BufMap = struct {...@@ -45,19 +45,18 @@ pub const BufMap = struct {
45 errdefer self.free(value_copy);45 errdefer self.free(value_copy);
46 const get_or_put = try self.hash_map.getOrPut(key);46 const get_or_put = try self.hash_map.getOrPut(key);
47 if (get_or_put.found_existing) {47 if (get_or_put.found_existing) {
48 self.free(get_or_put.kv.value);48 self.free(get_or_put.entry.value);
49 } else {49 } else {
50 get_or_put.kv.key = self.copy(key) catch |err| {50 get_or_put.entry.key = self.copy(key) catch |err| {
51 _ = self.hash_map.remove(key);51 _ = self.hash_map.remove(key);
52 return err;52 return err;
53 };53 };
54 }54 }
55 get_or_put.kv.value = value_copy;55 get_or_put.entry.value = value_copy;
56 }56 }
5757
58 pub fn get(self: BufMap, key: []const u8) ?[]const u8 {58 pub fn get(self: BufMap, key: []const u8) ?[]const u8 {
59 const entry = self.hash_map.get(key) orelse return null;59 return self.hash_map.get(key);
60 return entry.value;
61 }60 }
6261
63 pub fn delete(self: *BufMap, key: []const u8) void {62 pub fn delete(self: *BufMap, key: []const u8) void {
lib/std/buf_set.zig+3-5
...@@ -14,14 +14,12 @@ pub const BufSet = struct {...@@ -14,14 +14,12 @@ pub const BufSet = struct {
14 return self;14 return self;
15 }15 }
1616
17 pub fn deinit(self: *const BufSet) void {17 pub fn deinit(self: *BufSet) void {
18 var it = self.hash_map.iterator();18 for (self.hash_map.items()) |entry| {
19 while (true) {
20 const entry = it.next() orelse break;
21 self.free(entry.key);19 self.free(entry.key);
22 }20 }
23
24 self.hash_map.deinit();21 self.hash_map.deinit();
22 self.* = undefined;
25 }23 }
2624
27 pub fn put(self: *BufSet, key: []const u8) !void {25 pub fn put(self: *BufSet, key: []const u8) !void {
lib/std/build.zig+6-6
...@@ -422,12 +422,12 @@ pub const Builder = struct {...@@ -422,12 +422,12 @@ pub const Builder = struct {
422 .type_id = type_id,422 .type_id = type_id,
423 .description = description,423 .description = description,
424 };424 };
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) {
426 panic("Option '{}' declared twice", .{name});426 panic("Option '{}' declared twice", .{name});
427 }427 }
428 self.available_options_list.append(available_option) catch unreachable;428 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;
431 entry.value.used = true;431 entry.value.used = true;
432 switch (type_id) {432 switch (type_id) {
433 TypeId.Bool => switch (entry.value.value) {433 TypeId.Bool => switch (entry.value.value) {
...@@ -634,7 +634,7 @@ pub const Builder = struct {...@@ -634,7 +634,7 @@ pub const Builder = struct {
634 pub fn addUserInputOption(self: *Builder, name: []const u8, value: []const u8) !bool {634 pub fn addUserInputOption(self: *Builder, name: []const u8, value: []const u8) !bool {
635 const gop = try self.user_input_options.getOrPut(name);635 const gop = try self.user_input_options.getOrPut(name);
636 if (!gop.found_existing) {636 if (!gop.found_existing) {
637 gop.kv.value = UserInputOption{637 gop.entry.value = UserInputOption{
638 .name = name,638 .name = name,
639 .value = UserValue{ .Scalar = value },639 .value = UserValue{ .Scalar = value },
640 .used = false,640 .used = false,
...@@ -643,7 +643,7 @@ pub const Builder = struct {...@@ -643,7 +643,7 @@ pub const Builder = struct {
643 }643 }
644644
645 // option already exists645 // option already exists
646 switch (gop.kv.value.value) {646 switch (gop.entry.value.value) {
647 UserValue.Scalar => |s| {647 UserValue.Scalar => |s| {
648 // turn it into a list648 // turn it into a list
649 var list = ArrayList([]const u8).init(self.allocator);649 var list = ArrayList([]const u8).init(self.allocator);
...@@ -675,7 +675,7 @@ pub const Builder = struct {...@@ -675,7 +675,7 @@ pub const Builder = struct {
675 pub fn addUserInputFlag(self: *Builder, name: []const u8) !bool {675 pub fn addUserInputFlag(self: *Builder, name: []const u8) !bool {
676 const gop = try self.user_input_options.getOrPut(name);676 const gop = try self.user_input_options.getOrPut(name);
677 if (!gop.found_existing) {677 if (!gop.found_existing) {
678 gop.kv.value = UserInputOption{678 gop.entry.value = UserInputOption{
679 .name = name,679 .name = name,
680 .value = UserValue{ .Flag = {} },680 .value = UserValue{ .Flag = {} },
681 .used = false,681 .used = false,
...@@ -684,7 +684,7 @@ pub const Builder = struct {...@@ -684,7 +684,7 @@ pub const Builder = struct {
684 }684 }
685685
686 // option already exists686 // option already exists
687 switch (gop.kv.value.value) {687 switch (gop.entry.value.value) {
688 UserValue.Scalar => |s| {688 UserValue.Scalar => |s| {
689 warn("Flag '-D{}' conflicts with option '-D{}={}'.\n", .{ name, name, s });689 warn("Flag '-D{}' conflicts with option '-D{}={}'.\n", .{ name, name, s });
690 return true;690 return true;
lib/std/debug.zig+4-4
...@@ -1132,7 +1132,7 @@ pub const DebugInfo = struct {...@@ -1132,7 +1132,7 @@ pub const DebugInfo = struct {
1132 const seg_end = seg_start + segment_cmd.vmsize;1132 const seg_end = seg_start + segment_cmd.vmsize;
11331133
1134 if (rebased_address >= seg_start and rebased_address < seg_end) {1134 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| {
1136 return obj_di;1136 return obj_di;
1137 }1137 }
11381138
...@@ -1204,7 +1204,7 @@ pub const DebugInfo = struct {...@@ -1204,7 +1204,7 @@ pub const DebugInfo = struct {
1204 const seg_end = seg_start + info.SizeOfImage;1204 const seg_end = seg_start + info.SizeOfImage;
12051205
1206 if (address >= seg_start and address < seg_end) {1206 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| {
1208 return obj_di;1208 return obj_di;
1209 }1209 }
12101210
...@@ -1278,7 +1278,7 @@ pub const DebugInfo = struct {...@@ -1278,7 +1278,7 @@ pub const DebugInfo = struct {
1278 else => return error.MissingDebugInfo,1278 else => return error.MissingDebugInfo,
1279 }1279 }
12801280
1281 if (self.address_map.getValue(ctx.base_address)) |obj_di| {1281 if (self.address_map.get(ctx.base_address)) |obj_di| {
1282 return obj_di;1282 return obj_di;
1283 }1283 }
12841284
...@@ -1441,7 +1441,7 @@ pub const ModuleDebugInfo = switch (builtin.os.tag) {...@@ -1441,7 +1441,7 @@ pub const ModuleDebugInfo = switch (builtin.os.tag) {
1441 const o_file_path = mem.spanZ(self.strings[symbol.ofile.?.n_strx..]);1441 const o_file_path = mem.spanZ(self.strings[symbol.ofile.?.n_strx..]);
14421442
1443 // Check if its debug infos are already in the cache1443 // Check if its debug infos are already in the cache
1444 var o_file_di = self.ofiles.getValue(o_file_path) orelse1444 var o_file_di = self.ofiles.get(o_file_path) orelse
1445 (self.loadOFile(o_file_path) catch |err| switch (err) {1445 (self.loadOFile(o_file_path) catch |err| switch (err) {
1446 error.FileNotFound,1446 error.FileNotFound,
1447 error.MissingDebugInfo,1447 error.MissingDebugInfo,
lib/std/hash_map.zig+763-310
...@@ -9,17 +9,15 @@ const autoHash = std.hash.autoHash;...@@ -9,17 +9,15 @@ const autoHash = std.hash.autoHash;
9const Wyhash = std.hash.Wyhash;9const Wyhash = std.hash.Wyhash;
10const Allocator = mem.Allocator;10const Allocator = mem.Allocator;
11const builtin = @import("builtin");11const builtin = @import("builtin");
1212const hash_map = @This();
13const want_modification_safety = std.debug.runtime_safety;
14const debug_u32 = if (want_modification_safety) u32 else void;
1513
16pub fn AutoHashMap(comptime K: type, comptime V: type) type {14pub 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));
18}16}
1917
20/// Builtin hashmap for strings as keys.18/// Builtin hashmap for strings as keys.
21pub fn StringHashMap(comptime V: type) type {19pub fn StringHashMap(comptime V: type) type {
22 return HashMap([]const u8, V, hashString, eqlString);20 return HashMap([]const u8, V, hashString, eqlString, true);
23}21}
2422
25pub fn eqlString(a: []const u8, b: []const u8) bool {23pub fn eqlString(a: []const u8, b: []const u8) bool {
...@@ -30,422 +28,859 @@ pub fn hashString(s: []const u8) u32 {...@@ -30,422 +28,859 @@ pub fn hashString(s: []const u8) u32 {
30 return @truncate(u32, std.hash.Wyhash.hash(0, s));28 return @truncate(u32, std.hash.Wyhash.hash(0, s));
31}29}
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 {
34 return struct {48 return struct {
35 entries: []Entry,49 unmanaged: Unmanaged,
36 size: usize,
37 max_distance_from_start_index: usize,
38 allocator: *Allocator,50 allocator: *Allocator,
3951
40 /// This is used to detect bugs where a hashtable is edited while an iterator is running.52 pub const Unmanaged = HashMapUnmanaged(K, V, hash, eql, store_hash);
41 modification_count: debug_u32,53 pub const Entry = Unmanaged.Entry;
4254 pub const Hash = Unmanaged.Hash;
43 const Self = @This();55 pub const GetOrPutResult = Unmanaged.GetOrPutResult;
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 };
6556
57 /// Deprecated. Iterate using `items`.
66 pub const Iterator = struct {58 pub const Iterator = struct {
67 hm: *const Self,59 hm: *const Self,
68 // how many items have we returned60 /// Iterator through the entry array.
69 count: usize,
70 // iterator through the entry array
71 index: usize,61 index: usize,
72 // used to detect concurrent modification
73 initial_modification_count: debug_u32,
7462
75 pub fn next(it: *Iterator) ?*KV {63 pub fn next(it: *Iterator) ?*Entry {
76 if (want_modification_safety) {64 if (it.index >= it.hm.unmanaged.entries.items.len) return null;
77 assert(it.initial_modification_count == it.hm.modification_count); // concurrent modification65 const result = &it.hm.unmanaged.entries.items[it.index];
78 }66 it.index += 1;
79 if (it.count >= it.hm.size) return null;67 return result;
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
89 }68 }
9069
91 // Reset the iterator to the initial index70 /// Reset the iterator to the initial index
92 pub fn reset(it: *Iterator) void {71 pub fn reset(it: *Iterator) void {
93 it.count = 0;
94 it.index = 0;72 it.index = 0;
95 // Resetting the modification count too
96 it.initial_modification_count = it.hm.modification_count;
97 }73 }
98 };74 };
9975
76 const Self = @This();
77 const Index = Unmanaged.Index;
78
100 pub fn init(allocator: *Allocator) Self {79 pub fn init(allocator: *Allocator) Self {
101 return Self{80 return .{
102 .entries = &[_]Entry{},81 .unmanaged = .{},
103 .allocator = allocator,82 .allocator = allocator,
104 .size = 0,
105 .max_distance_from_start_index = 0,
106 .modification_count = if (want_modification_safety) 0 else {},
107 };83 };
108 }84 }
10985
110 pub fn deinit(hm: Self) void {86 pub fn deinit(self: *Self) void {
111 hm.allocator.free(hm.entries);87 self.unmanaged.deinit(self.allocator);
88 self.* = undefined;
112 }89 }
11390
114 pub fn clear(hm: *Self) void {91 pub fn clearRetainingCapacity(self: *Self) void {
115 for (hm.entries) |*entry| {92 return self.unmanaged.clearRetainingCapacity();
116 entry.used = false;
117 }
118 hm.size = 0;
119 hm.max_distance_from_start_index = 0;
120 hm.incrementModificationCount();
121 }93 }
12294
95 pub fn clearAndFree(self: *Self, allocator: *Allocator) void {
96 return self.unmanaged.clearAndFree(self.allocator);
97 }
98
99 /// Deprecated. Use `items().len`.
123 pub fn count(self: Self) usize {100 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 };
125 }110 }
126111
127 /// If key exists this function cannot fail.112 /// If key exists this function cannot fail.
128 /// If there is an existing item with `key`, then the result113 /// 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.
130 /// Otherwise, puts a new item with undefined value, and115 /// Otherwise, puts a new item with undefined value, and
131 /// the kv pointer points to it. Caller should then initialize116 /// the `Entry` pointer points to it. Caller should then initialize
132 /// the data.117 /// the value (but not the key).
133 pub fn getOrPut(self: *Self, key: K) !GetOrPutResult {118 pub fn getOrPut(self: *Self, key: K) !GetOrPutResult {
134 // TODO this implementation can be improved - we should only119 return self.unmanaged.getOrPut(self.allocator, key);
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 };
150 }120 }
151121
152 pub fn getOrPutValue(self: *Self, key: K, value: V) !*KV {122 /// If there is an existing item with `key`, then the result
153 const res = try self.getOrPut(key);123 /// `Entry` pointer points to it, and found_existing is true.
154 if (!res.found_existing)124 /// Otherwise, puts a new item with undefined value, and
155 res.kv.value = value;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);
158 }196 }
159197
160 fn optimizedCapacity(expected_count: usize) usize {198 /// If there is an `Entry` with a matching key, it is deleted from
161 // ensure that the hash map will be at most 60% full if199 /// the hash map, and then returned from this function.
162 // expected_count items are put into it200 pub fn remove(self: *Self, key: K) ?Entry {
163 var optimized_capacity = expected_count * 5 / 3;201 return self.unmanaged.remove(key);
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;
167 }202 }
168203
169 /// Increases capacity so that the hash map will be at most204 /// Asserts there is an `Entry` with matching key, deletes it from the hash map,
170 /// 60% full when expected_count items are put into it205 /// and discards it.
171 pub fn ensureCapacity(self: *Self, expected_count: usize) !void {206 pub fn removeAssertDiscard(self: *Self, key: K) void {
172 if (expected_count == 0) return;207 return self.unmanaged.removeAssertDiscard(key);
173 const optimized_capacity = optimizedCapacity(expected_count);
174 return self.ensureCapacityExact(optimized_capacity);
175 }208 }
176209
177 /// Sets the capacity to the new capacity if the new210 pub fn items(self: Self) []Entry {
178 /// capacity is greater than the current capacity.211 return self.unmanaged.items();
179 /// New capacity must be a power of two.212 }
180 fn ensureCapacityExact(self: *Self, new_capacity: usize) !void {213
181 // capacity must always be a power of two to allow for modulo214 pub fn clone(self: Self) !Self {
182 // optimization in the constrainIndex fn215 var other = try self.unmanaged.clone(self.allocator);
183 assert(math.isPowerOfTwo(new_capacity));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) {279 pub fn promote(self: Self, allocator: *Allocator) Managed {
186 return;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);
187 }290 }
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;332 /// If there is an existing item with `key`, then the result
190 try self.initCapacity(new_capacity);333 /// `Entry` pointer points to it, and found_existing is true.
191 self.incrementModificationCount();334 /// Otherwise, puts a new item with undefined value, and
192 if (old_entries.len > 0) {335 /// the `Entry` pointer points to it. Caller should then initialize
193 // dump all of the old elements into the new table336 /// the value (but not the key).
194 for (old_entries) |*old_entry| {337 /// If a new entry needs to be stored, this function asserts there
195 if (old_entry.used) {338 /// is enough capacity to store it.
196 self.internalPut(old_entry.kv.key).new_entry.kv.value = old_entry.kv.value;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 };
197 }349 }
198 }350 }
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;
200 }405 }
201 }406 }
202407
203 /// Returns the kv pair that was already there.408 /// Returns the number of total elements which may be present before it is
204 pub fn put(self: *Self, key: K, value: V) !?KV {409 /// no longer guaranteed that no allocations will be performed.
205 try self.autoCapacity();410 pub fn capacity(self: Self) usize {
206 return putAssumeCapacity(self, key, value);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);
207 }415 }
208416
209 /// Calls put() and asserts that no kv pair is clobbered.417 /// Clobbers any existing data. To detect if a put would clobber
210 pub fn putNoClobber(self: *Self, key: K, value: V) !void {418 /// existing data, see `getOrPut`.
211 assert((try self.put(key, value)) == null);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;
212 }422 }
213423
214 pub fn putAssumeCapacity(self: *Self, key: K, value: V) ?KV {424 /// Inserts a key-value pair into the hash map, asserting that no previous
215 assert(self.count() < self.entries.len);425 /// entry with the same key is already present
216 self.incrementModificationCount();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);432 /// Asserts there is enough capacity to store the new key-value pair.
219 put_result.new_entry.kv.value = value;433 /// Clobbers any existing data. To detect if a put would clobber
220 return put_result.old_kv;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;
221 }438 }
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`.
223 pub fn putAssumeCapacityNoClobber(self: *Self, key: K, value: V) void {443 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;
225 }447 }
226448
227 pub fn get(hm: *const Self, key: K) ?*KV {449 /// Inserts a new `Entry` into the hash map, returning the previous one, if any.
228 if (hm.entries.len == 0) {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 }
229 return null;481 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),
230 }489 }
231 return hm.internalGet(key);
232 }490 }
233491
234 pub fn getValue(hm: *const Self, key: K) ?V {492 pub fn get(self: Self, key: K) ?V {
235 return if (hm.get(key)) |kv| kv.value else null;493 return if (self.getEntry(key)) |entry| entry.value else null;
236 }494 }
237495
238 pub fn contains(hm: *const Self, key: K) bool {496 pub fn contains(self: Self, key: K) bool {
239 return hm.get(key) != null;497 return self.getEntry(key) != null;
240 }498 }
241499
242 /// Returns any kv pair that was removed.500 /// If there is an `Entry` with a matching key, it is deleted from
243 pub fn remove(hm: *Self, key: K) ?KV {501 /// the hash map, and then returned from this function.
244 if (hm.entries.len == 0) return null;502 pub fn remove(self: *Self, key: K) ?Entry {
245 hm.incrementModificationCount();503 const header = self.index_header orelse {
246 const start_index = hm.keyToIndex(key);504 // Linear scan.
247 {505 const h = if (store_hash) hash(key) else {};
248 var roll_over: usize = 0;506 for (self.entries.items) |item, i| {
249 while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {507 if (item.hash == h and eql(key, item.key)) {
250 const index = hm.constrainIndex(start_index + roll_over);508 return self.entries.swapRemove(i);
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;
269 }509 }
270 unreachable; // shifting everything in the table
271 }510 }
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),
272 }518 }
273 return null;
274 }519 }
275520
276 /// Calls remove(), asserts that a kv pair is removed, and discards it.521 /// Asserts there is an `Entry` with matching key, deletes it from the hash map,
277 pub fn removeAssertDiscard(hm: *Self, key: K) void {522 /// and discards it.
278 assert(hm.remove(key) != null);523 pub fn removeAssertDiscard(self: *Self, key: K) void {
524 assert(self.remove(key) != null);
279 }525 }
280526
281 pub fn iterator(hm: *const Self) Iterator {527 pub fn items(self: Self) []Entry {
282 return Iterator{528 return self.entries.items;
283 .hm = hm,
284 .count = 0,
285 .index = 0,
286 .initial_modification_count = hm.modification_count,
287 };
288 }529 }
289530
290 pub fn clone(self: Self) !Self {531 pub fn clone(self: Self, allocator: *Allocator) !Self {
291 var other = Self.init(self.allocator);532 // TODO this can be made more efficient by directly allocating
292 try other.initCapacity(self.entries.len);533 // the memory slices and memcpying the elements.
293 var it = self.iterator();534 var other = Self.init();
294 while (it.next()) |entry| {535 try other.initCapacity(allocator, self.entries.len);
295 try other.putNoClobber(entry.key, entry.value);536 for (self.entries.items) |entry| {
537 other.putAssumeCapacityNoClobber(entry.key, entry.value);
296 }538 }
297 return other;539 return other;
298 }540 }
299541
300 fn autoCapacity(self: *Self) !void {542 fn removeInternal(self: *Self, key: K, header: *IndexHeader, comptime I: type) ?Entry {
301 if (self.entries.len == 0) {543 const indexes = header.indexes(I);
302 return self.ensureCapacityExact(16);544 const h = hash(key);
303 }545 const start_index = header.constrainIndex(h);
304 // if we get too full (60%), double the capacity546 var roll_over: usize = 0;
305 if (self.size * 5 >= self.entries.len * 3) {547 while (roll_over <= header.max_distance_from_start_index) : (roll_over += 1) {
306 return self.ensureCapacityExact(self.entries.len * 2);548 const index_index = header.constrainIndex(start_index + roll_over);
307 }549 var index = &indexes[index_index];
308 }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 {566 // Now we have to shift over the following indexes.
311 hm.entries = try hm.allocator.alloc(Entry, capacity);567 roll_over += 1;
312 hm.size = 0;568 while (roll_over < header.indexes_len) : (roll_over += 1) {
313 hm.max_distance_from_start_index = 0;569 const next_index_index = header.constrainIndex(start_index + roll_over);
314 for (hm.entries) |*entry| {570 const next_index = &indexes[next_index_index];
315 entry.used = false;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;
316 }580 }
581 return null;
317 }582 }
318583
319 fn incrementModificationCount(hm: *Self) void {584 fn updateEntryIndex(
320 if (want_modification_safety) {585 self: *Self,
321 hm.modification_count +%= 1;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 }
322 }602 }
603 unreachable;
323 }604 }
324605
325 const InternalPutResult = struct {606 /// Must ensureCapacity before calling this.
326 new_entry: *Entry,607 fn getOrPutInternal(self: *Self, key: K, header: *IndexHeader, comptime I: type) GetOrPutResult {
327 old_kv: ?KV,608 const indexes = header.indexes(I);
328 };609 const h = hash(key);
329610 const start_index = header.constrainIndex(h);
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);
336 var roll_over: usize = 0;611 var roll_over: usize = 0;
337 var distance_from_start_index: usize = 0;612 var distance_from_start_index: usize = 0;
338 var got_result_entry = false;613 while (roll_over <= header.indexes_len) : ({
339 var result = InternalPutResult{
340 .new_entry = undefined,
341 .old_kv = null,
342 };
343 while (roll_over < self.entries.len) : ({
344 roll_over += 1;614 roll_over += 1;
345 distance_from_start_index += 1;615 distance_from_start_index += 1;
346 }) {616 }) {
347 const index = self.constrainIndex(start_index + roll_over);617 const index_index = header.constrainIndex(start_index + roll_over);
348 const entry = &self.entries[index];618 const index = indexes[index_index];
349619 if (index.isEmpty()) {
350 if (entry.used and !eql(entry.kv.key, key)) {620 indexes[index_index] = .{
351 if (entry.distance_from_start_index < distance_from_start_index) {621 .distance_from_start_index = @intCast(I, distance_from_start_index),
352 // robin hood to the rescue622 .entry_index = @intCast(I, self.entries.items.len),
353 const tmp = entry.*;623 };
354 self.max_distance_from_start_index = math.max(self.max_distance_from_start_index, distance_from_start_index);624 header.maybeBumpMax(distance_from_start_index);
355 if (!got_result_entry) {625 const new_entry = self.entries.addOneAssumeCapacity();
356 got_result_entry = true;626 new_entry.* = .{
357 result.new_entry = 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;
358 }696 }
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;
370 }697 }
371 continue;698 unreachable;
372 }699 }
700 }
701 unreachable;
702 }
373703
374 if (entry.used) {704 fn getInternal(self: Self, key: K, header: *IndexHeader, comptime I: type) ?*Entry {
375 result.old_kv = entry.kv;705 const indexes = header.indexes(I);
376 } else {706 const h = hash(key);
377 // adding an entry. otherwise overwriting old value with707 const start_index = header.constrainIndex(h);
378 // same key708 var roll_over: usize = 0;
379 self.size += 1;709 while (roll_over <= header.max_distance_from_start_index) : (roll_over += 1) {
380 }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);723 fn insertAllEntriesIntoNewHeader(self: *Self, header: *IndexHeader) void {
383 if (!got_result_entry) {724 switch (header.capacityIndexType()) {
384 result.new_entry = entry;725 .u8 => return self.insertAllEntriesIntoNewHeaderGeneric(header, u8),
385 }726 .u16 => return self.insertAllEntriesIntoNewHeaderGeneric(header, u16),
386 entry.* = Entry{727 .u32 => return self.insertAllEntriesIntoNewHeaderGeneric(header, u32),
387 .used = true,728 .usize => return self.insertAllEntriesIntoNewHeaderGeneric(header, usize),
388 .distance_from_start_index = distance_from_start_index,
389 .kv = KV{
390 .key = key,
391 .value = value,
392 },
393 };
394 return result;
395 }729 }
396 unreachable; // put into a full map
397 }730 }
398731
399 fn internalGet(hm: Self, key: K) ?*KV {732 fn insertAllEntriesIntoNewHeaderGeneric(self: *Self, header: *IndexHeader, comptime I: type) void {
400 const start_index = hm.keyToIndex(key);733 const indexes = header.indexes(I);
401 {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;
402 var roll_over: usize = 0;738 var roll_over: usize = 0;
403 while (roll_over <= hm.max_distance_from_start_index) : (roll_over += 1) {739 var distance_from_start_index: usize = 0;
404 const index = hm.constrainIndex(start_index + roll_over);740 while (roll_over < header.indexes_len) : ({
405 const entry = &hm.entries[index];741 roll_over += 1;
406742 distance_from_start_index += 1;
407 if (!entry.used) return null;743 }) {
408 if (eql(entry.kv.key, key)) return &entry.kv;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 }
409 }763 }
764 unreachable;
410 }765 }
411 return null;
412 }766 }
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 {782fn capacityIndexSize(indexes_len: usize) usize {
415 return hm.constrainIndex(@as(usize, hash(key)));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);
416 }805 }
417806
418 fn constrainIndex(hm: Self, i: usize) usize {807 fn setEmpty(idx: *Self) void {
419 // this is an optimization for modulo of power of two integers;808 idx.entry_index = math.maxInt(I);
420 // it requires hm.entries.len to always be a power of two
421 return i & (hm.entries.len - 1);
422 }809 }
423 };810 };
424}811}
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
426test "basic hash map usage" {861test "basic hash map usage" {
427 var map = AutoHashMap(i32, i32).init(std.testing.allocator);862 var map = AutoHashMap(i32, i32).init(std.testing.allocator);
428 defer map.deinit();863 defer map.deinit();
429864
430 testing.expect((try map.put(1, 11)) == null);865 testing.expect((try map.fetchPut(1, 11)) == null);
431 testing.expect((try map.put(2, 22)) == null);866 testing.expect((try map.fetchPut(2, 22)) == null);
432 testing.expect((try map.put(3, 33)) == null);867 testing.expect((try map.fetchPut(3, 33)) == null);
433 testing.expect((try map.put(4, 44)) == null);868 testing.expect((try map.fetchPut(4, 44)) == null);
434869
435 try map.putNoClobber(5, 55);870 try map.putNoClobber(5, 55);
436 testing.expect((try map.put(5, 66)).?.value == 55);871 testing.expect((try map.fetchPut(5, 66)).?.value == 55);
437 testing.expect((try map.put(5, 55)).?.value == 66);872 testing.expect((try map.fetchPut(5, 55)).?.value == 66);
438873
439 const gop1 = try map.getOrPut(5);874 const gop1 = try map.getOrPut(5);
440 testing.expect(gop1.found_existing == true);875 testing.expect(gop1.found_existing == true);
441 testing.expect(gop1.kv.value == 55);876 testing.expect(gop1.entry.value == 55);
442 gop1.kv.value = 77;877 gop1.entry.value = 77;
443 testing.expect(map.get(5).?.value == 77);878 testing.expect(map.getEntry(5).?.value == 77);
444879
445 const gop2 = try map.getOrPut(99);880 const gop2 = try map.getOrPut(99);
446 testing.expect(gop2.found_existing == false);881 testing.expect(gop2.found_existing == false);
447 gop2.kv.value = 42;882 gop2.entry.value = 42;
448 testing.expect(map.get(99).?.value == 42);883 testing.expect(map.getEntry(99).?.value == 42);
449884
450 const gop3 = try map.getOrPutValue(5, 5);885 const gop3 = try map.getOrPutValue(5, 5);
451 testing.expect(gop3.value == 77);886 testing.expect(gop3.value == 77);
...@@ -454,15 +889,15 @@ test "basic hash map usage" {...@@ -454,15 +889,15 @@ test "basic hash map usage" {
454 testing.expect(gop4.value == 41);889 testing.expect(gop4.value == 41);
455890
456 testing.expect(map.contains(2));891 testing.expect(map.contains(2));
457 testing.expect(map.get(2).?.value == 22);892 testing.expect(map.getEntry(2).?.value == 22);
458 testing.expect(map.getValue(2).? == 22);893 testing.expect(map.get(2).? == 22);
459894
460 const rmv1 = map.remove(2);895 const rmv1 = map.remove(2);
461 testing.expect(rmv1.?.key == 2);896 testing.expect(rmv1.?.key == 2);
462 testing.expect(rmv1.?.value == 22);897 testing.expect(rmv1.?.value == 22);
463 testing.expect(map.remove(2) == null);898 testing.expect(map.remove(2) == null);
899 testing.expect(map.getEntry(2) == null);
464 testing.expect(map.get(2) == null);900 testing.expect(map.get(2) == null);
465 testing.expect(map.getValue(2) == null);
466901
467 map.removeAssertDiscard(3);902 map.removeAssertDiscard(3);
468}903}
...@@ -498,8 +933,8 @@ test "iterator hash map" {...@@ -498,8 +933,8 @@ test "iterator hash map" {
498 it.reset();933 it.reset();
499934
500 var count: usize = 0;935 var count: usize = 0;
501 while (it.next()) |kv| : (count += 1) {936 while (it.next()) |entry| : (count += 1) {
502 buffer[@intCast(usize, kv.key)] = kv.value;937 buffer[@intCast(usize, entry.key)] = entry.value;
503 }938 }
504 testing.expect(count == 3);939 testing.expect(count == 3);
505 testing.expect(it.next() == null);940 testing.expect(it.next() == null);
...@@ -510,8 +945,8 @@ test "iterator hash map" {...@@ -510,8 +945,8 @@ test "iterator hash map" {
510945
511 it.reset();946 it.reset();
512 count = 0;947 count = 0;
513 while (it.next()) |kv| {948 while (it.next()) |entry| {
514 buffer[@intCast(usize, kv.key)] = kv.value;949 buffer[@intCast(usize, entry.key)] = entry.value;
515 count += 1;950 count += 1;
516 if (count >= 2) break;951 if (count >= 2) break;
517 }952 }
...@@ -531,14 +966,14 @@ test "ensure capacity" {...@@ -531,14 +966,14 @@ test "ensure capacity" {
531 defer map.deinit();966 defer map.deinit();
532967
533 try map.ensureCapacity(20);968 try map.ensureCapacity(20);
534 const initialCapacity = map.entries.len;969 const initial_capacity = map.capacity();
535 testing.expect(initialCapacity >= 20);970 testing.expect(initial_capacity >= 20);
536 var i: i32 = 0;971 var i: i32 = 0;
537 while (i < 20) : (i += 1) {972 while (i < 20) : (i += 1) {
538 testing.expect(map.putAssumeCapacity(i, i + 10) == null);973 testing.expect(map.fetchPutAssumeCapacity(i, i + 10) == null);
539 }974 }
540 // shouldn't resize from putAssumeCapacity975 // shouldn't resize from putAssumeCapacity
541 testing.expect(initialCapacity == map.entries.len);976 testing.expect(initial_capacity == map.capacity());
542}977}
543978
544pub fn getHashPtrAddrFn(comptime K: type) (fn (K) u32) {979pub fn getHashPtrAddrFn(comptime K: type) (fn (K) u32) {
...@@ -575,6 +1010,24 @@ pub fn getAutoEqlFn(comptime K: type) (fn (K, K) bool) {...@@ -575,6 +1010,24 @@ pub fn getAutoEqlFn(comptime K: type) (fn (K, K) bool) {
575 }.eql;1010 }.eql;
576}1011}
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
578pub fn getAutoHashStratFn(comptime K: type, comptime strategy: std.hash.Strategy) (fn (K) u32) {1031pub fn getAutoHashStratFn(comptime K: type, comptime strategy: std.hash.Strategy) (fn (K) u32) {
579 return struct {1032 return struct {
580 fn hash(key: K) u32 {1033 fn hash(key: K) u32 {
lib/std/http/headers.zig+35-37
...@@ -118,13 +118,12 @@ pub const Headers = struct {...@@ -118,13 +118,12 @@ pub const Headers = struct {
118 };118 };
119 }119 }
120120
121 pub fn deinit(self: Self) void {121 pub fn deinit(self: *Self) void {
122 {122 {
123 var it = self.index.iterator();123 for (self.index.items()) |*entry| {
124 while (it.next()) |kv| {124 const dex = &entry.value;
125 var dex = &kv.value;
126 dex.deinit();125 dex.deinit();
127 self.allocator.free(kv.key);126 self.allocator.free(entry.key);
128 }127 }
129 self.index.deinit();128 self.index.deinit();
130 }129 }
...@@ -134,6 +133,7 @@ pub const Headers = struct {...@@ -134,6 +133,7 @@ pub const Headers = struct {
134 }133 }
135 self.data.deinit();134 self.data.deinit();
136 }135 }
136 self.* = undefined;
137 }137 }
138138
139 pub fn clone(self: Self, allocator: *Allocator) !Self {139 pub fn clone(self: Self, allocator: *Allocator) !Self {
...@@ -155,10 +155,10 @@ pub const Headers = struct {...@@ -155,10 +155,10 @@ pub const Headers = struct {
155 const n = self.data.items.len + 1;155 const n = self.data.items.len + 1;
156 try self.data.ensureCapacity(n);156 try self.data.ensureCapacity(n);
157 var entry: HeaderEntry = undefined;157 var entry: HeaderEntry = undefined;
158 if (self.index.get(name)) |kv| {158 if (self.index.getEntry(name)) |kv| {
159 entry = try HeaderEntry.init(self.allocator, kv.key, value, never_index);159 entry = try HeaderEntry.init(self.allocator, kv.key, value, never_index);
160 errdefer entry.deinit();160 errdefer entry.deinit();
161 var dex = &kv.value;161 const dex = &kv.value;
162 try dex.append(n - 1);162 try dex.append(n - 1);
163 } else {163 } else {
164 const name_dup = try self.allocator.dupe(u8, name);164 const name_dup = try self.allocator.dupe(u8, name);
...@@ -195,7 +195,7 @@ pub const Headers = struct {...@@ -195,7 +195,7 @@ pub const Headers = struct {
195 /// Returns boolean indicating if something was deleted.195 /// Returns boolean indicating if something was deleted.
196 pub fn delete(self: *Self, name: []const u8) bool {196 pub fn delete(self: *Self, name: []const u8) bool {
197 if (self.index.remove(name)) |kv| {197 if (self.index.remove(name)) |kv| {
198 var dex = &kv.value;198 const dex = &kv.value;
199 // iterate backwards199 // iterate backwards
200 var i = dex.items.len;200 var i = dex.items.len;
201 while (i > 0) {201 while (i > 0) {
...@@ -207,7 +207,7 @@ pub const Headers = struct {...@@ -207,7 +207,7 @@ pub const Headers = struct {
207 }207 }
208 dex.deinit();208 dex.deinit();
209 self.allocator.free(kv.key);209 self.allocator.free(kv.key);
210 self.rebuild_index();210 self.rebuildIndex();
211 return true;211 return true;
212 } else {212 } else {
213 return false;213 return false;
...@@ -216,45 +216,52 @@ pub const Headers = struct {...@@ -216,45 +216,52 @@ pub const Headers = struct {
216216
217 /// Removes the element at the specified index.217 /// Removes the element at the specified index.
218 /// Moves items down to fill the empty space.218 /// 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.
219 pub fn orderedRemove(self: *Self, i: usize) void {222 pub fn orderedRemove(self: *Self, i: usize) void {
220 const removed = self.data.orderedRemove(i);223 const removed = self.data.orderedRemove(i);
221 const kv = self.index.get(removed.name).?;224 const kv = self.index.getEntry(removed.name).?;
222 var dex = &kv.value;225 const dex = &kv.value;
223 if (dex.items.len == 1) {226 if (dex.items.len == 1) {
224 // was last item; delete the index227 // was last item; delete the index
225 _ = self.index.remove(kv.key);
226 dex.deinit();228 dex.deinit();
227 removed.deinit();229 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);
229 } else {233 } else {
230 dex.shrink(dex.items.len - 1);234 dex.shrink(dex.items.len - 1);
231 removed.deinit();235 removed.deinit();
232 }236 }
233 // if it was the last item; no need to rebuild index237 // if it was the last item; no need to rebuild index
234 if (i != self.data.items.len) {238 if (i != self.data.items.len) {
235 self.rebuild_index();239 self.rebuildIndex();
236 }240 }
237 }241 }
238242
239 /// Removes the element at the specified index.243 /// Removes the element at the specified index.
240 /// The empty slot is filled from the end of the list.244 /// 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.
241 pub fn swapRemove(self: *Self, i: usize) void {247 pub fn swapRemove(self: *Self, i: usize) void {
242 const removed = self.data.swapRemove(i);248 const removed = self.data.swapRemove(i);
243 const kv = self.index.get(removed.name).?;249 const kv = self.index.getEntry(removed.name).?;
244 var dex = &kv.value;250 const dex = &kv.value;
245 if (dex.items.len == 1) {251 if (dex.items.len == 1) {
246 // was last item; delete the index252 // was last item; delete the index
247 _ = self.index.remove(kv.key);
248 dex.deinit();253 dex.deinit();
249 removed.deinit();254 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);
251 } else {258 } else {
252 dex.shrink(dex.items.len - 1);259 dex.shrink(dex.items.len - 1);
253 removed.deinit();260 removed.deinit();
254 }261 }
255 // if it was the last item; no need to rebuild index262 // if it was the last item; no need to rebuild index
256 if (i != self.data.items.len) {263 if (i != self.data.items.len) {
257 self.rebuild_index();264 self.rebuildIndex();
258 }265 }
259 }266 }
260267
...@@ -266,11 +273,7 @@ pub const Headers = struct {...@@ -266,11 +273,7 @@ pub const Headers = struct {
266 /// Returns a list of indices containing headers with the given name.273 /// Returns a list of indices containing headers with the given name.
267 /// The returned list should not be modified by the caller.274 /// The returned list should not be modified by the caller.
268 pub fn getIndices(self: Self, name: []const u8) ?HeaderIndexList {275 pub fn getIndices(self: Self, name: []const u8) ?HeaderIndexList {
269 if (self.index.get(name)) |kv| {276 return self.index.get(name);
270 return kv.value;
271 } else {
272 return null;
273 }
274 }277 }
275278
276 /// Returns a slice containing each header with the given name.279 /// Returns a slice containing each header with the given name.
...@@ -325,25 +328,20 @@ pub const Headers = struct {...@@ -325,25 +328,20 @@ pub const Headers = struct {
325 return buf;328 return buf;
326 }329 }
327330
328 fn rebuild_index(self: *Self) void {331 fn rebuildIndex(self: *Self) void {
329 { // clear out the indexes332 // clear out the indexes
330 var it = self.index.iterator();333 for (self.index.items()) |*entry| {
331 while (it.next()) |kv| {334 entry.value.shrinkRetainingCapacity(0);
332 var dex = &kv.value;
333 dex.items.len = 0; // keeps capacity available
334 }
335 }335 }
336 { // fill up indexes again; we know capacity is fine from before336 // fill up indexes again; we know capacity is fine from before
337 for (self.data.span()) |entry, i| {337 for (self.data.items) |entry, i| {
338 var dex = &self.index.get(entry.name).?.value;338 self.index.getEntry(entry.name).?.value.appendAssumeCapacity(i);
339 dex.appendAssumeCapacity(i);
340 }
341 }339 }
342 }340 }
343341
344 pub fn sort(self: *Self) void {342 pub fn sort(self: *Self) void {
345 std.sort.sort(HeaderEntry, self.data.items, {}, HeaderEntry.compare);343 std.sort.sort(HeaderEntry, self.data.items, {}, HeaderEntry.compare);
346 self.rebuild_index();344 self.rebuildIndex();
347 }345 }
348346
349 pub fn format(347 pub fn format(
lib/std/json.zig+28-28
...@@ -2149,27 +2149,27 @@ test "json.parser.dynamic" {...@@ -2149,27 +2149,27 @@ test "json.parser.dynamic" {
21492149
2150 var root = tree.root;2150 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").?;
2155 testing.expect(width.Integer == 800);2155 testing.expect(width.Integer == 800);
21562156
2157 const height = image.Object.get("Height").?.value;2157 const height = image.Object.get("Height").?;
2158 testing.expect(height.Integer == 600);2158 testing.expect(height.Integer == 600);
21592159
2160 const title = image.Object.get("Title").?.value;2160 const title = image.Object.get("Title").?;
2161 testing.expect(mem.eql(u8, title.String, "View from 15th Floor"));2161 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").?;
2164 testing.expect(animated.Bool == false);2164 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").?;
2167 testing.expect(array_of_object.Array.items.len == 1);2167 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").?;
2170 testing.expect(mem.eql(u8, obj0.String, "m"));2170 testing.expect(mem.eql(u8, obj0.String, "m"));
21712171
2172 const double = image.Object.get("double").?.value;2172 const double = image.Object.get("double").?;
2173 testing.expect(double.Float == 1.3412);2173 testing.expect(double.Float == 1.3412);
2174}2174}
21752175
...@@ -2217,12 +2217,12 @@ test "write json then parse it" {...@@ -2217,12 +2217,12 @@ test "write json then parse it" {
2217 var tree = try parser.parse(fixed_buffer_stream.getWritten());2217 var tree = try parser.parse(fixed_buffer_stream.getWritten());
2218 defer tree.deinit();2218 defer tree.deinit();
22192219
2220 testing.expect(tree.root.Object.get("f").?.value.Bool == false);2220 testing.expect(tree.root.Object.get("f").?.Bool == false);
2221 testing.expect(tree.root.Object.get("t").?.value.Bool == true);2221 testing.expect(tree.root.Object.get("t").?.Bool == true);
2222 testing.expect(tree.root.Object.get("int").?.value.Integer == 1234);2222 testing.expect(tree.root.Object.get("int").?.Integer == 1234);
2223 testing.expect(tree.root.Object.get("array").?.value.Array.items[0].Null == {});2223 testing.expect(tree.root.Object.get("array").?.Array.items[0].Null == {});
2224 testing.expect(tree.root.Object.get("array").?.value.Array.items[1].Float == 12.34);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").?.value.String, "hello"));2225 testing.expect(mem.eql(u8, tree.root.Object.get("str").?.String, "hello"));
2226}2226}
22272227
2228fn test_parse(arena_allocator: *std.mem.Allocator, json_str: []const u8) !Value {2228fn test_parse(arena_allocator: *std.mem.Allocator, json_str: []const u8) !Value {
...@@ -2245,7 +2245,7 @@ test "integer after float has proper type" {...@@ -2245,7 +2245,7 @@ test "integer after float has proper type" {
2245 \\ "ints": [1, 2, 3]2245 \\ "ints": [1, 2, 3]
2246 \\}2246 \\}
2247 );2247 );
2248 std.testing.expect(json.Object.getValue("ints").?.Array.items[0] == .Integer);2248 std.testing.expect(json.Object.get("ints").?.Array.items[0] == .Integer);
2249}2249}
22502250
2251test "escaped characters" {2251test "escaped characters" {
...@@ -2271,16 +2271,16 @@ test "escaped characters" {...@@ -2271,16 +2271,16 @@ test "escaped characters" {
22712271
2272 const obj = (try test_parse(&arena_allocator.allocator, input)).Object;2272 const obj = (try test_parse(&arena_allocator.allocator, input)).Object;
22732273
2274 testing.expectEqualSlices(u8, obj.get("backslash").?.value.String, "\\");2274 testing.expectEqualSlices(u8, obj.get("backslash").?.String, "\\");
2275 testing.expectEqualSlices(u8, obj.get("forwardslash").?.value.String, "/");2275 testing.expectEqualSlices(u8, obj.get("forwardslash").?.String, "/");
2276 testing.expectEqualSlices(u8, obj.get("newline").?.value.String, "\n");2276 testing.expectEqualSlices(u8, obj.get("newline").?.String, "\n");
2277 testing.expectEqualSlices(u8, obj.get("carriagereturn").?.value.String, "\r");2277 testing.expectEqualSlices(u8, obj.get("carriagereturn").?.String, "\r");
2278 testing.expectEqualSlices(u8, obj.get("tab").?.value.String, "\t");2278 testing.expectEqualSlices(u8, obj.get("tab").?.String, "\t");
2279 testing.expectEqualSlices(u8, obj.get("formfeed").?.value.String, "\x0C");2279 testing.expectEqualSlices(u8, obj.get("formfeed").?.String, "\x0C");
2280 testing.expectEqualSlices(u8, obj.get("backspace").?.value.String, "\x08");2280 testing.expectEqualSlices(u8, obj.get("backspace").?.String, "\x08");
2281 testing.expectEqualSlices(u8, obj.get("doublequote").?.value.String, "\"");2281 testing.expectEqualSlices(u8, obj.get("doublequote").?.String, "\"");
2282 testing.expectEqualSlices(u8, obj.get("unicode").?.value.String, "ą");2282 testing.expectEqualSlices(u8, obj.get("unicode").?.String, "ą");
2283 testing.expectEqualSlices(u8, obj.get("surrogatepair").?.value.String, "😂");2283 testing.expectEqualSlices(u8, obj.get("surrogatepair").?.String, "😂");
2284}2284}
22852285
2286test "string copy option" {2286test "string copy option" {
...@@ -2306,11 +2306,11 @@ test "string copy option" {...@@ -2306,11 +2306,11 @@ test "string copy option" {
2306 const obj_copy = tree_copy.root.Object;2306 const obj_copy = tree_copy.root.Object;
23072307
2308 for ([_][]const u8{ "noescape", "simple", "unicode", "surrogatepair" }) |field_name| {2308 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);
2310 }2310 }
23112311
2312 const nocopy_addr = &obj_nocopy.getValue("noescape").?.String[0];2312 const nocopy_addr = &obj_nocopy.get("noescape").?.String[0];
2313 const copy_addr = &obj_copy.getValue("noescape").?.String[0];2313 const copy_addr = &obj_copy.get("noescape").?.String[0];
23142314
2315 var found_nocopy = false;2315 var found_nocopy = false;
2316 for (input) |_, index| {2316 for (input) |_, index| {
src-self-hosted/Module.zig+83-114
...@@ -75,7 +75,7 @@ deletion_set: std.ArrayListUnmanaged(*Decl) = .{},...@@ -75,7 +75,7 @@ deletion_set: std.ArrayListUnmanaged(*Decl) = .{},
7575
76keep_source_files_loaded: bool,76keep_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
80const WorkItem = union(enum) {80const WorkItem = union(enum) {
81 /// Write the machine code for a Decl to the output file.81 /// Write the machine code for a Decl to the output file.
...@@ -795,49 +795,38 @@ pub fn deinit(self: *Module) void {...@@ -795,49 +795,38 @@ pub fn deinit(self: *Module) void {
795 const allocator = self.allocator;795 const allocator = self.allocator;
796 self.deletion_set.deinit(allocator);796 self.deletion_set.deinit(allocator);
797 self.work_queue.deinit();797 self.work_queue.deinit();
798 {798
799 var it = self.decl_table.iterator();799 for (self.decl_table.items()) |entry| {
800 while (it.next()) |kv| {800 entry.value.destroy(allocator);
801 kv.value.destroy(allocator);
802 }
803 self.decl_table.deinit();
804 }801 }
805 {802 self.decl_table.deinit();
806 var it = self.failed_decls.iterator();803
807 while (it.next()) |kv| {804 for (self.failed_decls.items()) |entry| {
808 kv.value.destroy(allocator);805 entry.value.destroy(allocator);
809 }
810 self.failed_decls.deinit();
811 }806 }
812 {807 self.failed_decls.deinit();
813 var it = self.failed_files.iterator();808
814 while (it.next()) |kv| {809 for (self.failed_files.items()) |entry| {
815 kv.value.destroy(allocator);810 entry.value.destroy(allocator);
816 }
817 self.failed_files.deinit();
818 }811 }
819 {812 self.failed_files.deinit();
820 var it = self.failed_exports.iterator();813
821 while (it.next()) |kv| {814 for (self.failed_exports.items()) |entry| {
822 kv.value.destroy(allocator);815 entry.value.destroy(allocator);
823 }
824 self.failed_exports.deinit();
825 }816 }
826 {817 self.failed_exports.deinit();
827 var it = self.decl_exports.iterator();818
828 while (it.next()) |kv| {819 for (self.decl_exports.items()) |entry| {
829 const export_list = kv.value;820 const export_list = entry.value;
830 allocator.free(export_list);821 allocator.free(export_list);
831 }
832 self.decl_exports.deinit();
833 }822 }
834 {823 self.decl_exports.deinit();
835 var it = self.export_owners.iterator();824
836 while (it.next()) |kv| {825 for (self.export_owners.items()) |entry| {
837 freeExportList(allocator, kv.value);826 freeExportList(allocator, entry.value);
838 }
839 self.export_owners.deinit();
840 }827 }
828 self.export_owners.deinit();
829
841 self.symbol_exports.deinit();830 self.symbol_exports.deinit();
842 self.root_scope.destroy(allocator);831 self.root_scope.destroy(allocator);
843 self.* = undefined;832 self.* = undefined;
...@@ -918,9 +907,9 @@ pub fn makeBinFileWritable(self: *Module) !void {...@@ -918,9 +907,9 @@ pub fn makeBinFileWritable(self: *Module) !void {
918}907}
919908
920pub fn totalErrorCount(self: *Module) usize {909pub fn totalErrorCount(self: *Module) usize {
921 const total = self.failed_decls.size +910 const total = self.failed_decls.items().len +
922 self.failed_files.size +911 self.failed_files.items().len +
923 self.failed_exports.size;912 self.failed_exports.items().len;
924 return if (total == 0) @boolToInt(self.link_error_flags.no_entry_point_found) else total;913 return if (total == 0) @boolToInt(self.link_error_flags.no_entry_point_found) else total;
925}914}
926915
...@@ -931,32 +920,23 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {...@@ -931,32 +920,23 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
931 var errors = std.ArrayList(AllErrors.Message).init(self.allocator);920 var errors = std.ArrayList(AllErrors.Message).init(self.allocator);
932 defer errors.deinit();921 defer errors.deinit();
933922
934 {923 for (self.failed_files.items()) |entry| {
935 var it = self.failed_files.iterator();924 const scope = entry.key;
936 while (it.next()) |kv| {925 const err_msg = entry.value;
937 const scope = kv.key;926 const source = try scope.getSource(self);
938 const err_msg = kv.value;927 try AllErrors.add(&arena, &errors, scope.subFilePath(), source, err_msg.*);
939 const source = try scope.getSource(self);
940 try AllErrors.add(&arena, &errors, scope.subFilePath(), source, err_msg.*);
941 }
942 }928 }
943 {929 for (self.failed_decls.items()) |entry| {
944 var it = self.failed_decls.iterator();930 const decl = entry.key;
945 while (it.next()) |kv| {931 const err_msg = entry.value;
946 const decl = kv.key;932 const source = try decl.scope.getSource(self);
947 const err_msg = kv.value;933 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
948 const source = try decl.scope.getSource(self);
949 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
950 }
951 }934 }
952 {935 for (self.failed_exports.items()) |entry| {
953 var it = self.failed_exports.iterator();936 const decl = entry.key.owner_decl;
954 while (it.next()) |kv| {937 const err_msg = entry.value;
955 const decl = kv.key.owner_decl;938 const source = try decl.scope.getSource(self);
956 const err_msg = kv.value;939 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
957 const source = try decl.scope.getSource(self);
958 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
959 }
960 }940 }
961941
962 if (errors.items.len == 0 and self.link_error_flags.no_entry_point_found) {942 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 {...@@ -1016,7 +996,7 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
1016 decl.analysis = .dependency_failure;996 decl.analysis = .dependency_failure;
1017 },997 },
1018 else => {998 else => {
1019 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);999 try self.failed_decls.ensureCapacity(self.failed_decls.items().len + 1);
1020 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(1000 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
1021 self.allocator,1001 self.allocator,
1022 decl.src(),1002 decl.src(),
...@@ -1086,7 +1066,7 @@ fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {...@@ -1086,7 +1066,7 @@ fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {
1086 error.OutOfMemory => return error.OutOfMemory,1066 error.OutOfMemory => return error.OutOfMemory,
1087 error.AnalysisFail => return error.AnalysisFail,1067 error.AnalysisFail => return error.AnalysisFail,
1088 else => {1068 else => {
1089 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);1069 try self.failed_decls.ensureCapacity(self.failed_decls.items().len + 1);
1090 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(1070 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
1091 self.allocator,1071 self.allocator,
1092 decl.src(),1072 decl.src(),
...@@ -1636,7 +1616,7 @@ fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void...@@ -1636,7 +1616,7 @@ fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void
1636fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {1616fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
1637 switch (root_scope.status) {1617 switch (root_scope.status) {
1638 .never_loaded, .unloaded_success => {1618 .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
1641 const source = try root_scope.getSource(self);1621 const source = try root_scope.getSource(self);
16421622
...@@ -1677,7 +1657,7 @@ fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree {...@@ -1677,7 +1657,7 @@ fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree {
16771657
1678 switch (root_scope.status) {1658 switch (root_scope.status) {
1679 .never_loaded, .unloaded_success => {1659 .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
1682 const source = try root_scope.getSource(self);1662 const source = try root_scope.getSource(self);
16831663
...@@ -1745,8 +1725,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {...@@ -1745,8 +1725,7 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
1745 const name = tree.tokenSliceLoc(name_loc);1725 const name = tree.tokenSliceLoc(name_loc);
1746 const name_hash = root_scope.fullyQualifiedNameHash(name);1726 const name_hash = root_scope.fullyQualifiedNameHash(name);
1747 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));1727 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
1748 if (self.decl_table.get(name_hash)) |kv| {1728 if (self.decl_table.get(name_hash)) |decl| {
1749 const decl = kv.value;
1750 // Update the AST Node index of the decl, even if its contents are unchanged, it may1729 // Update the AST Node index of the decl, even if its contents are unchanged, it may
1751 // have been re-ordered.1730 // have been re-ordered.
1752 decl.src_index = decl_i;1731 decl.src_index = decl_i;
...@@ -1774,14 +1753,11 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {...@@ -1774,14 +1753,11 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
1774 // TODO also look for global variable declarations1753 // TODO also look for global variable declarations
1775 // TODO also look for comptime blocks and exported globals1754 // TODO also look for comptime blocks and exported globals
1776 }1755 }
1777 {1756 // Handle explicitly deleted decls from the source code. Not to be confused
1778 // Handle explicitly deleted decls from the source code. Not to be confused1757 // with when we delete decls because they are no longer referenced.
1779 // with when we delete decls because they are no longer referenced.1758 for (deleted_decls.items()) |entry| {
1780 var it = deleted_decls.iterator();1759 //std.debug.warn("noticed '{}' deleted from source\n", .{entry.key.name});
1781 while (it.next()) |kv| {1760 try self.deleteDecl(entry.key);
1782 //std.debug.warn("noticed '{}' deleted from source\n", .{kv.key.name});
1783 try self.deleteDecl(kv.key);
1784 }
1785 }1761 }
1786}1762}
17871763
...@@ -1800,18 +1776,14 @@ fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void {...@@ -1800,18 +1776,14 @@ fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void {
1800 // we know which ones have been deleted.1776 // we know which ones have been deleted.
1801 var deleted_decls = std.AutoHashMap(*Decl, void).init(self.allocator);1777 var deleted_decls = std.AutoHashMap(*Decl, void).init(self.allocator);
1802 defer deleted_decls.deinit();1778 defer deleted_decls.deinit();
1803 try deleted_decls.ensureCapacity(self.decl_table.size);1779 try deleted_decls.ensureCapacity(self.decl_table.items().len);
1804 {1780 for (self.decl_table.items()) |entry| {
1805 var it = self.decl_table.iterator();1781 deleted_decls.putAssumeCapacityNoClobber(entry.value, {});
1806 while (it.next()) |kv| {
1807 deleted_decls.putAssumeCapacityNoClobber(kv.value, {});
1808 }
1809 }1782 }
18101783
1811 for (src_module.decls) |src_decl, decl_i| {1784 for (src_module.decls) |src_decl, decl_i| {
1812 const name_hash = root_scope.fullyQualifiedNameHash(src_decl.name);1785 const name_hash = root_scope.fullyQualifiedNameHash(src_decl.name);
1813 if (self.decl_table.get(name_hash)) |kv| {1786 if (self.decl_table.get(name_hash)) |decl| {
1814 const decl = kv.value;
1815 deleted_decls.removeAssertDiscard(decl);1787 deleted_decls.removeAssertDiscard(decl);
1816 //std.debug.warn("'{}' contents: '{}'\n", .{ src_decl.name, src_decl.contents });1788 //std.debug.warn("'{}' contents: '{}'\n", .{ src_decl.name, src_decl.contents });
1817 if (!srcHashEql(src_decl.contents_hash, decl.contents_hash)) {1789 if (!srcHashEql(src_decl.contents_hash, decl.contents_hash)) {
...@@ -1835,14 +1807,11 @@ fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void {...@@ -1835,14 +1807,11 @@ fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void {
1835 for (exports_to_resolve.items) |export_decl| {1807 for (exports_to_resolve.items) |export_decl| {
1836 _ = try self.resolveZirDecl(&root_scope.base, export_decl);1808 _ = try self.resolveZirDecl(&root_scope.base, export_decl);
1837 }1809 }
1838 {1810 // Handle explicitly deleted decls from the source code. Not to be confused
1839 // Handle explicitly deleted decls from the source code. Not to be confused1811 // with when we delete decls because they are no longer referenced.
1840 // with when we delete decls because they are no longer referenced.1812 for (deleted_decls.items()) |entry| {
1841 var it = deleted_decls.iterator();1813 //std.debug.warn("noticed '{}' deleted from source\n", .{entry.key.name});
1842 while (it.next()) |kv| {1814 try self.deleteDecl(entry.key);
1843 //std.debug.warn("noticed '{}' deleted from source\n", .{kv.key.name});
1844 try self.deleteDecl(kv.key);
1845 }
1846 }1815 }
1847}1816}
18481817
...@@ -1888,7 +1857,7 @@ fn deleteDeclExports(self: *Module, decl: *Decl) void {...@@ -1888,7 +1857,7 @@ fn deleteDeclExports(self: *Module, decl: *Decl) void {
1888 const kv = self.export_owners.remove(decl) orelse return;1857 const kv = self.export_owners.remove(decl) orelse return;
18891858
1890 for (kv.value) |exp| {1859 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| {
1892 // Remove exports with owner_decl matching the regenerating decl.1861 // Remove exports with owner_decl matching the regenerating decl.
1893 const list = decl_exports_kv.value;1862 const list = decl_exports_kv.value;
1894 var i: usize = 0;1863 var i: usize = 0;
...@@ -1983,7 +1952,7 @@ fn createNewDecl(...@@ -1983,7 +1952,7 @@ fn createNewDecl(
1983 name_hash: Scope.NameHash,1952 name_hash: Scope.NameHash,
1984 contents_hash: std.zig.SrcHash,1953 contents_hash: std.zig.SrcHash,
1985) !*Decl {1954) !*Decl {
1986 try self.decl_table.ensureCapacity(self.decl_table.size + 1);1955 try self.decl_table.ensureCapacity(self.decl_table.items().len + 1);
1987 const new_decl = try self.allocateNewDecl(scope, src_index, contents_hash);1956 const new_decl = try self.allocateNewDecl(scope, src_index, contents_hash);
1988 errdefer self.allocator.destroy(new_decl);1957 errdefer self.allocator.destroy(new_decl);
1989 new_decl.name = try mem.dupeZ(self.allocator, u8, decl_name);1958 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!...@@ -2043,7 +2012,7 @@ fn resolveZirDecl(self: *Module, scope: *Scope, src_decl: *zir.Decl) InnerError!
20432012
2044fn resolveZirDeclHavingIndex(self: *Module, scope: *Scope, src_decl: *zir.Decl, src_index: usize) InnerError!*Decl {2013fn resolveZirDeclHavingIndex(self: *Module, scope: *Scope, src_decl: *zir.Decl, src_index: usize) InnerError!*Decl {
2045 const name_hash = scope.namespace().fullyQualifiedNameHash(src_decl.name);2014 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).?;
2047 decl.src_index = src_index;2016 decl.src_index = src_index;
2048 try self.ensureDeclAnalyzed(decl);2017 try self.ensureDeclAnalyzed(decl);
2049 return decl;2018 return decl;
...@@ -2148,8 +2117,8 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const...@@ -2148,8 +2117,8 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const
2148 else => return self.fail(scope, src, "unable to export type '{}'", .{typed_value.ty}),2117 else => return self.fail(scope, src, "unable to export type '{}'", .{typed_value.ty}),
2149 }2118 }
21502119
2151 try self.decl_exports.ensureCapacity(self.decl_exports.size + 1);2120 try self.decl_exports.ensureCapacity(self.decl_exports.items().len + 1);
2152 try self.export_owners.ensureCapacity(self.export_owners.size + 1);2121 try self.export_owners.ensureCapacity(self.export_owners.items().len + 1);
21532122
2154 const new_export = try self.allocator.create(Export);2123 const new_export = try self.allocator.create(Export);
2155 errdefer self.allocator.destroy(new_export);2124 errdefer self.allocator.destroy(new_export);
...@@ -2168,23 +2137,23 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const...@@ -2168,23 +2137,23 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const
2168 // Add to export_owners table.2137 // Add to export_owners table.
2169 const eo_gop = self.export_owners.getOrPut(owner_decl) catch unreachable;2138 const eo_gop = self.export_owners.getOrPut(owner_decl) catch unreachable;
2170 if (!eo_gop.found_existing) {2139 if (!eo_gop.found_existing) {
2171 eo_gop.kv.value = &[0]*Export{};2140 eo_gop.entry.value = &[0]*Export{};
2172 }2141 }
2173 eo_gop.kv.value = try self.allocator.realloc(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);
2174 eo_gop.kv.value[eo_gop.kv.value.len - 1] = new_export;2143 eo_gop.entry.value[eo_gop.entry.value.len - 1] = new_export;
2175 errdefer eo_gop.kv.value = self.allocator.shrink(eo_gop.kv.value, eo_gop.kv.value.len - 1);2144 errdefer eo_gop.entry.value = self.allocator.shrink(eo_gop.entry.value, eo_gop.entry.value.len - 1);
21762145
2177 // Add to exported_decl table.2146 // Add to exported_decl table.
2178 const de_gop = self.decl_exports.getOrPut(exported_decl) catch unreachable;2147 const de_gop = self.decl_exports.getOrPut(exported_decl) catch unreachable;
2179 if (!de_gop.found_existing) {2148 if (!de_gop.found_existing) {
2180 de_gop.kv.value = &[0]*Export{};2149 de_gop.entry.value = &[0]*Export{};
2181 }2150 }
2182 de_gop.kv.value = try self.allocator.realloc(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);
2183 de_gop.kv.value[de_gop.kv.value.len - 1] = new_export;2152 de_gop.entry.value[de_gop.entry.value.len - 1] = new_export;
2184 errdefer de_gop.kv.value = self.allocator.shrink(de_gop.kv.value, de_gop.kv.value.len - 1);2153 errdefer de_gop.entry.value = self.allocator.shrink(de_gop.entry.value, de_gop.entry.value.len - 1);
21852154
2186 if (self.symbol_exports.get(symbol_name)) |_| {2155 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);
2188 self.failed_exports.putAssumeCapacityNoClobber(new_export, try ErrorMsg.create(2157 self.failed_exports.putAssumeCapacityNoClobber(new_export, try ErrorMsg.create(
2189 self.allocator,2158 self.allocator,
2190 src,2159 src,
...@@ -2197,10 +2166,10 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const...@@ -2197,10 +2166,10 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const
2197 }2166 }
21982167
2199 try self.symbol_exports.putNoClobber(symbol_name, new_export);2168 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) {
2201 error.OutOfMemory => return error.OutOfMemory,2170 error.OutOfMemory => return error.OutOfMemory,
2202 else => {2171 else => {
2203 try self.failed_exports.ensureCapacity(self.failed_exports.size + 1);2172 try self.failed_exports.ensureCapacity(self.failed_exports.items().len + 1);
2204 self.failed_exports.putAssumeCapacityNoClobber(new_export, try ErrorMsg.create(2173 self.failed_exports.putAssumeCapacityNoClobber(new_export, try ErrorMsg.create(
2205 self.allocator,2174 self.allocator,
2206 src,2175 src,
...@@ -2494,7 +2463,7 @@ fn getNextAnonNameIndex(self: *Module) usize {...@@ -2494,7 +2463,7 @@ fn getNextAnonNameIndex(self: *Module) usize {
2494fn lookupDeclName(self: *Module, scope: *Scope, ident_name: []const u8) ?*Decl {2463fn lookupDeclName(self: *Module, scope: *Scope, ident_name: []const u8) ?*Decl {
2495 const namespace = scope.namespace();2464 const namespace = scope.namespace();
2496 const name_hash = namespace.fullyQualifiedNameHash(ident_name);2465 const name_hash = namespace.fullyQualifiedNameHash(ident_name);
2497 return self.decl_table.getValue(name_hash);2466 return self.decl_table.get(name_hash);
2498}2467}
24992468
2500fn analyzeInstExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) InnerError!*Inst {2469fn analyzeInstExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) InnerError!*Inst {
...@@ -3489,8 +3458,8 @@ fn failNode(...@@ -3489,8 +3458,8 @@ fn failNode(
3489fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *ErrorMsg) InnerError {3458fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *ErrorMsg) InnerError {
3490 {3459 {
3491 errdefer err_msg.destroy(self.allocator);3460 errdefer err_msg.destroy(self.allocator);
3492 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);3461 try self.failed_decls.ensureCapacity(self.failed_decls.items().len + 1);
3493 try self.failed_files.ensureCapacity(self.failed_files.size + 1);3462 try self.failed_files.ensureCapacity(self.failed_files.items().len + 1);
3494 }3463 }
3495 switch (scope.tag) {3464 switch (scope.tag) {
3496 .decl => {3465 .decl => {
src-self-hosted/codegen.zig+2-2
...@@ -705,7 +705,7 @@ const Function = struct {...@@ -705,7 +705,7 @@ const Function = struct {
705 }705 }
706706
707 fn resolveInst(self: *Function, inst: *ir.Inst) !MCValue {707 fn resolveInst(self: *Function, inst: *ir.Inst) !MCValue {
708 if (self.inst_table.getValue(inst)) |mcv| {708 if (self.inst_table.get(inst)) |mcv| {
709 return mcv;709 return mcv;
710 }710 }
711 if (inst.cast(ir.Inst.Constant)) |const_inst| {711 if (inst.cast(ir.Inst.Constant)) |const_inst| {
...@@ -713,7 +713,7 @@ const Function = struct {...@@ -713,7 +713,7 @@ const Function = struct {
713 try self.inst_table.putNoClobber(inst, mcvalue);713 try self.inst_table.putNoClobber(inst, mcvalue);
714 return mcvalue;714 return mcvalue;
715 } else {715 } else {
716 return self.inst_table.getValue(inst).?;716 return self.inst_table.get(inst).?;
717 }717 }
718 }718 }
719719
src-self-hosted/link.zig+3-3
...@@ -1071,7 +1071,7 @@ pub const ElfFile = struct {...@@ -1071,7 +1071,7 @@ pub const ElfFile = struct {
1071 try self.file.?.pwriteAll(code, file_offset);1071 try self.file.?.pwriteAll(code, file_offset);
10721072
1073 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.1073 // 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{};
1075 return self.updateDeclExports(module, decl, decl_exports);1075 return self.updateDeclExports(module, decl, decl_exports);
1076 }1076 }
10771077
...@@ -1093,7 +1093,7 @@ pub const ElfFile = struct {...@@ -1093,7 +1093,7 @@ pub const ElfFile = struct {
1093 for (exports) |exp| {1093 for (exports) |exp| {
1094 if (exp.options.section) |section_name| {1094 if (exp.options.section) |section_name| {
1095 if (!mem.eql(u8, section_name, ".text")) {1095 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);
1097 module.failed_exports.putAssumeCapacityNoClobber(1097 module.failed_exports.putAssumeCapacityNoClobber(
1098 exp,1098 exp,
1099 try Module.ErrorMsg.create(self.allocator, 0, "Unimplemented: ExportOptions.section", .{}),1099 try Module.ErrorMsg.create(self.allocator, 0, "Unimplemented: ExportOptions.section", .{}),
...@@ -1111,7 +1111,7 @@ pub const ElfFile = struct {...@@ -1111,7 +1111,7 @@ pub const ElfFile = struct {
1111 },1111 },
1112 .Weak => elf.STB_WEAK,1112 .Weak => elf.STB_WEAK,
1113 .LinkOnce => {1113 .LinkOnce => {
1114 try module.failed_exports.ensureCapacity(module.failed_exports.size + 1);1114 try module.failed_exports.ensureCapacity(module.failed_exports.items().len + 1);
1115 module.failed_exports.putAssumeCapacityNoClobber(1115 module.failed_exports.putAssumeCapacityNoClobber(
1116 exp,1116 exp,
1117 try Module.ErrorMsg.create(self.allocator, 0, "Unimplemented: GlobalLinkage.LinkOnce", .{}),1117 try Module.ErrorMsg.create(self.allocator, 0, "Unimplemented: GlobalLinkage.LinkOnce", .{}),
src-self-hosted/main.zig+2-2
...@@ -720,7 +720,7 @@ fn fmtPathDir(...@@ -720,7 +720,7 @@ fn fmtPathDir(
720 defer dir.close();720 defer dir.close();
721721
722 const stat = try dir.stat();722 const stat = try dir.stat();
723 if (try fmt.seen.put(stat.inode, {})) |_| return;723 if (try fmt.seen.fetchPut(stat.inode, {})) |_| return;
724724
725 var dir_it = dir.iterate();725 var dir_it = dir.iterate();
726 while (try dir_it.next()) |entry| {726 while (try dir_it.next()) |entry| {
...@@ -768,7 +768,7 @@ fn fmtPathFile(...@@ -768,7 +768,7 @@ fn fmtPathFile(
768 defer fmt.gpa.free(source_code);768 defer fmt.gpa.free(source_code);
769769
770 // Add to set after no longer possible to get error.IsDir.770 // 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
773 const tree = try std.zig.parse(fmt.gpa, source_code);773 const tree = try std.zig.parse(fmt.gpa, source_code);
774 defer tree.deinit();774 defer tree.deinit();
src-self-hosted/translate_c.zig+13-14
...@@ -20,7 +20,7 @@ pub const Error = error{OutOfMemory};...@@ -20,7 +20,7 @@ pub const Error = error{OutOfMemory};
20const TypeError = Error || error{UnsupportedType};20const TypeError = Error || error{UnsupportedType};
21const TransError = TypeError || error{UnsupportedTranslation};21const 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
25fn addrHash(x: usize) u32 {25fn addrHash(x: usize) u32 {
26 switch (@typeInfo(usize).Int.bits) {26 switch (@typeInfo(usize).Int.bits) {
...@@ -776,8 +776,8 @@ fn checkForBuiltinTypedef(checked_name: []const u8) ?[]const u8 {...@@ -776,8 +776,8 @@ fn checkForBuiltinTypedef(checked_name: []const u8) ?[]const u8 {
776}776}
777777
778fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, top_level_visit: bool) Error!?*ast.Node {778fn 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|779 if (c.decl_table.get(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)))) |name|
780 return transCreateNodeIdentifier(c, kv.value); // Avoid processing this decl twice780 return transCreateNodeIdentifier(c, name); // Avoid processing this decl twice
781 const rp = makeRestorePoint(c);781 const rp = makeRestorePoint(c);
782782
783 const typedef_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, typedef_decl)));783 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...@@ -818,8 +818,8 @@ fn transCreateNodeTypedef(rp: RestorePoint, typedef_decl: *const ZigClangTypedef
818}818}
819819
820fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node {820fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node {
821 if (c.decl_table.get(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) |kv|821 if (c.decl_table.get(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) |name|
822 return try transCreateNodeIdentifier(c, kv.value); // Avoid processing this decl twice822 return try transCreateNodeIdentifier(c, name); // Avoid processing this decl twice
823 const record_loc = ZigClangRecordDecl_getLocation(record_decl);823 const record_loc = ZigClangRecordDecl_getLocation(record_decl);
824824
825 var bare_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, record_decl)));825 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!?*...@@ -969,7 +969,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
969969
970fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node {970fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node {
971 if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name|971 if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name|
972 return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice972 return try transCreateNodeIdentifier(c, name); // Avoid processing this decl twice
973 const rp = makeRestorePoint(c);973 const rp = makeRestorePoint(c);
974 const enum_loc = ZigClangEnumDecl_getLocation(enum_decl);974 const enum_loc = ZigClangEnumDecl_getLocation(enum_decl);
975975
...@@ -2130,7 +2130,7 @@ fn transInitListExprRecord(...@@ -2130,7 +2130,7 @@ fn transInitListExprRecord(
2130 var raw_name = try rp.c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl)));2130 var raw_name = try rp.c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl)));
2131 if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {2131 if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {
2132 const name = rp.c.decl_table.get(@ptrToInt(ZigClangFieldDecl_getCanonicalDecl(field_decl))).?;2132 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);
2134 }2134 }
2135 const field_name_tok = try appendIdentifier(rp.c, raw_name);2135 const field_name_tok = try appendIdentifier(rp.c, raw_name);
21362136
...@@ -2855,7 +2855,7 @@ fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangMemberE...@@ -2855,7 +2855,7 @@ fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangMemberE
2855 const field_decl = @ptrCast(*const struct_ZigClangFieldDecl, member_decl);2855 const field_decl = @ptrCast(*const struct_ZigClangFieldDecl, member_decl);
2856 if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {2856 if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) {
2857 const name = rp.c.decl_table.get(@ptrToInt(ZigClangFieldDecl_getCanonicalDecl(field_decl))).?;2857 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);
2859 }2859 }
2860 }2860 }
2861 const decl = @ptrCast(*const ZigClangNamedDecl, member_decl);2861 const decl = @ptrCast(*const ZigClangNamedDecl, member_decl);
...@@ -6040,8 +6040,8 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {...@@ -6040,8 +6040,8 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
6040 } else if (node.id == .PrefixOp) {6040 } else if (node.id == .PrefixOp) {
6041 return node;6041 return node;
6042 } else if (node.cast(ast.Node.Identifier)) |ident| {6042 } else if (node.cast(ast.Node.Identifier)) |ident| {
6043 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |kv| {6043 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
6044 if (kv.value.cast(ast.Node.VarDecl)) |var_decl|6044 if (value.cast(ast.Node.VarDecl)) |var_decl|
6045 return getContainer(c, var_decl.init_node.?);6045 return getContainer(c, var_decl.init_node.?);
6046 }6046 }
6047 } else if (node.cast(ast.Node.InfixOp)) |infix| {6047 } else if (node.cast(ast.Node.InfixOp)) |infix| {
...@@ -6064,8 +6064,8 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {...@@ -6064,8 +6064,8 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
60646064
6065fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {6065fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
6066 if (ref.cast(ast.Node.Identifier)) |ident| {6066 if (ref.cast(ast.Node.Identifier)) |ident| {
6067 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |kv| {6067 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
6068 if (kv.value.cast(ast.Node.VarDecl)) |var_decl| {6068 if (value.cast(ast.Node.VarDecl)) |var_decl| {
6069 if (var_decl.type_node) |ty|6069 if (var_decl.type_node) |ty|
6070 return getContainer(c, ty);6070 return getContainer(c, ty);
6071 }6071 }
...@@ -6104,8 +6104,7 @@ fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto {...@@ -6104,8 +6104,7 @@ fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto {
6104}6104}
61056105
6106fn addMacros(c: *Context) !void {6106fn addMacros(c: *Context) !void {
6107 var macro_it = c.global_scope.macro_table.iterator();6107 for (c.global_scope.macro_table.items()) |kv| {
6108 while (macro_it.next()) |kv| {
6109 if (getFnProto(c, kv.value)) |proto_node| {6108 if (getFnProto(c, kv.value)) |proto_node| {
6110 // If a macro aliases a global variable which is a function pointer, we conclude that6109 // If a macro aliases a global variable which is a function pointer, we conclude that
6111 // the macro is intended to represent a function that assumes the function pointer6110 // 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 {...@@ -758,7 +758,7 @@ pub const Module = struct {
758 }758 }
759759
760 fn writeInstParamToStream(self: Module, stream: var, inst: *Inst, inst_table: *const InstPtrTable) !void {760 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| {
762 if (info.index) |i| {762 if (info.index) |i| {
763 try stream.print("%{}", .{info.index});763 try stream.print("%{}", .{info.index});
764 } else {764 } else {
...@@ -843,7 +843,7 @@ const Parser = struct {...@@ -843,7 +843,7 @@ const Parser = struct {
843 skipSpace(self);843 skipSpace(self);
844 const decl = try parseInstruction(self, &body_context, ident);844 const decl = try parseInstruction(self, &body_context, ident);
845 const ident_index = body_context.instructions.items.len;845 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)) |_| {
847 return self.fail("redefinition of identifier '{}'", .{ident});847 return self.fail("redefinition of identifier '{}'", .{ident});
848 }848 }
849 try body_context.instructions.append(decl.inst);849 try body_context.instructions.append(decl.inst);
...@@ -929,7 +929,7 @@ const Parser = struct {...@@ -929,7 +929,7 @@ const Parser = struct {
929 skipSpace(self);929 skipSpace(self);
930 const decl = try parseInstruction(self, null, ident);930 const decl = try parseInstruction(self, null, ident);
931 const ident_index = self.decls.items.len;931 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)) |_| {
933 return self.fail("redefinition of identifier '{}'", .{ident});933 return self.fail("redefinition of identifier '{}'", .{ident});
934 }934 }
935 try self.decls.append(self.allocator, decl);935 try self.decls.append(self.allocator, decl);
...@@ -1153,7 +1153,7 @@ const Parser = struct {...@@ -1153,7 +1153,7 @@ const Parser = struct {
1153 else => continue,1153 else => continue,
1154 };1154 };
1155 const ident = self.source[name_start..self.i];1155 const ident = self.source[name_start..self.i];
1156 const kv = map.get(ident) orelse {1156 return map.get(ident) orelse {
1157 const bad_name = self.source[name_start - 1 .. self.i];1157 const bad_name = self.source[name_start - 1 .. self.i];
1158 const src = name_start - 1;1158 const src = name_start - 1;
1159 if (local_ref) {1159 if (local_ref) {
...@@ -1172,7 +1172,6 @@ const Parser = struct {...@@ -1172,7 +1172,6 @@ const Parser = struct {
1172 return &declval.base;1172 return &declval.base;
1173 }1173 }
1174 };1174 };
1175 return kv.value;
1176 }1175 }
11771176
1178 fn generateName(self: *Parser) ![]u8 {1177 fn generateName(self: *Parser) ![]u8 {
...@@ -1219,13 +1218,12 @@ const EmitZIR = struct {...@@ -1219,13 +1218,12 @@ const EmitZIR = struct {
1219 // by the hash table.1218 // by the hash table.
1220 var src_decls = std.ArrayList(*IrModule.Decl).init(self.allocator);1219 var src_decls = std.ArrayList(*IrModule.Decl).init(self.allocator);
1221 defer src_decls.deinit();1220 defer src_decls.deinit();
1222 try src_decls.ensureCapacity(self.old_module.decl_table.size);1221 try src_decls.ensureCapacity(self.old_module.decl_table.items().len);
1223 try self.decls.ensureCapacity(self.allocator, self.old_module.decl_table.size);1222 try self.decls.ensureCapacity(self.allocator, self.old_module.decl_table.items().len);
1224 try self.names.ensureCapacity(self.old_module.decl_table.size);1223 try self.names.ensureCapacity(self.old_module.decl_table.items().len);
12251224
1226 var decl_it = self.old_module.decl_table.iterator();1225 for (self.old_module.decl_table.items()) |entry| {
1227 while (decl_it.next()) |kv| {1226 const decl = entry.value;
1228 const decl = kv.value;
1229 src_decls.appendAssumeCapacity(decl);1227 src_decls.appendAssumeCapacity(decl);
1230 self.names.putAssumeCapacityNoClobber(mem.spanZ(decl.name), {});1228 self.names.putAssumeCapacityNoClobber(mem.spanZ(decl.name), {});
1231 }1229 }
...@@ -1248,7 +1246,7 @@ const EmitZIR = struct {...@@ -1248,7 +1246,7 @@ const EmitZIR = struct {
1248 .codegen_failure,1246 .codegen_failure,
1249 .dependency_failure,1247 .dependency_failure,
1250 .codegen_failure_retryable,1248 .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| {
1252 const fail_inst = try self.arena.allocator.create(Inst.CompileError);1250 const fail_inst = try self.arena.allocator.create(Inst.CompileError);
1253 fail_inst.* = .{1251 fail_inst.* = .{
1254 .base = .{1252 .base = .{
...@@ -1270,7 +1268,7 @@ const EmitZIR = struct {...@@ -1270,7 +1268,7 @@ const EmitZIR = struct {
1270 continue;1268 continue;
1271 },1269 },
1272 }1270 }
1273 if (self.old_module.export_owners.getValue(ir_decl)) |exports| {1271 if (self.old_module.export_owners.get(ir_decl)) |exports| {
1274 for (exports) |module_export| {1272 for (exports) |module_export| {
1275 const symbol_name = try self.emitStringLiteral(module_export.src, module_export.options.name);1273 const symbol_name = try self.emitStringLiteral(module_export.src, module_export.options.name);
1276 const export_inst = try self.arena.allocator.create(Inst.Export);1274 const export_inst = try self.arena.allocator.create(Inst.Export);
...@@ -1314,7 +1312,7 @@ const EmitZIR = struct {...@@ -1314,7 +1312,7 @@ const EmitZIR = struct {
1314 try new_body.inst_table.putNoClobber(inst, new_inst);1312 try new_body.inst_table.putNoClobber(inst, new_inst);
1315 return new_inst;1313 return new_inst;
1316 } else {1314 } else {
1317 return new_body.inst_table.getValue(inst).?;1315 return new_body.inst_table.get(inst).?;
1318 }1316 }
1319 }1317 }
13201318
...@@ -1424,7 +1422,7 @@ const EmitZIR = struct {...@@ -1424,7 +1422,7 @@ const EmitZIR = struct {
1424 try self.emitBody(body, &inst_table, &instructions);1422 try self.emitBody(body, &inst_table, &instructions);
1425 },1423 },
1426 .sema_failure => {1424 .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).?;
1428 const fail_inst = try self.arena.allocator.create(Inst.CompileError);1426 const fail_inst = try self.arena.allocator.create(Inst.CompileError);
1429 fail_inst.* = .{1427 fail_inst.* = .{
1430 .base = .{1428 .base = .{
...@@ -1841,7 +1839,7 @@ const EmitZIR = struct {...@@ -1841,7 +1839,7 @@ const EmitZIR = struct {
1841 self.next_auto_name += 1;1839 self.next_auto_name += 1;
1842 const gop = try self.names.getOrPut(proposed_name);1840 const gop = try self.names.getOrPut(proposed_name);
1843 if (!gop.found_existing) {1841 if (!gop.found_existing) {
1844 gop.kv.value = {};1842 gop.entry.value = {};
1845 return proposed_name;1843 return proposed_name;
1846 }1844 }
1847 }1845 }
...@@ -1861,9 +1859,9 @@ const EmitZIR = struct {...@@ -1861,9 +1859,9 @@ const EmitZIR = struct {
1861 },1859 },
1862 .kw_args = .{},1860 .kw_args = .{},
1863 };1861 };
1864 gop.kv.value = try self.emitUnnamedDecl(&primitive_inst.base);1862 gop.entry.value = try self.emitUnnamedDecl(&primitive_inst.base);
1865 }1863 }
1866 return gop.kv.value;1864 return gop.entry.value;
1867 }1865 }
18681866
1869 fn emitStringLiteral(self: *EmitZIR, src: usize, str: []const u8) !*Decl {1867 fn emitStringLiteral(self: *EmitZIR, src: usize, str: []const u8) !*Decl {