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

Contents of /dao/DelphiScanner/Components/tpsystools_4.04/source/StLArr.pas

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2671 - (show annotations) (download)
Tue Aug 25 18:15:15 2015 UTC (8 years, 9 months ago) by torben
File size: 37192 byte(s)
Added tpsystools component
1 // 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