| ... | @@ -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 | } |
| 55 | | 55 | |
| | 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. |
| | 62 | pub 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 same | 66 | /// 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 an | 76 | /// 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. |
| 70 | pub fn ArrayHashMap( | 78 | pub 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 | }; |
| 606 | | 614 | |
| | 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 | } |
| 621 | | 631 | |
| 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 | } |
| 634 | | 648 | |
| 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 that | 650 | /// 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 | } |
| 678 | | 692 | |
| 679 | /// Clears the map and releases the backing allocation | 693 | /// 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(); |
| 683 | | 697 | |
| 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, and | 760 | /// Otherwise, puts a new item with undefined value, and |
| 747 | /// the `Entry` pointer points to it. Caller should then initialize | 761 | /// 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 | } |
| 846 | | 860 | |
| 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( |
| 860 | | 874 | |
| 861 | /// Increases capacity, guaranteeing that insertions up until the | 875 | /// 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(); |
| 871 | | 885 | |
| 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 | } |
| 876 | | 890 | |
| 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 | } |
| 883 | | 897 | |
| 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); |
| 887 | | 901 | |
| 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 | } |
| 913 | | 927 | |
| 914 | /// Returns the number of total elements which may be present before it is | 928 | /// 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( |
| 922 | | 936 | |
| 923 | /// Clobbers any existing data. To detect if a put would clobber | 937 | /// 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 | } |
| 934 | | 948 | |
| 935 | /// Inserts a key-value pair into the hash map, asserting that no previous | 949 | /// Inserts a key-value pair into the hash map, asserting that no previous |
| 936 | /// entry with the same key is already present | 950 | /// 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 | } |
| 974 | | 988 | |
| 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 allocated | 1280 | /// 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); |
| 1277 | | 1291 | |
| 1278 | if (self.index_header) |header| { | 1292 | if (self.index_header) |header| { |
| 1279 | // TODO: I'm pretty sure this could be memcpy'd instead of | 1293 | // 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 | } |
| 1312 | | 1326 | |
| 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). The | 1337 | // 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 this | 1430 | /// performing hash and equality checks. It is a bug to call this |
| 1417 | /// function if the discarded entries require deinitialization. For | 1431 | /// 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 | } |
| 1424 | | 1438 | |
| 1425 | /// Shrinks the underlying `Entry` array to `new_len` elements and | 1439 | /// 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. For | 1444 | /// function if the discarded entries require deinitialization. For |
| 1431 | /// that use case, `shrinkRetainingCapacityContext` can be used | 1445 | /// 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(); |
| 1436 | | 1450 | |
| ... | @@ -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 | } |
| 1447 | | 1461 | |
| 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 | } |
| 2088 | | 2102 | |
| 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 { |
| 2097 | | 2111 | |
| 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 | } |
| 2112 | | 2126 | |
| 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 | } |
| 2120 | | 2134 | |
| 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. |