sdp4text-0.2: src/SDP/Text/Lazy.hs
{-# LANGUAGE Safe, MagicHash, MultiParamTypeClasses, FlexibleInstances #-}
{- |
Module : SDP.Text.Lazy
Copyright : (c) Andrey Mulik 2020
License : BSD-style
Maintainer : work.a.mulik@gmail.com
Portability : non-portable (GHC extensions)
"SDP.Text.Lazy" provides @sdp@ instances for lazy 'Text'.
-}
module SDP.Text.Lazy
(
-- * Exports
module System.IO.Classes,
module SDP.IndexedM,
-- * Lazy text
LText, Text, L.toCaseFold, L.toLower, L.toUpper, L.toTitle,
L.fromChunks, L.toChunks, L.toStrict, L.fromStrict,
L.foldrChunks, L.foldlChunks
)
where
import Prelude ()
import SDP.SafePrelude
import SDP.IndexedM
import SDP.Text ()
import qualified Data.Text.Lazy.IO as IO
import qualified Data.Text.Lazy as L
import Data.Text.Lazy ( Text )
import Data.Maybe
import SDP.Templates.AnyChunks
import SDP.ByteList.IOUblist
import SDP.ByteList.STUblist
import Control.Exception.SDP
import System.IO.Classes
default ()
--------------------------------------------------------------------------------
-- | 'Text' alias, may reduce ambiguity.
type LText = Text
--------------------------------------------------------------------------------
{- Nullable and Estimate instances. -}
instance Nullable Text
where
isNull = L.null
lzero = L.empty
instance Estimate Text
where
{-# INLINE (<.=>) #-}
xs <.=> n = xs `L.compareLength` fromIntegral n
{-# INLINE (<==>) #-}
xs <==> ys = xs `L.compareLength` L.length ys
--------------------------------------------------------------------------------
{- Bordered, Linear and Split instances. -}
instance Bordered Text Int
where
lower _ = 0
upper ts = sizeOf ts - 1
bounds ts = (0, sizeOf ts - 1)
sizeOf = fromIntegral . L.length
instance Linear Text Char
where
uncons' = L.uncons
unsnoc' = L.unsnoc
uncons = fromMaybe (pfailEx "(:>)") . L.uncons
unsnoc = fromMaybe (pfailEx "(:<)") . L.unsnoc
single = L.singleton
toHead = L.cons
toLast = L.snoc
(++) = L.append
head = L.head
last = L.last
tail = L.tail
init = L.init
(!^) es = L.index es . fromIntegral
write es = (es //) . single ... (,)
replicate n e = L.replicate (fromIntegral n) (L.singleton e)
fromList = L.pack
reverse = L.reverse
force = L.fromChunks . map force . L.toChunks
listR = L.unpack . reverse
listL = L.unpack
concat = L.concat . toList
filter = L.filter
concatMap f = concat . foldr ((:) . f) []
intersperse = L.intersperse
partition = L.partition
ofoldr f =
let go = \ ch (i, acc) -> (i + sizeOf ch, ofoldr (f . (+ i)) acc ch)
in snd ... L.foldrChunks go . (,) 0
ofoldl f base text =
let go = \ (i, acc) ch -> (i + sizeOf ch, ofoldl (f . (+ i)) acc ch)
in snd $ L.foldlChunks go (upper text, base) text
o_foldl' = L.foldl'
o_foldr = L.foldr
o_foldl = L.foldl
instance Split Text Char
where
take = L.take . fromIntegral
drop = L.drop . fromIntegral
keep = L.takeEnd . fromIntegral
sans = L.dropEnd . fromIntegral
split = L.splitAt . fromIntegral
chunks = L.chunksOf . fromIntegral
replaceBy = L.replace
splitsOn = L.splitOn
splitsBy = L.split
justifyL = L.justifyLeft . fromIntegral
justifyR = L.justifyRight . fromIntegral
isPrefixOf = L.isPrefixOf
isSuffixOf = L.isSuffixOf
isInfixOf = L.isInfixOf
prefix p = L.foldr (\ e c -> p e ? c + 1 $ 0) 0
suffix p = L.foldl (\ c e -> p e ? c + 1 $ 0) 0
takeWhile = L.takeWhile
dropWhile = L.dropWhile
takeEnd = L.takeWhileEnd
dropEnd = L.dropWhileEnd
--------------------------------------------------------------------------------
{- Map and Indexed instances. -}
instance Map Text Int Char
where
toMap ascs = isNull ascs ? Z $ assoc (l, u) ascs
where
l = fst $ minimumBy cmpfst ascs
u = fst $ maximumBy cmpfst ascs
toMap' defvalue ascs = isNull ascs ? Z $ assoc' (l, u) defvalue ascs
where
l = fst $ minimumBy cmpfst ascs
u = fst $ maximumBy cmpfst ascs
Z // ascs = toMap ascs
es // ascs = runST $ thaw es >>= (`overwrite` ascs) >>= done
(.!) es = L.index es . fromIntegral
kfoldr' = ofoldr'
kfoldl' = ofoldl'
kfoldr = ofoldr
kfoldl = ofoldl
instance Indexed Text Int Char
where
assoc bnds ascs = runST $ fromAssocs bnds ascs >>= done
assoc' bnds defvalue ascs = runST $ fromAssocs' bnds defvalue ascs >>= done
fromIndexed es = runST $ fromIndexed' es >>= done
--------------------------------------------------------------------------------
{- Thaw and Freeze instances. -}
instance Thaw (ST s) Text (STUblist s Char)
where
unsafeThaw = fromChunksM <=< mapM unsafeThaw . L.toChunks
thaw = fromChunksM <=< mapM thaw . L.toChunks
instance Freeze (ST s) (STUblist s Char) Text
where
unsafeFreeze = fmap L.fromChunks . mapM unsafeFreeze . toChunks
freeze = fmap L.fromChunks . mapM freeze . toChunks
instance (MonadIO io) => Thaw io Text (MIOUblist io Char)
where
unsafeThaw = fromChunksM <=< mapM unsafeThaw . L.toChunks
thaw = fromChunksM <=< mapM thaw . L.toChunks
instance (MonadIO io) => Freeze io (MIOUblist io Char) Text
where
unsafeFreeze = fmap L.fromChunks . mapM unsafeFreeze . toChunks
freeze = fmap L.fromChunks . mapM freeze . toChunks
--------------------------------------------------------------------------------
{- IsFile and IsTextFile instances. -}
instance IsFile Text
where
hGetContents = liftIO . IO.hGetContents
hPutContents = liftIO ... IO.hPutStr
instance IsTextFile Text
where
hPutStrLn = liftIO ... IO.hPutStrLn
hGetLine = liftIO . IO.hGetLine
hPutStr = liftIO ... IO.hPutStr
--------------------------------------------------------------------------------
done :: STUblist s Char -> ST s Text
done = freeze
pfailEx :: String -> a
pfailEx = throw . PatternMatchFail . showString "in SDP.Text.Lazy."