authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-11-28 14:07:30-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-11-28 14:07:30-05:00
log182cdf74bfb010936e167405cdb54c9f5a94e1a6
tree56b42f6971e317d7e9e5bb80ddf8f5f8a223d74d
parent8594f179f9d70fbc3bf39111c4e1f147d4a6dc3c
parente374483d67592907522141546450e89e4d2f5d1e
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #22087 from ziglang/std.ArrayHashMap

std.ArrayHashMap: add `reinit` method and other housekeeping, including the move towards "unmanaged" containers

1 files changed, 88 insertions(+), 74 deletions(-)

lib/std/array_hash_map.zig+88-74
...@@ -53,6 +53,14 @@ pub fn hashString(s: []const u8) u32 {...@@ -53,6 +53,14 @@ pub fn hashString(s: []const u8) u32 {
53 return @as(u32, @truncate(std.hash.Wyhash.hash(0, s)));53 return @as(u32, @truncate(std.hash.Wyhash.hash(0, s)));
54}54}
5555
56/// Deprecated in favor of `ArrayHashMapWithAllocator` (no code changes needed)
57/// or `ArrayHashMapUnmanaged` (will need to update callsites to pass an
58/// allocator). After Zig 0.14.0 is released, `ArrayHashMapWithAllocator` will
59/// be removed and `ArrayHashMapUnmanaged` will be a deprecated alias. After
60/// Zig 0.15.0 is released, the deprecated alias `ArrayHashMapUnmanaged` will
61/// be removed.
62pub const ArrayHashMap = ArrayHashMapWithAllocator;
63
56/// A hash table of keys and values, each stored sequentially.64/// A hash table of keys and values, each stored sequentially.
57///65///
58/// Insertion order is preserved. In general, this data structure supports the same66/// Insertion order is preserved. In general, this data structure supports the same
...@@ -67,7 +75,7 @@ pub fn hashString(s: []const u8) u32 {...@@ -67,7 +75,7 @@ pub fn hashString(s: []const u8) u32 {
67///75///
68/// See `ArrayHashMapUnmanaged` for a variant of this data structure that accepts an76/// See `ArrayHashMapUnmanaged` for a variant of this data structure that accepts an
69/// `Allocator` as a parameter when needed rather than storing it.77/// `Allocator` as a parameter when needed rather than storing it.
70pub fn ArrayHashMap(78pub fn ArrayHashMapWithAllocator(
71 comptime K: type,79 comptime K: type,
72 comptime V: type,80 comptime V: type,
73 /// A namespace that provides these two functions:81 /// A namespace that provides these two functions:
...@@ -604,42 +612,48 @@ pub fn ArrayHashMapUnmanaged(...@@ -604,42 +612,48 @@ pub fn ArrayHashMapUnmanaged(
604 ordered,612 ordered,
605 };613 };
606614
615 const Oom = Allocator.Error;
616
607 /// Convert from an unmanaged map to a managed map. After calling this,617 /// Convert from an unmanaged map to a managed map. After calling this,
608 /// the promoted map should no longer be used.618 /// the promoted map should no longer be used.
609 pub fn promote(self: Self, allocator: Allocator) Managed {619 pub fn promote(self: Self, gpa: Allocator) Managed {
610 if (@sizeOf(Context) != 0)620 if (@sizeOf(Context) != 0)
611 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call promoteContext instead.");621 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call promoteContext instead.");
612 return self.promoteContext(allocator, undefined);622 return self.promoteContext(gpa, undefined);
613 }623 }
614 pub fn promoteContext(self: Self, allocator: Allocator, ctx: Context) Managed {624 pub fn promoteContext(self: Self, gpa: Allocator, ctx: Context) Managed {
615 return .{625 return .{
616 .unmanaged = self,626 .unmanaged = self,
617 .allocator = allocator,627 .allocator = gpa,
618 .ctx = ctx,628 .ctx = ctx,
619 };629 };
620 }630 }
621631
622 pub fn init(allocator: Allocator, key_list: []const K, value_list: []const V) !Self {632 pub fn init(gpa: Allocator, key_list: []const K, value_list: []const V) Oom!Self {
623 var self: Self = .{};633 var self: Self = .{};
624 try self.entries.resize(allocator, key_list.len);634 errdefer self.deinit(gpa);
625 errdefer self.entries.deinit(allocator);635 try self.reinit(gpa, key_list, value_list);
636 return self;
637 }
638
639 pub fn reinit(self: *Self, gpa: Allocator, key_list: []const K, value_list: []const V) Oom!void {
640 try self.entries.resize(gpa, key_list.len);
626 @memcpy(self.keys(), key_list);641 @memcpy(self.keys(), key_list);
627 if (@sizeOf(V) != 0) {642 if (@sizeOf(V) != 0) {
628 assert(key_list.len == value_list.len);643 assert(key_list.len == value_list.len);
629 @memcpy(self.values(), value_list);644 @memcpy(self.values(), value_list);
630 }645 }
631 try self.reIndex(allocator);646 try self.reIndex(gpa);
632 return self;
633 }647 }
634648
635 /// Frees the backing allocation and leaves the map in an undefined state.649 /// Frees the backing allocation and leaves the map in an undefined state.
636 /// Note that this does not free keys or values. You must take care of that650 /// Note that this does not free keys or values. You must take care of that
637 /// before calling this function, if it is needed.651 /// before calling this function, if it is needed.
638 pub fn deinit(self: *Self, allocator: Allocator) void {652 pub fn deinit(self: *Self, gpa: Allocator) void {
639 self.pointer_stability.assertUnlocked();653 self.pointer_stability.assertUnlocked();
640 self.entries.deinit(allocator);654 self.entries.deinit(gpa);
641 if (self.index_header) |header| {655 if (self.index_header) |header| {
642 header.free(allocator);656 header.free(gpa);
643 }657 }
644 self.* = undefined;658 self.* = undefined;
645 }659 }
...@@ -677,13 +691,13 @@ pub fn ArrayHashMapUnmanaged(...@@ -677,13 +691,13 @@ pub fn ArrayHashMapUnmanaged(
677 }691 }
678692
679 /// Clears the map and releases the backing allocation693 /// Clears the map and releases the backing allocation
680 pub fn clearAndFree(self: *Self, allocator: Allocator) void {694 pub fn clearAndFree(self: *Self, gpa: Allocator) void {
681 self.pointer_stability.lock();695 self.pointer_stability.lock();
682 defer self.pointer_stability.unlock();696 defer self.pointer_stability.unlock();
683697
684 self.entries.shrinkAndFree(allocator, 0);698 self.entries.shrinkAndFree(gpa, 0);
685 if (self.index_header) |header| {699 if (self.index_header) |header| {
686 header.free(allocator);700 header.free(gpa);
687 self.index_header = null;701 self.index_header = null;
688 }702 }
689 }703 }
...@@ -746,25 +760,25 @@ pub fn ArrayHashMapUnmanaged(...@@ -746,25 +760,25 @@ pub fn ArrayHashMapUnmanaged(
746 /// Otherwise, puts a new item with undefined value, and760 /// Otherwise, puts a new item with undefined value, and
747 /// the `Entry` pointer points to it. Caller should then initialize761 /// the `Entry` pointer points to it. Caller should then initialize
748 /// the value (but not the key).762 /// the value (but not the key).
749 pub fn getOrPut(self: *Self, allocator: Allocator, key: K) !GetOrPutResult {763 pub fn getOrPut(self: *Self, gpa: Allocator, key: K) Oom!GetOrPutResult {
750 if (@sizeOf(Context) != 0)764 if (@sizeOf(Context) != 0)
751 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutContext instead.");765 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutContext instead.");
752 return self.getOrPutContext(allocator, key, undefined);766 return self.getOrPutContext(gpa, key, undefined);
753 }767 }
754 pub fn getOrPutContext(self: *Self, allocator: Allocator, key: K, ctx: Context) !GetOrPutResult {768 pub fn getOrPutContext(self: *Self, gpa: Allocator, key: K, ctx: Context) Oom!GetOrPutResult {
755 const gop = try self.getOrPutContextAdapted(allocator, key, ctx, ctx);769 const gop = try self.getOrPutContextAdapted(gpa, key, ctx, ctx);
756 if (!gop.found_existing) {770 if (!gop.found_existing) {
757 gop.key_ptr.* = key;771 gop.key_ptr.* = key;
758 }772 }
759 return gop;773 return gop;
760 }774 }
761 pub fn getOrPutAdapted(self: *Self, allocator: Allocator, key: anytype, key_ctx: anytype) !GetOrPutResult {775 pub fn getOrPutAdapted(self: *Self, gpa: Allocator, key: anytype, key_ctx: anytype) Oom!GetOrPutResult {
762 if (@sizeOf(Context) != 0)776 if (@sizeOf(Context) != 0)
763 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutContextAdapted instead.");777 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutContextAdapted instead.");
764 return self.getOrPutContextAdapted(allocator, key, key_ctx, undefined);778 return self.getOrPutContextAdapted(gpa, key, key_ctx, undefined);
765 }779 }
766 pub fn getOrPutContextAdapted(self: *Self, allocator: Allocator, key: anytype, key_ctx: anytype, ctx: Context) !GetOrPutResult {780 pub fn getOrPutContextAdapted(self: *Self, gpa: Allocator, key: anytype, key_ctx: anytype, ctx: Context) Oom!GetOrPutResult {
767 self.ensureTotalCapacityContext(allocator, self.entries.len + 1, ctx) catch |err| {781 self.ensureTotalCapacityContext(gpa, self.entries.len + 1, ctx) catch |err| {
768 // "If key exists this function cannot fail."782 // "If key exists this function cannot fail."
769 const index = self.getIndexAdapted(key, key_ctx) orelse return err;783 const index = self.getIndexAdapted(key, key_ctx) orelse return err;
770 const slice = self.entries.slice();784 const slice = self.entries.slice();
...@@ -844,13 +858,13 @@ pub fn ArrayHashMapUnmanaged(...@@ -844,13 +858,13 @@ pub fn ArrayHashMapUnmanaged(
844 }858 }
845 }859 }
846860
847 pub fn getOrPutValue(self: *Self, allocator: Allocator, key: K, value: V) !GetOrPutResult {861 pub fn getOrPutValue(self: *Self, gpa: Allocator, key: K, value: V) Oom!GetOrPutResult {
848 if (@sizeOf(Context) != 0)862 if (@sizeOf(Context) != 0)
849 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutValueContext instead.");863 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutValueContext instead.");
850 return self.getOrPutValueContext(allocator, key, value, undefined);864 return self.getOrPutValueContext(gpa, key, value, undefined);
851 }865 }
852 pub fn getOrPutValueContext(self: *Self, allocator: Allocator, key: K, value: V, ctx: Context) !GetOrPutResult {866 pub fn getOrPutValueContext(self: *Self, gpa: Allocator, key: K, value: V, ctx: Context) Oom!GetOrPutResult {
853 const res = try self.getOrPutContextAdapted(allocator, key, ctx, ctx);867 const res = try self.getOrPutContextAdapted(gpa, key, ctx, ctx);
854 if (!res.found_existing) {868 if (!res.found_existing) {
855 res.key_ptr.* = key;869 res.key_ptr.* = key;
856 res.value_ptr.* = value;870 res.value_ptr.* = value;
...@@ -860,32 +874,32 @@ pub fn ArrayHashMapUnmanaged(...@@ -860,32 +874,32 @@ pub fn ArrayHashMapUnmanaged(
860874
861 /// Increases capacity, guaranteeing that insertions up until the875 /// Increases capacity, guaranteeing that insertions up until the
862 /// `expected_count` will not cause an allocation, and therefore cannot fail.876 /// `expected_count` will not cause an allocation, and therefore cannot fail.
863 pub fn ensureTotalCapacity(self: *Self, allocator: Allocator, new_capacity: usize) !void {877 pub fn ensureTotalCapacity(self: *Self, gpa: Allocator, new_capacity: usize) Oom!void {
864 if (@sizeOf(ByIndexContext) != 0)878 if (@sizeOf(ByIndexContext) != 0)
865 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call ensureTotalCapacityContext instead.");879 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call ensureTotalCapacityContext instead.");
866 return self.ensureTotalCapacityContext(allocator, new_capacity, undefined);880 return self.ensureTotalCapacityContext(gpa, new_capacity, undefined);
867 }881 }
868 pub fn ensureTotalCapacityContext(self: *Self, allocator: Allocator, new_capacity: usize, ctx: Context) !void {882 pub fn ensureTotalCapacityContext(self: *Self, gpa: Allocator, new_capacity: usize, ctx: Context) Oom!void {
869 self.pointer_stability.lock();883 self.pointer_stability.lock();
870 defer self.pointer_stability.unlock();884 defer self.pointer_stability.unlock();
871885
872 if (new_capacity <= linear_scan_max) {886 if (new_capacity <= linear_scan_max) {
873 try self.entries.ensureTotalCapacity(allocator, new_capacity);887 try self.entries.ensureTotalCapacity(gpa, new_capacity);
874 return;888 return;
875 }889 }
876890
877 if (self.index_header) |header| {891 if (self.index_header) |header| {
878 if (new_capacity <= header.capacity()) {892 if (new_capacity <= header.capacity()) {
879 try self.entries.ensureTotalCapacity(allocator, new_capacity);893 try self.entries.ensureTotalCapacity(gpa, new_capacity);
880 return;894 return;
881 }895 }
882 }896 }
883897
884 try self.entries.ensureTotalCapacity(allocator, new_capacity);898 try self.entries.ensureTotalCapacity(gpa, new_capacity);
885 const new_bit_index = try IndexHeader.findBitIndex(new_capacity);899 const new_bit_index = try IndexHeader.findBitIndex(new_capacity);
886 const new_header = try IndexHeader.alloc(allocator, new_bit_index);900 const new_header = try IndexHeader.alloc(gpa, new_bit_index);
887901
888 if (self.index_header) |old_header| old_header.free(allocator);902 if (self.index_header) |old_header| old_header.free(gpa);
889 self.insertAllEntriesIntoNewHeader(if (store_hash) {} else ctx, new_header);903 self.insertAllEntriesIntoNewHeader(if (store_hash) {} else ctx, new_header);
890 self.index_header = new_header;904 self.index_header = new_header;
891 }905 }
...@@ -895,20 +909,20 @@ pub fn ArrayHashMapUnmanaged(...@@ -895,20 +909,20 @@ pub fn ArrayHashMapUnmanaged(
895 /// therefore cannot fail.909 /// therefore cannot fail.
896 pub fn ensureUnusedCapacity(910 pub fn ensureUnusedCapacity(
897 self: *Self,911 self: *Self,
898 allocator: Allocator,912 gpa: Allocator,
899 additional_capacity: usize,913 additional_capacity: usize,
900 ) !void {914 ) Oom!void {
901 if (@sizeOf(Context) != 0)915 if (@sizeOf(Context) != 0)
902 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call ensureTotalCapacityContext instead.");916 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call ensureTotalCapacityContext instead.");
903 return self.ensureUnusedCapacityContext(allocator, additional_capacity, undefined);917 return self.ensureUnusedCapacityContext(gpa, additional_capacity, undefined);
904 }918 }
905 pub fn ensureUnusedCapacityContext(919 pub fn ensureUnusedCapacityContext(
906 self: *Self,920 self: *Self,
907 allocator: Allocator,921 gpa: Allocator,
908 additional_capacity: usize,922 additional_capacity: usize,
909 ctx: Context,923 ctx: Context,
910 ) !void {924 ) Oom!void {
911 return self.ensureTotalCapacityContext(allocator, self.count() + additional_capacity, ctx);925 return self.ensureTotalCapacityContext(gpa, self.count() + additional_capacity, ctx);
912 }926 }
913927
914 /// Returns the number of total elements which may be present before it is928 /// Returns the number of total elements which may be present before it is
...@@ -922,25 +936,25 @@ pub fn ArrayHashMapUnmanaged(...@@ -922,25 +936,25 @@ pub fn ArrayHashMapUnmanaged(
922936
923 /// Clobbers any existing data. To detect if a put would clobber937 /// Clobbers any existing data. To detect if a put would clobber
924 /// existing data, see `getOrPut`.938 /// existing data, see `getOrPut`.
925 pub fn put(self: *Self, allocator: Allocator, key: K, value: V) !void {939 pub fn put(self: *Self, gpa: Allocator, key: K, value: V) Oom!void {
926 if (@sizeOf(Context) != 0)940 if (@sizeOf(Context) != 0)
927 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call putContext instead.");941 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call putContext instead.");
928 return self.putContext(allocator, key, value, undefined);942 return self.putContext(gpa, key, value, undefined);
929 }943 }
930 pub fn putContext(self: *Self, allocator: Allocator, key: K, value: V, ctx: Context) !void {944 pub fn putContext(self: *Self, gpa: Allocator, key: K, value: V, ctx: Context) Oom!void {
931 const result = try self.getOrPutContext(allocator, key, ctx);945 const result = try self.getOrPutContext(gpa, key, ctx);
932 result.value_ptr.* = value;946 result.value_ptr.* = value;
933 }947 }
934948
935 /// Inserts a key-value pair into the hash map, asserting that no previous949 /// Inserts a key-value pair into the hash map, asserting that no previous
936 /// entry with the same key is already present950 /// entry with the same key is already present
937 pub fn putNoClobber(self: *Self, allocator: Allocator, key: K, value: V) !void {951 pub fn putNoClobber(self: *Self, gpa: Allocator, key: K, value: V) Oom!void {
938 if (@sizeOf(Context) != 0)952 if (@sizeOf(Context) != 0)
939 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call putNoClobberContext instead.");953 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call putNoClobberContext instead.");
940 return self.putNoClobberContext(allocator, key, value, undefined);954 return self.putNoClobberContext(gpa, key, value, undefined);
941 }955 }
942 pub fn putNoClobberContext(self: *Self, allocator: Allocator, key: K, value: V, ctx: Context) !void {956 pub fn putNoClobberContext(self: *Self, gpa: Allocator, key: K, value: V, ctx: Context) Oom!void {
943 const result = try self.getOrPutContext(allocator, key, ctx);957 const result = try self.getOrPutContext(gpa, key, ctx);
944 assert(!result.found_existing);958 assert(!result.found_existing);
945 result.value_ptr.* = value;959 result.value_ptr.* = value;
946 }960 }
...@@ -973,13 +987,13 @@ pub fn ArrayHashMapUnmanaged(...@@ -973,13 +987,13 @@ pub fn ArrayHashMapUnmanaged(
973 }987 }
974988
975 /// Inserts a new `Entry` into the hash map, returning the previous one, if any.989 /// Inserts a new `Entry` into the hash map, returning the previous one, if any.
976 pub fn fetchPut(self: *Self, allocator: Allocator, key: K, value: V) !?KV {990 pub fn fetchPut(self: *Self, gpa: Allocator, key: K, value: V) Oom!?KV {
977 if (@sizeOf(Context) != 0)991 if (@sizeOf(Context) != 0)
978 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call fetchPutContext instead.");992 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call fetchPutContext instead.");
979 return self.fetchPutContext(allocator, key, value, undefined);993 return self.fetchPutContext(gpa, key, value, undefined);
980 }994 }
981 pub fn fetchPutContext(self: *Self, allocator: Allocator, key: K, value: V, ctx: Context) !?KV {995 pub fn fetchPutContext(self: *Self, gpa: Allocator, key: K, value: V, ctx: Context) Oom!?KV {
982 const gop = try self.getOrPutContext(allocator, key, ctx);996 const gop = try self.getOrPutContext(gpa, key, ctx);
983 var result: ?KV = null;997 var result: ?KV = null;
984 if (gop.found_existing) {998 if (gop.found_existing) {
985 result = KV{999 result = KV{
...@@ -1265,20 +1279,20 @@ pub fn ArrayHashMapUnmanaged(...@@ -1265,20 +1279,20 @@ pub fn ArrayHashMapUnmanaged(
1265 /// Create a copy of the hash map which can be modified separately.1279 /// Create a copy of the hash map which can be modified separately.
1266 /// The copy uses the same context as this instance, but is allocated1280 /// The copy uses the same context as this instance, but is allocated
1267 /// with the provided allocator.1281 /// with the provided allocator.
1268 pub fn clone(self: Self, allocator: Allocator) !Self {1282 pub fn clone(self: Self, gpa: Allocator) Oom!Self {
1269 if (@sizeOf(ByIndexContext) != 0)1283 if (@sizeOf(ByIndexContext) != 0)
1270 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call cloneContext instead.");1284 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call cloneContext instead.");
1271 return self.cloneContext(allocator, undefined);1285 return self.cloneContext(gpa, undefined);
1272 }1286 }
1273 pub fn cloneContext(self: Self, allocator: Allocator, ctx: Context) !Self {1287 pub fn cloneContext(self: Self, gpa: Allocator, ctx: Context) Oom!Self {
1274 var other: Self = .{};1288 var other: Self = .{};
1275 other.entries = try self.entries.clone(allocator);1289 other.entries = try self.entries.clone(gpa);
1276 errdefer other.entries.deinit(allocator);1290 errdefer other.entries.deinit(gpa);
12771291
1278 if (self.index_header) |header| {1292 if (self.index_header) |header| {
1279 // TODO: I'm pretty sure this could be memcpy'd instead of1293 // TODO: I'm pretty sure this could be memcpy'd instead of
1280 // doing all this work.1294 // doing all this work.
1281 const new_header = try IndexHeader.alloc(allocator, header.bit_index);1295 const new_header = try IndexHeader.alloc(gpa, header.bit_index);
1282 other.insertAllEntriesIntoNewHeader(if (store_hash) {} else ctx, new_header);1296 other.insertAllEntriesIntoNewHeader(if (store_hash) {} else ctx, new_header);
1283 other.index_header = new_header;1297 other.index_header = new_header;
1284 }1298 }
...@@ -1304,13 +1318,13 @@ pub fn ArrayHashMapUnmanaged(...@@ -1304,13 +1318,13 @@ pub fn ArrayHashMapUnmanaged(
1304 /// directly without going through the methods of this map.1318 /// directly without going through the methods of this map.
1305 ///1319 ///
1306 /// The time complexity of this operation is O(n).1320 /// The time complexity of this operation is O(n).
1307 pub fn reIndex(self: *Self, allocator: Allocator) !void {1321 pub fn reIndex(self: *Self, gpa: Allocator) Oom!void {
1308 if (@sizeOf(ByIndexContext) != 0)1322 if (@sizeOf(ByIndexContext) != 0)
1309 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call reIndexContext instead.");1323 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call reIndexContext instead.");
1310 return self.reIndexContext(allocator, undefined);1324 return self.reIndexContext(gpa, undefined);
1311 }1325 }
13121326
1313 pub fn reIndexContext(self: *Self, allocator: Allocator, ctx: Context) !void {1327 pub fn reIndexContext(self: *Self, gpa: Allocator, ctx: Context) Oom!void {
1314 // Recompute all hashes.1328 // Recompute all hashes.
1315 if (store_hash) {1329 if (store_hash) {
1316 for (self.keys(), self.entries.items(.hash)) |key, *hash| {1330 for (self.keys(), self.entries.items(.hash)) |key, *hash| {
...@@ -1323,8 +1337,8 @@ pub fn ArrayHashMapUnmanaged(...@@ -1323,8 +1337,8 @@ pub fn ArrayHashMapUnmanaged(
1323 // We're going to rebuild the index header and replace the existing one (if any). The1337 // We're going to rebuild the index header and replace the existing one (if any). The
1324 // indexes should sized such that they will be at most 60% full.1338 // indexes should sized such that they will be at most 60% full.
1325 const bit_index = try IndexHeader.findBitIndex(self.entries.capacity);1339 const bit_index = try IndexHeader.findBitIndex(self.entries.capacity);
1326 const new_header = try IndexHeader.alloc(allocator, bit_index);1340 const new_header = try IndexHeader.alloc(gpa, bit_index);
1327 if (self.index_header) |header| header.free(allocator);1341 if (self.index_header) |header| header.free(gpa);
1328 self.insertAllEntriesIntoNewHeader(if (store_hash) {} else ctx, new_header);1342 self.insertAllEntriesIntoNewHeader(if (store_hash) {} else ctx, new_header);
1329 self.index_header = new_header;1343 self.index_header = new_header;
1330 }1344 }
...@@ -1416,10 +1430,10 @@ pub fn ArrayHashMapUnmanaged(...@@ -1416,10 +1430,10 @@ pub fn ArrayHashMapUnmanaged(
1416 /// performing hash and equality checks. It is a bug to call this1430 /// performing hash and equality checks. It is a bug to call this
1417 /// function if the discarded entries require deinitialization. For1431 /// function if the discarded entries require deinitialization. For
1418 /// that use case, `shrinkRetainingCapacity` can be used instead.1432 /// that use case, `shrinkRetainingCapacity` can be used instead.
1419 pub fn shrinkAndFree(self: *Self, allocator: Allocator, new_len: usize) void {1433 pub fn shrinkAndFree(self: *Self, gpa: Allocator, new_len: usize) void {
1420 if (@sizeOf(ByIndexContext) != 0)1434 if (@sizeOf(ByIndexContext) != 0)
1421 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call shrinkAndFreeContext instead.");1435 @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call shrinkAndFreeContext instead.");
1422 return self.shrinkAndFreeContext(allocator, new_len, undefined);1436 return self.shrinkAndFreeContext(gpa, new_len, undefined);
1423 }1437 }
14241438
1425 /// Shrinks the underlying `Entry` array to `new_len` elements and1439 /// Shrinks the underlying `Entry` array to `new_len` elements and
...@@ -1430,7 +1444,7 @@ pub fn ArrayHashMapUnmanaged(...@@ -1430,7 +1444,7 @@ pub fn ArrayHashMapUnmanaged(
1430 /// function if the discarded entries require deinitialization. For1444 /// function if the discarded entries require deinitialization. For
1431 /// that use case, `shrinkRetainingCapacityContext` can be used1445 /// that use case, `shrinkRetainingCapacityContext` can be used
1432 /// instead.1446 /// instead.
1433 pub fn shrinkAndFreeContext(self: *Self, allocator: Allocator, new_len: usize, ctx: Context) void {1447 pub fn shrinkAndFreeContext(self: *Self, gpa: Allocator, new_len: usize, ctx: Context) void {
1434 self.pointer_stability.lock();1448 self.pointer_stability.lock();
1435 defer self.pointer_stability.unlock();1449 defer self.pointer_stability.unlock();
14361450
...@@ -1442,7 +1456,7 @@ pub fn ArrayHashMapUnmanaged(...@@ -1442,7 +1456,7 @@ pub fn ArrayHashMapUnmanaged(
1442 while (i < self.entries.len) : (i += 1)1456 while (i < self.entries.len) : (i += 1)
1443 self.removeFromIndexByIndex(i, if (store_hash) {} else ctx, header);1457 self.removeFromIndexByIndex(i, if (store_hash) {} else ctx, header);
1444 }1458 }
1445 self.entries.shrinkAndFree(allocator, new_len);1459 self.entries.shrinkAndFree(gpa, new_len);
1446 }1460 }
14471461
1448 /// Removes the last inserted `Entry` in the hash map and returns it.1462 /// Removes the last inserted `Entry` in the hash map and returns it.
...@@ -2086,7 +2100,7 @@ const IndexHeader = struct {...@@ -2086,7 +2100,7 @@ const IndexHeader = struct {
2086 return @as(u32, @intCast(self.length() - 1));2100 return @as(u32, @intCast(self.length() - 1));
2087 }2101 }
20882102
2089 fn findBitIndex(desired_capacity: usize) !u8 {2103 fn findBitIndex(desired_capacity: usize) Allocator.Error!u8 {
2090 if (desired_capacity > max_capacity) return error.OutOfMemory;2104 if (desired_capacity > max_capacity) return error.OutOfMemory;
2091 var new_bit_index = @as(u8, @intCast(std.math.log2_int_ceil(usize, desired_capacity)));2105 var new_bit_index = @as(u8, @intCast(std.math.log2_int_ceil(usize, desired_capacity)));
2092 if (desired_capacity > index_capacities[new_bit_index]) new_bit_index += 1;2106 if (desired_capacity > index_capacities[new_bit_index]) new_bit_index += 1;
...@@ -2097,11 +2111,11 @@ const IndexHeader = struct {...@@ -2097,11 +2111,11 @@ const IndexHeader = struct {
20972111
2098 /// Allocates an index header, and fills the entryIndexes array with empty.2112 /// Allocates an index header, and fills the entryIndexes array with empty.
2099 /// The distance array contents are undefined.2113 /// The distance array contents are undefined.
2100 fn alloc(allocator: Allocator, new_bit_index: u8) !*IndexHeader {2114 fn alloc(gpa: Allocator, new_bit_index: u8) Allocator.Error!*IndexHeader {
2101 const len = @as(usize, 1) << @as(math.Log2Int(usize), @intCast(new_bit_index));2115 const len = @as(usize, 1) << @as(math.Log2Int(usize), @intCast(new_bit_index));
2102 const index_size = hash_map.capacityIndexSize(new_bit_index);2116 const index_size = hash_map.capacityIndexSize(new_bit_index);
2103 const nbytes = @sizeOf(IndexHeader) + index_size * len;2117 const nbytes = @sizeOf(IndexHeader) + index_size * len;
2104 const bytes = try allocator.alignedAlloc(u8, @alignOf(IndexHeader), nbytes);2118 const bytes = try gpa.alignedAlloc(u8, @alignOf(IndexHeader), nbytes);
2105 @memset(bytes[@sizeOf(IndexHeader)..], 0xff);2119 @memset(bytes[@sizeOf(IndexHeader)..], 0xff);
2106 const result: *IndexHeader = @alignCast(@ptrCast(bytes.ptr));2120 const result: *IndexHeader = @alignCast(@ptrCast(bytes.ptr));
2107 result.* = .{2121 result.* = .{
...@@ -2111,11 +2125,11 @@ const IndexHeader = struct {...@@ -2111,11 +2125,11 @@ const IndexHeader = struct {
2111 }2125 }
21122126
2113 /// Releases the memory for a header and its associated arrays.2127 /// Releases the memory for a header and its associated arrays.
2114 fn free(header: *IndexHeader, allocator: Allocator) void {2128 fn free(header: *IndexHeader, gpa: Allocator) void {
2115 const index_size = hash_map.capacityIndexSize(header.bit_index);2129 const index_size = hash_map.capacityIndexSize(header.bit_index);
2116 const ptr: [*]align(@alignOf(IndexHeader)) u8 = @ptrCast(header);2130 const ptr: [*]align(@alignOf(IndexHeader)) u8 = @ptrCast(header);
2117 const slice = ptr[0 .. @sizeOf(IndexHeader) + header.length() * index_size];2131 const slice = ptr[0 .. @sizeOf(IndexHeader) + header.length() * index_size];
2118 allocator.free(slice);2132 gpa.free(slice);
2119 }2133 }
21202134
2121 /// Puts an IndexHeader into the state that it would be in after being freshly allocated.2135 /// Puts an IndexHeader into the state that it would be in after being freshly allocated.