REFBitImpl.mesa
Copyright © 1984 by Xerox Corporation. All rights reserved.
Last edited by Curry, October 13, 1986 11:38:20 am PDT
Don Curry April 30, 1987 9:55:35 pm PDT
Last Edited by: Don Curry July 18, 1987 10:58:18 am PDT
This package provides bit level access to the values behind Cedar REFs. `Error' will be raised if you try to twiddle refs or pointers in this way.
DIRECTORY
AMBridge, AMModel, AMTypes, Basics, Commander, CommandTool, Convert, RefTab, Interpreter, IO, PrincOpsUtils, REFBit, Rope, RopeList, RTTypesPrivate, WorldVM;
REFBitImpl: CEDAR PROGRAM
IMPORTS AMModel, AMTypes, AMBridge, Basics, Commander, CommandTool, Convert, RefTab, Interpreter, IO, PrincOpsUtils, Rope, RopeList, RTTypesPrivate, WorldVM
EXPORTS REFBit =
BEGIN OPEN REFBit;
Error: PUBLIC ERROR [msg: ROPE] = CODE;
Size: PUBLIC PROC[ref: REF] RETURNS [size: INT] = {RETURN[Desc[ref].bitForm.size]};
Get: PUBLIC PROC[ref: REF, index: INT] RETURNS [val: BOOL] = {
wdSz: CARDINAL = Basics.bitsPerWord;
desc: REFBitDesc ← Desc[ref];
idx: CARDINAL ← desc.bitForm[index].firstBit;
TVToDescWds[desc];
val ← Basics.BITAND[desc.wds[idx/wdSz], Basics.BITSHIFT[1, wdSz - (idx MOD wdSz)-1]]#0};
Set: PUBLIC PROC[ref: REF, index: INT, val: BOOL] = {
word: WORD;
wdSz: CARDINAL = Basics.bitsPerWord;
desc: REFBitDesc ← Desc[ref];
idx: CARDINAL ← desc.bitForm[index].firstBit;
bit: CARDINAL ← idx MOD wdSz;
wd: CARDINAL ← idx/wdSz;
TVToDescWds[desc];
word  ← desc.wds[wd];
desc.wds[wd] ← IF val
THEN Basics.BITOR  [word,      Basics.BITSHIFT[1, wdSz-bit-1]]
ELSE Basics.BITAND [word, Basics.BITNOT[ Basics.BITSHIFT[1, wdSz-bit-1]]];
DescWdsToTV[desc]};
Procs handy for format access, names, printing, speed etc.
refDescCache: RefTab.Ref ← RefTab.Create[];
ResetCache: PUBLIC PROC = {refDescCache ← RefTab.Create[]};
Desc: PUBLIC PROC[ref: REF] RETURNS [desc: REFBitDesc] = {
found: BOOL;
value:  REF;
IF ISTYPE[ref, ROPE] THEN ref ← NEWFromName[NARROW[ref]];
[found, value] ← RefTab.Fetch[refDescCache, ref];
IF found
THEN desc ← NARROW[value]
ELSE TRUSTED {
desc    ← NEW[REFBitDescRec ← [ ] ];
desc.tv   ← AMBridge.TVForReferent[ref];
desc.wds   ← AMBridge.TVToWordSequence[desc.tv];
desc.typeName ← AMTypes.TVToName[desc.tv];
desc.fieldForm ← FieldFormatFromTV[desc.tv, NIL];
desc.bitForm  ← FlattenFormat[desc.fieldForm]};
[] ← RefTab.Store[refDescCache, ref, desc]};
BitNameList: PUBLIC PROC[ref: REF, both: BOOL] RETURNS[list: LIST OF ROPE] = {
desc: REFBitDesc ← Desc[ref];
FOR i: CARDINAL DECREASING IN [0..desc.bitForm.size) DO
IF both THEN list ← CONS[(IF desc.bitForm[i].nameInv#NIL
THEN desc.bitForm[i].nameInv
ELSE Rope.Cat["not.", desc.bitForm[i].name]), list];
list ← CONS[(IF desc.bitForm[i].name#NIL
THEN desc.bitForm[i].name
ELSE Rope.Cat["not.", desc.bitForm[i].nameInv]), list] ENDLOOP };
FormatListing: PUBLIC PROC[record: REF, bitLevel: BOOLFALSE] RETURNS[listing: ROPE] = {
rope:  IO.STREAM ← IO.ROS[];
current: CARDINAL ← 0;
total:  CARDINAL ← 0;
form:  Format;
desc:  REFBitDesc ← Desc[record];
form  ← IF bitLevel THEN desc.bitForm ELSE desc.fieldForm;
IF form=NIL THEN RETURN[NIL];
rope.PutF["\nBit Format: %g", IO.rope[desc.typeName]];
rope.PutRope["\n Index First Size Name"];
FOR i: CARDINAL IN [0..form.size) DO
name: ROPENIL;
IF form[i].name#NIL
THEN name ← Rope.Cat[name, " ", form[i].name];
IF form[i].nameInv#NIL
THEN name ← Rope.Cat[name, " not.", form[i].nameInv];
IF current # form[i].firstBit THEN {current ← form[i].firstBit; rope.PutRope["\n"]};
rope.PutRope["\n"];
rope.PutF[" %4g %4g %4g%g",
IO.card[i],
IO.card[form[i].firstBit],
IO.card[form[i].bitSize],
IO.rope[name]];
total ← total + form[i].bitSize;
current ← current + form[i].bitSize;
ENDLOOP;
rope.PutF["\n ---\n BitTotal: %4g\n", IO.card[total]];
listing ← IO.RopeFromROS[rope] };
NEWFromName: PUBLIC PROC[record: ROPE] RETURNS[ref: REF] = {
tv:   TV;
errorRope: ROPE;
noResult: BOOL;
type: AMTypes.Type;
IF Rope.Find[record, "LIST"]#-1 THEN RETURN[ NewFromNameList[record] ];
[tv, errorRope, noResult] ← Interpreter.Evaluate[record, originalContext];
IF noResult OR errorRope#NIL THEN ERROR Error[errorRope];
type ← AMTypes.TVType[tv];
WHILE AMTypes.TypeClass[type]=type DO
type ← AMTypes.UnderType[AMTypes.TVToType[tv]];
tv  ← AMTypes.New[type] ENDLOOP;
TRUSTED {ref← AMBridge.SomeRefFromTV[tv]};
Desc[ref].typeName ← record };
Rec1:  TYPE = RECORD[i0:        CARDINAL];
Rec2:  TYPE = RECORD[i0, i1:       CARDINAL];
Rec3:  TYPE = RECORD[i0, i1, i2:      CARDINAL];
Rec4:  TYPE = RECORD[i0, i1, i2, i3:     CARDINAL];
Rec5:  TYPE = RECORD[i0, i1, i2, i3, i4:    CARDINAL];
Rec6:  TYPE = RECORD[i0, i1, i2, i3, i4, i5:   CARDINAL];
Rec7:  TYPE = RECORD[i0, i1, i2, i3, i4, i5, i6:  CARDINAL];
Rec8:  TYPE = RECORD[i0, i1, i2, i3, i4, i5, i6, i7: CARDINAL];
boolRef: REF BOOL  ← NEW[BOOLTRUE];
NewFromNameList: PROC[record: ROPE] RETURNS[ref: REF] = {
names: LIST OF ROPENIL;
inStm:  IO.STREAM ← IO.RIS[record];
rope:  IO.ROPE;
size:  INT;
desc:  REFBitDesc ← NEW[REFBitDescRec ← [ ] ];
boolType: AMTypes.Type;
DO
ENABLE IO.EndOfStream => EXIT;
rope ← IO.GetTokenRope[inStm].token;
SELECT TRUE FROM
Rope.Equal[rope, "LIST"] => LOOP;
Rope.Equal[rope, "["]  => LOOP;
Rope.Equal[rope, "]"]  => EXIT;
ENDCASE      => names ← CONS[rope, names];
ENDLOOP;
names  ← RopeList.Reverse[names];
size  ← RopeList.Length[names];
ref  ← SELECT (size-1)/16 +1 FROM
1   => NEW[Rec1],
2   => NEW[Rec2],
3   => NEW[Rec3],
4   => NEW[Rec4],
5   => NEW[Rec5],
6   => NEW[Rec6],
7   => NEW[Rec7],
8   => NEW[Rec8],
ENDCASE => ERROR;
TRUSTED{
boolRef: REF BOOLNEW[BOOLTRUE];
boolType ← AMTypes.UnderType[AMTypes.TVType[AMBridge.TVForReferent[boolRef]]];
desc.tv   ← AMBridge.TVForReferent[ref];
desc.wds   ← AMBridge.TVToWordSequence[desc.tv];
desc.typeName ← record;
desc.fieldForm ← NEW[FormatSeq[size]];
desc.bitForm  ← NEW[FormatSeq[size]]};
FOR i: INT IN [0..size) DO
desc.fieldForm[i] ← desc.bitForm[i] ← [
type:  boolType,
name:  names.first,
nameInv: NIL,
firstBit: i,
bitSize: 1 ];
names ← names.rest ENDLOOP;
[] ← RefTab.Store[refDescCache, ref, desc]};
DescWdsToTV: PUBLIC PROC[desc: REFBitDesc] =
TRUSTED {AMBridge.SetTVFromWordSequence[desc.tv, desc.wds]};
TVToDescWds: PUBLIC PROC[desc: REFBitDesc] =
TRUSTED {desc.wds ← AMBridge.TVToWordSequence[desc.tv]};
TVToDescWds: PUBLIC PROC[desc: REFBitDesc] =
TRUSTED {
CardPointer:  TYPE = LONG POINTER TO CARD;
ValueAddress: TYPE = RTTypesPrivate.ValueAddress;
Pointer:   TYPE = LONG POINTER;
ptr:    Pointer;
words: CARDINAL = TVSize[tv];
words: CARDINAL ← desc.wds.size;
SELECT words FROM
0 => {                     RETURN};
1 => {desc.wds[0] ← AMBridge.TVToLC[desc.tv];        RETURN};
2 => {LOOPHOLE[@desc.wds[0], CardPointer]^𡤊MBridge.TVToLC[desc.tv]; RETURN};
ENDCASE => {
a: ValueAddress ← RTTypesPrivate.GetValueAddress[desc.tv];
WITH t: a SELECT FROM
constant    => {--desc.wds ← t.value;-- RETURN};
pointer    => ptr ← t.ptr;
remotePointer  => {
desc.wds ← RTTypesRemotePrivate.GetRemoteWords
[remotePointer: t.ptr, nWords: words];
RETURN};
copiedRemoteObject => ptr ← t.ptr;
ENDCASE    => ERROR;
PrincOpsUtils.LongCopy[from: ptr, nwords: words, to: @desc.wds[0]] } };
Private
FieldFormatFromTV: PROC[toptv: TV, topName: ROPE] RETURNS[format: Format] = {
FieldFormatRecList: PROC[list: FormatList, tv: TV, name: ROPE] RETURNS [FormatList] = {
type:  AMTypes.Type ← AMTypes.TVType[tv];
utype: AMTypes.Type ← AMTypes.UnderType[type];
uClass: AMTypes.Class ← AMTypes.TypeClass[ utype];
SELECT uClass FROM
record, structure   => {
nofFlds: NAT ← AMTypes.NComponents[utype];
IF name#NIL AND name.Length[]>0 THEN name ← name.Cat["."];
FOR fldIndex: CARDINAL DECREASING IN [0..nofFlds) DO
fldTV: TV  ← AMTypes.IndexToTV[tv, fldIndex+1];
fldName: ROPE ← AMTypes.IndexToName[utype, fldIndex+1];
list ← FieldFormatRecList[list, fldTV, name.Cat[fldName]];
ENDLOOP};
cardinal, longCardinal, integer, longInteger, real, character,
enumerated,
subrange     => {
firstBit, bitSize: INT;
[firstBit, bitSize] ← FieldBitsFromTV[tv];
list ← CONS[[
type:  utype,
name:  name,
nameInv: NIL,
firstBit: firstBit,
bitSize: bitSize
], list] };
ENDCASE  => ERROR Error["I can't deal with this TYPE"];
RETURN[list]};
formlist: FormatList ← FieldFormatRecList[NIL, toptv, topName];
index:  INT ← 0;
FOR lst: FormatList ← formlist, lst.rest WHILE lst#NIL DO index ← index+1 ENDLOOP;
format ← NEW[FormatSeq[index]];
index ← 0;
FOR lst: FormatList ← formlist, lst.rest WHILE lst#NIL
DO format[index] ← lst.first; index ← index+1 ENDLOOP};
array, sequence  => {
ispacked: BOOL    ← AMTypes.IsPacked        [utype];
dType: AMTypes.Type ← AMTypes.UnderType [AMTypes.Domain [utype]];
rType: AMTypes.Type ← AMTypes.UnderType [ AMTypes.Range [utype]];
length: INT    ← AMTypes.Length         [tv];
rtv:  TV     ← AMTypes.New         [rType];
bitsUsed:  INT   ← 1;
bitsForType: INT;
TRUSTED {bitsForType ← RTTypesPrivate.BitsForType[rType].bft};
[  ] ← FieldBitsFromTV [rtv];
IF length <=0 THEN ERROR;
IF ispacked AND bitsForType > 16
THENWHILE bitsForType > bitsUsed DO bitsUsed ← bitsUsed*2 ENDLOOP
ELSE bitsUsed ← 16*((bitsForType-1)/16 +1);
format ← NEW[FormatSeq[length]];
FOR i: INT IN [0..length) DO
format[i].format ← NIL;
format[i].name ← IO.PutFR["seq.%g", IO.int[i]];
format[i].firstBit ← i*bitsUsed;
format[i].bitSize ← bitsForType;
ENDLOOP;
ERROR Error["I can't deal with this TYPE"]}; -- Yet
FieldBitsFromTV: PROC[fieldTV: TV] RETURNS[firstBit, bitSize: CARDINAL] = TRUSTED {
tvRef: REF RTTypesPrivate.TypedVariableRec ← NARROW[fieldTV];
WITH tv: tvRef SELECT FROM
entire => RETURN[0, AMTypes.TVSize[fieldTV]*16];
embedded => {
WITH fld: tv.fd SELECT FROM
small => RETURN[16*fld.wordOffset+fld.field.bitFirst, fld.field.bitCount];
large => RETURN[16*fld.wordOffset, fld.size*16];
ENDCASE => ERROR };
constant => RETURN[0, tv.value.size*16];
ENDCASE => ERROR };
FlattenFormat: PROC[format: Format] RETURNS[new: Format] = {
bitIdx, bitFrmIdx, fldFrmIdx, bitsum: CARDINAL ← 0;
FOR fldFrmIdx IN [0..format.size) DO bitsum ← bitsum + format[fldFrmIdx].bitSize ENDLOOP;
new ← NEW[ FormatSeq[bitsum]];
FOR fldFrmIdx IN [0..format.size) DO
decoded: BOOL;
names: LIST OF ROPENIL;
[decoded, names] ←
DecodedEnumTypeCheck[format[fldFrmIdx].type, format[fldFrmIdx].bitSize];
FOR bitIdx IN [0..format[fldFrmIdx].bitSize) DO
name, nameInv: IO.ROPE;
IF decoded
THEN {
name ← format[fldFrmIdx].name.Cat[".", names.first];
IF (bitIdx+1) = format[fldFrmIdx].bitSize THEN {
name  ← IF names.first=NIL THEN NIL ELSE name;
nameInv ← format[fldFrmIdx].name.Cat[".", names.rest.first] };
names  ← names.rest}
ELSE name ← IF format[fldFrmIdx].bitSize > 1
THEN format[fldFrmIdx].name.Cat[".", Convert.RopeFromInt[bitIdx]]
ELSE format[fldFrmIdx].name;
new[bitFrmIdx] ← [
type:  CODE[BOOL],
name:  name,
nameInv: nameInv,
firstBit: format[fldFrmIdx].firstBit + bitIdx,
bitSize: 1 ];
bitFrmIdx ← bitFrmIdx+1;
ENDLOOP ENDLOOP};
DecodedEnumTypeCheck: PROC[type: Type, size: CARDINAL]
RETURNS[isDET: BOOL, names: LIST OF ROPE] = {
A decoded enumerated type can be used to directly generate multiplex controls.
The type can be coded as {0, 1} or {0, 1, 2, 4, 8 ...} or {0, 3, 5, 9, 17 ...}.
The first and last cases have the advantage that zero can be used a default multiplex control (lsb = 0 => no other bit is true).
In all cases it's possible to name the bits and/or their inverses using the enumerated type element names.
zeroHot, oneHot: BOOLFALSE;
biPwr: CARDINAL ← 2;
tv:   TV;
index:  CARDINAL;
bitName: ROPE;
NextEnum: PROC = {
bitName ← NIL;
FOR tv ← tv, AMTypes.Next[tv] WHILE tv#NIL DO
TRUSTED {index ← AMBridge.TVToCardinal[tv]};
bitName ← AMTypes.TVToName[tv ! AMTypes.Error => CONTINUE];
IF bitName # NIL THEN EXIT ENDLOOP };
IF AMTypes.TypeClass[type] # enumerated THEN RETURN[FALSE, NIL];
tv ← AMTypes.First[type]; NextEnum[];
IF bitName = NIL OR Rope.Equal[bitName,"FALSE"] THEN RETURN[FALSE, NIL];
IF index # 0 THEN names ← CONS[NIL, names] ELSE
{zeroHot ← TRUE; names ← CONS[bitName, names]; tv ← AMTypes.Next[tv]; NextEnum[]};
IF index # 1 THEN names ← CONS[NIL, names] ELSE
{oneHot ← TRUE; names ← CONS[bitName, names]; tv ← AMTypes.Next[tv]; NextEnum[]};
THROUGH [1..size) DO
check: INTIF oneHot THEN biPwr ELSE biPwr+1;
IF bitName = NIL OR index # check THEN RETURN[FALSE, NIL];
names ← CONS[bitName, names];
tv ← AMTypes.Next[tv]; NextEnum[];
biPwr ← biPwr*2;
ENDLOOP;
IF bitName # NIL
THENRETURN[FALSE, NIL] -- leftovers
ELSERETURN[TRUE, names]};
FlattenFormatOld: PROC[format: Format] RETURNS[new: Format] = {
bitIdx, bitFrmIdx, fldFrmIdx, bitsum: CARDINAL ← 0;
FOR fldFrmIdx IN [0..format.size) DO bitsum ← bitsum + format[fldFrmIdx].bitSize ENDLOOP;
new ← NEW[ FormatSeq[bitsum]];
FOR fldFrmIdx IN [0..format.size) DO
FOR bitIdx IN [0..format[fldFrmIdx].bitSize) DO
name: IO.ROPEIF format[fldFrmIdx].bitSize > 1
THEN format[fldFrmIdx].name.Cat[".", Convert.RopeFromInt[bitIdx]]
ELSE format[fldFrmIdx].name;
new[bitFrmIdx] ← [
type:  CODE[BOOL],
name:  name,
nameInv: NIL,
firstBit: format[fldFrmIdx].firstBit + bitIdx,
bitSize: 1 ];
bitFrmIdx ← bitFrmIdx+1;
ENDLOOP ENDLOOP };
BitFormat: Commander.CommandProc = {
bitLevel:  BOOLFALSE;
list:  LIST OF ROPE;
length: NAT;
[list, length] ← CommandTool.ParseToList[cmd];
FOR list ← list, list.rest WHILE list#NIL DO
IF list.first.Fetch[0]='-
THENSELECT list.first.Fetch[1] FROM
'b,'B => bitLevel ← TRUE;
ENDCASE
ELSE cmd.out.PutRope[FormatListing[list.first, bitLevel]];
ENDLOOP };
MyType:  TYPE = INT[0..125];
MySeq:  TYPE = REF MySeqRec;
MySeqRec: TYPE = RECORD[SEQUENCE size: CARDINAL OF MyType];
MyPSeq:  TYPE = REF MyPSeqRec;
MyPSeqRec: TYPE = RECORD[PACKED SEQUENCE size: CARDINAL OF MyType];
MyArray: TYPE = ARRAY [-2..7) OF MyType;
MyPArray: TYPE = PACKED ARRAY [-1..9) OF MyType;
Test: Commander.CommandProc = {
aref:  REF ← NEW[MyArray];
apref: REF ← NEW[MyPArray];
ref:  MySeq ← NEW[MySeqRec[7]];
packed: MyPSeq ← NEW[MyPSeqRec[9]];
[] ← Size[aref];
[] ← Size[apref];
[] ← Size[ref];
[] ← Size[packed] };
bitFormatDoc: ROPE = "[nameOfSomeType] -b => bit level";
originalContext: AMModel.Context;
TRUSTED {originalContext ← AMModel.RootContext[WorldVM.LocalWorld[]]};
Commander.Register[key:"REFBitFormat", proc: BitFormat,  doc: bitFormatDoc];
Commander.Register[key:"Test",    proc: Test,   doc: bitFormatDoc];
END.