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

Annotation of /dao/DelphiScanner/Components/tpsystools_4.04/source/StLArr.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: 37192 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: StLArr.pas 4.04 *}
30     {*********************************************************}
31     {* SysTools: Large array classes *}
32     {*********************************************************}
33    
34     {$I StDefine.inc}
35    
36     {Notes:
37     - requires a 386 or better processor, even for 16-bit Delphi apps
38    
39     - uses the value in the SYSTEM variable HeapAllocFlags when allocating
40     memory for the array.
41    
42     - changing the size of an array allocates a new array, transfers the
43     old data, and then frees the original array.
44    
45     - arrays are always indexed from 0 to Count-1.
46    
47     - after creating a descendant that knows the type of each element, an
48     indexed default property can be used to access array elements in a
49     convenient fashion, e.g., A[100] := 6.0;
50    
51     - the Get and Put methods don't perform range checking.
52    
53     - for 32-bit matrix, Rows*Cols cannot exceed 2**32.
54     }
55    
56     unit StLArr;
57    
58     interface
59    
60     uses
61     Windows,
62     Classes, StConst, StBase;
63    
64     type
65     TStLArray = class(TStContainer)
66     {.Z+}
67     protected
68     {property instance variables}
69     FElSize : Integer; {Size of each array element}
70     FElStorable : boolean; {True if elements can be stored directly}
71    
72     {private instance variables}
73     laData : Pointer; {Pointer to data block}
74    
75     {undocumented protected methods}
76     procedure ForEachUntypedVar(Action : TIterateUntypedFunc;
77     OtherData : pointer);
78     override;
79     procedure GetArraySizes(var RowCount, ColCount, ElSize : Cardinal);
80     override;
81     procedure SetArraySizes(RowCount, ColCount, ElSize : Cardinal);
82     override;
83     function StoresUntypedVars : boolean;
84     override;
85     procedure laSetCount(Elements : LongInt);
86    
87     {.Z-}
88     public
89     constructor Create(Elements : LongInt; ElementSize : Cardinal);
90     {-Initialize a large 1D array}
91     destructor Destroy; override;
92     {-Free a large 1D array}
93    
94     procedure LoadFromStream(S : TStream); override;
95     {-Load a collection's data from a stream}
96     procedure StoreToStream(S : TStream); override;
97     {-Write a collection and its data to a stream}
98    
99     procedure Assign(Source: TPersistent); override;
100     {-Assign another container's contents to this one}
101     procedure Clear; override;
102     {-Fill the array with zeros}
103    
104     procedure Fill(const Value);
105     {-Fill array with specified value}
106    
107     procedure Put(El : LongInt; const Value);
108     {-Set an element}
109     procedure Get(El : LongInt; var Value);
110     {-Return an element}
111    
112     procedure Exchange(El1, El2 : LongInt);
113     {-Exchange the specified elements}
114     procedure Sort(Compare : TUntypedCompareFunc);
115     {-Sort the array using the given comparison function}
116    
117     property Count : LongInt
118     {-Read or write the number of elements in the array}
119     read FCount
120     write laSetCount;
121    
122     property ElementSize : Integer
123     read FElSize;
124    
125     property ElementsStorable : boolean
126     {-True if elements can be written directly to (or read from) disk}
127     read FElStorable write FElStorable;
128     end;
129    
130     type
131     TStLMatrix = class(TStContainer)
132     {.Z+}
133     protected
134     {property instance variables}
135     FElSize : Integer; {Size of each array element}
136     FCols : Cardinal; {Number of columns}
137     FRows : Cardinal; {Number of rows}
138     FElStorable : boolean; {True if elements can be stored directly}
139    
140     {private instance variables}
141     lmData : Pointer; {Pointer to data block}
142     lmRowSize : LongInt; {Number of bytes in a row}
143    
144     {undocumented protected methods}
145     procedure ForEachUntypedVar(Action : TIterateUntypedFunc; OtherData : pointer);
146     override;
147     procedure GetArraySizes(var RowCount, ColCount, ElSize : Cardinal);
148     override;
149     procedure SetArraySizes(RowCount, ColCount, ElSize : Cardinal);
150     override;
151     function StoresUntypedVars : boolean;
152     override;
153     procedure lmSetRows(Rows : Cardinal);
154     procedure lmSetCols(Cols : Cardinal);
155    
156     {.Z-}
157     public
158     constructor Create(Rows, Cols, ElementSize : Cardinal);
159     {-Initialize a large 2D matrix}
160     destructor Destroy; override;
161     {-Free a large 2D matrix}
162    
163     procedure LoadFromStream(S : TStream); override;
164     {-Load a collection's data from a stream}
165     procedure StoreToStream(S : TStream); override;
166     {-Write a collection and its data to a stream}
167    
168     procedure Assign(Source: TPersistent); override;
169     {-Assign another container's contents to this one}
170     procedure Clear; override;
171     {-Fill the matrix with zeros}
172    
173     procedure Fill(const Value);
174     {-Fill matrix with specified value}
175    
176     procedure Put(Row, Col : Cardinal; const Value);
177     {-Set an element}
178     procedure Get(Row, Col : Cardinal; var Value);
179     {-Return an element}
180    
181     procedure PutRow(Row : Cardinal; const RowValue);
182     {-Set an entire row}
183     procedure GetRow(Row : Cardinal; var RowValue);
184     {-Return an entire row}
185    
186     procedure ExchangeRows(Row1, Row2 : Cardinal);
187     {-Exchange the specified rows}
188     procedure SortRows(KeyCol : Cardinal; Compare : TUntypedCompareFunc);
189     {-Sort the array rows using the given comparison function and
190     the elements in the given column}
191    
192     property Rows : Cardinal
193     {-Read or write the number of rows in the array}
194     read FRows
195     write lmSetRows;
196     property Cols : Cardinal
197     {-Read or write the number of columns in the array}
198     read FCols
199     write lmSetCols;
200     property ElementSize : Integer
201     read FElSize;
202     property ElementsStorable : boolean
203     {-True if elements can be written directly to (or read from) disk}
204     read FElStorable write FElStorable;
205     end;
206    
207     {======================================================================}
208    
209     implementation
210    
211     function AssignArrayData(Container : TStContainer;
212     var Data;
213     OtherData : Pointer) : Boolean; far;
214     var
215     OurArray : TStLArray absolute OtherData;
216     RD : TAssignRowData absolute Data;
217     begin
218     OurArray.Put(RD.RowNum, RD.Data);
219     Result := true;
220     end;
221    
222     function AssignMatrixData(Container : TStContainer;
223     var Data;
224     OtherData : Pointer) : Boolean; far;
225     var
226     OurMatrix : TStLMatrix absolute OtherData;
227     RD : TAssignRowData absolute Data;
228     begin
229     OurMatrix.PutRow(RD.RowNum, RD.Data);
230     Result := true;
231     end;
232    
233     procedure TStLArray.Assign(Source: TPersistent);
234     begin
235     {$IFDEF ThreadSafe}
236     EnterCS;
237     try
238     {$ENDIF}
239     {The only containers that we allow to be assigned to a large array
240     are:
241     - another SysTools large array (TStLArray)
242     - a SysTools large matrix (TStLMatrix) with one column
243     - a SysTools virtual matrix (TStVMatrix) with one column}
244     if not AssignUntypedVars(Source, AssignArrayData) then
245     inherited Assign(Source);
246     {$IFDEF ThreadSafe}
247     finally
248     LeaveCS;
249     end;{try..finally}
250     {$ENDIF}
251     end;
252    
253     procedure TStLArray.Clear;
254     var
255     C : LongInt;
256     begin
257     {$IFDEF ThreadSafe}
258     EnterCS;
259     try
260     {$ENDIF}
261     C := FCount;
262     HugeFillChar(laData^, C*FElSize, 0);
263     {$IFDEF ThreadSafe}
264     finally
265     LeaveCS;
266     end;
267     {$ENDIF}
268     end;
269    
270     procedure TStLArray.ForEachUntypedVar(Action : TIterateUntypedFunc;
271     OtherData : pointer);
272     var
273     FullRow : ^TAssignRowData;
274     i : Cardinal;
275     begin
276     {$IFDEF ThreadSafe}
277     EnterCS;
278     try
279     {$ENDIF}
280     GetMem(FullRow, sizeof(Cardinal) + ElementSize);
281     try
282     for i := 0 to pred(Count) do
283     begin
284     FullRow^.RowNum := i;
285     Get(i, FullRow^.Data);
286     Action(Self, FullRow^, OtherData);
287     end;
288     finally
289     FreeMem(FullRow, sizeof(Cardinal) + ElementSize);
290     end;
291     {$IFDEF ThreadSafe}
292     finally
293     LeaveCS;
294     end;
295     {$ENDIF}
296     end;
297    
298     procedure TStLArray.GetArraySizes(var RowCount, ColCount, ElSize : Cardinal);
299     begin
300     RowCount := Count;
301     ColCount := 1;
302     ElSize := ElementSize;
303     end;
304    
305     procedure TStLArray.SetArraySizes(RowCount, ColCount, ElSize : Cardinal);
306     begin
307     if (ColCount <> 1) then
308     RaiseContainerError(stscTooManyCols);
309     if (LongInt(RowCount) <> Count) or
310     (LongInt(ElSize) <> ElementSize) then begin
311     HugeFreeMem(laData, FCount*FElSize);
312     FCount := RowCount;
313     FElSize := ElSize;
314     HugeGetMem(laData, RowCount*ElSize);
315     Clear;
316     end;
317     end;
318    
319     function TStLArray.StoresUntypedVars : boolean;
320     begin
321     Result := True;
322     end;
323    
324     constructor TStLArray.Create(Elements : LongInt; ElementSize : Cardinal);
325     begin
326     if (Elements <= 0) or (ElementSize = 0) or
327     ProductOverflow(Elements, ElementSize) then
328     RaiseContainerError(stscBadSize);
329    
330     CreateContainer(TStNode, 0);
331    
332     FCount := Elements;
333     FElSize := ElementSize;
334    
335     HugeGetMem(laData, Elements*LongInt(ElementSize));
336     Clear;
337     end;
338    
339     destructor TStLArray.Destroy;
340     begin
341     HugeFreeMem(laData, FCount*FElSize);
342     IncNodeProtection;
343     inherited Destroy;
344     end;
345    
346     procedure TStLArray.Exchange(El1, El2 : LongInt);
347     begin
348     {$IFDEF ThreadSafe}
349     EnterCS;
350     try
351     {$ENDIF}
352     {$IFOPT R+}
353     if (El1 < 0) or (El1 >= Count) or (El2 < 0) or (El2 >= Count) then
354     RaiseContainerError(stscBadIndex);
355     {$ENDIF}
356     asm
357     mov eax,Self
358     push ebx
359     push esi
360     push edi
361    
362     mov esi,El1
363     mov edi,El2
364     mov ecx,TStLArray([eax]).FElSize
365     mov edx,TStLArray([eax]).laData
366     db $0F,$AF,$F1 {imul esi,ecx, compiler bug workaround}
367     add esi,edx
368     db $0F,$AF,$F9 {imul edi,ecx, compiler bug workaround}
369     add edi,edx
370     mov edx,ecx
371     shr ecx,2
372     jz @2
373    
374     @1: mov eax,[esi] {avoid xchg instruction, which is slow}
375     mov ebx,[edi]
376     mov [esi],ebx
377     mov [edi],eax
378     add esi,4
379     add edi,4
380     dec ecx
381     jnz @1
382    
383     @2: mov ecx,edx
384     and ecx,3
385     jz @4
386    
387     @3: mov al,[esi] {avoid xchg instruction, which is slow}
388     mov bl,[edi]
389     mov [esi],bl
390     mov [edi],al
391     inc esi
392     inc edi
393     dec ecx
394     jnz @3
395    
396     @4: pop edi
397     pop esi
398     pop ebx
399     end;
400     {$IFDEF ThreadSafe}
401     finally
402     LeaveCS;
403     end;
404     {$ENDIF}
405     end;
406    
407    
408     procedure TStLArray.Fill(const Value);
409     begin
410     {$IFDEF ThreadSafe}
411     EnterCS;
412     try
413     {$ENDIF}
414     HugeFillStruc(laData^, FCount, Value, FElSize);
415     {$IFDEF ThreadSafe}
416     finally
417     LeaveCS;
418     end;
419     {$ENDIF}
420     end;
421    
422     procedure TStLArray.Get(El : LongInt; var Value);
423     (* model for code below
424     begin
425     move((PChar(laData)+El*FElSize)^, Value, FElSize);
426     end;
427     *)
428     begin
429     {$IFDEF ThreadSafe}
430     EnterCS;
431     try
432     {$ENDIF}
433     {$IFOPT R+}
434     if (El < 0) or (El >= Count) then
435     RaiseContainerError(stscBadIndex);
436     {$ENDIF}
437     asm
438     mov eax,Self
439     push esi
440     push edi
441     mov edi,Value
442     mov ecx,TStLArray([eax]).FElSize
443     mov esi,El
444     db $0F,$AF,$F1 {imul esi,ecx, compiler bug workaround}
445     add esi,TStLArray([eax]).laData
446     mov eax,ecx
447     shr ecx,2
448     rep movsd
449     mov ecx,eax
450     and ecx,3
451     rep movsb
452     pop edi
453     pop esi
454     end;
455     {$IFDEF ThreadSafe}
456     finally
457     LeaveCS;
458     end;
459     {$ENDIF}
460     end;
461    
462    
463     procedure TStLArray.laSetCount(Elements : LongInt);
464     var
465     CurSize, NewSize : LongInt;
466     CurFData : Pointer;
467     begin
468     {$IFDEF ThreadSafe}
469     EnterCS;
470     try
471     {$ENDIF}
472     {validate new size}
473     if (Elements <= 0) or ProductOverflow(Elements, FElSize) then
474     RaiseContainerError(stscBadSize);
475    
476     NewSize := Elements*FElSize;
477     CurSize := FCount*FElSize;
478     CurFData := laData;
479    
480     {allocate data block of new size}
481     HugeGetMem(laData, NewSize);
482    
483     FCount := Elements;
484    
485     {fill extra area with zeros and copy old data}
486     if NewSize > CurSize then begin
487     Clear;
488     NewSize := CurSize;
489     end;
490     HugeMove(CurFData^, laData^, NewSize);
491    
492     {free original data area}
493     HugeFreeMem(CurFData, CurSize);
494     {$IFDEF ThreadSafe}
495     finally
496     LeaveCS;
497     end;
498     {$ENDIF}
499     end;
500    
501     procedure TStLArray.Put(El : LongInt; const Value);
502     (* model for assembly language below
503     begin
504     move(Value, (PChar(laData)+Row*FElSize)^, FElSize);
505     end;
506     *)
507     begin
508     {$IFDEF ThreadSafe}
509     EnterCS;
510     try
511     {$ENDIF}
512     {$IFOPT R+}
513     if (El < 0) or (El >= Count) then
514     RaiseContainerError(stscBadIndex);
515     {$ENDIF}
516     asm
517     mov eax,Self
518     push esi
519     push edi
520     mov esi,Value
521     mov ecx,TStLArray([eax]).FElSize
522     mov edi,El
523     db $0F,$AF,$F9 {imul edi,ecx, compiler bug workaround}
524     add edi,TStLArray([eax]).laData
525     mov eax,ecx
526     shr ecx,2
527     rep movsd
528     mov ecx,eax
529     and ecx,3
530     rep movsb
531     pop edi
532     pop esi
533     end;
534     {$IFDEF ThreadSafe}
535     finally
536     LeaveCS;
537     end;
538     {$ENDIF}
539     end;
540    
541     procedure TStLArray.Sort(Compare : TUntypedCompareFunc);
542     const
543     StackSize = 32;
544     type
545     Stack = array[0..StackSize-1] of LongInt;
546     var
547     L : LongInt;
548     R : LongInt;
549     PL : LongInt;
550     PR : LongInt;
551     CurEl : Pointer;
552     PivEl : Pointer;
553     StackP : Integer;
554     LStack : Stack;
555     RStack : Stack;
556     begin
557     {$IFDEF ThreadSafe}
558     EnterCS;
559     try
560     {$ENDIF}
561     {Need at least 2 elements to sort}
562     if FCount <= 1 then
563     Exit;
564    
565     GetMem(CurEl, FElSize);
566     try
567     GetMem(PivEl, FElSize);
568     try
569     {Initialize the stacks}
570     StackP := 0;
571     LStack[0] := 0;
572     RStack[0] := FCount-1;
573    
574     {Repeatedly take top partition from stack}
575     repeat
576    
577     {Pop the stack}
578     L := LStack[StackP];
579     R := RStack[StackP];
580     Dec(StackP);
581    
582     {Sort current partition}
583     repeat
584    
585     {Load the pivot element}
586     Get((L+R) div 2, PivEl^);
587     PL := L;
588     PR := R;
589    
590     {Swap items in sort order around the pivot index}
591     repeat
592     Get(PL, CurEl^);
593     while Compare(CurEl^, PivEl^) < 0 do begin
594     Inc(PL);
595     Get(PL, CurEl^);
596     end;
597     Get(PR, CurEl^);
598     while Compare(PivEl^, CurEl^) < 0 do begin
599     Dec(PR);
600     Get(PR, CurEl^);
601     end;
602     if PL <= PR then begin
603     if PL <> PR then
604     {Swap the two elements}
605     Exchange(PL, PR);
606     Inc(PL); {assume we'll never sort 2 billion elements}
607     Dec(PR);
608     end;
609     until PL > PR;
610    
611     {Decide which partition to sort next}
612     if (PR-L) < (R-PL) then begin
613     {Right partition is bigger}
614     if PL < R then begin
615     {Stack the request for sorting right partition}
616     Inc(StackP);
617     LStack[StackP] := PL;
618     RStack[StackP] := R;
619     end;
620     {Continue sorting left partition}
621     R := PR;
622     end else begin
623     {Left partition is bigger}
624     if L < PR then begin
625     {Stack the request for sorting left partition}
626     Inc(StackP);
627     LStack[StackP] := L;
628     RStack[StackP] := PR;
629     end;
630     {Continue sorting right partition}
631     L := PL;
632     end;
633    
634     until L >= R;
635     until StackP < 0;
636     finally
637     FreeMem(PivEl, FElSize);
638     end;
639     finally
640     FreeMem(CurEl, FElSize);
641     end;
642     {$IFDEF ThreadSafe}
643     finally
644     LeaveCS;
645     end;
646     {$ENDIF}
647     end;
648    
649     procedure TStLArray.LoadFromStream(S : TStream);
650     var
651     Data : pointer;
652     Reader : TReader;
653     NumElements : longint;
654     ElementSize : LongInt;
655     i : longint;
656     TotSize : longint;
657     StreamedClass : TPersistentClass;
658     StreamedClassName : string;
659     Value : TValueType;
660     begin
661     {$IFDEF ThreadSafe}
662     EnterCS;
663     try
664     {$ENDIF}
665     Clear;
666     Reader := TReader.Create(S, 1024);
667     try
668     with Reader do
669     begin
670     StreamedClassName := ReadString;
671     StreamedClass := GetClass(StreamedClassName);
672     if (StreamedClass = nil) then
673     RaiseContainerErrorFmt(stscUnknownClass, [StreamedClassName]);
674     if (not IsOrInheritsFrom(StreamedClass, Self.ClassType)) or
675     (not IsOrInheritsFrom(TStLArray, StreamedClass)) then
676     RaiseContainerError(stscWrongClass);
677     NumElements := ReadInteger;
678     ElementSize := ReadInteger;
679     if (NumElements <> FCount) or (ElementSize <> FElSize) then
680     begin
681     HugeFreeMem(laData, FCount*FElSize);
682     FCount := NumElements;
683     FElSize := ElementSize;
684     HugeGetMem(laData, NumElements*ElementSize);
685     Clear;
686     end;
687     ElementsStorable := ReadBoolean;
688     if ElementsStorable then
689     begin
690     Read(Value, sizeof(Value)); {s/b vaBinary}
691     Read(TotSize, sizeof(longint));
692     GetMem(Data, FElSize);
693     try
694     for i := 0 to pred(FCount) do
695     begin
696     Read(Data^, FElSize);
697     Put(i, Data^);
698     end;
699     finally
700     FreeMem(Data, FElSize);
701     end;
702     end
703     else
704     begin
705     ReadListBegin;
706     for i := 0 to pred(FCount) do begin
707     Data := DoLoadData(Reader);
708     Put(i, Data^);
709     end;
710     ReadListEnd;
711     end;
712     end;
713     finally
714     Reader.Free;
715     end;
716     {$IFDEF ThreadSafe}
717     finally
718     LeaveCS;
719     end;
720     {$ENDIF}
721     end;
722    
723     procedure TStLArray.StoreToStream(S : TStream);
724     var
725     Writer : TWriter;
726     i : integer;
727     Data : pointer;
728     TotSize: longint;
729     Value : TValueType;
730     begin
731     {$IFDEF ThreadSafe}
732     EnterCS;
733     try
734     {$ENDIF}
735     Writer := TWriter.Create(S, 1024);
736     try
737     GetMem(Data, FElSize);
738     try
739     with Writer do begin
740     WriteString(Self.ClassName);
741     WriteInteger(FCount);
742     WriteInteger(FElSize);
743     WriteBoolean(FElStorable);
744     if ElementsStorable then begin
745     Value := vaBinary;
746     Write(Value, sizeof(Value));
747     TotSize := FCount * FElSize;
748     Write(TotSize, sizeof(longint));
749     for i := 0 to pred(FCount) do begin
750     Get(i, Data^);
751     Write(Data^, FElSize);
752     end;
753     end else begin
754     WriteListBegin;
755     for i := 0 to pred(FCount) do begin
756     Get(i, Data^);
757     DoStoreData(Writer, Data);
758     end;
759     WriteListEnd;
760     end;
761     end;
762     finally
763     FreeMem(Data, FElSize);
764     end;
765     finally
766     Writer.Free;
767     end;
768     {$IFDEF ThreadSafe}
769     finally
770     LeaveCS;
771     end;
772     {$ENDIF}
773     end;
774    
775     {----------------------------------------------------------------------}
776    
777     procedure TStLMatrix.Assign(Source: TPersistent);
778     begin
779     {$IFDEF ThreadSafe}
780     EnterCS;
781     try
782     {$ENDIF}
783     {The only containers that we allow to be assigned to a large matrix
784     are:
785     - a SysTools large array (TStLArray)
786     - another SysTools large matrix (TStLMatrix)
787     - a SysTools virtual matrix (TStVMatrix)}
788     if not AssignUntypedVars(Source, AssignMatrixData) then
789     inherited Assign(Source);
790     {$IFDEF ThreadSafe}
791     finally
792     LeaveCS;
793     end;{try..finally}
794     {$ENDIF}
795     end;
796    
797     procedure TStLMatrix.Clear;
798     begin
799     {$IFDEF ThreadSafe}
800     EnterCS;
801     try
802     {$ENDIF}
803     HugeFillChar(lmData^, FCount*FElSize, 0);
804     {$IFDEF ThreadSafe}
805     finally
806     LeaveCS;
807     end;
808     {$ENDIF}
809     end;
810    
811     procedure TStLMatrix.ForEachUntypedVar(Action : TIterateUntypedFunc;
812     OtherData : pointer);
813     var
814     FullRow : ^TAssignRowData;
815     i : Cardinal;
816     begin
817     {$IFDEF ThreadSafe}
818     EnterCS;
819     try
820     {$ENDIF}
821     GetMem(FullRow, sizeof(Cardinal) + lmRowSize);
822     try
823     for i := 0 to pred(Rows) do
824     begin
825     FullRow^.RowNum := i;
826     GetRow(i, FullRow^.Data);
827     Action(Self, FullRow^, OtherData);
828     end;
829     finally
830     FreeMem(FullRow, sizeof(Cardinal) + lmRowSize);
831     end;
832     {$IFDEF ThreadSafe}
833     finally
834     LeaveCS;
835     end;
836     {$ENDIF}
837     end;
838    
839     procedure TStLMatrix.GetArraySizes(var RowCount, ColCount, ElSize : Cardinal);
840     begin
841     RowCount := Rows;
842     ColCount := Cols;
843     ElSize := ElementSize;
844     end;
845    
846     procedure TStLMatrix.SetArraySizes(RowCount, ColCount, ElSize : Cardinal);
847     begin
848     if (RowCount <> Rows) or (ColCount <> Cols) or
849     (LongInt(ElSize) <> ElementSize) then
850     begin
851     HugeFreeMem(lmData, FCount*FElSize);
852     FElSize := ElSize;
853     FRows := RowCount;
854     FCols := ColCount;
855     {$IFDEF VERSION4}
856     FCount := RowCount*ColCount;
857     lmRowSize := ColCount*ElSize;
858     HugeGetMem(lmData, FCount*LongInt(ElSize));
859     {$ELSE}
860     FCount := LongInt(RowCount)*ColCount;
861     lmRowSize := LongInt(ColCount)*ElSize;
862     HugeGetMem(lmData, FCount*ElSize);
863     {$ENDIF}
864     Clear;
865     end;
866     end;
867    
868     function TStLMatrix.StoresUntypedVars : boolean;
869     begin
870     Result := true;
871     end;
872    
873     constructor TStLMatrix.Create(Rows, Cols, ElementSize : Cardinal);
874     begin
875     CreateContainer(TStNode, 0);
876    
877     FElSize := ElementSize;
878     FRows := Rows;
879     FCols := Cols;
880     FCount := LongInt(Rows)*LongInt(Cols);
881     lmRowSize := LongInt(Cols)*LongInt(ElementSize);
882    
883     if (Rows = 0) or (Cols = 0) or (ElementSize = 0) or
884     ProductOverflow(FCount, ElementSize) then
885     RaiseContainerError(stscBadSize);
886    
887     HugeGetMem(lmData, FCount*LongInt(ElementSize));
888     Clear;
889     end;
890    
891     destructor TStLMatrix.Destroy;
892     begin
893     HugeFreeMem(lmData, FCount*FElSize);
894     IncNodeProtection;
895     inherited Destroy;
896     end;
897    
898     procedure TStLMatrix.ExchangeRows(Row1, Row2 : Cardinal);
899     begin
900     {$IFDEF ThreadSafe}
901     EnterCS;
902     try
903     {$ENDIF}
904     {$IFOPT R+}
905     if (Row1 >= Rows) or (Row2 >= Rows) then
906     RaiseContainerError(stscBadIndex);
907     {$ENDIF}
908     asm
909     mov eax,Self
910     push ebx
911     push esi
912     push edi
913    
914     mov esi,Row1
915     mov edi,Row2
916     mov ecx,TStLMatrix([eax]).lmRowSize
917     mov edx,TStLMatrix([eax]).lmData
918     db $0F,$AF,$F1 {imul esi,ecx, compiler bug workaround}
919     add esi,edx
920     db $0F,$AF,$F9 {imul edi,ecx, compiler bug workaround}
921     add edi,edx
922     mov edx,ecx
923     shr ecx,2
924     jz @2
925    
926     @1: mov eax,[esi] {avoid xchg instruction, which is slow}
927     mov ebx,[edi]
928     mov [esi],ebx
929     mov [edi],eax
930     add esi,4
931     add edi,4
932     dec ecx
933     jnz @1
934    
935     @2: mov ecx,edx
936     and ecx,3
937     jz @4
938    
939     @3: mov al,[esi] {avoid xchg instruction, which is slow}
940     mov bl,[edi]
941     mov [esi],bl
942     mov [edi],al
943     inc esi
944     inc edi
945     dec ecx
946     jnz @3
947    
948     @4: pop edi
949     pop esi
950     pop ebx
951     end;
952     {$IFDEF ThreadSafe}
953     finally
954     LeaveCS;
955     end;
956     {$ENDIF}
957     end;
958    
959     procedure TStLMatrix.Fill(const Value);
960     begin
961     {$IFDEF ThreadSafe}
962     EnterCS;
963     try
964     {$ENDIF}
965     HugeFillStruc(lmData^, FCount, Value, FElSize);
966     {$IFDEF ThreadSafe}
967     finally
968     LeaveCS;
969     end;
970     {$ENDIF}
971     end;
972    
973     procedure TStLMatrix.Get(Row, Col : Cardinal; var Value);
974     (* model for assembly language below
975     begin
976     move((PChar(lmData)+(Row*FCols+Col)*FElSize)^, Value, FElSize);
977     end;
978     *)
979     begin
980     {$IFDEF ThreadSafe}
981     EnterCS;
982     try
983     {$ENDIF}
984     if (Row >= Rows) or (Col >= Cols) then
985     RaiseContainerError(stscBadIndex);
986     asm
987     mov eax,Self
988     push esi
989     push edi
990     mov edi,Value
991     mov esi,Row
992     imul esi,TStLMatrix([eax]).FCols
993     add esi,Col
994     mov ecx,TStLMatrix([eax]).FElSize
995     db $0F,$AF,$F1 {imul esi,ecx, compiler bug workaround}
996     add esi,TStLMatrix([eax]).lmData
997     mov eax,ecx
998     shr ecx,2
999     rep movsd
1000     mov ecx,eax
1001     and ecx,3
1002     rep movsb
1003     pop edi
1004     pop esi
1005     end;
1006     {$IFDEF ThreadSafe}
1007     finally
1008     LeaveCS;
1009     end;
1010     {$ENDIF}
1011     end;
1012    
1013     procedure TStLMatrix.GetRow(Row : Cardinal; var RowValue);
1014     begin
1015     {$IFDEF ThreadSafe}
1016     EnterCS;
1017     try
1018     {$ENDIF}
1019     {$IFOPT R+}
1020     if Row >= Rows then
1021     RaiseContainerError(stscBadIndex);
1022     {$ENDIF}
1023     move((PAnsiChar(lmData)+(LongInt(Row)*lmRowSize))^, RowValue, lmRowSize);
1024     {$IFDEF ThreadSafe}
1025     finally
1026     LeaveCS;
1027     end;
1028     {$ENDIF}
1029     end;
1030    
1031     procedure TStLMatrix.lmSetCols(Cols : Cardinal);
1032     var
1033     CurSize, NewSize, CurRowSize, NewRowSize, BufSize : LongInt;
1034     R, CurCols : Cardinal;
1035     CurFData, NewFData, RowData : Pointer;
1036     begin
1037     {$IFDEF ThreadSafe}
1038     EnterCS;
1039     try
1040     {$ENDIF}
1041     if Cols = FCols then
1042     Exit;
1043    
1044     {validate new size}
1045     if (Cols = 0) or
1046     ProductOverflow(Cols, FRows) or
1047     ProductOverflow(LongInt(Cols)*LongInt(FRows), FElSize) then
1048     RaiseContainerError(stscBadSize);
1049    
1050     {compute and save various sizes}
1051     CurSize := FCount*FElSize;
1052     NewSize := LongInt(Cols)*LongInt(FRows)*FElSize;
1053     CurRowSize := lmRowSize;
1054     NewRowSize := LongInt(Cols)*FElSize;
1055     CurCols := FCols;
1056     CurFData := lmData;
1057    
1058     {allocate data block of new size}
1059     HugeGetMem(NewFData, NewSize);
1060    
1061     {allocate a buffer to transfer row data}
1062     if NewRowSize > CurRowSize then
1063     BufSize := NewRowSize
1064     else
1065     BufSize := CurRowSize;
1066     try
1067     HugeGetMem(RowData, BufSize);
1068     except
1069     HugeFreeMem(NewFData, NewSize);
1070     end;
1071    
1072     {transfer rows from old array to new}
1073     if Cols > CurCols then
1074     HugeFillChar(RowData^, BufSize, 0);
1075     for R := 0 to FRows-1 do begin
1076     FCols := CurCols;
1077     lmRowSize := CurRowSize;
1078     lmData := CurFData;
1079     GetRow(R, RowData^);
1080     FCols := Cols;
1081     lmRowSize := NewRowSize;
1082     lmData := NewFData;
1083     PutRow(R, RowData^);
1084     end;
1085     HugeFreeMem(RowData, BufSize);
1086    
1087     FCount := LongInt(Cols)*LongInt(FRows);
1088    
1089     {free original data area}
1090     HugeFreeMem(CurFData, CurSize);
1091     {$IFDEF ThreadSafe}
1092     finally
1093     LeaveCS;
1094     end;
1095     {$ENDIF}
1096     end;
1097    
1098     procedure TStLMatrix.lmSetRows(Rows : Cardinal);
1099     var
1100     CurSize, NewSize : LongInt;
1101     CurFData : Pointer;
1102     begin
1103     {$IFDEF ThreadSafe}
1104     EnterCS;
1105     try
1106     {$ENDIF}
1107     if Rows = FRows then
1108     Exit;
1109    
1110     {validate new size}
1111     if (Rows = 0) or
1112     ProductOverflow(Rows, FCols) or
1113     ProductOverflow(LongInt(Rows)*LongInt(FCols), FElSize) then
1114     RaiseContainerError(stscBadSize);
1115    
1116     CurSize := FCount*FElSize;
1117     NewSize := LongInt(Rows)*LongInt(FCols)*FElSize;
1118     CurFData := lmData;
1119    
1120     {allocate data block of new size}
1121     HugeGetMem(lmData, NewSize);
1122    
1123     FCount := LongInt(Rows)*LongInt(FCols);
1124     FRows := Rows;
1125    
1126     {fill extra area with zeros and copy old data}
1127     if NewSize > CurSize then begin
1128     Clear;
1129     NewSize := CurSize;
1130     end;
1131     HugeMove(CurFData^, lmData^, NewSize);
1132    
1133     {free original data area}
1134     HugeFreeMem(CurFData, CurSize);
1135     {$IFDEF ThreadSafe}
1136     finally
1137     LeaveCS;
1138     end;
1139     {$ENDIF}
1140     end;
1141    
1142     procedure TStLMatrix.Put(Row, Col : Cardinal; const Value);
1143     (* model for assembly language below
1144     begin
1145     move(Value, (PChar(lmData)+(Row*FCols+Col)*FElSize)^, FElSize);
1146     end;
1147     *)
1148     begin
1149     {$IFDEF ThreadSafe}
1150     EnterCS;
1151     try
1152     {$ENDIF}
1153     {$IFOPT R+}
1154     if (Row >= Rows) or (Col >= Cols) then
1155     RaiseContainerError(stscBadIndex);
1156     {$ENDIF}
1157     asm
1158     mov eax,Self
1159     push esi
1160     push edi
1161     mov esi,Value
1162     mov edi,Row
1163     imul edi, TStLMatrix([eax]).FCols
1164     add edi,Col
1165     mov ecx,TStLMatrix([eax]).FElSize
1166     db $0F,$AF,$F9 {imul edi,ecx, compiler bug workaround}
1167     add edi,TStLMatrix([eax]).lmData
1168     mov eax,ecx
1169     shr ecx,2
1170     rep movsd
1171     mov ecx,eax
1172     and ecx,3
1173     rep movsb
1174     pop edi
1175     pop esi
1176     end;
1177     {$IFDEF ThreadSafe}
1178     finally
1179     LeaveCS;
1180     end;
1181     {$ENDIF}
1182     end;
1183    
1184     procedure TStLMatrix.PutRow(Row : Cardinal; const RowValue);
1185     begin
1186     {$IFDEF ThreadSafe}
1187     EnterCS;
1188     try
1189     {$ENDIF}
1190     {$IFOPT R+}
1191     if Row >= Rows then
1192     RaiseContainerError(stscBadIndex);
1193     {$ENDIF}
1194     move(RowValue, (PAnsiChar(lmData)+(LongInt(Row)*lmRowSize))^, lmRowSize);
1195     {$IFDEF ThreadSafe}
1196     finally
1197     LeaveCS;
1198     end;
1199     {$ENDIF}
1200     end;
1201    
1202     procedure TStLMatrix.SortRows(KeyCol : Cardinal; Compare : TUntypedCompareFunc);
1203     const
1204     StackSize = 32;
1205     type
1206     Stack = array[0..StackSize-1] of LongInt;
1207     var
1208     L : LongInt;
1209     R : LongInt;
1210     PL : LongInt;
1211     PR : LongInt;
1212     CurEl : Pointer;
1213     PivEl : Pointer;
1214     StackP : Integer;
1215     LStack : Stack;
1216     RStack : Stack;
1217     begin
1218     {$IFDEF ThreadSafe}
1219     EnterCS;
1220     try
1221     {$ENDIF}
1222     if KeyCol >= FCols then
1223     RaiseContainerError(stscBadIndex);
1224    
1225     {Need at least 2 rows to sort}
1226     if FRows <= 1 then
1227     Exit;
1228    
1229     GetMem(CurEl, FElSize);
1230     try
1231     GetMem(PivEl, FElSize);
1232    
1233     {Initialize the stacks}
1234     StackP := 0;
1235     LStack[0] := 0;
1236     RStack[0] := FRows-1;
1237    
1238     {Repeatedly take top partition from stack}
1239     repeat
1240    
1241     {Pop the stack}
1242     L := LStack[StackP];
1243     R := RStack[StackP];
1244     Dec(StackP);
1245    
1246     {Sort current partition}
1247     repeat
1248    
1249     {Load the pivot element}
1250     Get((L+R) div 2, KeyCol, PivEl^);
1251     PL := L;
1252     PR := R;
1253    
1254     {Swap items in sort order around the pivot index}
1255     repeat
1256     Get(PL, KeyCol, CurEl^);
1257     while Compare(CurEl^, PivEl^) < 0 do begin
1258     Inc(PL);
1259     Get(PL, KeyCol, CurEl^);
1260     end;
1261     Get(PR, KeyCol, CurEl^);
1262     while Compare(PivEl^, CurEl^) < 0 do begin
1263     Dec(PR);
1264     Get(PR, KeyCol, CurEl^);
1265     end;
1266     if PL <= PR then begin
1267     if PL <> PR then
1268     {Swap the two elements}
1269     ExchangeRows(PL, PR);
1270     Inc(PL); {assume we'll never sort 2 billion elements}
1271     Dec(PR);
1272     end;
1273     until PL > PR;
1274    
1275     {Decide which partition to sort next}
1276     if (PR-L) < (R-PL) then begin
1277     {Right partition is bigger}
1278     if PL < R then begin
1279     {Stack the request for sorting right partition}
1280     Inc(StackP);
1281     LStack[StackP] := PL;
1282     RStack[StackP] := R;
1283     end;
1284     {Continue sorting left partition}
1285     R := PR;
1286     end else begin
1287     {Left partition is bigger}
1288     if L < PR then begin
1289     {Stack the request for sorting left partition}
1290     Inc(StackP);
1291     LStack[StackP] := L;
1292     RStack[StackP] := PR;
1293     end;
1294     {Continue sorting right partition}
1295     L := PL;
1296     end;
1297    
1298     until L >= R;
1299     until StackP < 0;
1300    
1301     FreeMem(PivEl, FElSize);
1302     finally
1303     FreeMem(CurEl, FElSize);
1304     end;
1305     {$IFDEF ThreadSafe}
1306     finally
1307     LeaveCS;
1308     end;
1309     {$ENDIF}
1310     end;
1311    
1312     procedure TStLMatrix.LoadFromStream(S : TStream);
1313     var
1314     Data : pointer;
1315     Reader : TReader;
1316     NumRows : longint;
1317     NumCols : longint;
1318     ElementSize : cardinal;
1319     R, C : longint;
1320     TotSize : longint;
1321     StreamedClass : TPersistentClass;
1322     StreamedClassName : string;
1323     Value : TValueType;
1324     begin
1325     {$IFDEF ThreadSafe}
1326     EnterCS;
1327     try
1328     {$ENDIF}
1329     Clear;
1330     Reader := TReader.Create(S, 1024);
1331     try
1332     with Reader do
1333     begin
1334     StreamedClassName := ReadString;
1335     StreamedClass := GetClass(StreamedClassName);
1336     if (StreamedClass = nil) then
1337     RaiseContainerErrorFmt(stscUnknownClass, [StreamedClassName]);
1338     if (not IsOrInheritsFrom(StreamedClass, Self.ClassType)) or
1339     (not IsOrInheritsFrom(TStLMatrix, StreamedClass)) then
1340     RaiseContainerError(stscWrongClass);
1341     NumRows := ReadInteger;
1342     NumCols := ReadInteger;
1343     ElementSize := ReadInteger;
1344     if (NumRows <> LongInt(Rows)) or (NumCols <> LongInt(Cols)) or
1345     (LongInt(ElementSize) <> FElSize) then
1346     begin
1347     HugeFreeMem(lmData, FCount*FElSize);
1348     FElSize := ElementSize;
1349     FRows := NumRows;
1350     FCols := NumCols;
1351     FCount := LongInt(NumRows)*NumCols;
1352     lmRowSize := LongInt(NumCols)*LongInt(ElementSize);
1353     HugeGetMem(lmData, FCount*LongInt(ElementSize));
1354     Clear;
1355     end;
1356     ElementsStorable := ReadBoolean;
1357     if ElementsStorable then
1358     begin
1359     Read(Value, sizeof(Value)); {s/b vaBinary}
1360     Read(TotSize, sizeof(longint));
1361     GetMem(Data, FElSize);
1362     try
1363     for R := 0 to pred(FRows) do
1364     for C := 0 to pred(FCols) do
1365     begin
1366     Read(Data^, FElSize);
1367     Put(R, C, Data^);
1368     end;
1369     finally
1370     FreeMem(Data, FElSize);
1371     end;
1372     end
1373     else
1374     begin
1375     ReadListBegin;
1376     for R := 0 to pred(FRows) do
1377     for C := 0 to pred(FCols) do begin
1378     Data := DoLoadData(Reader);
1379     Put(R, C, Data^);
1380     end;
1381     ReadListEnd;
1382     end;
1383     end;
1384     finally
1385     Reader.Free;
1386     end;
1387     {$IFDEF ThreadSafe}
1388     finally
1389     LeaveCS;
1390     end;
1391     {$ENDIF}
1392     end;
1393    
1394     procedure TStLMatrix.StoreToStream(S : TStream);
1395     var
1396     Writer : TWriter;
1397     R, C : integer;
1398     Data : pointer;
1399     TotSize: longint;
1400     Value : TValueType;
1401     begin
1402     {$IFDEF ThreadSafe}
1403     EnterCS;
1404     try
1405     {$ENDIF}
1406     Writer := TWriter.Create(S, 1024);
1407     try
1408     GetMem(Data, FElSize);
1409     try
1410     with Writer do
1411     begin
1412     WriteString(Self.ClassName);
1413     WriteInteger(FRows);
1414     WriteInteger(FCols);
1415     WriteInteger(FElSize);
1416     WriteBoolean(FElStorable);
1417     if ElementsStorable then
1418     begin
1419     Value := vaBinary;
1420     Write(Value, sizeof(Value));
1421     TotSize := FCount * FElSize;
1422     Write(TotSize, sizeof(longint));
1423     for R := 0 to pred(FRows) do
1424     for C := 0 to pred(FCols) do
1425     begin
1426     Get(R, C, Data^);
1427     Write(Data^, FElSize);
1428     end;
1429     end
1430     else
1431     begin
1432     WriteListBegin;
1433     for R := 0 to pred(FRows) do
1434     for C := 0 to pred(FCols) do
1435     begin
1436     Get(R, C, Data^);
1437     DoStoreData(Writer, Data);
1438     end;
1439     WriteListEnd;
1440     end;
1441     end;
1442     finally
1443     FreeMem(Data, FElSize);
1444     end;
1445     finally
1446     Writer.Free;
1447     end;
1448     {$IFDEF ThreadSafe}
1449     finally
1450     LeaveCS;
1451     end;
1452     {$ENDIF}
1453     end;
1454    
1455    
1456     end.

  ViewVC Help
Powered by ViewVC 1.1.20