ikarus/src/ikarus.bytevectors.ss

523 lines
22 KiB
Scheme
Raw Normal View History

(library (ikarus bytevectors)
(export make-bytevector bytevector-length bytevector-s8-ref
bytevector-u8-ref bytevector-u8-set! bytevector-s8-set!
bytevector-copy! u8-list->bytevector bytevector->u8-list
bytevector-fill! bytevector-copy bytevector=?
bytevector-uint-ref bytevector-sint-ref
2007-05-16 11:05:06 -04:00
bytevector-uint-set! bytevector-sint-set!
bytevector->uint-list bytevector->sint-list)
(import
(except (ikarus)
make-bytevector bytevector-length bytevector-s8-ref
bytevector-u8-ref bytevector-u8-set! bytevector-s8-set!
bytevector-copy! u8-list->bytevector bytevector->u8-list
bytevector-fill! bytevector-copy bytevector=?
bytevector-uint-ref bytevector-sint-ref
2007-05-16 11:05:06 -04:00
bytevector-uint-set! bytevector-sint-set!
bytevector->uint-list bytevector->sint-list)
(ikarus system $fx)
2007-05-16 11:05:06 -04:00
(ikarus system $bignums)
(ikarus system $pairs)
(ikarus system $bytevectors))
(define ($bytevector-fill x i j fill)
(cond
[($fx= i j) x]
[else
($bytevector-set! x i fill)
($bytevector-fill x ($fxadd1 i) j fill)]))
(define make-bytevector
(case-lambda
[(k)
(if (and (fixnum? k) ($fx>= k 0))
($make-bytevector k)
(error 'make-bytevector "~s is not a valid size" k))]
[(k fill)
(if (and (fixnum? fill) ($fx<= -128 fill) ($fx<= fill 255))
($bytevector-fill (make-bytevector k) 0 k fill)
(error 'make-bytevector "~s is not a valid fill" fill))]))
(define bytevector-fill!
(lambda (x fill)
(unless (bytevector? x)
(error 'bytevector-fill! "~s is not a bytevector" x))
(unless (and (fixnum? fill) ($fx<= -128 fill) ($fx<= fill 255))
(error 'bytevector-fill! "~s is not a valid fill" fill))
($bytevector-fill x 0 ($bytevector-length x) fill)))
(define bytevector-length
(lambda (x)
(if (bytevector? x)
($bytevector-length x)
(error 'bytevector-length "~s is not a bytevector" x))))
(define bytevector-s8-ref
(lambda (x i)
(if (bytevector? x)
(if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($bytevector-length x)))
($bytevector-s8-ref x i)
(error 'bytevector-s8-ref "invalid index ~s for ~s" i x))
(error 'bytevector-s8-ref "~s is not a bytevector" x))))
(define bytevector-u8-ref
(lambda (x i)
(if (bytevector? x)
(if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($bytevector-length x)))
($bytevector-u8-ref x i)
(error 'bytevector-u8-ref "invalid index ~s for ~s" i x))
(error 'bytevector-u8-ref "~s is not a bytevector" x))))
(define bytevector-s8-set!
(lambda (x i v)
(if (bytevector? x)
(if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($bytevector-length x)))
(if (and (fixnum? v) ($fx<= -128 v) ($fx<= v 127))
($bytevector-set! x i v)
(error 'bytevector-s8-set! "~s is not a byte" v))
(error 'bytevector-s8-set! "invalid index ~s for ~s" i x))
(error 'bytevector-s8-set! "~s is not a bytevector" x))))
(define bytevector-u8-set!
(lambda (x i v)
(if (bytevector? x)
(if (and (fixnum? i) ($fx<= 0 i) ($fx< i ($bytevector-length x)))
(if (and (fixnum? v) ($fx<= 0 v) ($fx<= v 255))
($bytevector-set! x i v)
(error 'bytevector-u8-set! "~s is not an octet" v))
(error 'bytevector-u8-set! "invalid index ~s for ~s" i x))
(error 'bytevector-u8-set! "~s is not a bytevector" x))))
(define bytevector->u8-list
(lambda (x)
(unless (bytevector? x)
(error 'bytevector->u8-list "~s is not a bytevector" x))
(let f ([x x] [i ($bytevector-length x)] [ac '()])
(cond
[($fx= i 0) ac]
[else
(let ([i ($fxsub1 i)])
(f x i (cons ($bytevector-u8-ref x i) ac)))]))))
(define u8-list->bytevector
(letrec ([race
(lambda (h t ls n)
(if (pair? h)
(let ([h ($cdr h)])
(if (pair? h)
(if (not (eq? h t))
(race ($cdr h) ($cdr t) ls ($fx+ n 2))
(error 'u8-list->bytevector "circular list ~s" ls))
(if (null? h)
($fx+ n 1)
(error 'u8-list->bytevector "~s is not a proper list" ls))))
(if (null? h)
n
(error 'u8-list->bytevector "~s is not a proper list" ls))))]
[fill
(lambda (s i ls)
(cond
[(null? ls) s]
[else
(let ([c ($car ls)])
(unless (and (fixnum? c) ($fx<= 0 c) ($fx<= c 255))
(error 'u8-list->bytevector "~s is not an octet" c))
($bytevector-set! s i c)
(fill s ($fxadd1 i) (cdr ls)))]))])
(lambda (ls)
(let ([n (race ls ls ls 0)])
(let ([s ($make-bytevector n)])
(fill s 0 ls))))))
(define bytevector-copy
(lambda (src)
(unless (bytevector? src)
(error 'bytevector-copy "~s is not a bytevector" src))
(let ([n ($bytevector-length src)])
(let f ([src src] [dst ($make-bytevector n)] [i 0] [n n])
(cond
[($fx= i n) dst]
[else
($bytevector-set! dst i ($bytevector-u8-ref src i))
(f src dst ($fxadd1 i) n)])))))
2007-05-15 14:37:04 -04:00
(define bytevector=?
(lambda (x y)
(unless (bytevector? x)
(error 'bytevector=? "~s is not a bytevector" x))
(unless (bytevector? y)
(error 'bytevector=? "~s is not a bytevector" y))
(let ([n ($bytevector-length x)])
(and ($fx= n ($bytevector-length y))
(let f ([x x] [y y] [i 0] [n n])
(or ($fx= i n)
(and ($fx= ($bytevector-u8-ref x i)
($bytevector-u8-ref y i))
(f x y ($fxadd1 i) n))))))))
(define bytevector-copy!
(lambda (src src-start dst dst-start k)
(cond
[(or (not (fixnum? src-start)) ($fx< src-start 0))
(error 'bytevector-copy! "~s is not a valid starting index" src-start)]
[(or (not (fixnum? dst-start)) ($fx< dst-start 0))
(error 'bytevector-copy! "~s is not a valid starting index" dst-start)]
[(or (not (fixnum? k)) ($fx< k 0))
(error 'bytevector-copy! "~s is not a valid length" k)]
[(not (bytevector? src))
(error 'bytevector-copy! "~s is not a bytevector" src)]
[(not (bytevector? dst))
(error 'bytevector-copy! "~s is not a bytevector" dst)]
[(let ([n ($fx+ src-start k)])
(or ($fx< n 0) ($fx>= n ($bytevector-length src))))
(error 'bytevector-copy! "~s+~s is out of range" src-start k)]
[(let ([n ($fx+ dst-start k)])
(or ($fx< n 0) ($fx>= n ($bytevector-length dst))))
(error 'bytevector-copy! "~s+~s is out of range" dst-start k)]
[(eq? src dst)
(cond
[($fx< dst-start src-start)
(let f ([src src] [si src-start] [di dst-start] [sj ($fx+ src-start k)])
(unless ($fx= si sj)
($bytevector-set! src di ($bytevector-u8-ref src si))
(f src ($fxadd1 si) ($fxadd1 di) sj)))]
[($fx< src-start dst-start)
(let f ([src src] [si ($fx+ src-start k)] [di ($fx+ dst-start k)] [sj src-start])
(unless ($fx= si sj)
(let ([si ($fxsub1 si)] [di ($fxsub1 di)])
($bytevector-set! src di ($bytevector-u8-ref src si))
(f src si di sj))))]
[else (void)])]
[else
(let f ([src src] [si src-start] [dst dst] [di dst-start] [sj ($fx+ src-start k)])
(unless ($fx= si sj)
($bytevector-set! dst di ($bytevector-u8-ref src si))
(f src ($fxadd1 si) dst ($fxadd1 di) sj)))])))
(module (bytevector-uint-ref bytevector-sint-ref
bytevector->uint-list bytevector->sint-list)
(define (uref-big x ib il) ;; ib included, il excluded
(cond
[($fx= il ib) 0]
[else
(let ([b ($bytevector-u8-ref x ib)])
(cond
[($fx= b 0) (uref-big x ($fxadd1 ib) il)]
[else
(case ($fx- il ib)
[(1) b]
[(2) ($fx+ ($fxsll b 8)
($bytevector-u8-ref x ($fxsub1 il)))]
[(3)
($fx+ ($fxsll ($fx+ ($fxsll b 8)
($bytevector-u8-ref x ($fxadd1 ib)))
8)
($bytevector-u8-ref x ($fxsub1 il)))]
[else
(let ([im ($fxsra ($fx+ il ib) 1)])
(+ (uref-big x im il)
(* (uref-big x ib im)
(expt 256 ($fx- il im)))))])]))]))
(define (uref-little x il ib) ;; il included, ib excluded
(cond
[($fx= il ib) 0]
[else
(let ([ib^ ($fxsub1 ib)])
(let ([b ($bytevector-u8-ref x ib^)])
(cond
[($fx= b 0) (uref-little x il ib^)]
[else
(case ($fx- ib il)
[(1) b]
[(2) ($fx+ ($fxsll b 8) ($bytevector-u8-ref x il))]
[(3)
($fx+ ($fxsll ($fx+ ($fxsll b 8)
($bytevector-u8-ref x ($fxadd1 il)))
8)
($bytevector-u8-ref x il))]
[else
(let ([im ($fxsra ($fx+ il ib) 1)])
(+ (uref-little x il im)
(* (uref-little x im ib)
(expt 256 ($fx- im il)))))])])))]))
(define (sref-big x ib il) ;; ib included, il excluded
(cond
[($fx= il ib) -1]
[else
(let ([b ($bytevector-u8-ref x ib)])
(cond
[($fx= b 0) (uref-big x ($fxadd1 ib) il)]
[($fx= b 255) (sref-big-neg x ($fxadd1 ib) il)]
[($fx< b 128) (uref-big x ib il)]
[else (- (uref-big x ib il) (expt 256 ($fx- il ib)))]))]))
(define (sref-big-neg x ib il) ;; ib included, il excluded
(cond
[($fx= il ib) -1]
[else
(let ([b ($bytevector-u8-ref x ib)])
(cond
[($fx= b 255) (sref-big-neg x ($fxadd1 ib) il)]
[else (- (uref-big x ib il) (expt 256 ($fx- il ib)))]))]))
(define (sref-little x il ib) ;; il included, ib excluded
(cond
[($fx= il ib) -1]
[else
(let ([ib^ ($fxsub1 ib)])
(let ([b ($bytevector-u8-ref x ib^)])
(cond
[($fx= b 0) (uref-little x il ib^)]
[($fx= b 255) (sref-little-neg x il ib^)]
[($fx< b 128) (uref-little x il ib)]
[else (- (uref-little x il ib) (expt 256 ($fx- ib il)))])))]))
(define (sref-little-neg x il ib) ;; il included, ib excluded
(cond
[($fx= il ib) -1]
[else
(let ([ib^ ($fxsub1 ib)])
(let ([b ($bytevector-u8-ref x ib^)])
(cond
[($fx= b 255) (sref-little-neg x il ib^)]
[else (- (uref-little x il ib) (expt 256 ($fx- ib il)))])))]))
(define bytevector-sint-ref
(lambda (x k endianness size)
(define who 'bytevector-sint-ref)
(unless (bytevector? x) (error who "~s is not a bytevector" x))
(unless (and (fixnum? k) ($fx>= k 0)) (error who "invalid index ~s" k))
(unless (and (fixnum? size) ($fx>= size 1)) (error who "invalid size ~s" size))
(let ([n ($bytevector-length x)])
(unless ($fx< k n) (error who "index ~s is out of range" k))
(let ([end ($fx+ k size)])
(unless (and ($fx>= end 0) ($fx<= end n))
(error who "~s+~s is out of range" k size))
(case endianness
[(little) (sref-little x k end)]
[(big) (sref-big x k end)]
[else (error who "invalid endianness ~s" endianness)])))))
(define bytevector-uint-ref
(lambda (x k endianness size)
(define who 'bytevector-uint-ref)
(unless (bytevector? x) (error who "~s is not a bytevector" x))
(unless (and (fixnum? k) ($fx>= k 0)) (error who "invalid index ~s" k))
(unless (and (fixnum? size) ($fx>= size 1)) (error who "invalid size ~s" size))
(let ([n ($bytevector-length x)])
(unless ($fx< k n) (error who "index ~s is out of range" k))
(let ([end ($fx+ k size)])
(unless (and ($fx>= end 0) ($fx<= end n))
(error who "~s+~s is out of range" k size))
(case endianness
[(little) (uref-little x k end)]
[(big) (uref-big x k end)]
[else (error who "invalid endianness ~s" endianness)])))))
(define (bytevector->some-list x k n ls proc who)
(cond
[($fx= n 0) ls]
[else
(let ([i ($fx- n k)])
(cond
[($fx>= i 0)
(bytevector->some-list x k i (cons (proc x i n) ls) proc who)]
[else
(error who "invalid size ~s" k)]))]))
(define bytevector->uint-list
(lambda (x endianness size)
(define who 'bytevector->uint-list)
(unless (bytevector? x) (error who "~s is not a bytevector" x))
(unless (and (fixnum? size) ($fx>= size 1)) (error who "invalid size ~s" size))
(case endianness
[(little) (bytevector->some-list x size ($bytevector-length x)
'() uref-little 'bytevector->uint-list)]
[(big) (bytevector->some-list x size ($bytevector-length x)
'() uref-big 'bytevector->uint-list)]
[else (error who "invalid endianness ~s" endianness)])))
(define bytevector->sint-list
(lambda (x endianness size)
(define who 'bytevector->sint-list)
(unless (bytevector? x) (error who "~s is not a bytevector" x))
(unless (and (fixnum? size) ($fx>= size 1)) (error who "invalid size ~s" size))
(case endianness
[(little) (bytevector->some-list x size ($bytevector-length x)
'() sref-little 'bytevector->sint-list)]
[(big) (bytevector->some-list x size ($bytevector-length x)
'() sref-big 'bytevector->sint-list)]
2007-05-15 20:19:24 -04:00
[else (error who "invalid endianness ~s" endianness)]))))
2007-05-16 11:05:06 -04:00
(module (bytevector-uint-set! bytevector-sint-set!)
(define (lufx-set! x k1 n k2 who no)
2007-05-15 20:19:24 -04:00
(cond
2007-05-16 11:05:06 -04:00
[($fx= k1 k2)
(unless ($fxzero? n)
(error who "number ~s does not fit" no))]
2007-05-15 20:19:24 -04:00
[else
2007-05-16 11:05:06 -04:00
(lufx-set! x ($fxadd1 k1) ($fxsra n 8) k2 who no)
($bytevector-set! x k1 ($fxlogand n 255))]))
(define (lsfx-set! x k1 n k2 who no)
2007-05-15 20:19:24 -04:00
(cond
2007-05-16 11:05:06 -04:00
[($fx= k1 k2)
(unless ($fx= n -1) ;;; BUG: does not catch all errors
(error who "number ~s does not fit" no))]
2007-05-15 20:19:24 -04:00
[else
2007-05-16 11:05:06 -04:00
(lsfx-set! x ($fxadd1 k1) ($fxsra n 8) k2 who no)
($bytevector-set! x k1 ($fxlogand n 255))]))
(define (bufx-set! x k1 n k2 who no)
(cond
[($fx= k1 k2)
(unless ($fxzero? n)
(error who "number ~s does not fit" no))]
[else
(let ([k2 ($fxsub1 k2)])
(bufx-set! x k1 ($fxsra n 8) k2 who no)
($bytevector-set! x k2 ($fxlogand n 255)))]))
(define (bsfx-set! x k1 n k2 who no)
(cond
[($fx= k1 k2)
(unless ($fx= n -1)
(error who "number ~s does not fit" no))]
[else
(let ([k2 ($fxsub1 k2)])
(bsfx-set! x k1 ($fxsra n 8) k2 who no)
($bytevector-set! x k2 ($fxlogand n 255)))]))
(define (lbn-copy! x k n i j)
(unless ($fx= i j)
($bytevector-set! x k ($bignum-byte-ref n i))
(lbn-copy! x ($fxadd1 k) n ($fxadd1 i) j)))
(define (bbn-copy! x k n i j)
(unless ($fx= i j)
(let ([k ($fxsub1 k)])
($bytevector-set! x k ($bignum-byte-ref n i))
(bbn-copy! x k n ($fxadd1 i) j))))
(define (bv-zero! x i j)
(unless ($fx= i j)
($bytevector-set! x i 0)
(bv-zero! x ($fxadd1 i) j)))
(define (lbn-neg-copy! x xi n ni xj nj c)
(cond
[($fx= ni nj)
(case ($fxsra c 7)
[(#x01) ;;; borrow is 0, last byte was negative
(bv-neg-zero! x xi xj)]
[(#x00) ;;; borrow is 0, last byte was positive
(if ($fx< xi xj)
(bv-neg-zero! x xi xj)
(error 'bytevector-sint-set! "number ~s does not fit" n))]
[else (error 'lbn-neg-copy! "BUG: not handled ~s" c)])]
[else
(let ([c ($fx- ($fx+ 255 ($fxsra c 8)) ($bignum-byte-ref n ni))])
(lbn-neg-copy! x ($fxadd1 xi) n ($fxadd1 ni) xj nj c)
($bytevector-set! x xi ($fxlogand c 255)))]))
(define (lbn-pos-copy! x xi n ni nj xj c)
(cond
[($fx= ni nj)
(cond
[(or ($fx<= c 127) ($fx< xi xj))
;;; last byte was positive
(bv-zero! x xi xj)]
[else
(error 'bytevector-sint-set! "number ~s does not fit" n)])]
[else
(let ([c ($bignum-byte-ref n ni)])
(lbn-pos-copy! x ($fxadd1 xi) n ($fxadd1 ni) nj xj c)
($bytevector-set! x xi ($fxlogand c 255)))]))
(define (bv-neg-zero! x i j)
(unless ($fx= i j)
($bytevector-set! x i 255)
(bv-neg-zero! x ($fxadd1 i) j)))
(define (bignum-bytes n)
(let ([i ($bignum-size n)])
(let ([i-1 ($fxsub1 i)])
(if ($fxzero? ($bignum-byte-ref n i-1))
(let ([i-2 ($fxsub1 i-1)])
(if ($fxzero? ($bignum-byte-ref n i-2))
(let ([i-3 ($fxsub1 i-2)])
(if ($fxzero? ($bignum-byte-ref n i-3))
(let ([i-4 ($fxsub1 i-3)])
(if ($fxzero? ($bignum-byte-ref n i-4))
(error 'bignum-bytes "BUG: malformed bignum")
i-3))
i-2))
i-1))
i))))
2007-05-15 20:19:24 -04:00
(define bytevector-uint-set!
(lambda (x k n endianness size)
(define who 'bytevector-uint-set!)
(unless (bytevector? x) (error who "~s is not a bytevector" x))
(unless (and (fixnum? k) ($fx>= k 0)) (error who "invalid index ~s" k))
(unless (and (fixnum? size) ($fx>= size 1)) (error who "invalid size ~s" size))
(case endianness
2007-05-16 11:05:06 -04:00
[(little)
(cond
[(fixnum? n) (lufx-set! x k n ($fx+ k size) who n)]
[(bignum? n)
(if ($bignum-positive? n)
(let ([sz (bignum-bytes n)])
(cond
[($fx= sz size)
(lbn-copy! x k n 0 sz)]
[($fx< sz size)
(lbn-copy! x k n 0 sz)
(bv-zero! x ($fx+ k sz) ($fx+ k size))]
[else (error who "number ~s does not fit" n)]))
(error who "value ~s must be positive" n))]
[else (error who "invalid value argument ~s" n)])]
[(big)
(cond
[(fixnum? n) (bufx-set! x k n ($fx+ k size) who n)]
[(bignum? n)
(if ($bignum-positive? n)
(let ([sz (bignum-bytes n)])
(cond
[($fx<= sz size)
(bbn-copy! x ($fx+ k size) n 0 sz)]
[($fx< sz size)
(bbn-copy! x ($fx+ k size) n 0 sz)
(bv-zero! x k ($fx+ k ($fx- size sz)))]
[else (error who "number ~s does not fit" n)]))
(error who "value ~s must be positive" n))]
[else (error who "invalid value argument ~s" n)])]
[else (error who "invalid endianness ~s" endianness)])))
(define bytevector-sint-set!
(lambda (x k n endianness size)
(define who 'bytevector-sint-set!)
(unless (bytevector? x) (error who "~s is not a bytevector" x))
(unless (and (fixnum? k) ($fx>= k 0)) (error who "invalid index ~s" k))
(unless (and (fixnum? size) ($fx>= size 1)) (error who "invalid size ~s" size))
(case endianness
[(little)
(cond
[(fixnum? n) (lsfx-set! x k n ($fx+ k size) who n)]
[(bignum? n)
(if ($bignum-positive? n)
(let ([sz (bignum-bytes n)])
(cond
[($fx<= sz size)
(lbn-pos-copy! x k n 0 size sz 255)]
[else (error who "number ~s does not fit" n)]))
(let ([sz (bignum-bytes n)])
(cond
[($fx<= sz size)
(lbn-neg-copy! x k n 0 size sz 256)]
[else (error who "number ~s does not fit" n)])))]
[else (error who "invalid value argument ~s" n)])]
[(big)
(cond
[(fixnum? n) (bsfx-set! x k n ($fx+ k size) who n)]
;[(bignum? n)
; (if ($bignum-positive? n)
; (let ([sz ($bignum-size n)])
; (cond
; [($fx<= sz size)
; (bbn-copy! x ($fx+ k size) n 0 sz)]
; [($fx< sz size)
; (bbn-copy! x ($fx+ k size) n 0 sz)
; (bv-zero! x k ($fx+ k ($fx- size sz)))]
; [else (error who "number ~s does not fit" n)]))
; (error who "value ~s must be positive" n))]
[else (error who "invalid value argument ~s" n)])]
2007-05-15 20:19:24 -04:00
[else (error who "invalid endianness ~s" endianness)]))))
)