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