123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537 |
- {
- Copyright (c) 2001 by Peter Vreman
- TDictionary class
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- {$ifdef fpc}{$mode objfpc}{$endif}
- {$H+}
- unit fpcmdic;
- interface
- const { the real size will be [-hasharray..hasharray] ! }
- hasharraysize = 2047;
- type
- { namedindexobect for use with dictionary and indexarray }
- TDictionaryItem=class
- private
- Fname : string;
- FSpeedValue : cardinal;
- protected
- procedure SetName(const n:string);
- public
- left,
- right : TDictionaryItem;
- constructor create(const n:string);
- property Name:string read FName write SetName;
- property SpeedValue:cardinal read FSpeedValue;
- end;
- Pdictionaryhasharray=^Tdictionaryhasharray;
- Tdictionaryhasharray=array[-hasharraysize..hasharraysize] of TDictionaryItem;
- Tnamedindexcallback = procedure(p:TDictionaryItem) of object;
- Tdictionary=class
- private
- FRoot : TDictionaryItem;
- FHashArray : Pdictionaryhasharray;
- procedure cleartree(obj:TDictionaryItem);
- function insertNode(NewNode:TDictionaryItem;var currNode:TDictionaryItem):TDictionaryItem;
- procedure inserttree(currtree,currroot:TDictionaryItem);
- public
- noclear : boolean;
- replace_existing : boolean;
- constructor Create;
- destructor Destroy;override;
- procedure usehash;
- procedure clear;
- function delete(const s:string):TDictionaryItem;
- function empty:boolean;
- procedure foreach(proc2call:Tnamedindexcallback);
- function insert(obj:TDictionaryItem):TDictionaryItem;
- function rename(const olds,News : string):TDictionaryItem;
- function search(const s:string):TDictionaryItem;
- function speedsearch(const s:string;SpeedValue:Cardinal):TDictionaryItem;
- property Items[const s:string]:TDictionaryItem read Search;default;
- end;
- { Speed/Hash value }
- Function GetSpeedValue(Const s:String):cardinal;
- implementation
- {*****************************************************************************
- GetSpeedValue
- *****************************************************************************}
- var
- Crc32Tbl : array[0..255] of cardinal;
- procedure MakeCRC32Tbl;
- var
- crc : cardinal;
- i,n : integer;
- begin
- for i:=0 to 255 do
- begin
- crc:=i;
- for n:=1 to 8 do
- if odd(crc) then
- crc:=(crc shr 1) xor $edb88320
- else
- crc:=crc shr 1;
- Crc32Tbl[i]:=crc;
- end;
- end;
- Function GetSpeedValue(Const s:String):cardinal;
- var
- i : integer;
- InitCrc : cardinal;
- begin
- if Crc32Tbl[1]=0 then
- MakeCrc32Tbl;
- InitCrc:=$ffffffff;
- for i:=1 to Length(s) do
- InitCrc:=Crc32Tbl[byte(InitCrc) xor ord(s[i])] xor (InitCrc shr 8);
- GetSpeedValue:=InitCrc;
- end;
- {****************************************************************************
- TDictionaryItem
- ****************************************************************************}
- constructor TDictionaryItem.Create(const n:string);
- begin
- left:=nil;
- right:=nil;
- FSpeedValue:=$ffffffff;
- FName:=n;
- end;
- procedure TDictionaryItem.Setname(const n:string);
- begin
- if FSpeedValue=$ffffffff then
- FName:=n;
- end;
- {****************************************************************************
- TDICTIONARY
- ****************************************************************************}
- constructor Tdictionary.Create;
- begin
- FRoot:=nil;
- FHashArray:=nil;
- noclear:=false;
- replace_existing:=false;
- end;
- procedure Tdictionary.usehash;
- begin
- if not(assigned(FRoot)) and
- not(assigned(FHashArray)) then
- begin
- New(FHashArray);
- fillchar(FHashArray^,sizeof(FHashArray^),0);
- end;
- end;
- destructor Tdictionary.destroy;
- begin
- if not noclear then
- clear;
- if assigned(FHashArray) then
- dispose(FHashArray);
- end;
- procedure Tdictionary.cleartree(obj:TDictionaryItem);
- begin
- if assigned(obj.left) then
- cleartree(obj.left);
- if assigned(obj.right) then
- cleartree(obj.right);
- obj.free;
- obj:=nil;
- end;
- procedure Tdictionary.clear;
- var
- w : integer;
- begin
- if assigned(FRoot) then
- cleartree(FRoot);
- if assigned(FHashArray) then
- for w:=-hasharraysize to hasharraysize do
- if assigned(FHashArray^[w]) then
- cleartree(FHashArray^[w]);
- end;
- function Tdictionary.delete(const s:string):TDictionaryItem;
- var
- p,SpeedValue : cardinal;
- n : TDictionaryItem;
- procedure insert_right_bottom(var root,Atree:TDictionaryItem);
- begin
- while root.right<>nil do
- root:=root.right;
- root.right:=Atree;
- end;
- function delete_from_tree(root:TDictionaryItem):TDictionaryItem;
- type
- leftright=(left,right);
- var
- lr : leftright;
- oldroot : TDictionaryItem;
- begin
- oldroot:=nil;
- while (root<>nil) and (root.SpeedValue<>SpeedValue) do
- begin
- oldroot:=root;
- if SpeedValue<root.SpeedValue then
- begin
- root:=root.right;
- lr:=right;
- end
- else
- begin
- root:=root.left;
- lr:=left;
- end;
- end;
- while (root<>nil) and (root.name<>s) do
- begin
- oldroot:=root;
- if s<root.name then
- begin
- root:=root.right;
- lr:=right;
- end
- else
- begin
- root:=root.left;
- lr:=left;
- end;
- end;
- if root.left<>nil then
- begin
- { Now the Node pointing to root must point to the left
- subtree of root. The right subtree of root must be
- connected to the right bottom of the left subtree.}
- if lr=left then
- oldroot.left:=root.left
- else
- oldroot.right:=root.left;
- if root.right<>nil then
- insert_right_bottom(root.left,root.right);
- end
- else
- begin
- { There is no left subtree. So we can just replace the Node to
- delete with the right subtree.}
- if lr=left then
- oldroot.left:=root.right
- else
- oldroot.right:=root.right;
- end;
- delete_from_tree:=root;
- end;
- begin
- SpeedValue:=GetSpeedValue(s);
- n:=FRoot;
- if assigned(FHashArray) then
- begin
- { First, check if the Node to delete directly located under
- the hasharray.}
- p:=SpeedValue mod hasharraysize;
- n:=FHashArray^[p];
- if (n<>nil) and (n.SpeedValue=SpeedValue) and
- (n.name=s) then
- begin
- { The Node to delete is directly located under the
- hasharray. Make the hasharray point to the left
- subtree of the Node and place the right subtree on
- the right-bottom of the left subtree.}
- if n.left<>nil then
- begin
- FHashArray^[p]:=n.left;
- if n.right<>nil then
- insert_right_bottom(n.left,n.right);
- end
- else
- FHashArray^[p]:=n.right;
- delete:=n;
- exit;
- end;
- end
- else
- begin
- { First check if the Node to delete is the root.}
- if (FRoot<>nil) and (n.SpeedValue=SpeedValue) and
- (n.name=s) then
- begin
- if n.left<>nil then
- begin
- FRoot:=n.left;
- if n.right<>nil then
- insert_right_bottom(n.left,n.right);
- end
- else
- FRoot:=n.right;
- delete:=n;
- exit;
- end;
- end;
- delete:=delete_from_tree(n);
- end;
- function Tdictionary.empty:boolean;
- var
- w : integer;
- begin
- if assigned(FHashArray) then
- begin
- empty:=false;
- for w:=-hasharraysize to hasharraysize do
- if assigned(FHashArray^[w]) then
- exit;
- empty:=true;
- end
- else
- empty:=(FRoot=nil);
- end;
- procedure Tdictionary.foreach(proc2call:Tnamedindexcallback);
- procedure a(p:TDictionaryItem);
- begin
- proc2call(p);
- if assigned(p.left) then
- a(p.left);
- if assigned(p.right) then
- a(p.right);
- end;
- var
- i : integer;
- begin
- if assigned(FHashArray) then
- begin
- for i:=-hasharraysize to hasharraysize do
- if assigned(FHashArray^[i]) then
- a(FHashArray^[i]);
- end
- else
- if assigned(FRoot) then
- a(FRoot);
- end;
- function Tdictionary.insert(obj:TDictionaryItem):TDictionaryItem;
- begin
- obj.FSpeedValue:=GetSpeedValue(obj.name);
- if assigned(FHashArray) then
- insert:=insertNode(obj,FHashArray^[obj.SpeedValue mod hasharraysize])
- else
- insert:=insertNode(obj,FRoot);
- end;
- function tdictionary.insertNode(NewNode:TDictionaryItem;var currNode:TDictionaryItem):TDictionaryItem;
- begin
- if currNode=nil then
- begin
- currNode:=NewNode;
- insertNode:=NewNode;
- end
- { First check SpeedValue, to allow a fast insert }
- else
- if currNode.SpeedValue>NewNode.SpeedValue then
- insertNode:=insertNode(NewNode,currNode.right)
- else
- if currNode.SpeedValue<NewNode.SpeedValue then
- insertNode:=insertNode(NewNode,currNode.left)
- else
- begin
- if currNode.name>NewNode.name then
- insertNode:=insertNode(NewNode,currNode.right)
- else
- if currNode.name<NewNode.name then
- insertNode:=insertNode(NewNode,currNode.left)
- else
- begin
- if replace_existing and
- assigned(currNode) then
- begin
- NewNode.left:=currNode.left;
- NewNode.right:=currNode.right;
- currNode:=NewNode;
- insertNode:=NewNode;
- end
- else
- insertNode:=currNode;
- end;
- end;
- end;
- procedure tdictionary.inserttree(currtree,currroot:TDictionaryItem);
- begin
- if assigned(currtree) then
- begin
- inserttree(currtree.left,currroot);
- inserttree(currtree.right,currroot);
- currtree.right:=nil;
- currtree.left:=nil;
- insertNode(currtree,currroot);
- end;
- end;
- function tdictionary.rename(const olds,News : string):TDictionaryItem;
- var
- spdval : Cardinal;
- lasthp,
- hp,hp2,hp3 : TDictionaryItem;
- begin
- spdval:=GetSpeedValue(olds);
- if assigned(FHashArray) then
- hp:=FHashArray^[spdval mod hasharraysize]
- else
- hp:=FRoot;
- lasthp:=nil;
- while assigned(hp) do
- begin
- if spdval>hp.SpeedValue then
- begin
- lasthp:=hp;
- hp:=hp.left
- end
- else
- if spdval<hp.SpeedValue then
- begin
- lasthp:=hp;
- hp:=hp.right
- end
- else
- begin
- if (hp.name=olds) then
- begin
- { Get in hp2 the replacer for the root or hasharr }
- hp2:=hp.left;
- hp3:=hp.right;
- if not assigned(hp2) then
- begin
- hp2:=hp.right;
- hp3:=hp.left;
- end;
- { remove entry from the tree }
- if assigned(lasthp) then
- begin
- if lasthp.left=hp then
- lasthp.left:=hp2
- else
- lasthp.right:=hp2;
- end
- else
- begin
- if assigned(FHashArray) then
- FHashArray^[spdval mod hasharraysize]:=hp2
- else
- FRoot:=hp2;
- end;
- { reinsert the hp3 in the tree from hp2 }
- inserttree(hp3,hp2);
- { reset Node with New values }
- hp.name:=newS;
- hp.FSpeedValue:=GetSpeedValue(newS);
- hp.left:=nil;
- hp.right:=nil;
- { reinsert }
- if assigned(FHashArray) then
- rename:=insertNode(hp,FHashArray^[hp.SpeedValue mod hasharraysize])
- else
- rename:=insertNode(hp,FRoot);
- exit;
- end
- else
- if olds>hp.name then
- begin
- lasthp:=hp;
- hp:=hp.left
- end
- else
- begin
- lasthp:=hp;
- hp:=hp.right;
- end;
- end;
- end;
- end;
- function Tdictionary.search(const s:string):TDictionaryItem;
- begin
- search:=speedsearch(s,GetSpeedValue(s));
- end;
- function Tdictionary.speedsearch(const s:string;SpeedValue:Cardinal):TDictionaryItem;
- var
- NewNode:TDictionaryItem;
- begin
- if assigned(FHashArray) then
- NewNode:=FHashArray^[SpeedValue mod hasharraysize]
- else
- NewNode:=FRoot;
- while assigned(NewNode) do
- begin
- if SpeedValue>NewNode.SpeedValue then
- NewNode:=NewNode.left
- else
- if SpeedValue<NewNode.SpeedValue then
- NewNode:=NewNode.right
- else
- begin
- if (NewNode.name=s) then
- begin
- speedsearch:=NewNode;
- exit;
- end
- else
- if s>NewNode.name then
- NewNode:=NewNode.left
- else
- NewNode:=NewNode.right;
- end;
- end;
- speedsearch:=nil;
- end;
- end.
|