Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

simple riddle about macro

Name: Anonymous 2011-05-18 16:01

Bellow is a macro from Perl source code (perl.h).

# define _swab_32_(x) ((U32)( \
         (((U32)(x) & U32_CONST(0x000000ff)) << 24) | \
         (((U32)(x) & U32_CONST(0x0000ff00)) <<  8) | \
         (((U32)(x) & U32_CONST(0x00ff0000)) >>  8) | \
         (((U32)(x) & U32_CONST(0xff000000)) >> 24) ))


Provide at least 3 ideas, how this may be reused in other projects.

Name: Anonymous 2011-05-19 9:29

>>28
If you insist. I didn't have any handy code which does actual byteswapping as the data was read in in the proper endianess in the first place without requiring further swapping, but as the task itself is easy, I wrote this code to illustrate how to implement such a thing:

;;; Utilities

(defmacro with-gensyms ((&rest names) &body body)
  `(let ,(loop for name in names collect `(,name (gensym ,(string name))))
     ,@body))

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defun symbolicate (syms &optional (package *package*))
    (intern (apply #'concatenate 'string (mapcar #'string syms)) package)))

;;; Implementation

(defmacro define-byte-swapper
    (name &key (byte-count 4) (byte-size 8))  
  (with-gensyms (int)
    `(progn
       (declaim (inline ,name))
       (defun ,name (,int)
         (logior
          ,@(loop for i from 0 below byte-count collect                   
                  `(ash
                    (logand
                     ,(ash (1- (ash 1 byte-size)) (* i byte-size)) ,int)
                    ,(* byte-size (- (1- byte-count) (* i 2))))))))))

(defmacro define-byte-swappers (&key (up-to-powers-of-2-bytes 5)
                                  (byte-size 8))
  `(progn ,@(loop for i from 1 to up-to-powers-of-2-bytes collect
                  `(define-byte-swapper
                       ,(symbolicate
                         `(bswap ,(format nil "~D" (* byte-size (ash 1 i)))))
                       :byte-count ,(ash 1 i)))))

;; defines bswap16 to bswap256
(define-byte-swappers)


;;; Test

(setf *print-base* 16 *print-radix* t)
(values (bswap16 #x1122) (bswap32 #x11223344) (bswap64 #x1122334455667788) (bswap128 #x1122334455667788AABBCCDDEEFF1234) (bswap256 #x1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF)) ; =>
#x2211
#x44332211
#x8877665544332211
#x3412FFEEDDCCBBAA8877665544332211
#xEFCDAB9078563412EFCDAB9078563412EFCDAB9078563412EFCDAB9078563412


If this were not meant to be an example, some of those defmacro's would be written as macrolet's and the inner defun may be written as a compiler macro or as a macro (if support for old implementation which can't inline is to be considered), but the difference in the implementation is too small to be worth showing, so only this inlining version is shown.

Name: >>29 2011-05-19 9:41

Also to show some alternate uses of the same code. Let's say you don't have 8bit bytes, or you want to reverse a string of arbitrary bits, you can do it just as well using this:

CL-USER> (setf *print-base* 2 *print-radix* t)
T
CL-USER> (define-byte-swapper bswap8bits :byte-count 8 :byte-size 1)
BSWAP8BITS
CL-USER> (bswap8bits #b11001010)
#b1010011

It truly shows that you only have to write code once and use anywhere. The exception to this rule is when you can find a much better way to optimize a specific case and you need that speed.

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List