[Oberon] Dynamically sized allocation with NEW()

Tomas Kral thomas.kral at email.cz
Fri Aug 3 10:36:19 CEST 2018


On Thu, 2 Aug 2018 19:38:10 +0200
Jörg <joerg.straube at iaeth.ch> wrote:

> This is obviously not a recipe for all cases, but it shows that you
> can live with NEW without size...

Hi,

I maintain this self allocating bitmap example, as referred `NEW with
size' (becomes obsession of mine, sort of..), I have revisited after
`ORP' recent update. It is not perfect and possibly stands to be
corrected, improved or made simple.

MODULE BM; (*TK 20.9.2017 / 3.8.2018  variable size bitmap example*)
  IMPORT SYSTEM, Kernel, Texts, Oberon;

  TYPE
    Tag = POINTER TO TypeDesc;
    TypeDesc = RECORD 
      size: INTEGER;
      ext: ARRAY 3 OF INTEGER;
      ptr: INTEGER;
      next: Tag
    END; (* see Project Oberon, figure 8.8 *)

    (*Address = POINTER TO RECORD END; (* this pointer will be
    redefined by TypeTag *)*)
  
    Bitmap* = POINTER TO BitmapDesc;
    BitmapDesc = RECORD
      tag: TypeDesc; (* type descriptor of the pointer "base" *)
      mk: INTEGER; (* mark used by GC *)
      base: INTEGER; (* Address *)
      width, height: INTEGER
    END;

  VAR 
     W: Texts.Writer; B*: Bitmap;
     first: Tag; (* first in tag list *)

  PROCEDURE New(w, h: INTEGER): Bitmap;
    VAR b: Bitmap; t: Tag;
  BEGIN
    NEW(b); IF b # NIL THEN
      b.width := w; b.height := h;

      (* the following code defines bitmap type tag *)

      b.tag.size := (w+7) DIV 8 * h; (* bitmap size in bytes *)
      b.tag.size := (b.tag.size+31) DIV 32 * 32; (* allocate multiple
      of 32 byte blocks *)
      b.tag.ext[0] := -1; b.tag.ext[1] := -1; b.tag.ext[2] := -1;
      b.tag.ptr := -1; (* type has no pointers, important for GC *)
      b.mk := 0; (* unmark, GC marks for collection when it stops being
      referenced *)

      (* allocate memory and define its type *)
      Kernel.New(b.base, SYSTEM.ADR(b.tag));

      (* link new bitmap tag to list *)
      b.tag.next := first; first := SYSTEM.VAL(Tag, SYSTEM.ADR(b.tag));

      IF b.base = 0 (*Address = NIL*) THEN b := NIL
      ELSE (* report allocatted size and address *)
        Texts.WriteInt(W, b.tag.size, 6); Texts.WriteInt(W, b.base, 8);
        Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
      END

    END (* b # NIL *)
  RETURN b END New;

  PROCEDURE Create*;
    VAR w, h:INTEGER; S: Texts.Scanner;
  BEGIN
    Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos);
  Texts.Scan(S);
    IF S.class = Texts.Int THEN
      w := S.i; Texts.Scan(S);
      IF S.class = Texts.Int THEN h := S.i END
    END;
    B := New(w, h)
  END Create;

BEGIN Texts.OpenWriter(W); first := NIL
END BM.


Test allocating various block sizes, [width] x [height] in pixels
BM.Create 1 1 ~ this is a dot!
BM.Create 32 1 ~
BM.Create 32 32 ~
BM.Create 256 256 ~
BM.Create 256 1024 ~
BM.Create 1024 1024 ~

And watch system heap
System.Watch  System.Collect  System.Free BM ~

-- 
Tomas Kral <thomas.kral at email.cz>


More information about the Oberon mailing list