Subject: Re: How to write portable bitwise operation code? (or how not to think like a c hacker)
From: rpw3@rpw3.org (Rob Warnock)
Date: Fri, 06 Apr 2007 22:37:34 -0500
Newsgroups: comp.lang.lisp
Message-ID: <5fudnQ5-KIdjjIrbnZ2dnUVZ_uygnZ2d@speakeasy.net>
Liu Fung Sin <fungsin.lui@gmail.com> wrote:
+---------------
| Coming from a C programming background, I have no problem writing this
| routine to check whether a number is a valid ipv4 netmask:
...[C code elided]...
| valid_netmask(0xffffff00) => 1
| 
| However, I can't do the same in common lisp. For instance, I can't
| assume the size of fixnum and that the result of lognot is not a
| unsigned 32bit integer.
+---------------

Try not thinking so much about C and unsigned-32 and look at the
math of what you're trying to do in general [see if the number is
a string of 1's followed by a string of 0's and nothing else] and
then see what's already in Common Lisp that will help you. E.g., I
think this might do what you want:

   > (defun valid-netmask-p (x &optional (addr-width 32))
       (and (plusp x)
	    (= (integer-length x) addr-width)
	    (let ((y (- (ash 1 addr-width) 1 x))) ; strip/cmpl 1st run of 1's
	      (= y (1- (ash 1 (integer-length y))))))) ; also a run of 1's?

   VALID-NETMASK-P
   > (mapcar 'valid-netmask-p '(#b11111111111111111111111111111111
				#b11111111111111111111111100000000
				#b11111111111111110000000000000000
				#b10000000000000000000000000000000
				#b11111101111111110000000000000000
				#b01111111111111110000000000000000
				#b11111111111111110001000000000000
				#b00000000000000000000000000000000
				))

    (T T T T NIL NIL NIL NIL)
    > 

You'll notice I generalized it just a wee bit:

    > (valid-netmask-p #b111111111111111110000000000000000000000000000000 48)

    T
    > (valid-netmask-p #xffffffffffffffffffff000000000000 128)

    T
    > (valid-netmask-p #xffffffffffffffffffff000001000000 128)

    NIL
    > 


-Rob

-----
Rob Warnock			<rpw3@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607