module Codec.Compression.Zlib.OutputWindow(
OutputWindow
, emptyWindow
, addByte
, addChunk
, addOldChunk
, outByteString
)
where
import Data.ByteString.Builder
import Data.ByteString.Lazy(ByteString)
import qualified Data.ByteString as SBS
import qualified Data.ByteString.Lazy as BS
import Data.Int
import Data.FingerTree
import Data.Foldable(foldMap)
import Data.Monoid
import Data.Word
data OutputWindow = OutputWindow {
owCommitted :: !(FingerTree Int SBS.ByteString)
, owRecent :: !Builder
}
instance Monoid Int where
mempty = 0
mappend = (+)
instance Measured Int SBS.ByteString where
measure = SBS.length
emptyWindow :: OutputWindow
emptyWindow = OutputWindow empty mempty
addByte :: OutputWindow -> Word8 -> OutputWindow
addByte !ow !b = ow{ owRecent = owRecent ow <> word8 b }
addChunk :: OutputWindow -> ByteString -> OutputWindow
addChunk !ow !bs = ow{ owRecent = owRecent ow <> lazyByteString bs }
addOldChunk :: OutputWindow -> Int -> Int64 -> (OutputWindow, ByteString)
addOldChunk !ow !dist !len = (OutputWindow output (lazyByteString chunk), chunk)
where
output = owCommitted ow |> BS.toStrict (toLazyByteString (owRecent ow))
dropAmt = measure output dist
(prev, sme) = split (> dropAmt) output
s :< rest = viewl sme
start = SBS.take (fromIntegral len) (SBS.drop (dropAmtmeasure prev) s)
len' = fromIntegral len SBS.length start
(m, rest') = split (> len') rest
middle = BS.toStrict (toLazyByteString (outFinger m))
end = case viewl rest' of
EmptyL -> SBS.empty
bs2 :< _ -> SBS.take (len' measure m) bs2
chunkInf = BS.fromChunks [start, middle, end] `BS.append` chunk
chunk = BS.take len chunkInf
outFinger :: FingerTree Int SBS.ByteString -> Builder
outFinger = foldMap byteString
outByteString :: OutputWindow -> ByteString
outByteString ow =
toLazyByteString (outFinger (owCommitted ow) <> owRecent ow)