From 9de70551dcf0106c8d5494ccae5f173cd4457193 Mon Sep 17 00:00:00 2001 From: Greg Hendershott Date: Tue, 19 Aug 2014 23:05:51 -0400 Subject: [PATCH] Fix bug with equal? on small bit-vectors. --- .../data-test/tests/data/bit-vector.rkt | 30 +++++++++++++++++++ racket/collects/data/bit-vector.rkt | 24 ++++++++++----- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/pkgs/data-pkgs/data-test/tests/data/bit-vector.rkt b/pkgs/data-pkgs/data-test/tests/data/bit-vector.rkt index 021f59c79c..cad3112cdf 100644 --- a/pkgs/data-pkgs/data-test/tests/data/bit-vector.rkt +++ b/pkgs/data-pkgs/data-test/tests/data/bit-vector.rkt @@ -87,6 +87,36 @@ (eq-hash-code (bit-vector #t #f #t #f #t))) #f)) +(test-case "bit-vector, equal-proc (via equal?)" + ;; Zero length bit-vectors are equal... + (equal? (make-bit-vector 0 #t) + (make-bit-vector 0 #t)) + ;; ...even if fill value differed, because it's N/A + (equal? (make-bit-vector 0 #t) + (make-bit-vector 0 #f)) + ;; Check a range of bit lengths spanning a few 8-bit bytes: + (for ([len (in-range 1 24)]) + (check-equal? + (equal? (make-bit-vector len #t) + (make-bit-vector len #t)) + #t) + (check-equal? + (equal? (make-bit-vector len #t) + (make-bit-vector len #f)) + #f)) + ;; Attempt to flush out potential bugs wrt to unused bits + ;; that might be set by a "fill" value (implementation + ;; detail we don't know for sure here), but should + ;; definitely be ignored by equal?. + (let ([x (make-bit-vector 1 #t)] ;#t fill value + [y (make-bit-vector 1 #f)]) ;#f fill value + ;; Set the only bit to #t in both + (bit-vector-set! x 0 #t) + (bit-vector-set! y 0 #t) + ;; Should be equal, regardless of different fill values + ;; in make-bit-vector: + (check-equal? (equal? x y) #t))) + (test-case "for/bit-vector" (check-equal? (for/bit-vector ([i 5]) (odd? i)) (bit-vector #f #t #f #t #f)) diff --git a/racket/collects/data/bit-vector.rkt b/racket/collects/data/bit-vector.rkt index 0f90c0a143..e0f9fc4b07 100644 --- a/racket/collects/data/bit-vector.rkt +++ b/racket/collects/data/bit-vector.rkt @@ -148,8 +148,7 @@ bit-vector-copy #f) -; A bit vector is represented as a vector of words. -; Each word contains 30 or 62 bits depending on the size of a fixnum. +;; A bit vector is represented as bytes. (serializable-struct bit-vector (words size) ; words is the bytes of words ; size is the number of bits in bitvector @@ -187,11 +186,22 @@ [nx (bit-vector-size x)] [ny (bit-vector-size y)]) (and (= nx ny) - (for/and ([index (in-range (- (bytes-length vx) 1))]) - (eq? (bytes-ref vx index) - (bytes-ref vy index))) - ; TODO: check last word - ))) + (or (zero? nx) ;zero-length bit-vectors are equal + (let ([last-index (sub1 (bytes-length vx))]) + (and + ;; Check all but last byte. + ;; These use all bits, therefore simple eq?. + (for/and ([index (in-range (sub1 last-index))]) + (eq? (bytes-ref vx index) + (bytes-ref vy index))) + ;; Check the used bits of the last byte. + (let ([used-bits (min 8 (remainder nx 256))]) + (eq? (bitwise-bit-field (bytes-ref vx last-index) + 0 + used-bits) + (bitwise-bit-field (bytes-ref vy last-index) + 0 + used-bits))))))))) (define (hash-code x hc) (let ([v (bit-vector-words x)] [n (bit-vector-size x)])