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

Annotation of /dao/DelphiScanner/Components/tpsystools_4.04/source/StVArr.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: 23468 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: StVArr.pas 4.04 *}
30     {*********************************************************}
31     {* SysTools: Virtual matrix class *}
32     {*********************************************************}
33    
34     {$I StDefine.inc}
35    
36     {$I+} {trap I/O exceptions here}
37    
38     {Notes:
39     - The virtual matrix uses a disk file for the main storage of a
40     two-dimensional array. A specified number of rows from the matrix can
41     be stored in a memory cache.
42    
43     - The cache must be large enough to hold at least 2 rows. In 16-bit mode,
44     the cache can hold at most about 5460 rows. In 32-bit mode, the number
45     of cached rows is essentially unlimited.
46    
47     - Normally the disk file is treated as a pure file of rows, where each
48     row is composed of cell columns. By overriding the HeaderSize, WriteHeader,
49     and ReadHeader methods, the application can use a file that has a header
50     prior to the array data.
51    
52     - By defining a matrix of one column, the TStVMatrix class can be used
53     as a cache manager for any file of record.
54     }
55    
56     unit StVArr;
57    
58     interface
59    
60     uses
61     Windows, Classes,
62     SysUtils, StConst, StBase,
63     StUtils; {used for ExchangeStructs}
64    
65     type
66     {.Z-}
67     TStCacheRec = record
68     crRow : Cardinal; {row number in cache}
69     crRowData : Pointer; {pointer to row buffer}
70     crTime : LongInt; {quasi-time last used}
71     crDirty : Integer; {non-zero if Row changed in memory}
72     end;
73     TStCacheArray = array[0..(StMaxBlockSize div SizeOf(TStCacheRec))-1] of TStCacheRec;
74     PStCacheArray = ^TStCacheArray;
75     {.Z-}
76    
77     TStVMatrix = class(TStContainer)
78     {.Z+}
79     protected
80     {property instance variables}
81     FRows : Cardinal; {number of rows}
82     FCacheRows: Integer; {number of cached rows}
83     FCols : Cardinal; {number of columns}
84     FElSize : Integer; {size of each array element}
85    
86     {private instance variables}
87     vmRowSize : LongInt; {number of bytes in a row}
88     vmCacheCnt : Integer; {number of used rows in cache}
89     vmCacheTime: LongInt; {quasi-time for LRU}
90     vmCache : PStCacheArray; {sorted collection of cached rows}
91     vmDataF : Integer; {data file}
92    
93     {protected undocumented methods}
94     procedure ForEachUntypedVar(Action : TIterateUntypedFunc;
95     OtherData : pointer);
96     override;
97     procedure GetArraySizes(var RowCount, ColCount, ElSize : Cardinal);
98     override;
99     procedure SetArraySizes(RowCount, ColCount, ElSize : Cardinal);
100     override;
101     function StoresUntypedVars : boolean;
102     override;
103     procedure vmSetCacheRows(CacheRows : Integer);
104     procedure vmAllocateCache;
105     procedure vmDeallocateCache;
106     procedure vmInvalidateCache;
107     procedure vmFlushCacheNode(CacheIndex : Integer);
108     function vmIncCacheTime : LongInt;
109     function vmSearchCache(Row : Cardinal; var CacheIndex : Integer) : Boolean;
110     function vmGetRowData(Row : Cardinal; MakeDirty : Boolean) : Pointer;
111     procedure vmWriteRow(Row : Cardinal; Data : Pointer; Seek : Boolean);
112     procedure vmSetRows(Rows : Cardinal);
113    
114     {.Z-}
115     public
116     constructor Create(Rows, Cols, ElementSize : Cardinal;
117     CacheRows : Integer;
118     const DataFile : string; OpenMode : Word); virtual;
119     {-Initialize a virtual 2D matrix}
120     destructor Destroy; override;
121     {-Free a virtual 2D matrix}
122     procedure FlushCache;
123     {-Write any dirty cache rows to disk}
124    
125     function HeaderSize : LongInt; virtual;
126     {-Return the header size of the array file, default 0}
127     procedure WriteHeader; virtual;
128     {-Write a header to the array file, default none}
129     procedure ReadHeader; virtual;
130     {-Read a header from the array file, default none}
131    
132     procedure Assign(Source: TPersistent); override;
133     {-Assign another container's contents to this one}
134     procedure Clear; override;
135     {-Fill the matrix with zeros}
136     procedure Fill(const Value);
137     {-Fill matrix with specified element value}
138    
139     procedure Put(Row, Col : Cardinal; const Value);
140     {-Set an element}
141     procedure Get(Row, Col : Cardinal; var Value);
142     {-Return an element}
143    
144     procedure PutRow(Row : Cardinal; const RowValue);
145     {-Set an entire row}
146     procedure GetRow(Row : Cardinal; var RowValue);
147     {-Return an entire row}
148    
149     procedure ExchangeRows(Row1, Row2 : Cardinal);
150     {-Exchange the specified rows}
151     procedure SortRows(KeyCol : Cardinal; Compare : TUntypedCompareFunc);
152     {-Sort the array rows using the given comparison function and
153     the elements in the given column}
154    
155     property Rows : Cardinal
156     {-Read or write the number of rows in the array}
157     read FRows
158     write vmSetRows;
159    
160     property CacheRows : Integer
161     {-Read or write the number of cache rows in the array}
162     read FCacheRows
163     write vmSetCacheRows;
164     property Cols : Cardinal
165     {-Read the number of columns in the array}
166     read FCols;
167    
168     property ElementSize : Integer
169     {-Read the size of each element in the array}
170     read FElSize;
171     end;
172    
173    
174     implementation
175    
176     function AssignMatrixData(Container : TStContainer;
177     var Data;
178     OtherData : Pointer) : Boolean; far;
179     var
180     OurMatrix : TStVMatrix absolute OtherData;
181     RD : TAssignRowData absolute Data;
182     begin
183     OurMatrix.PutRow(RD.RowNum, RD.Data);
184     Result := true;
185     end;
186    
187     procedure TStVMatrix.Assign(Source: TPersistent);
188     begin
189     {$IFDEF ThreadSafe}
190     EnterCS;
191     try
192     {$ENDIF}
193     {The only containers that we allow to be assigned to a large matrix
194     are:
195     - a SysTools large array (TStLArray)
196     - a SysTools large matrix (TStLMatrix)
197     - another SysTools virtual matrix (TStVMatrix)}
198     if not AssignUntypedVars(Source, AssignMatrixData) then
199     inherited Assign(Source);
200     {$IFDEF ThreadSafe}
201     finally
202     LeaveCS;
203     end;{try..finally}
204     {$ENDIF}
205     end;
206    
207     procedure TStVMatrix.Clear;
208     var
209     Row : Cardinal;
210     begin
211     {$IFDEF ThreadSafe}
212     EnterCS;
213     try
214     {$ENDIF}
215     vmInvalidateCache;
216     vmCacheCnt := 1;
217     with vmCache^[0] do begin
218     HugeFillChar(crRowData^, vmRowSize, 0);
219     crRow := 0;
220     crTime := vmIncCacheTime;
221     crDirty := 0;
222     FileSeek(vmDataF, 0, 0);
223     WriteHeader;
224     for Row := 0 to FRows-1 do
225     vmWriteRow(Row, crRowData, False);
226     end;
227     {$IFDEF ThreadSafe}
228     finally
229     LeaveCS;
230     end;
231     {$ENDIF}
232     end;
233    
234     procedure TStVMatrix.ForEachUntypedVar(Action : TIterateUntypedFunc;
235     OtherData : pointer);
236     var
237     FullRow : ^TAssignRowData;
238     i : Cardinal;
239     begin
240     {$IFDEF ThreadSafe}
241     EnterCS;
242     try
243     {$ENDIF}
244     GetMem(FullRow, sizeof(Cardinal) + vmRowSize);
245     try
246     for i := 0 to pred(Rows) do
247     begin
248     FullRow^.RowNum := i;
249     GetRow(i, FullRow^.Data);
250     Action(Self, FullRow^, OtherData);
251     end;
252     finally
253     FreeMem(FullRow, sizeof(Cardinal) + vmRowSize);
254     end;
255     {$IFDEF ThreadSafe}
256     finally
257     LeaveCS;
258     end;
259     {$ENDIF}
260     end;
261    
262     procedure TStVMatrix.GetArraySizes(var RowCount, ColCount, ElSize : Cardinal);
263     begin
264     RowCount := Rows;
265     ColCount := Cols;
266     ElSize := ElementSize;
267     end;
268    
269     procedure TStVMatrix.SetArraySizes(RowCount, ColCount, ElSize : Cardinal);
270     begin
271     if (ColCount <> Cols) then
272     RaiseContainerError(stscBadColCount);
273     if (LongInt(ElSize) <> ElementSize) then
274     RaiseContainerError(stscBadElSize);
275     if (RowCount <> Rows) then
276     begin
277     Rows := RowCount;
278     end;
279     end;
280    
281     function TStVMatrix.StoresUntypedVars : boolean;
282     begin
283     Result := true;
284     end;
285    
286     constructor TStVMatrix.Create(Rows, Cols, ElementSize : Cardinal;
287     CacheRows : Integer;
288     const DataFile : string; OpenMode : Word);
289     begin
290     FElSize := ElementSize;
291     FRows := Rows;
292     FCols := Cols;
293     FCount := LongInt(Rows)*LongInt(Cols);
294     vmRowSize := LongInt(Cols)*LongInt(ElementSize);
295     FCacheRows := CacheRows;
296     vmDataF := -1;
297    
298     CreateContainer(TStNode, 0);
299    
300     if (Rows = 0) or (Cols = 0) or (ElementSize = 0) or (CacheRows < 2) or
301     ProductOverflow(Cols, ElementSize) or
302     ProductOverflow(LongInt(Cols)*LongInt(ElementSize), Rows) or
303     (LongInt(Cols)*LongInt(ElementSize)*LongInt(Rows) > MaxLongInt-HeaderSize) or
304     (CacheRows > StMaxBlockSize div SizeOf(TStCacheRec)) then
305     RaiseContainerError(stscBadSize);
306    
307     vmAllocateCache;
308    
309     {open the data file}
310     vmDataF := FileOpen(DataFile, OpenMode);
311     if vmDataF < 0 then begin
312     {file not found, create it}
313     vmDataF := FileCreate(DataFile);
314     if vmDataF < 0 then
315     RaiseContainerError(stscFileCreate)
316     else begin
317     FileClose(vmDataF);
318     vmDataF := FileOpen(DataFile, OpenMode);
319     if vmDataF < 0 then
320     RaiseContainerError(stscFileOpen);
321     {write user defined header to file}
322     WriteHeader;
323     FileSeek(vmDataF, 0, 0);
324     end;
325     end;
326    
327     {read user defined header from file}
328     ReadHeader;
329     end;
330    
331     destructor TStVMatrix.Destroy;
332     begin
333     if Assigned(vmCache) then begin
334     if vmDataF > 0 then
335     FlushCache;
336     vmDeallocateCache;
337     end;
338    
339     if vmDataF > 0 then begin
340     {write user defined header to file}
341     FileSeek(vmDataF, 0, 0);
342     WriteHeader;
343     FileClose(vmDataF);
344     end;
345    
346     IncNodeProtection;
347     inherited Destroy;
348     end;
349    
350     procedure TStVMatrix.ExchangeRows(Row1, Row2 : Cardinal);
351     begin
352     {$IFDEF ThreadSafe}
353     EnterCS;
354     try
355     {$ENDIF}
356     {$IFOPT R+}
357     if (Row1 >= Rows) or (Row2 >= Rows) then
358     RaiseContainerError(stscBadIndex);
359     {$ENDIF}
360     ExchangeStructs(vmGetRowData(Row1, True)^, vmGetRowData(Row2, True)^, vmRowSize);
361     {$IFDEF ThreadSafe}
362     finally
363     LeaveCS;
364     end;
365     {$ENDIF}
366     end;
367    
368     procedure TStVMatrix.Fill(const Value);
369     var
370     Row : Cardinal;
371     begin
372     {$IFDEF ThreadSafe}
373     EnterCS;
374     try
375     {$ENDIF}
376     vmInvalidateCache;
377     vmCacheCnt := 1;
378     with vmCache^[0] do begin
379     HugeFillStruc(crRowData^, FCols, Value, FElSize);
380     crRow := 0;
381     crTime := vmIncCacheTime;
382     crDirty := 0;
383     FileSeek(vmDataF, 0, 0);
384     WriteHeader;
385     for Row := 0 to FRows-1 do
386     vmWriteRow(Row, crRowData, False);
387     end;
388     {$IFDEF ThreadSafe}
389     finally
390     LeaveCS;
391     end;
392     {$ENDIF}
393     end;
394    
395     procedure TStVMatrix.FlushCache;
396     var
397     I : Integer;
398     begin
399     {$IFDEF ThreadSafe}
400     EnterCS;
401     try
402     {$ENDIF}
403     for I := 0 to vmCacheCnt-1 do
404     vmFlushCacheNode(I);
405     {$IFDEF ThreadSafe}
406     finally
407     LeaveCS;
408     end;
409     {$ENDIF}
410     end;
411    
412     procedure TStVMatrix.Get(Row, Col : Cardinal; var Value);
413     begin
414     {$IFDEF ThreadSafe}
415     EnterCS;
416     try
417     {$ENDIF}
418     {$IFOPT R+}
419     if (Row >= Rows) or (Col >= Cols) then
420     RaiseContainerError(stscBadIndex);
421     {$ENDIF}
422     Move(PAnsiChar(vmGetRowData(Row, False))[LongInt(Col)*FElSize], Value, FElSize);
423     {$IFDEF ThreadSafe}
424     finally
425     LeaveCS;
426     end;
427     {$ENDIF}
428     end;
429    
430     procedure TStVMatrix.GetRow(Row : Cardinal; var RowValue);
431     begin
432     {$IFDEF ThreadSafe}
433     EnterCS;
434     try
435     {$ENDIF}
436     {$IFOPT R+}
437     if Row >= Rows then
438     RaiseContainerError(stscBadIndex);
439     {$ENDIF}
440     HugeMove(vmGetRowData(Row, False)^, RowValue, vmRowSize);
441     {$IFDEF ThreadSafe}
442     finally
443     LeaveCS;
444     end;
445     {$ENDIF}
446     end;
447    
448     function TStVMatrix.HeaderSize : LongInt;
449     begin
450     Result := 0;
451     end;
452    
453     procedure TStVMatrix.ReadHeader;
454     begin
455     {does nothing by default}
456     {can assume that FilePos = 0 when this is called}
457     end;
458    
459     procedure TStVMatrix.Put(Row, Col : Cardinal; const Value);
460     begin
461     {$IFDEF ThreadSafe}
462     EnterCS;
463     try
464     {$ENDIF}
465     {$IFOPT R+}
466     if (Row >= Rows) or (Col >= Cols) then
467     RaiseContainerError(stscBadIndex);
468     {$ENDIF}
469     Move(Value, PAnsiChar(vmGetRowData(Row, True))[LongInt(Col)*FElSize], FElSize);
470     {$IFDEF ThreadSafe}
471     finally
472     LeaveCS;
473     end;
474     {$ENDIF}
475     end;
476    
477     procedure TStVMatrix.PutRow(Row : Cardinal; const RowValue);
478     begin
479     {$IFDEF ThreadSafe}
480     EnterCS;
481     try
482     {$ENDIF}
483     {$IFOPT R+}
484     if Row >= Rows then
485     RaiseContainerError(stscBadIndex);
486     {$ENDIF}
487     HugeMove(RowValue, vmGetRowData(Row, True)^, vmRowSize);
488     {$IFDEF ThreadSafe}
489     finally
490     LeaveCS;
491     end;
492     {$ENDIF}
493     end;
494    
495     procedure TStVMatrix.SortRows(KeyCol : Cardinal; Compare : TUntypedCompareFunc);
496     const
497     StackSize = 32;
498     type
499     Stack = array[0..StackSize-1] of LongInt;
500     var
501     L : LongInt;
502     R : LongInt;
503     PL : LongInt;
504     PR : LongInt;
505     CurEl : Pointer;
506     PivEl : Pointer;
507     StackP : Integer;
508     LStack : Stack;
509     RStack : Stack;
510     begin
511     {$IFDEF ThreadSafe}
512     EnterCS;
513     try
514     {$ENDIF}
515     if KeyCol >= Cols then
516     RaiseContainerError(stscBadIndex);
517    
518     {Need at least 2 rows to sort}
519     if FRows <= 1 then
520     Exit;
521    
522     GetMem(CurEl, FElSize);
523     try
524     GetMem(PivEl, FElSize);
525    
526     {Initialize the stacks}
527     StackP := 0;
528     LStack[0] := 0;
529     RStack[0] := FRows-1;
530    
531     {Repeatedly take top partition from stack}
532     repeat
533    
534     {Pop the stack}
535     L := LStack[StackP];
536     R := RStack[StackP];
537     Dec(StackP);
538    
539     {Sort current partition}
540     repeat
541    
542     {Load the pivot element}
543     Get((L+R) div 2, KeyCol, PivEl^);
544     PL := L;
545     PR := R;
546    
547     {Swap items in sort order around the pivot index}
548     repeat
549     Get(PL, KeyCol, CurEl^);
550     while Compare(CurEl^, PivEl^) < 0 do begin
551     Inc(PL);
552     Get(PL, KeyCol, CurEl^);
553     end;
554     Get(PR, KeyCol, CurEl^);
555     while Compare(PivEl^, CurEl^) < 0 do begin
556     Dec(PR);
557     Get(PR, KeyCol, CurEl^);
558     end;
559     if PL <= PR then begin
560     if PL <> PR then
561     {Swap the two elements}
562     ExchangeRows(PL, PR);
563     Inc(PL); {assume we'll never sort 2 billion elements}
564     Dec(PR);
565     end;
566     until PL > PR;
567    
568     {Decide which partition to sort next}
569     if (PR-L) < (R-PL) then begin
570     {Right partition is bigger}
571     if PL < R then begin
572     {Stack the request for sorting right partition}
573     Inc(StackP);
574     LStack[StackP] := PL;
575     RStack[StackP] := R;
576     end;
577     {Continue sorting left partition}
578     R := PR;
579     end else begin
580     {Left partition is bigger}
581     if L < PR then begin
582     {Stack the request for sorting left partition}
583     Inc(StackP);
584     LStack[StackP] := L;
585     RStack[StackP] := PR;
586     end;
587     {Continue sorting right partition}
588     L := PL;
589     end;
590    
591     until L >= R;
592     until StackP < 0;
593    
594     FreeMem(PivEl, FElSize);
595     finally
596     FreeMem(CurEl, FElSize);
597     end;
598     {$IFDEF ThreadSafe}
599     finally
600     LeaveCS;
601     end;
602     {$ENDIF}
603     end;
604    
605     procedure TStVMatrix.vmAllocateCache;
606     var
607     I : Integer;
608     begin
609     GetMem(vmCache, FCacheRows*SizeOf(TStCacheRec));
610     FillChar(vmCache^, FCacheRows*SizeOf(TStCacheRec), 0);
611     try
612     for I := 0 to FCacheRows-1 do
613     with vmCache^[I] do
614     HugeGetMem(crRowData, vmRowSize);
615     except
616     vmDeallocateCache;
617     raise;
618     end;
619     vmInvalidateCache;
620     end;
621    
622     procedure TStVMatrix.vmDeallocateCache;
623     var
624     I : Integer;
625     begin
626     if Assigned(vmCache) then begin
627     for I := FCacheRows-1 downto 0 do
628     HugeFreeMem(vmCache^[I].crRowData, vmRowSize);
629     if Assigned(vmCache) then
630     FreeMem(vmCache, FCacheRows*SizeOf(TStCacheRec));
631     vmCache := nil;
632     end;
633     FCacheRows := 0;
634     end;
635    
636     procedure TStVMatrix.vmFlushCacheNode(CacheIndex : Integer);
637     begin
638     with vmCache^[CacheIndex] do
639     if crDirty > 0 then begin
640     vmWriteRow(crRow, crRowData, True);
641     crDirty := 0;
642     end;
643     end;
644    
645     function TStVMatrix.vmGetRowData(Row : Cardinal; MakeDirty : Boolean) : Pointer;
646     var
647     CacheIndex, OldestIndex : Integer;
648     OldestTime, Bytes : LongInt;
649     TmpRowData : Pointer;
650     begin
651     if not vmSearchCache(Row, CacheIndex) then begin
652     {row not found in cache}
653     if vmCacheCnt = FCacheRows then begin
654     {cache full, must throw out oldest row in cache}
655     OldestTime := MaxLongInt;
656     OldestIndex := 0; {prevent D32 from generating a warning}
657     for CacheIndex := 0 to vmCacheCnt-1 do
658     with vmCache^[CacheIndex] do
659     if crTime < OldestTime then begin
660     OldestIndex := CacheIndex;
661     OldestTime := crTime;
662     end;
663     vmFlushCacheNode(OldestIndex);
664     dec(vmCacheCnt);
665     TmpRowData := vmCache^[OldestIndex].crRowData;
666     Move(vmCache^[OldestIndex+1], vmCache^[OldestIndex],
667     (vmCacheCnt-OldestIndex)*SizeOf(TStCacheRec));
668     vmCache^[vmCacheCnt].crRowData := TmpRowData;
669     {find spot where row should now be inserted}
670     vmSearchCache(Row, CacheIndex);
671     end;
672    
673     {add row to cache}
674     TmpRowData := vmCache^[vmCacheCnt].crRowData;
675     Move(vmCache^[CacheIndex], vmCache^[CacheIndex+1],
676     (vmCacheCnt-CacheIndex)*SizeOf(TStCacheRec));
677     inc(vmCacheCnt);
678     with vmCache^[CacheIndex] do begin
679     crRowData := TmpRowData;
680     crRow := Row;
681     Bytes := FileSeek(vmDataF, HeaderSize+LongInt(Row)*vmRowSize, 0);
682     if Bytes >= 0 then
683     Bytes := FileRead(vmDataF, crRowData^, vmRowSize);
684     if Bytes < 0 then
685     RaiseContainerError(stscFileRead);
686     {else if Bytes = 0 then}
687     {row hasn't been written to yet}
688     {HugeFillChar(crRowData^, vmRowSize, 0);}
689     crDirty := 0;
690     end;
691     end;
692    
693     with vmCache^[CacheIndex] do begin
694     Result := crRowData;
695     if MakeDirty then
696     crDirty := 1;
697     crTime := vmIncCacheTime;
698     end;
699     end;
700    
701     function TStVMatrix.vmIncCacheTime : LongInt;
702     var
703     I : Integer;
704     begin
705     if vmCacheTime = MaxLongInt-1 then begin
706     {reset time for all buffers}
707     for I := 0 to vmCacheCnt-1 do
708     vmCache^[I].crTime := 0;
709     vmCacheTime := 0;
710     end;
711     inc(vmCacheTime);
712     Result := vmCacheTime;
713     end;
714    
715     procedure TStVMatrix.vmInvalidateCache;
716     begin
717     vmCacheCnt := 0;
718     vmCacheTime := 0;
719     end;
720    
721     function TStVMatrix.vmSearchCache(Row : Cardinal; var CacheIndex : Integer) : Boolean;
722     var
723     L, R, M : Integer;
724     Comp : LongInt;
725     begin
726     if vmCacheCnt = 0 then begin
727     Result := False;
728     CacheIndex := 0;
729     Exit;
730     end;
731    
732     {search cache for row using binary search}
733     L := 0;
734     R := vmCacheCnt-1;
735     repeat
736     M := (L+R) div 2;
737     with vmCache^[M] do begin
738     Comp := LongInt(Row)-LongInt(crRow);
739     if Comp = 0 then begin
740     {found row in cache}
741     Result := True;
742     CacheIndex := M;
743     Exit;
744     end else if Comp < 0 then
745     R := M-1
746     else
747     L := M+1;
748     end;
749     until L > R;
750    
751     {not found, return where it should be inserted}
752     Result := False;
753     CacheIndex := M;
754     if Comp > 0 then
755     inc(CacheIndex);
756     end;
757    
758     procedure TStVMatrix.vmSetCacheRows(CacheRows : Integer);
759     var
760     I : Integer;
761     NewCache : PStCacheArray;
762     begin
763     {$IFDEF ThreadSafe}
764     EnterCS;
765     try
766     {$ENDIF}
767     if CacheRows = FCacheRows then
768     Exit;
769    
770     if (CacheRows < 2) or (CacheRows > StMaxBlockSize div SizeOf(TStCacheRec)) then
771     RaiseContainerError(stscBadSize);
772    
773     {allocate new cache descriptor array}
774     GetMem(NewCache, CacheRows*SizeOf(TStCacheRec));
775     FillChar(NewCache^, CacheRows*SizeOf(TStCacheRec), 0);
776    
777     try
778     {allocate new buffers if any}
779     for I := FCacheRows to CacheRows-1 do
780     with NewCache^[I] do
781     HugeGetMem(crRowData, vmRowSize);
782    
783     {transfer old cache buffers to new array}
784     for I := 0 to FCacheRows-1 do
785     if I < CacheRows then
786     NewCache^[I] := vmCache^[I]
787     else begin
788     {number of buffers shrunk, get rid of excess buffers}
789     if I < vmCacheCnt then
790     vmFlushCacheNode(I);
791     HugeFreeMem(vmCache^[I].crRowData, vmRowSize);
792     end;
793    
794     except
795     for I := CacheRows-1 downto 0 do
796     HugeFreeMem(NewCache^[I].crRowData, vmRowSize);
797     FreeMem(NewCache, CacheRows*SizeOf(TStCacheRec));
798     end;
799    
800     {update cache in-use count}
801     if vmCacheCnt > CacheRows then
802     vmCacheCnt := CacheRows;
803    
804     {deallocate old cache}
805     FreeMem(vmCache, FCacheRows*SizeOf(TStCacheRec));
806     vmCache := NewCache;
807     FCacheRows := CacheRows;
808     {$IFDEF ThreadSafe}
809     finally
810     LeaveCS;
811     end;
812     {$ENDIF}
813     end;
814    
815     procedure TStVMatrix.vmSetRows(Rows : Cardinal);
816     var
817     I : Integer;
818     NewSize : LongInt;
819     begin
820     {$IFDEF ThreadSafe}
821     EnterCS;
822     try
823     {$ENDIF}
824     if Rows = FRows then
825     Exit;
826    
827     {validate new size}
828     if (Rows = 0) or
829     ProductOverflow(Rows, Cols) or
830     ProductOverflow(LongInt(Rows)*LongInt(Cols), FElSize) then
831     RaiseContainerError(stscBadSize);
832    
833     if Rows < FRows then begin
834     {dump now-irrelevant rows from cache}
835     for I := 0 to vmCacheCnt-1 do
836     if vmCache^[I].crRow >= Rows then begin
837     vmCacheCnt := I;
838     break;
839     end;
840     {truncate data file}
841     NewSize := HeaderSize+LongInt(Rows)*LongInt(Cols)*FElSize;
842     if FileSeek(vmDataF, 0, 2) > NewSize then begin
843     FileSeek(vmDataF, NewSize, 0);
844     if not SetEndOfFile(vmDataF) then
845     RaiseContainerError(stscFileWrite);
846     end;
847     end;
848    
849     FRows := Rows;
850     FileSeek(vmDataF, 0, 0);
851     WriteHeader;
852     {$IFDEF ThreadSafe}
853     finally
854     LeaveCS;
855     end;
856     {$ENDIF}
857     end;
858    
859     procedure TStVMatrix.vmWriteRow(Row : Cardinal; Data : Pointer; Seek : Boolean);
860     var
861     Bytes : LongInt;
862     begin
863     if Seek then
864     FileSeek(vmDataF, HeaderSize+LongInt(Row)*vmRowSize, 0);
865     Bytes := FileWrite(vmDataF, Data^, vmRowSize);
866     if (Bytes < 0) or (Bytes <> vmRowSize) then
867     RaiseContainerError(stscFileWrite);
868     end;
869    
870     procedure TStVMatrix.WriteHeader;
871     begin
872     {does nothing by default}
873     {can assume that FilePos = 0 when this is called}
874     end;
875    
876    
877     end.

  ViewVC Help
Powered by ViewVC 1.1.20