/[projects]/dao/DelphiScanner/Components/tpsystools_4.04/source/StHASH.pas
ViewVC logotype

Annotation of /dao/DelphiScanner/Components/tpsystools_4.04/source/StHASH.pas

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2671 - (hide annotations) (download)
Tue Aug 25 18:15:15 2015 UTC (8 years, 10 months ago) by torben
File size: 25905 byte(s)
Added tpsystools component
1 torben 2671 // Upgraded to Delphi 2009: Sebastian Zierer
2    
3     (* ***** BEGIN LICENSE BLOCK *****
4     * Version: MPL 1.1
5     *
6     * The contents of this file are subject to the Mozilla Public License Version
7     * 1.1 (the "License"); you may not use this file except in compliance with
8     * the License. You may obtain a copy of the License at
9     * http://www.mozilla.org/MPL/
10     *
11     * Software distributed under the License is distributed on an "AS IS" basis,
12     * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13     * for the specific language governing rights and limitations under the
14     * License.
15     *
16     * The Original Code is TurboPower SysTools
17     *
18     * The Initial Developer of the Original Code is
19     * TurboPower Software
20     *
21     * Portions created by the Initial Developer are Copyright (C) 1996-2002
22     * the Initial Developer. All Rights Reserved.
23     *
24     * Contributor(s):
25     *
26     * ***** END LICENSE BLOCK ***** *)
27    
28     {*********************************************************}
29     {* SysTools: StHASH.PAS 4.04 *}
30     {*********************************************************}
31     {* SysTools: Hash table class *}
32     {*********************************************************}
33    
34     {$I StDefine.inc}
35    
36     {Notes:
37     - Generally the same as STDICT.PAS, but the hash table is
38     keyed on elements of arbitrary type rather than just strings.
39    
40     - Also manages an LRU counter and updates each node's LRU when
41     it is added or accessed. If the maximum allowed number of nodes
42     in the table is exceeded, the least recently used node is
43     automatically removed from the table. By default, MaxLongInt
44     nodes can be in the table so the automatic removal logic does
45     not come into play. When a node is automatically removed, the
46     NodeRemoved virtual method is called to notify the program
47     that the node is being removed.
48     }
49    
50     unit StHASH;
51    
52     interface
53    
54     uses
55     SysUtils,
56     Classes,
57     {$IFDEF ThreadSafe}
58     Windows,
59     {$ENDIF}
60     StConst,
61     StBase;
62    
63     type
64     TStHashNode = class(TStNode)
65     {.Z+}
66     protected
67     hnNext : TStHashNode; {Next node in hash list}
68     hnValue: Pointer; {Pointer to value of element}
69     hnValSize : Cardinal; {Size of hnValue memory block}
70     FLRU : LongInt; {LRU counter of this node}
71    
72     function GetValue : Pointer;
73    
74     {.Z-}
75     public
76     constructor CreateNode(const AValue; AValSize : Cardinal; AData : Pointer);
77     virtual;
78     {-Initialize node}
79     destructor Destroy; override;
80     {-Free name string and destroy node}
81    
82     property Value : Pointer
83     read GetValue;
84     property LRU : LongInt
85     read FLRU
86     write FLRU;
87     end;
88    
89     {.Z+}
90     THashArray = array[0..(MaxInt div SizeOf(TStHashNode))-1] of TStHashNode;
91     PHashArray = ^THashArray;
92     {.Z-}
93    
94     THashFunc = function (const V; Size : Integer) : Integer;
95    
96     TStHashTable = class(TStContainer)
97     {.Z+}
98     protected
99     {property instance variables}
100     FValSize : Cardinal; {Size of each element in table}
101     FHashSize : Integer; {Bins in hash array}
102     FEqual : TUntypedCompareFunc; {Element compare function}
103     FHash : THashFunc; {Hash function}
104     FMaxNodes : LongInt; {Max nodes allowed in table}
105    
106     {private instance variables}
107     htHeads : PHashArray; {Pointer to head of node lists}
108     htTails : PHashArray; {Pointer to tail of node lists}
109     htLRU : LongInt; {LRU counter}
110     htIgnoreDups : Boolean; {Ignore duplicates during Join?}
111    
112     {protected undocumented methods}
113     procedure htInsertNode(H : Integer; This : TStHashNode);
114     procedure htIterate(Action : TIterateFunc; OtherData : Pointer;
115     var H : Integer; var Prev, This : TStHashNode);
116     procedure htSetEqual(E : TUntypedCompareFunc);
117     procedure htSetHash(H : THashFunc);
118     procedure htSetHashSize(Size : Integer);
119     procedure htSetMaxNodes(Nodes : LongInt);
120     procedure htMoveToFront(H : Integer; Prev, This : TStHashNode);
121     procedure htFindNode(const V; var H : Integer;
122     var Prev, This : TStHashNode);
123     procedure htUpdateLRU(This : TStHashNode);
124     procedure htDeleteOldestNode;
125    
126     {.Z-}
127     public
128     constructor Create(AValSize : Cardinal; AHashSize : Integer); virtual;
129     {-Initialize an empty hash table}
130     destructor Destroy; override;
131     {-Destroy a hash table}
132    
133     procedure LoadFromStream(S : TStream); override;
134     {-Read a hash table and its data from a stream}
135     procedure StoreToStream(S : TStream); override;
136     {-Write a hash table and its data to a stream}
137    
138     procedure Clear; override;
139     {-Remove all nodes from container but leave it instantiated}
140    
141     function Exists(const V; var Data : Pointer) : Boolean;
142     {-Return True and the Data pointer if V is in the hash table}
143     procedure Add(const V; Data : Pointer);
144     {-Add new value and Data to the hash table}
145     procedure Delete(const V);
146     {-Delete a value from the hash table}
147     procedure Update(const V; Data : Pointer);
148     {-Update the data for an existing element}
149     function Find(Data : Pointer; var V) : Boolean;
150     {-Return True and the element value that matches Data}
151    
152     procedure Assign(Source: TPersistent); override;
153     {-Assign another hash table's contents to this one}
154     procedure Join(H : TStHashTable; IgnoreDups : Boolean);
155     {-Add hash table H into this one and dispose H}
156    
157     function Iterate(Action : TIterateFunc;
158     OtherData : Pointer) : TStHashNode;
159     {-Call Action for all the nodes, returning the last node visited}
160    
161     procedure NodeRemoved(const V; Data : Pointer); virtual;
162     {-Called when a not recently used node is removed from the table}
163    
164     function BinCount(H : Integer) : LongInt;
165     {-Return number of names in a hash bin (for testing)}
166    
167     property Equal : TUntypedCompareFunc
168     {-Change the string compare function; only for an empty table}
169     read FEqual
170     write htSetEqual;
171    
172     property Hash : THashFunc
173     {-Change the hash function; only for an empty table}
174     read FHash
175     write htSetHash;
176    
177     property HashSize : Integer
178     {-Change the hash table size; preserves existing elements}
179     read FHashSize
180     write htSetHashSize;
181    
182     property ValSize : Cardinal
183     {-Read the size of each element in the table}
184     read FValSize;
185    
186     property MaxNodes : LongInt
187     {-Change the maximum nodes in the table}
188     read FMaxNodes
189     write htSetMaxNodes;
190     end;
191    
192     {======================================================================}
193    
194     implementation
195    
196     {$IFDEF ThreadSafe}
197     var
198     ClassCritSect : TRTLCriticalSection;
199     {$ENDIF}
200    
201     procedure EnterClassCS;
202     begin
203     {$IFDEF ThreadSafe}
204     EnterCriticalSection(ClassCritSect);
205     {$ENDIF}
206     end;
207    
208     procedure LeaveClassCS;
209     begin
210     {$IFDEF ThreadSafe}
211     LeaveCriticalSection(ClassCritSect);
212     {$ENDIF}
213     end;
214    
215    
216    
217     {----------------------------------------------------------------------}
218    
219     constructor TStHashNode.CreateNode(const AValue; AValSize : Cardinal;
220     AData : Pointer);
221     begin
222     Create(AData);
223     hnValSize := AValSize;
224     GetMem(hnValue, AValSize);
225     Move(AValue, hnValue^, AValSize);
226     end;
227    
228     destructor TStHashNode.Destroy;
229     begin
230     if Assigned(hnValue) then
231     FreeMem(hnValue, hnValSize);
232     inherited Destroy;
233     end;
234    
235     function TStHashNode.GetValue : Pointer;
236     begin
237     Result := hnValue;
238     end;
239    
240     {----------------------------------------------------------------------}
241    
242     procedure TStHashTable.Add(const V; Data : Pointer);
243     var
244     H : Integer;
245     P, T : TStHashNode;
246     begin
247     {$IFDEF ThreadSafe}
248     EnterCS;
249     try
250     {$ENDIF}
251     htFindNode(V, H, P, T);
252     if Assigned(T) then
253     RaiseContainerError(stscDupNode);
254     htInsertNode(H, TStHashNode.CreateNode(V, FValSize, Data));
255     {$IFDEF ThreadSafe}
256     finally
257     LeaveCS;
258     end;
259     {$ENDIF}
260     end;
261    
262     function AssignNode(Container : TStContainer;
263     Node : TStNode;
264     OtherData : Pointer) : Boolean; far;
265     var
266     HashNode : TStHashNode absolute Node;
267     OurHashTbl : TStHashTable absolute OtherData;
268     begin
269     OurHashTbl.Add(HashNode.Value^, HashNode.Data);
270     Result := true;
271     end;
272    
273     procedure TStHashTable.Assign(Source: TPersistent);
274     begin
275     {$IFDEF ThreadSafe}
276     EnterCS;
277     try
278     {$ENDIF}
279     {The only container that we allow to be assigned to a hash table
280     is... another hash table}
281     if (Source is TStHashTable) then begin
282     Clear;
283     FValSize := TStHashTable(Source).ValSize;
284     TStHashTable(Source).Iterate(AssignNode, Self);
285     end
286     else
287     inherited Assign(Source);
288     {$IFDEF ThreadSafe}
289     finally
290     LeaveCS;
291     end;
292     {$ENDIF}
293     end;
294    
295    
296     function TStHashTable.BinCount(H : Integer) : LongInt;
297     var
298     C : LongInt;
299     T : TStHashNode;
300     begin
301     {$IFDEF ThreadSafe}
302     EnterCS;
303     try
304     {$ENDIF}
305     C := 0;
306     T := htHeads^[H];
307     while Assigned(T) do begin
308     inc(C);
309     T := T.hnNext;
310     end;
311     Result := C;
312     {$IFDEF ThreadSafe}
313     finally
314     LeaveCS;
315     end;
316     {$ENDIF}
317     end;
318    
319     procedure TStHashTable.Clear;
320     var
321     TableSize : Cardinal;
322     begin
323     {$IFDEF ThreadSafe}
324     EnterCS;
325     try
326     {$ENDIF}
327     if FCount <> 0 then begin
328     Iterate(DestroyNode, nil);
329     FCount := 0;
330     htLRU := 0;
331     TableSize := FHashSize*SizeOf(TStHashNode);
332     FillChar(htHeads^, TableSize, 0);
333     FillChar(htTails^, TableSize, 0);
334     end;
335     {$IFDEF ThreadSafe}
336     finally
337     LeaveCS;
338     end;
339     {$ENDIF}
340     end;
341    
342     constructor TStHashTable.Create(AValSize : Cardinal; AHashSize : Integer);
343     begin
344     if AValSize = 0 then
345     RaiseContainerError(stscBadSize);
346    
347     CreateContainer(TStHashNode, 0);
348    
349     FValSize := AValSize;
350     FMaxNodes := MaxLongInt;
351    
352     {allocate hash table by assigning to the HashSize property}
353     HashSize := AHashSize;
354     end;
355    
356     procedure TStHashTable.Delete(const V);
357     var
358     H : Integer;
359     P, T : TStHashNode;
360     begin
361     {$IFDEF ThreadSafe}
362     EnterCS;
363     try
364     {$ENDIF}
365     htFindNode(V, H, P, T);
366     if Assigned(T) then begin
367     if Assigned(P) then
368     P.hnNext := T.hnNext
369     else
370     htHeads^[H] := T.hnNext;
371     if T = htTails^[H] then
372     htTails^[H] := P;
373     DestroyNode(Self, T, nil);
374     Dec(FCount);
375     end;
376     {$IFDEF ThreadSafe}
377     finally
378     LeaveCS;
379     end;
380     {$ENDIF}
381     end;
382    
383     destructor TStHashTable.Destroy;
384     var
385     TableSize : Cardinal;
386     begin
387     if conNodeProt = 0 then
388     Clear;
389     TableSize := FHashSize*SizeOf(TStHashNode);
390     if Assigned(htHeads) then
391     FreeMem(htHeads, TableSize);
392     if Assigned(htTails) then
393     FreeMem(htTails, TableSize);
394     IncNodeProtection;
395     inherited Destroy;
396     end;
397    
398     function TStHashTable.Exists(const V; var Data : Pointer) : Boolean;
399     var
400     H : Integer;
401     P, T : TStHashNode;
402     begin
403     {$IFDEF ThreadSafe}
404     EnterCS;
405     try
406     {$ENDIF}
407     htFindNode(V, H, P, T);
408     if Assigned(T) then begin
409     htMoveToFront(H, P, T);
410     htUpdateLRU(T);
411     Result := True;
412     Data := T.Data;
413     end else
414     Result := False;
415     {$IFDEF ThreadSafe}
416     finally
417     LeaveCS;
418     end;
419     {$ENDIF}
420     end;
421    
422     function FindNodeData(Container : TStContainer; Node : TStNode;
423     OtherData : Pointer) : Boolean; far;
424     begin
425     Result := (OtherData <> Node.Data);
426     end;
427    
428     function TStHashTable.Find(Data : Pointer; var V) : Boolean;
429     var
430     H : Integer;
431     P, T : TStHashNode;
432     begin
433     {$IFDEF ThreadSafe}
434     EnterCS;
435     try
436     {$ENDIF}
437     htIterate(FindNodeData, Data, H, P, T);
438     if Assigned(T) then begin
439     htMoveToFront(H, P, T);
440     htUpdateLRU(T);
441     Result := True;
442     Move(T.Value^, V, FValSize);
443     end else
444     Result := False;
445     {$IFDEF ThreadSafe}
446     finally
447     LeaveCS;
448     end;
449     {$ENDIF}
450     end;
451    
452     procedure TStHashTable.htDeleteOldestNode;
453     {-Find and delete the hash node with the smallest LRU counter}
454     var
455     H, MinH : Integer;
456     MinLRU : LongInt;
457     T, P : TStHashNode;
458     begin
459     if FCount <> 0 then begin
460     MinLRU := MaxLongInt;
461     MinH := 0;
462     for H := 0 to FHashSize-1 do
463     if Assigned(htTails^[H]) and (htTails^[H].LRU <= MinLRU) then begin
464     MinH := H;
465     MinLRU := htTails^[H].LRU;
466     end;
467    
468     {notify the application}
469     with htTails^[MinH] do
470     NodeRemoved(hnValue^, Data);
471    
472     {destroy the node}
473     DestroyNode(Self, htTails^[MinH], nil);
474     dec(FCount);
475    
476     {remove the node}
477     if htTails^[MinH] = htHeads^[MinH] then begin
478     {only node in this bin}
479     htTails^[MinH] := nil;
480     htHeads^[MinH] := nil;
481     end else begin
482     {at least two nodes in this bin}
483     T := htHeads^[MinH];
484     P := nil;
485     while T <> htTails^[MinH] do begin
486     P := T;
487     T := T.hnNext;
488     end;
489     P.hnNext := nil;
490     htTails^[MinH] := P;
491     end;
492     end;
493     end;
494    
495     procedure TStHashTable.htFindNode(const V; var H : Integer;
496     var Prev, This : TStHashNode);
497     var
498     P, T : TStHashNode;
499     begin
500     if not(Assigned(FEqual) and Assigned(FHash)) then
501     RaiseContainerError(stscNoCompare);
502    
503     Prev := nil;
504     This := nil;
505     H := FHash(V, HashSize);
506     T := htHeads^[H];
507     P := nil;
508     while Assigned(T) do begin
509     if FEqual(V, T.Value^) = 0 then begin
510     Prev := P;
511     This := T;
512     Exit;
513     end;
514     P := T;
515     T := T.hnNext;
516     end;
517    
518     {not found}
519     This := nil;
520     end;
521    
522     procedure TStHashTable.htInsertNode(H : Integer; This : TStHashNode);
523     {-Insert node This at front of hash bin H}
524     var
525     P : TStHashNode;
526     begin
527     P := htHeads^[H];
528     htHeads^[H] := This;
529     if not Assigned(htTails^[H]) then
530     htTails^[H] := This;
531     This.hnNext := P;
532     htUpdateLRU(This);
533     Inc(FCount);
534     if FCount > FMaxNodes then
535     htDeleteOldestNode;
536     end;
537    
538     procedure TStHashTable.htIterate(Action : TIterateFunc; OtherData : Pointer;
539     var H : Integer; var Prev, This : TStHashNode);
540     {-Internal version of Iterate that returns more details}
541     var
542     AHash : Integer;
543     P, T, N : TStHashNode;
544     begin
545     if FCount <> 0 then begin
546     for AHash := 0 to FHashSize-1 do begin
547     T := htHeads^[AHash];
548     P := nil;
549     while Assigned(T) do begin
550     N := T.hnNext;
551     if Action(Self, T, OtherData) then begin
552     P := T;
553     T := N;
554     end else begin
555     H := AHash;
556     Prev := P;
557     This := T;
558     Exit;
559     end;
560     end;
561     end;
562     end;
563     This := nil;
564     end;
565    
566     procedure TStHashTable.htMoveToFront(H : Integer; Prev, This : TStHashNode);
567     {-Move This to front of list}
568     begin
569     if Assigned(Prev) then begin
570     Prev.hnNext := This.hnNext;
571     This.hnNext := htHeads^[H];
572     htHeads^[H] := This;
573     if This = htTails^[H] then
574     htTails^[H] := Prev;
575     end;
576     end;
577    
578     procedure TStHashTable.htSetEqual(E : TUntypedCompareFunc);
579     begin
580     {$IFDEF ThreadSafe}
581     EnterCS;
582     try
583     {$ENDIF}
584     if Count = 0 then
585     FEqual := E;
586     {$IFDEF ThreadSafe}
587     finally
588     LeaveCS;
589     end;
590     {$ENDIF}
591     end;
592    
593     procedure TStHashTable.htSetHash(H : THashFunc);
594     begin
595     {$IFDEF ThreadSafe}
596     EnterCS;
597     try
598     {$ENDIF}
599     if Count = 0 then
600     FHash := H;
601     {$IFDEF ThreadSafe}
602     finally
603     LeaveCS;
604     end;
605     {$ENDIF}
606     end;
607    
608     procedure TStHashTable.htSetHashSize(Size : Integer);
609     var
610     HInx : integer;
611     TableSize: LongInt;
612     Temp : TStHashNode;
613     Node : TStHashNode;
614     OldHeads : PHashArray;
615     OldTails : PHashArray;
616     OldSize : Integer;
617     OldCount : Integer;
618     OldDisposeData : TDisposeDataProc;
619     OldOnDisposeData : TStDisposeDataEvent;
620     begin
621     {$IFDEF ThreadSafe}
622     EnterCS;
623     try
624     {$ENDIF}
625     {calculate the new table size}
626     TableSize := LongInt(Size) * sizeof(TStHashNode);
627     if (Size <= 0) {or (TableSize > MaxBlockSize)} then
628     RaiseContainerError(stscBadSize);
629    
630     {only do something if there's something to do}
631     if (Size <> FHashSize) then begin
632    
633     {Notes: lots of things are going to be happening here: new
634     allocations, nodes copied from the old table to the new,
635     etc. Ideally if an exception is raised we would like to
636     restore the hash table to the state it was in
637     originally, before letting the exception escape}
638    
639     {save enough data about the current state of the table to
640     allow restoring in case of an exception}
641     OldHeads := htHeads;
642     OldTails := htTails;
643     OldSize := FHashSize;
644     OldCount := FCount;
645     OldDisposeData := DisposeData;
646     OldOnDisposeData := OnDisposeData;
647    
648     {reset Self's data}
649     htHeads := nil;
650     htTails := nil;
651     FHashSize := Size;
652     FCount := 0;
653     DisposeData := nil;
654     OnDisposeData := nil;
655    
656     {from this point, exceptions can occur with impunity...}
657     try
658     {allocate the new head and tail tables}
659     htHeads := AllocMem(TableSize);
660     htTails := AllocMem(TableSize);
661    
662     {if there is data to transfer, do so}
663     if (OldHeads <> nil) and (OldCount <> 0) then begin
664     for HInx := 0 to pred(OldSize) do begin
665     Node := OldHeads^[HInx];
666     while Assigned(Node) do begin
667     Add(Node.hnValue^, Node.Data);
668     Node := Node.hnNext;
669     end;
670     end;
671     end;
672    
673     {now all the data has been transferred, we can
674     destroy the old table}
675     if (OldHeads <> nil) then begin
676     for HInx := 0 to pred(OldSize) do begin
677     Node := OldHeads^[HInx];
678     while Assigned(Node) do begin
679     Temp := Node;
680     Node := Node.hnNext;
681     Temp.Free;
682     end;
683     end;
684     FreeMem(OldHeads, OldSize * sizeof(TStHashNode));
685     end;
686     if (OldTails <> nil) then
687     FreeMem(OldTails, OldSize * sizeof(TStHashNode));
688    
689     {restore the disposedata routines}
690     DisposeData := OldDisposeData;
691     OnDisposeData := OldOnDisposeData;
692    
693     except
694     {destroy the new data}
695     if (htHeads <> nil) then begin
696     for HInx := 0 to pred(FHashSize) do begin
697     Node := htHeads^[HInx];
698     while Assigned(Node) do begin
699     Temp := Node;
700     Node := Node.hnNext;
701     Temp.Free;
702     end;
703     end;
704     FreeMem(htHeads, TableSize);
705     end;
706     if (htTails <> nil) then
707     FreeMem(htTails, TableSize);
708     {restore the old data}
709     htHeads := OldHeads;
710     htTails := OldTails;
711     FHashSize := OldSize;
712     FCount := OldCount;
713     DisposeData := OldDisposeData;
714     OnDisposeData := OldOnDisposeData;
715     {reraise the exception}
716     raise;
717     end;
718     end;
719     {$IFDEF ThreadSafe}
720     finally
721     LeaveCS;
722     end;
723     {$ENDIF}
724     end;
725    
726     procedure TStHashTable.htSetMaxNodes(Nodes : LongInt);
727     begin
728     if Nodes < 1 then
729     RaiseContainerError(stscBadSize);
730     FMaxNodes := Nodes;
731     while FCount > FMaxNodes do
732     htDeleteOldestNode;
733     end;
734    
735     type
736     TMinNode = record
737     MLRU : LongInt;
738     MNode : TStHashNode;
739     end;
740     PMinNode = ^TMinNode;
741    
742     function FindMinPositiveNode(Container : TStContainer;
743     Node : TStNode;
744     OtherData : Pointer) : Boolean; far;
745     {-Used to find the smallest non-negative LRU in the table}
746     begin
747     with PMinNode(OtherData)^, TStHashNode(Node) do
748     if (LRU >= 0) and (LRU <= MLRU) then begin
749     MLRU := LRU;
750     MNode := TStHashNode(Node);
751     end;
752     Result := True;
753     end;
754    
755     function NegateNodeLRU(Container : TStContainer;
756     Node : TStNode;
757     OtherData : Pointer) : Boolean; far;
758     {-Used to negate the LRU values of all nodes in the table}
759     begin
760     with TStHashNode(Node) do
761     LRU := -LRU;
762     Result := True;
763     end;
764    
765     procedure TStHashTable.htUpdateLRU(This : TStHashNode);
766     {-Reassign all LRU values sequentially in their existing order}
767     var
768     MinNode : TMinNode;
769     begin
770     inc(htLRU);
771     This.LRU := htLRU;
772     if htLRU = MaxLongInt then begin
773     {scan table and pack LRU values}
774     htLRU := 0;
775     repeat
776     inc(htLRU);
777     MinNode.MLRU := MaxLongInt;
778     MinNode.MNode := nil;
779     Iterate(FindMinPositiveNode, @MinNode);
780     if not Assigned(MinNode.MNode) then
781     break;
782     {nodes already visited are set to a negative value}
783     {depends on never having an LRU of zero}
784     MinNode.MNode.LRU := -htLRU;
785     until False;
786     {negative values are made positive}
787     Iterate(NegateNodeLRU, nil);
788     end;
789     end;
790    
791     function TStHashTable.Iterate(Action : TIterateFunc;
792     OtherData : Pointer) : TStHashNode;
793     var
794     H : Integer;
795     P : TStHashNode;
796     begin
797     {$IFDEF ThreadSafe}
798     EnterCS;
799     try
800     {$ENDIF}
801     htIterate(Action, OtherData, H, P, Result);
802     {$IFDEF ThreadSafe}
803     finally
804     LeaveCS;
805     end;
806     {$ENDIF}
807     end;
808    
809     function JoinNode(Container : TStContainer;
810     Node : TStNode;
811     OtherData : Pointer) : Boolean; far;
812     {-Used to add nodes from another table into this one}
813     var
814     H : Integer;
815     P, T : TStHashNode;
816     begin
817     Result := True;
818     with TStHashTable(OtherData) do begin
819     htFindNode(TStHashNode(Node).Value^, H, P, T);
820     if Assigned(T) then
821     if htIgnoreDups then begin
822     Node.Free;
823     Exit;
824     end else
825     RaiseContainerError(stscDupNode);
826     htInsertNode(H, TStHashNode(Node));
827     end;
828     end;
829    
830     procedure TStHashTable.Join(H : TStHashTable; IgnoreDups : Boolean);
831     begin
832     {$IFDEF ThreadSafe}
833     EnterClassCS;
834     EnterCS;
835     H.EnterCS;
836     try
837     {$ENDIF}
838     htIgnoreDups := IgnoreDups;
839     H.Iterate(JoinNode, Self);
840     {dispose of D, but not its nodes}
841     H.IncNodeProtection;
842     H.Free;
843     {$IFDEF ThreadSafe}
844     finally
845     H.LeaveCS;
846     LeaveCS;
847     LeaveClassCS;
848     end;
849     {$ENDIF}
850     end;
851    
852     procedure TStHashTable.LoadFromStream(S : TStream);
853     var
854     Data, Value : Pointer;
855     AValSize : Cardinal;
856     Reader : TReader;
857     StreamedClass : TPersistentClass;
858     StreamedNodeClass : TPersistentClass;
859     StreamedClassName : string;
860     StreamedNodeClassName : string;
861     begin
862     {$IFDEF ThreadSafe}
863     EnterCS;
864     try
865     {$ENDIF}
866     Clear;
867     Reader := TReader.Create(S, 1024);
868     try
869     with Reader do begin
870     StreamedClassName := ReadString;
871     StreamedClass := GetClass(StreamedClassName);
872     if not Assigned(StreamedClass) then
873     RaiseContainerErrorFmt(stscUnknownClass, [StreamedClassName]);
874     if (StreamedClass <> Self.ClassType) then
875     RaiseContainerError(stscWrongClass);
876     StreamedNodeClassName := ReadString;
877     StreamedNodeClass := GetClass(StreamedNodeClassName);
878     if not Assigned(StreamedNodeClass) then
879     RaiseContainerErrorFmt(stscUnknownNodeClass, [StreamedNodeClassName]);
880     if (StreamedNodeClass <> conNodeClass) then
881     RaiseContainerError(stscWrongNodeClass);
882    
883     AValSize := ReadInteger;
884     if AValSize <> FValSize then
885     RaiseContainerError(stscBadSize);
886     HashSize := ReadInteger;
887     FMaxNodes := ReadInteger;
888     GetMem(Value, FValSize);
889     try
890     ReadListBegin;
891     while not EndOfList do begin
892     ReadBoolean;
893     Read(Value^, FValSize);
894     Data := DoLoadData(Reader);
895     Add(Value^, Data);
896     end;
897     ReadListEnd;
898     finally
899     FreeMem(Value, FValSize);
900     end;
901     end;
902     finally
903     Reader.Free;
904     end;
905     {$IFDEF ThreadSafe}
906     finally
907     LeaveCS;
908     end;
909     {$ENDIF}
910     end;
911    
912     procedure TStHashTable.NodeRemoved(const V; Data : Pointer);
913     begin
914     {does nothing by default}
915     end;
916    
917     procedure TStHashTable.StoreToStream(S : TStream);
918     var
919     H : Integer;
920     Walker : TStHashNode;
921     Writer : TWriter;
922     begin
923     {$IFDEF ThreadSafe}
924     EnterCS;
925     try
926     {$ENDIF}
927     Writer := TWriter.Create(S, 1024);
928     try
929     with Writer do begin
930     WriteString(Self.ClassName);
931     WriteString(conNodeClass.ClassName);
932     WriteInteger(FValSize);
933     WriteInteger(FHashSize);
934     WriteInteger(FMaxNodes);
935     WriteListBegin;
936     if Count <> 0 then
937     for H := 0 to FHashSize-1 do begin
938     Walker := htHeads^[H];
939     while Assigned(Walker) do begin
940     {writing the True boolean prevents false termination of the
941     list if Value's first byte is zero when the stream is
942     loaded into another hash table}
943     WriteBoolean(True);
944     Write(Walker.Value^, FValSize);
945     DoStoreData(Writer, Walker.Data);
946     Walker := Walker.hnNext;
947     end;
948     end;
949     WriteListEnd;
950     end;
951     finally
952     Writer.Free;
953     end;
954     {$IFDEF ThreadSafe}
955     finally
956     LeaveCS;
957     end;
958     {$ENDIF}
959     end;
960    
961     procedure TStHashTable.Update(const V; Data : Pointer);
962     var
963     H : Integer;
964     P, T : TStHashNode;
965     begin
966     {$IFDEF ThreadSafe}
967     EnterCS;
968     try
969     {$ENDIF}
970     htFindNode(V, H, P, T);
971     if Assigned(T) then begin
972     htMoveToFront(H, P, T);
973     htUpdateLRU(T);
974     T.Data := Data;
975     end;
976     {$IFDEF ThreadSafe}
977     finally
978     LeaveCS;
979     end;
980     {$ENDIF}
981     end;
982    
983     {$IFDEF ThreadSafe}
984     initialization
985     Windows.InitializeCriticalSection(ClassCritSect);
986     finalization
987     Windows.DeleteCriticalSection(ClassCritSect);
988     {$ENDIF}
989     end.

  ViewVC Help
Powered by ViewVC 1.1.20