liquidhaskell-0.8.10.7: benchmarks/text-0.11.2.3/Data/Text/Lazy/Internal.hs
{-@ LIQUID "--pruneunsorted" @-}
{-@ LIQUID "--maxparams=3" @-}
{- LIQUID "--trust-sizes" @-}
{-# LANGUAGE BangPatterns, DeriveDataTypeable #-}
-- |
-- Module : Data.Text.Lazy.Internal
-- Copyright : (c) 2009, 2010 Bryan O'Sullivan
--
-- License : BSD-style
-- Maintainer : bos@serpentine.com, rtomharper@googlemail.com,
-- duncan@haskell.org
-- Stability : experimental
-- Portability : GHC
--
-- A module containing private 'Text' internals. This exposes the
-- 'Text' representation and low level construction functions.
-- Modules which extend the 'Text' system may need to use this module.
--
-- You should not use this module unless you are determined to monkey
-- with the internals, as the functions here do just about nothing to
-- preserve data invariants. You have been warned!
module Data.Text.Lazy.Internal
(
Text(..)
, chunk
, empty
, foldrChunks
, foldlChunks
-- * Data type invariant and abstraction functions
-- $invariant
, strictInvariant
, lazyInvariant
, showStructure
-- * Chunk allocation sizes
, defaultChunkSize
, smallChunkSize
, chunkOverhead
) where
import Data.Text ()
import Data.Text.UnsafeShift (shiftL)
import Data.Typeable (Typeable)
import Foreign.Storable (sizeOf)
import Foreign.ForeignPtr
import qualified Data.Text.Internal as T
--LIQUID
import Language.Haskell.Liquid.Prelude
import qualified Data.Text.Fusion.Size as TODO_REBARE
import qualified Data.Text.Array as TODO_REBARE
import qualified Data.Text as TODO_REBARE
data Text = Empty
| Chunk {-# UNPACK #-} !T.Text Text
--LIQUID deriving (Typeable)
{-@ data Text [ltlen] = Empty
| Chunk { txtHead :: TextNE, txtRest :: Text }
@-}
{-@ measure ltlen :: Text -> Integer
ltlen Empty = 0
ltlen (Chunk t ts) = (tlen t) + (ltlen ts)
@-}
{-@ measure ltlength :: Text -> Integer
ltlength Empty = 0
ltlength (Chunk t ts) = (tlength t) + (ltlength ts)
@-}
{-@ measure sum_ltlengths :: [Text] -> Integer
sum_ltlengths [] = 0
sum_ltlengths (t:ts) = (ltlength t) + (sum_ltlengths ts)
@-}
{-@ qualif SumLTLengthsAcc(v:Text, ts:List Text, t:Text):
ltlength(v) = sum_ltlengths(ts) + ltlength(t)
@-}
{-@ type LTextN N = {v:Text | (ltlen v) = N} @-}
{-@ type LTextNC N = {v:Text | (ltlength v) = N} @-}
{-@ type LTextNE = {v:Text | (((ltlen v) > 0) && (ltlength v) > 0)} @-}
{-@ type LTextLE T = {v:Text | (ltlen v) <= (ltlen T)} @-}
{-@ type LTextLT T = {v:Text | (ltlen v) < (ltlen T)} @-}
{-@ qualif LTLenLe(v:Text, t:Text): (ltlen v) <= (ltlen t) @-}
{-@ invariant {v:Text | (ltlen v) >= 0} @-}
{-@ invariant {v:Text | (ltlength v) >= 0} @-}
{-@ invariant {v:Text | (((ltlength v) = 0) <=> ((ltlen v) = 0))} @-}
{-@ invariant {v0:[Text] | (sum_ltlengths v0) >= 0} @-}
{-@ invariant {v0:[{v:Text | (sum_ltlengths v0) >= (ltlength v)}] | true} @-}
-- $invariant
--
-- The data type invariant for lazy 'Text': Every 'Text' is either 'Empty' or
-- consists of non-null 'T.Text's. All functions must preserve this,
-- and the QC properties must check this.
-- | Check the invariant strictly.
{-@ strictInvariant :: Text -> Bool @-}
strictInvariant :: Text -> Bool
strictInvariant Empty = True
strictInvariant x@(Chunk (T.Text _ _ len) cs)
| len > 0 = strictInvariant cs
| otherwise = liquidError $ "Data.Text.Lazy: invariant violation: "
++ showStructure x
-- | Check the invariant lazily.
{-@ lazyInvariant :: Text -> Text @-}
lazyInvariant :: Text -> Text
lazyInvariant Empty = Empty
lazyInvariant x@(Chunk c@(T.Text _ _ len) cs)
| len > 0 = Chunk c (lazyInvariant cs)
| otherwise = liquidError $ "Data.Text.Lazy: invariant violation: "
++ showStructure x
-- | Display the internal structure of a lazy 'Text'.
{-@ showStructure :: Text -> String @-}
showStructure :: Text -> String
showStructure Empty = "Empty"
showStructure (Chunk t Empty) = "Chunk " ++ show t ++ " Empty"
showStructure (Chunk t ts) =
"Chunk " ++ show t ++ " (" ++ showStructure ts ++ ")"
-- | Smart constructor for 'Chunk'. Guarantees the data type invariant.
{-@ chunk :: t:_ -> ts:Text
-> {v:Text | (((ltlength v) = ((tlength t) + (ltlength ts)))
&& ((ltlen v) = ((tlen t) + (ltlen ts))))}
@-}
chunk :: T.Text -> Text -> Text
{-# INLINE chunk #-}
chunk t@(T.Text _ _ len) ts | len == 0 = ts
| otherwise = Chunk t ts
-- | Smart constructor for 'Empty'.
{-@ empty :: {v:Text | (ltlength v) = 0} @-}
empty :: Text
{-# INLINE [0] empty #-}
empty = Empty
-- | Consume the chunks of a lazy 'Text' with a natural right fold.
{-@ foldrChunks :: forall <p :: Text -> a -> Bool>.
(ts:Text -> t:TextNE -> a<p ts> -> a<p (Chunk t ts)>)
-> a<p Empty>
-> t:Text
-> a<p t>
@-}
foldrChunks :: (Text -> T.Text -> a -> a) -> a -> Text -> a
foldrChunks f z = go
where go Empty = z
go (Chunk c cs) = f cs c (go cs)
--LIQUID foldrChunks :: (T.Text -> a -> a) -> a -> Text -> a
--LIQUID foldrChunks f z = go
--LIQUID where go Empty = z
--LIQUID go (Chunk c cs) = f c (go cs)
{-# INLINE foldrChunks #-}
-- | Consume the chunks of a lazy 'Text' with a strict, tail-recursive,
-- accumulating left fold.
{-@ foldlChunks :: (a -> TextNE -> a) -> a -> Text -> a @-}
foldlChunks :: (a -> T.Text -> a) -> a -> Text -> a
foldlChunks f z = go z
where go !a Empty = a
go !a (Chunk c cs) = go (f a c) cs
{-# INLINE foldlChunks #-}
-- | Currently set to 16 KiB, less the memory management overhead.
{-@ defaultChunkSize :: {v:Nat | v = 16368} @-}
defaultChunkSize :: Int
defaultChunkSize = 16384 - chunkOverhead
{-# INLINE defaultChunkSize #-}
-- | Currently set to 128 bytes, less the memory management overhead.
{-@ smallChunkSize :: {v:Nat | v = 112} @-}
smallChunkSize :: Int
smallChunkSize = 128 - chunkOverhead
{-# INLINE smallChunkSize #-}
-- | The memory management overhead. Currently this is tuned for GHC only.
{-@ chunkOverhead :: {v:Nat | v = 16} @-}
chunkOverhead :: Int
chunkOverhead = sizeOf (undefined :: Int) `shiftL` 1
{-# INLINE chunkOverhead #-}