UNSAFE MODULE; IMPORT FloatMode, Word; CONST Bits = ARRAY [0..3] OF INTEGER { 8, 16, 32, 64 }; VAR init_done := FALSE; local : T; TYPE Inner = RECORD F : BITS 24 FOR CHAR END; (* STRICTALIGN will require this record to have alignment of 32, to prevent it's crossing a word boundary if it were to be allocated, as a field of a containing record, starting at the last or next-to-last byte of a machine word. LAZYALIGN will allow alignment of 8 bits. *) TYPE Outer = RECORD A : CHAR; B : Inner (* ^There will be padding before B IFF alignment of Inner is > 8. *) END; PROCEDURE RTPacking IsLazy ( ) : BOOLEAN = VAR V : Outer; Offset : CARDINAL; BEGIN Offset := ADR ( V . B ) - ADR ( V . A ); RETURN Offset = ADRSIZE ( CHAR ) END IsLazy; PROCEDURELocal (): T = VAR a: RECORD ch: CHAR; x: EXTENDED; END; b: RECORD ch: CHAR; x: RECORD ch: CHAR; END; END; i: INTEGER := 1; x: ADDRESS := ADR (i); p: UNTRACED REF CHAR := x; BEGIN IF NOT init_done THEN local.word_size := SizeOf (ADRSIZE (INTEGER)); local.long_size := SizeOf (ADRSIZE (LONGINT)); local.max_align := SizeOf (ADR (a.x) - ADR (a.ch)); local.struct_align := SizeOf (ADR (b.x) - ADR (b.ch)); local.little_endian := (p^ = VAL (1, CHAR)); local.float := FloatKind.IEEE; IF NOT FloatMode.IEEE THEN local.float := FloatKind.VAX; END; local.lazy_align := IsLazy(); init_done := TRUE; END; RETURN local; END Local; PROCEDURESizeOf (n: INTEGER): CARDINAL = BEGIN (* convert address units to bits *) n := n DIV ADRSIZE(CHAR) * BITSIZE(CHAR); (* look for a known size *) FOR i := FIRST (Bits) TO LAST (Bits) DO IF (Bits[i] = n) THEN RETURN n; END; END; <*ASSERT FALSE*> END SizeOf; PROCEDUREEncode (READONLY t: T): INTEGER = VAR n := 0; BEGIN n := Word.Or (Word.Shift (n, 1), ORD (t.lazy_align)); n := Word.Or (Word.Shift (n, 2), BitSize (t.long_size)); n := Word.Or (Word.Shift (n, 2), BitSize (t.word_size)); n := Word.Or (Word.Shift (n, 2), BitSize (t.max_align)); n := Word.Or (Word.Shift (n, 2), BitSize (t.struct_align)); n := Word.Or (Word.Shift (n, 1), ORD (t.little_endian)); n := Word.Or (Word.Shift (n, 2), ORD (t.float)); RETURN n; END Encode; PROCEDUREDecode (i: INTEGER): T = VAR t: T; BEGIN t.float := VAL (Word.And (i, 3), FloatKind); i := Word.Shift (i, -2); t.little_endian := VAL (Word.And (i, 1), BOOLEAN); i := Word.Shift (i, -1); t.struct_align := Bits[Word.And (i, 3)]; i := Word.Shift (i, -2); t.max_align := Bits[Word.And (i, 3)]; i := Word.Shift (i, -2); t.word_size := Bits[Word.And (i, 3)]; i := Word.Shift (i, -2); t.long_size := Bits[Word.And (i, 3)]; i := Word.Shift (i, -2); t.lazy_align := VAL (Word.And (i, 1), BOOLEAN); i := Word.Shift (i, -1); <*ASSERT i = 0*> RETURN t; END Decode; PROCEDUREBitSize (n: CARDINAL): [FIRST (Bits) .. LAST (Bits)] = BEGIN FOR i := FIRST (Bits) TO LAST (Bits) DO IF (Bits[i] = n) THEN RETURN i; END; END; <*ASSERT FALSE*> END BitSize; BEGIN END RTPacking.