home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turbo Toolbox
/
Turbo_Toolbox.iso
/
1991
/
07_08
/
tricks
/
swap.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1991-02-24
|
7KB
|
218 lines
(* ------------------------------------------------------ *)
(* SWAP.PAS *)
(* Das Modul erlaubt das Auslagern von dynamischen *)
(* Variablen in eine Disketten-/Plattendatei. *)
(* (c) 1991 Ralf Homburg & TOOLBOX *) }
(* ------------------------------------------------------ *)
{$I-}
UNIT Swap;
INTERFACE
CONST
SwapFile = 'SwapFile'; { Name der Swapdatei. Kann be- }
{ liebig gewählt werden. }
SwapSign = -123454321; { Kennung zur Unterscheidung von }
{ geswapten und nicht geswapten }
{ Zeigern. }
FUNCTION SwappedOut(VAR Ptr) : BOOLEAN;
{ "Ptr" ist ein beliebiger Zeiger. SwappedOut gibt TRUE }
{ zurück, wenn der Inhalt des Zeigers mit SwapOut ausge- }
{ lagert wurde. Die Funktion kann z.B. dazu genutzt wer- }
{ den, um festzustellen, ob SwapIn bzw. SwapOut erfolg- }
{ reich waren. }
PROCEDURE SwapOut(VAR Ptr; Size : WORD);
{ "Ptr" ist ein beliebiger Zeiger, der auf einen mit New }
{ bzw. GETMEM zugewiesenen Speicherbereich von "Size" }
{ Bytes zeigt. SwapOut sichert den Inhalt des Zeigers in }
{ die mit "SwapFile" festgelegte Swap-Datei. Der von }
{ "Ptr" belegte Heap wird freigegeben, sofern kein Da- }
{ teifehler beim Speichern aufgetreten ist, und der Zei- }
{ ger "Ptr" wird auf eine zum Zurückladen des alten In- }
{ halts erforderliche Struktur verbogen. }
{ Achtung! Der Zeiger darf bis zum Aufruf von SwapIn }
{ nicht mehr manipuliert werden! }
PROCEDURE SwapIn(VAR Ptr);
{ "Ptr" ist ein mit SwapOut geswappter Zeiger. SwapIn re- }
{ stauriert die in der Swapdatei gespeicherten Daten des }
{ Zeigers. Dazu muß allerdings ausreichend Platz auf dem }
{ Heap vorhanden sein. Ansonsten wird der Aufruf von }
{ SwapIn ignoriert. }
IMPLEMENTATION
TYPE
BlockPtr = ^Block;
Block = RECORD
Sign,
FirstRec,
LastRec : LONGINT;
Prev,
Next : BlockPtr;
END;
VAR
OldExitProc : Pointer;
FirstFree,
LastFree,
FirstUsed,
LastUsed : BlockPtr;
SFile : FILE;
PROCEDURE InsertBlock(VAR First, Last, Block : BlockPtr);
BEGIN
Block^.Next := NIL;
Block^.Prev := Last;
IF Last <> NIL THEN
Last^.Next := Block;
Last := Block;
IF First = NIL THEN
First := Block;
END;
PROCEDURE RemoveBlock(VAR First, Last, Block : BlockPtr);
BEGIN
IF Block^.Prev <> NIL THEN
Block^.Prev^.Next := Block^.Next
ELSE
First := Block^.Next;
IF Block^.Next <> NIL THEN
Block^.Next^.Prev := Block^.Prev
ELSE
Last := Block^.Prev;
END;
FUNCTION SwappedOut(VAR Ptr) : BOOLEAN;
VAR
Block : BlockPtr ABSOLUTE Ptr;
BEGIN
SwappedOut := (Block^.Sign = SwapSign);
END;
FUNCTION GetFreeBlock(Size : WORD) : BlockPtr;
VAR
Block : BlockPtr;
BEGIN
Block := FirstFree;
WHILE (Block <> NIL) AND
(Block^.LastRec - Block^.FirstRec + 1 < Size) DO
Block := Block^.Next;
IF Block = NIL THEN BEGIN
New(Block);
Block^.FirstRec := FileSize(SFile);
Block^.LastRec := Block^.FirstRec + Size - 1;
InsertBlock(FirstFree, LastFree, Block);
END;
GetFreeBlock := Block;
END;
PROCEDURE SetBlockFree(VAR Block : BlockPtr);
VAR
Search : BlockPtr;
Found : BOOLEAN;
BEGIN
InsertBlock(FirstFree, LastFree, Block);
Search := FirstFree;
Found := FALSE;
WHILE (Search <> NIL) AND NOT(Found) DO BEGIN
IF Search^.FirstRec - 1 = Block^.LastRec THEN BEGIN
Search^.FirstRec := Block^.FirstRec;
RemoveBlock(FirstFree, LastFree, Block);
Dispose(Block);
Block := Search;
Found := TRUE;
END;
Search := Search^.Next;
END;
Search := FirstFree;
Found := FALSE;
WHILE (Search <> NIL) AND NOT(Found) DO BEGIN
IF Search^.LastRec + 1 = Block^.FirstRec THEN BEGIN
Search^.LastRec := Block^.LastRec;
RemoveBlock(FirstFree, LastFree, Block);
Dispose(Block);
Found := TRUE;
END;
Search := Search^.Next;
END;
END;
PROCEDURE SwapOut(VAR Ptr; Size : WORD);
VAR
Data : Pointer ABSOLUTE Ptr;
Block,
Free : BlockPtr;
Result : WORD;
BEGIN
IF (Data <> NIL) AND NOT SwappedOut(Ptr) THEN BEGIN
Free := GetFreeBlock(Size);
Seek(SFile, Free^.FirstRec);
BlockWrite(SFile, Data^, Size, Result);
IF (IOResult = 0) AND (Result = Size) THEN BEGIN
New(Block);
Block^.Sign := SwapSign;
Block^.FirstRec := Free^.FirstRec;
Block^.LastRec := Block^.FirstRec + Size - 1;
InsertBlock(FirstUsed, LastUsed, Block);
FreeMem(Data, Size);
Data := Block;
IF Free^.LastRec > Block^.LastRec THEN
Free^.FirstRec := Block^.LastRec + 1
ELSE BEGIN
RemoveBlock(FirstFree, LastFree, Free);
Dispose(Free);
END;
END;
END;
END;
PROCEDURE SwapIn(VAR Ptr);
VAR
Data : Pointer;
Block : BlockPtr ABSOLUTE Ptr;
Size,
Result : WORD;
BEGIN
Size := Block^.LastRec - Block^.FirstRec + 1;
IF (Block <> NIL) AND (SwappedOut(Ptr)) AND
(MaxAvail >= Size) THEN BEGIN
GetMem(Data, Size);
Seek(SFile, Block^.FirstRec);
BlockRead(SFile, Data^, Size, Result);
IF (IOResult = 0) AND (Result = Size) THEN BEGIN
RemoveBlock(FirstUsed, LastUsed, Block);
SetBlockFree(Block);
Pointer(Ptr) := Data;
END ELSE
FreeMem(Data, Size);
END;
END;
{$F+}
PROCEDURE NewExitProc;
BEGIN
ExitProc := OldExitProc;
Close(SFile);
Erase(SFile);
END;
{$F-}
BEGIN
FirstFree := NIL;
LastFree := NIL;
FirstUsed := NIL;
LastUsed := NIL;
OldExitProc := ExitProc;
ExitProc := @NewExitProc;
Assign(SFile, SwapFile);
Rewrite(SFile, 1);
IF IOResult <> 0 THEN Halt;
END.
(* ------------------------------------------------------ *)
(* Ende von SWAP.PAS *)