authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-12 18:21:19-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-07-12 18:21:19-04:00
log9b79ce1cd302a196bbb49e5fa89657bd840f4066
treef717633b02bdd9cf1c7bc724908e8d19ef097981
parent3063f0a5ed373947badd0af056db310283c76e37
parent28dd9d478d24190ab5c8c4b892d7dfc16c380ae0
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #9365 from ifreund/hash-map-fix

std/hash_map: fix ensureUnusedCapacity() over-allocating

6 files changed, 36 insertions(+), 15 deletions(-)

lib/std/hash_map.zig+14-1
...@@ -848,7 +848,7 @@ pub fn HashMapUnmanaged(...@@ -848,7 +848,7 @@ pub fn HashMapUnmanaged(
848 return ensureUnusedCapacityContext(self, allocator, additional_size, undefined);848 return ensureUnusedCapacityContext(self, allocator, additional_size, undefined);
849 }849 }
850 pub fn ensureUnusedCapacityContext(self: *Self, allocator: *Allocator, additional_size: Size, ctx: Context) !void {850 pub fn ensureUnusedCapacityContext(self: *Self, allocator: *Allocator, additional_size: Size, ctx: Context) !void {
851 return ensureTotalCapacityContext(self, allocator, self.capacity() + additional_size, ctx);851 return ensureTotalCapacityContext(self, allocator, self.count() + additional_size, ctx);
852 }852 }
853853
854 pub fn clearRetainingCapacity(self: *Self) void {854 pub fn clearRetainingCapacity(self: *Self) void {
...@@ -1956,6 +1956,19 @@ test "std.hash_map getOrPutAdapted" {...@@ -1956,6 +1956,19 @@ test "std.hash_map getOrPutAdapted" {
1956 }1956 }
1957}1957}
19581958
1959test "std.hash_map ensureUnusedCapacity" {
1960 var map = AutoHashMap(u64, u64).init(testing.allocator);
1961 defer map.deinit();
1962
1963 try map.ensureUnusedCapacity(32);
1964 const capacity = map.capacity();
1965 try map.ensureUnusedCapacity(32);
1966
1967 // Repeated ensureUnusedCapacity() calls with no insertions between
1968 // should not change the capacity.
1969 try testing.expectEqual(capacity, map.capacity());
1970}
1971
1959test "compile everything" {1972test "compile everything" {
1960 std.testing.refAllDecls(AutoHashMap(i32, i32));1973 std.testing.refAllDecls(AutoHashMap(i32, i32));
1961 std.testing.refAllDecls(StringHashMap([]const u8));1974 std.testing.refAllDecls(StringHashMap([]const u8));
src/codegen/c.zig+3-3
...@@ -39,11 +39,11 @@ const BlockData = struct {...@@ -39,11 +39,11 @@ const BlockData = struct {
39};39};
4040
41pub const CValueMap = std.AutoHashMap(*Inst, CValue);41pub const CValueMap = std.AutoHashMap(*Inst, CValue);
42pub const TypedefMap = std.HashMap(42pub const TypedefMap = std.ArrayHashMap(
43 Type,43 Type,
44 struct { name: []const u8, rendered: []u8 },44 struct { name: []const u8, rendered: []u8 },
45 Type.HashContext,45 Type.HashContext32,
46 std.hash_map.default_max_load_percentage,46 true,
47);47);
4848
49fn formatTypeAsCIdentifier(49fn formatTypeAsCIdentifier(
src/codegen/spirv.zig+1-1
...@@ -18,7 +18,7 @@ const Inst = ir.Inst;...@@ -18,7 +18,7 @@ const Inst = ir.Inst;
18pub const Word = u32;18pub const Word = u32;
19pub const ResultId = u32;19pub const ResultId = u32;
2020
21pub const TypeMap = std.HashMap(Type, u32, Type.HashContext, std.hash_map.default_max_load_percentage);21pub const TypeMap = std.HashMap(Type, u32, Type.HashContext64, std.hash_map.default_max_load_percentage);
22pub const InstMap = std.AutoHashMap(*Inst, ResultId);22pub const InstMap = std.AutoHashMap(*Inst, ResultId);
2323
24const IncomingBlock = struct {24const IncomingBlock = struct {
src/link.zig+1-1
...@@ -168,7 +168,7 @@ pub const File = struct {...@@ -168,7 +168,7 @@ pub const File = struct {
168 };168 };
169169
170 /// For DWARF .debug_info.170 /// For DWARF .debug_info.
171 pub const DbgInfoTypeRelocsTable = std.HashMapUnmanaged(Type, DbgInfoTypeReloc, Type.HashContext, std.hash_map.default_max_load_percentage);171 pub const DbgInfoTypeRelocsTable = std.HashMapUnmanaged(Type, DbgInfoTypeReloc, Type.HashContext64, std.hash_map.default_max_load_percentage);
172172
173 /// For DWARF .debug_info.173 /// For DWARF .debug_info.
174 pub const DbgInfoTypeReloc = struct {174 pub const DbgInfoTypeReloc = struct {
src/link/C.zig+5-8
...@@ -89,8 +89,7 @@ pub fn freeDecl(self: *C, decl: *Module.Decl) void {...@@ -89,8 +89,7 @@ pub fn freeDecl(self: *C, decl: *Module.Decl) void {
89fn deinitDecl(gpa: *Allocator, decl: *Module.Decl) void {89fn deinitDecl(gpa: *Allocator, decl: *Module.Decl) void {
90 decl.link.c.code.deinit(gpa);90 decl.link.c.code.deinit(gpa);
91 decl.fn_link.c.fwd_decl.deinit(gpa);91 decl.fn_link.c.fwd_decl.deinit(gpa);
92 var it = decl.fn_link.c.typedefs.valueIterator();92 for (decl.fn_link.c.typedefs.values()) |value| {
93 while (it.next()) |value| {
94 gpa.free(value.rendered);93 gpa.free(value.rendered);
95 }94 }
96 decl.fn_link.c.typedefs.deinit(gpa);95 decl.fn_link.c.typedefs.deinit(gpa);
...@@ -108,8 +107,7 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {...@@ -108,8 +107,7 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
108 const code = &decl.link.c.code;107 const code = &decl.link.c.code;
109 fwd_decl.shrinkRetainingCapacity(0);108 fwd_decl.shrinkRetainingCapacity(0);
110 {109 {
111 var it = typedefs.valueIterator();110 for (typedefs.values()) |value| {
112 while (it.next()) |value| {
113 module.gpa.free(value.rendered);111 module.gpa.free(value.rendered);
114 }112 }
115 }113 }
...@@ -135,8 +133,7 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {...@@ -135,8 +133,7 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
135 object.blocks.deinit(module.gpa);133 object.blocks.deinit(module.gpa);
136 object.code.deinit();134 object.code.deinit();
137 object.dg.fwd_decl.deinit();135 object.dg.fwd_decl.deinit();
138 var it = object.dg.typedefs.valueIterator();136 for (object.dg.typedefs.values()) |value| {
139 while (it.next()) |value| {
140 module.gpa.free(value.rendered);137 module.gpa.free(value.rendered);
141 }138 }
142 object.dg.typedefs.deinit();139 object.dg.typedefs.deinit();
...@@ -207,7 +204,7 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {...@@ -207,7 +204,7 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
207 }204 }
208205
209 var fn_count: usize = 0;206 var fn_count: usize = 0;
210 var typedefs = std.HashMap(Type, void, Type.HashContext, std.hash_map.default_max_load_percentage).init(comp.gpa);207 var typedefs = std.HashMap(Type, void, Type.HashContext64, std.hash_map.default_max_load_percentage).init(comp.gpa);
211 defer typedefs.deinit();208 defer typedefs.deinit();
212209
213 // Typedefs, forward decls and non-functions first.210 // Typedefs, forward decls and non-functions first.
...@@ -217,7 +214,7 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {...@@ -217,7 +214,7 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
217 if (!decl.has_tv) continue;214 if (!decl.has_tv) continue;
218 const buf = buf: {215 const buf = buf: {
219 if (decl.val.castTag(.function)) |_| {216 if (decl.val.castTag(.function)) |_| {
220 try typedefs.ensureUnusedCapacity(decl.fn_link.c.typedefs.count());217 try typedefs.ensureUnusedCapacity(@intCast(u32, decl.fn_link.c.typedefs.count()));
221 var it = decl.fn_link.c.typedefs.iterator();218 var it = decl.fn_link.c.typedefs.iterator();
222 while (it.next()) |new| {219 while (it.next()) |new| {
223 const gop = typedefs.getOrPutAssumeCapacity(new.key_ptr.*);220 const gop = typedefs.getOrPutAssumeCapacity(new.key_ptr.*);
src/type.zig+12-1
...@@ -602,7 +602,7 @@ pub const Type = extern union {...@@ -602,7 +602,7 @@ pub const Type = extern union {
602 return hasher.final();602 return hasher.final();
603 }603 }
604604
605 pub const HashContext = struct {605 pub const HashContext64 = struct {
606 pub fn hash(self: @This(), t: Type) u64 {606 pub fn hash(self: @This(), t: Type) u64 {
607 _ = self;607 _ = self;
608 return t.hash();608 return t.hash();
...@@ -613,6 +613,17 @@ pub const Type = extern union {...@@ -613,6 +613,17 @@ pub const Type = extern union {
613 }613 }
614 };614 };
615615
616 pub const HashContext32 = struct {
617 pub fn hash(self: @This(), t: Type) u32 {
618 _ = self;
619 return @truncate(u32, t.hash());
620 }
621 pub fn eql(self: @This(), a: Type, b: Type) bool {
622 _ = self;
623 return a.eql(b);
624 }
625 };
626
616 pub fn copy(self: Type, allocator: *Allocator) error{OutOfMemory}!Type {627 pub fn copy(self: Type, allocator: *Allocator) error{OutOfMemory}!Type {
617 if (self.tag_if_small_enough < Tag.no_payload_count) {628 if (self.tag_if_small_enough < Tag.no_payload_count) {
618 return Type{ .tag_if_small_enough = self.tag_if_small_enough };629 return Type{ .tag_if_small_enough = self.tag_if_small_enough };