packages feed

bitstream 0.1 → 0.2

raw patch · 7 files changed

+1513/−827 lines, 7 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Data.Bitstream: instance Bitstream (Packet d) => Bitstream (Bitstream d)
- Data.Bitstream: instance Bitstream (Packet d) => Eq (Bitstream d)
- Data.Bitstream: instance Bitstream (Packet d) => Monoid (Bitstream d)
- Data.Bitstream: instance Bitstream (Packet d) => Ord (Bitstream d)
- Data.Bitstream.Lazy: instance Bitstream (Packet d) => Bitstream (Bitstream d)
- Data.Bitstream.Lazy: instance Bitstream (Packet d) => Eq (Bitstream d)
- Data.Bitstream.Lazy: instance Bitstream (Packet d) => Monoid (Bitstream d)
- Data.Bitstream.Lazy: instance Bitstream (Packet d) => Ord (Bitstream d)
+ Data.Bitstream: fromBits :: (Integral β, Bits β, Bitstream α) => β -> α
+ Data.Bitstream: fromNBits :: (Integral n, Integral β, Bits β, Bitstream α) => n -> β -> α
+ Data.Bitstream: instance Bitstream (Bitstream Left)
+ Data.Bitstream: instance Bitstream (Bitstream Right)
+ Data.Bitstream: instance Bitstream (Bitstream d) => Eq (Bitstream d)
+ Data.Bitstream: instance Bitstream (Bitstream d) => Monoid (Bitstream d)
+ Data.Bitstream: instance Bitstream (Bitstream d) => Ord (Bitstream d)
+ Data.Bitstream: streamPackets :: Bitstream d -> Stream (Packet d)
+ Data.Bitstream: toBits :: (Bitstream α, Bits β) => α -> β
+ Data.Bitstream: unsafeFromPackets :: Bitstream (Packet d) => Int -> Vector (Packet d) -> Bitstream d
+ Data.Bitstream: unstreamPackets :: Bitstream (Packet d) => Stream (Packet d) -> Bitstream d
+ Data.Bitstream.Generic: basicAppend :: Bitstream α => α -> α -> α
+ Data.Bitstream.Generic: basicConcat :: Bitstream α => [α] -> α
+ Data.Bitstream.Generic: basicCons :: Bitstream α => Bool -> α -> α
+ Data.Bitstream.Generic: basicCons' :: Bitstream α => Bool -> α -> α
+ Data.Bitstream.Generic: basicDrop :: (Bitstream α, Integral n) => n -> α -> α
+ Data.Bitstream.Generic: basicDropWhile :: Bitstream α => (Bool -> Bool) -> α -> α
+ Data.Bitstream.Generic: basicFilter :: Bitstream α => (Bool -> Bool) -> α -> α
+ Data.Bitstream.Generic: basicFromNBits :: (Bitstream α, Integral n, Integral β, Bits β) => n -> β -> α
+ Data.Bitstream.Generic: basicInit :: Bitstream α => α -> α
+ Data.Bitstream.Generic: basicMap :: Bitstream α => (Bool -> Bool) -> α -> α
+ Data.Bitstream.Generic: basicPartition :: Bitstream α => (Bool -> Bool) -> α -> (α, α)
+ Data.Bitstream.Generic: basicReverse :: Bitstream α => α -> α
+ Data.Bitstream.Generic: basicScanl :: Bitstream α => (Bool -> Bool -> Bool) -> Bool -> α -> α
+ Data.Bitstream.Generic: basicSnoc :: Bitstream α => α -> Bool -> α
+ Data.Bitstream.Generic: basicStream :: Bitstream α => α -> Stream Bool
+ Data.Bitstream.Generic: basicTail :: Bitstream α => α -> α
+ Data.Bitstream.Generic: basicTake :: (Bitstream α, Integral n) => n -> α -> α
+ Data.Bitstream.Generic: basicTakeWhile :: Bitstream α => (Bool -> Bool) -> α -> α
+ Data.Bitstream.Generic: basicToBits :: (Bitstream α, Bits β) => α -> β
+ Data.Bitstream.Generic: basicUnstream :: Bitstream α => Stream Bool -> α
+ Data.Bitstream.Generic: fromBits :: (Integral β, Bits β, Bitstream α) => β -> α
+ Data.Bitstream.Generic: fromNBits :: (Integral n, Integral β, Bits β, Bitstream α) => n -> β -> α
+ Data.Bitstream.Generic: toBits :: (Bitstream α, Bits β) => α -> β
+ Data.Bitstream.Lazy: fromBits :: (Integral β, Bits β, Bitstream α) => β -> α
+ Data.Bitstream.Lazy: fromNBits :: (Integral n, Integral β, Bits β, Bitstream α) => n -> β -> α
+ Data.Bitstream.Lazy: instance Bitstream (Bitstream Left)
+ Data.Bitstream.Lazy: instance Bitstream (Bitstream Right)
+ Data.Bitstream.Lazy: instance Bitstream (Bitstream d) => Eq (Bitstream d)
+ Data.Bitstream.Lazy: instance Bitstream (Bitstream d) => Monoid (Bitstream d)
+ Data.Bitstream.Lazy: instance Bitstream (Bitstream d) => Ord (Bitstream d)
+ Data.Bitstream.Lazy: toBits :: (Bitstream α, Bits β) => α -> β
- Data.Bitstream: appendFile :: Bitstream (Packet d) => FilePath -> Bitstream d -> IO ()
+ Data.Bitstream: appendFile :: (Bitstream (Bitstream d), Bitstream (Packet d)) => FilePath -> Bitstream d -> IO ()
- Data.Bitstream: drop :: (Bitstream α, Integral n) => n -> α -> α
+ Data.Bitstream: drop :: (Integral n, Bitstream α) => n -> α -> α
- Data.Bitstream: fromPackets :: Vector (Packet d) -> Bitstream d
+ Data.Bitstream: fromPackets :: Bitstream (Packet d) => Vector (Packet d) -> Bitstream d
- Data.Bitstream: hPut :: Bitstream (Packet d) => Handle -> Bitstream d -> IO ()
+ Data.Bitstream: hPut :: (Bitstream (Bitstream d), Bitstream (Packet d)) => Handle -> Bitstream d -> IO ()
- Data.Bitstream: interact :: Bitstream (Packet d) => (Bitstream d -> Bitstream d) -> IO ()
+ Data.Bitstream: interact :: (Bitstream (Bitstream d), Bitstream (Packet d)) => (Bitstream d -> Bitstream d) -> IO ()
- Data.Bitstream: putBits :: Bitstream (Packet d) => Bitstream d -> IO ()
+ Data.Bitstream: putBits :: (Bitstream (Bitstream d), Bitstream (Packet d)) => Bitstream d -> IO ()
- Data.Bitstream: replicate :: (Bitstream α, Integral n) => n -> Bool -> α
+ Data.Bitstream: replicate :: (Integral n, Bitstream α) => n -> Bool -> α
- Data.Bitstream: take :: (Bitstream α, Integral n) => n -> α -> α
+ Data.Bitstream: take :: (Integral n, Bitstream α) => n -> α -> α
- Data.Bitstream: toByteString :: Bitstream (Packet d) => Bitstream d -> ByteString
+ Data.Bitstream: toByteString :: (Bitstream (Bitstream d), Bitstream (Packet d)) => Bitstream d -> ByteString
- Data.Bitstream: unfoldrN :: (Bitstream α, Integral n) => n -> (β -> Maybe (Bool, β)) -> β -> α
+ Data.Bitstream: unfoldrN :: (Integral n, Bitstream α) => n -> (β -> Maybe (Bool, β)) -> β -> α
- Data.Bitstream: writeFile :: Bitstream (Packet d) => FilePath -> Bitstream d -> IO ()
+ Data.Bitstream: writeFile :: (Bitstream (Bitstream d), Bitstream (Packet d)) => FilePath -> Bitstream d -> IO ()
- Data.Bitstream.Generic: drop :: (Bitstream α, Integral n) => n -> α -> α
+ Data.Bitstream.Generic: drop :: (Integral n, Bitstream α) => n -> α -> α
- Data.Bitstream.Generic: replicate :: (Bitstream α, Integral n) => n -> Bool -> α
+ Data.Bitstream.Generic: replicate :: (Integral n, Bitstream α) => n -> Bool -> α
- Data.Bitstream.Generic: take :: (Bitstream α, Integral n) => n -> α -> α
+ Data.Bitstream.Generic: take :: (Integral n, Bitstream α) => n -> α -> α
- Data.Bitstream.Generic: unfoldrN :: (Bitstream α, Integral n) => n -> (β -> Maybe (Bool, β)) -> β -> α
+ Data.Bitstream.Generic: unfoldrN :: (Integral n, Bitstream α) => n -> (β -> Maybe (Bool, β)) -> β -> α
- Data.Bitstream.Lazy: appendFile :: Bitstream (Packet d) => FilePath -> Bitstream d -> IO ()
+ Data.Bitstream.Lazy: appendFile :: (Bitstream (Bitstream d), Bitstream (Packet d)) => FilePath -> Bitstream d -> IO ()
- Data.Bitstream.Lazy: cycle :: Bitstream (Packet d) => Bitstream d -> Bitstream d
+ Data.Bitstream.Lazy: cycle :: Bitstream (Bitstream d) => Bitstream d -> Bitstream d
- Data.Bitstream.Lazy: drop :: (Bitstream α, Integral n) => n -> α -> α
+ Data.Bitstream.Lazy: drop :: (Integral n, Bitstream α) => n -> α -> α
- Data.Bitstream.Lazy: fromByteString :: Bitstream (Packet d) => ByteString -> Bitstream d
+ Data.Bitstream.Lazy: fromByteString :: Bitstream (Bitstream d) => ByteString -> Bitstream d
- Data.Bitstream.Lazy: fromChunks :: Bitstream (Packet d) => [Bitstream d] -> Bitstream d
+ Data.Bitstream.Lazy: fromChunks :: Bitstream (Bitstream d) => [Bitstream d] -> Bitstream d
- Data.Bitstream.Lazy: getContents :: Bitstream (Packet d) => IO (Bitstream d)
+ Data.Bitstream.Lazy: getContents :: Bitstream (Bitstream d) => IO (Bitstream d)
- Data.Bitstream.Lazy: hGet :: Bitstream (Packet d) => Handle -> Int -> IO (Bitstream d)
+ Data.Bitstream.Lazy: hGet :: Bitstream (Bitstream d) => Handle -> Int -> IO (Bitstream d)
- Data.Bitstream.Lazy: hGetContents :: Bitstream (Packet d) => Handle -> IO (Bitstream d)
+ Data.Bitstream.Lazy: hGetContents :: Bitstream (Bitstream d) => Handle -> IO (Bitstream d)
- Data.Bitstream.Lazy: hGetNonBlocking :: Bitstream (Packet d) => Handle -> Int -> IO (Bitstream d)
+ Data.Bitstream.Lazy: hGetNonBlocking :: (Bitstream (Bitstream d), Bitstream (Packet d)) => Handle -> Int -> IO (Bitstream d)
- Data.Bitstream.Lazy: hPut :: Bitstream (Packet d) => Handle -> Bitstream d -> IO ()
+ Data.Bitstream.Lazy: hPut :: (Bitstream (Bitstream d), Bitstream (Packet d)) => Handle -> Bitstream d -> IO ()
- Data.Bitstream.Lazy: interact :: Bitstream (Packet d) => (Bitstream d -> Bitstream d) -> IO ()
+ Data.Bitstream.Lazy: interact :: (Bitstream (Bitstream d), Bitstream (Packet d)) => (Bitstream d -> Bitstream d) -> IO ()
- Data.Bitstream.Lazy: putBits :: Bitstream (Packet d) => Bitstream d -> IO ()
+ Data.Bitstream.Lazy: putBits :: (Bitstream (Bitstream d), Bitstream (Packet d)) => Bitstream d -> IO ()
- Data.Bitstream.Lazy: readFile :: Bitstream (Packet d) => FilePath -> IO (Bitstream d)
+ Data.Bitstream.Lazy: readFile :: Bitstream (Bitstream d) => FilePath -> IO (Bitstream d)
- Data.Bitstream.Lazy: replicate :: (Bitstream α, Integral n) => n -> Bool -> α
+ Data.Bitstream.Lazy: replicate :: (Integral n, Bitstream α) => n -> Bool -> α
- Data.Bitstream.Lazy: take :: (Bitstream α, Integral n) => n -> α -> α
+ Data.Bitstream.Lazy: take :: (Integral n, Bitstream α) => n -> α -> α
- Data.Bitstream.Lazy: toByteString :: Bitstream (Packet d) => Bitstream d -> ByteString
+ Data.Bitstream.Lazy: toByteString :: (Bitstream (Bitstream d), Bitstream (Packet d)) => Bitstream d -> ByteString
- Data.Bitstream.Lazy: unfoldrN :: (Bitstream α, Integral n) => n -> (β -> Maybe (Bool, β)) -> β -> α
+ Data.Bitstream.Lazy: unfoldrN :: (Integral n, Bitstream α) => n -> (β -> Maybe (Bool, β)) -> β -> α
- Data.Bitstream.Lazy: writeFile :: Bitstream (Packet d) => FilePath -> Bitstream d -> IO ()
+ Data.Bitstream.Lazy: writeFile :: (Bitstream (Bitstream d), Bitstream (Packet d)) => FilePath -> Bitstream d -> IO ()

Files

+ ChangeLog view
@@ -0,0 +1,6 @@+== bitstream-0.2 / 2011-07-08+* bugfix: Make stream fusion actually work+* Implement fromBits / toBits+* Strict Bitstreams' bit length should only be a hint, just like stream size.+* Strict Bitstream should keep bit-length maintained+* Strict bitstrems should use unstreamPackets instead of hand-written unfoldr-based unstreamers.
Data/Bitstream.hs view
@@ -1,7 +1,9 @@ {-# LANGUAGE     BangPatterns   , FlexibleContexts+  , FlexibleInstances   , ScopedTypeVariables+  , UnboxedTuples   , UndecidableInstances   , UnicodeSyntax   #-}@@ -16,7 +18,7 @@ -- Strict 'Bitstream's are made of strict 'SV.Vector' of 'Packet's, -- and each 'Packet's have at least 1 bit. module Data.Bitstream-    ( -- * Types+    ( -- * Data types       Bitstream     , Left     , Right@@ -28,15 +30,23 @@     , pack     , unpack     , fromPackets+    , unsafeFromPackets     , toPackets        -- ** Converting from\/to strict 'BS.ByteString's     , fromByteString     , toByteString +    -- ** Converting from\/to 'Bits''+    , fromBits+    , fromNBits+    , toBits+       -- ** Converting from\/to 'S.Stream's     , stream     , unstream+    , streamPackets+    , unstreamPackets        -- * Changing bit order in octets     , directionLToR@@ -74,7 +84,7 @@     , any     , all -      -- * Building lists+      -- * Building 'Bitstream's       -- ** Scans     , scanl     , scanl1@@ -161,14 +171,16 @@ import qualified Data.List as L import Data.Monoid import qualified Data.Vector.Generic as GV+import qualified Data.Vector.Generic.New as New+import qualified Data.Vector.Generic.Mutable as MVector import qualified Data.Vector.Storable as SV import qualified Data.Vector.Fusion.Stream as S import Data.Vector.Fusion.Stream.Monadic (Stream(..), Step(..)) import Data.Vector.Fusion.Stream.Size import Data.Vector.Fusion.Util import Prelude ( Bool(..), Eq(..), Int, Integral, Maybe(..), Monad(..), Num(..)-               , Ord(..), Show(..), ($), div, error, fmap-               , fromIntegral, fst, mod, otherwise+               , Ord(..), Show(..), ($), error, fmap, fromIntegral, fst+               , otherwise                ) import Prelude.Unicode hiding ((⧺), (∈), (∉)) import System.IO (FilePath, Handle, IO)@@ -178,12 +190,15 @@ -- /directions/ controlling how octets are interpreted as bits. There -- are two types of concrete 'Bitstream's: @'Bitstream' 'Left'@ and -- @'Bitstream' 'Right'@.-newtype Bitstream d-    = Bitstream (SV.Vector (Packet d))+data Bitstream d+    = Bitstream {-# UNPACK #-} !Int -- bit length+                {-# UNPACK #-} !(SV.Vector (Packet d))+-- THINKME: The bit length should only be a hint, just like stream+-- size.  instance Show (Packet d) ⇒ Show (Bitstream d) where     {-# INLINEABLE show #-}-    show (Bitstream v0)+    show (Bitstream _ v0)         = L.concat           [ "(S"           , L.concat (L.unfoldr go v0)@@ -194,7 +209,7 @@           go v | SV.null v = Nothing                | otherwise = Just (show (SV.head v), SV.tail v) -instance G.Bitstream (Packet d) ⇒ Eq (Bitstream d) where+instance G.Bitstream (Bitstream d) ⇒ Eq (Bitstream d) where     {-# INLINE (==) #-}     x == y = stream x ≡ stream y @@ -209,7 +224,7 @@ --   , 'compare' z y -- 'LT' --   ] -- @-instance G.Bitstream (Packet d) ⇒ Ord (Bitstream d) where+instance G.Bitstream (Bitstream d) ⇒ Ord (Bitstream d) where     {-# INLINE compare #-}     x `compare` y = stream x `compare` stream y @@ -220,225 +235,353 @@ -- 'mappend' = 'append' -- 'mconcat' = 'concat' -- @-instance G.Bitstream (Packet d) ⇒ Monoid (Bitstream d) where+instance G.Bitstream (Bitstream d) ⇒ Monoid (Bitstream d) where     mempty  = (∅)     mappend = (⧺)     mconcat = concat -instance G.Bitstream (Packet d) ⇒ G.Bitstream (Bitstream d) where-    {-# INLINE [0] stream #-}-    stream (Bitstream v)-        = {-# CORE "Bitstream stream" #-}-          S.concatMap stream (GV.stream v)-          `S.sized`-          Exact (length (Bitstream v))+instance G.Bitstream (Bitstream Left) where+    {-# INLINE basicStream #-}+    basicStream = strictStream -    {-# INLINE [0] unstream #-}-    unstream-        = {-# CORE "Bitstream unstream" #-}-          Bitstream ∘ GV.unstream ∘ packPackets+    {-# INLINE basicUnstream #-}+    basicUnstream = strictUnstream -    {-# INLINEABLE [2] cons #-}-    cons b (Bitstream v)-        | SV.null v = Bitstream (SV.singleton (singleton b))-        | otherwise = case SV.head v of-                        p | length p < (8 ∷ Int)-                                → Bitstream ((b `cons` p) `SV.cons` SV.tail v)-                          | otherwise-                                → Bitstream (singleton b `SV.cons` v)+    {-# INLINE basicCons #-}+    basicCons = strictCons -    {-# INLINEABLE [2] snoc #-}-    snoc (Bitstream v) b-        | SV.null v = Bitstream (SV.singleton (singleton b))-        | otherwise = case SV.last v of-                        p | length p < (8 ∷ Int)-                                → Bitstream (SV.init v `SV.snoc` (p `snoc` b))-                          | otherwise-                                → Bitstream (v `SV.snoc` singleton b)+    {-# INLINE basicSnoc #-}+    basicSnoc = strictSnoc -    {-# INLINE [2] append #-}-    append (Bitstream x) (Bitstream y)-        = Bitstream (x SV.++ y)+    {-# INLINE basicAppend #-}+    basicAppend = strictAppend -    {-# INLINEABLE [2] tail #-}-    tail (Bitstream v)-        | SV.null v = emptyStream-        | otherwise = case tail (SV.head v) of-                        p' | null p'   → Bitstream (SV.tail v)-                           | otherwise → Bitstream (p' `SV.cons` SV.tail v)+    {-# INLINE basicTail #-}+    basicTail = strictTail -    {-# INLINEABLE [2] init #-}-    init (Bitstream v)-        | SV.null v = emptyStream-        | otherwise = case init (SV.last v) of-                        p' | null p'   → Bitstream (SV.init v)-                           | otherwise → Bitstream (SV.init v `SV.snoc` p')+    {-# INLINE basicInit #-}+    basicInit = strictInit -    {-# INLINE [2] map #-}-    map f (Bitstream v)-        = Bitstream (SV.map (map f) v)+    {-# INLINE basicMap #-}+    basicMap = strictMap -    {-# INLINE [2] reverse #-}-    reverse (Bitstream v)-        = Bitstream (SV.reverse (SV.map reverse v))+    {-# INLINE basicReverse #-}+    basicReverse = strictReverse -    {-# INLINE [1] scanl #-}-    scanl f b-        = unstream ∘ S.scanl f b ∘ stream+    {-# INLINE basicConcat #-}+    basicConcat = strictConcat -    {-# INLINE [2] concat #-}-    concat = Bitstream ∘ SV.concat ∘ L.map toPackets+    {-# INLINE basicScanl #-}+    basicScanl = strictScanl -    {-# INLINEABLE replicate #-}-    replicate n0 b-        | n0 ≤ 0         = (∅)-        | n0 `mod` 8 ≡ 0 = Bitstream anterior-        | otherwise      = Bitstream (anterior `SV.snoc` posterior)-        where-          {-# INLINE anterior #-}-          anterior = SV.replicate n p-              where-                n ∷ Int-                {-# INLINE n #-}-                n = fromIntegral (n0 `div` 8)-                {-# INLINE p #-}-                p = replicate (8 ∷ Int) b+    {-# INLINE basicTake #-}+    basicTake = strictTake -          {-# INLINE posterior #-}-          posterior = replicate n b-              where-                n ∷ Int-                {-# INLINE n #-}-                n = fromIntegral (n0 `mod` 8)+    {-# INLINE basicDrop #-}+    basicDrop = strictDrop -    {-# INLINEABLE [2] take #-}-    take n0 (Bitstream v0)-        | n0 ≤ 0    = (∅)-        | otherwise = Bitstream (SV.unfoldrN nOctets go (n0, v0))-        where-          {-# INLINE nOctets #-}-          nOctets ∷ Int-          nOctets = fromIntegral (min n0 (fromIntegral (SV.length v0)))-          {-# INLINE go #-}-          go (0, _) = Nothing-          go (n, v)-              | SV.null v = Nothing-              | otherwise = let p  = SV.head v-                                v' = SV.tail v-                                p' = take n p-                                n' = n - length p'+    {-# INLINE basicTakeWhile #-}+    basicTakeWhile = strictTakeWhile++    {-# INLINE basicDropWhile #-}+    basicDropWhile = strictDropWhile++    {-# INLINE basicFilter #-}+    basicFilter = strictFilter++    {-# INLINE basicFromNBits #-}+    basicFromNBits = (unstreamPackets ∘) ∘ lePacketsFromNBits++    {-# INLINE basicToBits #-}+    basicToBits = unId ∘ lePacketsToBits ∘ streamPackets++instance G.Bitstream (Bitstream Right) where+    {-# INLINE basicStream #-}+    basicStream = strictStream++    {-# INLINE basicUnstream #-}+    basicUnstream = strictUnstream++    {-# INLINE basicCons #-}+    basicCons = strictCons++    {-# INLINE basicSnoc #-}+    basicSnoc = strictSnoc++    {-# INLINE basicAppend #-}+    basicAppend = strictAppend++    {-# INLINE basicTail #-}+    basicTail = strictTail++    {-# INLINE basicInit #-}+    basicInit = strictInit++    {-# INLINE basicMap #-}+    basicMap = strictMap++    {-# INLINE basicReverse #-}+    basicReverse = strictReverse++    {-# INLINE basicConcat #-}+    basicConcat = strictConcat++    {-# INLINE basicScanl #-}+    basicScanl = strictScanl++    {-# INLINE basicTake #-}+    basicTake = strictTake++    {-# INLINE basicDrop #-}+    basicDrop = strictDrop++    {-# INLINE basicTakeWhile #-}+    basicTakeWhile = strictTakeWhile++    {-# INLINE basicDropWhile #-}+    basicDropWhile = strictDropWhile++    {-# INLINE basicFilter #-}+    basicFilter = strictFilter++    {-# INLINEABLE basicFromNBits #-}+    basicFromNBits = (unstreamPackets ∘) ∘ bePacketsFromNBits++    {-# INLINEABLE basicToBits #-}+    basicToBits = unId ∘ bePacketsToBits ∘ streamPackets++strictStream ∷ G.Bitstream (Packet d) ⇒ Bitstream d → S.Stream Bool+{-# INLINE strictStream #-}+strictStream (Bitstream l v)+    = {-# CORE "Strict Bitstream stream" #-}+      S.concatMap stream (GV.stream v)+      `S.sized`+      Exact l++strictUnstream ∷ G.Bitstream (Packet d) ⇒ S.Stream Bool → Bitstream d+{-# INLINE strictUnstream #-}+strictUnstream+    = {-# CORE "Strict Bitstream unstream" #-}+      unstreamPackets ∘ packPackets++strictCons ∷ G.Bitstream (Packet d) ⇒ Bool → Bitstream d → Bitstream d+{-# INLINEABLE strictCons #-}+strictCons b (Bitstream 0 _) = Bitstream 1 (SV.singleton (singleton b))+strictCons b (Bitstream l v)+    = case SV.head v of+        p | length p < (8 ∷ Int)+                → Bitstream (l+1) ((b `cons` p) `SV.cons` SV.tail v)+          | otherwise+                → Bitstream (l+1) (singleton b `SV.cons` v)++strictSnoc ∷ G.Bitstream (Packet d) ⇒ Bitstream d → Bool → Bitstream d+{-# INLINEABLE strictSnoc #-}+strictSnoc (Bitstream 0 _) b = Bitstream 1 (SV.singleton (singleton b))+strictSnoc (Bitstream l v) b+    = case SV.last v of+        p | length p < (8 ∷ Int)+                → Bitstream (l+1) (SV.init v `SV.snoc` (p `snoc` b))+          | otherwise+                → Bitstream (l+1) (v `SV.snoc` singleton b)++strictAppend ∷ G.Bitstream (Packet d) ⇒ Bitstream d → Bitstream d → Bitstream d+{-# INLINE strictAppend #-}+strictAppend (Bitstream lx x) (Bitstream ly y)+    = Bitstream (lx + ly) (x SV.++ y)++strictTail ∷ G.Bitstream (Packet d) ⇒ Bitstream d → Bitstream d+{-# INLINEABLE strictTail #-}+strictTail (Bitstream 0 _) = emptyStream+strictTail (Bitstream l v)+    = case tail (SV.head v) of+        p' | null p'   → Bitstream (l-1) (SV.tail v)+           | otherwise → Bitstream (l-1) (p' `SV.cons` SV.tail v)++strictInit ∷ G.Bitstream (Packet d) ⇒ Bitstream d → Bitstream d+{-# INLINEABLE strictInit #-}+strictInit (Bitstream 0 _) = emptyStream+strictInit (Bitstream l v)+    = case init (SV.last v) of+        p' | null p'   → Bitstream (l-1) (SV.init v)+           | otherwise → Bitstream (l-1) (SV.init v `SV.snoc` p')++strictMap ∷ G.Bitstream (Packet d) ⇒ (Bool → Bool) → Bitstream d → Bitstream d+{-# INLINE strictMap #-}+strictMap f (Bitstream l v)+    = Bitstream l (SV.map (map f) v)++strictReverse ∷ G.Bitstream (Packet d) ⇒ Bitstream d → Bitstream d+{-# INLINE strictReverse #-}+strictReverse (Bitstream l v)+    = Bitstream l (SV.reverse (SV.map reverse v))++strictConcat ∷ G.Bitstream (Bitstream d) ⇒ [Bitstream d] → Bitstream d+{-# INLINEABLE strictConcat #-}+strictConcat xs+    = let (!l, !vs) = L.mapAccumL (\n x → (n + length x, toPackets x)) 0 xs+          !v        = SV.concat vs+      in+        Bitstream l v++strictScanl ∷ G.Bitstream (Bitstream d) ⇒ (Bool → Bool → Bool) → Bool → Bitstream d → Bitstream d+{-# INLINE strictScanl #-}+strictScanl f b+    = unstream ∘ S.scanl f b ∘ stream++strictTake ∷ ( Integral n+             , G.Bitstream (Bitstream d)+             , G.Bitstream (Packet d)+             )+           ⇒ n+           → Bitstream d+           → Bitstream d+{-# INLINEABLE strictTake #-}+strictTake n0 (Bitstream l0 v0)+    | l0 ≡ 0    = (∅)+    | n0 ≤ 0    = (∅)+    | otherwise = let !e = New.create (MVector.new (SV.length v0))+                  in+                    case go n0 v0 0 0 e of+                      (# l, np, mv #)+                          → let !mv' = New.apply (MVector.take np) mv+                                !v   = GV.new mv'                             in-                              return (p', (n', v'))+                              Bitstream l v+    where+      {-# INLINE go #-}+      go 0 _ l np mv  = (# l, np, mv #)+      go n v l np mv+          | SV.null v = (# l, np, mv #)+          | otherwise = let !p   = SV.head v+                            !p'  = take n p+                            !n'  = n - length p'+                            !v'  = SV.tail v+                            !l'  = l + length p'+                            !np' = np + 1+                            !mv' = New.modify (\x → MVector.write x np p') mv+                        in+                          go n' v' l' np' mv' -    {-# INLINEABLE [2] drop #-}-    drop n0 (Bitstream v0)-        | n0 ≤ 0    = Bitstream v0-        | otherwise = Bitstream (go n0 v0)-        where-          {-# INLINE go #-}-          go 0 v = v-          go n v-              | SV.null v = v-              | otherwise = case SV.head v of-                              p | n ≥ length p → go (n - length p) (SV.tail v)-                                | otherwise    → drop n p `SV.cons` (SV.tail v)+strictDrop ∷ (Integral n, G.Bitstream (Packet d)) ⇒ n → Bitstream d → Bitstream d+{-# INLINEABLE strictDrop #-}+strictDrop n0 (Bitstream l0 v0)+    | n0 ≤ 0    = Bitstream l0 v0+    | otherwise = case go n0 l0 v0 of+                    (# l, v #) → Bitstream l v+    where+      {-# INLINE go #-}+      go 0 l v = (# l, v #)+      go _ 0 v = (# 0, v #)+      go n l v = let !p = SV.head v+                 in+                   case drop n p of+                     p' | null p'   → go (n - length p) (l - length p) (SV.tail v)+                        | otherwise → (# l - length p + length p'+                                       , p' `SV.cons` SV.tail v #) -    {-# INLINEABLE [2] takeWhile #-}-    takeWhile f (Bitstream v0)-        = Bitstream (GV.unstream (takeWhilePS (GV.stream v0)))-        where-          {-# INLINE takeWhilePS #-}-          takeWhilePS (Stream step s0 sz) = Stream step' (Just s0) (toMax sz)-              where-                {-# INLINE step' #-}-                step' Nothing  = return Done-                step' (Just s)-                    = do r ← step s-                         case r of-                           Yield p s'-                               → case takeWhile f p of-                                    p' | p ≡ p'    → return $ Yield p' (Just s')-                                       | otherwise → return $ Yield p' Nothing-                           Skip    s'-                               → return $ Skip (Just s')-                           Done-                               → return Done+strictTakeWhile ∷ G.Bitstream (Packet d) ⇒ (Bool → Bool) → Bitstream d → Bitstream d+{-# INLINEABLE strictTakeWhile #-}+strictTakeWhile f+    = unstreamPackets ∘ takeWhilePS ∘ streamPackets+    where+      {-# INLINE takeWhilePS #-}+      takeWhilePS (Stream step s0 sz) = Stream step' (Just s0) (toMax sz)+          where+            {-# INLINE step' #-}+            step' Nothing  = return Done+            step' (Just s)+                = do r ← step s+                     case r of+                       Yield p s'+                           → case takeWhile f p of+                                p' | p ≡ p'    → return $ Yield p' (Just s')+                                   | otherwise → return $ Yield p' Nothing+                       Skip    s'+                           → return $ Skip (Just s')+                       Done+                           → return Done -    {-# INLINEABLE [2] dropWhile #-}-    dropWhile f (Bitstream v0) = Bitstream (go v0)-        where-          {-# INLINE go #-}-          go v | SV.null v = v-               | otherwise = case dropWhile f (SV.head v) of-                               p' | null p'   → go (SV.tail v)-                                  | otherwise → p' `SV.cons` SV.tail v+strictDropWhile ∷ G.Bitstream (Packet d) ⇒ (Bool → Bool) → Bitstream d → Bitstream d+{-# INLINEABLE strictDropWhile #-}+strictDropWhile _ (Bitstream 0  v0) = Bitstream 0 v0+strictDropWhile f (Bitstream l0 v0) = case go l0 v0 of+                                        (# l, v #) → Bitstream l v+    where+      {-# INLINE go #-}+      go 0 v = (# 0, v #)+      go l v = let !p    = SV.head v+                   !pLen = length p+               in+                 case dropWhile f p of+                   p' | null p'   → go (l - pLen) (SV.tail v)+                      | otherwise → (# l - pLen + length p'+                                     , p' `SV.cons` SV.tail v #) -    {-# INLINEABLE [2] filter #-}-    filter f (Bitstream v0)-        = Bitstream (GV.unstream (filterPS (GV.stream v0)))-        where-          {-# INLINE filterPS #-}-          filterPS (Stream step s0 sz) = Stream step' s0 (toMax sz)-              where-                {-# INLINE step' #-}-                step' s-                    = do r ← step s-                         case r of-                           Yield p s' → case filter f p of-                                           p' | null p'   → return $ Skip s'-                                              | otherwise → return $ Yield p' s'-                           Skip    s' → return $ Skip s'-                           Done       → return Done+strictFilter ∷ G.Bitstream (Packet d) ⇒ (Bool → Bool) → Bitstream d → Bitstream d+{-# INLINEABLE strictFilter #-}+strictFilter f+    = unstreamPackets ∘ filterPS ∘ streamPackets+    where+      {-# INLINE filterPS #-}+      filterPS (Stream step s0 sz) = Stream step' s0 (toMax sz)+          where+            {-# INLINE step' #-}+            step' s+                = do r ← step s+                     case r of+                       Yield p s' → case filter f p of+                                       p' | null p'   → return $ Skip s'+                                          | otherwise → return $ Yield p' s'+                       Skip    s' → return $ Skip s'+                       Done       → return Done  strictHead ∷ G.Bitstream (Packet d) ⇒ Bitstream d → Bool-{-# RULES "head → strictHead" [2]+{-# RULES "head → strictHead" [1]     ∀(v ∷ G.Bitstream (Packet d) ⇒ Bitstream d).     head v = strictHead v #-} {-# INLINE strictHead #-}-strictHead (Bitstream v) = head (SV.head v)+strictHead (Bitstream _ v) = head (SV.head v)  strictLast ∷ G.Bitstream (Packet d) ⇒ Bitstream d → Bool-{-# RULES "last → strictLast" [2]+{-# RULES "last → strictLast" [1]     ∀(v ∷ G.Bitstream (Packet d) ⇒ Bitstream d).     last v = strictLast v #-} {-# INLINE strictLast #-}-strictLast (Bitstream v) = last (SV.last v)+strictLast (Bitstream _ v) = last (SV.last v)  strictNull ∷ Bitstream d → Bool-{-# RULES "null → strictNull" [2] null = strictNull #-}+{-# RULES "null → strictNull" [1] null = strictNull #-} {-# INLINE strictNull #-}-strictNull (Bitstream v) = SV.null v+strictNull (Bitstream 0 _) = True+strictNull _               = False -strictLength ∷ (G.Bitstream (Packet d), Num n) ⇒ Bitstream d → n-{-# RULES "length → strictLength" [2]-    ∀(v ∷ G.Bitstream (Packet d) ⇒ Bitstream d).-    length v = strictLength v #-}-{-# INLINEABLE strictLength #-}-strictLength (Bitstream v)-    = SV.foldl' (\n p → n + length p) 0 v+strictLength ∷ Num n ⇒ Bitstream d → n+{-# RULES "length → strictLength" [1] length = strictLength #-}+{-# INLINE strictLength #-}+strictLength (Bitstream len _) = fromIntegral len  strictAnd ∷ G.Bitstream (Packet d) ⇒ Bitstream d → Bool-{-# RULES "and → strictAnd" [2]+{-# RULES "and → strictAnd" [1]     ∀(v ∷ G.Bitstream (Packet d) ⇒ Bitstream d).     and v = strictAnd v #-} {-# INLINE strictAnd #-}-strictAnd (Bitstream v)+strictAnd (Bitstream _ v)     = SV.all and v  strictOr ∷ G.Bitstream (Packet d) ⇒ Bitstream d → Bool-{-# RULES "or → strictOr" [2]+{-# RULES "or → strictOr" [1]     ∀(v ∷ G.Bitstream (Packet d) ⇒ Bitstream d).     or v = strictOr v #-} {-# INLINE strictOr #-}-strictOr (Bitstream v)+strictOr (Bitstream _ v)     = SV.any or v  strictIndex ∷ (G.Bitstream (Packet d), Integral n) ⇒ Bitstream d → n → Bool-{-# RULES "(!!) → strictIndex" [2]+{-# RULES "(!!) → strictIndex" [1]     ∀(v ∷ G.Bitstream (Packet d) ⇒ Bitstream d) n.     v !! n = strictIndex v n #-} {-# INLINEABLE strictIndex #-}-strictIndex (Bitstream v0) i0+strictIndex (Bitstream _ v0) i0     | i0 < 0    = indexOutOfRange i0     | otherwise = go v0 i0     where@@ -461,10 +604,11 @@ -- 'Bitstream'. {-# INLINE fromByteString #-} fromByteString ∷ BS.ByteString → Bitstream d-fromByteString bs0 = Bitstream (SV.unfoldrN nOctets go bs0)+fromByteString bs0+    = Bitstream (nOctets ⋅ 8) (SV.unfoldrN nOctets go bs0)     where-      {-# INLINE nOctets #-}       nOctets ∷ Int+      {-# INLINE nOctets #-}       nOctets = BS.length bs0       {-# INLINE go #-}       go bs = do (o, bs') ← BS.uncons bs@@ -474,7 +618,9 @@ -- into a strict 'BS.ByteString'. The resulting octets will be padded -- with zeroes if the 'length' of @bs@ is not multiple of 8. {-# INLINEABLE toByteString #-}-toByteString ∷ ∀d. G.Bitstream (Packet d) ⇒ Bitstream d → BS.ByteString+toByteString ∷ ∀d. ( G.Bitstream (Bitstream d)+                   , G.Bitstream (Packet d)+                                     ) ⇒ Bitstream d → BS.ByteString toByteString = unstreamBS              ∘ (packPackets ∷ Stream Id Bool → Stream Id (Packet d))              ∘ stream@@ -493,29 +639,64 @@                     Skip    s' → go s'                     Done       → return Nothing --- | /O(1)/ Convert a 'SV.Vector' of 'Packet's into a 'Bitstream'.-fromPackets ∷ SV.Vector (Packet d) → Bitstream d+-- WARNING: countBits is rather slow.+countBits ∷ (G.Bitstream (Packet d), Num n) ⇒ SV.Vector (Packet d) → n+{-# INLINE countBits #-}+countBits = SV.foldl' (\n p → n + length p) 0++-- | /O(n)/ Convert a 'SV.Vector' of 'Packet's into a 'Bitstream'.+fromPackets ∷ G.Bitstream (Packet d) ⇒ SV.Vector (Packet d) → Bitstream d {-# INLINE fromPackets #-}-fromPackets = Bitstream+fromPackets v = Bitstream (countBits v) v +-- | /O(1)/ Convert a 'SV.Vector' of 'Packet's into a 'Bitstream',+-- with provided overall bit length. The correctness of the bit length+-- isn't checked, so you MUST be sure your bit length is absolutely+-- correct.+unsafeFromPackets ∷ G.Bitstream (Packet d) ⇒ Int → SV.Vector (Packet d) → Bitstream d+{-# INLINE unsafeFromPackets #-}+unsafeFromPackets = Bitstream+ -- | /O(1)/ Convert a 'Bitstream' into a 'SV.Vector' of 'Packet's. toPackets ∷ Bitstream d → SV.Vector (Packet d) {-# INLINE toPackets #-}-toPackets (Bitstream d) = d+toPackets (Bitstream _ d) = d +-- | /O(1)/ Convert a 'Bitstream' into a 'S.Stream' of 'Packet's.+streamPackets ∷ Bitstream d → S.Stream (Packet d)+{-# NOINLINE streamPackets #-}+streamPackets (Bitstream _ v) = GV.stream v++-- | /O(n)/ Convert a 'S.Stream' of 'Packet's into 'Bitstream'.+unstreamPackets ∷ G.Bitstream (Packet d) ⇒ S.Stream (Packet d) → Bitstream d+{-# NOINLINE unstreamPackets #-}+unstreamPackets s+    = let !v = GV.unstream s+          !l = countBits v+      in+        Bitstream l v++{-# RULES+"Strict Bitstream streamPackets/unstreamPackets fusion"+    ∀s. streamPackets (unstreamPackets s) = s++"Strict Bitstream unstreamPackets/streamPackets fusion"+    ∀v. unstreamPackets (streamPackets v) = v+  #-}+ -- | /O(n)/ Convert a @'Bitstream' 'Left'@ into a @'Bitstream' -- 'Right'@. Bit directions only affect octet-based operations such as -- 'toByteString'. directionLToR ∷ Bitstream Left → Bitstream Right {-# INLINE directionLToR #-}-directionLToR (Bitstream v) = Bitstream (SV.map packetLToR v)+directionLToR (Bitstream l v) = Bitstream l (SV.map packetLToR v)  -- | /O(n)/ Convert a @'Bitstream' 'Right'@ into a @'Bitstream' -- 'Left'@. Bit directions only affect octet-based operations such as -- 'toByteString'. directionRToL ∷ Bitstream Right → Bitstream Left {-# INLINE directionRToL #-}-directionRToL (Bitstream v) = Bitstream (SV.map packetRToL v)+directionRToL (Bitstream l v) = Bitstream l (SV.map packetRToL v)  -- | /O(n)/ Read a 'Bitstream' from the stdin strictly, equivalent to -- 'hGetContents' @stdin@. The 'Handle' is closed after the contents@@ -526,7 +707,11 @@  -- | /O(n)/ Write a 'Bitstream' to the stdout, equivalent to 'hPut' -- @stdout@.-putBits ∷ G.Bitstream (Packet d) ⇒ Bitstream d → IO ()+putBits ∷ ( G.Bitstream (Bitstream d)+          , G.Bitstream (Packet d)+          )+        ⇒ Bitstream d+        → IO () {-# INLINE putBits #-} putBits = BS.putStr ∘ toByteString @@ -534,7 +719,11 @@ -- -> 'Bitstream' d@ as its argument. The entire input from the stdin -- is passed to this function as its argument, and the resulting -- 'Bitstream' is output on the stdout.-interact ∷ G.Bitstream (Packet d) ⇒ (Bitstream d → Bitstream d) → IO ()+interact ∷ ( G.Bitstream (Bitstream d)+           , G.Bitstream (Packet d)+           )+         ⇒ (Bitstream d → Bitstream d)+         → IO () {-# INLINE interact #-} interact = BS.interact ∘ lift'     where@@ -547,12 +736,22 @@ readFile = fmap fromByteString ∘ BS.readFile  -- | /O(n)/ Write a 'Bitstream' to a file.-writeFile ∷ G.Bitstream (Packet d) ⇒ FilePath → Bitstream d → IO ()+writeFile ∷ ( G.Bitstream (Bitstream d)+            , G.Bitstream (Packet d)+            ) +          ⇒ FilePath+          → Bitstream d+          → IO () {-# INLINE writeFile #-} writeFile = (∘ toByteString) ∘ BS.writeFile  -- | /O(n)/ Append a 'Bitstream' to a file.-appendFile ∷ G.Bitstream (Packet d) ⇒ FilePath → Bitstream d → IO ()+appendFile ∷ ( G.Bitstream (Bitstream d)+             , G.Bitstream (Packet d)+             )+           ⇒ FilePath+           → Bitstream d+           → IO () {-# INLINE appendFile #-} appendFile = (∘ toByteString) ∘ BS.appendFile @@ -597,6 +796,11 @@ hGetNonBlocking = (fmap fromByteString ∘) ∘ BS.hGetNonBlocking  -- | /O(n)/ Write a 'Bitstream' to the given 'Handle'.-hPut ∷ G.Bitstream (Packet d) ⇒ Handle → Bitstream d → IO ()+hPut ∷ ( G.Bitstream (Bitstream d)+       , G.Bitstream (Packet d)+       )+     ⇒ Handle+     → Bitstream d+     → IO () {-# INLINE hPut #-} hPut = (∘ toByteString) ∘ BS.hPut
Data/Bitstream/Generic.hs view
@@ -5,21 +5,43 @@   #-} -- | Generic interface to diverse types of 'Bitstream'. module Data.Bitstream.Generic-    ( Bitstream(..)+    ( -- * The type class+      Bitstream(..) +    -- * Introducing and eliminating 'Bitstream's+    , empty+    , (∅)+    , singleton     , pack     , unpack -    , empty-    , singleton+    -- ** Converting from\/to 'Bits''+    , fromBits+    , fromNBits+    , toBits +    -- ** Converting from\/to 'S.Stream's+    , stream+    , unstream++    -- * Basic interface+    , cons+    , cons'+    , snoc+    , append+    , (⧺)     , head     , last+    , tail+    , init     , null     , length -    , concatMap+    -- * Transforming 'Bitstream's+    , map+    , reverse +    -- * Reducing 'Bitstream's     , foldl     , foldl'     , foldl1@@ -27,32 +49,57 @@     , foldr     , foldr1 +    -- ** Special folds+    , concat+    , concatMap     , and     , or     , any     , all -    , unfoldr-    , unfoldrN-+    -- * Building 'Bitstream's+    -- ** scans+    , scanl     , scanl1     , scanr     , scanr1 +    -- ** Replication+    , replicate++    -- ** Unfolding+    , unfoldr+    , unfoldrN++    -- * Substreams+    , take+    , drop+    , takeWhile+    , dropWhile     , span     , break +    -- * Searching streams     , elem+    , (∈)+    , (∋)     , notElem+    , (∉)+    , (∌) +    -- ** Searching with a predicate     , find+    , filter+    , partition +    -- ** Indexing streams     , (!!)     , elemIndex     , elemIndices     , findIndex     , findIndices +    -- * Zipping and unzipping streams     , zip     , zip3     , zip4@@ -68,16 +115,10 @@     , unzip4     , unzip5     , unzip6--    , (∅)-    , (⧺)-    , (∈)-    , (∋)-    , (∉)-    , (∌)     )     where import qualified Data.List as L+import Data.Bits import Data.Bitstream.Fusion import Data.Maybe import Data.Vector.Fusion.Stream (Stream)@@ -94,177 +135,62 @@ {- Notes about inlining / rewriting phase control:     1. We want "*/unstream fusion" rules always fire.-   2. Unfused form specialisations should occur at phase 2 and later.-   3. Fusible form inlinings should occur at phase 1 and later.-   4. stream / unstream inlinings should occur last i.e. phase 0.+   2. Fusible producer inlinings should always occur.+   3. Unfused form specialisations should occur at phase 1 and later.+   4. Fusible consumer/filter inlinings should occur last i.e. phase 0.+   5. stream/unstream inlinings should never occur.  -}  -- | Class of diverse types of 'Bitstream'. ----- Methods of this class are functions of 'Bitstream's that is either+-- Methods of this class are functions of 'Bitstream's that are either -- basic functions to implement other ones, or have to preserve their -- packet/chunk structure for efficiency and strictness behaviour. ----- Minimum complete implementation: /All but/ 'cons'', 'concat',--- 'replicate' and 'partition'.+-- Minimum complete implementation: /All but/ 'basicCons'',+-- 'basicConcat', 'basicReplicate', 'basicPartition' and+-- 'basicFromBits'. class Bitstream α where-    -- | /O(n)/ Explicitly convert a 'Bitstream' into a 'Stream' of-    -- 'Bool'.-    ---    -- 'Bitstream' operations are automatically fused whenever it's-    -- possible, safe, and effective to do so, but sometimes you may-    -- find the rules are too conservative. These two functions-    -- 'stream' and 'unstream' provide a means for coercive stream-    -- fusion.-    ---    -- You should be careful when you use 'stream'. Most functions in-    -- this package are optimised to minimise frequency of memory-    -- allocations and copyings, but getting 'Bitstream's back from-    -- @'Stream' 'Bool'@ requires the whole 'Bitstream' to be-    -- constructed from scratch. Moreover, for lazy 'Bitstream's this-    -- leads to be an incorrect strictness behaviour because lazy-    -- 'Bitstream's are represented as lists of strict 'Bitstream'-    -- chunks but 'stream' can't preserve the original chunk-    -- structure. Let's say you have a lazy 'Bitstream' with the-    -- following chunks:-    ---    -- @-    -- bs = [chunk1, chunk2, chunk3, ...]-    -- @-    ---    -- and you want to drop the first bit of such stream. Our 'tail'-    -- is only strict on the @chunk1@ and will produce the following-    -- chunks:-    ---    -- @-    -- 'tail' bs = [chunk0, chunk1', chunk2, chunk3, ...]-    -- @-    ---    -- where @chunk0@ is a singleton vector of the first packet of-    -- @chunk1@ whose first bit is dropped, and @chunk1'@ is a vector-    -- of remaining packets of the @chunk1@. Neither @chunk2@ nor-    -- @chunk3@ have to be evaluated here as you might expect.-    ---    -- But think about the following expression:-    ---    -- @-    -- import qualified Data.Vector.Fusion.Stream as Stream-    -- 'unstream' $ Stream.tail $ 'stream' bs-    -- @-    ---    -- the resulting chunk structure will be:-    ---    -- @-    -- [chunk1', chunk2', chunk3', ...]-    -- @-    ---    -- where each and every chunks are slightly different from the-    -- original chunks, and this time @chunk1'@ has the same length as-    -- @chunk1@ but the last bit of @chunk1'@ is from the first bit of-    -- @chunk2@. This means when you next time apply some functions-    -- strict on the first chunk, you end up fully evaluating @chunk2@-    -- as well as @chunk1@ and this can be a serious misbehaviour for-    -- lazy 'Bitstream's.-    ---    -- The automatic fusion rules are carefully designed to fire only-    -- when there aren't any reason to preserve the original packet /-    -- chunk structure.-    stream ∷ α → Stream Bool+    basicStream   ∷ α → Stream Bool+    basicUnstream ∷ Stream Bool → α -    -- | /O(n)/ Convert a 'S.Stream' of 'Bool' into a 'Bitstream'.-    unstream ∷ Stream Bool → α+    basicCons   ∷ Bool → α → α+    basicCons'  ∷ Bool → α → α+    {-# INLINE basicCons' #-}+    basicCons'  = basicCons+    basicSnoc   ∷ α → Bool → α+    basicAppend ∷ α → α → α+    basicTail   ∷ α → α+    basicInit   ∷ α → α -    -- | /strict: O(n), lazy: O(1)/ 'cons' is an analogous to (':')-    -- for lists.-    cons ∷ Bool → α → α+    basicMap     ∷ (Bool → Bool) → α → α+    basicReverse ∷ α → α -    -- | /O(n)/ For strict 'Bitstream's, 'cons'' is exactly the same-    -- as 'cons'.-    ---    -- For lazy ones, 'cons'' is strict in the 'Bitstream' we are-    -- consing onto. More precisely, it forces the first chunk to be-    -- evaluated. It does this because, for space efficiency, it may-    -- coalesce the new bit onto the first chunk rather than starting-    -- a new chunk.-    cons' ∷ Bool → α → α-    {-# INLINE cons' #-}-    cons' = cons+    basicConcat ∷ [α] → α+    {-# INLINE basicConcat #-}+    basicConcat []     = (∅)+    basicConcat (α:αs) = α ⧺ concat αs -    -- | /O(n)/ Append a bit to the end of a 'Bitstream'.-    snoc ∷ α → Bool → α+    basicScanl ∷ (Bool → Bool → Bool) → Bool → α → α -    -- | /O(n)/ Append two 'Bitstream's.-    append ∷ α → α → α+    basicTake      ∷ Integral n ⇒ n → α → α+    basicDrop      ∷ Integral n ⇒ n → α → α+    basicTakeWhile ∷ (Bool → Bool) → α → α+    basicDropWhile ∷ (Bool → Bool) → α → α -    -- | /O(1)/ Extract the bits after the 'head' of a non-empty-    -- 'Bitstream'. An exception will be thrown if empty.-    tail ∷ α → α+    basicFilter    ∷ (Bool → Bool) → α → α+    basicPartition ∷ (Bool → Bool) → α → (α, α)+    {-# INLINE basicPartition #-}+    basicPartition f α = (filter f α, filter ((¬) ∘ f) α) -    -- | /O(n)/ Return all the bits of a 'Bitstream' except the last-    -- one. An exception will be thrown if empty.-    init ∷ α → α+    basicFromNBits ∷ (Integral n, Integral β, Bits β) ⇒ n → β → α+    basicToBits    ∷ Bits β ⇒ α → β -    -- | /O(n)/ Map a function over a 'Bitstream'.-    map ∷ (Bool → Bool) → α → α -    -- | /O(n)/ Reverse a 'Bitstream'.-    reverse ∷ α → α--    -- | /O(n)/ Concatenate all 'Bitstream's in the list.-    concat ∷ [α] → α-    {-# INLINE concat #-}-    concat []     = (∅)-    concat (α:αs) = α ⧺ concat αs--    -- | /O(n)/ 'scanl' is similar to 'foldl', but returns a-    -- 'Bitstream' of successive reduced bits from the left:-    ---    -- @-    -- 'scanl' f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...]-    -- @-    ---    -- Note that-    ---    -- @-    -- 'last' ('scanl' f z xs) == 'foldl' f z xs-    -- @-    scanl ∷ (Bool → Bool → Bool) → Bool → α → α--    -- | /O(n)/ @'replicate' n x@ is a 'Bitstream' of length @n@ with-    -- @x@ the value of every bit.-    replicate ∷ Integral n ⇒ n → Bool → α-    {-# INLINE replicate #-}-    replicate n = unstream ∘ genericReplicate n--    -- | /O(n)/ 'take' @n@, applied to a 'Bitstream' @xs@, returns the-    -- prefix of @xs@ of length @n@, or @xs@ itself if @n > 'length'-    -- xs@.-    take ∷ Integral n ⇒ n → α → α--    -- | /O(n)/ 'drop' @n xs@ returns the suffix of @xs@ after the-    -- first @n@ bits, or 'empty' if @n > 'length' xs@.-    drop ∷ Integral n ⇒ n → α → α--    -- | /O(n)/ 'takeWhile', applied to a predicate @p@ and a-    -- 'Bitstream' @xs@, returns the longest prefix (possibly 'empty')-    -- of @xs@ of bits that satisfy @p@.-    takeWhile ∷ (Bool → Bool) → α → α--    -- | /O(n)/ 'dropWhile' @p xs@ returns the suffix remaining after-    -- 'takeWhile' @p xs@.-    dropWhile ∷ (Bool → Bool) → α → α--    -- | /O(n)/ 'filter', applied to a predicate and a 'Bitstream',-    -- returns the 'Bitstream' of those bits that satisfy the-    -- predicate.-    filter ∷ (Bool → Bool) → α → α--    -- | /O(n)/ The 'partition' function takes a predicate and a-    -- 'Bitstream' and returns the pair of 'Bitstream's of bits which-    -- do and do not satisfy the predicate, respectively.-    partition ∷ (Bool → Bool) → α → (α, α)-    {-# INLINEABLE partition #-}-    partition f α = (filter f α, filter ((¬) ∘ f) α)+-- | /O(1)/ The empty 'Bitstream'.+empty ∷ Bitstream α ⇒ α+{-# INLINE empty #-}+empty = unstream S.empty  -- | (&#x2205;) = 'empty' --@@ -273,43 +199,13 @@ (∅) ∷ Bitstream α ⇒ α (∅) = empty --- | (&#x29FA;) = 'append'------ U+29FA, DOUBLE PLUS-(⧺) ∷ Bitstream α ⇒ α → α → α-(⧺) = append-{-# INLINE (⧺) #-}---- | (&#x2208;) = 'elem'------ U+2208, ELEMENT OF-(∈) ∷ Bitstream α ⇒ Bool → α → Bool-{-# INLINE (∈) #-}-(∈) = elem---- | (&#x220B;) = 'flip' (&#x2208;)------ U+220B, CONTAINS AS MEMBER-(∋) ∷ Bitstream α ⇒ α → Bool → Bool-(∋) = flip elem-{-# INLINE (∋) #-}---- | (&#x2209;) = 'notElem'------ U+2209, NOT AN ELEMENT OF-(∉) ∷ Bitstream α ⇒ Bool → α → Bool-(∉) = notElem-{-# INLINE (∉) #-}---- | (&#x220C;) = 'flip' (&#x2209;)------ U+220C, DOES NOT CONTAIN AS MEMBER-(∌) ∷ Bitstream α ⇒ α → Bool → Bool-(∌) = flip notElem-{-# INLINE (∌) #-}+-- | /O(1)/ Convert a 'Bool' into a 'Bitstream'.+singleton ∷ Bitstream α ⇒ Bool → α+{-# INLINE singleton #-}+singleton = unstream ∘ S.singleton  -- | /O(n)/ Convert a ['Bool'] into a 'Bitstream'.-{-# INLINE [1] pack #-}+{-# INLINE pack #-} pack ∷ Bitstream α ⇒ [Bool] → α pack = unstream ∘ S.fromList @@ -318,26 +214,160 @@ {-# RULES "Bitstream unpack/unstream fusion"     ∀s. unpack (unstream s) = S.toList s   #-}-{-# INLINE [1] unpack #-}+{-# INLINE [0] unpack #-} unpack = S.toList ∘ stream --- | /O(1)/ The empty 'Bitstream'.-empty ∷ Bitstream α ⇒ α-{-# INLINE [1] empty #-}-empty = unstream S.empty+-- | /O(n)/ Explicitly convert a 'Bitstream' into a 'Stream' of+-- 'Bool'.+--+-- 'Bitstream' operations are automatically fused whenever it's+-- possible, safe, and effective to do so, but sometimes you may find+-- the rules are too conservative. These two functions 'stream' and+-- 'unstream' provide a means for coercive stream fusion.+--+-- You should be careful when you use 'stream'. Most functions in this+-- package are optimised to minimise frequency of memory allocations+-- and copyings, but getting 'Bitstream's back from @'Stream' 'Bool'@+-- requires the whole 'Bitstream' to be constructed from+-- scratch. Moreover, for lazy 'Bitstream's this leads to be an+-- incorrect strictness behaviour because lazy 'Bitstream's are+-- represented as lists of strict 'Bitstream' chunks but 'stream'+-- can't preserve the original chunk structure. Let's say you have a+-- lazy 'Bitstream' with the following chunks:+--+-- @+-- bs = [chunk1, chunk2, chunk3, ...]+-- @+--+-- and you want to drop the first bit of such stream. Our 'tail' is+-- only strict on the @chunk1@ and will produce the following chunks:+--+-- @+-- 'tail' bs = [chunk0, chunk1', chunk2, chunk3, ...]+-- @+--+-- where @chunk0@ is a singleton vector of the first packet of+-- @chunk1@ whose first bit is dropped, and @chunk1'@ is a vector of+-- remaining packets of the @chunk1@. Neither @chunk2@ nor @chunk3@+-- have to be evaluated here as you might expect.+--+-- But think about the following expression:+--+-- @+-- import qualified Data.Vector.Fusion.Stream as Stream+-- 'unstream' $ Stream.tail $ 'stream' bs+-- @+--+-- the resulting chunk structure will be:+--+-- @+-- [chunk1', chunk2', chunk3', ...]+-- @+--+-- where each and every chunks are slightly different from the+-- original chunks, and this time @chunk1'@ has the same length as+-- @chunk1@ but the last bit of @chunk1'@ is from the first bit of+-- @chunk2@. This means when you next time apply some functions strict+-- on the first chunk, you end up fully evaluating @chunk2@ as well as+-- @chunk1@ and this can be a serious misbehaviour for lazy+-- 'Bitstream's.+--+-- The automatic fusion rules are carefully designed to fire only when+-- there aren't any reason to preserve the original packet / chunk+-- structure.+stream ∷ Bitstream α ⇒ α → Stream Bool+{-# NOINLINE stream #-}+stream = basicStream --- | /O(1)/ Convert a 'Bool' into a 'Bitstream'.-singleton ∷ Bitstream α ⇒ Bool → α-{-# INLINE [1] singleton #-}-singleton = unstream ∘ S.singleton+-- | /O(n)/ Convert a 'S.Stream' of 'Bool' into a 'Bitstream'.+unstream ∷ Bitstream α ⇒ Stream Bool → α+{-# NOINLINE unstream #-}+unstream = basicUnstream +{-# RULES+"Bitstream stream/unstream fusion"+    ∀s. stream (unstream s) = s++"Bitstream unstream/stream fusion"+    ∀v. unstream (stream v) = v+  #-}++-- | /O(n)/ Convert a 'Bits' into a 'Bitstream'. Note that this+-- function is undefined for instances of 'Bits' which have no fixed+-- 'bitSize' (like 'Integer').+fromBits ∷ (Integral β, Bits β, Bitstream α) ⇒ β → α+{-# INLINE fromBits #-}+fromBits β = basicFromNBits (bitSize β) β++-- | /O(n)/ Convert the lower 'n' bits of the given 'Bits'. In the+-- case that more bits are requested than the 'Bits' provides, this+-- acts as if the 'Bits' has an infinite number of leading 0 bits.+fromNBits ∷ (Integral n, Integral β, Bits β, Bitstream α) ⇒ n → β → α+{-# INLINE fromNBits #-}+fromNBits = basicFromNBits++-- | /O(n)/ Convert a 'Bitstream' into a 'Bits'.+toBits ∷ (Bitstream α, Bits β) ⇒ α → β+{-# INLINE [0] toBits #-}+toBits = basicToBits++-- | /strict: O(n), lazy: O(1)/ 'cons' is an analogous to (':') for+-- lists.+cons ∷ Bitstream α ⇒ Bool → α → α+{-# RULES+"Bitstream cons/unstream fusion"+    ∀b s. cons b (unstream s) = unstream (S.cons b s)+  #-}+{-# INLINE [0] cons #-}+cons = basicCons++-- | /O(n)/ For strict 'Bitstream's, 'cons'' is exactly the same as+-- 'cons'.+--+-- For lazy ones, 'cons'' is strict in the 'Bitstream' we are consing+-- onto. More precisely, it forces the first chunk to be evaluated. It+-- does this because, for space efficiency, it may coalesce the new+-- bit onto the first chunk rather than starting a new chunk.+cons' ∷ Bitstream α ⇒ Bool → α → α+{-# RULES+"Bitstream cons'/unstream fusion"+    ∀b s. cons' b (unstream s) = unstream (S.cons b s)+  #-}+{-# INLINE [0] cons' #-}+cons' = basicCons'++-- | /O(n)/ Append a bit to the end of a 'Bitstream'.+snoc ∷ Bitstream α ⇒ α → Bool → α+{-# RULES+"Bitstream snoc/unstream fusion"+    ∀s b. snoc (unstream s) b = unstream (S.snoc s b)+  #-}+{-# INLINE [0] snoc #-}+snoc = basicSnoc++-- | /O(n)/ Append two 'Bitstream's.+append ∷ Bitstream α ⇒ α → α → α+{-# RULES+"Bitstream append/unstream fusion"+    ∀s1 s2. append (unstream s1) (unstream s2) = unstream (s1 S.++ s2)+  #-}+{-# INLINE [0] append #-}+append = basicAppend++-- | (&#x29FA;) = 'append'+--+-- U+29FA, DOUBLE PLUS+(⧺) ∷ Bitstream α ⇒ α → α → α+{-# INLINE (⧺) #-}+(⧺) = append+ -- | /O(1)/ Extract the first bit of a non-empty 'Bitstream'. An -- exception will be thrown if empty. head ∷ Bitstream α ⇒ α → Bool {-# RULES "Bitstream head/unstream fusion"     ∀s. head (unstream s) = S.head s   #-}-{-# INLINE [1] head #-}+{-# INLINE [0] head #-} head = S.head ∘ stream  -- | /strict: O(1), lazy: O(n)/ Extract the last bit of a finite@@ -346,31 +376,138 @@ {-# RULES "Bitstream last/unstream fusion"     ∀s. last (unstream s) = S.last s   #-}-{-# INLINE [1] last #-}+{-# INLINE [0] last #-} last = S.last ∘ stream +-- | /O(1)/ Extract the bits after the 'head' of a non-empty+-- 'Bitstream'. An exception will be thrown if empty.+tail ∷ Bitstream α ⇒ α → α+{-# RULES+"Bitstream tail/unstream fusion"+    ∀s. tail (unstream s) = unstream (S.tail s)+  #-}+{-# INLINE [0] tail #-}+tail = basicTail++-- | /O(n)/ Return all the bits of a 'Bitstream' except the last+-- one. An exception will be thrown if empty.+init ∷ Bitstream α ⇒ α → α+{-# RULES+"Bitstream init/unstream fusion"+    ∀s. init (unstream s) = unstream (S.init s)+  #-}+{-# INLINE [0] init #-}+init = basicInit+ -- | /O(1)/ Test whether a 'Bitstream' is empty. null ∷ Bitstream α ⇒ α → Bool {-# RULES "Bitstream null/unstream fusion"     ∀s. null (unstream s) = S.null s   #-}-{-# INLINE [1] null #-}+{-# INLINE [0] null #-} null = S.null ∘ stream --- | /O(n)/ Retern the length of a finite 'Bitstream'.+-- | /strict: O(1), lazy: O(n)/ Return the length of a finite+-- 'Bitstream'. length ∷ Bitstream α ⇒ Num n ⇒ α → n {-# RULES "Bitstream length/unstream fusion"     ∀s. length (unstream s) = genericLength s   #-}-{-# INLINE [1] length #-}+{-# INLINE [0] length #-} length = genericLength ∘ stream +-- | /O(n)/ Map a function over a 'Bitstream'.+map ∷ Bitstream α ⇒ (Bool → Bool) → α → α+{-# RULES+"Bitstream map/unstream fusion"+    ∀f s. map f (unstream s) = unstream (S.map f s)+  #-}+{-# INLINE [0] map #-}+map = basicMap++-- | /O(n)/ Reverse a 'Bitstream'.+reverse ∷ Bitstream α ⇒ α → α+{-# INLINE [0] reverse #-}+reverse = basicReverse++-- | /O(n)/ 'foldl', applied to a binary operator, a starting value+-- (typically the left-identity of the operator), and a 'Bitstream',+-- reduces the 'Bitstream' using the binary operator, from left to+-- right:+--+-- @+-- 'foldl' f z [x1, x2, ..., xn] == (...((z `f` x1) `f` x2) `f`...) `f` xn+-- @+--+-- The 'Bitstream' must be finite.+foldl ∷ Bitstream α ⇒ (β → Bool → β) → β → α → β+{-# RULES "Bitstream foldl/unstream fusion"+    ∀f β s. foldl f β (unstream s) = S.foldl f β s+  #-}+{-# INLINE [0] foldl #-}+foldl f β = S.foldl f β ∘ stream++-- | /O(n)/ 'foldl'' is a variant of 'foldl' that is strict on the+-- accumulator.+foldl' ∷ Bitstream α ⇒ (β → Bool → β) → β → α → β+{-# RULES "Bitstream foldl'/unstream fusion"+    ∀f β s. foldl' f β (unstream s) = S.foldl' f β s+  #-}+{-# INLINE [0] foldl' #-}+foldl' f β = S.foldl' f β ∘ stream++-- | /O(n)/ 'foldl1' is a variant of 'foldl' that has no starting+-- value argument, and thus must be applied to non-empty 'Bitstream's.+foldl1 ∷ Bitstream α ⇒ (Bool → Bool → Bool) → α → Bool+{-# RULES "Bitstream foldl1/unstream fusion"+    ∀f s. foldl1 f (unstream s) = S.foldl1 f s+  #-}+{-# INLINE [0] foldl1 #-}+foldl1 f = S.foldl1 f ∘ stream++-- | /O(n)/ A strict version of 'foldl1'.+foldl1' ∷ Bitstream α ⇒ (Bool → Bool → Bool) → α → Bool+{-# RULES "Bitstream foldl1'/unstream fusion"+    ∀f s. foldl1' f (unstream s) = S.foldl1' f s+  #-}+{-# INLINE [0] foldl1' #-}+foldl1' f = S.foldl1' f ∘ stream++-- | /O(n)/ 'foldr', applied to a binary operator, a starting value+-- (typically the right-identity of the operator), and a 'Bitstream',+-- reduces the 'Bitstream' using the binary operator, from right to+-- left:+--+-- @+-- 'foldr' f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...)+-- @+foldr ∷ Bitstream α ⇒ (Bool → β → β) → β → α → β+{-# RULES "Bitstream foldr/unstream fusion"+    ∀f β s. foldr f β (unstream s) = S.foldr f β s+  #-}+{-# INLINE [0] foldr #-}+foldr f β = S.foldr f β ∘ stream++-- | /O(n)/ 'foldr1' is a variant of 'foldr' that has no starting+-- value argument, and thus must be applied to non-empty 'Bitstream's.+foldr1 ∷ Bitstream α ⇒ (Bool → Bool → Bool) → α → Bool+{-# RULES "Bitstream foldr1/unstream fusion"+    ∀f s. foldr1 f (unstream s) = S.foldr1 f s+  #-}+{-# INLINE [0] foldr1 #-}+foldr1 f = S.foldr1 f ∘ stream++-- | /O(n)/ Concatenate all 'Bitstream's in the list.+concat ∷ Bitstream α ⇒ [α] → α+{-# INLINE [0] concat #-}+concat = basicConcat+ -- | Map a function over a 'Bitstream' and concatenate the results. concatMap ∷ Bitstream α ⇒ (Bool → α) → α → α {-# RULES "Bitstream concatMap/unstream fusion"     ∀f s. concatMap f (unstream s) = unstream (S.concatMap f s)   #-}-{-# INLINE [1] concatMap #-}+{-# INLINE [0] concatMap #-} concatMap f = concat ∘ L.map f ∘ unpack  -- | /O(n)/ 'and' returns the conjunction of a 'Bool' list. For the@@ -382,7 +519,7 @@ {-# RULES "Bitstream and/unstream fusion"     ∀s. and (unstream s) = S.and s   #-}-{-# INLINE [1] and #-}+{-# INLINE [0] and #-} and = S.and ∘ stream  -- | /O(n)/ 'or' returns the disjunction of a 'Bool' list. For the@@ -394,7 +531,7 @@ {-# RULES "Bitstream or/unstream fusion"     ∀s. or (unstream s) = S.or s   #-}-{-# INLINE [1] or #-}+{-# INLINE [0] or #-} or = S.or ∘ stream  -- | /O(n)/ Applied to a predicate and a 'Bitstream', 'any' determines@@ -406,7 +543,7 @@ {-# RULES "Bitstream any/unstream fusion"     ∀f s. any f (unstream s) = S.or (S.map f s)   #-}-{-# INLINE [1] any #-}+{-# INLINE [0] any #-} any f = S.or ∘ S.map f ∘ stream  -- | /O(n)/ Applied to a predicate and a 'Bitstream', 'all' determines@@ -418,9 +555,29 @@ {-# RULES "Bitstream all/unstream fusion"     ∀f s. all f (unstream s) = S.and (S.map f s)   #-}-{-# INLINE [1] all #-}+{-# INLINE [0] all #-} all f = S.and ∘ S.map f ∘ stream +-- | /O(n)/ 'scanl' is similar to 'foldl', but returns a 'Bitstream'+-- of successive reduced bits from the left:+--+-- @+-- 'scanl' f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...]+-- @+--+-- Note that+--+-- @+-- 'last' ('scanl' f z xs) == 'foldl' f z xs+-- @+scanl ∷ Bitstream α ⇒ (Bool → Bool → Bool) → Bool → α → α+{-# RULES+"Bitstream scanl/unstream fusion"+    ∀f b s. scanl f b (unstream s) = unstream (S.scanl f b s)+  #-}+{-# INLINE [0] scanl #-}+scanl = basicScanl+ -- | /O(n)/ 'scanl1' is a variant of 'scanl' that has no starting -- value argument: --@@ -428,10 +585,7 @@ -- 'scanl1' f [x1, x2, ...] == [x1, x1 `f` x2, ...] -- @ scanl1 ∷ Bitstream α ⇒ (Bool → Bool → Bool) → α → α-{-# RULES "Bitstream scanl1/unstream fusion"-    ∀f s. scanl1 f (unstream s) = S.scanl1 f s-  #-}-{-# INLINE [1] scanl1 #-}+{-# INLINE [0] scanl1 #-} scanl1 f α     | null α    = α     | otherwise = scanl f (head α) (tail α)@@ -442,81 +596,20 @@ -- 'head' ('scanr' f z xs) == 'foldr' f z xs -- @ scanr ∷ Bitstream α ⇒ (Bool → Bool → Bool) → Bool → α → α-{-# INLINE [1] scanr #-}+{-# INLINE [0] scanr #-} scanr f b = reverse ∘ scanl (flip f) b ∘ reverse  -- | /O(n)/ 'scanr1' is a variant of 'scanr' that has no starting -- value argument. scanr1 ∷ Bitstream α ⇒ (Bool → Bool → Bool) → α → α-{-# INLINE [1] scanr1 #-}+{-# INLINE [0] scanr1 #-} scanr1 f = reverse ∘ scanl1 (flip f) ∘ reverse --- | /O(n)/ 'foldl', applied to a binary operator, a starting value--- (typically the left-identity of the operator), and a 'Bitstream',--- reduces the 'Bitstream' using the binary operator, from left to--- right:------ @--- 'foldl' f z [x1, x2, ..., xn] == (...((z `f` x1) `f` x2) `f`...) `f` xn--- @------ The 'Bitstream' must be finite.-foldl ∷ Bitstream α ⇒ (β → Bool → β) → β → α → β-{-# RULES "Bitstream foldl/unstream fusion"-    ∀f β s. foldl f β (unstream s) = S.foldl f β s-  #-}-{-# INLINE [1] foldl #-}-foldl f β = S.foldl f β ∘ stream---- | /O(n)/ 'foldl'' is a variant of 'foldl' that is strict on the--- accumulator.-foldl' ∷ Bitstream α ⇒ (β → Bool → β) → β → α → β-{-# RULES "Bitstream foldl'/unstream fusion"-    ∀f β s. foldl' f β (unstream s) = S.foldl' f β s-  #-}-{-# INLINE [1] foldl' #-}-foldl' f β = S.foldl' f β ∘ stream---- | /O(n)/ 'foldl1' is a variant of 'foldl' that has no starting--- value argument, and thus must be applied to non-empty 'Bitstream's.-foldl1 ∷ Bitstream α ⇒ (Bool → Bool → Bool) → α → Bool-{-# RULES "Bitstream foldl1/unstream fusion"-    ∀f s. foldl1 f (unstream s) = S.foldl1 f s-  #-}-{-# INLINE [1] foldl1 #-}-foldl1 f = S.foldl1 f ∘ stream---- | /O(n)/ A strict version of 'foldl1'.-foldl1' ∷ Bitstream α ⇒ (Bool → Bool → Bool) → α → Bool-{-# RULES "Bitstream foldl1'/unstream fusion"-    ∀f s. foldl1' f (unstream s) = S.foldl1' f s-  #-}-{-# INLINE [1] foldl1' #-}-foldl1' f = S.foldl1' f ∘ stream---- | /O(n)/ 'foldr', applied to a binary operator, a starting value--- (typically the right-identity of the operator), and a 'Bitstream',--- reduces the 'Bitstream' using the binary operator, from right to--- left:------ @--- 'foldr' f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...)--- @-foldr ∷ Bitstream α ⇒ (Bool → β → β) → β → α → β-{-# RULES "Bitstream foldr/unstream fusion"-    ∀f β s. foldr f β (unstream s) = S.foldr f β s-  #-}-{-# INLINE [1] foldr #-}-foldr f β = S.foldr f β ∘ stream---- | /O(n)/ 'foldr1' is a variant of 'foldr' that has no starting--- value argument, and thus must be applied to non-empty 'Bitstream's.-foldr1 ∷ Bitstream α ⇒ (Bool → Bool → Bool) → α → Bool-{-# RULES "Bitstream foldr1/unstream fusion"-    ∀f s. foldr1 f (unstream s) = S.foldr1 f s-  #-}-{-# INLINE [1] foldr1 #-}-foldr1 f = S.foldr1 f ∘ stream+-- | /O(n)/ @'replicate' n x@ is a 'Bitstream' of length @n@ with @x@+-- the value of every bit.+replicate ∷ (Integral n, Bitstream α) ⇒ n → Bool → α+{-# INLINE replicate #-}+replicate n = unstream ∘ genericReplicate n  -- | /O(n)/ The 'unfoldr' function is a \`dual\' to 'foldr': while -- 'foldr' reduces a 'Bitstream' to a summary value, 'unfoldr' builds@@ -526,23 +619,56 @@ -- 'Bitstream' and @b@ is used as the next element in a recursive -- call. unfoldr ∷ Bitstream α ⇒ (β → Maybe (Bool, β)) → β → α-{-# INLINE [1] unfoldr #-}+{-# INLINE unfoldr #-} unfoldr f = unstream ∘ S.unfoldr f  -- | /O(n)/ 'unfoldrN' is a variant of 'unfoldr' but constructs a -- 'Bitstream' with at most @n@ bits.-unfoldrN ∷ (Bitstream α, Integral n) ⇒ n → (β → Maybe (Bool, β)) → β → α-{-# INLINE [1] unfoldrN #-}+unfoldrN ∷ (Integral n, Bitstream α) ⇒ n → (β → Maybe (Bool, β)) → β → α+{-# INLINE unfoldrN #-} unfoldrN n f = unstream ∘ genericUnfoldrN n f --- | /O(n)/ 'Bitstream' index (subscript) operator, starting from 0.-(!!) ∷ (Bitstream α, Integral n) ⇒ α → n → Bool-{-# RULES "Bitstream (!!)/unstream fusion"-    ∀s n. (unstream s) !! n = genericIndex s n+-- | /O(n)/ 'take' @n@, applied to a 'Bitstream' @xs@, returns the+-- prefix of @xs@ of length @n@, or @xs@ itself if @n > 'length' xs@.+take ∷ (Integral n, Bitstream α) ⇒ n → α → α+{-# RULES+"Bitstream take/unstream fusion"+    ∀n s. take n (unstream s) = unstream (genericTake n s)   #-}-{-# INLINE [1] (!!) #-}-α !! n = genericIndex (stream α) n+{-# INLINE [0] take #-}+take = basicTake +-- | /O(n)/ 'drop' @n xs@ returns the suffix of @xs@ after the first+-- @n@ bits, or 'empty' if @n > 'length' xs@.+drop ∷ (Integral n, Bitstream α) ⇒ n → α → α+{-# RULES+"Bitstream drop/unstream fusion"+    ∀n s. drop n (unstream s) = unstream (genericDrop n s)+  #-}+{-# INLINE [0] drop #-}+drop = basicDrop++-- | /O(n)/ 'takeWhile', applied to a predicate @p@ and a 'Bitstream'+-- @xs@, returns the longest prefix (possibly 'empty') of @xs@ of bits+-- that satisfy @p@.+takeWhile ∷ Bitstream α ⇒ (Bool → Bool) → α → α+{-# RULES+"Bitstream takeWhile/unstream fusion"+    ∀f s. takeWhile f (unstream s) = unstream (S.takeWhile f s)+  #-}+{-# INLINE [0] takeWhile #-}+takeWhile = basicTakeWhile++-- | /O(n)/ 'dropWhile' @p xs@ returns the suffix remaining after+-- 'takeWhile' @p xs@.+dropWhile ∷ Bitstream α ⇒ (Bool → Bool) → α → α+{-# RULES+"Bitstream dropWhile/unstream fusion"+    ∀f s. dropWhile f (unstream s) = unstream (S.dropWhile f s)+  #-}+{-# INLINE [0] dropWhile #-}+dropWhile = basicDropWhile+ -- | /O(n)/ 'span', applied to a predicate @p@ and a 'Bitstream' @xs@, -- returns a tuple where first element is longest prefix (possibly -- 'empty') of @xs@ of bits that satisfy @p@ and second element is the@@ -551,7 +677,7 @@ -- 'span' @p xs@ is equivalent to @('takeWhile' p xs, 'dropWhile' p -- xs)@ span ∷ Bitstream α ⇒ (Bool → Bool) → α → (α, α)-{-# INLINE [1] span #-}+{-# INLINE span #-} span f α     = let hd = takeWhile f α           tl = drop (length hd ∷ Integer) α@@ -565,7 +691,7 @@ -- -- 'break' @p@ is equivalent to @'span' ('not' . p)@. break ∷ Bitstream α ⇒ (Bool → Bool) → α → (α, α)-{-# INLINE [1] break #-}+{-# INLINE break #-} break f = span ((¬) ∘ f)  -- | /O(n)/ 'elem' is the 'Bitstream' membership predicate, usually@@ -577,18 +703,46 @@ {-# RULES "Bitstream elem/unstream fusion"     ∀b s. elem b (unstream s) = S.elem b s   #-}-{-# INLINE [1] elem #-}+{-# INLINE [0] elem #-} elem True  = or elem False = (¬) ∘ and +-- | (&#x2208;) = 'elem'+--+-- U+2208, ELEMENT OF+(∈) ∷ Bitstream α ⇒ Bool → α → Bool+{-# INLINE (∈) #-}+(∈) = elem++-- | (&#x220B;) = 'flip' (&#x2208;)+--+-- U+220B, CONTAINS AS MEMBER+(∋) ∷ Bitstream α ⇒ α → Bool → Bool+{-# INLINE (∋) #-}+(∋) = flip elem+ -- | /O(n)/ 'notElem' is the negation of 'elem'. notElem ∷ Bitstream α ⇒ Bool → α → Bool {-# RULES "Bitstream notElem/unstream fusion"     ∀b s. notElem b (unstream s) = S.notElem b s   #-}-{-# INLINE [1] notElem #-}+{-# INLINE [0] notElem #-} notElem = ((¬) ∘) ∘ (∈) +-- | (&#x2209;) = 'notElem'+--+-- U+2209, NOT AN ELEMENT OF+(∉) ∷ Bitstream α ⇒ Bool → α → Bool+{-# INLINE (∉) #-}+(∉) = notElem++-- | (&#x220C;) = 'flip' (&#x2209;)+--+-- U+220C, DOES NOT CONTAIN AS MEMBER+(∌) ∷ Bitstream α ⇒ α → Bool → Bool+(∌) = flip notElem+{-# INLINE (∌) #-}+ -- | /O(n)/ The 'find' function takes a predicate and a 'Bitstream' -- and returns the bit in the 'Bitstream' matching the predicate, or -- 'Nothing' if there is no such bit.@@ -596,9 +750,34 @@ {-# RULES "Bitstream find/unstream fusion"     ∀f s. find f (unstream s) = S.find f s   #-}-{-# INLINE [1] find #-}+{-# INLINE [0] find #-} find f = S.find f ∘ stream +-- | /O(n)/ 'filter', applied to a predicate and a 'Bitstream',+-- returns the 'Bitstream' of those bits that satisfy the predicate.+filter ∷ Bitstream α ⇒ (Bool → Bool) → α → α+{-# RULES+"Bitstream filter/unstream fusion"+    ∀f s. filter f (unstream s) = unstream (S.filter f s)+  #-}+{-# INLINE [0] filter #-}+filter = basicFilter++-- | /O(n)/ The 'partition' function takes a predicate and a+-- 'Bitstream' and returns the pair of 'Bitstream's of bits which do+-- and do not satisfy the predicate, respectively.+partition ∷ Bitstream α ⇒ (Bool → Bool) → α → (α, α)+{-# INLINE [0] partition #-}+partition = basicPartition++-- | /O(n)/ 'Bitstream' index (subscript) operator, starting from 0.+(!!) ∷ (Bitstream α, Integral n) ⇒ α → n → Bool+{-# RULES "Bitstream (!!)/unstream fusion"+    ∀s n. (unstream s) !! n = genericIndex s n+  #-}+{-# INLINE [0] (!!) #-}+α !! n = genericIndex (stream α) n+ -- | /O(n)/ The 'elemIndex' function returns the index of the first -- bit in the given 'Bitstream' which is equal to the query bit, or -- 'Nothing' if there is no such bit.@@ -606,7 +785,7 @@ {-# RULES "Bitstream elemIndex/unstream fusion"     ∀b s. elemIndex b (unstream s) = genericFindIndex (≡ b) s   #-}-{-# INLINE [1] elemIndex #-}+{-# INLINE [0] elemIndex #-} elemIndex = findIndex ∘ (≡)  -- | /O(n)/ The 'elemIndices' function extends 'elemIndex', by@@ -620,7 +799,7 @@               $ S.filter ((≡ b) ∘ snd)               $ genericIndexed s   #-}-{-# INLINE [1] elemIndices #-}+{-# INLINE [0] elemIndices #-} elemIndices = findIndices ∘ (≡)  -- | /O(n)/ The 'findIndex' function takes a predicate and a@@ -631,7 +810,7 @@ {-# RULES "Bitstream findIndex/unstream fusion"     ∀f s. findIndex f (unstream s) = genericFindIndex f s   #-}-{-# INLINE [1] findIndex #-}+{-# INLINE [0] findIndex #-} findIndex f = genericFindIndex f ∘ stream  -- | /O(n)/ The 'findIndices' function extends 'findIndex', by@@ -645,7 +824,7 @@               $ S.filter (f ∘ snd)               $ genericIndexed s   #-}-{-# INLINE [1] findIndices #-}+{-# INLINE [0] findIndices #-} findIndices f     = S.toList     ∘ S.map fst@@ -661,7 +840,7 @@     zip (unstream s1) (unstream s2)         = S.toList (S.zip s1 s2)   #-}-{-# INLINE [1] zip #-}+{-# INLINE [0] zip #-} zip = zipWith (,)  -- | The 'zip3' function takes three 'Bitstream's and returns a list@@ -671,7 +850,7 @@     zip3 (unstream s1) (unstream s2) (unstream s3)         = S.toList (S.zip3 s1 s2 s3)   #-}-{-# INLINE [1] zip3 #-}+{-# INLINE [0] zip3 #-} zip3 = zipWith3 (,,)  -- | The 'zip4' function takes four lists and returns a list of@@ -681,7 +860,7 @@     zip4 (unstream s1) (unstream s2) (unstream s3) (unstream s4)         = S.toList (S.zip4 s1 s2 s3 s4)   #-}-{-# INLINE [1] zip4 #-}+{-# INLINE [0] zip4 #-} zip4 = zipWith4 (,,,)  -- | The 'zip5' function takes five 'Bitstream's and returns a list of@@ -691,7 +870,7 @@     zip5 (unstream s1) (unstream s2) (unstream s3) (unstream s4) (unstream s5)         = S.toList (S.zip5 s1 s2 s3 s4 s5)   #-}-{-# INLINE [1] zip5 #-}+{-# INLINE [0] zip5 #-} zip5 = zipWith5 (,,,,)  -- | The 'zip6' function takes six 'Bitstream's and returns a list of@@ -701,7 +880,7 @@     zip6 (unstream s1) (unstream s2) (unstream s3) (unstream s4) (unstream s5) (unstream s6)         = S.toList (S.zip6 s1 s2 s3 s4 s5 s6)   #-}-{-# INLINE [1] zip6 #-}+{-# INLINE [0] zip6 #-} zip6 = zipWith6 (,,,,,)  -- | /O(min(m, n))/ 'zipWith' generalises 'zip' by zipping with the@@ -712,7 +891,7 @@     zipWith f (unstream s1) (unstream s2)         = S.toList (S.zipWith f s1 s2)   #-}-{-# INLINEABLE [1] zipWith #-}+{-# INLINEABLE [0] zipWith #-} zipWith f α β = S.toList $                 S.zipWith f                      (stream α)@@ -726,7 +905,7 @@     zipWith3 f (unstream s1) (unstream s2) (unstream s3)         = S.toList (S.zipWith3 f s1 s2 s3)   #-}-{-# INLINEABLE [1] zipWith3 #-}+{-# INLINEABLE [0] zipWith3 #-} zipWith3 f α β γ = S.toList $                    S.zipWith3 f                         (stream α)@@ -741,7 +920,7 @@     zipWith4 f (unstream s1) (unstream s2) (unstream s3) (unstream s4)         = S.toList (S.zipWith4 f s1 s2 s3 s4)   #-}-{-# INLINEABLE [1] zipWith4 #-}+{-# INLINEABLE [0] zipWith4 #-} zipWith4 f α β γ δ = S.toList $                      S.zipWith4 f                           (stream α)@@ -757,7 +936,7 @@     zipWith5 f (unstream s1) (unstream s2) (unstream s3) (unstream s4) (unstream s5)         = S.toList (S.zipWith5 f s1 s2 s3 s4 s5)   #-}-{-# INLINEABLE [1] zipWith5 #-}+{-# INLINEABLE [0] zipWith5 #-} zipWith5 f α β γ δ ε = S.toList $                        S.zipWith5 f                             (stream α)@@ -774,7 +953,7 @@     zipWith6 f (unstream s1) (unstream s2) (unstream s3) (unstream s4) (unstream s5) (unstream s6)         = S.toList (S.zipWith6 f s1 s2 s3 s4 s5 s6)   #-}-{-# INLINEABLE [1] zipWith6 #-}+{-# INLINEABLE [0] zipWith6 #-} zipWith6 f α β γ δ ε ζ = S.toList $                          S.zipWith6 f                               (stream α)@@ -788,14 +967,14 @@ -- 'Bitstream' of first components and a 'Bitstream' of second -- components. unzip ∷ Bitstream α ⇒ [(Bool, Bool)] → (α, α)-{-# INLINEABLE [1] unzip #-}+{-# INLINEABLE unzip #-} unzip xs = ( unstream $ S.map fst $ S.fromList xs            , unstream $ S.map snd $ S.fromList xs )  -- | The 'unzip3' function takes a list of triples and returns three -- 'Bitstream's, analogous to 'unzip'. unzip3 ∷ Bitstream α ⇒ [(Bool, Bool, Bool)] → (α, α, α)-{-# INLINEABLE [1] unzip3 #-}+{-# INLINEABLE unzip3 #-} unzip3 xs = ( unstream $ S.map (\(α, _, _) → α) $ S.fromList xs             , unstream $ S.map (\(_, β, _) → β) $ S.fromList xs             , unstream $ S.map (\(_, _, γ) → γ) $ S.fromList xs )@@ -803,7 +982,7 @@ -- | The 'unzip4' function takes a list of quadruples and returns -- four 'Bitstream's, analogous to 'unzip'. unzip4 ∷ Bitstream α ⇒ [(Bool, Bool, Bool, Bool)] → (α, α, α, α)-{-# INLINEABLE [1] unzip4 #-}+{-# INLINEABLE unzip4 #-} unzip4 xs = ( unstream $ S.map (\(α, _, _, _) → α) $ S.fromList xs             , unstream $ S.map (\(_, β, _, _) → β) $ S.fromList xs             , unstream $ S.map (\(_, _, γ, _) → γ) $ S.fromList xs@@ -812,7 +991,7 @@ -- | The 'unzip5' function takes a list of five-tuples and returns -- five 'Bitstream's, analogous to 'unzip'. unzip5 ∷ Bitstream α ⇒ [(Bool, Bool, Bool, Bool, Bool)] → (α, α, α, α, α)-{-# INLINEABLE [1] unzip5 #-}+{-# INLINEABLE unzip5 #-} unzip5 xs = ( unstream $ S.map (\(α, _, _, _, _) → α) $ S.fromList xs             , unstream $ S.map (\(_, β, _, _, _) → β) $ S.fromList xs             , unstream $ S.map (\(_, _, γ, _, _) → γ) $ S.fromList xs@@ -822,62 +1001,10 @@ -- | The 'unzip6' function takes a list of six-tuples and returns six -- 'Bitstream's, analogous to 'unzip'. unzip6 ∷ Bitstream α ⇒ [(Bool, Bool, Bool, Bool, Bool, Bool)] → (α, α, α, α, α, α)-{-# INLINEABLE [1] unzip6 #-}+{-# INLINEABLE unzip6 #-} unzip6 xs = ( unstream $ S.map (\(α, _, _, _, _, _) → α) $ S.fromList xs             , unstream $ S.map (\(_, β, _, _, _, _) → β) $ S.fromList xs             , unstream $ S.map (\(_, _, γ, _, _, _) → γ) $ S.fromList xs             , unstream $ S.map (\(_, _, _, δ, _, _) → δ) $ S.fromList xs             , unstream $ S.map (\(_, _, _, _, ε, _) → ε) $ S.fromList xs             , unstream $ S.map (\(_, _, _, _, _, ζ) → ζ) $ S.fromList xs )--{-# RULES-"Bitstream stream/unstream fusion"-    ∀s. stream (unstream s) = s--"Bitstream unstream/stream fusion"-    ∀v. unstream (stream v) = v-  #-}--{-# RULES-"Bitstream cons/unstream fusion"-    ∀b s. cons b (unstream s) = unstream (S.cons b s)--"Bitstream cons'/unstream fusion"-    ∀b s. cons' b (unstream s) = unstream (S.cons b s)--"Bitstream snoc/unstream fusion"-    ∀s b. snoc (unstream s) b = unstream (S.snoc s b)--"Bitstream append/unstream fusion"-    ∀s1 s2. append (unstream s1) (unstream s2) = unstream (s1 S.++ s2)--"Bitstream tail/unstream fusion"-    ∀s. tail (unstream s) = unstream (S.tail s)--"Bitstream init/unstream fusion"-    ∀s. init (unstream s) = unstream (S.init s)--"Bitstream map/unstream fusion"-    ∀f s. map f (unstream s) = unstream (S.map f s)--"Bitstream scanl/unstream fusion"-    ∀f b s. scanl f b (unstream s) = unstream (S.scanl f b s)--"Bitstream scanl1/unstream fusion"-    ∀f s. scanl1 f (unstream s) = unstream (S.scanl1 f s)--"Bitstream take/unstream fusion"-    ∀n s. take n (unstream s) = unstream (genericTake n s)--"Bitstream drop/unstream fusion"-    ∀n s. drop n (unstream s) = unstream (genericDrop n s)--"Bitstream takeWhile/unstream fusion"-    ∀f s. takeWhile f (unstream s) = unstream (S.takeWhile f s)--"Bitstream dropWhile/unstream fusion"-    ∀f s. dropWhile f (unstream s) = unstream (S.dropWhile f s)--"Bitstream filter/unstream fusion"-    ∀f s. filter f (unstream s) = unstream (S.filter f s)-  #-}
Data/Bitstream/Internal.hs view
@@ -4,24 +4,31 @@   #-} module Data.Bitstream.Internal     ( packPackets++    , lePacketsFromNBits+    , bePacketsFromNBits++    , lePacketsToBits+    , bePacketsToBits     )     where+import Data.Bits import Data.Bitstream.Generic import Data.Bitstream.Packet import Data.Vector.Fusion.Stream.Monadic (Stream(..), Step(..)) import Data.Vector.Fusion.Stream.Size-import Prelude hiding (null)+import Prelude hiding (length, null) import Prelude.Unicode  packPackets ∷ (Bitstream (Packet d), Monad m) ⇒ Stream m Bool → Stream m (Packet d)-{-# INLINE packPackets #-}+{-# INLINEABLE packPackets #-} packPackets (Stream step s0 sz) = Stream step' ((∅), Just s0) sz'     where       sz' ∷ Size       {-# INLINE sz' #-}       sz' = case sz of-              Exact n → Exact (n+7 `div` 8)-              Max   n → Max   (n+7 `div` 8)+              Exact n → Exact ((n+7) `div` 8)+              Max   n → Max   ((n+7) `div` 8)               Unknown → Unknown       {-# INLINE step' #-}       step' (p, Just s)@@ -36,3 +43,84 @@                      | otherwise → return $ Yield p ((⊥)       , Nothing)       step' (_, Nothing)           = return Done++nOctets ∷ Integral n ⇒ n → Int+{-# INLINE nOctets #-}+nOctets nBits+    = (fromIntegral nBits + 7) `div` 8++lePacketsFromNBits ∷ ( Integral n+                     , Integral β+                     , Bits β+                     , Monad m+                     )+                   ⇒ n+                   → β+                   → Stream m (Packet Left)+{-# INLINEABLE lePacketsFromNBits #-}+lePacketsFromNBits n0 β0 = Stream step (n0, β0) (Exact (nOctets n0))+    where+      {-# INLINE step #-}+      step (n, β)+          | n > 0+              = let !n'  = min 8 n+                    !n'' = n - n'+                    !p   = fromNBits n' β+                    !β'  = β `shiftR` 8+                in+                  return $ Yield p (n'', β')+          | otherwise+              = return Done++bePacketsFromNBits ∷ ( Integral n+                     , Integral β+                     , Bits β+                     , Monad m+                     )+                   ⇒ n+                   → β+                   → Stream m (Packet Right)+{-# INLINEABLE bePacketsFromNBits #-}+bePacketsFromNBits n0 β = Stream step (n0, nOctets n0 ⋅ 8) (Exact (nOctets n0))+    where+      {-# INLINE step #-}+      step (n, r)+          | n > 0+              = let !r'  = r - 8+                    !n'  = n - fromIntegral r'+                    !n'' = n - n'+                    !p   = fromNBits n' (β `shiftR` r')+                in+                  return $ Yield p (n'', r')+          | otherwise+              = return Done++lePacketsToBits ∷ (Monad m, Bits β) ⇒ Stream m (Packet Left) → m β+{-# INLINEABLE lePacketsToBits #-}+lePacketsToBits (Stream step s0 _) = go (s0, 0, 0)+    where+      {-# INLINE go #-}+      go (s, o, n)+          = do r ← step s+               case r of+                 Yield p s' → let !n' = (toBits p `shiftL` o) .|. n+                                  !o' = o + length p+                              in+                                go (s', o', n')+                 Skip    s' → go (s', o, n)+                 Done       → return n++bePacketsToBits ∷ (Monad m, Bits β) ⇒ Stream m (Packet Right) → m β+{-# INLINEABLE bePacketsToBits #-}+bePacketsToBits (Stream step s0 _) = go (s0, 0)+    where+      {-# INLINE go #-}+      go (s, n)+          = do r ← step s+               case r of+                 Yield p s' → let !o  = length p+                                  !n' = (n `shiftL` o) .|. toBits p+                              in+                                go (s', n')+                 Skip    s' → go (s', n)+                 Done       → return n
Data/Bitstream/Lazy.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE     BangPatterns   , FlexibleContexts+  , FlexibleInstances   , ScopedTypeVariables   , UndecidableInstances   , UnicodeSyntax@@ -16,7 +17,7 @@ -- Lazy 'Bitstream's are made of possibly infinite list of strict -- 'SB.Bitstream's as chunks, and each chunks have at least 1 bit. module Data.Bitstream.Lazy-    ( -- * Types+    ( -- * Data types       Bitstream     , Left     , Right@@ -34,6 +35,11 @@     , fromByteString     , toByteString +    -- ** Converting from\/to 'Bits''+    , fromBits+    , fromNBits+    , toBits+       -- ** Converting from\/to 'S.Stream's     , stream     , unstream@@ -75,7 +81,7 @@     , any     , all -      -- * Building lists+      -- * Building 'Bitstream's       -- ** Scans     , scanl     , scanl1@@ -205,7 +211,7 @@           , " ]"           ] -instance G.Bitstream (Packet d) ⇒ Eq (Bitstream d) where+instance G.Bitstream (Bitstream d) ⇒ Eq (Bitstream d) where     {-# INLINE (==) #-}     x == y = stream x ≡ stream y @@ -220,7 +226,7 @@ --   , 'compare' z y -- 'LT' --   ] -- @-instance G.Bitstream (Packet d) ⇒ Ord (Bitstream d) where+instance G.Bitstream (Bitstream d) ⇒ Ord (Bitstream d) where     {-# INLINE compare #-}     x `compare` y = stream x `compare` stream y @@ -231,142 +237,319 @@ -- 'mappend' = 'append' -- 'mconcat' = 'concat' -- @-instance G.Bitstream (Packet d) ⇒ Monoid (Bitstream d) where+instance G.Bitstream (Bitstream d) ⇒ Monoid (Bitstream d) where     mempty  = (∅)     mappend = (⧺)     mconcat = concat -instance G.Bitstream (Packet d) ⇒ G.Bitstream (Bitstream d) where-    {-# INLINE [0] stream #-}-    stream-        = {-# CORE "Lazy Bitstream stream" #-}-          S.concatMap stream ∘ streamChunks+instance G.Bitstream (Bitstream Left) where+    {-# INLINE basicStream #-}+    basicStream = lazyStream -    {-# INLINE [0] unstream #-}-    unstream-        = {-# CORE "Lazy Bitstream unstream" #-}-          unId ∘ unstreamChunks ∘ packChunks ∘ packPackets+    {-# INLINE basicUnstream #-}+    basicUnstream = lazyUnstream -    {-# INLINE [2] cons #-}-    cons b = Chunk (singleton b)+    {-# INLINE basicCons #-}+    basicCons = lazyCons -    {-# INLINEABLE [2] cons' #-}-    cons' b Empty-        = Chunk (SB.singleton b) Empty-    cons' b (Chunk x xs)-        | length x < (chunkBits ∷ Int)-            = Chunk (b `cons` x) xs-        | otherwise-            = Chunk (singleton b) (Chunk x xs)+    {-# INLINE basicCons' #-}+    basicCons' = lazyCons' -    {-# INLINEABLE [2] snoc #-}-    snoc Empty b-        = Chunk (SB.singleton b) Empty-    snoc (Chunk x Empty) b-        | length x < (chunkBits ∷ Int)-            = Chunk (x `snoc` b) Empty-        | otherwise-            = Chunk x (Chunk (singleton b) Empty)-    snoc (Chunk x xs) b-        = Chunk x (xs `snoc` b)+    {-# INLINE basicSnoc #-}+    basicSnoc = lazySnoc -    {-# INLINE [2] append #-}-    append Empty ch        = ch-    append (Chunk x xs) ch = Chunk x (append xs ch)+    {-# INLINE basicAppend #-}+    basicAppend = lazyAppend -    {-# INLINEABLE [2] tail #-}-    tail Empty        = emptyStream-    tail (Chunk x xs) = case tail x of+    {-# INLINE basicTail #-}+    basicTail = lazyTail++    {-# INLINE basicInit #-}+    basicInit = lazyInit++    {-# INLINE basicMap #-}+    basicMap = lazyMap++    {-# INLINE basicReverse #-}+    basicReverse = lazyReverse++    {-# INLINE basicConcat #-}+    basicConcat = lazyConcat++    {-# INLINE basicScanl #-}+    basicScanl = lazyScanl++    {-# INLINE basicTake #-}+    basicTake = lazyTake++    {-# INLINE basicDrop #-}+    basicDrop = lazyDrop++    {-# INLINE basicTakeWhile #-}+    basicTakeWhile = lazyTakeWhile++    {-# INLINE basicDropWhile #-}+    basicDropWhile = lazyDropWhile++    {-# INLINE basicFilter #-}+    basicFilter = lazyFilter++    {-# INLINE basicFromNBits #-}+    basicFromNBits+        = ((unId ∘ unstreamChunks ∘ packChunks) ∘) ∘ lePacketsFromNBits++    {-# INLINE basicToBits #-}+    basicToBits = unId ∘ lePacketsToBits ∘ unpackChunks ∘ streamChunks++instance G.Bitstream (Bitstream Right) where+    {-# INLINE basicStream #-}+    basicStream = lazyStream++    {-# INLINE basicUnstream #-}+    basicUnstream = lazyUnstream++    {-# INLINE basicCons #-}+    basicCons = lazyCons++    {-# INLINE basicCons' #-}+    basicCons' = lazyCons'++    {-# INLINE basicSnoc #-}+    basicSnoc = lazySnoc++    {-# INLINE basicAppend #-}+    basicAppend = lazyAppend++    {-# INLINE basicTail #-}+    basicTail = lazyTail++    {-# INLINE basicInit #-}+    basicInit = lazyInit++    {-# INLINE basicMap #-}+    basicMap = lazyMap++    {-# INLINE basicReverse #-}+    basicReverse = lazyReverse++    {-# INLINE basicConcat #-}+    basicConcat = lazyConcat++    {-# INLINE basicScanl #-}+    basicScanl = lazyScanl++    {-# INLINE basicTake #-}+    basicTake = lazyTake++    {-# INLINE basicDrop #-}+    basicDrop = lazyDrop++    {-# INLINE basicTakeWhile #-}+    basicTakeWhile = lazyTakeWhile++    {-# INLINE basicDropWhile #-}+    basicDropWhile = lazyDropWhile++    {-# INLINE basicFilter #-}+    basicFilter = lazyFilter++    {-# INLINE basicFromNBits #-}+    basicFromNBits+        = ((unId ∘ unstreamChunks ∘ packChunks) ∘) ∘ bePacketsFromNBits++    {-# INLINE basicToBits #-}+    basicToBits = unId ∘ bePacketsToBits ∘ unpackChunks ∘ streamChunks++lazyStream ∷ G.Bitstream (SB.Bitstream d) ⇒ Bitstream d → S.Stream Bool+{-# INLINE lazyStream #-}+lazyStream+    = {-# CORE "Lazy Bitstream stream" #-}+      S.concatMap stream ∘ streamChunks++lazyUnstream ∷ ( G.Bitstream (SB.Bitstream d)+               , G.Bitstream (Packet d)+               )+             ⇒ S.Stream Bool+             → Bitstream d+{-# INLINE lazyUnstream #-}+lazyUnstream+    = {-# CORE "Lazy Bitstream unstream" #-}+      unId ∘ unstreamChunks ∘ packChunks ∘ packPackets++lazyCons ∷ G.Bitstream (SB.Bitstream d) ⇒ Bool → Bitstream d → Bitstream d+{-# INLINE lazyCons #-}+lazyCons = Chunk ∘ singleton++lazyCons' ∷ G.Bitstream (SB.Bitstream d) ⇒ Bool → Bitstream d → Bitstream d+{-# INLINEABLE lazyCons' #-}+lazyCons' b Empty+    = Chunk (SB.singleton b) Empty+lazyCons' b (Chunk x xs)+    | length x < (chunkBits ∷ Int)+        = Chunk (b `cons` x) xs+    | otherwise+        = Chunk (singleton b) (Chunk x xs)++lazySnoc ∷ ( G.Bitstream (SB.Bitstream d)+           , G.Bitstream (Bitstream d)+           )+         ⇒ Bitstream d+         → Bool+         → Bitstream d+{-# INLINEABLE lazySnoc #-}+lazySnoc Empty b+    = Chunk (SB.singleton b) Empty+lazySnoc (Chunk x Empty) b+    | length x < (chunkBits ∷ Int)+        = Chunk (x `snoc` b) Empty+    | otherwise+        = Chunk x (Chunk (singleton b) Empty)+lazySnoc (Chunk x xs) b+    = Chunk x (xs `snoc` b)++lazyAppend ∷ G.Bitstream (Bitstream d) ⇒ Bitstream d → Bitstream d → Bitstream d+{-# INLINE lazyAppend #-}+lazyAppend Empty ch        = ch+lazyAppend (Chunk x xs) ch = Chunk x (append xs ch)++lazyTail ∷ G.Bitstream (SB.Bitstream d) ⇒ Bitstream d → Bitstream d+{-# INLINEABLE lazyTail #-}+lazyTail Empty        = emptyStream+lazyTail (Chunk x xs) = case tail x of                           x' | null x'   → xs                              | otherwise → Chunk x' xs -    {-# INLINEABLE [2] init #-}-    init Empty           = emptyStream-    init (Chunk x Empty) = case init x of+lazyInit ∷ ( G.Bitstream (SB.Bitstream d)+           , G.Bitstream (Bitstream d)+           )+         ⇒ Bitstream d+         → Bitstream d+{-# INLINEABLE lazyInit #-}+lazyInit Empty           = emptyStream+lazyInit (Chunk x Empty) = case init x of                              x' | null x'   → Empty                                 | otherwise → Chunk x' Empty-    init (Chunk x xs   ) = Chunk x (init xs)--    {-# INLINE [2] map #-}-    map _ Empty        = Empty-    map f (Chunk x xs) = Chunk (map f x) (map f xs)+lazyInit (Chunk x xs   ) = Chunk x (init xs) -    {-# INLINEABLE [2] reverse #-}-    reverse ch0 = go ch0 Empty-        where-          {-# INLINE go #-}-          go Empty        ch = ch-          go (Chunk x xs) ch = go xs (Chunk (reverse x) ch)+lazyMap ∷ ( G.Bitstream (SB.Bitstream d)+          , G.Bitstream (Bitstream d)+          )+        ⇒ (Bool → Bool)+        → Bitstream d+        → Bitstream d+{-# INLINE lazyMap #-}+lazyMap _ Empty        = Empty+lazyMap f (Chunk x xs) = Chunk (map f x) (map f xs) -    {-# INLINE [2] scanl #-}-    scanl f b ch-        = Chunk (singleton b)-                (case ch of-                   Empty      → Empty-                   Chunk x xs → let h   = head x-                                    x'  = scanl f (f b h) (tail x)-                                    l   = last x'-                                    x'' = init x'-                                    xs' = scanl f l xs-                                in-                                  if null x''-                                  then xs'-                                  else Chunk x'' xs')+lazyReverse ∷ G.Bitstream (SB.Bitstream d) ⇒ Bitstream d → Bitstream d+{-# INLINEABLE lazyReverse #-}+lazyReverse ch0 = go ch0 Empty+    where+      {-# INLINE go #-}+      go Empty        ch = ch+      go (Chunk x xs) ch = go xs (Chunk (reverse x) ch) -    {-# INLINE [2] concat #-}-    concat = fromChunks ∘ L.concatMap toChunks+lazyConcat ∷ G.Bitstream (SB.Bitstream d) ⇒ [Bitstream d] → Bitstream d+{-# INLINE lazyConcat #-}+lazyConcat = fromChunks ∘ L.concatMap toChunks -    {-# INLINEABLE replicate #-}-    replicate n b-        | n ≤ 0         = Empty-        | n < chunkBits = Chunk (replicate n b) Empty-        | otherwise     = Chunk x (replicate (n - chunkBits) b)-        where-          x = replicate (chunkBits ∷ Int) b+lazyScanl ∷ ( G.Bitstream (SB.Bitstream d)+            , G.Bitstream (Bitstream d)+            )+          ⇒ (Bool → Bool → Bool)+          → Bool+          → Bitstream d+          → Bitstream d+{-# INLINEABLE lazyScanl #-}+lazyScanl f b ch+    = Chunk (singleton b)+            (case ch of+               Empty      → Empty+               Chunk x xs → let h   = head x+                                x'  = scanl f (f b h) (tail x)+                                l   = last x'+                                x'' = init x'+                                xs' = scanl f l xs+                            in+                              if null x''+                              then xs'+                              else Chunk x'' xs') -    {-# INLINEABLE [2] take #-}-    take _ Empty        = Empty-    take n (Chunk x xs)-        | n ≤ 0         = Empty-        | n ≥ length x  = Chunk x (take (n - length x) xs)-        | otherwise     = Chunk (take n x) Empty+lazyTake ∷ ( Integral n+           , G.Bitstream (SB.Bitstream d)+           , G.Bitstream (Bitstream d)+           )+         ⇒ n+         → Bitstream d+         → Bitstream d+{-# INLINEABLE lazyTake #-}+lazyTake _ Empty        = Empty+lazyTake n (Chunk x xs)+    | n ≤ 0              = Empty+    | n ≥ length x       = Chunk x (take (n - length x) xs)+    | otherwise          = Chunk (take n x) Empty -    {-# INLINEABLE [2] drop #-}-    drop _ Empty       = Empty-    drop n (Chunk x xs)-        | n ≤ 0        = Chunk x xs-        | n ≥ length x = drop (n - length x) xs-        | otherwise    = Chunk (drop n x) xs+lazyDrop ∷ ( Integral n+           , G.Bitstream (SB.Bitstream d)+           , G.Bitstream (Bitstream d)+           )+         ⇒ n+         → Bitstream d+         → Bitstream d+{-# INLINEABLE lazyDrop #-}+lazyDrop _ Empty        = Empty+lazyDrop n (Chunk x xs)+    | n ≤ 0              = Chunk x xs+    | n ≥ length x       = drop (n - length x) xs+    | otherwise          = Chunk (drop n x) xs -    {-# INLINEABLE [2] takeWhile #-}-    takeWhile _ Empty        = Empty-    takeWhile f (Chunk x xs) = case takeWhile f x of+lazyTakeWhile ∷ ( G.Bitstream (SB.Bitstream d)+                , G.Bitstream (Bitstream d)+                )+              ⇒ (Bool → Bool)+              → Bitstream d+              → Bitstream d+{-# INLINEABLE lazyTakeWhile #-}+lazyTakeWhile _ Empty        = Empty+lazyTakeWhile f (Chunk x xs) = case takeWhile f x of                                  x' | x ≡ x'    → Chunk x' (takeWhile f xs)                                     | otherwise → Chunk x' Empty -    {-# INLINEABLE [2] dropWhile #-}-    dropWhile _ Empty        = Empty-    dropWhile f (Chunk x xs) = case dropWhile f x of+lazyDropWhile ∷ ( G.Bitstream (SB.Bitstream d)+                , G.Bitstream (Bitstream d)+                )+              ⇒ (Bool → Bool)+              → Bitstream d+              → Bitstream d+{-# INLINEABLE lazyDropWhile #-}+lazyDropWhile _ Empty        = Empty+lazyDropWhile f (Chunk x xs) = case dropWhile f x of                                  x' | null x'   → dropWhile f xs                                     | otherwise → Chunk x' xs -    {-# INLINEABLE [2] filter #-}-    filter _ Empty        = Empty-    filter f (Chunk x xs) = case filter f x of+lazyFilter ∷ ( G.Bitstream (SB.Bitstream d)+             , G.Bitstream (Bitstream d)+             )+           ⇒ (Bool → Bool)+           → Bitstream d+           → Bitstream d+{-# INLINEABLE lazyFilter #-}+lazyFilter _ Empty        = Empty+lazyFilter f (Chunk x xs) = case filter f x of                               x' | null x'   → filter f xs                                  | otherwise → Chunk x' (filter f xs) -lazyHead ∷ G.Bitstream (Packet d) ⇒ Bitstream d → Bool-{-# RULES "head → lazyHead" [2]-    ∀(v ∷ G.Bitstream (Packet d) ⇒ Bitstream d).+lazyHead ∷ G.Bitstream (SB.Bitstream d) ⇒ Bitstream d → Bool+{-# RULES "head → lazyHead" [1]+    ∀(v ∷ G.Bitstream (SB.Bitstream d) ⇒ Bitstream d).     head v = lazyHead v #-} {-# INLINE lazyHead #-} lazyHead Empty       = emptyStream lazyHead (Chunk x _) = head x -lazyLast ∷ G.Bitstream (Packet d) ⇒ Bitstream d → Bool-{-# RULES "last → lazyLast" [2]-    ∀(v ∷ G.Bitstream (Packet d) ⇒ Bitstream d).+lazyLast ∷ G.Bitstream (SB.Bitstream d) ⇒ Bitstream d → Bool+{-# RULES "last → lazyLast" [1]+    ∀(v ∷ G.Bitstream (SB.Bitstream d) ⇒ Bitstream d).     last v = lazyLast v #-} {-# INLINE lazyLast #-} lazyLast Empty           = emptyStream@@ -374,14 +557,14 @@ lazyLast (Chunk _ xs   ) = lazyLast xs  lazyNull ∷ Bitstream d → Bool-{-# RULES "null → lazyNull" [2] null = lazyNull #-}+{-# RULES "null → lazyNull" [1] null = lazyNull #-} {-# INLINE lazyNull #-} lazyNull Empty = True lazyNull _     = False -lazyLength ∷ (G.Bitstream (Packet d), Num n) ⇒ Bitstream d → n-{-# RULES "length → lazyLength" [2]-    ∀(v ∷ G.Bitstream (Packet d) ⇒ Bitstream d).+lazyLength ∷ (G.Bitstream (SB.Bitstream d), Num n) ⇒ Bitstream d → n+{-# RULES "length → lazyLength" [1]+    ∀(v ∷ G.Bitstream (SB.Bitstream d) ⇒ Bitstream d).     length v = lazyLength v #-} {-# INLINE lazyLength #-} lazyLength = go 0@@ -390,9 +573,9 @@       go !soFar Empty        = soFar       go !soFar (Chunk x xs) = go (soFar + length x) xs -lazyAnd ∷ G.Bitstream (Packet d) ⇒ Bitstream d → Bool-{-# RULES "and → lazyAnd" [2]-    ∀(v ∷ G.Bitstream (Packet d) ⇒ Bitstream d).+lazyAnd ∷ G.Bitstream (SB.Bitstream d) ⇒ Bitstream d → Bool+{-# RULES "and → lazyAnd" [1]+    ∀(v ∷ G.Bitstream (SB.Bitstream d) ⇒ Bitstream d).     and v = lazyAnd v #-} {-# INLINEABLE lazyAnd #-} lazyAnd Empty        = False@@ -400,9 +583,9 @@     | and x          = lazyAnd xs     | otherwise      = False -lazyOr ∷ G.Bitstream (Packet d) ⇒ Bitstream d → Bool-{-# RULES "or → lazyOr" [2]-    ∀(v ∷ G.Bitstream (Packet d) ⇒ Bitstream d).+lazyOr ∷ G.Bitstream (SB.Bitstream d) ⇒ Bitstream d → Bool+{-# RULES "or → lazyOr" [1]+    ∀(v ∷ G.Bitstream (SB.Bitstream d) ⇒ Bitstream d).     or v = lazyOr v #-} {-# INLINEABLE lazyOr #-} lazyOr Empty        = True@@ -410,9 +593,14 @@     | or x          = True     | otherwise     = lazyOr xs -lazyIndex ∷ (G.Bitstream (Packet d), Integral n) ⇒ Bitstream d → n → Bool-{-# RULES "(!!) → lazyIndex" [2]-    ∀(v ∷ G.Bitstream (Packet d) ⇒ Bitstream d) n.+lazyIndex ∷ ( G.Bitstream (SB.Bitstream d)+            , Integral n+            )+          ⇒ Bitstream d+          → n+          → Bool+{-# RULES "(!!) → lazyIndex" [1]+    ∀(v ∷ G.Bitstream (SB.Bitstream d) ⇒ Bitstream d) n.     v !! n = lazyIndex v n #-} {-# INLINEABLE lazyIndex #-} lazyIndex ch0 i0@@ -435,7 +623,7 @@  -- | /O(n)/ Convert a list of chunks, strict 'SB.Bitstream's, into a -- lazy 'Bitstream'.-fromChunks ∷ G.Bitstream (Packet d) ⇒ [SB.Bitstream d] → Bitstream d+fromChunks ∷ G.Bitstream (SB.Bitstream d) ⇒ [SB.Bitstream d] → Bitstream d {-# INLINE fromChunks #-} fromChunks []     = Empty fromChunks (x:xs)@@ -450,7 +638,7 @@ toChunks (Chunk x xs) = x : toChunks xs  -- | /O(n)/ Convert a lazy 'LS.ByteString' into a lazy 'Bitstream'.-fromByteString ∷ G.Bitstream (Packet d) ⇒ LS.ByteString → Bitstream d+fromByteString ∷ G.Bitstream (SB.Bitstream d) ⇒ LS.ByteString → Bitstream d {-# INLINE fromByteString #-} fromByteString = fromChunks ∘ L.map SB.fromByteString ∘ LS.toChunks @@ -458,22 +646,32 @@ -- into a lazy 'LS.ByteString'. The resulting octets will be padded -- with zeroes if @bs@ is finite and its 'length' is not multiple of -- 8.-toByteString ∷ G.Bitstream (Packet d) ⇒ Bitstream d → LS.ByteString+toByteString ∷ ( G.Bitstream (SB.Bitstream d)+               , G.Bitstream (Packet d)+               )+             ⇒ Bitstream d+             → LS.ByteString {-# INLINE toByteString #-} toByteString = LS.fromChunks ∘ L.map SB.toByteString ∘ toChunks -streamChunks ∷ Monad m ⇒ Bitstream d → Stream m (SB.Bitstream d)-{-# INLINE [0] streamChunks #-}+streamChunks ∷ ( G.Bitstream (SB.Bitstream d)+               , Monad m+               )+             ⇒ Bitstream d+             → Stream m (SB.Bitstream d)+{-# NOINLINE streamChunks #-} streamChunks ch0 = Stream step ch0 Unknown     where       {-# INLINE step #-}       step Empty        = return Done       step (Chunk x xs) = return $ Yield x xs -unstreamChunks ∷ (G.Bitstream (Packet d), Monad m)+unstreamChunks ∷ ( G.Bitstream (SB.Bitstream d)+                 , Monad m+                 )                ⇒ Stream m (SB.Bitstream d)                → m (Bitstream d)-{-# INLINE [0] unstreamChunks #-}+{-# NOINLINE unstreamChunks #-} unstreamChunks (Stream step s0 _) = go s0     where       {-# INLINE go #-}@@ -495,26 +693,21 @@   #-}  -- Awful implementation to gain speed...-packChunks ∷ ∀m d. Monad m+packChunks ∷ ∀d m. (G.Bitstream (Packet d), Monad m)            ⇒ Stream m (Packet d)            → Stream m (SB.Bitstream d)-{-# INLINE packChunks #-}+{-# INLINEABLE packChunks #-} packChunks (Stream step s0 sz)-    = Stream step' (emptyChunk, 0, Just s0) sz'+    = Stream step' (emptyChunk, 0, 0, Just s0) sz'     where       emptyChunk ∷ New.New SV.Vector (Packet d)       {-# INLINE emptyChunk #-}       emptyChunk-          = New.create (MVector.new chunkSize)+          = New.create (MVector.unsafeNew chunkSize) -      newChunk ∷ New.New SV.Vector (Packet d)-               → Int-               → SB.Bitstream d-      {-# INLINE newChunk #-}-      newChunk ch len-          = SB.fromPackets-            $ GV.new-            $ New.apply (MVector.take len) ch+      singletonChunk ∷ Packet d → New.New SV.Vector (Packet d)+      {-# INLINE singletonChunk #-}+      singletonChunk = writePacket emptyChunk 0        writePacket ∷ New.New SV.Vector (Packet d)                   → Int@@ -524,33 +717,48 @@       writePacket ch len p           = New.modify (\mv → MVector.write mv len p) ch +      newChunk ∷ G.Bitstream (Packet d)+               ⇒ New.New SV.Vector (Packet d)+               → Int+               → Int+               → SB.Bitstream d+      {-# INLINE newChunk #-}+      newChunk ch cLen bLen+          = SB.unsafeFromPackets bLen+            $ GV.new+            $ New.apply (MVector.take cLen) ch+       sz' ∷ Size       {-# INLINE sz' #-}       sz' = case sz of-              Exact n → Exact (n + chunkSize - 1 `div` chunkSize)-              Max   n → Max   (n + chunkSize - 1 `div` chunkSize)+              Exact n → Exact ((n + chunkSize - 1) `div` chunkSize)+              Max   n → Max   ((n + chunkSize - 1) `div` chunkSize)               Unknown → Unknown        {-# INLINE step' #-}-      step' (ch, len, Just s)+      step' (ch, cLen, bLen, Just s)           = do r ← step s                case r of                  Yield p s'-                     | len ≡ chunkSize-                           → return $ Yield (newChunk ch len)-                                            (emptyChunk, 0, Just s')+                     | cLen ≡ chunkSize+                           → return $ Yield (newChunk ch cLen bLen)+                                            (singletonChunk p, 1, length p, Just s')                      | otherwise-                           → return $ Skip  (writePacket ch len p, len+1, Just s')-                 Skip s'   → return $ Skip  (ch             , len  , Just s')+                           → return $ Skip  (writePacket ch cLen p, cLen+1, bLen + length p, Just s')+                 Skip s'   → return $ Skip  (ch                   , cLen  , bLen           , Just s')                  Done-                     | len ≡ 0+                     | cLen ≡ 0                            → return Done                      | otherwise-                           → return $ Yield (newChunk ch len)-                                            ((⊥), (⊥), Nothing)-      step' (_, _, Nothing)+                           → return $ Yield (newChunk ch cLen bLen)+                                            ((⊥), (⊥), (⊥), Nothing)+      step' (_, _, _, Nothing)           = return Done +unpackChunks ∷ S.Stream (SB.Bitstream d) → S.Stream (Packet d)+{-# INLINE unpackChunks #-}+unpackChunks = S.concatMap SB.streamPackets+ -- | /O(n)/ Convert a @'Bitstream' 'Left'@ into a @'Bitstream' -- 'Right'@. Bit directions only affect octet-based operations such as -- 'toByteString'.@@ -600,25 +808,30 @@ repeat b = xs     where       xs = Chunk x xs-      x  = replicate (chunkBits ∷ Int) b+      x  = SB.fromPackets (SV.replicate chunkSize p)+      p  = pack (L.replicate 8 b)  -- | /O(n)/ 'cycle' ties a finite 'Bitstream' into a circular one, or -- equivalently, the infinite repetition of the original 'Bitstream'. -- It is the identity on infinite 'Bitstream's.-cycle ∷ G.Bitstream (Packet d) ⇒ Bitstream d → Bitstream d+cycle ∷ G.Bitstream (Bitstream d) ⇒ Bitstream d → Bitstream d {-# INLINE cycle #-} cycle Empty = emptyStream cycle ch    = ch ⧺ cycle ch  -- | /O(n)/ 'getContents' is equivalent to 'hGetContents' -- @stdin@. Will read /lazily/.-getContents ∷ G.Bitstream (Packet d) ⇒ IO (Bitstream d)+getContents ∷ G.Bitstream (SB.Bitstream d) ⇒ IO (Bitstream d) {-# INLINE getContents #-} getContents = fmap fromByteString LS.getContents  -- | /O(n)/ Write a 'Bitstream' to @stdout@, equivalent to 'hPut' -- @stdout@.-putBits ∷ G.Bitstream (Packet d) ⇒ Bitstream d → IO ()+putBits ∷ ( G.Bitstream (SB.Bitstream d)+          , G.Bitstream (Packet d)+          )+        ⇒ Bitstream d+        → IO () {-# INLINE putBits #-} putBits = LS.putStr ∘ toByteString @@ -626,7 +839,11 @@ -- -> 'Bitstream' d@ as its argument. The entire input from the stdin -- is lazily passed to this function as its argument, and the -- resulting 'Bitstream' is output on the stdout.-interact ∷ G.Bitstream (Packet d) ⇒ (Bitstream d → Bitstream d) → IO ()+interact ∷ ( G.Bitstream (SB.Bitstream d)+           , G.Bitstream (Packet d)+           )+         ⇒ (Bitstream d → Bitstream d)+         → IO () {-# INLINE interact #-} interact = LS.interact ∘ lift'     where@@ -634,17 +851,27 @@       lift' f = toByteString ∘ f ∘ fromByteString  -- | /O(n)/ Read an entire file lazily into a 'Bitstream'.-readFile ∷ G.Bitstream (Packet d) ⇒ FilePath → IO (Bitstream d)+readFile ∷ G.Bitstream (SB.Bitstream d) ⇒ FilePath → IO (Bitstream d) {-# INLINE readFile #-} readFile = fmap fromByteString ∘ LS.readFile  -- | /O(n)/ Write a 'Bitstream' to a file.-writeFile ∷ G.Bitstream (Packet d) ⇒ FilePath → Bitstream d → IO ()+writeFile ∷ ( G.Bitstream (SB.Bitstream d)+            , G.Bitstream (Packet d)+            )+          ⇒ FilePath+          → Bitstream d+          → IO () {-# INLINE writeFile #-} writeFile = (∘ toByteString) ∘ LS.writeFile  -- | /O(n)/ Append a 'Bitstream' to a file.-appendFile ∷ G.Bitstream (Packet d) ⇒ FilePath → Bitstream d → IO ()+appendFile ∷ ( G.Bitstream (SB.Bitstream d)+             , G.Bitstream (Packet d)+             )+           ⇒ FilePath+           → Bitstream d+           → IO () {-# INLINE appendFile #-} appendFile = (∘ toByteString) ∘ LS.appendFile @@ -653,7 +880,7 @@ -- size. -- -- Once EOF is encountered, the 'Handle' is closed.-hGetContents ∷ G.Bitstream (Packet d) ⇒ Handle → IO (Bitstream d)+hGetContents ∷ G.Bitstream (SB.Bitstream d) ⇒ Handle → IO (Bitstream d) {-# INLINE hGetContents #-} hGetContents = fmap fromByteString ∘ LS.hGetContents @@ -667,17 +894,27 @@ -- 'hGet' will behave as if EOF was reached. -- {-# INLINE hGet #-}-hGet ∷ G.Bitstream (Packet d) ⇒ Handle → Int → IO (Bitstream d)+hGet ∷ G.Bitstream (SB.Bitstream d) ⇒ Handle → Int → IO (Bitstream d) hGet = (fmap fromByteString ∘) ∘ LS.hGet  -- | /O(n)/ 'hGetNonBlocking' is similar to 'hGet', except that it -- will never block waiting for data to become available, instead it -- returns only whatever data is available. {-# INLINE hGetNonBlocking #-}-hGetNonBlocking ∷ G.Bitstream (Packet d) ⇒ Handle → Int → IO (Bitstream d)+hGetNonBlocking ∷ ( G.Bitstream (SB.Bitstream d)+                  , G.Bitstream (Packet d)+                  )+                ⇒ Handle+                → Int+                → IO (Bitstream d) hGetNonBlocking = (fmap fromByteString ∘) ∘ LS.hGetNonBlocking  -- | /O(n)/ Write a 'Bitstream' to the given 'Handle'.-hPut ∷ G.Bitstream (Packet d) ⇒ Handle → Bitstream d → IO ()+hPut ∷ ( G.Bitstream (SB.Bitstream d)+       , G.Bitstream (Packet d)+       )+     ⇒ Handle+     → Bitstream d+     → IO () {-# INLINE hPut #-} hPut = (∘ toByteString) ∘ LS.hPut
Data/Bitstream/Packet.hs view
@@ -3,7 +3,6 @@   , EmptyDataDecls   , FlexibleContexts   , FlexibleInstances-  , RankNTypes   , UnicodeSyntax   #-} -- | For internal use only.@@ -45,6 +44,8 @@ -- --   * 10010100 => [False, False, True , False, True, False, False, True] --+-- 'Bits' operations (like 'toBits') treat a 'Left' bitstream as a+-- little-endian integer. data Left  -- | 'Right' bitstreams interpret an octet as a vector of bits whose@@ -54,6 +55,8 @@ -- --   * 10010100 => [True, False, False, True, False, True , False, False] --+-- 'Bits' operations (like 'toBits') treat a 'Right' bitstream as a+-- big-endian integer. data Right  -- | 'Packet's are strict 'Bitstream's having at most 8 bits.@@ -120,17 +123,18 @@           (oy `shiftR` (8-ny))  instance Bitstream (Packet Left) where-    {-# INLINE [0] stream #-}-    stream (Packet n o) = {-# CORE "Packet Left stream" #-}-                          Stream step 0 (Exact n)+    {-# INLINE basicStream #-}+    basicStream (Packet n o)+        = {-# CORE "Packet Left stream" #-}+          Stream step 0 (Exact n)         where           {-# INLINE step #-}           step !i               | i ≥ n     = return Done               | otherwise = return $! Yield (o `testBit` i) (i+1) -    {-# INLINE [0] unstream #-}-    unstream (Stream step s0 sz)+    {-# INLINE basicUnstream #-}+    basicUnstream (Stream step s0 sz)         = {-# CORE "Packet Left unstream" #-}           case upperBound sz of             Just n@@ -158,31 +162,31 @@                      Skip    s'      → safeConsume s' i o                      Done            → return $! Packet i o -    {-# INLINE [2] cons #-}-    cons b p+    {-# INLINE basicCons #-}+    basicCons b p         | full p    = packetOverflow         | otherwise = b `unsafeConsL` p -    {-# INLINE [2] snoc #-}-    snoc p b+    {-# INLINE basicSnoc #-}+    basicSnoc p b         | full p    = packetOverflow         | otherwise = p `unsafeSnocL` b -    {-# INLINE [2] append #-}-    append (Packet nx ox) (Packet ny oy)+    {-# INLINE basicAppend #-}+    basicAppend (Packet nx ox) (Packet ny oy)         | nx + ny > 8 = packetOverflow         | otherwise   = Packet (nx + ny) (ox .|. (oy `shiftL` nx)) -    {-# INLINE [2] tail #-}-    tail (Packet 0 _) = emptyNotAllowed-    tail (Packet n o) = Packet (n-1) (o `shiftR` 1)+    {-# INLINE basicTail #-}+    basicTail (Packet 0 _) = emptyNotAllowed+    basicTail (Packet n o) = Packet (n-1) (o `shiftR` 1) -    {-# INLINE [2] init #-}-    init (Packet 0 _) = emptyNotAllowed-    init (Packet n o) = Packet (n-1) o+    {-# INLINE basicInit #-}+    basicInit (Packet 0 _) = emptyNotAllowed+    basicInit (Packet n o) = Packet (n-1) o -    {-# INLINE [2] map #-}-    map f (Packet n o0) = Packet n (go 0 o0)+    {-# INLINE basicMap #-}+    basicMap f (Packet n o0) = Packet n (go 0 o0)         where           {-# INLINE go #-}           go i o@@ -190,21 +194,15 @@               | f (o `testBit` i) = go (i+1) (o `setBit`   i)               | otherwise         = go (i+1) (o `clearBit` i) -    {-# INLINE [2] reverse #-}-    reverse (Packet n o)+    {-# INLINE basicReverse #-}+    basicReverse (Packet n o)         = Packet n (reverseBits o `shiftR` (8-n)) -    {-# INLINE [1] scanl #-}-    scanl = scanlPacket--    {-# INLINE [2] replicate #-}-    replicate n b-        | n > 8     = packetOverflow-        | b         = Packet (fromIntegral n) (0xFF `shiftR` (8 - fromIntegral n))-        | otherwise = Packet (fromIntegral n) 0+    {-# INLINE basicScanl #-}+    basicScanl = scanlPacket -    {-# INLINE [2] take #-}-    take l (Packet n o)+    {-# INLINE basicTake #-}+    basicTake l (Packet n o)         | l ≤ 0      = (∅)         | otherwise             = let n' = fromIntegral (min (fromIntegral n) l)@@ -212,8 +210,8 @@               in                 Packet n' o' -    {-# INLINE [2] drop #-}-    drop l (Packet n o)+    {-# INLINE basicDrop #-}+    basicDrop l (Packet n o)         | l ≤ 0      = Packet n o         | otherwise             = let d  = fromIntegral (min (fromIntegral n) l)@@ -222,27 +220,43 @@               in                 Packet n' o' -    {-# INLINE [2] takeWhile #-}-    takeWhile = takeWhilePacket+    {-# INLINE basicTakeWhile #-}+    basicTakeWhile = takeWhilePacket -    {-# INLINE [2] dropWhile #-}-    dropWhile = dropWhilePacket+    {-# INLINE basicDropWhile #-}+    basicDropWhile = dropWhilePacket -    {-# INLINE [1] filter #-}-    filter = filterPacket+    {-# INLINE basicFilter #-}+    basicFilter = filterPacket +    {-# INLINEABLE basicFromNBits #-}+    basicFromNBits n β+        | n < 0     = (∅)+        | n > 8     = packetOverflow+        | n ≡ 8     = Packet (fromIntegral n) (fromIntegral β)+        | otherwise = let n' ∷ Int+                          n' = fromIntegral n+                          o  ∷ Word8+                          o  = fromIntegral (β .&. ((1 `shiftL` n') - 1))+                      in Packet n' o++    {-# INLINE basicToBits #-}+    basicToBits = fromIntegral ∘ toOctet++ instance Bitstream (Packet Right) where-    {-# INLINE [0] stream #-}-    stream (Packet n o) = {-# CORE "Packet Right stream" #-}-                          Stream step 0 (Exact n)+    {-# INLINE basicStream #-}+    basicStream (Packet n o)+        = {-# CORE "Packet Right stream" #-}+          Stream step 0 (Exact n)         where           {-# INLINE step #-}           step !i               | i ≥ n     = return Done               | otherwise = return $! Yield (o `testBit` (7-i)) (i+1) -    {-# INLINE [0] unstream #-}-    unstream (Stream step s0 sz)+    {-# INLINE basicUnstream #-}+    basicUnstream (Stream step s0 sz)         = {-# CORE "Packet Right unstream" #-}           case upperBound sz of             Just n@@ -270,31 +284,31 @@                      Skip    s'      → safeConsume s' i o                      Done            → return $! Packet i o -    {-# INLINE [2] cons #-}-    cons b p+    {-# INLINE basicCons #-}+    basicCons b p         | full p    = packetOverflow         | otherwise = b `unsafeConsR` p -    {-# INLINE [2] snoc #-}-    snoc p b+    {-# INLINE basicSnoc #-}+    basicSnoc p b         | full p    = packetOverflow         | otherwise = p `unsafeSnocR` b -    {-# INLINE [2] append #-}-    append (Packet nx ox) (Packet ny oy)+    {-# INLINE basicAppend #-}+    basicAppend (Packet nx ox) (Packet ny oy)         | nx + ny > 8 = packetOverflow         | otherwise   = Packet (nx + ny) (ox .|. (oy `shiftR` nx)) -    {-# INLINE [2] tail #-}-    tail (Packet 0 _) = emptyNotAllowed-    tail (Packet n o) = Packet (n-1) (o `shiftL` 1)+    {-# INLINE basicTail #-}+    basicTail (Packet 0 _) = emptyNotAllowed+    basicTail (Packet n o) = Packet (n-1) (o `shiftL` 1) -    {-# INLINE [2] init #-}-    init (Packet 0 _) = emptyNotAllowed-    init (Packet n o) = Packet (n-1) o+    {-# INLINE basicInit #-}+    basicInit (Packet 0 _) = emptyNotAllowed+    basicInit (Packet n o) = Packet (n-1) o -    {-# INLINE [2] map #-}-    map f (Packet n o0) = Packet n (go 0 o0)+    {-# INLINE basicMap #-}+    basicMap f (Packet n o0) = Packet n (go 0 o0)         where           {-# INLINE go #-}           go i o@@ -302,21 +316,15 @@               | f (o `testBit` (7-i)) = go (i+1) (o `setBit`   (7-i))               | otherwise             = go (i+1) (o `clearBit` (7-i)) -    {-# INLINE [2] reverse #-}-    reverse (Packet n o)+    {-# INLINE basicReverse #-}+    basicReverse (Packet n o)         = Packet n (reverseBits o `shiftL` (8-n)) -    {-# INLINE [1] scanl #-}-    scanl = scanlPacket--    {-# INLINE [2] replicate #-}-    replicate n b-        | n > 8     = packetOverflow-        | b         = Packet (fromIntegral n) (0xFF `shiftL` (8 - fromIntegral n))-        | otherwise = Packet (fromIntegral n) 0+    {-# INLINE basicScanl #-}+    basicScanl = scanlPacket -    {-# INLINE [2] take #-}-    take l (Packet n o)+    {-# INLINE basicTake #-}+    basicTake l (Packet n o)         | l ≤ 0      = (∅)         | otherwise             = let n' = fromIntegral (min (fromIntegral n) l)@@ -324,8 +332,8 @@               in                 Packet n' o' -    {-# INLINE [2] drop #-}-    drop l (Packet n o)+    {-# INLINE basicDrop #-}+    basicDrop l (Packet n o)         | l ≤ 0      = Packet n o         | otherwise             = let d  = fromIntegral (min (fromIntegral n) l)@@ -334,58 +342,76 @@               in                 Packet n' o' -    {-# INLINE [2] takeWhile #-}-    takeWhile = takeWhilePacket+    {-# INLINE basicTakeWhile #-}+    basicTakeWhile = takeWhilePacket -    {-# INLINE [2] dropWhile #-}-    dropWhile = dropWhilePacket+    {-# INLINE basicDropWhile #-}+    basicDropWhile = dropWhilePacket -    {-# INLINE [1] filter #-}-    filter = filterPacket+    {-# INLINE basicFilter #-}+    basicFilter = filterPacket +    {-# INLINEABLE basicFromNBits #-}+    basicFromNBits n β+        | n < 0     = (∅)+        | n > 8     = packetOverflow+        | n ≡ 8     = Packet (fromIntegral n) (fromIntegral β)+        | otherwise = let n' ∷ Int+                          n' = fromIntegral n+                          o  ∷ Word8+                          o  = fromIntegral ( (β .&. ((1 `shiftL` n') - 1))+                                              `shiftL`+                                              (8-n')+                                            )+                      in Packet n' o++    {-# INLINE basicToBits #-}+    basicToBits (Packet n o)+        = fromIntegral (o `shiftR` (8-n))+ packetHeadL ∷ Packet Left → Bool-{-# RULES "head → packetHeadL" [2] head = packetHeadL #-}+{-# RULES "head → packetHeadL" [1] head = packetHeadL #-} {-# INLINE packetHeadL #-} packetHeadL (Packet 0 _) = emptyNotAllowed packetHeadL (Packet _ o) = o `testBit` 0  packetHeadR ∷ Packet Right → Bool-{-# RULES "head → packetHeadR" [2] head = packetHeadR #-}+{-# RULES "head → packetHeadR" [1] head = packetHeadR #-} {-# INLINE packetHeadR #-} packetHeadR (Packet 0 _) = emptyNotAllowed packetHeadR (Packet _ o) = o `testBit` 7  packetLastL ∷ Packet Left → Bool-{-# RULES "last → packetLastL" [2] last = packetLastL #-}+{-# RULES "last → packetLastL" [1] last = packetLastL #-} {-# INLINE packetLastL #-} packetLastL (Packet 0 _) = emptyNotAllowed packetLastL (Packet n o) = o `testBit` (n-1)  packetLastR ∷ Packet Right → Bool-{-# RULES "head → packetLastR" [2] last = packetLastR #-}+{-# RULES "head → packetLastR" [1] last = packetLastR #-} {-# INLINE packetLastR #-} packetLastR (Packet 0 _) = emptyNotAllowed packetLastR (Packet n o) = o `testBit` (8-n)  packetAndL ∷ Packet Left → Bool-{-# RULES "and → packetAndL" [2] and = packetAndL #-}+{-# RULES "and → packetAndL" [1] and = packetAndL #-} {-# INLINE packetAndL #-} packetAndL (Packet n o) = (0xFF `shiftR` (8-n)) ≡ o  packetAndR ∷ Packet Right → Bool-{-# RULES "and → packetAndR" [2] and = packetAndR #-}+{-# RULES "and → packetAndR" [1] and = packetAndR #-} {-# INLINE packetAndR #-} packetAndR (Packet n o) = (0xFF `shiftL` (8-n)) ≡ o  packetIndexL ∷ Integral n ⇒ Packet Left → n → Bool-{-# RULES "(!!) → packetIndexL" [2] (!!) = packetIndexL #-}+{-# RULES "(!!) → packetIndexL" [1] (!!) = packetIndexL #-} {-# INLINE packetIndexL #-} packetIndexL p i     | i < 0 ∨ i ≥ length p = indexOutOfRange i     | otherwise            = unsafePacketIndexL p i  packetIndexR ∷ Integral n ⇒ Packet Right → n → Bool-{-# RULES "(!!) → packetIndexR" [2] (!!) = packetIndexR #-}+{-# RULES "(!!) → packetIndexR" [1] (!!) = packetIndexR #-} {-# INLINE packetIndexR #-} packetIndexR p i     | i < 0 ∨ i ≥ length p = indexOutOfRange i@@ -402,18 +428,18 @@     = o `testBit` (7 - fromIntegral i)  packetNull ∷ Packet d → Bool-{-# RULES "null → packetNull" [2] null = packetNull #-}+{-# RULES "null → packetNull" [1] null = packetNull #-} {-# INLINE packetNull #-} packetNull (Packet 0 _) = True packetNull _            = False  packetLength ∷ Num n ⇒ Packet d → n-{-# RULES "length → packetLength" [2] length = packetLength #-}+{-# RULES "length → packetLength" [1] length = packetLength #-} {-# INLINE packetLength #-} packetLength (Packet n _) = fromIntegral n  packetOr ∷ Packet d → Bool-{-# RULES "or → packetOr" [2] or = packetOr #-}+{-# RULES "or → packetOr" [1] or = packetOr #-} {-# INLINE packetOr #-} packetOr (Packet _ o) = o ≢ 0 
bitstream.cabal view
@@ -6,23 +6,21 @@         fusion. This is like @bytestring@ but stores bits instead of         bytes. -        NOTE: GHC 7.0.1 fails to fuse almost every cases of bitstream-        fusion, producing very large and not-so-fast object code. See:-        <http://hackage.haskell.org/trac/ghc/ticket/4397>--Version: 0.1+Version: 0.2 License: PublicDomain License-File: COPYING Author: PHO <pho at cielonegro dot org> Maintainer: PHO <pho at cielonegro dot org> Stability: experimental Homepage: http://cielonegro.org/Bitstream.html+Bug-Reports: http://static.cielonegro.org/ditz/bitstream/ Category: Data Tested-With: GHC == 7.0.1 Cabal-Version: >= 1.10 Build-Type: Simple Extra-Source-Files:     COPYING+    ChangeLog  Source-Repository head     Type: git