CMU CL's parse-integer has cleverness for parsing bignums relatively
quickly. It's not as scary as Catacomb, but not bad. Use it instead of
the grotty hack we had previously.
Returns two values: the integer parsed (or nil if there wasn't enough for a
sensible parse), and the index following the characters of the integer."
(unless end (setf end (length string)))
Returns two values: the integer parsed (or nil if there wasn't enough for a
sensible parse), and the index following the characters of the integer."
(unless end (setf end (length string)))
- (labels ((simple (a i r goodp sgn)
- (loop
- (when (>= i end)
- (return (values (and goodp (* a sgn)) i)))
- (let ((d (digit-char-p (char string i) r)))
- (unless d
- (return (values (and goodp (* a sgn)) i)))
- (setf a (+ (* a r) d))
- (setf goodp t)
- (incf i))))
+ (labels ((simple (i r goodp sgn)
+ (multiple-value-bind
+ (a i)
+ (if (and (< i end)
+ (digit-char-p (char string i) r))
+ (parse-integer string
+ :start i :end end
+ :radix r
+ :junk-allowed t)
+ (values nil i))
+ (values (if a (* sgn a) (and goodp 0)) i)))
- (cond (r (simple 0 i r nil sgn))
+ (cond (r (simple i r nil sgn))
((>= i end) (values nil i))
((and (char= (char string i) #\0)
(>= (- end i) 2))
(case (char string (1+ i))
((>= i end) (values nil i))
((and (char= (char string i) #\0)
(>= (- end i) 2))
(case (char string (1+ i))
- (#\x (simple 0 (+ i 2) 16 nil sgn))
- (#\o (simple 0 (+ i 2) 8 nil sgn))
- (#\b (simple 0 (+ i 2) 2 nil sgn))
- (t (simple 0 (1+ i) 8 t sgn))))
+ (#\x (simple (+ i 2) 16 nil sgn))
+ (#\o (simple (+ i 2) 8 nil sgn))
+ (#\b (simple (+ i 2) 2 nil sgn))
+ (t (simple (1+ i) 8 t sgn))))
- (r i)
- (simple 0 i 10 nil +1)
+ (r i)
+ (simple i 10 nil +1)
(cond ((not r) (values nil i))
((and (< i end)
(char= (char string i) #\_)
(<= 2 r 36))
(cond ((not r) (values nil i))
((and (< i end)
(char= (char string i) #\_)
(<= 2 r 36))
- (simple 0 (1+ i) r nil sgn))
+ (simple (1+ i) r nil sgn))
(t
(values (* r sgn) i))))))))
(cond ((>= start end) (values nil start))
(t
(values (* r sgn) i))))))))
(cond ((>= start end) (values nil start))