packages feed

bitstring 0.0.0 → 0.0.1

raw patch · 5 files changed

+717/−1419 lines, 5 filesdep ~bytestringsetup-changedPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: bytestring

API changes (from Hackage documentation)

- Data.BitString: instance Eq BitChunk
- Data.BitString: instance Eq BitString
- Data.BitString: instance Show BitChunk
- Data.BitString: instance Show BitString
- Data.BitString.BigEndian: instance Eq BitChunk
- Data.BitString.BigEndian: instance Eq BitString
- Data.BitString.BigEndian: instance Show BitChunk
- Data.BitString.BigEndian: instance Show BitString
+ Data.BitString: debugShowBitString :: BitString -> String
+ Data.BitString: instance GHC.Classes.Eq Data.BitString.BitChunk
+ Data.BitString: instance GHC.Classes.Eq Data.BitString.BitString
+ Data.BitString: instance GHC.Show.Show Data.BitString.BitChunk
+ Data.BitString: instance GHC.Show.Show Data.BitString.BitString
+ Data.BitString: showBitString :: BitString -> String
+ Data.BitString.BigEndian: debugShowBitString :: BitString -> String
+ Data.BitString.BigEndian: instance GHC.Classes.Eq Data.BitString.BigEndian.BitChunk
+ Data.BitString.BigEndian: instance GHC.Classes.Eq Data.BitString.BigEndian.BitString
+ Data.BitString.BigEndian: instance GHC.Show.Show Data.BitString.BigEndian.BitChunk
+ Data.BitString.BigEndian: instance GHC.Show.Show Data.BitString.BigEndian.BitString
+ Data.BitString.BigEndian: showBitString :: BitString -> String

Files

Data/BitString.hs view
@@ -1,690 +1,9 @@-- {-# LANGUAGE CPP, BangPatterns #-} --- #define BITSTRING_BIGENDIAN--- #define WITH_QUICKCHECK--#ifndef BITSTRING_BIGENDIAN -- | Lazy bitstrings, somewhat similar to lazy bytestrings. -- This module is intended to be imported qualified.-module Data.BitString -#else--- | Big-endian bitstrings. In this context, \"big-endian\" means that--- the bits in the bytes are in the opposite order than what would be--- logical. If you ask me, this is just plain stupid, but some people--- apparently still use it...-module Data.BitString.BigEndian-#endif--  (-    BitString-    ---  , empty-  , bitString-  , bitStringLazy-  , unsafeBitString'-    ---  , take-  , drop-  , splitAt-  , append-  , concat-    ---  , toList-  , fromList-  , to01List-  , from01List-    ---  , null-  , length-    ---  , foldl'-  , findSubstring-    ---  , realizeBitStringLazy-  , realizeBitStringStrict-  , realizeBitString'  -    ---#ifdef WITH_QUICKCHECK-  , runAllTest-  , BitChunk (..)-  , BitString ( BitString )-  , mypack-  , prop_fromToList -  , prop_toFromList -  , prop_append     -  , prop_drop       -  , prop_take       -  , prop_dropChunk  -  , prop_takeChunk  -  , prop_realign    -  , prop_realizeChunk -  , prop_realize      -  , prop_realizeLen      -  , prop_findSubstring1 -  , prop_findSubstring1a -  , prop_findSubstring1b -  , prop_findSubstring2 -#endif        -  )-  where-  -----------------------------------------------------------------------------------import Prelude hiding (take,drop,last,length,splitAt,concat,null,rem,init)--import Control.Monad-import Control.Applicative hiding ( empty )--import Data.Bits ()-import Data.Int  ()-import Data.Word ()-import Data.Maybe-import qualified Data.List as List--import Data.ByteString (ByteString)-import qualified Data.ByteString          as B-import qualified Data.ByteString.Internal as B--- import qualified Data.ByteString.Unsafe   as U-import qualified Data.ByteString.Lazy     as L--#ifdef WITH_QUICKCHECK-import Test.QuickCheck hiding ( (.&.) )-import qualified Data.ByteString.Char8 as BC-import Data.Char (ord)-#endif--import Foreign-import System.IO.Unsafe------------------------------------------------------------------------------------flippedFoldM_ :: Monad m => a -> [b] -> (a -> b -> m a) -> m () -flippedFoldM_ x ys f = foldM_ f x ys--flippedFoldM ::  Monad m => a -> [b] -> (a -> b -> m a) -> m a -flippedFoldM x ys f = foldM f x ys------------------------------------------------------------------------------------#ifdef BITSTRING_BIGENDIAN--{--bitReverseWord8_naive :: Word8 -> Word8-bitReverseWord8_naive x -  = shiftR (x .&. 0x80) 7-  + shiftR (x .&. 0x40) 5-  + shiftR (x .&. 0x20) 3-  + shiftR (x .&. 0x10) 1-  + shiftL (x .&. 0x08) 1-  + shiftL (x .&. 0x04) 3-  + shiftL (x .&. 0x02) 5-  + shiftL (x .&. 0x01) 7-     -bitReverseWord8_table :: ByteString     -bitReverseWord8_table = B.pack $ map reverseWord8_naive [0..255]--bitReverseWord8 :: Word8 -> Word8-bitReverseWord8 = U.unsafeIndex reverseWord8_table . fromIntegral--}--byteReverseWord32 :: Word32 -> Word32-byteReverseWord32 w -  = shiftR w 24 -  + shiftR w 8  .&. 0x0000ff00 -  + shiftL w 8  .&. 0x00ff0000 -  + shiftL w 24--#endif // BITSTRING_BIGENDIAN------------------------------------------------------------------------------------data BitChunk = BitChunk-  { bitChunkOffset :: !Int64-  , bitChunkLength :: !Int64-  , bitChunkData   :: !ByteString-  }--#ifdef WITH_QUICKCHECK--mypack :: String -> ByteString-mypack = B.pack . map c2w where-  c2w = fromIntegral . ord--instance Show BitChunk where-  show (BitChunk ofs len dat) = "BitChunk " ++ show ofs ++ " " ++ show len ++ " (mypack " ++ show dat ++ ")"--#else  --instance Show BitChunk where-  show chunk = "BitChunk <" ++ map f (bitChunkTo01List chunk) ++ ">" where -    f 0 = '0'-    f 1 = '1'--#endif // WITH_QUICKCHECK--emptyBitChunk :: BitChunk-emptyBitChunk = BitChunk 0 0 B.empty--{-  -bitChunk' :: Int64 -> ByteString -> BitChunk  -bitChunk' ofs bs = BitString ofs (len-ofs) bs where -  len = 8 * fromIntegral (B.length bs)--}---- | warning! no boundary checks-unsafeBitChunk'  -  :: Int64      -- ^ offset -  -> Int64      -- ^ length-  -> ByteString  -- ^ source-  -> BitChunk -unsafeBitChunk' ofs len dat = BitChunk ofs len dat where --bitChunk :: ByteString -> BitChunk  -bitChunk bs = unsafeBitChunk' 0 (8 * fromIntegral (B.length bs)) bs------------------------------------------------------------------------------------bitChunkDrop :: Int64 -> BitChunk -> BitChunk-bitChunkDrop k (BitChunk ofs len dat) = if k<len-  then BitChunk (ofs+k) (len-k) dat-  else emptyBitChunk--bitChunkTake :: Int64 -> BitChunk -> BitChunk-bitChunkTake k bc@(BitChunk ofs len dat) -  | k==0      = emptyBitChunk-  | k<=len    = BitChunk ofs k dat-  | otherwise = bc---- TODO: better implementation    -splitBitChunkAt :: Int64 -> BitChunk -> (BitChunk,BitChunk)    -splitBitChunkAt k b = (bitChunkTake k b, bitChunkDrop k b)  ------------------------------------------------------------------------------------{-# INLINE boolToWord8 #-}-boolToWord8 :: Bool -> Word8-boolToWord8 bool = case bool of-  True  -> 1-  False -> 0--{-# INLINE word8ToBool #-}-word8ToBool :: Word8 -> Bool-word8ToBool w = (w/=0)------------------------------------------------------------------------------------unsafeLookupBitChunk :: BitChunk -> Int64 -> Bool-unsafeLookupBitChunk chunk j = unsafeLookupBitChunk01 chunk j /= 0--unsafeLookupBitChunk01 :: BitChunk -> Int64 -> Word8-unsafeLookupBitChunk01 (BitChunk ofs len dat) j = bit where-  (n,k) = divMod (ofs+j) 8-  byte = B.index dat (fromIntegral n)-#ifndef BITSTRING_BIGENDIAN-  bit = ((shiftR byte (fromIntegral k)) .&. 1) -#else-  bit = ((shiftR byte (fromIntegral (7-k))) .&. 1) -#endif-----------------------------------------------------------------------------------  -bitChunkToList :: BitChunk -> [Bool]-bitChunkToList chunk@(BitChunk ofs len dat) = -  [ unsafeLookupBitChunk chunk k | k<-[0..len-1] ]--bitChunkFromList :: [Bool] -> BitChunk-bitChunkFromList bits = BitChunk 0 (fromIntegral len) (B.pack bytes) where-  (len,bytes) = worker bits-  worker []   = ( 0, [] )-  worker bits = ( len' + List.length this , byte:ys ) where-    (this,rest) = List.splitAt 8 bits-#ifndef BITSTRING_BIGENDIAN-    byte = List.foldl' (+) 0 $ zipWith shiftL (map boolToWord8 this) [0..7]-#else-    byte = List.foldl' (+) 0 $ zipWith shiftL (map boolToWord8 this) [7,6..0]-#endif-    (len' , ys) = worker rest--bitChunkTo01List :: BitChunk -> [Word8]-bitChunkTo01List chunk@(BitChunk ofs len dat) = -  [ unsafeLookupBitChunk01 chunk k | k<-[0..len-1] ]--bitChunkFrom01List :: [Word8] -> BitChunk-bitChunkFrom01List bits = BitChunk 0 (fromIntegral len) (B.pack bytes) where-  (len,bytes) = worker bits-  worker []   = ( 0, [] )-  worker bits = ( len' + List.length this , byte:ys ) where-    (this,rest) = List.splitAt 8 bits-#ifndef BITSTRING_BIGENDIAN-    byte = List.foldl' (+) 0 $ zipWith shiftL (map (.&. 1) this) [0..7]-#else-    byte = List.foldl' (+) 0 $ zipWith shiftL (map (.&. 1) this) [7,6..0]-#endif-    (len' , ys) = worker rest-    -instance Eq BitChunk where-  -- | warning! very slow! TODO: make a better routine---  (==) :: BitChunk -> BitChunk -> Bool-  (==) x y = bitChunkToList x == bitChunkToList y-    ------------------------------------------------------------------------------------- | Creates a new 'BitChunk' with offset field 0-realignBitChunk :: BitChunk -> BitChunk -realignBitChunk (BitChunk ofs len dat) = -  BitChunk 0 len $ case ofsFrac of -    0 -> dat'-    _ -> B.pack $ B.zipWith f dat' (B.snoc (B.tail dat') 0) -  where -    ofsFrac2 = 8 - ofsFrac-#ifndef BITSTRING_BIGENDIAN-    f b1 b2 = shiftR b1 (fromIntegral ofsFrac) + shiftL b2 (fromIntegral ofsFrac2)-#else-    f b1 b2 = shiftL b1 (fromIntegral ofsFrac) + shiftR b2 (fromIntegral ofsFrac2)-#endif    -    dat' = B.drop (fromIntegral ofsInt) dat-    (ofsInt, ofsFrac) = divMod ofs 8 -    -realizeBitChunk :: BitChunk -> (ByteString, Maybe (Word8,Int))-realizeBitChunk orig = (whole, end) where-  chunk@(BitChunk 0 len dat) = realignBitChunk orig-  (n,k) = divMod len 8-  whole = B.take (fromIntegral n) dat-  end = case k of-    0 -> Nothing-    _ -> let w' = B.index dat (fromIntegral n)-#ifndef BITSTRING_BIGENDIAN-             mask = 2^k - 1 :: Word8-             w = w' .&. mask-#else--- and at this point, the the inventor and users of big endianness deserve an extra fuck!-             kk = fromIntegral k :: Int-             mask = shiftL (2^kk-1) (8-kk) -             w = w' .&. mask-#endif-         in  Just (w, fromIntegral k) -           -----------------------------------------------------------------------------------unBitString :: BitString -> [BitChunk]-unBitString (BitString xs) = xs-  -newtype BitString = BitString [BitChunk] -#ifdef WITH_QUICKCHECK -  deriving Show-#else-instance Show BitString where-  show bits = "BitString <" ++ map f (to01List bits) ++ ">" where -    f 0 = '0'-    f 1 = '1'-    f _ = error "BitString/show: impossible"-#endif--empty :: BitString-empty = BitString [] -- emptyChunk]---- | Create a 'BitString' from a portion of a 'ByteString'.--- Warning! No boundary checks are performed!-unsafeBitString' -  :: Int64      -- ^ offset -  -> Int64      -- ^ length-  -> ByteString  -- ^ source -  -> BitString-unsafeBitString' ofs len bs = BitString [unsafeBitChunk' ofs len bs] ---- | Create a 'BitString' from a strict 'ByteString'-bitString :: ByteString -> BitString  -bitString bs = unsafeBitString' 0 (8 * fromIntegral (B.length bs)) bs---- | Create a 'BitString' from a lazy 'ByteString'-bitStringLazy :: L.ByteString -> BitString  -bitStringLazy = concat . map bitString . L.toChunks --drop :: Int64 -> BitString -> BitString-drop k (BitString cs) = BitString (worker k cs) where-  worker _ [] = []-  worker k (BitChunk ofs len dat : cs) = if k < len -    then BitChunk (ofs+k) (len-k) dat : cs-    else worker (k-len) cs--take :: Int64 -> BitString -> BitString-take k (BitString cs) = BitString (worker k cs) where-  worker 0 _  = []-  worker _ [] = []-  worker k (c@(BitChunk ofs len dat) : cs) = if k <= len -    then [ BitChunk ofs k dat ]-    else c : worker (k-len) cs---- TODO: better implementation    -splitAt :: Int64 -> BitString -> (BitString,BitString)    -splitAt k b = (take k b, drop k b)--append :: BitString -> BitString -> BitString    -append (BitString chunks1) (BitString chunks2) = BitString (chunks1 ++ chunks2)--concat :: [BitString] -> BitString-concat xs = case xs of-  [] -> empty-  _  -> (BitString . List.concat . map unBitString) xs   -- hmm how strict or lazy this should be?--toList :: BitString -> [Bool]-toList (BitString chunks) = List.concatMap bitChunkToList chunks--fromList :: [Bool] -> BitString-fromList digits = BitString [bitChunkFromList digits]--to01List :: BitString -> [Word8]-to01List (BitString chunks) = List.concatMap bitChunkTo01List chunks--from01List :: [Word8] -> BitString-from01List digits = BitString [bitChunkFrom01List digits]------------------------------------------------------------------------------------length :: BitString -> Int64-length (BitString chunks) = List.foldl' (+) 0 (map bitChunkLength chunks)--null :: BitString -> Bool-null bits = (length bits == 0)---- | warning! very slow! TODO: make a better routine-instance Eq BitString where-  -- (==) :: BitString -> BitString -> Bool-  (==) = fallbackEqual-  --- | slow, fallback equality test, via converting to list-fallbackEqual :: BitString -> BitString -> Bool-fallbackEqual x y = (toList x == toList y)------------------------------------------------------------------------------------foldl' :: (a -> Bool -> a) -> a -> BitString -> a-foldl' fun init bits = List.foldl' fun init (toList bits)------------------------------------------------------------------------------------findSubstring-  :: BitString    -- ^ the string to search for-  -> BitString    -- ^ the string to search in-  -> Maybe Int64  -- ^ the index of the first substring, if exists-findSubstring = findSubstring32---- the basic unit is a Word32-findSubstring32 -  :: BitString    -- ^ the string to search for-  -> BitString    -- ^ the string to search in-  -> Maybe Int64  -- ^ the index of the first substring, if exists-findSubstring32 small large = -  unsafePerformIO $ do-    withForeignPtr fptr_b_small $ \p'' -> do-      let p' = (plusPtr p'' ofs_b_small) :: Ptr Word8-      allocaArray (k+1) $ \q -> allocaArray (k+1) $ \p -> do-        -- we store in 'q' the last 'm' bits-        -- and in 'p' the bits we are searching for-        -#ifndef BITSTRING_BIGENDIAN-        let p8 = (castPtr :: Ptr Word32 -> Ptr Word8) p-        forM_ [0..len_b_small-1] $ \i -> do { x <- peekElemOff p' i ; pokeElemOff p8 i x }-        peekElemOff p k >>= \x -> pokeElemOff p k (x .&. mask)-        pokeElemOff q k 0   -- this is quite important, because of the shifts!-#else -        pokeElemOff p k 0   -- just to be on the safe side-        let p8 = (castPtr :: Ptr Word32 -> Ptr Word8) p-        forM_ [0..len_b_small-1] $ \i -> do { x <- peekElemOff p' i ; pokeElemOff p8 i x }-        forM_ [0..k] $ \j -> do { y <- peekElemOff p j ; pokeElemOff p j (byteReverseWord32 y) }-        peekElemOff p k >>= \x -> pokeElemOff p k (x .&. mask)-        pokeElemOff q k 0   -- this is quite important, because of the shifts!-#endif         --{--        print (m,m32)-        print len_b_small-        print hmm-        peekArray ((k+1)*4) (castPtr p :: Ptr Word8) >>= print       --}--        worker p q 0 (to01List large)-      -  where-    m = length small-    m32 = fromIntegral (mod m 32) :: Int    -    d32 = fromIntegral (div m 32) :: Int--    hmm :: (Int, Word32, Int)-    hmm@(k,mask,initShift) = case m32 of-#ifndef BITSTRING_BIGENDIAN    -      0 -> ( d32 - 1  , 0xffffffff     , 31                          )-      _ -> ( d32      , 2^m32  - 1     , fromIntegral (mod (m-1) 32) )-#else-      0 -> ( d32 - 1  , 0xffffffff                , 0                              )  -      _ -> ( d32      , shiftL (2^m32-1) (32-m32) , fromIntegral ( 32 - mod m 32 ) )-#endif    --    b_small = realizeBitStringStrict small-    (fptr_b_small, ofs_b_small, len_b_small) = B.toForeignPtr b_small-    -    worker :: Ptr Word32 -> Ptr Word32 -> Int64 -> [Word8] -> IO (Maybe Int64)-    worker !p !q !pos !bits = do----      peekArray ((k+1)*4) (castPtr q :: Ptr Word8) >>= print       --      conds <- forM [0..k-1] $ \j -> do { x <- peekElemOff p j ; y <- peekElemOff q j ; return (x==y) }-      cond  <- do { x <- peekElemOff p k ; y <- peekElemOff q k ; return (x .&. mask == y .&. mask) }-      if and (cond:conds) && pos >= m-        then return (Just (pos - m))-        else case bits of-          [] -> return Nothing-          (b:bs) -> do--#ifndef BITSTRING_BIGENDIAN-            let init_cr = (fromIntegral b , initShift)-            flippedFoldM_ init_cr [k,k-1..0] $ \(c,r) j -> do-              y <- peekElemOff q j-              let cr' = ( y .&. 1 , 31 )-              pokeElemOff q j (shiftR y 1 + shiftL c r)-              return cr'-            worker p q (pos+1) bs -#else-            let init_cr = (fromIntegral b , initShift)-            flippedFoldM_ init_cr [k,k-1..0] $ \(c,r) j -> do-              y <- peekElemOff q j-              let cr' = ( shiftR y 31 , 0 )-              pokeElemOff q j (shiftL y 1 + shiftL c r)-              return cr'-            worker p q (pos+1) bs -#endif-      -----------------------------------------------------------------------------------realizeBitString' :: BitString -> [ByteString]   -realizeBitString' (BitString chunks) = worker Nothing chunks where-  worker :: Maybe (Word8,Int) -> [BitChunk] -> [ByteString]-  worker rem (b:bs) = -    case rem of -      Nothing -> -        let (s, rem') = realizeBitChunk b-        in  s : worker rem' bs-      Just (w,k) -> -        if r >= q-          then B.singleton t : s : worker rem' bs-               -- (B.cons t s) : worker rem' bs-          else worker (Just (t, k+fromIntegral r)) bs-        where-          q = 8 - fromIntegral k-          r = bitChunkLength b-          (x,y) = splitBitChunkAt q b-          (s, rem') = realizeBitChunk y-#ifndef BITSTRING_BIGENDIAN          -          t = List.foldl' (+) w-            $ zipWith shiftL (bitChunkTo01List x) [k..]-#else-          -- also, fuck. and fuck, again.-          u = 7-k-          t = List.foldl' (+) w-            $ zipWith shiftL (bitChunkTo01List x) [u,u-1..]-#endif-  worker rem [] = case rem of-    Nothing    -> []-    Just (w,_) -> [B.singleton w] ---realizeBitStringLazy :: BitString -> L.ByteString-realizeBitStringLazy = L.fromChunks . realizeBitString'--realizeBitStringStrict :: BitString -> B.ByteString-realizeBitStringStrict = B.concat . realizeBitString'------------------------------------------------------------------------------------#ifdef WITH_QUICKCHECK--newtype Size     = Size     Int64  deriving Show-newtype BoolList = BoolList [Bool] deriving Show--newtype SearchFor = SearchFor BitString deriving Show--instance Arbitrary Size where-  arbitrary = Size <$> (fromIntegral :: Int -> Int64) <$> choose (0,64) -- 192)--instance Arbitrary BoolList where-  arbitrary = do-    Size k <- arbitrary -    BoolList <$> vector (fromIntegral k) --instance Arbitrary BitChunk where-  arbitrary = do-    k <- choose (0,24) :: Gen Int-    l <- choose (0,15) :: Gen Int-    BoolList list <- arbitrary-    let bits1 = bitChunkDrop (fromIntegral k) $ bitChunkFromList list-        len = bitChunkLength bits1-        bits2 = bitChunkTake (max 0 $ len - fromIntegral l) bits1-    return bits2---- with 48 bits, it's unlikely that there are other random appearances -instance Arbitrary SearchFor where-  arbitrary = do-    b <- arbitrary-    let l = length b-    if l >= 48 && l < 96 -      then return (SearchFor b) -      else arbitrary-    -instance Arbitrary BitString where-  arbitrary = do-    k <- choose (0,7)-    BitString <$> vector k --runAllTest :: IO ()     -runAllTest = do-  let mytest (text,prop) = do-        print text-        quickCheck prop-        -  mytest ("fromToList"    , prop_fromToList )-  mytest ("toFromList"    , prop_toFromList )-  mytest ("append"       , prop_append     )-  mytest ("drop"         , prop_drop       )-  mytest ("take"         , prop_take       )-  mytest ("dropChunk"    , prop_dropChunk  )-  mytest ("takeChunk"    , prop_takeChunk  )-  mytest ("realign"      , prop_realign    )-  mytest ("realizeChunk" , prop_realizeChunk )-  mytest ("realize"      , prop_realize      )-  mytest ("realize"      , prop_realize      )-  mytest ("realize"      , prop_realize      )-  mytest ("realize"      , prop_realize      )-  mytest ("realizeLen"   , prop_realizeLen   )--  mytest ("findSubstring1"  , prop_findSubstring1  )-  mytest ("findSubstring1"  , prop_findSubstring1  )-  mytest ("findSubstring1"  , prop_findSubstring1  )-  mytest ("findSubstring1"  , prop_findSubstring1  )-  mytest ("findSubstring1a" , prop_findSubstring1a )-  mytest ("findSubstring1b" , prop_findSubstring1b )-  mytest ("findSubstring2"  , prop_findSubstring2  )--prop_fromToList :: BitString -> Bool-prop_fromToList bits = fromList (toList bits) == bits--prop_toFromList :: BoolList -> Bool-prop_toFromList (BoolList list) = toList (fromList list) == list--prop_append :: [BitString] -> Bool-prop_append xs = toList (concat xs) == List.concat (map toList xs)--prop_drop :: Size -> BitString -> Bool-prop_drop (Size k) xs = toList (drop k xs) == List.drop (fromIntegral k) (toList xs)--prop_take :: Size -> BitString -> Bool-prop_take (Size k) xs = toList (take k xs) == List.take (fromIntegral k) (toList xs)--prop_dropChunk :: Size -> BitChunk -> Bool-prop_dropChunk (Size k) xs = bitChunkToList (bitChunkDrop k xs) == List.drop (fromIntegral k) (bitChunkToList xs)--prop_takeChunk :: Size -> BitChunk -> Bool-prop_takeChunk (Size k) xs = bitChunkToList (bitChunkTake k xs) == List.take (fromIntegral k) (bitChunkToList xs)--prop_realign :: BitChunk -> Bool-prop_realign chunk = realignBitChunk chunk == chunk--prop_realizeChunk :: BitChunk -> Bool-prop_realizeChunk chunk = append (bitString whole) (BitString [end]) == BitString [chunk] where-  (whole,remain) = realizeBitChunk chunk-  end = case remain of-    Nothing -> emptyBitChunk-    Just (w,k) -> BitChunk 0 (fromIntegral k) (B.singleton w)--prop_realize :: BitString -> Bool-prop_realize bits = let n = length bits in unsafeBitString' 0 n (realizeBitStringStrict bits) == bits--prop_realizeLen :: BitString -> Bool-prop_realizeLen bits = let n = length bits in div (n+7) 8 == (fromIntegral $ B.length $ realizeBitStringStrict bits) -    -prop_findSubstring1 :: SearchFor -> BitString -> BitString -> Bool-prop_findSubstring1 (SearchFor what) pre post = findSubstring what big == Just (length pre) where-  big = concat [ pre , what , post ] --prop_findSubstring1a :: SearchFor -> BitString -> Bool-prop_findSubstring1a (SearchFor what) pre = findSubstring what big == Just (length pre) where-  big = concat [ pre , what ] --prop_findSubstring1b :: SearchFor -> BitString -> Bool-prop_findSubstring1b (SearchFor what) post = findSubstring what big == Just 0 where-  big = concat [ what , post  ] --prop_findSubstring2 :: SearchFor -> BitString -> BitString -> Bool-prop_findSubstring2 (SearchFor what) pre post = findSubstring what big == Nothing where-  big = concat [ pre , post ] ---------  -{-  -test = BitString xxx--xxx =-  [ BitChunk 17 49 (mypack "9\176N\152%\f\STX\144\ETX")-  , BitChunk 22 50 (mypack "\148\&6\184\RS\134\144+\241\210")-  , BitChunk 0 0 (mypack "")-  , BitChunk 0 0 (mypack "")-  , BitChunk 0 9 (mypack "$\NUL")-  ]  - -yyy = map (bitChunk) $ realizeBitString' test--}--{--let what = (BitString [BitChunk 0 16 (mypack "c\229W"),BitChunk 0 0 (mypack ""),BitChunk 20 13 (mypack "\169\188\"\DLEf\EOT"),BitChunk 0 0 (mypack ""),BitChunk 3 9 (mypack "/\FS+"),BitChunk 21 26 (mypack "&,\159\249\158&h\STX"),BitChunk 0 0 (mypack "")])--let pre = BitString [BitChunk 3 13 (mypack "\245\200\180\NUL"),BitChunk 17 4 (mypack "{\SI\DC2"),BitChunk 24 33 (mypack "\207\135W\RS\240\180{\SOH")]--let post = BitString [BitChunk 16 19 (mypack "e\142\&0z\209m\NUL"),BitChunk 14 27 (mypack "\248m\207\146\&8\224\NUL")]--}+-- --------  -#endif // WITH_QUICKCHECK+module Data.BitString ---------------------------------------------------------------------------------+#include "BitString.inc"
Data/BitString/BigEndian.hs view
@@ -1,692 +1,17 @@--- DO NOT EDIT THIS FILE-{-# OPTIONS_GHC -DBITSTRING_BIGENDIAN #-}-- {-# LANGUAGE CPP, BangPatterns #-} --- #define BITSTRING_BIGENDIAN--- #define WITH_QUICKCHECK+#define BITSTRING_BIGENDIAN -#ifndef BITSTRING_BIGENDIAN--- | Lazy bitstrings, somewhat similar to lazy bytestrings.+-- | Lazy, big-endian bitstrings, somewhat similar to lazy bytestrings.+--+-- In this context, \"big-endian\" means that the bits in the bytes +-- are in the opposite order than what would be logical. If you ask me, +-- this is doesn't make too much sense, but this convention apparently still +-- have usage...+-- -- This module is intended to be imported qualified.-module Data.BitString -#else--- | Big-endian bitstrings. In this context, \"big-endian\" means that--- the bits in the bytes are in the opposite order than what would be--- logical. If you ask me, this is just plain stupid, but some people--- apparently still use it...-module Data.BitString.BigEndian-#endif--  (-    BitString-    ---  , empty-  , bitString-  , bitStringLazy-  , unsafeBitString'-    ---  , take-  , drop-  , splitAt-  , append-  , concat-    ---  , toList-  , fromList-  , to01List-  , from01List-    ---  , null-  , length-    ---  , foldl'-  , findSubstring-    ---  , realizeBitStringLazy-  , realizeBitStringStrict-  , realizeBitString'  -    ---#ifdef WITH_QUICKCHECK-  , runAllTest-  , BitChunk (..)-  , BitString ( BitString )-  , mypack-  , prop_fromToList -  , prop_toFromList -  , prop_append     -  , prop_drop       -  , prop_take       -  , prop_dropChunk  -  , prop_takeChunk  -  , prop_realign    -  , prop_realizeChunk -  , prop_realize      -  , prop_realizeLen      -  , prop_findSubstring1 -  , prop_findSubstring1a -  , prop_findSubstring1b -  , prop_findSubstring2 -#endif        -  )-  where-  -----------------------------------------------------------------------------------import Prelude hiding (take,drop,last,length,splitAt,concat,null,rem,init)--import Control.Monad-import Control.Applicative hiding ( empty )--import Data.Bits ()-import Data.Int  ()-import Data.Word ()-import Data.Maybe-import qualified Data.List as List--import Data.ByteString (ByteString)-import qualified Data.ByteString          as B-import qualified Data.ByteString.Internal as B--- import qualified Data.ByteString.Unsafe   as U-import qualified Data.ByteString.Lazy     as L--#ifdef WITH_QUICKCHECK-import Test.QuickCheck hiding ( (.&.) )-import qualified Data.ByteString.Char8 as BC-import Data.Char (ord)-#endif--import Foreign-import System.IO.Unsafe------------------------------------------------------------------------------------flippedFoldM_ :: Monad m => a -> [b] -> (a -> b -> m a) -> m () -flippedFoldM_ x ys f = foldM_ f x ys--flippedFoldM ::  Monad m => a -> [b] -> (a -> b -> m a) -> m a -flippedFoldM x ys f = foldM f x ys------------------------------------------------------------------------------------#ifdef BITSTRING_BIGENDIAN--{--bitReverseWord8_naive :: Word8 -> Word8-bitReverseWord8_naive x -  = shiftR (x .&. 0x80) 7-  + shiftR (x .&. 0x40) 5-  + shiftR (x .&. 0x20) 3-  + shiftR (x .&. 0x10) 1-  + shiftL (x .&. 0x08) 1-  + shiftL (x .&. 0x04) 3-  + shiftL (x .&. 0x02) 5-  + shiftL (x .&. 0x01) 7-     -bitReverseWord8_table :: ByteString     -bitReverseWord8_table = B.pack $ map reverseWord8_naive [0..255]--bitReverseWord8 :: Word8 -> Word8-bitReverseWord8 = U.unsafeIndex reverseWord8_table . fromIntegral--}--byteReverseWord32 :: Word32 -> Word32-byteReverseWord32 w -  = shiftR w 24 -  + shiftR w 8  .&. 0x0000ff00 -  + shiftL w 8  .&. 0x00ff0000 -  + shiftL w 24--#endif // BITSTRING_BIGENDIAN------------------------------------------------------------------------------------data BitChunk = BitChunk-  { bitChunkOffset :: !Int64-  , bitChunkLength :: !Int64-  , bitChunkData   :: !ByteString-  }--#ifdef WITH_QUICKCHECK--mypack :: String -> ByteString-mypack = B.pack . map c2w where-  c2w = fromIntegral . ord--instance Show BitChunk where-  show (BitChunk ofs len dat) = "BitChunk " ++ show ofs ++ " " ++ show len ++ " (mypack " ++ show dat ++ ")"--#else  --instance Show BitChunk where-  show chunk = "BitChunk <" ++ map f (bitChunkTo01List chunk) ++ ">" where -    f 0 = '0'-    f 1 = '1'--#endif // WITH_QUICKCHECK--emptyBitChunk :: BitChunk-emptyBitChunk = BitChunk 0 0 B.empty--{-  -bitChunk' :: Int64 -> ByteString -> BitChunk  -bitChunk' ofs bs = BitString ofs (len-ofs) bs where -  len = 8 * fromIntegral (B.length bs)--}---- | warning! no boundary checks-unsafeBitChunk'  -  :: Int64      -- ^ offset -  -> Int64      -- ^ length-  -> ByteString  -- ^ source-  -> BitChunk -unsafeBitChunk' ofs len dat = BitChunk ofs len dat where --bitChunk :: ByteString -> BitChunk  -bitChunk bs = unsafeBitChunk' 0 (8 * fromIntegral (B.length bs)) bs------------------------------------------------------------------------------------bitChunkDrop :: Int64 -> BitChunk -> BitChunk-bitChunkDrop k (BitChunk ofs len dat) = if k<len-  then BitChunk (ofs+k) (len-k) dat-  else emptyBitChunk--bitChunkTake :: Int64 -> BitChunk -> BitChunk-bitChunkTake k bc@(BitChunk ofs len dat) -  | k==0      = emptyBitChunk-  | k<=len    = BitChunk ofs k dat-  | otherwise = bc---- TODO: better implementation    -splitBitChunkAt :: Int64 -> BitChunk -> (BitChunk,BitChunk)    -splitBitChunkAt k b = (bitChunkTake k b, bitChunkDrop k b)  ------------------------------------------------------------------------------------{-# INLINE boolToWord8 #-}-boolToWord8 :: Bool -> Word8-boolToWord8 bool = case bool of-  True  -> 1-  False -> 0--{-# INLINE word8ToBool #-}-word8ToBool :: Word8 -> Bool-word8ToBool w = (w/=0)------------------------------------------------------------------------------------unsafeLookupBitChunk :: BitChunk -> Int64 -> Bool-unsafeLookupBitChunk chunk j = unsafeLookupBitChunk01 chunk j /= 0--unsafeLookupBitChunk01 :: BitChunk -> Int64 -> Word8-unsafeLookupBitChunk01 (BitChunk ofs len dat) j = bit where-  (n,k) = divMod (ofs+j) 8-  byte = B.index dat (fromIntegral n)-#ifndef BITSTRING_BIGENDIAN-  bit = ((shiftR byte (fromIntegral k)) .&. 1) -#else-  bit = ((shiftR byte (fromIntegral (7-k))) .&. 1) -#endif-----------------------------------------------------------------------------------  -bitChunkToList :: BitChunk -> [Bool]-bitChunkToList chunk@(BitChunk ofs len dat) = -  [ unsafeLookupBitChunk chunk k | k<-[0..len-1] ]--bitChunkFromList :: [Bool] -> BitChunk-bitChunkFromList bits = BitChunk 0 (fromIntegral len) (B.pack bytes) where-  (len,bytes) = worker bits-  worker []   = ( 0, [] )-  worker bits = ( len' + List.length this , byte:ys ) where-    (this,rest) = List.splitAt 8 bits-#ifndef BITSTRING_BIGENDIAN-    byte = List.foldl' (+) 0 $ zipWith shiftL (map boolToWord8 this) [0..7]-#else-    byte = List.foldl' (+) 0 $ zipWith shiftL (map boolToWord8 this) [7,6..0]-#endif-    (len' , ys) = worker rest--bitChunkTo01List :: BitChunk -> [Word8]-bitChunkTo01List chunk@(BitChunk ofs len dat) = -  [ unsafeLookupBitChunk01 chunk k | k<-[0..len-1] ]--bitChunkFrom01List :: [Word8] -> BitChunk-bitChunkFrom01List bits = BitChunk 0 (fromIntegral len) (B.pack bytes) where-  (len,bytes) = worker bits-  worker []   = ( 0, [] )-  worker bits = ( len' + List.length this , byte:ys ) where-    (this,rest) = List.splitAt 8 bits-#ifndef BITSTRING_BIGENDIAN-    byte = List.foldl' (+) 0 $ zipWith shiftL (map (.&. 1) this) [0..7]-#else-    byte = List.foldl' (+) 0 $ zipWith shiftL (map (.&. 1) this) [7,6..0]-#endif-    (len' , ys) = worker rest-    -instance Eq BitChunk where-  -- | warning! very slow! TODO: make a better routine---  (==) :: BitChunk -> BitChunk -> Bool-  (==) x y = bitChunkToList x == bitChunkToList y-    ------------------------------------------------------------------------------------- | Creates a new 'BitChunk' with offset field 0-realignBitChunk :: BitChunk -> BitChunk -realignBitChunk (BitChunk ofs len dat) = -  BitChunk 0 len $ case ofsFrac of -    0 -> dat'-    _ -> B.pack $ B.zipWith f dat' (B.snoc (B.tail dat') 0) -  where -    ofsFrac2 = 8 - ofsFrac-#ifndef BITSTRING_BIGENDIAN-    f b1 b2 = shiftR b1 (fromIntegral ofsFrac) + shiftL b2 (fromIntegral ofsFrac2)-#else-    f b1 b2 = shiftL b1 (fromIntegral ofsFrac) + shiftR b2 (fromIntegral ofsFrac2)-#endif    -    dat' = B.drop (fromIntegral ofsInt) dat-    (ofsInt, ofsFrac) = divMod ofs 8 -    -realizeBitChunk :: BitChunk -> (ByteString, Maybe (Word8,Int))-realizeBitChunk orig = (whole, end) where-  chunk@(BitChunk 0 len dat) = realignBitChunk orig-  (n,k) = divMod len 8-  whole = B.take (fromIntegral n) dat-  end = case k of-    0 -> Nothing-    _ -> let w' = B.index dat (fromIntegral n)-#ifndef BITSTRING_BIGENDIAN-             mask = 2^k - 1 :: Word8-             w = w' .&. mask-#else--- and at this point, the the inventor and users of big endianness deserve an extra fuck!-             kk = fromIntegral k :: Int-             mask = shiftL (2^kk-1) (8-kk) -             w = w' .&. mask-#endif-         in  Just (w, fromIntegral k) -           -----------------------------------------------------------------------------------unBitString :: BitString -> [BitChunk]-unBitString (BitString xs) = xs-  -newtype BitString = BitString [BitChunk] -#ifdef WITH_QUICKCHECK -  deriving Show-#else-instance Show BitString where-  show bits = "BitString <" ++ map f (to01List bits) ++ ">" where -    f 0 = '0'-    f 1 = '1'-    f _ = error "BitString/show: impossible"-#endif--empty :: BitString-empty = BitString [] -- emptyChunk]---- | Create a 'BitString' from a portion of a 'ByteString'.--- Warning! No boundary checks are performed!-unsafeBitString' -  :: Int64      -- ^ offset -  -> Int64      -- ^ length-  -> ByteString  -- ^ source -  -> BitString-unsafeBitString' ofs len bs = BitString [unsafeBitChunk' ofs len bs] ---- | Create a 'BitString' from a strict 'ByteString'-bitString :: ByteString -> BitString  -bitString bs = unsafeBitString' 0 (8 * fromIntegral (B.length bs)) bs---- | Create a 'BitString' from a lazy 'ByteString'-bitStringLazy :: L.ByteString -> BitString  -bitStringLazy = concat . map bitString . L.toChunks --drop :: Int64 -> BitString -> BitString-drop k (BitString cs) = BitString (worker k cs) where-  worker _ [] = []-  worker k (BitChunk ofs len dat : cs) = if k < len -    then BitChunk (ofs+k) (len-k) dat : cs-    else worker (k-len) cs--take :: Int64 -> BitString -> BitString-take k (BitString cs) = BitString (worker k cs) where-  worker 0 _  = []-  worker _ [] = []-  worker k (c@(BitChunk ofs len dat) : cs) = if k <= len -    then [ BitChunk ofs k dat ]-    else c : worker (k-len) cs---- TODO: better implementation    -splitAt :: Int64 -> BitString -> (BitString,BitString)    -splitAt k b = (take k b, drop k b)--append :: BitString -> BitString -> BitString    -append (BitString chunks1) (BitString chunks2) = BitString (chunks1 ++ chunks2)--concat :: [BitString] -> BitString-concat xs = case xs of-  [] -> empty-  _  -> (BitString . List.concat . map unBitString) xs   -- hmm how strict or lazy this should be?--toList :: BitString -> [Bool]-toList (BitString chunks) = List.concatMap bitChunkToList chunks--fromList :: [Bool] -> BitString-fromList digits = BitString [bitChunkFromList digits]--to01List :: BitString -> [Word8]-to01List (BitString chunks) = List.concatMap bitChunkTo01List chunks--from01List :: [Word8] -> BitString-from01List digits = BitString [bitChunkFrom01List digits]------------------------------------------------------------------------------------length :: BitString -> Int64-length (BitString chunks) = List.foldl' (+) 0 (map bitChunkLength chunks)--null :: BitString -> Bool-null bits = (length bits == 0)---- | warning! very slow! TODO: make a better routine-instance Eq BitString where-  -- (==) :: BitString -> BitString -> Bool-  (==) = fallbackEqual-  --- | slow, fallback equality test, via converting to list-fallbackEqual :: BitString -> BitString -> Bool-fallbackEqual x y = (toList x == toList y)------------------------------------------------------------------------------------foldl' :: (a -> Bool -> a) -> a -> BitString -> a-foldl' fun init bits = List.foldl' fun init (toList bits)------------------------------------------------------------------------------------findSubstring-  :: BitString    -- ^ the string to search for-  -> BitString    -- ^ the string to search in-  -> Maybe Int64  -- ^ the index of the first substring, if exists-findSubstring = findSubstring32---- the basic unit is a Word32-findSubstring32 -  :: BitString    -- ^ the string to search for-  -> BitString    -- ^ the string to search in-  -> Maybe Int64  -- ^ the index of the first substring, if exists-findSubstring32 small large = -  unsafePerformIO $ do-    withForeignPtr fptr_b_small $ \p'' -> do-      let p' = (plusPtr p'' ofs_b_small) :: Ptr Word8-      allocaArray (k+1) $ \q -> allocaArray (k+1) $ \p -> do-        -- we store in 'q' the last 'm' bits-        -- and in 'p' the bits we are searching for-        -#ifndef BITSTRING_BIGENDIAN-        let p8 = (castPtr :: Ptr Word32 -> Ptr Word8) p-        forM_ [0..len_b_small-1] $ \i -> do { x <- peekElemOff p' i ; pokeElemOff p8 i x }-        peekElemOff p k >>= \x -> pokeElemOff p k (x .&. mask)-        pokeElemOff q k 0   -- this is quite important, because of the shifts!-#else -        pokeElemOff p k 0   -- just to be on the safe side-        let p8 = (castPtr :: Ptr Word32 -> Ptr Word8) p-        forM_ [0..len_b_small-1] $ \i -> do { x <- peekElemOff p' i ; pokeElemOff p8 i x }-        forM_ [0..k] $ \j -> do { y <- peekElemOff p j ; pokeElemOff p j (byteReverseWord32 y) }-        peekElemOff p k >>= \x -> pokeElemOff p k (x .&. mask)-        pokeElemOff q k 0   -- this is quite important, because of the shifts!-#endif         --{--        print (m,m32)-        print len_b_small-        print hmm-        peekArray ((k+1)*4) (castPtr p :: Ptr Word8) >>= print       --}--        worker p q 0 (to01List large)-      -  where-    m = length small-    m32 = fromIntegral (mod m 32) :: Int    -    d32 = fromIntegral (div m 32) :: Int--    hmm :: (Int, Word32, Int)-    hmm@(k,mask,initShift) = case m32 of-#ifndef BITSTRING_BIGENDIAN    -      0 -> ( d32 - 1  , 0xffffffff     , 31                          )-      _ -> ( d32      , 2^m32  - 1     , fromIntegral (mod (m-1) 32) )-#else-      0 -> ( d32 - 1  , 0xffffffff                , 0                              )  -      _ -> ( d32      , shiftL (2^m32-1) (32-m32) , fromIntegral ( 32 - mod m 32 ) )-#endif    --    b_small = realizeBitStringStrict small-    (fptr_b_small, ofs_b_small, len_b_small) = B.toForeignPtr b_small-    -    worker :: Ptr Word32 -> Ptr Word32 -> Int64 -> [Word8] -> IO (Maybe Int64)-    worker !p !q !pos !bits = do----      peekArray ((k+1)*4) (castPtr q :: Ptr Word8) >>= print       --      conds <- forM [0..k-1] $ \j -> do { x <- peekElemOff p j ; y <- peekElemOff q j ; return (x==y) }-      cond  <- do { x <- peekElemOff p k ; y <- peekElemOff q k ; return (x .&. mask == y .&. mask) }-      if and (cond:conds) && pos >= m-        then return (Just (pos - m))-        else case bits of-          [] -> return Nothing-          (b:bs) -> do--#ifndef BITSTRING_BIGENDIAN-            let init_cr = (fromIntegral b , initShift)-            flippedFoldM_ init_cr [k,k-1..0] $ \(c,r) j -> do-              y <- peekElemOff q j-              let cr' = ( y .&. 1 , 31 )-              pokeElemOff q j (shiftR y 1 + shiftL c r)-              return cr'-            worker p q (pos+1) bs -#else-            let init_cr = (fromIntegral b , initShift)-            flippedFoldM_ init_cr [k,k-1..0] $ \(c,r) j -> do-              y <- peekElemOff q j-              let cr' = ( shiftR y 31 , 0 )-              pokeElemOff q j (shiftL y 1 + shiftL c r)-              return cr'-            worker p q (pos+1) bs -#endif-      -----------------------------------------------------------------------------------realizeBitString' :: BitString -> [ByteString]   -realizeBitString' (BitString chunks) = worker Nothing chunks where-  worker :: Maybe (Word8,Int) -> [BitChunk] -> [ByteString]-  worker rem (b:bs) = -    case rem of -      Nothing -> -        let (s, rem') = realizeBitChunk b-        in  s : worker rem' bs-      Just (w,k) -> -        if r >= q-          then B.singleton t : s : worker rem' bs-               -- (B.cons t s) : worker rem' bs-          else worker (Just (t, k+fromIntegral r)) bs-        where-          q = 8 - fromIntegral k-          r = bitChunkLength b-          (x,y) = splitBitChunkAt q b-          (s, rem') = realizeBitChunk y-#ifndef BITSTRING_BIGENDIAN          -          t = List.foldl' (+) w-            $ zipWith shiftL (bitChunkTo01List x) [k..]-#else-          -- also, fuck. and fuck, again.-          u = 7-k-          t = List.foldl' (+) w-            $ zipWith shiftL (bitChunkTo01List x) [u,u-1..]-#endif-  worker rem [] = case rem of-    Nothing    -> []-    Just (w,_) -> [B.singleton w] ---realizeBitStringLazy :: BitString -> L.ByteString-realizeBitStringLazy = L.fromChunks . realizeBitString'--realizeBitStringStrict :: BitString -> B.ByteString-realizeBitStringStrict = B.concat . realizeBitString'------------------------------------------------------------------------------------#ifdef WITH_QUICKCHECK--newtype Size     = Size     Int64  deriving Show-newtype BoolList = BoolList [Bool] deriving Show--newtype SearchFor = SearchFor BitString deriving Show--instance Arbitrary Size where-  arbitrary = Size <$> (fromIntegral :: Int -> Int64) <$> choose (0,64) -- 192)--instance Arbitrary BoolList where-  arbitrary = do-    Size k <- arbitrary -    BoolList <$> vector (fromIntegral k) --instance Arbitrary BitChunk where-  arbitrary = do-    k <- choose (0,24) :: Gen Int-    l <- choose (0,15) :: Gen Int-    BoolList list <- arbitrary-    let bits1 = bitChunkDrop (fromIntegral k) $ bitChunkFromList list-        len = bitChunkLength bits1-        bits2 = bitChunkTake (max 0 $ len - fromIntegral l) bits1-    return bits2---- with 48 bits, it's unlikely that there are other random appearances -instance Arbitrary SearchFor where-  arbitrary = do-    b <- arbitrary-    let l = length b-    if l >= 48 && l < 96 -      then return (SearchFor b) -      else arbitrary-    -instance Arbitrary BitString where-  arbitrary = do-    k <- choose (0,7)-    BitString <$> vector k --runAllTest :: IO ()     -runAllTest = do-  let mytest (text,prop) = do-        print text-        quickCheck prop-        -  mytest ("fromToList"    , prop_fromToList )-  mytest ("toFromList"    , prop_toFromList )-  mytest ("append"       , prop_append     )-  mytest ("drop"         , prop_drop       )-  mytest ("take"         , prop_take       )-  mytest ("dropChunk"    , prop_dropChunk  )-  mytest ("takeChunk"    , prop_takeChunk  )-  mytest ("realign"      , prop_realign    )-  mytest ("realizeChunk" , prop_realizeChunk )-  mytest ("realize"      , prop_realize      )-  mytest ("realize"      , prop_realize      )-  mytest ("realize"      , prop_realize      )-  mytest ("realize"      , prop_realize      )-  mytest ("realizeLen"   , prop_realizeLen   )--  mytest ("findSubstring1"  , prop_findSubstring1  )-  mytest ("findSubstring1"  , prop_findSubstring1  )-  mytest ("findSubstring1"  , prop_findSubstring1  )-  mytest ("findSubstring1"  , prop_findSubstring1  )-  mytest ("findSubstring1a" , prop_findSubstring1a )-  mytest ("findSubstring1b" , prop_findSubstring1b )-  mytest ("findSubstring2"  , prop_findSubstring2  )--prop_fromToList :: BitString -> Bool-prop_fromToList bits = fromList (toList bits) == bits--prop_toFromList :: BoolList -> Bool-prop_toFromList (BoolList list) = toList (fromList list) == list--prop_append :: [BitString] -> Bool-prop_append xs = toList (concat xs) == List.concat (map toList xs)--prop_drop :: Size -> BitString -> Bool-prop_drop (Size k) xs = toList (drop k xs) == List.drop (fromIntegral k) (toList xs)--prop_take :: Size -> BitString -> Bool-prop_take (Size k) xs = toList (take k xs) == List.take (fromIntegral k) (toList xs)--prop_dropChunk :: Size -> BitChunk -> Bool-prop_dropChunk (Size k) xs = bitChunkToList (bitChunkDrop k xs) == List.drop (fromIntegral k) (bitChunkToList xs)--prop_takeChunk :: Size -> BitChunk -> Bool-prop_takeChunk (Size k) xs = bitChunkToList (bitChunkTake k xs) == List.take (fromIntegral k) (bitChunkToList xs)--prop_realign :: BitChunk -> Bool-prop_realign chunk = realignBitChunk chunk == chunk--prop_realizeChunk :: BitChunk -> Bool-prop_realizeChunk chunk = append (bitString whole) (BitString [end]) == BitString [chunk] where-  (whole,remain) = realizeBitChunk chunk-  end = case remain of-    Nothing -> emptyBitChunk-    Just (w,k) -> BitChunk 0 (fromIntegral k) (B.singleton w)--prop_realize :: BitString -> Bool-prop_realize bits = let n = length bits in unsafeBitString' 0 n (realizeBitStringStrict bits) == bits--prop_realizeLen :: BitString -> Bool-prop_realizeLen bits = let n = length bits in div (n+7) 8 == (fromIntegral $ B.length $ realizeBitStringStrict bits) -    -prop_findSubstring1 :: SearchFor -> BitString -> BitString -> Bool-prop_findSubstring1 (SearchFor what) pre post = findSubstring what big == Just (length pre) where-  big = concat [ pre , what , post ] --prop_findSubstring1a :: SearchFor -> BitString -> Bool-prop_findSubstring1a (SearchFor what) pre = findSubstring what big == Just (length pre) where-  big = concat [ pre , what ] --prop_findSubstring1b :: SearchFor -> BitString -> Bool-prop_findSubstring1b (SearchFor what) post = findSubstring what big == Just 0 where-  big = concat [ what , post  ] --prop_findSubstring2 :: SearchFor -> BitString -> BitString -> Bool-prop_findSubstring2 (SearchFor what) pre post = findSubstring what big == Nothing where-  big = concat [ pre , post ] ---------  -{-  -test = BitString xxx--xxx =-  [ BitChunk 17 49 (mypack "9\176N\152%\f\STX\144\ETX")-  , BitChunk 22 50 (mypack "\148\&6\184\RS\134\144+\241\210")-  , BitChunk 0 0 (mypack "")-  , BitChunk 0 0 (mypack "")-  , BitChunk 0 9 (mypack "$\NUL")-  ]  - -yyy = map (bitChunk) $ realizeBitString' test--}--{--let what = (BitString [BitChunk 0 16 (mypack "c\229W"),BitChunk 0 0 (mypack ""),BitChunk 20 13 (mypack "\169\188\"\DLEf\EOT"),BitChunk 0 0 (mypack ""),BitChunk 3 9 (mypack "/\FS+"),BitChunk 21 26 (mypack "&,\159\249\158&h\STX"),BitChunk 0 0 (mypack "")])--let pre = BitString [BitChunk 3 13 (mypack "\245\200\180\NUL"),BitChunk 17 4 (mypack "{\SI\DC2"),BitChunk 24 33 (mypack "\207\135W\RS\240\180{\SOH")]--let post = BitString [BitChunk 16 19 (mypack "e\142\&0z\209m\NUL"),BitChunk 14 27 (mypack "\248m\207\146\&8\224\NUL")]--}+-- --------  -#endif // WITH_QUICKCHECK+module Data.BitString.BigEndian  ---------------------------------------------------------------------------------+#include "BitString.inc"
− Setup.lhs
@@ -1,39 +0,0 @@-#! /usr/bin/env runhaskell->-> import Control.Monad-> import Distribution.Simple-> import Distribution.PackageDescription-> import System.IO-> import System.Directory->-> copyFileWithPrefix src tgt prefix = ->   readFile src >>= \txt -> writeFile tgt (prefix ++ txt)->-> copyFiles srcdir tgtdir prefix = do->   files <- getDirectoryContents srcdir->   forM_ files $ \fname -> do->     let src = srcdir ++ fname->         tgt = tgtdir ++ fname->     doesFileExist src >>= \b -> when b $ copyFileWithPrefix src tgt prefix->     doesDirectoryExist src>>= \b -> when ( b && fname /= "." && fname /= ".." ) $ do->       createDirectoryIfMissing False tgt->       copyFiles (src ++ "/") (tgt ++ "/") prefix->-> thePrefix = "-- DO NOT EDIT THIS FILE\n{-# OPTIONS_GHC -DBITSTRING_BIGENDIAN #-}\n"->-> myPreBuildHook args buildflags = do->   createDirectoryIfMissing False "Data/BitString"->   copyFileWithPrefix "Data/BitString.hs" "Data/BitString/BigEndian.hs" thePrefix->   return $ emptyHookedBuildInfo  ->-> myPostCleanHook args cleanflags pdep mlocalbuildinfo = do->   removeDirectoryRecursive "Data/BitString"->-> myUserHooks = simpleUserHooks ->   { preBuild = myPreBuildHook ->   , postClean = myPostCleanHook->   }->-> main = do->   defaultMainWithHooks myUserHooks->
bitstring.cabal view
@@ -1,18 +1,20 @@+Cabal-Version:       2.2 Name:                bitstring-Version:             0.0.0+Version:             0.0.1 Synopsis:            Lazy bit strings Description:         Lazy bit strings, built on the top of bytestrings.-License:             BSD3+License:             BSD-3-Clause License-file:        LICENSE Author:              Balazs Komuves Maintainer:          bkomuves (plus) hackage (at) gmail (dot) com-Homepage:            http://code.haskell.org/~bkomuves/+Homepage:            https://github.com/bkomuves/bitstring Stability:           Experimental Category:            Data-Tested-With:         GHC == 6.10.1 -Cabal-Version:       >= 1.6-Build-Type:          Custom+Tested-With:         GHC == 9.12.1+Build-Type:          Simple +extra-source-files:  ./include/BitString.inc+ Flag base4   Description: Base v4  @@ -20,6 +22,7 @@   Description: Build with QuickCheck test. Note that Show instances will be different.   Default: False + Library    if flag(base4)@@ -33,14 +36,16 @@     Build-Depends:        QuickCheck == 2.*     cpp-options:          -DWITH_QUICKCHECK -  Build-Depends:       bytestring+  Build-Depends:       bytestring >= 0.10 && < 0.13      Exposed-Modules:     Data.BitString,                        Data.BitString.BigEndian      Hs-Source-Dirs:      .-    -  Extensions:          CPP-  ghc-options:         -Wall +  include-dirs:        ./include++  default-language:    Haskell2010+  other-extensions:    CPP+  ghc-options:         -Wno-name-shadowing -Wno-duplicate-exports      
+ include/BitString.inc view
@@ -0,0 +1,688 @@++  (+    BitString+    --+  , empty+  , bitString+  , bitStringLazy+  , unsafeBitString'+    --+  , showBitString+  , debugShowBitString+    --+  , take+  , drop+  , splitAt+  , append+  , concat+    --+  , toList+  , fromList+  , to01List+  , from01List+    --+  , null+  , length+    --+  , foldl'+  , findSubstring+    --+  , realizeBitStringLazy+  , realizeBitStringStrict+  , realizeBitString'  +    --+#ifdef WITH_QUICKCHECK+  , runAllTest+  , runAllTest'+  , BitChunk (..)+  , BitString ( MkBitString )+  , showBitChunk+  , debugShowBitChunk+  , mypack+  , prop_fromToList +  , prop_toFromList +  , prop_append     +  , prop_drop       +  , prop_take       +  , prop_dropChunk  +  , prop_takeChunk  +  , prop_realign    +  , prop_realizeChunk +  , prop_realize      +  , prop_realizeLen      +  , prop_findSubstring1 +  , prop_findSubstring1a +  , prop_findSubstring1b +  , prop_findSubstring2 +#endif        +  )+  where+  +--------------------------------------------------------------------------------++import qualified Prelude+import Prelude hiding (take,drop,last,length,splitAt,concat,null,rem,init,foldl')++import Control.Monad+import Control.Applicative hiding ( empty )++import Data.Bits ()+import Data.Int  ()+import Data.Word ()+import Data.Char (ord)+import Data.Maybe+import qualified Data.List as List++import Data.ByteString (ByteString)+import qualified Data.ByteString          as B+import qualified Data.ByteString.Internal as B+import qualified Data.ByteString.Lazy     as L++#ifdef WITH_QUICKCHECK+import Test.QuickCheck hiding ( (.&.) )+import qualified Data.ByteString.Char8 as BC+#endif++import Foreign+import System.IO.Unsafe++--------------------------------------------------------------------------------++flippedFoldM_ :: Monad m => a -> [b] -> (a -> b -> m a) -> m () +flippedFoldM_ x ys f = foldM_ f x ys++flippedFoldM ::  Monad m => a -> [b] -> (a -> b -> m a) -> m a +flippedFoldM x ys f = foldM f x ys++--------------------------------------------------------------------------------++#ifdef BITSTRING_BIGENDIAN++{-+bitReverseWord8_naive :: Word8 -> Word8+bitReverseWord8_naive x +  = shiftR (x .&. 0x80) 7+  + shiftR (x .&. 0x40) 5+  + shiftR (x .&. 0x20) 3+  + shiftR (x .&. 0x10) 1+  + shiftL (x .&. 0x08) 1+  + shiftL (x .&. 0x04) 3+  + shiftL (x .&. 0x02) 5+  + shiftL (x .&. 0x01) 7+     +bitReverseWord8_table :: ByteString     +bitReverseWord8_table = B.pack $ map reverseWord8_naive [0..255]++bitReverseWord8 :: Word8 -> Word8+bitReverseWord8 = U.unsafeIndex reverseWord8_table . fromIntegral+-}++byteReverseWord32 :: Word32 -> Word32+byteReverseWord32 w +  = shiftR w 24 +  + shiftR w 8  .&. 0x0000ff00 +  + shiftL w 8  .&. 0x00ff0000 +  + shiftL w 24++#endif +-- #define BITSTRING_BIGENDIAN++--------------------------------------------------------------------------------++data BitChunk = MkBitChunk+  { bitChunkOffset :: !Int64+  , bitChunkLength :: !Int64+  , bitChunkData   :: !ByteString+  }++mypack :: String -> ByteString+mypack = B.pack . map c2w where+  c2w = fromIntegral . ord++debugShowBitChunk :: BitChunk -> String+debugShowBitChunk (MkBitChunk ofs len dat) = "BitChunk " ++ show ofs ++ " " ++ show len ++ " (mypack " ++ show dat ++ ")"++showBitChunk :: BitChunk -> String+showBitChunk chunk = "MkBitChunk <" ++ map f (bitChunkTo01List chunk) ++ ">" where +  f 0 = '0'+  f 1 = '1'++instance Show BitChunk where+  show = showBitChunk++emptyBitChunk :: BitChunk+emptyBitChunk = MkBitChunk 0 0 B.empty++{-  +bitChunk' :: Int64 -> ByteString -> BitChunk  +bitChunk' ofs bs = MkBitString ofs (len-ofs) bs where +  len = 8 * fromIntegral (B.length bs)+-}++-- | warning! no boundary checks+unsafeBitChunk'  +  :: Int64        -- ^ offset +  -> Int64        -- ^ length+  -> ByteString   -- ^ source+  -> BitChunk +unsafeBitChunk' ofs len dat = MkBitChunk ofs len dat where ++bitChunk :: ByteString -> BitChunk  +bitChunk bs = unsafeBitChunk' 0 (8 * fromIntegral (B.length bs)) bs++--------------------------------------------------------------------------------++bitChunkDrop :: Int64 -> BitChunk -> BitChunk+bitChunkDrop k (MkBitChunk ofs len dat) = if k<len+  then MkBitChunk (ofs+k) (len-k) dat+  else emptyBitChunk++bitChunkTake :: Int64 -> BitChunk -> BitChunk+bitChunkTake k bc@(MkBitChunk ofs len dat) +  | k==0      = emptyBitChunk+  | k<=len    = MkBitChunk ofs k dat+  | otherwise = bc++-- TODO: better implementation    +splitBitChunkAt :: Int64 -> BitChunk -> (BitChunk,BitChunk)    +splitBitChunkAt k b = (bitChunkTake k b, bitChunkDrop k b)  ++--------------------------------------------------------------------------------++{-# INLINE boolToWord8 #-}+boolToWord8 :: Bool -> Word8+boolToWord8 bool = case bool of+  True  -> 1+  False -> 0++{-# INLINE word8ToBool #-}+word8ToBool :: Word8 -> Bool+word8ToBool w = (w/=0)++--------------------------------------------------------------------------------++unsafeLookupBitChunk :: BitChunk -> Int64 -> Bool+unsafeLookupBitChunk chunk j = unsafeLookupBitChunk01 chunk j /= 0++unsafeLookupBitChunk01 :: BitChunk -> Int64 -> Word8+unsafeLookupBitChunk01 (MkBitChunk ofs len dat) j = bit where+  (n,k) = divMod (ofs+j) 8+  byte = B.index dat (fromIntegral n)+#ifndef BITSTRING_BIGENDIAN+  bit = ((shiftR byte (fromIntegral k)) .&. 1) +#else+  bit = ((shiftR byte (fromIntegral (7-k))) .&. 1) +#endif++--------------------------------------------------------------------------------+  +bitChunkToList :: BitChunk -> [Bool]+bitChunkToList chunk@(MkBitChunk ofs len dat) = +  [ unsafeLookupBitChunk chunk k | k<-[0..len-1] ]++bitChunkFromList :: [Bool] -> BitChunk+bitChunkFromList bits = MkBitChunk 0 (fromIntegral len) (B.pack bytes) where+  (len,bytes) = worker bits+  worker []   = ( 0, [] )+  worker bits = ( len' + List.length this , byte:ys ) where+    (this,rest) = List.splitAt 8 bits+#ifndef BITSTRING_BIGENDIAN+    byte = List.foldl' (+) 0 $ zipWith shiftL (map boolToWord8 this) [0..7]+#else+    byte = List.foldl' (+) 0 $ zipWith shiftL (map boolToWord8 this) [7,6..0]+#endif+    (len' , ys) = worker rest++bitChunkTo01List :: BitChunk -> [Word8]+bitChunkTo01List chunk@(MkBitChunk ofs len dat) = +  [ unsafeLookupBitChunk01 chunk k | k<-[0..len-1] ]++bitChunkFrom01List :: [Word8] -> BitChunk+bitChunkFrom01List bits = MkBitChunk 0 (fromIntegral len) (B.pack bytes) where+  (len,bytes) = worker bits+  worker []   = ( 0, [] )+  worker bits = ( len' + List.length this , byte:ys ) where+    (this,rest) = List.splitAt 8 bits+#ifndef BITSTRING_BIGENDIAN+    byte = List.foldl' (+) 0 $ zipWith shiftL (map (.&. 1) this) [0..7]+#else+    byte = List.foldl' (+) 0 $ zipWith shiftL (map (.&. 1) this) [7,6..0]+#endif+    (len' , ys) = worker rest+    +instance Eq BitChunk where+  -- | warning! very slow! TODO: make a better routine+--  (==) :: BitChunk -> BitChunk -> Bool+  (==) = bitChunkIsEqualNaive+    +  -- | warning! very slow! TODO: make a better routine+bitChunkIsEqualNaive ::  BitChunk -> BitChunk -> Bool+bitChunkIsEqualNaive x y = bitChunkToList x == bitChunkToList y++--------------------------------------------------------------------------------++-- | Creates a new 'BitChunk' with offset field 0+realignBitChunk :: BitChunk -> BitChunk +realignBitChunk (MkBitChunk ofs len dat) = +  MkBitChunk 0 len $ case ofsFrac of +    0 -> dat'+    _ -> B.pack $ B.zipWith f dat' (B.snoc (B.tail dat') 0) +  where +    ofsFrac2 = 8 - ofsFrac+#ifndef BITSTRING_BIGENDIAN+    f b1 b2 = shiftR b1 (fromIntegral ofsFrac) + shiftL b2 (fromIntegral ofsFrac2)+#else+    f b1 b2 = shiftL b1 (fromIntegral ofsFrac) + shiftR b2 (fromIntegral ofsFrac2)+#endif    +    dat' = B.drop (fromIntegral ofsInt) dat+    (ofsInt, ofsFrac) = divMod ofs 8 +    +realizeBitChunk :: BitChunk -> (ByteString, Maybe (Word8,Int))+realizeBitChunk orig = (whole, end) where+  chunk@(MkBitChunk 0 len dat) = realignBitChunk orig+  (n,k) = divMod len 8+  whole = B.take (fromIntegral n) dat+  end = case k of+    0 -> Nothing+    _ -> let w' = B.index dat (fromIntegral n)+#ifndef BITSTRING_BIGENDIAN+             mask = 2^k - 1 :: Word8+             w = w' .&. mask+#else+-- and at this point, the the inventor and users of big endianness deserve an extra fuck!+             kk = fromIntegral k :: Int+             mask = shiftL (2^kk-1) (8-kk) +             w = w' .&. mask+#endif+         in  Just (w, fromIntegral k) +           +--------------------------------------------------------------------------------++unBitString :: BitString -> [BitChunk]+unBitString (MkBitString xs) = xs+  +newtype BitString = MkBitString [BitChunk] ++debugShowBitString :: BitString -> String+debugShowBitString (MkBitString list) = "MkBitString " ++ show list++showBitString :: BitString -> String+showBitString bits = "MkBitString <" ++ map f (to01List bits) ++ ">" where +  f 0 = '0'+  f 1 = '1'+  f _ = error "BitString/show: impossible"++instance Show BitString where +  show = showBitString++empty :: BitString+empty = MkBitString [] ++-- | Create a 'BitString' from a portion of a 'ByteString'.+-- Warning! No boundary checks are performed!+unsafeBitString' +  :: Int64       -- ^ offset +  -> Int64       -- ^ length+  -> ByteString  -- ^ source +  -> BitString+unsafeBitString' ofs len bs = MkBitString [unsafeBitChunk' ofs len bs] ++-- | Create a 'BitString' from a strict 'ByteString'+bitString :: ByteString -> BitString  +bitString bs = unsafeBitString' 0 (8 * fromIntegral (B.length bs)) bs++-- | Create a 'BitString' from a lazy 'ByteString'+bitStringLazy :: L.ByteString -> BitString  +bitStringLazy = concat . map bitString . L.toChunks ++drop :: Int64 -> BitString -> BitString+drop k (MkBitString cs) = MkBitString (worker k cs) where+  worker _ [] = []+  worker k (MkBitChunk ofs len dat : cs) = if k < len +    then MkBitChunk (ofs+k) (len-k) dat : cs+    else worker (k-len) cs++take :: Int64 -> BitString -> BitString+take k (MkBitString cs) = MkBitString (worker k cs) where+  worker 0 _  = []+  worker _ [] = []+  worker k (c@(MkBitChunk ofs len dat) : cs) = if k <= len +    then [ MkBitChunk ofs k dat ]+    else c : worker (k-len) cs++-- TODO: better implementation    +splitAt :: Int64 -> BitString -> (BitString,BitString)    +splitAt k b = (take k b, drop k b)++append :: BitString -> BitString -> BitString    +append (MkBitString chunks1) (MkBitString chunks2) = MkBitString (chunks1 ++ chunks2)++concat :: [BitString] -> BitString+concat xs = case xs of+  [] -> empty+  _  -> (MkBitString . List.concat . map unBitString) xs   -- hmm how strict or lazy this should be?++toList :: BitString -> [Bool]+toList (MkBitString chunks) = List.concatMap bitChunkToList chunks++fromList :: [Bool] -> BitString+fromList digits = MkBitString [bitChunkFromList digits]++to01List :: BitString -> [Word8]+to01List (MkBitString chunks) = List.concatMap bitChunkTo01List chunks++from01List :: [Word8] -> BitString+from01List digits = MkBitString [bitChunkFrom01List digits]++--------------------------------------------------------------------------------++length :: BitString -> Int64+length (MkBitString chunks) = List.foldl' (+) 0 (map bitChunkLength chunks)++null :: BitString -> Bool+null bits = (length bits == 0)++-- | warning! very slow! TODO: make a better routine+instance Eq BitString where+  -- (==) :: BitString -> BitString -> Bool+  (==) = fallbackEqual+  +-- | slow, fallback equality test, via converting to list+fallbackEqual :: BitString -> BitString -> Bool+fallbackEqual x y = (toList x == toList y)++--------------------------------------------------------------------------------++foldl' :: (a -> Bool -> a) -> a -> BitString -> a+foldl' fun init bits = List.foldl' fun init (toList bits)++--------------------------------------------------------------------------------++findSubstring+  :: BitString    -- ^ the string to search for+  -> BitString    -- ^ the string to search in+  -> Maybe Int64  -- ^ the index of the first substring, if exists+findSubstring = findSubstring32++-- the basic unit is a Word32+findSubstring32 +  :: BitString    -- ^ the string to search for+  -> BitString    -- ^ the string to search in+  -> Maybe Int64  -- ^ the index of the first substring, if exists+findSubstring32 small large = +  unsafePerformIO $ do+    withForeignPtr fptr_b_small $ \p'' -> do+      let p' = (plusPtr p'' ofs_b_small) :: Ptr Word8+      allocaArray (k+1) $ \q -> allocaArray (k+1) $ \p -> do+        -- we store in 'q' the last 'm' bits+        -- and in 'p' the bits we are searching for+        +#ifndef BITSTRING_BIGENDIAN+        let p8 = (castPtr :: Ptr Word32 -> Ptr Word8) p+        forM_ [0..len_b_small-1] $ \i -> do { x <- peekElemOff p' i ; pokeElemOff p8 i x }+        peekElemOff p k >>= \x -> pokeElemOff p k (x .&. mask)+        pokeElemOff q k 0   -- this is quite important, because of the shifts!+#else +        pokeElemOff p k 0   -- just to be on the safe side+        let p8 = (castPtr :: Ptr Word32 -> Ptr Word8) p+        forM_ [0..len_b_small-1] $ \i -> do { x <- peekElemOff p' i ; pokeElemOff p8 i x }+        forM_ [0..k] $ \j -> do { y <- peekElemOff p j ; pokeElemOff p j (byteReverseWord32 y) }+        peekElemOff p k >>= \x -> pokeElemOff p k (x .&. mask)+        pokeElemOff q k 0   -- this is quite important, because of the shifts!+#endif         ++{-+        print (m,m32)+        print len_b_small+        print hmm+        peekArray ((k+1)*4) (castPtr p :: Ptr Word8) >>= print       +-}++        worker p q 0 (to01List large)+      +  where+    m = length small+    m32 = fromIntegral (mod m 32) :: Int    +    d32 = fromIntegral (div m 32) :: Int++    hmm :: (Int, Word32, Int)+    hmm@(k,mask,initShift) = case m32 of+#ifndef BITSTRING_BIGENDIAN    +      0 -> ( d32 - 1  , 0xffffffff     , 31                          )+      _ -> ( d32      , 2^m32  - 1     , fromIntegral (mod (m-1) 32) )+#else+      0 -> ( d32 - 1  , 0xffffffff                , 0                              )  +      _ -> ( d32      , shiftL (2^m32-1) (32-m32) , fromIntegral ( 32 - mod m 32 ) )+#endif    ++    b_small = realizeBitStringStrict small+    (fptr_b_small, ofs_b_small, len_b_small) = B.toForeignPtr b_small+    +    worker :: Ptr Word32 -> Ptr Word32 -> Int64 -> [Word8] -> IO (Maybe Int64)+    worker !p !q !pos !bits = do++--      peekArray ((k+1)*4) (castPtr q :: Ptr Word8) >>= print       ++      conds <- forM [0..k-1] $ \j -> do { x <- peekElemOff p j ; y <- peekElemOff q j ; return (x==y) }+      cond  <- do { x <- peekElemOff p k ; y <- peekElemOff q k ; return (x .&. mask == y .&. mask) }+      if and (cond:conds) && pos >= m+        then return (Just (pos - m))+        else case bits of+          [] -> return Nothing+          (b:bs) -> do++#ifndef BITSTRING_BIGENDIAN+            let init_cr = (fromIntegral b , initShift)+            flippedFoldM_ init_cr [k,k-1..0] $ \(c,r) j -> do+              y <- peekElemOff q j+              let cr' = ( y .&. 1 , 31 )+              pokeElemOff q j (shiftR y 1 + shiftL c r)+              return cr'+            worker p q (pos+1) bs +#else+            let init_cr = (fromIntegral b , initShift)+            flippedFoldM_ init_cr [k,k-1..0] $ \(c,r) j -> do+              y <- peekElemOff q j+              let cr' = ( shiftR y 31 , 0 )+              pokeElemOff q j (shiftL y 1 + shiftL c r)+              return cr'+            worker p q (pos+1) bs +#endif+      +--------------------------------------------------------------------------------++realizeBitString' :: BitString -> [ByteString]   +realizeBitString' (MkBitString chunks) = worker Nothing chunks where+  worker :: Maybe (Word8,Int) -> [BitChunk] -> [ByteString]+  worker rem (b:bs) = +    case rem of +      Nothing -> +        let (s, rem') = realizeBitChunk b+        in  s : worker rem' bs+      Just (w,k) -> +        if r >= q+          then B.singleton t : s : worker rem' bs+               -- (B.cons t s) : worker rem' bs+          else worker (Just (t, k+fromIntegral r)) bs+        where+          q = 8 - fromIntegral k+          r = bitChunkLength b+          (x,y) = splitBitChunkAt q b+          (s, rem') = realizeBitChunk y+#ifndef BITSTRING_BIGENDIAN          +          t = List.foldl' (+) w+            $ zipWith shiftL (bitChunkTo01List x) [k..]+#else+          -- also, fuck. and fuck, again.+          u = 7-k+          t = List.foldl' (+) w+            $ zipWith shiftL (bitChunkTo01List x) [u,u-1..]+#endif+  worker rem [] = case rem of+    Nothing    -> []+    Just (w,_) -> [B.singleton w] +++realizeBitStringLazy :: BitString -> L.ByteString+realizeBitStringLazy = L.fromChunks . realizeBitString'++realizeBitStringStrict :: BitString -> B.ByteString+realizeBitStringStrict = B.concat . realizeBitString'++--------------------------------------------------------------------------------++#ifdef WITH_QUICKCHECK++newtype Size     = Size     Int64  deriving Show+newtype BoolList = BoolList [Bool] deriving Show++newtype SearchFor = SearchFor BitString deriving Show++instance Arbitrary Size where+  arbitrary = Size <$> (fromIntegral :: Int -> Int64) <$> choose (0,64) -- 192)++instance Arbitrary BoolList where+  arbitrary = do+    Size k <- arbitrary +    BoolList <$> vector (fromIntegral k) ++instance Arbitrary BitChunk where+  arbitrary = do+    k <- choose (0,24) :: Gen Int+    l <- choose (0,15) :: Gen Int+    BoolList list <- arbitrary+    let bits1 = bitChunkDrop (fromIntegral k) $ bitChunkFromList list+        len = bitChunkLength bits1+        bits2 = bitChunkTake (max 0 $ len - fromIntegral l) bits1+    return bits2++-- with 48 bits, it's unlikely that there are other random appearances +instance Arbitrary SearchFor where+  arbitrary = do+    b <- arbitrary+    let l = length b+    if l >= 48 && l < 96 +      then return (SearchFor b) +      else arbitrary+    +instance Arbitrary BitString where+  arbitrary = do+    k <- choose (0,7)+    MkBitString <$> vector k ++runAllTest :: IO ()     +runAllTest = runAllTest' 500++runAllTest' :: Int -> IO ()     +runAllTest' n = do+  let mytest (text,prop) = do+        putStr text+        putStr (": " ++ replicate (20 - Prelude.length text) ' ')+        quickCheckWith (stdArgs { maxSuccess = n }) prop+        +  mytest ("fromToList"   , prop_fromToList )+  mytest ("toFromList"   , prop_toFromList )+  mytest ("append"       , prop_append     )+  mytest ("drop"         , prop_drop       )+  mytest ("take"         , prop_take       )+  mytest ("dropChunk"    , prop_dropChunk  )+  mytest ("takeChunk"    , prop_takeChunk  )+  mytest ("realign"      , prop_realign    )+  mytest ("realizeChunk" , prop_realizeChunk )+  mytest ("realize"      , prop_realize      )+  mytest ("realize"      , prop_realize      )+  mytest ("realize"      , prop_realize      )+  mytest ("realize"      , prop_realize      )+  mytest ("realizeLen"   , prop_realizeLen   )++  mytest ("findSubstring1"  , prop_findSubstring1  )+  mytest ("findSubstring1"  , prop_findSubstring1  )+  mytest ("findSubstring1"  , prop_findSubstring1  )+  mytest ("findSubstring1"  , prop_findSubstring1  )+  mytest ("findSubstring1a" , prop_findSubstring1a )+  mytest ("findSubstring1b" , prop_findSubstring1b )+  mytest ("findSubstring2"  , prop_findSubstring2  )++prop_fromToList :: BitString -> Bool+prop_fromToList bits = fromList (toList bits) == bits++prop_toFromList :: BoolList -> Bool+prop_toFromList (BoolList list) = toList (fromList list) == list++prop_append :: [BitString] -> Bool+prop_append xs = toList (concat xs) == List.concat (map toList xs)++prop_drop :: Size -> BitString -> Bool+prop_drop (Size k) xs = toList (drop k xs) == List.drop (fromIntegral k) (toList xs)++prop_take :: Size -> BitString -> Bool+prop_take (Size k) xs = toList (take k xs) == List.take (fromIntegral k) (toList xs)++prop_dropChunk :: Size -> BitChunk -> Bool+prop_dropChunk (Size k) xs = bitChunkToList (bitChunkDrop k xs) == List.drop (fromIntegral k) (bitChunkToList xs)++prop_takeChunk :: Size -> BitChunk -> Bool+prop_takeChunk (Size k) xs = bitChunkToList (bitChunkTake k xs) == List.take (fromIntegral k) (bitChunkToList xs)++prop_realign :: BitChunk -> Bool+prop_realign chunk = realignBitChunk chunk == chunk++prop_realizeChunk :: BitChunk -> Bool+prop_realizeChunk chunk = append (bitString whole) (MkBitString [end]) == MkBitString [chunk] where+  (whole,remain) = realizeBitChunk chunk+  end = case remain of+    Nothing -> emptyBitChunk+    Just (w,k) -> MkBitChunk 0 (fromIntegral k) (B.singleton w)++prop_realize :: BitString -> Bool+prop_realize bits = let n = length bits in unsafeBitString' 0 n (realizeBitStringStrict bits) == bits++prop_realizeLen :: BitString -> Bool+prop_realizeLen bits = let n = length bits in div (n+7) 8 == (fromIntegral $ B.length $ realizeBitStringStrict bits) +    +prop_findSubstring1 :: SearchFor -> BitString -> BitString -> Bool+prop_findSubstring1 (SearchFor what) pre post = findSubstring what big == Just (length pre) where+  big = concat [ pre , what , post ] ++prop_findSubstring1a :: SearchFor -> BitString -> Bool+prop_findSubstring1a (SearchFor what) pre = findSubstring what big == Just (length pre) where+  big = concat [ pre , what ] ++prop_findSubstring1b :: SearchFor -> BitString -> Bool+prop_findSubstring1b (SearchFor what) post = findSubstring what big == Just 0 where+  big = concat [ what , post  ] ++prop_findSubstring2 :: SearchFor -> BitString -> BitString -> Bool+prop_findSubstring2 (SearchFor what) pre post = findSubstring what big == Nothing where+  big = concat [ pre , post ] ++------+  +{-  +test = BitString xxx++xxx =+  [ BitChunk 17 49 (mypack "9\176N\152%\f\STX\144\ETX")+  , BitChunk 22 50 (mypack "\148\&6\184\RS\134\144+\241\210")+  , BitChunk 0 0 (mypack "")+  , BitChunk 0 0 (mypack "")+  , BitChunk 0 9 (mypack "$\NUL")+  ]  + +yyy = map (bitChunk) $ realizeBitString' test+-}++{-+let what = (BitString [BitChunk 0 16 (mypack "c\229W"),BitChunk 0 0 (mypack ""),BitChunk 20 13 (mypack "\169\188\"\DLEf\EOT"),BitChunk 0 0 (mypack ""),BitChunk 3 9 (mypack "/\FS+"),BitChunk 21 26 (mypack "&,\159\249\158&h\STX"),BitChunk 0 0 (mypack "")])++let pre = BitString [BitChunk 3 13 (mypack "\245\200\180\NUL"),BitChunk 17 4 (mypack "{\SI\DC2"),BitChunk 24 33 (mypack "\207\135W\RS\240\180{\SOH")]++let post = BitString [BitChunk 16 19 (mypack "e\142\&0z\209m\NUL"),BitChunk 14 27 (mypack "\248m\207\146\&8\224\NUL")]+-}++------+  +#endif +-- #define WITH_QUICKCHECK++--------------------------------------------------------------------------------