(* BSD 2-Clause License Copyright (c) 2018-2021, Anton Krotov All rights reserved. *) MODULE CHUNKLISTS; IMPORT LISTS, WR := WRITER; CONST LENOFBYTECHUNK = 65536; LENOFINTCHUNK = 16384; TYPE ANYLIST = POINTER TO RECORD (LISTS.LIST) length: INTEGER END; BYTELIST* = POINTER TO RECORD (ANYLIST) END; BYTECHUNK = POINTER TO RECORD (LISTS.ITEM) data: ARRAY LENOFBYTECHUNK OF BYTE; count: INTEGER END; INTLIST* = POINTER TO RECORD (ANYLIST) END; INTCHUNK = POINTER TO RECORD (LISTS.ITEM) data: ARRAY LENOFINTCHUNK OF INTEGER; count: INTEGER END; PROCEDURE SetByte* (list: BYTELIST; idx: INTEGER; byte: BYTE); VAR chunk: BYTECHUNK; item: LISTS.ITEM; BEGIN ASSERT(idx >= 0); ASSERT(list # NIL); item := LISTS.getidx(list, idx DIV LENOFBYTECHUNK); ASSERT(item # NIL); chunk := item(BYTECHUNK); idx := idx MOD LENOFBYTECHUNK; ASSERT(idx < chunk.count); chunk.data[idx] := byte END SetByte; PROCEDURE GetByte* (list: BYTELIST; idx: INTEGER): BYTE; VAR chunk: BYTECHUNK; item: LISTS.ITEM; BEGIN ASSERT(idx >= 0); ASSERT(list # NIL); item := LISTS.getidx(list, idx DIV LENOFBYTECHUNK); ASSERT(item # NIL); chunk := item(BYTECHUNK); idx := idx MOD LENOFBYTECHUNK; ASSERT(idx < chunk.count) RETURN chunk.data[idx] END GetByte; PROCEDURE PushByte* (list: BYTELIST; byte: BYTE); VAR chunk: BYTECHUNK; BEGIN ASSERT(list # NIL); chunk := list.last(BYTECHUNK); IF chunk.count = LENOFBYTECHUNK THEN NEW(chunk); chunk.count := 0; LISTS.push(list, chunk) END; chunk.data[chunk.count] := byte; INC(chunk.count); INC(list.length) END PushByte; PROCEDURE PushStr* (list: BYTELIST; str: ARRAY OF CHAR): INTEGER; VAR i, res: INTEGER; BEGIN res := list.length; i := 0; REPEAT PushByte(list, ORD(str[i])); INC(i) UNTIL str[i - 1] = 0X RETURN res END PushStr; PROCEDURE GetStr* (list: BYTELIST; pos: INTEGER; VAR str: ARRAY OF CHAR): BOOLEAN; VAR i: INTEGER; res: BOOLEAN; BEGIN res := FALSE; i := 0; WHILE (pos < list.length) & (i < LEN(str)) & ~res DO str[i] := CHR(GetByte(list, pos)); res := str[i] = 0X; INC(pos); INC(i) END RETURN res END GetStr; PROCEDURE WriteToFile* (list: BYTELIST); VAR chunk: BYTECHUNK; BEGIN chunk := list.first(BYTECHUNK); WHILE chunk # NIL DO WR.Write(chunk.data, chunk.count); chunk := chunk.next(BYTECHUNK) END END WriteToFile; PROCEDURE CreateByteList* (): BYTELIST; VAR bytelist: BYTELIST; list: LISTS.LIST; chunk: BYTECHUNK; BEGIN NEW(bytelist); list := LISTS.create(bytelist); bytelist.length := 0; NEW(chunk); chunk.count := 0; LISTS.push(list, chunk) RETURN list(BYTELIST) END CreateByteList; PROCEDURE SetInt* (list: INTLIST; idx: INTEGER; int: INTEGER); VAR chunk: INTCHUNK; item: LISTS.ITEM; BEGIN ASSERT(idx >= 0); ASSERT(list # NIL); item := LISTS.getidx(list, idx DIV LENOFINTCHUNK); ASSERT(item # NIL); chunk := item(INTCHUNK); idx := idx MOD LENOFINTCHUNK; ASSERT(idx < chunk.count); chunk.data[idx] := int END SetInt; PROCEDURE GetInt* (list: INTLIST; idx: INTEGER): INTEGER; VAR chunk: INTCHUNK; item: LISTS.ITEM; BEGIN ASSERT(idx >= 0); ASSERT(list # NIL); item := LISTS.getidx(list, idx DIV LENOFINTCHUNK); ASSERT(item # NIL); chunk := item(INTCHUNK); idx := idx MOD LENOFINTCHUNK; ASSERT(idx < chunk.count) RETURN chunk.data[idx] END GetInt; PROCEDURE PushInt* (list: INTLIST; int: INTEGER); VAR chunk: INTCHUNK; BEGIN ASSERT(list # NIL); chunk := list.last(INTCHUNK); IF chunk.count = LENOFINTCHUNK THEN NEW(chunk); chunk.count := 0; LISTS.push(list, chunk) END; chunk.data[chunk.count] := int; INC(chunk.count); INC(list.length) END PushInt; PROCEDURE CreateIntList* (): INTLIST; VAR intlist: INTLIST; list: LISTS.LIST; chunk: INTCHUNK; BEGIN NEW(intlist); list := LISTS.create(intlist); intlist.length := 0; NEW(chunk); chunk.count := 0; LISTS.push(list, chunk) RETURN list(INTLIST) END CreateIntList; PROCEDURE Length* (list: ANYLIST): INTEGER; RETURN list.length END Length; END CHUNKLISTS.