bitvec 1.1.1.0 → 1.1.2.0
raw patch · 24 files changed
+188/−67 lines, 24 filesdep +quickcheck-classes-basedep −ghc-primsetup-changedPVP ok
version bump matches the API change (PVP)
Dependencies added: quickcheck-classes-base
Dependencies removed: ghc-prim
API changes (from Hackage documentation)
Files
- README.md +1/−1
- Setup.lhs +0/−5
- bench/Bench.hs +1/−1
- bench/Bench/BitIndex.hs +1/−1
- bench/Bench/GCD.hs +1/−1
- bench/Bench/Intersection.hs +1/−1
- bench/Bench/Invert.hs +1/−1
- bench/Bench/Product.hs +1/−1
- bench/Bench/RandomFlip.hs +2/−2
- bench/Bench/RandomRead.hs +1/−1
- bench/Bench/RandomWrite.hs +2/−2
- bench/Bench/Remainder.hs +1/−1
- bench/Bench/Reverse.hs +1/−1
- bench/Bench/Sum.hs +2/−2
- bench/Bench/Union.hs +1/−1
- bitvec.cabal +10/−15
- changelog.md +6/−0
- src/Data/Bit/Immutable.hs +53/−2
- src/Data/Bit/Mutable.hs +21/−5
- test/Main.hs +7/−4
- test/Support.hs +16/−1
- test/Tests/F2Poly.hs +7/−4
- test/Tests/MVector.hs +8/−3
- test/Tests/Vector.hs +43/−11
README.md view
@@ -1,4 +1,4 @@-# bitvec [](https://github.com/Bodigrim/bitvec/actions?query=workflow%3Aci) [](https://travis-ci.com/Bodigrim/bitvec) [](https://hackage.haskell.org/package/bitvec) [](https://matrix.hackage.haskell.org/package/bitvec) [](http://stackage.org/lts/package/bitvec) [](http://stackage.org/nightly/package/bitvec) [](https://coveralls.io/github/Bodigrim/bitvec)+# bitvec [](https://hackage.haskell.org/package/bitvec) [](http://stackage.org/lts/package/bitvec) [](http://stackage.org/nightly/package/bitvec) A newtype over `Bool` with a better `Vector` instance: 8x less memory, up to 1000x faster.
− Setup.lhs
@@ -1,5 +0,0 @@-#!/usr/bin/env runhaskell--> import Distribution.Simple-> main = defaultMain-
bench/Bench.hs view
@@ -1,6 +1,6 @@ module Main where -import Gauge.Main+import Test.Tasty.Bench import Bench.BitIndex import Bench.GCD
bench/Bench/BitIndex.hs view
@@ -7,7 +7,7 @@ import Data.Bits import qualified Data.Vector.Unboxed as U import qualified Data.Vector.Unboxed.Mutable as MU-import Gauge.Main+import Test.Tasty.Bench randomVec :: MU.Unbox a => (Bool -> a) -> Int -> U.Vector a randomVec f k = U.generate n (\i -> f (i == n - 1))
bench/Bench/GCD.hs view
@@ -7,8 +7,8 @@ import Data.Bits import qualified Data.Vector.Unboxed as U import qualified Data.Vector.Unboxed.Mutable as MU-import Gauge.Main import System.Random+import Test.Tasty.Bench randomBools :: [Bool] randomBools = map (> (0 :: Int)) $ randoms $ mkStdGen 42
bench/Bench/Intersection.hs view
@@ -8,8 +8,8 @@ import qualified Data.IntSet as IS import qualified Data.Vector.Unboxed as U import qualified Data.Vector.Unboxed.Mutable as MU-import Gauge.Main import System.Random+import Test.Tasty.Bench randomBools :: [Bool] randomBools
bench/Bench/Invert.hs view
@@ -7,8 +7,8 @@ import Data.Bits import qualified Data.Vector.Unboxed as U import qualified Data.Vector.Unboxed.Mutable as MU-import Gauge.Main import System.Random+import Test.Tasty.Bench randomBools :: [Bool] randomBools
bench/Bench/Product.hs view
@@ -7,8 +7,8 @@ import Data.Bits import qualified Data.Vector.Unboxed as U import qualified Data.Vector.Unboxed.Mutable as MU-import Gauge.Main import System.Random+import Test.Tasty.Bench randomBools :: [Bool] randomBools
bench/Bench/RandomFlip.hs view
@@ -7,11 +7,11 @@ import Data.Bit import qualified Data.Bit.ThreadSafe as TS import Data.Bits+import Data.Foldable import qualified Data.IntSet as IS-import Data.List import qualified Data.Vector.Unboxed.Mutable as MU-import Gauge.Main import System.Random+import Test.Tasty.Bench randomFlips :: [Int] randomFlips
bench/Bench/RandomRead.hs view
@@ -10,8 +10,8 @@ -- import Data.List import qualified Data.Vector.Unboxed as U import qualified Data.Vector.Unboxed.Mutable as MU-import Gauge.Main import System.Random+import Test.Tasty.Bench randomVec :: [Bool] randomVec
bench/Bench/RandomWrite.hs view
@@ -7,11 +7,11 @@ import Data.Bit import qualified Data.Bit.ThreadSafe as TS import Data.Bits+import Data.Foldable import qualified Data.IntSet as IS-import Data.List import qualified Data.Vector.Unboxed.Mutable as MU-import Gauge.Main import System.Random+import Test.Tasty.Bench randomWrites :: [(Int, Bool)] randomWrites
bench/Bench/Remainder.hs view
@@ -10,7 +10,6 @@ import Data.Bits import qualified Data.Vector.Unboxed as U import qualified Data.Vector.Unboxed.Mutable as MU-import Gauge.Main import GHC.Exts #ifdef MIN_VERSION_ghc_bignum import GHC.Num.Integer@@ -18,6 +17,7 @@ import GHC.Integer.Logarithms #endif import System.Random+import Test.Tasty.Bench randomBools :: [Bool] randomBools
bench/Bench/Reverse.hs view
@@ -7,8 +7,8 @@ import Data.Bits import qualified Data.Vector.Unboxed as U import qualified Data.Vector.Unboxed.Mutable as MU-import Gauge.Main import System.Random+import Test.Tasty.Bench randomBools :: [Bool] randomBools
bench/Bench/Sum.hs view
@@ -5,11 +5,11 @@ import Data.Bit import qualified Data.Bit.ThreadSafe as TS import Data.Bits-import Data.List+import Data.Foldable import qualified Data.Vector.Unboxed as U import qualified Data.Vector.Unboxed.Mutable as MU-import Gauge.Main import System.Random+import Test.Tasty.Bench randomBools :: [Bool] randomBools
bench/Bench/Union.hs view
@@ -8,8 +8,8 @@ import qualified Data.IntSet as IS import qualified Data.Vector.Unboxed as U import qualified Data.Vector.Unboxed.Mutable as MU-import Gauge.Main import System.Random+import Test.Tasty.Bench randomBools :: [Bool] randomBools
bitvec.cabal view
@@ -1,10 +1,10 @@ name: bitvec-version: 1.1.1.0-cabal-version: 2.0+version: 1.1.2.0+cabal-version: >=1.10 build-type: Simple license: BSD3 license-file: LICENSE-copyright: 2019-2020 Andrew Lelechenko, 2012-2016 James Cook+copyright: 2019-2021 Andrew Lelechenko, 2012-2016 James Cook maintainer: Andrew Lelechenko <andrew.lelechenko@gmail.com> homepage: https://github.com/Bodigrim/bitvec synopsis: Space-efficient bit vectors@@ -46,7 +46,7 @@ author: Andrew Lelechenko <andrew.lelechenko@gmail.com>, James Cook <mokus@deepbondi.net> -tested-with: GHC ==8.0.2 GHC ==8.2.2 GHC ==8.4.4 GHC ==8.6.5 GHC ==8.8.1 GHC ==8.8.2 GHC ==8.8.4 GHC ==8.10.2+tested-with: GHC ==8.0.2 GHC ==8.2.2 GHC ==8.4.4 GHC ==8.6.5 GHC ==8.8.1 GHC ==8.8.2 GHC ==8.8.4 GHC ==8.10.7 GHC ==9.0.1 GHC ==9.2.1 extra-source-files: changelog.md README.md@@ -61,6 +61,7 @@ `zipBits`, `invertBits` and `countBits`. Users are strongly encouraged to enable this flag whenever possible. default: False+ manual: True library exposed-modules:@@ -70,7 +71,6 @@ base >=4.9 && <5, bytestring >=0.10, deepseq,- ghc-prim, primitive >=0.5, vector >=0.11 default-language: Haskell2010@@ -87,10 +87,7 @@ Data.Bit.MutableTS Data.Bit.PdepPext Data.Bit.Utils- if flag(libgmp)- other-modules:- Data.Bit.Gmp- ghc-options: -O2 -Wall+ ghc-options: -O2 -Wall -Wcompat include-dirs: src if impl(ghc <9.0)@@ -109,6 +106,7 @@ base, bitvec, primitive >=0.5,+ quickcheck-classes-base, quickcheck-classes >=0.6.1, vector >=0.11, tasty,@@ -125,7 +123,7 @@ Tests.SetOps Tests.SetOpsTS Tests.Vector- ghc-options: -Wall -threaded -rtsopts+ ghc-options: -Wall -threaded -rtsopts -Wcompat include-dirs: test if impl(ghc <9.0)@@ -139,11 +137,8 @@ bitvec, containers, random,+ tasty-bench, vector- build-depends:- tasty-bench- mixins:- tasty-bench (Test.Tasty.Bench as Gauge.Main) type: exitcode-stdio-1.0 main-is: Bench.hs default-language: Haskell2010@@ -161,7 +156,7 @@ Bench.Reverse Bench.Sum Bench.Union- ghc-options: -O2 -Wall+ ghc-options: -O2 -Wall -Wcompat if impl(ghc <9.0) build-depends: integer-gmp
changelog.md view
@@ -1,3 +1,9 @@+# 1.1.2.0++* Fix `setBit`, `clearBit`, `complementBit` to preserve vector's length.+* Fix various issues on big-endian architectures.+* Fix Cabal 3.7+ incompatibility.+ # 1.1.1.0 * Export `BitVec` and `BitMVec` constructors.
src/Data/Bit/Immutable.hs view
@@ -2,8 +2,10 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE MagicHash #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TupleSections #-} {-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -fno-warn-orphans #-}@@ -37,6 +39,8 @@ , listBits ) where +#include "MachDeps.h"+ import Control.Monad import Control.Monad.ST import Data.Bits@@ -61,6 +65,10 @@ import Data.Word import Unsafe.Coerce +#ifdef WORDS_BIGENDIAN+import GHC.Exts+#endif+ #if UseLibGmp gmpLimbShift :: Int gmpLimbShift = case wordSize of@@ -84,6 +92,27 @@ | n < 0 || n >= U.length v = False | otherwise = unBit (U.unsafeIndex v n) + setBit v n+ | n < 0 || n >= U.length v = v+ | otherwise = runST $ do+ u <- U.thaw v+ MU.unsafeWrite u n (Bit True)+ U.unsafeFreeze u++ clearBit v n+ | n < 0 || n >= U.length v = v+ | otherwise = runST $ do+ u <- U.thaw v+ MU.unsafeWrite u n (Bit False)+ U.unsafeFreeze u++ complementBit v n+ | n < 0 || n >= U.length v = v+ | otherwise = runST $ do+ u <- U.thaw v+ unsafeFlipBit u n+ U.unsafeFreeze u+ bit n | n < 0 = U.empty | otherwise = runST $ do@@ -163,13 +192,31 @@ -- | Cast a unboxed vector of 'Word8' -- to an unboxed vector of bits. --+-- On big-endian architectures 'castFromWords8'+-- resorts to copying instead of aliasing underlying arrays.+-- -- >>> :set -XOverloadedLists -- >>> castFromWords8 [123] -- [1,1,0,1,1,1,1,0] castFromWords8 :: U.Vector Word8 -> U.Vector Bit castFromWords8 ws = BitVec (off `shiftL` 3) (len `shiftL` 3) arr where+#ifdef WORDS_BIGENDIAN+ P.Vector off' len arr' = unsafeCoerce ws+ off = 0+ arr = runST $ do+ let lenWords = nWords $ len `shiftL` 3+ len' = wordsToBytes lenWords+ marr <- newByteArray len'+ copyByteArray marr 0 arr' off' len+ fillByteArray marr len (len' - len) 0+ forM_ [0..lenWords - 1] $ \i -> do+ W# w <- readByteArray marr i+ writeByteArray marr i (W# (byteSwap# w))+ unsafeFreezeByteArray marr+#else P.Vector off len arr = unsafeCoerce ws+#endif -- | Try to cast an unboxed vector of bits -- to an unboxed vector of 'Word8'.@@ -178,10 +225,14 @@ -- -- > castToWords8 (castFromWords8 v) == Just v castToWords8 :: U.Vector Bit -> Maybe (U.Vector Word8)+#ifdef WORDS_BIGENDIAN+castToWords8 = const Nothing+#else castToWords8 (BitVec s n ws)- | s .&. 7 == 0, n .&. 7 == 0 =- Just $ unsafeCoerce $ P.Vector (s `shiftR` 3) (n `shiftR` 3) ws+ | s .&. 7 == 0, n .&. 7 == 0+ = Just $ unsafeCoerce $ P.Vector (s `shiftR` 3) (n `shiftR` 3) ws | otherwise = Nothing+#endif -- | Clone an unboxed vector of bits -- to a new unboxed vector of 'Word8'.
src/Data/Bit/Mutable.hs view
@@ -2,6 +2,7 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE MagicHash #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} @@ -26,6 +27,8 @@ , reverseInPlace ) where +#include "MachDeps.h"+ import Control.Monad import Control.Monad.Primitive import Control.Monad.ST@@ -42,6 +45,10 @@ import qualified Data.Vector.Unboxed.Mutable as MU import Data.Word +#ifdef WORDS_BIGENDIAN+import GHC.Exts+#endif+ -- | Cast a vector of words to a vector of bits. -- Cf. 'Data.Bit.castFromWords'. castFromWordsM :: MVector s Word -> MVector s Bit@@ -83,11 +90,20 @@ -> m (MVector (PrimState m) Word8) cloneToWords8M v = do let lenBits = MU.length v- lenWords = (lenBits + 7) `shiftR` 3- w@(BitMVec _ _ arr) <- MU.unsafeNew (lenWords `shiftL` 3)- MU.unsafeCopy (MU.slice 0 lenBits w) v- MU.set (MU.slice lenBits (lenWords `shiftL` 3 - lenBits) w) (Bit False)- pure $ MU.MV_Word8 $ P.MVector 0 lenWords arr+ -- Take care about big-endian architectures: allocate full words!+ actualLenBytes = (lenBits + 7) `shiftR` 3+ roundedLenBytes = wordsToBytes (nWords lenBits)+ ws@(BitMVec _ _ arr) <- MU.unsafeNew (roundedLenBytes `shiftL` 3)+ MU.unsafeCopy (MU.slice 0 lenBits ws) v+ MU.set (MU.slice lenBits (roundedLenBytes `shiftL` 3 - lenBits) ws) (Bit False)++#ifdef WORDS_BIGENDIAN+ forM_ [0..nWords lenBits - 1] $ \i -> do+ W# w <- readByteArray arr i+ writeByteArray arr i (W# (byteSwap# w))+#endif++ pure $ MU.MV_Word8 $ P.MVector 0 actualLenBytes arr {-# INLINE cloneToWords8M #-} -- | Zip two vectors with the given function.
test/Main.hs view
@@ -5,12 +5,15 @@ import Control.Exception import Data.Bit-import Data.Proxy-import Test.QuickCheck.Classes import Test.Tasty import Test.Tasty.QuickCheck +#ifdef MIN_VERSION_quickcheck_classes_base+import Data.Proxy+import Test.QuickCheck.Classes.Base import Support+#endif+ import Tests.Conc (concTests) import Tests.F2Poly (f2polyTests) import Tests.MVector (mvectorTests)@@ -34,6 +37,7 @@ lawsTests :: TestTree lawsTests = adjustOption (const $ QuickCheckTests 100) $ testGroup "Bit"+#ifdef MIN_VERSION_quickcheck_classes_base $ map lawsToTest [ bitsLaws (Proxy :: Proxy Bit) , eqLaws (Proxy :: Proxy Bit)@@ -41,11 +45,10 @@ , boundedEnumLaws (Proxy :: Proxy Bit) , showLaws (Proxy :: Proxy Bit) , showReadLaws (Proxy :: Proxy Bit)-#if MIN_VERSION_quickcheck_classes(0,6,3) , numLaws (Proxy :: Proxy Bit)-#endif , integralLaws (Proxy :: Proxy Bit) ] +++#endif [ testProperty "divideByZero" prop_bitDivideByZero , testProperty "toRational" prop_bitToRational ]
test/Support.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE RankNTypes #-}@@ -15,10 +16,16 @@ import qualified Data.Vector.Generic.Mutable as M import qualified Data.Vector.Generic.New as N import qualified Data.Vector.Unboxed as U-import Test.QuickCheck.Classes import Test.Tasty import Test.Tasty.QuickCheck +#ifdef MIN_VERSION_quickcheck_classes_base+import Test.QuickCheck.Classes.Base+#endif+#ifdef MIN_VERSION_quickcheck_classes+import qualified Test.QuickCheck.Classes as QCC+#endif+ instance Arbitrary Bit where arbitrary = Bit <$> arbitrary shrink = fmap Bit . shrink . unBit@@ -156,6 +163,14 @@ twoTimesMore = adjustOption $ \(QuickCheckTests n) -> QuickCheckTests (n * 2) +#ifdef MIN_VERSION_quickcheck_classes_base lawsToTest :: Laws -> TestTree lawsToTest (Laws name props) = testGroup name $ map (uncurry testProperty) props+#endif++#ifdef MIN_VERSION_quickcheck_classes+lawsToTest' :: QCC.Laws -> TestTree+lawsToTest' (QCC.Laws name props) =+ testGroup name $ map (uncurry testProperty) props+#endif
test/Tests/F2Poly.hs view
@@ -8,7 +8,6 @@ import Control.Exception import Data.Bit import Data.Bits-import Data.Proxy import Data.Ratio import GHC.Exts #ifdef MIN_VERSION_ghc_bignum@@ -16,10 +15,14 @@ #else import GHC.Integer.Logarithms #endif-import Test.QuickCheck.Classes import Test.Tasty import Test.Tasty.QuickCheck +#ifdef MIN_VERSION_quickcheck_classes_base+import Data.Proxy+import Test.QuickCheck.Classes.Base+#endif+ import Support f2polyTests :: TestTree@@ -36,14 +39,14 @@ , testProperty "GCD" prop_f2polyGCD , testProperty "Enum" $ \n -> let x = toEnum n in toEnum (fromEnum x) === (x :: F2Poly)+#ifdef MIN_VERSION_quickcheck_classes_base , tenTimesLess $ lawsToTest $ showLaws (Proxy :: Proxy F2Poly)-#if MIN_VERSION_quickcheck_classes(0,6,3) , lawsToTest $ numLaws (Proxy :: Proxy F2Poly)-#endif , lawsToTest $ integralLaws (Proxy :: Proxy F2Poly)+#endif , testProperty "fromNegative" prop_f2polyFromNegative , testProperty "divideByZero" prop_f2polyDivideByZero , testProperty "toRational" prop_f2polyToRational
test/Tests/MVector.hs view
@@ -16,17 +16,20 @@ import Data.Bit.ThreadSafe #endif import Data.Bits-import Data.Proxy import qualified Data.Vector.Generic as V import qualified Data.Vector.Generic.Mutable as MG import qualified Data.Vector.Generic.New as N import qualified Data.Vector.Unboxed as U import qualified Data.Vector.Unboxed.Mutable as M-import Test.QuickCheck.Classes import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.QuickCheck +#ifdef MIN_VERSION_quickcheck_classes+import Data.Proxy+import Test.QuickCheck.Classes+#endif+ mvectorTests :: TestTree mvectorTests = testGroup "Data.Vector.Unboxed.Mutable.Bit" [ testGroup "Data.Vector.Unboxed.Mutable functions"@@ -43,7 +46,9 @@ , tenTimesLess $ testProperty "castToWords_2" prop_castToWords_2 ]- , lawsToTest $ muvectorLaws (Proxy :: Proxy Bit)+#ifdef MIN_VERSION_quickcheck_classes+ , lawsToTest' $ muvectorLaws (Proxy :: Proxy Bit)+#endif , testCase "basicInitialize 1" case_write_init_read1 , testCase "basicInitialize 2" case_write_init_read2 , testCase "basicInitialize 3" case_write_init_read3
test/Tests/Vector.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE CPP #-}+ module Tests.Vector ( vectorTests ) where@@ -9,11 +11,15 @@ import Data.Bit import Data.Bits import Data.List (findIndex)+import qualified Data.Vector.Primitive as P import qualified Data.Vector.Unboxed as U import Data.Word import Test.Tasty-import Test.Tasty.QuickCheck+import Test.Tasty.QuickCheck (Property, NonNegative(..), Positive(..), testProperty, Large(..), (===), property, once, (==>), ioProperty, (.&&.), counterexample)+import Unsafe.Coerce +#include "MachDeps.h"+ vectorTests :: TestTree vectorTests = testGroup "Data.Vector.Unboxed.Bit" [ testGroup "Data.Vector.Unboxed functions"@@ -82,6 +88,9 @@ , testProperty "zeroBits" prop_zeroBits , testProperty "bitSize" prop_bitSize , testProperty "isSigned" prop_isSigned+ , testProperty "setBit" prop_setBit+ , testProperty "clearBit" prop_clearBit+ , testProperty "complementBit" prop_complementBit ] ] @@ -133,19 +142,31 @@ Just ws -> castFromWords ws === xs prop_cloneFromWords8_def :: U.Vector Word8 -> Property-prop_cloneFromWords8_def ws =- U.toList (castFromWords8 ws) === concatMap wordToBitList (U.toList ws)+prop_cloneFromWords8_def ws+ = counterexample ("offset = " ++ show off ++ " len = " ++ show len)+ $ U.toList (castFromWords8 ws) === concatMap wordToBitList (U.toList ws)+ where+ P.Vector off len _ = unsafeCoerce ws prop_cloneToWords8_def :: U.Vector Bit -> Property-prop_cloneToWords8_def xs = U.toList (cloneToWords8 xs) === loop (U.toList xs)- where- loop [] = []- loop bs = case packBitsToWord bs of- (w, bs') -> w : loop bs'+prop_cloneToWords8_def xs@(BitVec off len _)+ = counterexample ("offset = " ++ show off ++ " len = " ++ show len)+ $ U.toList (cloneToWords8 xs) === loop (U.toList xs)+ where+ loop [] = []+ loop bs = case packBitsToWord bs of+ (w, bs') -> w : loop bs' prop_castToWords8_1 :: U.Vector Word8 -> Property-prop_castToWords8_1 ws =- Just ws === castToWords8 (castFromWords8 ws)+#ifdef WORDS_BIGENDIAN+prop_castToWords8_1 ws = Nothing === castToWords8 (castFromWords8 ws)+#else+prop_castToWords8_1 ws+ = counterexample ("offset = " ++ show off ++ " len = " ++ show len)+ $ Just ws === castToWords8 (castFromWords8 ws)+ where+ P.Vector off len _ = unsafeCoerce ws+#endif prop_castToWords8_2 :: U.Vector Bit -> Property prop_castToWords8_2 xs = case castToWords8 xs of@@ -323,7 +344,18 @@ prop_isSigned :: U.Vector Bit -> Property prop_isSigned v = isSigned v === False +prop_setBit :: Int -> U.Vector Bit -> Property+prop_setBit n v = v `setBit` n === U.imap ((.|.) . Bit . (== n)) v++prop_clearBit :: Int -> U.Vector Bit -> Property+prop_clearBit n v = v `clearBit` n === U.imap ((.&.) . Bit . (/= n)) v++prop_complementBit :: Int -> U.Vector Bit -> Property+prop_complementBit n v = v `complementBit` n === U.imap (xor . Bit . (== n)) v+ prop_cloneToByteString :: U.Vector Bit -> Property-prop_cloneToByteString v = cloneToByteString (cloneFromByteString bs) === bs+prop_cloneToByteString v@(BitVec off len _)+ = counterexample ("offset = " ++ show off ++ " len = " ++ show len)+ $ cloneToByteString (cloneFromByteString bs) === bs where bs = cloneToByteString v