diff --git a/collects/data/bit-vector.rkt b/collects/data/bit-vector.rkt index a0cd7c8226..3c4a69b14a 100644 --- a/collects/data/bit-vector.rkt +++ b/collects/data/bit-vector.rkt @@ -27,24 +27,27 @@ (fxvector-set! words q (- (expt 2 r) 1))) (bit-vector words size word-size)) -(define (bit-vector* . init-bits) - (define bv (make-bit-vector (length init-bits))) - (for ([i (in-naturals)] - [b (in-list init-bits)]) - (bit-vector-set! bv i b)) - bv) +(define bit-vector* + (let ([bit-vector + (lambda init-bits + (list->bit-vector init-bits))]) + bit-vector)) -(define (bit-vector-ref bv n - [default (bad-index-error 'bit-vector-ref n)]) +(define not-given (gensym)) + +(define (bit-vector-ref bv n [default not-given]) (unless (exact-nonnegative-integer? n) - (raise-type-error 'bit-vector-ref "exact nonnegative integer" n)) - (cond - [(>= n (bit-vector-size bv)) - (if (procedure? default) - (default) - default)] - [else - (unsafe-bit-vector-ref bv n)])) + (raise-argument-error 'bit-vector-ref "exact-nonnegative-integer?" n)) + (cond [(< n (bit-vector-size bv)) + (unsafe-bit-vector-ref bv n)] + [else + (cond [(eq? default not-given) + (raise-range-error 'bit-vector-ref + "bit-vector" + "" n bv 0 (sub1 (bit-vector-size bv)))] + [(procedure? default) + (default)] + [else default])])) (define (unsafe-bit-vector-ref bv n) (define-values (wi bi) (quotient/remainder n bits-in-a-word)) @@ -97,6 +100,37 @@ (for/sum ([fx (in-fxvector (bit-vector-words bv))]) (fxpopcount fx))) +(define (bit-vector->list bv) + (define len (bit-vector-size bv)) + (let loop ([i 0]) + (cond [(< i len) + (cons (unsafe-bit-vector-ref bv i) + (loop (add1 i)))] + [else null]))) + +(define (list->bit-vector init-bits) + (define len (length init-bits)) + (define bv (make-bit-vector len)) + (for ([i (in-range len)] + [b (in-list init-bits)]) + (bit-vector-set! bv i b)) + bv) + +(define (bit-vector->string bv) + (let* ([l (bit-vector-size bv)] + [s (make-string l)]) + (for ([i (in-range l)]) + (string-set! s i (if (unsafe-bit-vector-ref bv i) #\1 #\0))) + s)) + +(define (string->bit-vector s) + (let* ([bv (make-bit-vector (string-length s) #f)]) + (for ([i (in-range (string-length s))]) + (when (eqv? (string-ref s i) #\1) + (bit-vector-set! bv i #t))) + bv)) + + (define-vector-wraps "bit-vector" bit-vector? bit-vector-length bit-vector-ref bit-vector-set! make-bit-vector unsafe-bit-vector-ref bit-vector-set! bit-vector-length @@ -171,6 +205,14 @@ (-> bit-vector? any)] (rename bit-vector-copy* bit-vector-copy - (-> bit-vector? bit-vector?))) + (-> bit-vector? bit-vector?)) + [bit-vector->list + (-> bit-vector? (listof boolean?))] + [list->bit-vector + (-> (listof boolean?) bit-vector?)] + [bit-vector->string + (-> bit-vector? string?)] + [string->bit-vector + (-> (and/c string? #rx"^[01]*$") bit-vector?)]) (provide in-bit-vector for/bit-vector for*/bit-vector) diff --git a/collects/data/scribblings/bit-vector.scrbl b/collects/data/scribblings/bit-vector.scrbl index 7cc0efffe8..32bf6919ef 100644 --- a/collects/data/scribblings/bit-vector.scrbl +++ b/collects/data/scribblings/bit-vector.scrbl @@ -32,17 +32,19 @@ Creates a new bit-vector of size @racket[size]. All elements are initialized to @racket[fill]. @examples[#:eval the-eval -(define bv (make-bit-vector 3)) -(bit-vector-ref bv 1)] +(bit-vector-ref (make-bit-vector 3) 2) +(bit-vector-ref (make-bit-vector 3 #t) 2) +] } @defproc[(bit-vector [elem boolean?] ...) bit-vector?]{ Creates a new bit-vector containing each @racket[elem] in order. + @examples[#:eval the-eval -(define bv (bit-vector #f #t #f)) -(bit-vector-ref bv 1)] +(bit-vector-ref (bit-vector #f #t #f) 1) +] } @defproc[(bit-vector? [v any/c]) boolean?]{ @@ -56,8 +58,13 @@ Returns @racket[#t] if @racket[v] is a bit-vector, @racket[#f] otherwise. any/c]{ Returns the element at index @racket[index], if @racket[index] is less -than @racket[(bit-vector-length gv)]. Otherwise, @racket[default] is +than @racket[(bit-vector-length bv)]. Otherwise, @racket[default] is invoked if it is a procedure, returned otherwise. + +@examples[#:eval the-eval +(bit-vector-ref (bit-vector #f #t) 1) +(bit-vector-ref (bit-vector #f #t) 5 'not-there) +] } @defproc[(bit-vector-set! @@ -68,9 +75,13 @@ invoked if it is a procedure, returned otherwise. void?]{ Sets the value at index @racket[index] to be @racket[value]. + @examples[#:eval the-eval -(define bv (bit-vector #f #t #f)) -(bit-vector-ref bv 1)] +(define bv (bit-vector #f #t)) +(bit-vector-ref bv 0) +(bit-vector-set! bv 0 #t) +(bit-vector-ref bv 0) +] } @defproc[(bit-vector-length [bv bit-vector?]) @@ -83,6 +94,7 @@ Returns the number of items in the bit-vector @racket[bv]. exact-nonnegative-integer?]{ Returns the number of set bits in the bit-vector @racket[bv]. + @examples[#:eval the-eval (bit-vector-popcount (bit-vector #f #t #t))] } @@ -103,10 +115,9 @@ to @racket[end] (exclusive). Returns a sequence whose elements are the elements of the bit-vector @racket[bv]. Mutation of @racket[bv] while the sequence is running changes the elements produced by the sequence. To obtain a sequence -from a snapshot of @racket[gv], use @racket[(in-vector +from a snapshot of @racket[bv], use @racket[(in-bit-vector (bit-vector-copy bv))] instead. - @examples[#:eval the-eval (define bv (bit-vector #f #t #f)) (for/list ([x (in-bit-vector bv)]) x)] @@ -133,11 +144,13 @@ the value of @racket[fill-expr], which defaults to @racket[#f] (i.e., the default argument of @racket[make-bit-vector]). @examples[#:eval the-eval -(define (to-list bv) (for/list ([x bv]) x)) -(to-list (for/bit-vector ([i '(1 2 3)]) (odd? i))) -(to-list (for/bit-vector #:length 2 ([i '(1 2 3)]) (odd? i))) -(to-list (for/bit-vector #:length 4 ([i '(1 2 3)]) (odd? i))) -(to-list +(bit-vector->list + (for/bit-vector ([i '(1 2 3)]) (odd? i))) +(bit-vector->list + (for/bit-vector #:length 2 ([i '(1 2 3)]) (odd? i))) +(bit-vector->list + (for/bit-vector #:length 4 ([i '(1 2 3)]) (odd? i))) +(bit-vector->list (for/bit-vector #:length 4 #:fill #t ([i '(1 2 3)]) (odd? i))) ] @@ -152,4 +165,20 @@ mutate a shared bit-vector.} Like @racket[for/bit-vector] but with the implicit nesting of @racket[for*]. } +@deftogether[[ +@defproc[(bit-vector->list [bv bit-vector?]) (listof boolean?)] +@defproc[(list->bit-vector [bits (listof boolean?)]) bit-vector?] +@defproc[(bit-vector->string [bv bit-vector?]) (and/c string? #rx"^[01]*$")] +@defproc[(string->bit-vector [s (and/c string? #rx"^[01]*$")]) bit-vector?] +]]{ + +Converts between bit-vectors and their representations as lists and +strings. + +@examples[#:eval the-eval +(bit-vector->list (string->bit-vector "100111")) +(bit-vector->string (list->bit-vector '(#t #f #t #t))) +] +} + @close-eval[the-eval] diff --git a/collects/tests/data/bit-vector.rkt b/collects/tests/data/bit-vector.rkt index cd70a85a8c..021f59c79c 100644 --- a/collects/tests/data/bit-vector.rkt +++ b/collects/tests/data/bit-vector.rkt @@ -114,3 +114,13 @@ (for ([ws (in-list '(8 30 62))]) (for ([i (in-range 10)]) (test (* ws 10)))))) + +(test-case "bit-vector string->list" + (let ([bitstrings '("0" "1" "10" "11" "1010110011100011110000")]) + (for ([s (in-list bitstrings)]) + (check-equal? (bit-vector->string (string->bit-vector s)) s) + (let ([bitlist (for/list ([c (in-string s)]) (eqv? c #\1))]) + (check-equal? (bit-vector->list (string->bit-vector s)) + bitlist) + (check-equal? (string->bit-vector s) + (list->bit-vector bitlist))))))