* steve <84sg03zscs.fsf@loft.i-did-not-set--mail-host-address--so-tickle-me> : Wrote on Sat, 24 Jul 2021 10:41:55 -0400:
[define-bitfields - not yet but will try to use it shortly]
What I am looking for is a macro that does basically the same thing
but uses integers for field and masks, instead of bitvectors. It would
be nice, I would write it myself now but I am still under the weather
so to speak.
Not quite the same thing but recently I came up with a very crude DEFSTRUCT-PACKED which operates on (array (unsigned-byte 8)).
I may have written something better before and forgotten about it but
what to do with a poor memory and being under the weather and all
The syntax is (defstruct-packed name options slot-defs)
options is empty - just to get emacs to indent it properly
slot-defs = (slot-name [ init-val [ type [ count ]]] )
all the slots are C- "integral" values int8 int16 int32 int64 and I
assume efficient functions exist to do IO
load32 (array offset)
store32 (uint32 array offset), etc.
and the accessors will just translate to those functions.
;; structures for the metadata
(defstruct packed-slot-rep
name type initial-element count type-size octet-count offset)
(defstruct packed-struct-rep name slot-table)
(defun parse-packed-slot-def-rep (slot-def)
(let* ((atomp (atom slot-def))
(slot-name (if atomp slot-def (car slot-def)))
(init (if atomp 0 (or (cadr slot-def) 0)))
(type (if atomp 'uint8 (or (caddr slot-def) 'uint8)))
(count (if atomp 1 (or (cadddr slot-def) 1)))
(type-size (ecase type
((uint8) 1)
((uint16) 2)
((uint32) 4)
((uint64) 8)))
(octet-count (* type-size count)))
(make-packed-slot-rep
:name slot-name :type type :initial-element init
:count count :type-size type-size
:octet-count octet-count)))
(defun parse-packed-struct-rep (name slot-defs)
(let* ((rep (make-packed-struct-rep :name name))
(slot-table (mapcar #'parse-packed-slot-def-rep slot-defs))
(offset 0))
(dolist (p slot-table)
(setf (packed-slot-rep-offset p) offset)
(incf offset (packed-slot-rep-octet-count p)))
(setf (packed-struct-rep-slot-table rep) slot-table)
(setf (get name 'struct-rep) rep)))
(defun make-array-for-packed-struct
(packed-struct-name &optional (rep (get packed-struct-name 'struct-rep)))
(let* ((length (reduce #'+ (packed-struct-rep-slot-table rep)
:key 'packed-slot-rep-octet-count))
(array (make-array length :element-type '(unsigned-byte 8))))
(init-array-for-packed-struct array rep)
array))
;; and the macro
(defmacro defstruct-packed (name options &rest slot-defs)
(declare (ignore options))
(let* ((rep (parse-packed-struct-rep name slot-defs))
(slot-table (packed-struct-rep-slot-table rep))
(constructor-name (intern (concatenate 'string "MAKE-"
(symbol-name name))))
(forms nil))
(push `(defun ,constructor-name () (make-array-for-packed-struct ',name))
forms)
(dolist (slot-rep slot-table)
(with-slots ((slot-name name) type-size offset count) slot-rep
(when (= count 1)
(let* ((accessor-name (intern (concatenate 'string (symbol-name name)
"-"
(symbol-name slot-name))))
(p (gensym "P"))
(w (gensym "W")))
(push `(defun ,accessor-name (p)
,(ecase type-size
(1 `(aref p ,offset))
(2 `(load16 p ,offset))
(4 `(load32 p ,offset))
(8 `(load64 p ,offset))))
forms)
(push
(ecase type-size
(1 `(defsetf ,accessor-name (,p) (,w)
`(setf (aref ,,p ,,offset) ,,w)))
(2 `(defsetf ,accessor-name (,p) (,w)
`(store16 ,,p ,,w ,,offset)))
(4 `(defsetf ,accessor-name (,p) (,w)
`(store32 ,,p ,,w ,,offset)))
(8 `(defsetf ,accessor-name (,p) (,w)
`(store64 ,,p ,,w ,,offset))))
forms)))))
`(progn ,@(nreverse forms))))
All very straightforward and crude but since I've lost the chops I can't
figure out how to put the setters into one single backquoted form with
the ecase evaluated INSIDE.
Like you said this sort of thing used to be a breeze a decade ago. In
any case the mind will be renewed in the world to come so programming
there shouldn't be a problem
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)