-- requiring that the entire content be resident in memory.

-- Some operations, such as 'concat', 'append', 'reverse' and 'cons',

--- have better complexity than their "Data.Text" equivalents, due to

--- optimisations resulting from the list spine structure. And for

--- other operations lazy 'Text's are usually within a few percent of

--- strict ones, but with better heap usage. For data larger than

--- available memory, or if you have tight memory constraints, this

--- module will be the only option.

+-- have better time complexity than their "Data.Text" equivalents, due

+-- to the underlying representation being a list of chunks. For other

+-- operations, lazy 'Text's are usually within a few percent of strict

+-- ones, but often with better heap usage if used in a streaming

+-- fashion. For data larger than available memory, or if you have

+-- tight memory constraints, this module will be the only option.

-- This module is intended to be imported @qualified@, to avoid name

-- clashes with "Prelude" functions. eg.

-- | /O(n)/ Convert a 'Text' into a 'String'.

--- Subject to ~~array ~~fusion.

unpack t = S.unstreamList (stream t)

{-# INLINE [1] unpack #-}

unstream (S.snoc (stream t) c) = snoc t c

--- | /O(n\/c)/ Appends one 'Text' to another. Subject to array

+-- | /O(n\/c)/ Appends one 'Text' to another. Subject to fusion.

append :: Text -> Text -> Text

append xs ys = foldrChunks Chunk ys xs

{-# INLINE [1] append #-}

-- | /O(1)/ Returns the first character and rest of a 'Text', or

--- 'Nothing' if empty. Subject to ~~array ~~fusion.

+-- 'Nothing' if empty. Subject to fusion.

uncons :: Text -> Maybe (Char, Text)

uncons (Chunk t ts) = Just (T.unsafeHead t, ts')

-- | /O(1)/ Returns the first character of a 'Text', which must be

--- non-empty. Subject to ~~array ~~fusion.

+-- non-empty. Subject to fusion.

head t = S.head (stream t)

-- | /O(1)/ Returns all characters after the head of a 'Text', which

--- must be non-empty. Subject to ~~array ~~fusion.

+-- must be non-empty. Subject to fusion.

tail (Chunk t ts) = chunk (T.tail t) ts

tail Empty = emptyError "tail"

-- | /O(1)/ Returns all but the last character of a 'Text', which must

--- be non-empty. Subject to ~~array ~~fusion.

+-- be non-empty. Subject to fusion.

init (Chunk t0 ts0) = go t0 ts0

where go t (Chunk t' ts) = Chunk t (go t' ts)

unstream (S.init (stream t)) = init t

--- | /O(1)/ Tests whether a 'Text' is empty or not. Subject to~~ array~~

+-- | /O(1)/ Tests whether a 'Text' is empty or not. Subject to

{-# INLINE isSingleton #-}

-- | /O(1)/ Returns the last character of a 'Text', which must be

--- non-empty. Subject to ~~array ~~fusion.

+-- non-empty. Subject to fusion.

last Empty = emptyError "last"

last (Chunk t ts) = go t ts

{-# INLINE intercalate #-}

-- | /O(n)/ The 'intersperse' function takes a character and places it

--- between the characters of a 'Text'. Subject to array fusion.

-intersperse :: Char -> Text -> Text

-intersperse c t = unstream (S.intersperse c (stream t))

+-- between the characters of a 'Text'. Subject to fusion. Performs

+-- replacement on invalid scalar values.

+intersperse :: Char -> Text -> Text

+intersperse c t = unstream (S.intersperse (safe c) (stream t))

{-# INLINE intersperse #-}

-- | /O(n)/ Left-justify a string to the given length, using the

-- | /O(n)/ 'foldl', applied to a binary operator, a starting value

-- (typically the left-identity of the operator), and a 'Text',

-- reduces the 'Text' using the binary operator, from left to right.

--- Subject to ~~array ~~fusion.

foldl :: (a -> Char -> a) -> a -> Text -> a

foldl f z t = S.foldl f z (stream t)

-- | /O(n)/ A strict version of 'foldl'.

--- Subject to ~~array ~~fusion.

foldl' :: (a -> Char -> a) -> a -> Text -> a

foldl' f z t = S.foldl' f z (stream t)

-- | /O(n)/ A variant of 'foldl' that has no starting value argument,

--- and thus must be applied to a non-empty 'Text'. Subject to array

+-- and thus must be applied to a non-empty 'Text'. Subject to fusion.

foldl1 :: (Char -> Char -> Char) -> Text -> Char

foldl1 f t = S.foldl1 f (stream t)

--- | /O(n)/ A strict version of 'foldl1'.

--- Subject to array fusion.

+-- | /O(n)/ A strict version of 'foldl1'. Subject to fusion.

foldl1' :: (Char -> Char -> Char) -> Text -> Char

foldl1' f t = S.foldl1' f (stream t)

-- | /O(n)/ 'foldr', applied to a binary operator, a starting value

-- (typically the right-identity of the operator), and a 'Text',

-- reduces the 'Text' using the binary operator, from right to left.

--- Subject to ~~array ~~fusion.

foldr :: (Char -> a -> a) -> a -> Text -> a

foldr f z t = S.foldr f z (stream t)

--- | /O(n)/ A variant of 'foldr' that has no starting value argument, and

--- thust must be applied to a non-empty 'Text'. Subject to array

+-- | /O(n)/ A variant of 'foldr' that has no starting value argument,

+-- and thust must be applied to a non-empty 'Text'. Subject to

foldr1 :: (Char -> Char -> Char) -> Text -> Char

foldr1 f t = S.foldr1 f (stream t)

-- | /O(n)/ 'any' @p@ @t@ determines whether any character in the

--- 'Text' @t@ satisifes the predicate @p@. Subject to ~~array ~~fusion.

+-- 'Text' @t@ satisifes the predicate @p@. Subject to fusion.

any :: (Char -> Bool) -> Text -> Bool

any p t = S.any p (stream t)

-- | /O(n)/ 'all' @p@ @t@ determines whether all characters in the

--- 'Text' @t@ satisify the predicate @p@. Subject to ~~array ~~fusion.

+-- 'Text' @t@ satisify the predicate @p@. Subject to fusion.

all :: (Char -> Bool) -> Text -> Bool

all p t = S.all p (stream t)

-- | /O(n)/ 'maximum' returns the maximum value from a 'Text', which

--- must be non-empty. Subject to ~~array ~~fusion.

+-- must be non-empty. Subject to fusion.

maximum t = S.maximum (stream t)

-- | /O(n)/ 'minimum' returns the minimum value from a 'Text', which

--- must be non-empty. Subject to ~~array ~~fusion.

+-- must be non-empty. Subject to fusion.

minimum t = S.minimum (stream t)

where len' = fromIntegral len

--- | /O(n)/ 'takeWhile', applied to a predicate @p@ and a 'Text', returns

--- the longest prefix (possibly empty) of elements that satisfy @p@.

--- This function is subject to array fusion.

+-- | /O(n)/ 'takeWhile', applied to a predicate @p@ and a 'Text',

+-- returns the longest prefix (possibly empty) of elements that

+-- satisfy @p@. Subject to fusion.

takeWhile :: (Char -> Bool) -> Text -> Text

takeWhile p t0 = takeWhile' t0

where takeWhile' Empty = Empty

-- | /O(n)/ 'dropWhile' @p@ @t@ returns the suffix remaining after

--- 'takeWhile' @p@ @t@. ~~This function is s~~ubject to ~~array ~~fusion.

+-- 'takeWhile' @p@ @t@. Subject to fusion.

dropWhile :: (Char -> Bool) -> Text -> Text

dropWhile p t0 = dropWhile' t0

where dropWhile' Empty = Empty

-- | /O(n)/ The 'isPrefixOf' function takes two 'Text's and returns

--- 'True' iff the first is a prefix of the second. This function is

+-- 'True' iff the first is a prefix of the second. Subject to fusion.

isPrefixOf :: Text -> Text -> Bool

isPrefixOf Empty _ = True

isPrefixOf _ Empty = False

-- | /O(n)/ The 'countChar' function returns the number of times the

--- query element appears in the given 'Text'. This function is subject

+-- query element appears in the given 'Text'. Subject to fusion.

countChar :: Char -> Text -> Int64

countChar c t = S.countChar c (stream t)