[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bit fields in defstruct



    Date: 15 Apr 86 00:17 EST
    From: Dave.Touretzky@A.CS.CMU.EDU

    Can someone tell me why Common Lisp defstruct doesn't support bit fields?
    This is a Zetalisp feature that I make heavy use of.  The equivalent feature
    in Common Lisp would look something like:

	    (defstruct thingie
	      (foo 'default-foo-value)
	      ((low-bar  (byte 8  0))
	       (mid-bar  (byte 8  8) #x00 :read-only t) ;filled by constructor
	       (high-bar (byte 8 12) #x1a))
	      (baz 'default-baz-value))

    This makes THINGIE a vector with 4 elements (counting the structure name);
    the second element is an integer with default value #x1a0000.  The structure
    has 5 access functions:

	    THINGIE-FOO
	    THINGIE-LOW-BAR
	    THINGIE-MID-BAR
	    THINGIE-HIGH-BAR
	    THINGIE-BAZ

    The access function for -BAR slots expands to a LDB, and the SETF macro
    expands to a DPB.  The knowledge that three of the slots of a THINGIE are
    bit fields of the same integer is hidden from the rest of the program.

    The reason I need this feature is I am building thousands of instances of a
    particular structure, and the difference between representing half a dozen
    bit fields with one integer versus six integers is significant in terms of
    memory cost.  I don't think a user should build his own access functions for
    bit fields; I think defstruct should do that for him.

Two things:

(1) Syntax.  What do you think about
	(defstruct thingie
	  (foo 'default-foo-value)
	  ((low-bar     0 :byte-field (byte 8 0))
	   (mid-bar  #x00 :byte-field (byte 8 8) :read-only t)
	   (high-bar #x1A :byte-field (byte 8 12)))
	  (baz 'default-baz-value))
instead of yours?  Yes, I know the default value must be specified, but
this syntax is consistent with non-nested syntax.  I propose that a
value of NIL means that it isn't filled in (and isn't forced to zero
(see [3]).

(2) Performance.  Users should be wary that doing such things has
efficiency issues depending on the boundaries between fixnum and bignum.
That is, since the fields are integers, a user could accidentally go
consing a lot of bignums, where a normal defstruct wouldn't.

[3, In your example, mid-bar and high-bar overlap.  mid-bar gets filled
in by the constructor, and high-bar has a default.  How are these
merged, since they overlap?]

    PS:  I suppose if defstruct were highly optimizing one could declare six
    fields of :TYPE BIT and expect them to be packed into one word.  This
    doesn't solve everything though; in some cases (like when communicating
    with external programs) one wants to specify the exact postion of each bit
    field in a word.  Also, one might want to have overlapping bit fields in the
    same word, such as three 1-bit fields and a 3-bit field that covers them.

Indeed, this is one of the motivations for Symbolics extending defstruct
along these lines.  Normal users don't need this; it is usually used for
interfacing to hardware device registers, and sometimes network packets
that have overlapping fields themselves.