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

Contents of /dao/DelphiScanner/Components/tpsystools_4.04/source/StVArr.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: 23468 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: 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