sdp4bytestring-0.2: src/SDP/ByteString/Lazy.hs
{-# LANGUAGE Trustworthy, MagicHash, MultiParamTypeClasses, FlexibleInstances #-}
{- |
Module : SDP.ByteString.Lazy
Copyright : (c) Andrey Mulik 2019
License : BSD-style
Maintainer : work.a.mulik@gmail.com
Portability : non-portable (GHC Extensions)
"SDP.ByteString.Lazy" provides @sdp@ instances for lazy 'ByteString'.
-}
module SDP.ByteString.Lazy
(
-- * Exports
module System.IO.Classes,
module SDP.Indexed,
module SDP.Sort,
-- * ByteString
ByteString, LByteString, B.fromStrict, B.toStrict, B.fromChunks, B.toChunks
)
where
import Prelude ()
import SDP.SafePrelude
import SDP.Templates.AnyChunks
import SDP.ByteList.IOUblist
import SDP.ByteList.STUblist
import SDP.ByteList.ST
import SDP.SortM.Tim
import SDP.Indexed
import SDP.Sort
import Data.ByteString.Lazy.Internal ( ByteString (..) )
import qualified Data.ByteString.Lazy as B
import qualified SDP.ByteString as S
import Data.Foldable as F ( foldrM )
import Data.Maybe
import Control.Exception.SDP
import System.IO.Classes
default ()
--------------------------------------------------------------------------------
-- | Type synonym to avoid ambiguity.
type LByteString = ByteString
--------------------------------------------------------------------------------
{- Bordered, Linear and Split instances. -}
instance Bordered ByteString Int
where
lower = const 0
sizeOf = fromEnum . B.length
upper bs = sizeOf bs - 1
bounds bs = (0, sizeOf bs - 1)
indices bs = [0 .. sizeOf bs - 1]
indexIn bs = \ i -> i >= 0 && i < sizeOf bs
instance Linear ByteString Word8
where
replicate = B.replicate . toEnum
concat = B.concat . toList
fromList = B.pack
intersperse = B.intersperse
filter = B.filter
listR = \ bs -> let n = sizeOf bs in (bs .!) <$> [n - 1, n - 2 .. 0]
single = B.singleton
listL = B.unpack
(++) = B.append
(!^) es = B.index es . toEnum
write bs = (bs //) . single ... (,)
uncons' = B.uncons
unsnoc' = B.unsnoc
uncons = fromMaybe (pfailEx "uncons") . B.uncons
unsnoc = fromMaybe (pfailEx "unsnoc") . B.unsnoc
toHead = B.cons
toLast = B.snoc
force = B.copy
head = B.head
tail = B.tail
last = B.last
init = B.init
partitions is bs = map fromList . partitions is $ listL bs
isSubseqOf xs ys = B.all (`B.elem` ys) xs
-- | O(n) nub, requires O(1) memory.
nub bs = runST $ do
hs <- filled 256 False
B.foldr (\ b io -> writeM' hs b True >> io) (return ()) bs
done' hs
where
done' :: STByteList s Word8 Bool -> ST s ByteString
done' = fmap fromList . kfoldrM (\ i b is -> pure $ b ? (i : is) $ is) []
nubBy f = fromList . B.foldr (\ b es -> any (f b) es ? es $ (b : es)) [] . nub
ofoldr f = \ base bs ->
let n = sizeOf bs; go i = n == i ? base $ f i (bs !^ i) (go $ i + 1)
in go 0
ofoldl f = \ base bs ->
let go i = -1 == i ? base $ f i (go $ i + 1) (bs !^ i)
in go (upper bs)
o_foldr = B.foldr
o_foldl = B.foldl
instance Split ByteString Word8
where
take = B.take . toEnum
drop = B.drop . toEnum
split = B.splitAt . toEnum
isPrefixOf = B.isPrefixOf
isSuffixOf = B.isSuffixOf
isInfixOf = on isInfixOf listL
takeWhile = B.takeWhile
dropWhile = B.dropWhile
spanl = B.span
breakl = B.break
prefix p = B.foldr (\ e c -> p e ? c + 1 $ 0) 0
suffix p = B.foldl (\ c e -> p e ? c + 1 $ 0) 0
--------------------------------------------------------------------------------
{- Map, Indexed and Sort instances. -}
instance Map ByteString Int Word8
where
toMap = toMap' 0
toMap' defvalue ascs = null ascs ? Z $ assoc' (ascsBounds ascs) defvalue ascs
(.!) es = B.index es . toEnum
Z // ascs = toMap ascs
es // ascs = assoc (bounds es) (assocs es ++ ascs)
(.$) = fmap fromEnum ... B.findIndex
(*$) = fmap fromEnum ... B.findIndices
kfoldr = ofoldr
kfoldl = ofoldl
instance Indexed ByteString Int Word8
where
assoc = flip assoc' 0
assoc' bnds@(l, _) defvalue ascs = B.fromChunks $
go l [ (offset bnds i, e) | (i, e) <- ascs, inRange bnds i ]
where
go :: Int -> [(Int, Word8)] -> [S.ByteString]
go _ [] = []
go cl ies' = chunk : go nl rest
where
chunk = fromList $ assoc' (cl, nl - 1) defvalue ch
(ch, rest) = partition (\ (i, _) -> i < nl) ies'
nl = cl + lim
fromIndexed es = assoc bnds' [ (offset bnds i, e) | (i, e) <- assocs es ]
where
bnds' = defaultBounds (sizeOf es)
bnds = bounds es
instance Sort ByteString Word8
where
sortBy f bs = runST $ do es' <- thaw bs; timSortBy f es'; done es'
sortedBy _ Empty = True
sortedBy f (Chunk ch Z) = sortedBy f ch
sortedBy f (Chunk Z chs) = sortedBy f chs
sortedBy f (Chunk ch chs) = sortedBy f ch && last ch `f` head chs && sortedBy f chs
--------------------------------------------------------------------------------
instance Thaw (ST s) ByteString (STUblist s Word8)
where
thaw = fromChunksM <=< B.foldrChunks (liftA2 (:) . thaw) (return [])
instance Freeze (ST s) (STUblist s Word8) ByteString
where
freeze = F.foldrM (\ e rs -> (`Chunk` rs) <$> freeze e) Empty . toChunks
instance (MonadIO io) => Thaw io ByteString (MIOUblist io Word8)
where
thaw = fromChunksM <=< B.foldrChunks (liftA2 (:) . thaw) (return [])
instance (MonadIO io) => Freeze io (MIOUblist io Word8) ByteString
where
freeze = F.foldrM (\ e rs -> (`Chunk` rs) <$> freeze e) Empty . toChunks
--------------------------------------------------------------------------------
{- Nullable and Estimate instances. -}
instance Nullable ByteString
where
lzero = B.empty
isNull = B.null
instance Estimate ByteString
where
(<==>) = go 0
where
go o Empty Empty = o <=> 0
go o xs Empty = xs <.=> (-o)
go o Empty ys = o <=.> ys
go o (Chunk ch1 chs1) (Chunk ch2 chs2) =
go (o + sizeOf ch1 - sizeOf ch2) chs1 chs2
Empty <.=> n = 0 <=> n
(Chunk ch chs) <.=> n = ch .> n ? GT $ chs <.=> (n - sizeOf ch)
--------------------------------------------------------------------------------
{- IsFile and IsTextFile instances. -}
instance IsFile ByteString
where
hGetContents = liftIO . B.hGetContents
hPutContents = liftIO ... B.hPut
instance IsTextFile ByteString
where
hPutStrLn h = liftIO . (>> hPutChar h '\n') . hPutStr h
hGetLine = liftIO . fmap B.fromStrict . S.hGetLine
hPutStr = liftIO ... B.hPut
--------------------------------------------------------------------------------
ascsBounds :: (Ord a) => [(a, b)] -> (a, a)
ascsBounds = \ ((x, _) : xs) -> foldr (\ (e, _) (mn, mx) -> (min mn e, max mx e)) (x, x) xs
done :: STUblist s Word8 -> ST s ByteString
done = freeze
pfailEx :: String -> a
pfailEx = throw . PatternMatchFail . showString "in SDP.ByteString.Lazy."
lim :: Int
lim = 1024