| ... | @@ -604,6 +604,8 @@ pub fn ArrayHashMapUnmanaged( | ... | @@ -604,6 +604,8 @@ pub fn ArrayHashMapUnmanaged( |
| 604 | ordered, | 604 | ordered, |
| 605 | }; | 605 | }; |
| 606 | | 606 | |
| | 607 | const Oom = Allocator.Error; |
| | 608 | |
| 607 | /// Convert from an unmanaged map to a managed map. After calling this, | 609 | /// Convert from an unmanaged map to a managed map. After calling this, |
| 608 | /// the promoted map should no longer be used. | 610 | /// the promoted map should no longer be used. |
| 609 | pub fn promote(self: Self, allocator: Allocator) Managed { | 611 | pub fn promote(self: Self, allocator: Allocator) Managed { |
| ... | @@ -619,14 +621,14 @@ pub fn ArrayHashMapUnmanaged( | ... | @@ -619,14 +621,14 @@ pub fn ArrayHashMapUnmanaged( |
| 619 | }; | 621 | }; |
| 620 | } | 622 | } |
| 621 | | 623 | |
| 622 | pub fn init(allocator: Allocator, key_list: []const K, value_list: []const V) !Self { | 624 | pub fn init(allocator: Allocator, key_list: []const K, value_list: []const V) Oom!Self { |
| 623 | var self: Self = .{}; | 625 | var self: Self = .{}; |
| 624 | errdefer self.deinit(allocator); | 626 | errdefer self.deinit(allocator); |
| 625 | try self.reinit(allocator, key_list, value_list); | 627 | try self.reinit(allocator, key_list, value_list); |
| 626 | return self; | 628 | return self; |
| 627 | } | 629 | } |
| 628 | | 630 | |
| 629 | pub fn reinit(self: *Self, allocator: Allocator, key_list: []const K, value_list: []const V) !void { | 631 | pub fn reinit(self: *Self, allocator: Allocator, key_list: []const K, value_list: []const V) Oom!void { |
| 630 | try self.entries.resize(allocator, key_list.len); | 632 | try self.entries.resize(allocator, key_list.len); |
| 631 | @memcpy(self.keys(), key_list); | 633 | @memcpy(self.keys(), key_list); |
| 632 | if (@sizeOf(V) != 0) { | 634 | if (@sizeOf(V) != 0) { |
| ... | @@ -750,24 +752,24 @@ pub fn ArrayHashMapUnmanaged( | ... | @@ -750,24 +752,24 @@ pub fn ArrayHashMapUnmanaged( |
| 750 | /// Otherwise, puts a new item with undefined value, and | 752 | /// Otherwise, puts a new item with undefined value, and |
| 751 | /// the `Entry` pointer points to it. Caller should then initialize | 753 | /// the `Entry` pointer points to it. Caller should then initialize |
| 752 | /// the value (but not the key). | 754 | /// the value (but not the key). |
| 753 | pub fn getOrPut(self: *Self, allocator: Allocator, key: K) !GetOrPutResult { | 755 | pub fn getOrPut(self: *Self, allocator: Allocator, key: K) Oom!GetOrPutResult { |
| 754 | if (@sizeOf(Context) != 0) | 756 | if (@sizeOf(Context) != 0) |
| 755 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutContext instead."); | 757 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutContext instead."); |
| 756 | return self.getOrPutContext(allocator, key, undefined); | 758 | return self.getOrPutContext(allocator, key, undefined); |
| 757 | } | 759 | } |
| 758 | pub fn getOrPutContext(self: *Self, allocator: Allocator, key: K, ctx: Context) !GetOrPutResult { | 760 | pub fn getOrPutContext(self: *Self, allocator: Allocator, key: K, ctx: Context) Oom!GetOrPutResult { |
| 759 | const gop = try self.getOrPutContextAdapted(allocator, key, ctx, ctx); | 761 | const gop = try self.getOrPutContextAdapted(allocator, key, ctx, ctx); |
| 760 | if (!gop.found_existing) { | 762 | if (!gop.found_existing) { |
| 761 | gop.key_ptr.* = key; | 763 | gop.key_ptr.* = key; |
| 762 | } | 764 | } |
| 763 | return gop; | 765 | return gop; |
| 764 | } | 766 | } |
| 765 | pub fn getOrPutAdapted(self: *Self, allocator: Allocator, key: anytype, key_ctx: anytype) !GetOrPutResult { | 767 | pub fn getOrPutAdapted(self: *Self, allocator: Allocator, key: anytype, key_ctx: anytype) Oom!GetOrPutResult { |
| 766 | if (@sizeOf(Context) != 0) | 768 | if (@sizeOf(Context) != 0) |
| 767 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutContextAdapted instead."); | 769 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutContextAdapted instead."); |
| 768 | return self.getOrPutContextAdapted(allocator, key, key_ctx, undefined); | 770 | return self.getOrPutContextAdapted(allocator, key, key_ctx, undefined); |
| 769 | } | 771 | } |
| 770 | pub fn getOrPutContextAdapted(self: *Self, allocator: Allocator, key: anytype, key_ctx: anytype, ctx: Context) !GetOrPutResult { | 772 | pub fn getOrPutContextAdapted(self: *Self, allocator: Allocator, key: anytype, key_ctx: anytype, ctx: Context) Oom!GetOrPutResult { |
| 771 | self.ensureTotalCapacityContext(allocator, self.entries.len + 1, ctx) catch |err| { | 773 | self.ensureTotalCapacityContext(allocator, self.entries.len + 1, ctx) catch |err| { |
| 772 | // "If key exists this function cannot fail." | 774 | // "If key exists this function cannot fail." |
| 773 | const index = self.getIndexAdapted(key, key_ctx) orelse return err; | 775 | const index = self.getIndexAdapted(key, key_ctx) orelse return err; |
| ... | @@ -848,12 +850,12 @@ pub fn ArrayHashMapUnmanaged( | ... | @@ -848,12 +850,12 @@ pub fn ArrayHashMapUnmanaged( |
| 848 | } | 850 | } |
| 849 | } | 851 | } |
| 850 | | 852 | |
| 851 | pub fn getOrPutValue(self: *Self, allocator: Allocator, key: K, value: V) !GetOrPutResult { | 853 | pub fn getOrPutValue(self: *Self, allocator: Allocator, key: K, value: V) Oom!GetOrPutResult { |
| 852 | if (@sizeOf(Context) != 0) | 854 | if (@sizeOf(Context) != 0) |
| 853 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutValueContext instead."); | 855 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutValueContext instead."); |
| 854 | return self.getOrPutValueContext(allocator, key, value, undefined); | 856 | return self.getOrPutValueContext(allocator, key, value, undefined); |
| 855 | } | 857 | } |
| 856 | pub fn getOrPutValueContext(self: *Self, allocator: Allocator, key: K, value: V, ctx: Context) !GetOrPutResult { | 858 | pub fn getOrPutValueContext(self: *Self, allocator: Allocator, key: K, value: V, ctx: Context) Oom!GetOrPutResult { |
| 857 | const res = try self.getOrPutContextAdapted(allocator, key, ctx, ctx); | 859 | const res = try self.getOrPutContextAdapted(allocator, key, ctx, ctx); |
| 858 | if (!res.found_existing) { | 860 | if (!res.found_existing) { |
| 859 | res.key_ptr.* = key; | 861 | res.key_ptr.* = key; |
| ... | @@ -864,12 +866,12 @@ pub fn ArrayHashMapUnmanaged( | ... | @@ -864,12 +866,12 @@ pub fn ArrayHashMapUnmanaged( |
| 864 | | 866 | |
| 865 | /// Increases capacity, guaranteeing that insertions up until the | 867 | /// Increases capacity, guaranteeing that insertions up until the |
| 866 | /// `expected_count` will not cause an allocation, and therefore cannot fail. | 868 | /// `expected_count` will not cause an allocation, and therefore cannot fail. |
| 867 | pub fn ensureTotalCapacity(self: *Self, allocator: Allocator, new_capacity: usize) !void { | 869 | pub fn ensureTotalCapacity(self: *Self, allocator: Allocator, new_capacity: usize) Oom!void { |
| 868 | if (@sizeOf(ByIndexContext) != 0) | 870 | if (@sizeOf(ByIndexContext) != 0) |
| 869 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call ensureTotalCapacityContext instead."); | 871 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call ensureTotalCapacityContext instead."); |
| 870 | return self.ensureTotalCapacityContext(allocator, new_capacity, undefined); | 872 | return self.ensureTotalCapacityContext(allocator, new_capacity, undefined); |
| 871 | } | 873 | } |
| 872 | pub fn ensureTotalCapacityContext(self: *Self, allocator: Allocator, new_capacity: usize, ctx: Context) !void { | 874 | pub fn ensureTotalCapacityContext(self: *Self, allocator: Allocator, new_capacity: usize, ctx: Context) Oom!void { |
| 873 | self.pointer_stability.lock(); | 875 | self.pointer_stability.lock(); |
| 874 | defer self.pointer_stability.unlock(); | 876 | defer self.pointer_stability.unlock(); |
| 875 | | 877 | |
| ... | @@ -901,7 +903,7 @@ pub fn ArrayHashMapUnmanaged( | ... | @@ -901,7 +903,7 @@ pub fn ArrayHashMapUnmanaged( |
| 901 | self: *Self, | 903 | self: *Self, |
| 902 | allocator: Allocator, | 904 | allocator: Allocator, |
| 903 | additional_capacity: usize, | 905 | additional_capacity: usize, |
| 904 | ) !void { | 906 | ) Oom!void { |
| 905 | if (@sizeOf(Context) != 0) | 907 | if (@sizeOf(Context) != 0) |
| 906 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call ensureTotalCapacityContext instead."); | 908 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call ensureTotalCapacityContext instead."); |
| 907 | return self.ensureUnusedCapacityContext(allocator, additional_capacity, undefined); | 909 | return self.ensureUnusedCapacityContext(allocator, additional_capacity, undefined); |
| ... | @@ -911,7 +913,7 @@ pub fn ArrayHashMapUnmanaged( | ... | @@ -911,7 +913,7 @@ pub fn ArrayHashMapUnmanaged( |
| 911 | allocator: Allocator, | 913 | allocator: Allocator, |
| 912 | additional_capacity: usize, | 914 | additional_capacity: usize, |
| 913 | ctx: Context, | 915 | ctx: Context, |
| 914 | ) !void { | 916 | ) Oom!void { |
| 915 | return self.ensureTotalCapacityContext(allocator, self.count() + additional_capacity, ctx); | 917 | return self.ensureTotalCapacityContext(allocator, self.count() + additional_capacity, ctx); |
| 916 | } | 918 | } |
| 917 | | 919 | |
| ... | @@ -926,24 +928,24 @@ pub fn ArrayHashMapUnmanaged( | ... | @@ -926,24 +928,24 @@ pub fn ArrayHashMapUnmanaged( |
| 926 | | 928 | |
| 927 | /// Clobbers any existing data. To detect if a put would clobber | 929 | /// Clobbers any existing data. To detect if a put would clobber |
| 928 | /// existing data, see `getOrPut`. | 930 | /// existing data, see `getOrPut`. |
| 929 | pub fn put(self: *Self, allocator: Allocator, key: K, value: V) !void { | 931 | pub fn put(self: *Self, allocator: Allocator, key: K, value: V) Oom!void { |
| 930 | if (@sizeOf(Context) != 0) | 932 | if (@sizeOf(Context) != 0) |
| 931 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call putContext instead."); | 933 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call putContext instead."); |
| 932 | return self.putContext(allocator, key, value, undefined); | 934 | return self.putContext(allocator, key, value, undefined); |
| 933 | } | 935 | } |
| 934 | pub fn putContext(self: *Self, allocator: Allocator, key: K, value: V, ctx: Context) !void { | 936 | pub fn putContext(self: *Self, allocator: Allocator, key: K, value: V, ctx: Context) Oom!void { |
| 935 | const result = try self.getOrPutContext(allocator, key, ctx); | 937 | const result = try self.getOrPutContext(allocator, key, ctx); |
| 936 | result.value_ptr.* = value; | 938 | result.value_ptr.* = value; |
| 937 | } | 939 | } |
| 938 | | 940 | |
| 939 | /// Inserts a key-value pair into the hash map, asserting that no previous | 941 | /// Inserts a key-value pair into the hash map, asserting that no previous |
| 940 | /// entry with the same key is already present | 942 | /// entry with the same key is already present |
| 941 | pub fn putNoClobber(self: *Self, allocator: Allocator, key: K, value: V) !void { | 943 | pub fn putNoClobber(self: *Self, allocator: Allocator, key: K, value: V) Oom!void { |
| 942 | if (@sizeOf(Context) != 0) | 944 | if (@sizeOf(Context) != 0) |
| 943 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call putNoClobberContext instead."); | 945 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call putNoClobberContext instead."); |
| 944 | return self.putNoClobberContext(allocator, key, value, undefined); | 946 | return self.putNoClobberContext(allocator, key, value, undefined); |
| 945 | } | 947 | } |
| 946 | pub fn putNoClobberContext(self: *Self, allocator: Allocator, key: K, value: V, ctx: Context) !void { | 948 | pub fn putNoClobberContext(self: *Self, allocator: Allocator, key: K, value: V, ctx: Context) Oom!void { |
| 947 | const result = try self.getOrPutContext(allocator, key, ctx); | 949 | const result = try self.getOrPutContext(allocator, key, ctx); |
| 948 | assert(!result.found_existing); | 950 | assert(!result.found_existing); |
| 949 | result.value_ptr.* = value; | 951 | result.value_ptr.* = value; |
| ... | @@ -977,12 +979,12 @@ pub fn ArrayHashMapUnmanaged( | ... | @@ -977,12 +979,12 @@ pub fn ArrayHashMapUnmanaged( |
| 977 | } | 979 | } |
| 978 | | 980 | |
| 979 | /// Inserts a new `Entry` into the hash map, returning the previous one, if any. | 981 | /// Inserts a new `Entry` into the hash map, returning the previous one, if any. |
| 980 | pub fn fetchPut(self: *Self, allocator: Allocator, key: K, value: V) !?KV { | 982 | pub fn fetchPut(self: *Self, allocator: Allocator, key: K, value: V) Oom!?KV { |
| 981 | if (@sizeOf(Context) != 0) | 983 | if (@sizeOf(Context) != 0) |
| 982 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call fetchPutContext instead."); | 984 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call fetchPutContext instead."); |
| 983 | return self.fetchPutContext(allocator, key, value, undefined); | 985 | return self.fetchPutContext(allocator, key, value, undefined); |
| 984 | } | 986 | } |
| 985 | pub fn fetchPutContext(self: *Self, allocator: Allocator, key: K, value: V, ctx: Context) !?KV { | 987 | pub fn fetchPutContext(self: *Self, allocator: Allocator, key: K, value: V, ctx: Context) Oom!?KV { |
| 986 | const gop = try self.getOrPutContext(allocator, key, ctx); | 988 | const gop = try self.getOrPutContext(allocator, key, ctx); |
| 987 | var result: ?KV = null; | 989 | var result: ?KV = null; |
| 988 | if (gop.found_existing) { | 990 | if (gop.found_existing) { |
| ... | @@ -1269,12 +1271,12 @@ pub fn ArrayHashMapUnmanaged( | ... | @@ -1269,12 +1271,12 @@ pub fn ArrayHashMapUnmanaged( |
| 1269 | /// Create a copy of the hash map which can be modified separately. | 1271 | /// Create a copy of the hash map which can be modified separately. |
| 1270 | /// The copy uses the same context as this instance, but is allocated | 1272 | /// The copy uses the same context as this instance, but is allocated |
| 1271 | /// with the provided allocator. | 1273 | /// with the provided allocator. |
| 1272 | pub fn clone(self: Self, allocator: Allocator) !Self { | 1274 | pub fn clone(self: Self, allocator: Allocator) Oom!Self { |
| 1273 | if (@sizeOf(ByIndexContext) != 0) | 1275 | if (@sizeOf(ByIndexContext) != 0) |
| 1274 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call cloneContext instead."); | 1276 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call cloneContext instead."); |
| 1275 | return self.cloneContext(allocator, undefined); | 1277 | return self.cloneContext(allocator, undefined); |
| 1276 | } | 1278 | } |
| 1277 | pub fn cloneContext(self: Self, allocator: Allocator, ctx: Context) !Self { | 1279 | pub fn cloneContext(self: Self, allocator: Allocator, ctx: Context) Oom!Self { |
| 1278 | var other: Self = .{}; | 1280 | var other: Self = .{}; |
| 1279 | other.entries = try self.entries.clone(allocator); | 1281 | other.entries = try self.entries.clone(allocator); |
| 1280 | errdefer other.entries.deinit(allocator); | 1282 | errdefer other.entries.deinit(allocator); |
| ... | @@ -1308,13 +1310,13 @@ pub fn ArrayHashMapUnmanaged( | ... | @@ -1308,13 +1310,13 @@ pub fn ArrayHashMapUnmanaged( |
| 1308 | /// directly without going through the methods of this map. | 1310 | /// directly without going through the methods of this map. |
| 1309 | /// | 1311 | /// |
| 1310 | /// The time complexity of this operation is O(n). | 1312 | /// The time complexity of this operation is O(n). |
| 1311 | pub fn reIndex(self: *Self, allocator: Allocator) !void { | 1313 | pub fn reIndex(self: *Self, allocator: Allocator) Oom!void { |
| 1312 | if (@sizeOf(ByIndexContext) != 0) | 1314 | if (@sizeOf(ByIndexContext) != 0) |
| 1313 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call reIndexContext instead."); | 1315 | @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call reIndexContext instead."); |
| 1314 | return self.reIndexContext(allocator, undefined); | 1316 | return self.reIndexContext(allocator, undefined); |
| 1315 | } | 1317 | } |
| 1316 | | 1318 | |
| 1317 | pub fn reIndexContext(self: *Self, allocator: Allocator, ctx: Context) !void { | 1319 | pub fn reIndexContext(self: *Self, allocator: Allocator, ctx: Context) Oom!void { |
| 1318 | // Recompute all hashes. | 1320 | // Recompute all hashes. |
| 1319 | if (store_hash) { | 1321 | if (store_hash) { |
| 1320 | for (self.keys(), self.entries.items(.hash)) |key, *hash| { | 1322 | for (self.keys(), self.entries.items(.hash)) |key, *hash| { |
| ... | @@ -2090,7 +2092,7 @@ const IndexHeader = struct { | ... | @@ -2090,7 +2092,7 @@ const IndexHeader = struct { |
| 2090 | return @as(u32, @intCast(self.length() - 1)); | 2092 | return @as(u32, @intCast(self.length() - 1)); |
| 2091 | } | 2093 | } |
| 2092 | | 2094 | |
| 2093 | fn findBitIndex(desired_capacity: usize) !u8 { | 2095 | fn findBitIndex(desired_capacity: usize) Allocator.Error!u8 { |
| 2094 | if (desired_capacity > max_capacity) return error.OutOfMemory; | 2096 | if (desired_capacity > max_capacity) return error.OutOfMemory; |
| 2095 | var new_bit_index = @as(u8, @intCast(std.math.log2_int_ceil(usize, desired_capacity))); | 2097 | var new_bit_index = @as(u8, @intCast(std.math.log2_int_ceil(usize, desired_capacity))); |
| 2096 | if (desired_capacity > index_capacities[new_bit_index]) new_bit_index += 1; | 2098 | if (desired_capacity > index_capacities[new_bit_index]) new_bit_index += 1; |
| ... | @@ -2101,7 +2103,7 @@ const IndexHeader = struct { | ... | @@ -2101,7 +2103,7 @@ const IndexHeader = struct { |
| 2101 | | 2103 | |
| 2102 | /// Allocates an index header, and fills the entryIndexes array with empty. | 2104 | /// Allocates an index header, and fills the entryIndexes array with empty. |
| 2103 | /// The distance array contents are undefined. | 2105 | /// The distance array contents are undefined. |
| 2104 | fn alloc(allocator: Allocator, new_bit_index: u8) !*IndexHeader { | 2106 | fn alloc(allocator: Allocator, new_bit_index: u8) Allocator.Error!*IndexHeader { |
| 2105 | const len = @as(usize, 1) << @as(math.Log2Int(usize), @intCast(new_bit_index)); | 2107 | const len = @as(usize, 1) << @as(math.Log2Int(usize), @intCast(new_bit_index)); |
| 2106 | const index_size = hash_map.capacityIndexSize(new_bit_index); | 2108 | const index_size = hash_map.capacityIndexSize(new_bit_index); |
| 2107 | const nbytes = @sizeOf(IndexHeader) + index_size * len; | 2109 | const nbytes = @sizeOf(IndexHeader) + index_size * len; |