1 (* Copyright (C) DooM 2D:Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *)
16 {$INCLUDE a_modes.inc}
17 {.$DEFINE RBHASH_DEBUG_RESIZE}
18 {.$DEFINE RBHASH_DEBUG_DELETE}
19 {$IF DEFINED(D2F_DEBUG)}
20 {$DEFINE RBHASH_SANITY_CHECKS}
21 {$ENDIF}
22 // hash table (robin hood)
25 interface
28 type
29 // WARNING! don't put structures into hash, use ponters or ids!
31 private
35 public
39 private
40 type
49 private
58 private
66 public
83 implementation
85 uses
86 SysUtils;
89 // ////////////////////////////////////////////////////////////////////////// //
91 begin
92 if not assigned(ahashfn) then raise Exception.Create('cannot create hash without hash function');
93 if not assigned(aequfn) then raise Exception.Create('cannot create hash without equality function');
103 begin
111 begin
112 {$IFDEF RBHASH_SANITY_CHECKS}
113 if (mFreeEntryHead = -1) then raise Exception.Create('internal error in hash entry allocator (0)');
114 if (mEntries[mFreeEntryHead].hash <> 0) then raise Exception.Create('internal error in hash entry allocator (1)');
115 {$ENDIF}
124 var
126 begin
127 {$IFDEF RBHASH_SANITY_CHECKS}
129 if (e = nil) then raise Exception.Create('internal error in hash entry allocator (trying to release nil entry)');
130 if (e.nextFree <> -1) or (e.hash = 0) then raise Exception.Create('internal error in hash entry allocator (trying to release unallocated entry)');
131 {$ENDIF}
133 {$IFDEF RBHASH_SANITY_CHECKS}
134 if (idx >= Length(mEntries)) then raise Exception.Create('internal error in hash entry allocator (invalid calculated index)');
135 {$ENDIF}
144 var
146 begin
147 {$IFDEF RBHASH_SANITY_CHECKS}
150 {$ENDIF}
157 var
161 begin
171 begin
183 var
187 begin
197 begin
203 begin
205 break;
215 var
219 begin
224 begin
226 begin
227 // put entry
230 break;
234 begin
235 // swapping the current bucket with the one to insert
248 var
253 begin
260 // check if we already have this key
263 begin
265 begin
271 begin
272 // replace element
273 //mBuckets[idx].key := akey;
275 exit;
281 // need to resize hash?
283 begin
285 if (Length(mEntries) <> newsz) then raise Exception.Create('internal error in hash table (resize)');
287 {$IFDEF RBHASH_DEBUG_RESIZE}
288 writeln('resizing hash; used=', mBucketsUsed, '; total=', blen, '; maxload=', blen*LoadFactorPrc div 100, '; newsz=', newsz);
289 {$ENDIF}
291 // resize entries array
295 // mFreeEntryHead will be fixed in `rehash()`
296 // reinsert entries
300 // create new entry
310 // see http://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/
312 var
315 begin
323 // find key
328 begin
338 begin
339 // key not found
340 {$IFDEF RBHASH_DEBUG_DELETE}
342 {$ENDIF}
343 exit;
346 {$IFDEF RBHASH_DEBUG_DELETE}
347 writeln('del: key ', akey, ': found at ', idxcur, '(', stidx, '); ek=', mBuckets[idxcur].key, '; ev=', mBuckets[idxcur].value);
348 {$ENDIF}
353 begin
354 {$IFDEF RBHASH_DEBUG_DELETE}
355 writeln(' dist=', dist, '; idxcur=', idxcur, '; idxnext=', idxnext, '; ce=', (mBuckets[idxcur] <> nil), '; ne=', (mBuckets[idxnext] <> nil));
356 {$ENDIF}
357 if (mBuckets[idxnext] = nil) then begin {$IFDEF RBHASH_DEBUG_DELETE}writeln(' idxnext nil');{$ENDIF} mBuckets[idxcur] := nil; break; end;
359 if (pdist = 0) then begin {$IFDEF RBHASH_DEBUG_DELETE}writeln(' pdist is zero');{$ENDIF} mBuckets[idxcur] := nil; break; end;
371 var
373 begin
379 begin
392 var
395 begin
396 // clear buckets
399 // reinsert entries
403 begin
406 begin
408 end
409 else
410 begin