bitstream-0.2: Data/Bitstream.hs
{-# LANGUAGE
BangPatterns
, FlexibleContexts
, FlexibleInstances
, ScopedTypeVariables
, UnboxedTuples
, UndecidableInstances
, UnicodeSyntax
#-}
-- | Fast, packed, strict bit streams (i.e. list of 'Bool's) with
-- semi-automatic stream fusion.
--
-- This module is intended to be imported @qualified@, to avoid name
-- clashes with "Prelude" functions. e.g.
--
-- > import qualified Data.BitStream as BS
--
-- Strict 'Bitstream's are made of strict 'SV.Vector' of 'Packet's,
-- and each 'Packet's have at least 1 bit.
module Data.Bitstream
( -- * Data types
Bitstream
, Left
, Right
-- * Introducing and eliminating 'Bitstream's
, empty
, (∅)
, singleton
, 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
, directionRToL
-- * Basic interface
, cons
, snoc
, append
, (⧺)
, head
, last
, tail
, init
, null
, length
-- * Transforming 'Bitstream's
, map
, reverse
-- * Reducing 'Bitstream's
, foldl
, foldl'
, foldl1
, foldl1'
, foldr
, foldr1
-- ** Special folds
, concat
, concatMap
, and
, or
, any
, all
-- * Building 'Bitstream's
-- ** Scans
, scanl
, scanl1
, scanr
, scanr1
-- ** Replication
, replicate
-- ** Unfolding
, unfoldr
, unfoldrN
-- * Substreams
, take
, drop
, takeWhile
, dropWhile
, span
, break
-- * Searching streams
-- ** Searching by equality
, elem
, (∈)
, (∋)
, notElem
, (∉)
, (∌)
-- ** Searching with a predicate
, find
, filter
, partition
-- ** Indexing streams
, (!!)
, elemIndex
, elemIndices
, findIndex
, findIndices
-- * Zipping and unzipping streams
, zip
, zip3
, zip4
, zip5
, zip6
, zipWith
, zipWith3
, zipWith4
, zipWith5
, zipWith6
, unzip
, unzip3
, unzip4
, unzip5
, unzip6
-- * I/O with 'Bitstream's
-- ** Standard input and output
, getContents
, putBits
, interact
-- ** Files
, readFile
, writeFile
, appendFile
-- ** I/O with 'Handle's
, hGetContents
, hGet
, hGetSome
, hGetNonBlocking
, hPut
)
where
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 as BS
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(..), ($), error, fmap, fromIntegral, fst
, otherwise
)
import Prelude.Unicode hiding ((⧺), (∈), (∉))
import System.IO (FilePath, Handle, IO)
-- | A space-efficient representation of a 'Bool' vector, supporting
-- many efficient operations. 'Bitstream's have an idea of
-- /directions/ controlling how octets are interpreted as bits. There
-- are two types of concrete 'Bitstream's: @'Bitstream' 'Left'@ and
-- @'Bitstream' 'Right'@.
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)
= L.concat
[ "(S"
, L.concat (L.unfoldr go v0)
, ")"
]
where
{-# INLINE go #-}
go v | SV.null v = Nothing
| otherwise = Just (show (SV.head v), SV.tail v)
instance G.Bitstream (Bitstream d) ⇒ Eq (Bitstream d) where
{-# INLINE (==) #-}
x == y = stream x ≡ stream y
-- | 'Bitstream's are lexicographically ordered.
--
-- @
-- let x = 'pack' ['True' , 'False', 'False']
-- y = 'pack' ['False', 'True' , 'False']
-- z = 'pack' ['False']
-- in
-- [ 'compare' x y -- 'GT'
-- , 'compare' z y -- 'LT'
-- ]
-- @
instance G.Bitstream (Bitstream d) ⇒ Ord (Bitstream d) where
{-# INLINE compare #-}
x `compare` y = stream x `compare` stream y
-- | 'Bitstream' forms 'Monoid' in the same way as ordinary lists:
--
-- @
-- 'mempty' = 'empty'
-- 'mappend' = 'append'
-- 'mconcat' = 'concat'
-- @
instance G.Bitstream (Bitstream d) ⇒ Monoid (Bitstream d) where
mempty = (∅)
mappend = (⧺)
mconcat = concat
instance G.Bitstream (Bitstream Left) 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
{-# 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
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'
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 #)
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
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 #)
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" [1]
∀(v ∷ G.Bitstream (Packet d) ⇒ Bitstream d).
head v = strictHead v #-}
{-# INLINE strictHead #-}
strictHead (Bitstream _ v) = head (SV.head v)
strictLast ∷ G.Bitstream (Packet d) ⇒ Bitstream d → Bool
{-# RULES "last → strictLast" [1]
∀(v ∷ G.Bitstream (Packet d) ⇒ Bitstream d).
last v = strictLast v #-}
{-# INLINE strictLast #-}
strictLast (Bitstream _ v) = last (SV.last v)
strictNull ∷ Bitstream d → Bool
{-# RULES "null → strictNull" [1] null = strictNull #-}
{-# INLINE strictNull #-}
strictNull (Bitstream 0 _) = True
strictNull _ = False
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" [1]
∀(v ∷ G.Bitstream (Packet d) ⇒ Bitstream d).
and v = strictAnd v #-}
{-# INLINE strictAnd #-}
strictAnd (Bitstream _ v)
= SV.all and v
strictOr ∷ G.Bitstream (Packet d) ⇒ Bitstream d → Bool
{-# RULES "or → strictOr" [1]
∀(v ∷ G.Bitstream (Packet d) ⇒ Bitstream d).
or v = strictOr v #-}
{-# INLINE strictOr #-}
strictOr (Bitstream _ v)
= SV.any or v
strictIndex ∷ (G.Bitstream (Packet d), Integral n) ⇒ Bitstream d → n → Bool
{-# RULES "(!!) → strictIndex" [1]
∀(v ∷ G.Bitstream (Packet d) ⇒ Bitstream d) n.
v !! n = strictIndex v n #-}
{-# INLINEABLE strictIndex #-}
strictIndex (Bitstream _ v0) i0
| i0 < 0 = indexOutOfRange i0
| otherwise = go v0 i0
where
{-# INLINE go #-}
go v i
| SV.null v = indexOutOfRange i
| otherwise = case SV.head v of
p | i < length p → p !! i
| otherwise → go (SV.tail v) (i - length p)
emptyStream ∷ α
emptyStream
= error "Data.Bitstream: empty stream"
{-# INLINE indexOutOfRange #-}
indexOutOfRange ∷ Integral n ⇒ n → α
indexOutOfRange n = error ("Data.Bitstream: index out of range: " L.++ show n)
-- | /O(n)/ Convert a strict 'BS.ByteString' into a strict
-- 'Bitstream'.
{-# INLINE fromByteString #-}
fromByteString ∷ BS.ByteString → Bitstream d
fromByteString bs0
= Bitstream (nOctets ⋅ 8) (SV.unfoldrN nOctets go bs0)
where
nOctets ∷ Int
{-# INLINE nOctets #-}
nOctets = BS.length bs0
{-# INLINE go #-}
go bs = do (o, bs') ← BS.uncons bs
return (fromOctet o, bs')
-- | /O(n)/ @'toByteString' bits@ converts a strict 'Bitstream' @bits@
-- 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 (Bitstream d)
, G.Bitstream (Packet d)
) ⇒ Bitstream d → BS.ByteString
toByteString = unstreamBS
∘ (packPackets ∷ Stream Id Bool → Stream Id (Packet d))
∘ stream
unstreamBS ∷ Stream Id (Packet d) → BS.ByteString
{-# INLINE unstreamBS #-}
unstreamBS (Stream step s0 sz)
= case upperBound sz of
Just n → fst $ BS.unfoldrN n (unId ∘ go) s0
Nothing → BS.unfoldr (unId ∘ go) s0
where
{-# INLINE go #-}
go s = do r ← step s
case r of
Yield p s' → return $ Just (toOctet p, s')
Skip s' → go s'
Done → return Nothing
-- 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 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
-- | /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 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 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
-- have been read.
getContents ∷ G.Bitstream (Packet d) ⇒ IO (Bitstream d)
{-# INLINE getContents #-}
getContents = fmap fromByteString BS.getContents
-- | /O(n)/ Write a 'Bitstream' to the stdout, equivalent to 'hPut'
-- @stdout@.
putBits ∷ ( G.Bitstream (Bitstream d)
, G.Bitstream (Packet d)
)
⇒ Bitstream d
→ IO ()
{-# INLINE putBits #-}
putBits = BS.putStr ∘ toByteString
-- | The 'interact' function takes a function of type @'Bitstream' d
-- -> '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 (Bitstream d)
, G.Bitstream (Packet d)
)
⇒ (Bitstream d → Bitstream d)
→ IO ()
{-# INLINE interact #-}
interact = BS.interact ∘ lift'
where
{-# INLINE lift' #-}
lift' f = toByteString ∘ f ∘ fromByteString
-- | /O(n)/ Read an entire file strictly into a 'Bitstream'.
readFile ∷ G.Bitstream (Packet d) ⇒ FilePath → IO (Bitstream d)
{-# INLINE readFile #-}
readFile = fmap fromByteString ∘ BS.readFile
-- | /O(n)/ Write a 'Bitstream' to a file.
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 (Bitstream d)
, G.Bitstream (Packet d)
)
⇒ FilePath
→ Bitstream d
→ IO ()
{-# INLINE appendFile #-}
appendFile = (∘ toByteString) ∘ BS.appendFile
-- | /O(n)/ Read entire handle contents strictly into a 'Bitstream'.
--
-- This function reads chunks at a time, doubling the chunksize on each
-- read. The final buffer is then realloced to the appropriate size. For
-- files > half of available memory, this may lead to memory exhaustion.
-- Consider using 'readFile' in this case.
--
-- The 'Handle' is closed once the contents have been read, or if an
-- exception is thrown.
hGetContents ∷ G.Bitstream (Packet d) ⇒ Handle → IO (Bitstream d)
{-# INLINE hGetContents #-}
hGetContents = fmap fromByteString ∘ BS.hGetContents
-- | /O(n)/ @'hGet' h n@ reads a 'Bitstream' directly from the
-- specified 'Handle' @h@. First argument @h@ is the 'Handle' to read
-- from, and the second @n@ is the number of /octets/ to read, not
-- /bits/. It returns the octets read, up to @n@, or null if EOF has
-- been reached.
--
-- If the handle is a pipe or socket, and the writing end is closed,
-- 'hGet' will behave as if EOF was reached.
hGet ∷ G.Bitstream (Packet d) ⇒ Handle → Int → IO (Bitstream d)
{-# INLINE hGet #-}
hGet = (fmap fromByteString ∘) ∘ BS.hGet
-- | /O(n)/ Like 'hGet', except that a shorter 'Bitstream' may be
-- returned if there are not enough octets immediately available to
-- satisfy the whole request. 'hGetSome' only blocks if there is no
-- data available, and EOF has not yet been reached.
hGetSome ∷ G.Bitstream (Packet d) ⇒ Handle → Int → IO (Bitstream d)
{-# INLINE hGetSome #-}
hGetSome = (fmap fromByteString ∘) ∘ BS.hGetSome
-- | /O(n)/ 'hGetNonBlocking' is similar to 'hGet', except that it
-- will never block waiting for data to become available. If there is
-- no data available to be read, 'hGetNonBlocking' returns 'empty'.
hGetNonBlocking ∷ G.Bitstream (Packet d) ⇒ Handle → Int → IO (Bitstream d)
{-# INLINE hGetNonBlocking #-}
hGetNonBlocking = (fmap fromByteString ∘) ∘ BS.hGetNonBlocking
-- | /O(n)/ Write a 'Bitstream' to the given 'Handle'.
hPut ∷ ( G.Bitstream (Bitstream d)
, G.Bitstream (Packet d)
)
⇒ Handle
→ Bitstream d
→ IO ()
{-# INLINE hPut #-}
hPut = (∘ toByteString) ∘ BS.hPut