(* BSD 2-Clause License Copyright (c) 2018, Anton Krotov All rights reserved. *) MODULE CHUNKLISTS; IMPORT LISTS, WR := WRITER; CONST LENOFBYTECHUNK = 64000; LENOFINTCHUNK = 16000; 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 ChunkNum: INTEGER; chunk: BYTECHUNK; BEGIN ASSERT(idx >= 0); ASSERT(list # NIL); ChunkNum := idx DIV LENOFBYTECHUNK; idx := idx MOD LENOFBYTECHUNK; chunk := list.first(BYTECHUNK); WHILE (chunk # NIL) & (ChunkNum > 0) DO chunk := chunk.next(BYTECHUNK); DEC(ChunkNum) END; ASSERT(chunk # NIL); ASSERT(idx < chunk.count); chunk.data[idx] := byte END SetByte; PROCEDURE GetByte* (list: BYTELIST; idx: INTEGER): BYTE; VAR ChunkNum: INTEGER; chunk: BYTECHUNK; BEGIN ASSERT(idx >= 0); ASSERT(list # NIL); ChunkNum := idx DIV LENOFBYTECHUNK; idx := idx MOD LENOFBYTECHUNK; chunk := list.first(BYTECHUNK); WHILE (chunk # NIL) & (ChunkNum > 0) DO chunk := chunk.next(BYTECHUNK); DEC(ChunkNum) END; ASSERT(chunk # NIL); 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 WriteToFile* (file: WR.FILE; list: BYTELIST); VAR chunk: BYTECHUNK; BEGIN chunk := list.first(BYTECHUNK); WHILE chunk # NIL DO WR.Write(file, 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 ChunkNum: INTEGER; chunk: INTCHUNK; BEGIN ASSERT(idx >= 0); ASSERT(list # NIL); ChunkNum := idx DIV LENOFINTCHUNK; idx := idx MOD LENOFINTCHUNK; chunk := list.first(INTCHUNK); WHILE (chunk # NIL) & (ChunkNum > 0) DO chunk := chunk.next(INTCHUNK); DEC(ChunkNum) END; ASSERT(chunk # NIL); ASSERT(idx < chunk.count); chunk.data[idx] := int END SetInt; PROCEDURE GetInt* (list: INTLIST; idx: INTEGER): INTEGER; VAR ChunkNum: INTEGER; chunk: INTCHUNK; BEGIN ASSERT(idx >= 0); ASSERT(list # NIL); ChunkNum := idx DIV LENOFINTCHUNK; idx := idx MOD LENOFINTCHUNK; chunk := list.first(INTCHUNK); WHILE (chunk # NIL) & (ChunkNum > 0) DO chunk := chunk.next(INTCHUNK); DEC(ChunkNum) END; ASSERT(chunk # NIL); 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.