module Data.Bitstream.Lazy
(
Bitstream
, Left
, Right
, empty
, (∅)
, singleton
, pack
, unpack
, fromChunks
, toChunks
, fromByteString
, toByteString
, fromBits
, fromNBits
, toBits
, stream
, unstream
, directionLToR
, directionRToL
, cons
, cons'
, snoc
, append
, (⧺)
, head
, last
, tail
, init
, null
, length
, map
, reverse
, foldl
, foldl'
, foldl1
, foldl1'
, foldr
, foldr1
, concat
, concatMap
, and
, or
, any
, all
, scanl
, scanl1
, scanr
, scanr1
, iterate
, repeat
, replicate
, cycle
, unfoldr
, unfoldrN
, take
, drop
, takeWhile
, dropWhile
, span
, break
, elem
, (∈)
, (∋)
, notElem
, (∉)
, (∌)
, find
, filter
, partition
, (!!)
, elemIndex
, elemIndices
, findIndex
, findIndices
, zip
, zip3
, zip4
, zip5
, zip6
, zipWith
, zipWith3
, zipWith4
, zipWith5
, zipWith6
, unzip
, unzip3
, unzip4
, unzip5
, unzip6
, getContents
, putBits
, interact
, readFile
, writeFile
, appendFile
, hGetContents
, hGet
, hGetNonBlocking
, hPut
)
where
import qualified Data.Bitstream as SB
import Data.Bitstream.Generic hiding (Bitstream)
import qualified Data.Bitstream.Generic as G
import Data.Bitstream.Internal
import Data.Bitstream.Packet
import qualified Data.ByteString.Lazy as LS
import qualified Data.List as L
import Data.Monoid
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 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 Prelude ( Bool(..), Eq(..), Int, Integral, Maybe(..)
, Monad(..), Num(..), Ord(..), Show(..)
, ($), div, error, fmap, otherwise
)
import Prelude.Unicode hiding ((⧺), (∈), (∉))
import System.IO (FilePath, Handle, IO)
chunkSize ∷ Num α ⇒ α
chunkSize = fromInteger (32 ⋅ 1024)
chunkBits ∷ Num α ⇒ α
chunkBits = chunkSize ⋅ 8
data Bitstream d
= Empty
| Chunk !(SB.Bitstream d) (Bitstream d)
instance Show (Packet d) ⇒ Show (Bitstream d) where
show ch
= L.concat
[ "[L: "
, L.concat (L.intersperse " " (L.map show (toChunks ch)))
, " ]"
]
instance G.Bitstream (Bitstream d) ⇒ Eq (Bitstream d) where
x == y = stream x ≡ stream y
instance G.Bitstream (Bitstream d) ⇒ Ord (Bitstream d) where
x `compare` y = stream x `compare` stream y
instance G.Bitstream (Bitstream d) ⇒ Monoid (Bitstream d) where
mempty = (∅)
mappend = (⧺)
mconcat = concat
instance G.Bitstream (Bitstream Left) where
basicStream = lazyStream
basicUnstream = lazyUnstream
basicCons = lazyCons
basicCons' = lazyCons'
basicSnoc = lazySnoc
basicAppend = lazyAppend
basicTail = lazyTail
basicInit = lazyInit
basicMap = lazyMap
basicReverse = lazyReverse
basicConcat = lazyConcat
basicScanl = lazyScanl
basicTake = lazyTake
basicDrop = lazyDrop
basicTakeWhile = lazyTakeWhile
basicDropWhile = lazyDropWhile
basicFilter = lazyFilter
basicFromNBits
= ((unId ∘ unstreamChunks ∘ packChunks) ∘) ∘ lePacketsFromNBits
basicToBits = unId ∘ lePacketsToBits ∘ unpackChunks ∘ streamChunks
instance G.Bitstream (Bitstream Right) where
basicStream = lazyStream
basicUnstream = lazyUnstream
basicCons = lazyCons
basicCons' = lazyCons'
basicSnoc = lazySnoc
basicAppend = lazyAppend
basicTail = lazyTail
basicInit = lazyInit
basicMap = lazyMap
basicReverse = lazyReverse
basicConcat = lazyConcat
basicScanl = lazyScanl
basicTake = lazyTake
basicDrop = lazyDrop
basicTakeWhile = lazyTakeWhile
basicDropWhile = lazyDropWhile
basicFilter = lazyFilter
basicFromNBits
= ((unId ∘ unstreamChunks ∘ packChunks) ∘) ∘ bePacketsFromNBits
basicToBits = unId ∘ bePacketsToBits ∘ unpackChunks ∘ streamChunks
lazyStream ∷ G.Bitstream (SB.Bitstream d) ⇒ Bitstream d → S.Stream Bool
lazyStream
=
S.concatMap stream ∘ streamChunks
lazyUnstream ∷ ( G.Bitstream (SB.Bitstream d)
, G.Bitstream (Packet d)
)
⇒ S.Stream Bool
→ Bitstream d
lazyUnstream
=
unId ∘ unstreamChunks ∘ packChunks ∘ packPackets
lazyCons ∷ G.Bitstream (SB.Bitstream d) ⇒ Bool → Bitstream d → Bitstream d
lazyCons = Chunk ∘ singleton
lazyCons' ∷ G.Bitstream (SB.Bitstream d) ⇒ Bool → Bitstream d → Bitstream d
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
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
lazyAppend Empty ch = ch
lazyAppend (Chunk x xs) ch = Chunk x (append xs ch)
lazyTail ∷ G.Bitstream (SB.Bitstream d) ⇒ Bitstream d → Bitstream d
lazyTail Empty = emptyStream
lazyTail (Chunk x xs) = case tail x of
x' | null x' → xs
| otherwise → Chunk x' xs
lazyInit ∷ ( G.Bitstream (SB.Bitstream d)
, G.Bitstream (Bitstream d)
)
⇒ Bitstream d
→ Bitstream d
lazyInit Empty = emptyStream
lazyInit (Chunk x Empty) = case init x of
x' | null x' → Empty
| otherwise → Chunk x' Empty
lazyInit (Chunk x xs ) = Chunk x (init xs)
lazyMap ∷ ( G.Bitstream (SB.Bitstream d)
, G.Bitstream (Bitstream d)
)
⇒ (Bool → Bool)
→ Bitstream d
→ Bitstream d
lazyMap _ Empty = Empty
lazyMap f (Chunk x xs) = Chunk (map f x) (map f xs)
lazyReverse ∷ G.Bitstream (SB.Bitstream d) ⇒ Bitstream d → Bitstream d
lazyReverse ch0 = go ch0 Empty
where
go Empty ch = ch
go (Chunk x xs) ch = go xs (Chunk (reverse x) ch)
lazyConcat ∷ G.Bitstream (SB.Bitstream d) ⇒ [Bitstream d] → Bitstream d
lazyConcat = fromChunks ∘ L.concatMap toChunks
lazyScanl ∷ ( G.Bitstream (SB.Bitstream d)
, G.Bitstream (Bitstream d)
)
⇒ (Bool → Bool → Bool)
→ Bool
→ Bitstream d
→ Bitstream d
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')
lazyTake ∷ ( Integral n
, G.Bitstream (SB.Bitstream d)
, G.Bitstream (Bitstream d)
)
⇒ n
→ Bitstream d
→ Bitstream d
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
lazyDrop ∷ ( Integral n
, G.Bitstream (SB.Bitstream d)
, G.Bitstream (Bitstream d)
)
⇒ n
→ Bitstream d
→ Bitstream d
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
lazyTakeWhile ∷ ( G.Bitstream (SB.Bitstream d)
, G.Bitstream (Bitstream d)
)
⇒ (Bool → Bool)
→ Bitstream d
→ Bitstream d
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
lazyDropWhile ∷ ( G.Bitstream (SB.Bitstream d)
, G.Bitstream (Bitstream d)
)
⇒ (Bool → Bool)
→ Bitstream d
→ Bitstream d
lazyDropWhile _ Empty = Empty
lazyDropWhile f (Chunk x xs) = case dropWhile f x of
x' | null x' → dropWhile f xs
| otherwise → Chunk x' xs
lazyFilter ∷ ( G.Bitstream (SB.Bitstream d)
, G.Bitstream (Bitstream d)
)
⇒ (Bool → Bool)
→ Bitstream d
→ Bitstream d
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 (SB.Bitstream d) ⇒ Bitstream d → Bool
lazyHead Empty = emptyStream
lazyHead (Chunk x _) = head x
lazyLast ∷ G.Bitstream (SB.Bitstream d) ⇒ Bitstream d → Bool
lazyLast Empty = emptyStream
lazyLast (Chunk x Empty) = last x
lazyLast (Chunk _ xs ) = lazyLast xs
lazyNull ∷ Bitstream d → Bool
lazyNull Empty = True
lazyNull _ = False
lazyLength ∷ (G.Bitstream (SB.Bitstream d), Num n) ⇒ Bitstream d → n
lazyLength = go 0
where
go !soFar Empty = soFar
go !soFar (Chunk x xs) = go (soFar + length x) xs
lazyAnd ∷ G.Bitstream (SB.Bitstream d) ⇒ Bitstream d → Bool
lazyAnd Empty = False
lazyAnd (Chunk x xs)
| and x = lazyAnd xs
| otherwise = False
lazyOr ∷ G.Bitstream (SB.Bitstream d) ⇒ Bitstream d → Bool
lazyOr Empty = True
lazyOr (Chunk x xs)
| or x = True
| otherwise = lazyOr xs
lazyIndex ∷ ( G.Bitstream (SB.Bitstream d)
, Integral n
, Show n
)
⇒ Bitstream d
→ n
→ Bool
lazyIndex ch0 i0
| i0 < 0 = indexOutOfRange i0
| otherwise = go ch0 i0
where
go Empty _ = indexOutOfRange i0
go (Chunk x xs) i
| i < length x = x !! i
| otherwise = go xs (i length x)
emptyStream ∷ α
emptyStream
= error "Data.Bitstream.Lazy: empty stream"
indexOutOfRange ∷ (Integral n, Show n) ⇒ n → α
indexOutOfRange n = error ("Data.Bitstream.Lazy: index out of range: " L.++ show n)
fromChunks ∷ G.Bitstream (SB.Bitstream d) ⇒ [SB.Bitstream d] → Bitstream d
fromChunks [] = Empty
fromChunks (x:xs)
| null x = fromChunks xs
| otherwise = Chunk x (fromChunks xs)
toChunks ∷ Bitstream d → [SB.Bitstream d]
toChunks Empty = []
toChunks (Chunk x xs) = x : toChunks xs
fromByteString ∷ G.Bitstream (SB.Bitstream d) ⇒ LS.ByteString → Bitstream d
fromByteString = fromChunks ∘ L.map SB.fromByteString ∘ LS.toChunks
toByteString ∷ ( G.Bitstream (SB.Bitstream d)
, G.Bitstream (Packet d)
)
⇒ Bitstream d
→ LS.ByteString
toByteString = LS.fromChunks ∘ L.map SB.toByteString ∘ toChunks
streamChunks ∷ ( G.Bitstream (SB.Bitstream d)
, Monad m
)
⇒ Bitstream d
→ Stream m (SB.Bitstream d)
streamChunks ch0 = Stream step ch0 Unknown
where
step Empty = return Done
step (Chunk x xs) = return $ Yield x xs
unstreamChunks ∷ ( G.Bitstream (SB.Bitstream d)
, Monad m
)
⇒ Stream m (SB.Bitstream d)
→ m (Bitstream d)
unstreamChunks (Stream step s0 _) = go s0
where
go s = do r ← step s
case r of
Yield x s' → do xs ← go s'
if null x
then return xs
else return $ Chunk x xs
Skip s' → go s'
Done → return Empty
packChunks ∷ ∀d m. (G.Bitstream (Packet d), Monad m)
⇒ Stream m (Packet d)
→ Stream m (SB.Bitstream d)
packChunks (Stream step s0 sz)
= Stream step' (emptyChunk, 0, 0, Just s0) sz'
where
emptyChunk ∷ New.New SV.Vector (Packet d)
emptyChunk
= New.create (MVector.unsafeNew chunkSize)
singletonChunk ∷ Packet d → New.New SV.Vector (Packet d)
singletonChunk = writePacket emptyChunk 0
writePacket ∷ New.New SV.Vector (Packet d)
→ Int
→ Packet d
→ New.New SV.Vector (Packet d)
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
newChunk ch cLen bLen
= SB.unsafeFromPackets bLen
$ GV.new
$ New.apply (MVector.take cLen) ch
sz' ∷ Size
sz' = case sz of
Exact n → Exact ((n + chunkSize 1) `div` chunkSize)
Max n → Max ((n + chunkSize 1) `div` chunkSize)
Unknown → Unknown
step' (ch, cLen, bLen, Just s)
= do r ← step s
case r of
Yield p s'
| cLen ≡ chunkSize
→ return $ Yield (newChunk ch cLen bLen)
(singletonChunk p, 1, length p, Just s')
| otherwise
→ return $ Skip (writePacket ch cLen p, cLen+1, bLen + length p, Just s')
Skip s' → return $ Skip (ch , cLen , bLen , Just s')
Done
| cLen ≡ 0
→ return Done
| otherwise
→ return $ Yield (newChunk ch cLen bLen)
((⊥), (⊥), (⊥), Nothing)
step' (_, _, _, Nothing)
= return Done
unpackChunks ∷ S.Stream (SB.Bitstream d) → S.Stream (Packet d)
unpackChunks = S.concatMap SB.streamPackets
directionLToR ∷ Bitstream Left → Bitstream Right
directionLToR Empty = Empty
directionLToR (Chunk x xs) = Chunk (SB.directionLToR x) (directionLToR xs)
directionRToL ∷ Bitstream Right → Bitstream Left
directionRToL Empty = Empty
directionRToL (Chunk x xs) = Chunk (SB.directionRToL x) (directionRToL xs)
iterate ∷ G.Bitstream (Packet d) ⇒ (Bool → Bool) → Bool → Bitstream d
iterate f b = xs
where
xs = Chunk x xs
x = SB.fromPackets (SV.replicate chunkSize p)
p = pack (L.take 8 (L.iterate f b))
repeat ∷ G.Bitstream (Packet d) ⇒ Bool → Bitstream d
repeat b = xs
where
xs = Chunk x xs
x = SB.fromPackets (SV.replicate chunkSize p)
p = pack (L.replicate 8 b)
cycle ∷ G.Bitstream (Bitstream d) ⇒ Bitstream d → Bitstream d
cycle Empty = emptyStream
cycle ch = ch ⧺ cycle ch
getContents ∷ G.Bitstream (SB.Bitstream d) ⇒ IO (Bitstream d)
getContents = fmap fromByteString LS.getContents
putBits ∷ ( G.Bitstream (SB.Bitstream d)
, G.Bitstream (Packet d)
)
⇒ Bitstream d
→ IO ()
putBits = LS.putStr ∘ toByteString
interact ∷ ( G.Bitstream (SB.Bitstream d)
, G.Bitstream (Packet d)
)
⇒ (Bitstream d → Bitstream d)
→ IO ()
interact = LS.interact ∘ lift'
where
lift' f = toByteString ∘ f ∘ fromByteString
readFile ∷ G.Bitstream (SB.Bitstream d) ⇒ FilePath → IO (Bitstream d)
readFile = fmap fromByteString ∘ LS.readFile
writeFile ∷ ( G.Bitstream (SB.Bitstream d)
, G.Bitstream (Packet d)
)
⇒ FilePath
→ Bitstream d
→ IO ()
writeFile = (∘ toByteString) ∘ LS.writeFile
appendFile ∷ ( G.Bitstream (SB.Bitstream d)
, G.Bitstream (Packet d)
)
⇒ FilePath
→ Bitstream d
→ IO ()
appendFile = (∘ toByteString) ∘ LS.appendFile
hGetContents ∷ G.Bitstream (SB.Bitstream d) ⇒ Handle → IO (Bitstream d)
hGetContents = fmap fromByteString ∘ LS.hGetContents
hGet ∷ G.Bitstream (SB.Bitstream d) ⇒ Handle → Int → IO (Bitstream d)
hGet = (fmap fromByteString ∘) ∘ LS.hGet
hGetNonBlocking ∷ ( G.Bitstream (SB.Bitstream d)
, G.Bitstream (Packet d)
)
⇒ Handle
→ Int
→ IO (Bitstream d)
hGetNonBlocking = (fmap fromByteString ∘) ∘ LS.hGetNonBlocking
hPut ∷ ( G.Bitstream (SB.Bitstream d)
, G.Bitstream (Packet d)
)
⇒ Handle
→ Bitstream d
→ IO ()
hPut = (∘ toByteString) ∘ LS.hPut