📄 hashes.pas
字号:
self.f_Keys[k][x].ItemIndex := ItemIndex; { Add the index to the spares list. } SetLength(self.f_SpareItems, Length(self.f_SpareItems) + 1); self.f_SpareItems[High(self.f_SpareItems)] := i; end else begin { No, create a new one. } SetLength(self.f_Keys[k], Length(self.f_Keys[k]) + 1); self.f_Keys[k][High(self.f_Keys[k])].Key := Key; self.f_Keys[k][High(self.f_Keys[k])].ItemIndex := ItemIndex; self.f_Keys[k][High(self.f_Keys[k])].Hash := HashThis(Key); end;end;function THash.FFindKey(const Key: string; var k, x: integer): boolean;var i: integer; h: cardinal;begin { Which bucket? } h := HashThis(Key); k := h and f_CurrentItemMask; result := false; { Look for it. } for i := 0 to High(self.f_Keys[k]) do if (self.f_Keys[k][i].Hash = h) or true then if (self.f_Keys[k][i].Key = Key) then begin { Found it! } result := true; x := i; break; end;end;procedure THash.Rename(const Key, NewName: string);var k, x, i: integer;begin { Hash has been modified, so disallow Next. } self.f_NextAllowed := false; if (self.FFindKey(Key, k, x)) then begin { Remember the ItemIndex. } i := self.f_Keys[k][x].ItemIndex; { Overwrite key with the last in the list. } self.f_Keys[k][x] := self.f_Keys[k][High(self.f_Keys[k])]; { Delete the last in the list. } SetLength(self.f_Keys[k], Length(self.f_Keys[k]) - 1); { Create the new item. } self.FSetOrAddKey(NewName, i); end else raise EHashFindError.CreateFmt('Key "%s" not found', [Key]); self.FAutoCompact;end;function THash.CurrentKey: string;begin if (not (self.f_NextAllowed)) then raise EHashIterateError.Create('Cannot find CurrentKey as the hash has ' + 'been modified since Restart was called') else if (self.f_CurrentKey = '') then raise EHashIterateError.Create('Cannot find CurrentKey as Next has not yet ' + 'been called after Restart') else result := self.f_CurrentKey;end;function THash.Next: boolean;begin if (not (self.f_NextAllowed)) then raise EHashIterateError.Create('Cannot get Next as the hash has ' + 'been modified since Restart was called'); result := false; if (self.f_CurrentIterator.ck = -1) then begin self.f_CurrentIterator.ck := 0; self.f_CurrentIterator.cx := 0; end; while ((not result) and (self.f_CurrentIterator.ck <= f_CurrentItemMaxIdx)) do begin if (self.f_CurrentIterator.cx < Length(self.f_Keys[self.f_CurrentIterator.ck])) then begin result := true; self.f_CurrentKey := self.f_Keys[self.f_CurrentIterator.ck][self.f_CurrentIterator.cx].Key; inc(self.f_CurrentIterator.cx); end else begin inc(self.f_CurrentIterator.ck); self.f_CurrentIterator.cx := 0; end; end;end;procedure THash.Restart;begin self.f_CurrentIterator.ck := -1; self.f_CurrentIterator.cx := 0; self.f_NextAllowed := true;end;function THash.FGetItemCount: integer;var i: integer;begin { Calculate our item count. } result := 0; for i := 0 to f_CurrentItemMaxIdx do inc(result, Length(self.f_Keys[i]));end;function THash.FAllocItemIndex: integer;begin if (Length(self.f_SpareItems) > 0) then begin { Use the top SpareItem. } result := self.f_SpareItems[High(self.f_SpareItems)]; SetLength(self.f_SpareItems, Length(self.f_SpareItems) - 1); end else begin result := self.FIndexMax + 1; end;end;procedure THash.Compact;var aSpaces: array of boolean; aMapping: array of integer; i, j: integer;begin { Find out where the gaps are. We could do this by sorting, but that's at least O(n log n), and sometimes O(n^2), so we'll go for the O(n) method, even though it involves multiple passes. Note that this is a lot faster than it looks. Disabling this saves about 3% in my benchmarks, but uses a lot more memory. } if (self.AllowCompact) then begin SetLength(aSpaces, self.FIndexMax + 1); SetLength(aMapping, self.FIndexMax + 1); for i := 0 to High(aSpaces) do aSpaces[i] := false; for i := 0 to High(aMapping) do aMapping[i] := i; for i := 0 to High(self.f_SpareItems) do aSpaces[self.f_SpareItems[i]] := true; { Starting at the low indexes, fill empty ones from the high indexes. } i := 0; j := self.FIndexMax; while (i < j) do begin if (aSpaces[i]) then begin while ((i < j) and (aSpaces[j])) do dec(j); if (i < j) then begin aSpaces[i] := false; aSpaces[j] := true; self.FMoveIndex(j, i); aMapping[j] := i end; end else inc(i); end; j := self.FIndexMax; while (aSpaces[j]) do dec(j); { Trim the items array down to size. } self.FTrimIndexes(j + 1); { Clear the spaces. } SetLength(self.f_SpareItems, 0); { Update our buckets. } for i := 0 to f_CurrentItemMaxIdx do for j := 0 to High(self.f_Keys[i]) do self.f_Keys[i][j].ItemIndex := aMapping[self.f_Keys[i][j].ItemIndex]; end;end;procedure THash.FAutoCompact;begin if (self.AllowCompact) then if (Length(self.f_SpareItems) >= c_HashCompactM) then if (self.FIndexMax * c_HashCompactR > Length(self.f_SpareItems)) then self.Compact;end;procedure THash.Clear;var i: integer;begin self.FClearItems; SetLength(self.f_SpareItems, 0); for i := 0 to f_CurrentItemMaxIdx do SetLength(self.f_Keys[i], 0);end;procedure THash.FUpdateMasks;begin f_CurrentItemMask := (1 shl f_CurrentItemShift) - 1; f_CurrentItemMaxIdx := (1 shl f_CurrentItemShift) - 1; f_CurrentItemCount := (1 shl f_CurrentItemShift);end;procedure THash.FUpdateBuckets;begin { This is just a temporary thing. } SetLength(self.f_Keys, self.f_CurrentItemCount);end;function THash.NewIterator: THashIterator;begin result.ck := -1; result.cx := 0;end;function THash.Previous: boolean;begin if (not (self.f_NextAllowed)) then raise EHashIterateError.Create('Cannot get Next as the hash has ' + 'been modified since Restart was called'); result := false; if (self.f_CurrentIterator.ck >= 0) then begin while ((not result) and (self.f_CurrentIterator.ck >= 0)) do begin dec(self.f_CurrentIterator.cx); if (self.f_CurrentIterator.cx >= 0) then begin result := true; self.f_CurrentKey := self.f_Keys[self.f_CurrentIterator.ck][self.f_CurrentIterator.cx].Key; end else begin dec(self.f_CurrentIterator.ck); if (self.f_CurrentIterator.ck >= 0) then self.f_CurrentIterator.cx := Length(self.f_Keys[self.f_CurrentIterator.ck]); end; end; end;end;{ TStringHash }procedure TStringHash.FDeleteIndex(i: integer);begin self.f_Items[i] := '';end;function TStringHash.FGetItem(const Key: string): string;var k, x: integer;begin if (self.FFindKey(Key, k, x)) then result := self.f_Items[self.f_Keys[k][x].ItemIndex] else raise EHashFindError.CreateFmt('Key "%s" not found', [Key]);end;procedure TStringHash.FMoveIndex(oldIndex, newIndex: integer);begin self.f_Items[newIndex] := self.f_Items[oldIndex];end;procedure TStringHash.FSetItem(const Key, Value: string);var k, x, i: integer;begin if (self.FFindKey(Key, k, x)) then self.f_Items[self.f_Keys[k][x].ItemIndex] := Value else begin { New index entry, or recycle an old one. } i := self.FAllocItemIndex; if (i > High(self.f_Items)) then SetLength(self.f_Items, i + 1); self.f_Items[i] := Value; { Add it to the hash. } SetLength(self.f_Keys[k], Length(self.f_Keys[k]) + 1); self.f_Keys[k][High(self.f_Keys[k])].Key := Key; self.f_Keys[k][High(self.f_Keys[k])].ItemIndex := i; self.f_Keys[k][High(self.f_Keys[k])].Hash := HashThis(Key); { Hash has been modified, so disallow Next. } self.f_NextAllowed := false; end;end;function TStringHash.FIndexMax: integer;begin result := High(self.f_Items);end;procedure TStringHash.FTrimIndexes(count: integer);begin SetLength(self.f_Items, count);end;procedure TStringHash.FClearItems;begin SetLength(self.f_Items, 0);end;{ TIntegerHash }procedure TIntegerHash.FDeleteIndex(i: integer);begin self.f_Items[i] := 0;end;function TIntegerHash.FGetItem(const Key: string): integer;var k, x: integer;begin if (self.FFindKey(Key, k, x)) then result := self.f_Items[self.f_Keys[k][x].ItemIndex] else raise EHashFindError.CreateFmt('Key "%s" not found', [Key]);end;procedure TIntegerHash.FMoveIndex(oldIndex, newIndex: integer);begin self.f_Items[newIndex] := self.f_Items[oldIndex];end;procedure TIntegerHash.FSetItem(const Key: string; Value: integer);var k, x, i: integer;begin if (self.FFindKey(Key, k, x)) then self.f_Items[self.f_Keys[k][x].ItemIndex] := Value else begin { New index entry, or recycle an old one. } i := self.FAllocItemIndex; if (i > High(self.f_Items)) then SetLength(self.f_Items, i + 1); self.f_Items[i] := Value; { Add it to the hash. } SetLength(self.f_Keys[k], Length(self.f_Keys[k]) + 1); self.f_Keys[k][High(self.f_Keys[k])].Key := Key; self.f_Keys[k][High(self.f_Keys[k])].ItemIndex := i; self.f_Keys[k][High(self.f_Keys[k])].Hash := HashThis(Key); { Hash has been modified, so disallow Next. } self.f_NextAllowed := false; end;end;function TIntegerHash.FIndexMax: integer;begin result := High(self.f_Items);end;procedure TIntegerHash.FTrimIndexes(count: integer);begin SetLength(self.f_Items, count);end;procedure TIntegerHash.FClearItems;begin SetLength(self.f_Items, 0);end;{ TObjectHash }procedure TObjectHash.FDeleteIndex(i: integer);begin self.f_Items[i].Free; self.f_Items[i] := nil;end;function TObjectHash.FGetItem(const Key: string): TObject;var k, x: integer;begin if (self.FFindKey(Key, k, x)) then result := self.f_Items[self.f_Keys[k][x].ItemIndex] else raise EHashFindError.CreateFmt('Key "%s" not found', [Key]);end;procedure TObjectHash.FMoveIndex(oldIndex, newIndex: integer);begin self.f_Items[newIndex] := self.f_Items[oldIndex];end;procedure TObjectHash.FSetItem(const Key: string; Value: TObject);var k, x, i: integer;begin if (self.FFindKey(Key, k, x)) then begin self.f_Items[self.f_Keys[k][x].ItemIndex].Free; self.f_Items[self.f_Keys[k][x].ItemIndex] := Value; end else begin { New index entry, or recycle an old one. } i := self.FAllocItemIndex; if (i > High(self.f_Items)) then SetLength(self.f_Items, i + 1); self.f_Items[i] := Value; { Add it to the hash. } SetLength(self.f_Keys[k], Length(self.f_Keys[k]) + 1); self.f_Keys[k][High(self.f_Keys[k])].Key := Key; self.f_Keys[k][High(self.f_Keys[k])].ItemIndex := i; self.f_Keys[k][High(self.f_Keys[k])].Hash := HashThis(Key); { Hash has been modified, so disallow Next. } self.f_NextAllowed := false; end;end;function TObjectHash.FIndexMax: integer;begin result := High(self.f_Items);end;procedure TObjectHash.FTrimIndexes(count: integer);begin SetLength(self.f_Items, count);end;procedure TObjectHash.FClearItems;var i: integer;begin for i := 0 to High(self.f_Items) do if (Assigned(self.f_Items[i])) then self.f_Items[i].Free; SetLength(self.f_Items, 0);end;destructor TObjectHash.Destroy;var i: integer;begin for i := 0 to High(self.f_Items) do if (Assigned(self.f_Items[i])) then self.f_Items[i].Free; inherited;end;end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -