home *** CD-ROM | disk | FTP | other *** search
Modula Implementation | 1988-10-03 | 12.9 KB | 319 lines |
- IMPLEMENTATION MODULE DynArrayHandler;
- (*-------------------------------------------------------------------*
- * Dieses Modul umfa₧t die Verwaltung dynamischer Arrays mit *
- * beliebigen Typen bis zu einer Elementgrö₧e von <MaxElementSize>. *
- * Die Typenkompatibilität wird über die Grö₧e der übergebenen *
- * Variablen kontrolliert. Typenkonvertierungen sind mit Variablen *
- * unterschiedlichen Typs bei gleicher Grö₧e möglich. *
- * Die Grö₧e des Arrays wird über den grö₧ten Index, der beim *
- * Schreiben von Elementen verwendet wurde, bestimmen. *
- * Lesender Zugriff auf Indizes oberhalb des grö₧ten, zum Schreiben *
- * verwendeten Index, wird mit einer Fehlermeldung quittiert. *
- *-------------------------------------------------------------------*
- * Copyright 1987: Dipl.-Inform. Frank F. Wachtmeister *
- *-------------------------------------------------------------------*
- * System : ATARI 520 ST+, SM 124, PADERCOMP DL-2, EPSON FX-105 *
- * Compiler: TDI MODULA-2/ST 0272-742796(UK) *
- *-------------------------------------------------------------------*
- * Verwendete Module, die nicht zum Grundpaket gehören: *
- * Debugger: erhältlich über PASCAL Intern. 4/88 *
- *-------------------------------------------------------------------*
- * Fehlermeldungen (ausgegeben über Debugger.Error): *
- * 91: Storage : Created Heap not sufficient. Allocation failed. *
- * 106: DynArray: DynArray not initialized. *
- * 107: DynArray: Array Element inkompatible with Variable. *
- * 108: DynArray: Array Index out of Bounds. *
- * 109: DynArray: Array Address Error. *
- * 110: DynArray: Array Element too large ( > <MaxElementSize> ). *
- *-------------------------------------------------------------------*)
-
- FROM Debugger IMPORT stop, Error, InitDebugger, Activate,
- Into, Leaving, Message, ShowByte, ShowWord, ShowLong;
- FROM Storage IMPORT CreateHeap, ALLOCATE, DEALLOCATE;
- FROM Streams IMPORT Stream, Write8Bit, Read8Bit, Write16Bit, Read16Bit;
- FROM SYSTEM IMPORT BYTE;
-
- CONST DEBUG = FALSE;
-
- TYPE
- SegmentPtr = POINTER TO SegmentType;
-
- SegmentType = RECORD
- next : SegmentPtr;
- block: ARRAY[1..MaxElementSize] OF BYTE;
- END;
-
- DynArray = POINTER TO Deskript; (* Opaque Type *)
-
- Deskript = RECORD
- size, (* Grö₧e eines Elements in Bytes *)
- index, (* Grö₧tmöglicher Index zum Lesen *)
- anzseg: CARDINAL; (* Anzahl initialisierter Segmente *)
- init, (* Zeiger auf das Initialisierungssegment *)
- list : SegmentPtr; (* Zeiger auf die Segment-Liste *)
- END;
-
-
- (*-------------------------------------------------------------------*
- * New kontrolliert, ob mit NEW zugewiesener Speicherplatz auch *
- * tatsächlich zugewiesen wurde. *
- *-------------------------------------------------------------------*)
- PROCEDURE New (VAR p: SegmentPtr);
- BEGIN
- NEW (p);
- IF p=NIL THEN Error (91); HALT; END;
- END New;
-
- (*-------------------------------------------------------------------*
- * NewSegment hängt an die Segmentliste von dyn ein Segment an. *
- * Dies Segment ist wie in dyn^.init definiert, initialisiert. *
- *-------------------------------------------------------------------*)
- PROCEDURE NewSegment (VAR dyn: DynArray);
- VAR i : CARDINAL;
- p,q: SegmentPtr;
- BEGIN
- IF DEBUG THEN Into ('NewSegment') END;
- IF dyn=NIL THEN Error (106)
- ELSE
- WITH dyn^ DO
- p:=list; i:=0; q:=NIL;
- WHILE p<>NIL DO q:=p; p:=p^.next; INC(i); END;
- IF i<>anzseg THEN Error (109); END;
- New (p);
- IF q<>NIL THEN q^.next:=p ELSE list:=p END;
- INC (anzseg);
- WITH p^ DO
- next:=NIL;
- block:=init^.block;
- END;
- END;
- END;
- IF DEBUG THEN Leaving ('NewSegment') END;
- END NewSegment;
-
- (*-------------------------------------------------------------------*
- * DefDynArray definiert und initialisiert ein dynamisches Array vom *
- * Typ elem. Die Variable elem wird hier auch als Initialisierung von*
- * nicht explizit definierten Array-Elementen verwendet. *
- * So haben bei: *
- * *
- * DefDynArray (dyn, init); *
- * Put (dyn, 50, a); *
- * *
- * die Elemente von mit dem Index von 0 bis 49 den Wert von init; *
- * das Element mit Index 50 hat den Wert von a. *
- *-------------------------------------------------------------------*)
- PROCEDURE DefDynArray (VAR dyn: DynArray; elem: ARRAY OF BYTE);
- VAR i,j: CARDINAL;
- BEGIN
- IF DEBUG THEN Into ('DefDynArray') END;
- IF SIZE(elem)>MaxElementSize THEN Error (110)
- ELSE
- NEW (dyn); IF dyn=NIL THEN Error (91)
- ELSE
- WITH dyn^ DO
- size := SIZE(elem);
- index := 0; anzseg:=0; list := NIL;
-
- New (init); (* Vorbesetzen des Initialisierungsblocks *)
- i:=1; j:=0;
- WITH init^ DO
- next:=NIL;
- REPEAT
- FOR j:=0 TO HIGH(elem) DO block[i+j]:=elem[j] END;
- i:=i+size;
- UNTIL (i+size-1)>MaxElementSize;
- END
- END;
- NewSegment (dyn);
- END
- END;
- IF DEBUG THEN Leaving ('DefDynArray') END;
- END DefDynArray;
-
- (*-------------------------------------------------------------------*
- * DeleteDynArray löscht ein dynamisches Array und gibt den *
- * benötigten Speicherplatz wieder frei. *
- *-------------------------------------------------------------------*)
- PROCEDURE DeleteDynArray (VAR dyn: DynArray);
- VAR p,q: SegmentPtr;
- BEGIN
- IF DEBUG THEN Into ('DeleteDynArray') END;
- IF dyn<>NIL THEN
- WITH dyn^ DO
- DISPOSE (init);
- p:=list;
- WHILE p<>NIL DO
- q:=p^.next;
- DISPOSE (p);
- p:=q;
- END;
- END;
- DISPOSE (dyn); dyn:=NIL;
- END;
- IF DEBUG THEN Leaving ('DeleteDynArray') END;
- END DeleteDynArray;
-
-
- (*-------------------------------------------------------------------*
- * Get liest aus dem dynamischen Array dyn das Element mit dem *
- * Index ind und speichert es in der übergebenen Variablen elem. *
- * Ist die Grö₧e der übergebenen Variablen ungleich der Grö₧e der *
- * Array-Elemente, kommt Fehlermeldung 107. *
- * Ist der Index ind grö₧er als die Indizes bisher geschriebenener *
- * Elemente, kommt Fehlermeldung Nr. 108. *
- * Fehlermeldung Nr. 109: Array Address Error sollte eigentlich nicht*
- * kommen und lä₧t auf einen "wildernden Pointer" schlie₧en, der *
- * hoffentlich nicht zu diesem Modul gehört. *
- *-------------------------------------------------------------------*)
- PROCEDURE Get (VAR dyn: DynArray; ind: CARDINAL; VAR elem: ARRAY OF BYTE);
- VAR
- i,
- segnr,
- baddr: CARDINAL;
- p : SegmentPtr;
- BEGIN
- IF DEBUG THEN Into ('Get') END;
- IF dyn=NIL THEN Error (106)
- ELSE
- WITH dyn^ DO
- IF SIZE(elem)<>size THEN Error (107)
- ELSIF ind > index THEN Error (108) END;
-
- segnr := ind DIV (MaxElementSize DIV size);
- IF segnr > anzseg THEN Error (109)
- ELSE
- p:=list;
- WHILE segnr>0 DO DEC(segnr); p:=p^.next; END;
- baddr:=(ind MOD (MaxElementSize DIV size))*size+1;
- FOR i:=0 TO HIGH (elem) DO
- elem[i]:=p^.block[baddr+i];
- END
- END
- END
- END;
- IF DEBUG THEN Leaving ('Get') END;
- END Get;
-
-
- (*-------------------------------------------------------------------*
- * Put speichert die Variable elem im dynamischen Array dyn unter *
- * dem Index ind ab. *
- * Ist die Grö₧e der übergebenen Variablen ungleich der Grö₧e der *
- * Array-Elemente, kommt Fehlermeldung 107. *
- * Ist der Index ind grö₧er als die Indizes bisher geschriebenener *
- * Elemente, wird das Array entsprechend erweitert. *
- * Für diesen Fall gilt: *
- * Alle Elemente vom ehemals letzten Element bis zum neuen Element *
- * werden mit dem Wert des an DefDynarray übergebenen Initiali- *
- * sierungswertes besetzt. *
- *-------------------------------------------------------------------*)
- PROCEDURE Put (VAR dyn: DynArray; ind: CARDINAL; VAR elem: ARRAY OF BYTE);
- VAR
- i,
- segnr,
- baddr: CARDINAL;
- p : SegmentPtr;
- BEGIN
- IF DEBUG THEN Into ('Put') END;
- IF dyn=NIL THEN Error (106)
- ELSE
- WITH dyn^ DO
- IF SIZE(elem)<>size THEN Error (107)
- ELSE
- segnr := ind DIV (MaxElementSize DIV size);
- IF ind > index THEN index:=ind END;
- WHILE segnr >= anzseg DO (* reserviere + initialisiere Blöcke *)
- NewSegment (dyn);
- END;
- p:=list;
- WHILE segnr>0 DO DEC(segnr); p:=p^.next; END;
- baddr:=(ind MOD (MaxElementSize DIV size))*size+1;
- FOR i:=0 TO HIGH (elem) DO
- p^.block[baddr+i]:=elem[i];
- END
- END
- END
- END;
- IF DEBUG THEN Leaving ('Put') END;
- END Put;
-
- (*-------------------------------------------------------------------*
- * LastIndex gibt den letzten, zum Lesen erlaubten Index des *
- * dynamischen Arrays dyn zurück. *
- *-------------------------------------------------------------------*)
- PROCEDURE LastIndex (VAR dyn: DynArray): CARDINAL;
- BEGIN
- IF dyn=NIL THEN Error (106); RETURN (0);
- ELSE
- RETURN (dyn^.index);
- END;
- END LastIndex;
-
-
- (*-------------------------------------------------------------------*
- * ElementSize gibt die Grö₧e eines einzelnen Array-Elementes in *
- * Byte zurück. *
- *-------------------------------------------------------------------*)
- PROCEDURE ElementSize (VAR dyn: DynArray): CARDINAL;
- BEGIN
- IF dyn=NIL THEN Error (106); RETURN (0)
- ELSE
- RETURN (dyn^.size);
- END;
- END ElementSize;
-
- (*-------------------------------------------------------------------*
- * LoadDynArray lädt aus dem Stream <in> die Elemente des Arrays. *
- * Die Variable elem wird hier auch als Initialisierung von nicht *
- * explizit definierten Array-Elementen verwendet. *
- * Siehe auch DefDynArray. *
- * Der Stream <in> mu₧ für READ geöffnet sein und entsprechendes *
- * Format besitzen: *
- * Byte 0..1: Grö₧e eines Array-Elements *
- * Byte 2..3: Anzahl der Elemente *
- * Byte 4..n: Array-Elemente *
- *-------------------------------------------------------------------*)
- PROCEDURE LoadDynArray (VAR in: Stream;
- VAR dyn: DynArray; elem: ARRAY OF BYTE);
- VAR i,j: CARDINAL;
- anzelem,
- sizelem: CARDINAL;
- BEGIN
- DefDynArray (dyn, elem);
- Read16Bit (in, sizelem); Read16Bit (in, anzelem);
- IF sizelem<>ElementSize(dyn) THEN
- Message ('Fehler beim Laden eines Arrays:');
- Error (107);
- ELSE
- FOR i:=0 TO anzelem DO
- FOR j:=0 TO HIGH(elem) DO Read8Bit (in, elem[j]) END;
- Put (dyn, i, elem);
- END
- END;
- END LoadDynArray;
-
-
- (*-------------------------------------------------------------------*
- * SaveDynArray speichert ein dynamisches Array in den Stream <out>. *
- * Der Stream <out> mu₧ für READWRITE geöffnet sein. *
- * Die Variable <elem> dient zum Typ-Check und kann einen beliebigen*
- * Wert enthalten. *
- * Das Speicherformat ist in LoadDynArray beschrieben. *
- * NICHT VERGESSEN: Stream <out> SCHLIESSEN !! *
- *-------------------------------------------------------------------*)
- PROCEDURE SaveDynArray (VAR out: Stream;
- VAR dyn: DynArray; elem: ARRAY OF BYTE);
- VAR i,j: CARDINAL;
- BEGIN
- Write16Bit (out, ElementSize(dyn));
- Write16Bit (out, LastIndex (dyn));
- FOR i:=0 TO LastIndex (dyn) DO
- Get (dyn, i, elem);
- FOR j:=0 TO HIGH(elem) DO Write8Bit (out, elem[j]) END;
- END;
- END SaveDynArray;
-
- END DynArrayHandler.
-
-