Rocksolid Light

Welcome to RetroBBS

mail  files  register  newsreader  groups  login

Message-ID:  

No amount of genius can overcome a preoccupation with detail.


devel / comp.lang.lisp / Re: MACRO: define-bitflags

SubjectAuthor
* MACRO: define-bitflagssteve
`- Re: MACRO: define-bitflagsMadhu

1
MACRO: define-bitflags

<84sg03zscs.fsf@loft.i-did-not-set--mail-host-address--so-tickle-me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=16646&group=comp.lang.lisp#16646

  copy link   Newsgroups: comp.lang.lisp
Path: i2pn2.org!i2pn.org!news.neodome.net!news.uzoreto.com!news-out.netnews.com!news.alt.net!fdc3.netnews.com!peer02.ams1!peer.ams1.xlned.com!news.xlned.com!peer02.ams4!peer.am4.highwinds-media.com!peer02.iad!feed-me.highwinds-media.com!news.highwinds-media.com!feeder.usenetexpress.com!tr1.iad1.usenetexpress.com!border1.nntp.dca1.giganews.com!nntp.giganews.com!buffer1.nntp.dca1.giganews.com!buffer2.nntp.dca1.giganews.com!news.giganews.com.POSTED!not-for-mail
NNTP-Posting-Date: Sat, 24 Jul 2021 09:41:59 -0500
From: steve@loft.i-did-not-set--mail-host-address--so-tickle-me (steve)
Newsgroups: comp.lang.lisp
Subject: MACRO: define-bitflags
Date: Sat, 24 Jul 2021 10:41:55 -0400
Message-ID: <84sg03zscs.fsf@loft.i-did-not-set--mail-host-address--so-tickle-me>
Organization: Loft - a Gnu/Linux system
User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux)
Cancel-Lock: sha1:6JClBYgUD6BfmGTeK3LVB0l7RqU=
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="=-=-="
Lines: 422
X-Usenet-Provider: http://www.giganews.com
X-Trace: sv3-Qyfn/0CuoCnfC4rBOyE/pITRqCnc/GmVnEidFXN9hhHu6CZjsgOHdU9AtDgH8gz3drIofkuIb/OgnvK!FyJdQwBsfv+rD/76yrac8kZsa6bhPINMilkqDbpEq25hPynIW4DhJ9tzZnuxhfpJOED2NrJzaYq0!9tGOpMwhazL4p+lKkMlnui9GqRKkbg==
X-Complaints-To: abuse@giganews.com
X-DMCA-Notifications: http://www.giganews.com/info/dmca.html
X-Abuse-and-DMCA-Info: Please be sure to forward a copy of ALL headers
X-Abuse-and-DMCA-Info: Otherwise we will be unable to process your complaint properly
X-Postfilter: 1.3.40
X-Original-Bytes: 19918
X-Received-Bytes: 20224
 by: steve - Sat, 24 Jul 2021 14:41 UTC
Attachments: /home/steve/common-lisp/bitfields/bitfields.lisp (message/external-body)

I wanted to share some code and get some thoughts, and say a bit thank
you to the lisp community...

#|
(defsystem "local"
:description "A macro for using bit-fields as bit-vectors."
:version "0.3.1"
:description "bitfield macro"
:components ((:file "bitfields"))
:author "steve g"
:licence "GPL")

I do not know how to use defsystem or asdf. I use makefiles.

Description: A macro for using bit-fields as bit-vectors.
Date: 2021-07-24 09:51:15-05:00
Author: Steve
Version: 0.3.1
License: GPL
Platform: GNU/Linux/Fedora
localplatform: Linux loft 5.12.14-s1-loft
TestedOnSytems: (sbcl franz lispworks)
TestedSystemInfo: ("franz allegro-express 32bit ^1"
"LispWorks(R) Personal Edition ^2"
"Steele Bank Common Lisp non-unicode mode")
---------

This macro is fun to play with. be careful it is being used but not really
tested fully. Always check the macro expansion. This macro is so indispensable
to me I thought I would share it; like c.l.l used to do. I do not know how to
use github or google drive. I just have always used USEnet or ftp. I have no
email address because my ISP thinks I am a ter(ro)rist and I simply cannot
bring myself to use MySQL. I really need a nice small database - like SAP
sybase for linux (hint hint ).

hence the use of USEnet.

I would love to hear comments about this, I wrote it like ~20 years ago, and
it still works for me. I don't remember it all; someone once asked me what the
longest loop macro I wrote was; well here it is. I would like to add
conditions to the macro; I just don't know how to access the macro
environment. I would love to know the calling function for better condition
handling as these bit vectors get all over the place. I neglected to use a
structure or object for simplicity (obviously) and for efficiency I recommend
using the type checking option.

* Warning: Not all common lisp implementations can expand a loop macro of this
depth. clisp used to be the notable refusal. I am using SBCL and it can
handle loop macros from Satan himself. Thank you people of the sbcl; I can
program once again!

The macro looks difficult to me now; like I said I am a tad under the weather
still. Believe it or not I wrote this in one sitting. I sure do miss those
dayz.

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.

Well please enjoy and let me know if there is a bug, if you find this
interesting, or if you have something similiar. I have seen something similiar
on github; this vrsion seems to be somewhat efficient.

(defun-bitflags (line-flags
(:check-type t)
(:accessor nil)
(:conc-name line-)
(:initial-element 0)
(:reset-function reset-line-flags)
(:constructor create-line-flags)
(:predicate-suffix -p)
(:print-function print-line-flags)
(:default-mask (:set modified 1))
(:optimize (speed 3) (space 0)))
"Test define-bitflags"
(modified :initial-element 1)
insertion
(deletion :documentation "This is a bit-flag")
(killed :mask ((:set deletion t) (:toggle insertion))))
|#

(defmacro define-bitflags (name/options &rest bit-fields)
(flet ((make-fn-name (&rest names)
(intern (format nil "~{~@[~a~]~}" names)))
(extract-docstring (field)
(let ((string (cadr (member :documentation field))))
(when string (list string))))
(l-assq (item lst)
(declare (list lst))
"Return ASSOC <item> <lst>. Equality is defined by EQ."
(assoc item lst :test #'eq))
(l-memq (item lst)
(declare (list lst))
(member item lst :test #'eq))
(lst-length=1 (lst)
(declare (list lst))
"Return T or nil if length of the list <lst> is one."
(and (consp lst) (null (cdr lst)))))
(let (field-masks default-masks
print-function print-function-parameters (conc-name t)
constructor-name constructor-parameters type reset-function
type-check optimizations documentation max-field-size
(initial-element 0) (predicate-suffix '-p) (accessor-p t))

(when (stringp (car bit-fields))
;; Snarf the docstring
(setq documentation (list (pop bit-fields))))

(setq bit-fields
;; Ensure each of BIT-FIELDS is a list for easier parsing
(mapcar #'(lambda (field)
(if (consp field) field (list field)))
bit-fields))

(setq field-masks
;; Set to an alist of field names and their bit position in
;; the bit vector. This is used to build a suitable mask in
;; the setf expanders. Also create the type specifier for the
;; bit-vector since we're already traversing the list.
(let ((bit -1))
(prog1 (mapcar
#'(lambda (field)
(cons field (incf bit)))
;; While we're looping through the list of fields
;; check the validity of the keyword arguments.
(mapcar
#'(lambda (bit-field)
(let ((field (car bit-field))
(keys (cdr bit-field)))
(loop for key in keys by #'cddr
do (check-type key (member :documentation
:mask :initial-element)))
field))
bit-fields))
(setq type
`(simple-bit-vector ,(1+ bit))))))

;; Setup some defaults for when NAME/OPTIONS is an atom (which
;; is an indication that no options have been supplied).
(cond ((or (atom name/options)
(and (lst-length=1 name/options)
(setq name/options (car name/options))))
(setq conc-name
(make-fn-name name/options "-"))
(setq constructor-name
(make-fn-name 'make "-" name/options)))
(t
;; NAME/OPTIONS is a list, parse the default options
(dolist (option (cdr name/options))
(ecase (pop option)
(:CONC-NAME
(setq conc-name (car option)))
(:INITIAL-ELEMENT (setq initial-element (car option)))
(:ACCESSOR (setq accessor-p (pop option)))
(:CONSTRUCTOR
(setq constructor-name (pop option))
(setq constructor-parameters option))
(:PRINT-FUNCTION
(setq print-function (pop option))
(setq print-function-parameters (car option)))
(:RESET-FUNCTION (setq reset-function (pop option)))
(:PREDICATE-SUFFIX (setq predicate-suffix (car option)))
(:DEFAULT-MASK (setq default-masks option))
(:CHECK-TYPE (setq type-check (car option)))
(:OPTIMIZE (setq optimizations
(list `(optimize ,@ option))))))))
;; Fill in the needed defaults in case they were not supplied
(when (eq conc-name t)
(setq conc-name (make-fn-name (car name/options) "-")))
(when (null constructor-name)
(setq constructor-name
(make-fn-name 'make "-" (car name/options))))
(if print-function
;; Get length of the largest field name for print-function
(setq max-field-size
(+ (loop for field in field-masks
for field-name = (car field)
maximizing (length (symbol-name field-name)))
8)))

;; Now construct the forms
(loop for field in bit-fields
for counter upfrom 0
for field-name = (pop field)
for fn-name = (make-fn-name conc-name field-name)
for value-var = (make-symbol (format nil "BIT-~:@(~R~)" counter))
;; Accessors
when accessor-p
collect `(defun ,fn-name (flags)
,(if type-check
`(check-type flags ,type)
`(declare ,@ optimizations (type ,type flags)))
,@ (extract-docstring field)
(sbit flags ,counter))
into result
;; Predicates
collect `(defun
,(make-fn-name fn-name predicate-suffix) (flags)
,(if type-check
`(check-type flags ,type)
`(declare ,@ optimizations (type ,type flags)))
(plusp (sbit flags ,counter)))
into result
;; Setf expansions with masks ...
collect `(defsetf ,fn-name (flags) (,value-var)
`(progn ,,.
(let ((masks
;; replace `sublis' with `progn' to debug
(sublis field-masks
(remove-if
#'(lambda (mask)
(eq (cadr mask) field-name))
(append default-masks
(cadr (l-memq :mask field)))))))
(when masks
;; Masks: ((:SET 2 1) (:TOGGLE 1))
(loop for mask in masks
collect
(ecase (pop mask)
(:SET
``(setf (sbit (the ,',type
,flags) ,,(car mask))
,,(cond ((eq (cadr mask) t)
value-var)
(t (check-type (cadr mask) bit)
(cadr mask)))))
(:TOGGLE
``(setf (sbit (the ,',type
,flags) ,,(car mask))
(if (zerop (sbit (the ,',type
,flags) ,,(car mask)))
1 0)))))))
(setf (sbit (the ,',type ,flags) ,,counter)
,,value-var)))
into result
finally
(return
`(progn ,@ result
;; When the print-function was supplied create a
;; function that will pretty print the status of
;; a given bitvector - for easier debugging.
,@ (when print-function
`((defun ,print-function
,(if print-function-parameters
`(&optional (flags ,print-function-parameters)
(stream *standard-output*))
'(flags &optional (stream *standard-output*)))
(check-type flags ,type)
(fresh-line stream)
(write-string
,(concatenate 'string
";; Status of "
(string-downcase (symbol-name
(car name/options)))
":")
stream)
,@(mapcar
#'(lambda (field)
(let ((name (symbol-name (car field)))
(bit-position (cdr field)))
`(format
stream
,(concatenate 'string
"~%;; ~"
(princ-to-string max-field-size)
"<"
(string-downcase name)
":~;~[nil~;t ~]~>")
(sbit flags ,bit-position))))
field-masks))))
;; When the value of reset-function is non-nil
;; create a function that will set an existing
;; bit-vector to it's original state.
,@ (when reset-function
`((defun ,reset-function (flags)
,(if type-check
`(check-type flags ,type)
`(declare ,@ optimizations
(type ,type flags)))
,@ (mapcar
#'(lambda (field)
(let ((field-name (car field))
(value (or (cadr
(l-memq :initial-element
(cdr field)))
initial-element)))
`(setf (sbit (the ,type flags)
,(cdr (l-assq field-name field-masks)))
,value)))
bit-fields)
flags)))
;; Finally the constructor
(defun ,constructor-name
,(or constructor-parameters
`(&key ,@(mapcar
#'(lambda (field)
(list field
(or (cadr (member :initial-element
(assoc field bit-fields)))
initial-element)))
(mapcar #'car bit-fields))))
,. documentation
(the ,type
(make-array ,(1+ counter)
:element-type 'bit
:initial-contents (list ,@(mapcar #'car bit-fields))
)))))))))


Click here to read the complete articleAttachments: /home/steve/common-lisp/bitfields/bitfields.lisp (message/external-body)
Re: MACRO: define-bitflags

<m3h7gge0nb.fsf@leonis4.robolove.meer.net>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=16647&group=comp.lang.lisp#16647

  copy link   Newsgroups: comp.lang.lisp
Path: i2pn2.org!i2pn.org!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail
From: enometh@meer.net (Madhu)
Newsgroups: comp.lang.lisp
Subject: Re: MACRO: define-bitflags
Date: Tue, 27 Jul 2021 11:52:48 +0530
Organization: Motzarella
Lines: 119
Message-ID: <m3h7gge0nb.fsf@leonis4.robolove.meer.net>
References: <84sg03zscs.fsf@loft.i-did-not-set--mail-host-address--so-tickle-me>
Mime-Version: 1.0
Content-Type: text/plain
Injection-Info: reader02.eternal-september.org; posting-host="b0a98f130d940da871a3998ff7c939e3";
logging-data="23494"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18JxUYA1f476zQIkuW1SfyIsyfCocpO4rc="
Cancel-Lock: sha1:9enVWbJo7IpXIbuIO0PcCVohF0g=
sha1:yc9+WElEkxrSGpkILqWzJ6VRTPs=
 by: Madhu - Tue, 27 Jul 2021 06:22 UTC

* 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


devel / comp.lang.lisp / Re: MACRO: define-bitflags

1
server_pubkey.txt

rocksolid light 0.9.81
clearnet tor