| ... | @@ -773,11 +773,6 @@ pub fn HashMapUnmanaged( | ... | @@ -773,11 +773,6 @@ pub fn HashMapUnmanaged( |
| 773 | self.used = 0; | 773 | self.used = 0; |
| 774 | self.fingerprint = tombstone; | 774 | self.fingerprint = tombstone; |
| 775 | } | 775 | } |
| 776 | | | |
| 777 | pub fn reset(self: *Metadata) void { | | |
| 778 | self.used = 0; | | |
| 779 | self.fingerprint = free; | | |
| 780 | } | | |
| 781 | }; | 776 | }; |
| 782 | | 777 | |
| 783 | comptime { | 778 | comptime { |
| ... | @@ -1115,24 +1110,12 @@ pub fn HashMapUnmanaged( | ... | @@ -1115,24 +1110,12 @@ pub fn HashMapUnmanaged( |
| 1115 | } | 1110 | } |
| 1116 | const mask = self.capacity() - 1; | 1111 | const mask = self.capacity() - 1; |
| 1117 | const fingerprint = Metadata.takeFingerprint(hash); | 1112 | const fingerprint = Metadata.takeFingerprint(hash); |
| 1118 | var start = @truncate(usize, hash & mask); | 1113 | // Don't loop indefinitely when there are no empty slots. |
| 1119 | var idx = start; | 1114 | var limit = self.capacity(); |
| | 1115 | var idx = @truncate(usize, hash & mask); |
| 1120 | | 1116 | |
| 1121 | var metadata = self.metadata.? + idx; | 1117 | var metadata = self.metadata.? + idx; |
| 1122 | if (metadata[0].isUsed() and metadata[0].fingerprint == fingerprint) { | 1118 | while ((metadata[0].isUsed() or metadata[0].isTombstone()) and limit != 0) { |
| 1123 | const test_key = &self.keys()[idx]; | | |
| 1124 | const eql = ctx.eql(key, test_key.*); | | |
| 1125 | if (eql) return idx; | | |
| 1126 | } | | |
| 1127 | // Temporarily mark the start position as "free" so that the probe loop | | |
| 1128 | // doesn't infinitely loop when all other slots are filled or tombstones. | | |
| 1129 | const saved = metadata[0]; | | |
| 1130 | metadata[0].reset(); | | |
| 1131 | defer self.metadata.?[start] = saved; | | |
| 1132 | idx = (idx + 1) & mask; // initial idx was already checked | | |
| 1133 | metadata = self.metadata.? + idx; | | |
| 1134 | | | |
| 1135 | while (metadata[0].isUsed() or metadata[0].isTombstone()) { | | |
| 1136 | if (metadata[0].isUsed() and metadata[0].fingerprint == fingerprint) { | 1119 | if (metadata[0].isUsed() and metadata[0].fingerprint == fingerprint) { |
| 1137 | const test_key = &self.keys()[idx]; | 1120 | const test_key = &self.keys()[idx]; |
| 1138 | // If you get a compile error on this line, it means that your generic eql | 1121 | // If you get a compile error on this line, it means that your generic eql |
| ... | @@ -1148,6 +1131,7 @@ pub fn HashMapUnmanaged( | ... | @@ -1148,6 +1131,7 @@ pub fn HashMapUnmanaged( |
| 1148 | } | 1131 | } |
| 1149 | } | 1132 | } |
| 1150 | | 1133 | |
| | 1134 | limit -= 1; |
| 1151 | idx = (idx + 1) & mask; | 1135 | idx = (idx + 1) & mask; |
| 1152 | metadata = self.metadata.? + idx; | 1136 | metadata = self.metadata.? + idx; |
| 1153 | } | 1137 | } |
| ... | @@ -1305,39 +1289,12 @@ pub fn HashMapUnmanaged( | ... | @@ -1305,39 +1289,12 @@ pub fn HashMapUnmanaged( |
| 1305 | } | 1289 | } |
| 1306 | const mask = self.capacity() - 1; | 1290 | const mask = self.capacity() - 1; |
| 1307 | const fingerprint = Metadata.takeFingerprint(hash); | 1291 | const fingerprint = Metadata.takeFingerprint(hash); |
| 1308 | var start = @truncate(usize, hash & mask); | 1292 | var limit = self.capacity(); |
| 1309 | var idx = start; | 1293 | var idx = @truncate(usize, hash & mask); |
| 1310 | | 1294 | |
| 1311 | var first_tombstone_idx: usize = self.capacity(); // invalid index | 1295 | var first_tombstone_idx: usize = self.capacity(); // invalid index |
| 1312 | var metadata = self.metadata.? + idx; | 1296 | var metadata = self.metadata.? + idx; |
| 1313 | if (metadata[0].isUsed() and metadata[0].fingerprint == fingerprint) { | 1297 | while ((metadata[0].isUsed() or metadata[0].isTombstone()) and limit != 0) { |
| 1314 | const test_key = &self.keys()[idx]; | | |
| 1315 | const eql = ctx.eql(key, test_key.*); | | |
| 1316 | if (eql) { | | |
| 1317 | return GetOrPutResult{ | | |
| 1318 | .key_ptr = test_key, | | |
| 1319 | .value_ptr = &self.values()[idx], | | |
| 1320 | .found_existing = true, | | |
| 1321 | }; | | |
| 1322 | } | | |
| 1323 | } else if (metadata[0].isTombstone()) { | | |
| 1324 | first_tombstone_idx = idx; | | |
| 1325 | } | | |
| 1326 | // Temporarily mark the start position as "free" so that the probe loop | | |
| 1327 | // doesn't infinitely loop when all other slots are filled or tombstones. | | |
| 1328 | const saved = metadata[0]; | | |
| 1329 | metadata[0].reset(); | | |
| 1330 | defer { | | |
| 1331 | // Don't restore when the 'home' slot was originally a tombstone | | |
| 1332 | // and the probe missed, since it is now occupied by the new key. | | |
| 1333 | const home = &self.metadata.?[start]; | | |
| 1334 | assert(!home.isUsed() or home.fingerprint == fingerprint); | | |
| 1335 | if (!home.isUsed()) home.* = saved; | | |
| 1336 | } | | |
| 1337 | idx = (idx + 1) & mask; // initial idx was already checked | | |
| 1338 | metadata = self.metadata.? + idx; | | |
| 1339 | | | |
| 1340 | while (metadata[0].isUsed() or metadata[0].isTombstone()) { | | |
| 1341 | if (metadata[0].isUsed() and metadata[0].fingerprint == fingerprint) { | 1298 | if (metadata[0].isUsed() and metadata[0].fingerprint == fingerprint) { |
| 1342 | const test_key = &self.keys()[idx]; | 1299 | const test_key = &self.keys()[idx]; |
| 1343 | // If you get a compile error on this line, it means that your generic eql | 1300 | // If you get a compile error on this line, it means that your generic eql |
| ... | @@ -1359,6 +1316,7 @@ pub fn HashMapUnmanaged( | ... | @@ -1359,6 +1316,7 @@ pub fn HashMapUnmanaged( |
| 1359 | first_tombstone_idx = idx; | 1316 | first_tombstone_idx = idx; |
| 1360 | } | 1317 | } |
| 1361 | | 1318 | |
| | 1319 | limit -= 1; |
| 1362 | idx = (idx + 1) & mask; | 1320 | idx = (idx + 1) & mask; |
| 1363 | metadata = self.metadata.? + idx; | 1321 | metadata = self.metadata.? + idx; |
| 1364 | } | 1322 | } |
| ... | @@ -1944,7 +1902,6 @@ test "std.hash_map repeat putAssumeCapacity/remove" { | ... | @@ -1944,7 +1902,6 @@ test "std.hash_map repeat putAssumeCapacity/remove" { |
| 1944 | | 1902 | |
| 1945 | try map.ensureTotalCapacity(20); | 1903 | try map.ensureTotalCapacity(20); |
| 1946 | const limit = map.unmanaged.available; | 1904 | const limit = map.unmanaged.available; |
| 1947 | const cycles = 100; | | |
| 1948 | | 1905 | |
| 1949 | var i: u32 = 0; | 1906 | var i: u32 = 0; |
| 1950 | while (i < limit) : (i += 1) { | 1907 | while (i < limit) : (i += 1) { |
| ... | @@ -1954,7 +1911,7 @@ test "std.hash_map repeat putAssumeCapacity/remove" { | ... | @@ -1954,7 +1911,7 @@ test "std.hash_map repeat putAssumeCapacity/remove" { |
| 1954 | // Repeatedly delete/insert an entry without resizing the map. | 1911 | // Repeatedly delete/insert an entry without resizing the map. |
| 1955 | // Put to different keys so entries don't land in the just-freed slot. | 1912 | // Put to different keys so entries don't land in the just-freed slot. |
| 1956 | i = 0; | 1913 | i = 0; |
| 1957 | while (i < cycles * limit) : (i += 1) { | 1914 | while (i < 10 * limit) : (i += 1) { |
| 1958 | try testing.expect(map.remove(i)); | 1915 | try testing.expect(map.remove(i)); |
| 1959 | if (i % 2 == 0) { | 1916 | if (i % 2 == 0) { |
| 1960 | map.putAssumeCapacityNoClobber(limit + i, i); | 1917 | map.putAssumeCapacityNoClobber(limit + i, i); |
| ... | @@ -1963,13 +1920,9 @@ test "std.hash_map repeat putAssumeCapacity/remove" { | ... | @@ -1963,13 +1920,9 @@ test "std.hash_map repeat putAssumeCapacity/remove" { |
| 1963 | } | 1920 | } |
| 1964 | } | 1921 | } |
| 1965 | | 1922 | |
| 1966 | i = (cycles - 1) * limit; | 1923 | i = 9 * limit; |
| 1967 | while (i < cycles * limit) : (i += 1) { | 1924 | while (i < 10 * limit) : (i += 1) { |
| 1968 | try expectEqual(map.get(i), null); // (removed) key miss | 1925 | try expectEqual(map.get(limit + i), i); |
| 1969 | try expectEqual(map.get(limit + i), i); // key hit | | |
| 1970 | const gop = map.getOrPutAssumeCapacity(limit + i); | | |
| 1971 | try testing.expect(gop.found_existing); | | |
| 1972 | try testing.expectEqual(gop.value_ptr.*, i); | | |
| 1973 | } | 1926 | } |
| 1974 | try expectEqual(map.unmanaged.available, 0); | 1927 | try expectEqual(map.unmanaged.available, 0); |
| 1975 | try expectEqual(map.unmanaged.count(), limit); | 1928 | try expectEqual(map.unmanaged.count(), limit); |