1{-# LANGUAGE BangPatterns #-}
2{-# OPTIONS_GHC -fno-warn-orphans #-}
6-- Copyright : (c) Tom Harper 2008-2009,
7-- (c) Bryan O'Sullivan 2009,
8-- (c) Duncan Coutts 2009
11-- Maintainer : rtharper@aftereternity.co.uk, bos@serpentine.com,
13-- Stability : experimental
16-- A time and space-efficient implementation of Unicode text using
17-- packed Word16 arrays. Suitable for performance critical use, both
18-- in terms of large data quantities and high speed.
20-- This module is intended to be imported @qualified@, to avoid name
21-- clashes with "Prelude" functions, e.g.
23-- > import qualified Data.Text as T
33 -- * Creation and elimination
82 -- ** Accumulating maps
86 -- ** Generation and unfolding
93 -- ** Breaking strings
106 -- ** Breaking into many substrings
111 -- ** Breaking into lines and words
139 -- * Zipping and unzipping
146import Prelude (Char, Bool(..), Functor(..), Int, Maybe(..), String,
149 (&&), (||), (+), (-), (<), (>), (<=), (>=), (.), ($),
150 not, return, otherwise)
151import Control.Exception (assert)
152import Data.Char (isSpace)
153import Control.Monad.ST (ST)
154import qualified Data.Text.Array as A
155import qualified Data.List as L
156import Data.Monoid (Monoid(..))
157import Data.Word (Word16)
158import Data.String (IsString(..))
160import qualified Data.Text.Fusion as S
161import Data.Text.Fusion (Stream(..), Step(..), stream, reverseStream, unstream)
162import Data.Text.Internal (Text(..), empty, text)
163import qualified Prelude as P
164import Data.Text.Unsafe (iter, iter_, unsafeHead, unsafeTail)
165import Data.Text.UnsafeChar (unsafeChr)
166import qualified Data.Text.Utf16 as U16
170-- Most of the functions in this module are subject to /array fusion/,
171-- meaning that a pipeline of functions will usually allocate at most
174instance Eq Text where
175 t1 == t2 = (stream t1) `S.eq` (stream t2)
177instance Show Text where
178 showsPrec p ps r = showsPrec p (unpack ps) r
180instance Read Text where
181 readsPrec p str = [(pack x,y) | (x,y) <- readsPrec p str]
183instance Monoid Text where
188instance IsString Text where
191-- -----------------------------------------------------------------------------
192-- * Conversion to/from 'Text'
194-- | /O(n)/ Convert a 'String' into a 'Text'.
196-- This function is subject to array fusion.
197pack :: String -> Text
198pack str = (unstream (stream_list str))
200 stream_list s0 = S.Stream next s0 (P.length s0) -- total guess
203 next (x:xs) = S.Yield x xs
204{-# INLINE [1] pack #-}
205-- TODO: Has to do validation! -- No, it doesn't, the
207-- | /O(n)/ Convert a Text into a String.
208-- Subject to array fusion.
209unpack :: Text -> String
210unpack txt = (unstream_list (stream txt))
212 unstream_list (S.Stream next s0 _len) = unfold s0
214 unfold !s = case next s of
216 S.Skip s' -> unfold s'
217 S.Yield x s' -> x : unfold s'
218{-# INLINE [1] unpack #-}
220-- | /O(1)/ Convert a character into a Text.
221-- Subject to array fusion.
222singleton :: Char -> Text
223singleton c = unstream (Stream next (c:[]) 1)
226 next (k:ks) = Yield k ks
228{-# INLINE [1] singleton #-}
230-- -----------------------------------------------------------------------------
233-- | /O(n)/ Adds a character to the front of a 'Text'. This function
234-- is more costly than its 'List' counterpart because it requires
235-- copying a new array. Subject to array fusion.
236cons :: Char -> Text -> Text
237cons c t = unstream (S.cons c (stream t))
240-- | /O(n)/ Adds a character to the end of a 'Text'. This copies the
241-- entire array in the process. Subject to array fusion.
242snoc :: Text -> Char -> Text
243snoc t c = unstream (S.snoc (stream t) c)
246-- | /O(n)/ Appends one 'Text' to the other by copying both of them
247-- into a new 'Text'. Subject to array fusion.
248append :: Text -> Text -> Text
249append (Text arr1 off1 len1) (Text arr2 off2 len2) = Text (A.run x) 0 len
253 arr <- A.unsafeNew len :: ST s (A.MArray s Word16)
254 copy arr1 off1 (len1+off1) arr 0
255 copy arr2 off2 (len2+off2) arr len1
258 copy arr i max arr' j
259 | i >= max = return ()
260 | otherwise = do A.unsafeWrite arr' j (arr `A.unsafeIndex` i)
261 copy arr (i+1) max arr' (j+1)
265"TEXT append -> fused" [~1] forall t1 t2.
266 append t1 t2 = unstream (S.append (stream t1) (stream t2))
267"TEXT append -> unfused" [1] forall t1 t2.
268 unstream (S.append (stream t1) (stream t2)) = append t1 t2
271-- | /O(1)/ Returns the first character of a 'Text', which must be
272-- non-empty. Subject to array fusion.
274head t = S.head (stream t)
277-- | /O(1)/ Returns the first character and rest of a 'Text', or
278-- 'Nothing' if empty. Subject to array fusion.
279uncons :: Text -> Maybe (Char, Text)
280uncons t@(Text arr off len)
282 | otherwise = Just (c, textP arr (off+d) (len-d))
283 where (c,d) = iter t 0
286-- | Lifted from Control.Arrow and specialized.
287second :: (b -> c) -> (a,b) -> (a,c)
288second f (a, b) = (a, f b)
291"TEXT uncons -> fused" [~1] forall t.
292 uncons t = fmap (second unstream) (S.uncons (stream t))
293"TEXT uncons -> unfused" [1] forall t.
294 fmap (second unstream) (S.uncons (stream t)) = uncons t
297-- | /O(1)/ Returns the last character of a 'Text', which must be
298-- non-empty. Subject to array fusion.
300last (Text arr off len)
301 | len <= 0 = emptyError "last"
302 | n < 0xDC00 || n > 0xDFFF = unsafeChr n
303 | otherwise = U16.chr2 n0 n
304 where n = A.unsafeIndex arr (off+len-1)
305 n0 = A.unsafeIndex arr (off+len-2)
306{-# INLINE [1] last #-}
309"TEXT last -> fused" [~1] forall t.
310 last t = S.last (stream t)
311"TEXT last -> unfused" [1] forall t.
312 S.last (stream t) = last t
315-- | Construct a 'Text' without invisibly pinning its byte array in
316-- memory if its length has dwindled to zero.
317textP :: A.Array Word16 -> Int -> Int -> Text
318textP arr off len | len == 0 = empty
319 | otherwise = text arr off len
322-- | /O(1)/ Returns all characters after the head of a 'Text', which
323-- must be non-empty. Subject to array fusion.
325tail t@(Text arr off len)
326 | len <= 0 = emptyError "tail"
327 | otherwise = textP arr (off+d) (len-d)
329{-# INLINE [1] tail #-}
332"TEXT tail -> fused" [~1] forall t.
333 tail t = unstream (S.tail (stream t))
334"TEXT tail -> unfused" [1] forall t.
335 unstream (S.tail (stream t)) = tail t
338-- | /O(1)/ Returns all but the last character of a 'Text', which must
339-- be non-empty. Subject to array fusion.
341init (Text arr off len) | len <= 0 = emptyError "init"
342 | n >= 0xDC00 && n <= 0xDFFF = textP arr off (len-2)
343 | otherwise = textP arr off (len-1)
345 n = A.unsafeIndex arr (off+len-1)
346{-# INLINE [1] init #-}
349"TEXT init -> fused" [~1] forall t.
350 init t = unstream (S.init (stream t))
351"TEXT init -> unfused" [1] forall t.
352 unstream (S.init (stream t)) = init t
355-- | /O(1)/ Tests whether a 'Text' is empty or not. Subject to array
358null (Text _arr _off len) = assert (len >= 0) $ len <= 0
359{-# INLINE [1] null #-}
362"TEXT null -> fused" [~1] forall t.
363 null t = S.null (stream t)
364"TEXT null -> unfused" [1] forall t.
365 S.null (stream t) = null t
368-- | /O(n)/ Returns the number of characters in a 'Text'.
369-- Subject to array fusion.
371length t = S.length (stream t)
374-- -----------------------------------------------------------------------------
376-- | /O(n)/ 'map' @f @xs is the 'Text' obtained by applying @f@ to
377-- each element of @xs@. Subject to array fusion.
378map :: (Char -> Char) -> Text -> Text
379map f t = unstream (S.map f (stream t))
380{-# INLINE [1] map #-}
382-- | /O(n)/ The 'intercalate' function takes a 'Text' and a list of
383-- 'Text's and concatenates the list after interspersing the first
384-- argument between each element of the list.
385intercalate :: Text -> [Text] -> Text
386intercalate t ts = unstream (S.intercalate (stream t) (L.map stream ts))
387{-# INLINE intercalate #-}
389-- | /O(n)/ The 'intersperse' function takes a character and places it
390-- between the characters of a 'Text'. Subject to array fusion.
391intersperse :: Char -> Text -> Text
392intersperse c t = unstream (S.intersperse c (stream t))
393{-# INLINE intersperse #-}
395-- | /O(n)/ Reverse the characters of a string. Subject to array fusion.
396reverse :: Text -> Text
397reverse t = S.reverse (stream t)
398{-# INLINE reverse #-}
400-- | /O(n)/ The 'transpose' function transposes the rows and columns
401-- of its 'Text' argument. Note that this function uses 'pack',
402-- 'unpack', and the list version of transpose, and is thus not very
404transpose :: [Text] -> [Text]
405transpose ts = P.map pack (L.transpose (P.map unpack ts))
407-- -----------------------------------------------------------------------------
408-- * Reducing 'Text's (folds)
410-- | /O(n)/ 'foldl', applied to a binary operator, a starting value
411-- (typically the left-identity of the operator), and a 'Text',
412-- reduces the 'Text' using the binary operator, from left to right.
413-- Subject to array fusion.
414foldl :: (b -> Char -> b) -> b -> Text -> b
415foldl f z t = S.foldl f z (stream t)
418-- | /O(n)/ A strict version of 'foldl'.
419-- Subject to array fusion.
420foldl' :: (b -> Char -> b) -> b -> Text -> b
421foldl' f z t = S.foldl' f z (stream t)
424-- | /O(n)/ A variant of 'foldl' that has no starting value argument,
425-- and thus must be applied to a non-empty 'Text'. Subject to array
427foldl1 :: (Char -> Char -> Char) -> Text -> Char
428foldl1 f t = S.foldl1 f (stream t)
431-- | /O(n)/ A strict version of 'foldl1'.
432-- Subject to array fusion.
433foldl1' :: (Char -> Char -> Char) -> Text -> Char
434foldl1' f t = S.foldl1' f (stream t)
435{-# INLINE foldl1' #-}
437-- | /O(n)/ 'foldr', applied to a binary operator, a starting value
438-- (typically the right-identity of the operator), and a 'Text',
439-- reduces the 'Text' using the binary operator, from right to left.
440-- Subject to array fusion.
441foldr :: (Char -> b -> b) -> b -> Text -> b
442foldr f z t = S.foldr f z (stream t)
445-- | /O(n)/ A variant of 'foldr' that has no starting value argument, and
446-- thust must be applied to a non-empty 'Text'. Subject to array
448foldr1 :: (Char -> Char -> Char) -> Text -> Char
449foldr1 f t = S.foldr1 f (stream t)
452-- -----------------------------------------------------------------------------
455-- | /O(n)/ Concatenate a list of 'Text's. Subject to array fusion.
456concat :: [Text] -> Text
457concat ts = unstream (S.concat (L.map stream ts))
460-- | /O(n)/ Map a function over a 'Text' that results in a 'Text', and
461-- concatenate the results. This function is subject to array fusion.
463-- Note: if in 'concatMap' @f@ @t@, @f@ is defined in terms of fusible
464-- functions, it will also be fusible.
465concatMap :: (Char -> Text) -> Text -> Text
466concatMap f t = unstream (S.concatMap (stream . f) (stream t))
467{-# INLINE concatMap #-}
469-- | /O(n)/ 'any' @p@ @t@ determines whether any character in the
470-- 'Text' @t@ satisifes the predicate @p@. Subject to array fusion.
471any :: (Char -> Bool) -> Text -> Bool
472any p t = S.any p (stream t)
475-- | /O(n)/ 'all' @p@ @t@ determines whether all characters in the
476-- 'Text' @t@ satisify the predicate @p@. Subject to array fusion.
477all :: (Char -> Bool) -> Text -> Bool
478all p t = S.all p (stream t)
481-- | /O(n)/ 'maximum' returns the maximum value from a 'Text', which
482-- must be non-empty. Subject to array fusion.
483maximum :: Text -> Char
484maximum t = S.maximum (stream t)
485{-# INLINE maximum #-}
487-- | /O(n)/ 'minimum' returns the minimum value from a 'Text', which
488-- must be non-empty. Subject to array fusion.
489minimum :: Text -> Char
490minimum t = S.minimum (stream t)
491{-# INLINE minimum #-}
493-- -----------------------------------------------------------------------------
496-- | /O(n)/ 'scanl' is similar to 'foldl', but returns a list of
497-- successive reduced values from the left. This function is subject
500-- > scanl f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...]
504-- > last (scanl f z xs) == foldl f z xs.
505scanl :: (Char -> Char -> Char) -> Char -> Text -> Text
506scanl f z t = unstream (S.scanl f z (stream t))
509-- | /O(n)/ 'scanl1' is a variant of 'scanl' that has no starting
510-- value argument. This function is subject to array fusion.
512-- > scanl1 f [x1, x2, ...] == [x1, x1 `f` x2, ...]
513scanl1 :: (Char -> Char -> Char) -> Text -> Text
514scanl1 f t | null t = empty
515 | otherwise = scanl f (unsafeHead t) (unsafeTail t)
518-- | /O(n)/ 'scanr' is the right-to-left dual of 'scanl'.
520-- > scanr f v t == reverse (scanl (flip f) v t)
521scanr :: (Char -> Char -> Char) -> Char -> Text -> Text
522scanr f z = S.reverse . S.reverseScanr f z . reverseStream
525-- | /O(n)/ 'scanr1' is a variant of 'scanr' that has no starting
526-- value argument. This function is subject to array fusion.
527scanr1 :: (Char -> Char -> Char) -> Text -> Text
528scanr1 f t | null t = empty
529 | otherwise = scanr f (last t) (init t)
532-- | /O(n)/ Like a combination of 'map' and 'foldl'. Applies a
533-- function to each element of a 'Text', passing an accumulating
534-- parameter from left to right, and returns a final 'Text'.
535mapAccumL :: (a -> Char -> (a,Char)) -> a -> Text -> (a, Text)
536mapAccumL f s t = case uncons t of
537 Nothing -> (s, empty)
538 Just (x, xs) -> (s'', cons y ys)
539 where (s', y ) = f s x
540 (s'',ys) = mapAccumL f s' xs
542-- | The 'mapAccumR' function behaves like a combination of 'map' and
543-- 'foldr'; it applies a function to each element of a 'Text', passing
544-- an accumulating parameter from right to left, and returning a final
545-- value of this accumulator together with the new 'Text'.
546mapAccumR :: (a -> Char -> (a,Char)) -> a -> Text -> (a, Text)
547mapAccumR f s t = case uncons t of
548 Nothing -> (s, empty)
549 Just (x, xs) -> (s'', cons y ys)
550 where (s'',y ) = f s' x
551 (s', ys) = mapAccumR f s xs
553-- -----------------------------------------------------------------------------
554-- ** Generating and unfolding 'Text's
556-- | /O(n)/ 'replicate' @n@ @c@ is a 'Text' of length @n@ with @c@ the
557-- value of every element.
558replicate :: Int -> Char -> Text
559replicate n c = unstream (S.replicate n c)
560{-# INLINE replicate #-}
562-- | /O(n)/, where @n@ is the length of the result. The 'unfoldr'
563-- function is analogous to the List 'L.unfoldr'. 'unfoldr' builds a
564-- 'Text' from a seed value. The function takes the element and
565-- returns 'Nothing' if it is done producing the 'Text', otherwise
566-- 'Just' @(a,b)@. In this case, @a@ is the next 'Char' in the
567-- string, and @b@ is the seed value for further production.
568unfoldr :: (a -> Maybe (Char,a)) -> a -> Text
569unfoldr f s = unstream (S.unfoldr f s)
570{-# INLINE unfoldr #-}
572-- | /O(n)/ Like 'unfoldr', 'unfoldrN' builds a 'Text' from a seed
573-- value. However, the length of the result should be limited by the
574-- first argument to 'unfoldrN'. This function is more efficient than
575-- 'unfoldr' when the maximum length of the result is known and
576-- correct, otherwise its performance is similar to 'unfoldr'.
577unfoldrN :: Int -> (a -> Maybe (Char,a)) -> a -> Text
578unfoldrN n f s = unstream (S.unfoldrN n f s)
579{-# INLINE unfoldrN #-}
581-- -----------------------------------------------------------------------------
584-- | /O(n)/ 'take' @n@, applied to a 'Text', returns the prefix of the
585-- 'Text' of length @n@, or the 'Text' itself if @n@ is greater than
586-- the length of the Text.
587take :: Int -> Text -> Text
588take n t@(Text arr off len)
591 | otherwise = Text arr off (loop 0 0)
594 | i >= len || cnt >= n = i
595 | otherwise = loop (i+d) (cnt+1)
597{-# INLINE [1] take #-}
600"TEXT take -> fused" [~1] forall n t.
601 take n t = unstream (S.take n (stream t))
602"TEXT take -> unfused" [1] forall n t.
603 unstream (S.take n (stream t)) = take n t
606-- | /O(n)/ 'drop' @n@, applied to a 'Text', returns the suffix of the
607-- 'Text' of length @n@, or the empty 'Text' if @n@ is greater than the
608-- length of the 'Text'.
609drop :: Int -> Text -> Text
610drop n t@(Text arr off len)
613 | otherwise = loop 0 0
614 where end = off + len
616 | i >= end || cnt >= n = Text arr (off+i) (len-i)
617 | otherwise = loop (i+d) (cnt+1)
619{-# INLINE [1] drop #-}
622"TEXT drop -> fused" [~1] forall n t.
623 drop n t = unstream (S.drop n (stream t))
624"TEXT drop -> unfused" [1] forall n t.
625 unstream (S.drop n (stream t)) = drop n t
628-- | /O(n)/ 'takeWhile', applied to a predicate @p@ and a 'Text', returns
629-- the longest prefix (possibly empty) of elements that satisfy @p@.
630-- This function is subject to array fusion.
631takeWhile :: (Char -> Bool) -> Text -> Text
632takeWhile p t@(Text arr off len) = loop 0
633 where loop !i | i >= len = t
635 | otherwise = textP arr off i
636 where (c,d) = iter t i
637{-# INLINE [1] takeWhile #-}
640"TEXT takeWhile -> fused" [~1] forall p t.
641 takeWhile p t = unstream (S.takeWhile p (stream t))
642"TEXT takeWhile -> unfused" [1] forall p t.
643 unstream (S.takeWhile p (stream t)) = takeWhile p t
646-- | /O(n)/ 'dropWhile' @p@ @xs@ returns the suffix remaining after
647-- 'takeWhile' @p@ @xs@. This function is subject to array fusion.
648dropWhile :: (Char -> Bool) -> Text -> Text
649dropWhile p t@(Text arr off len) = loop 0 0
650 where loop !i !l | l >= len = empty
651 | p c = loop (i+d) (l+d)
652 | otherwise = Text arr (off+i) (len-l)
653 where (c,d) = iter t i
654{-# INLINE [1] dropWhile #-}
657"TEXT dropWhile -> fused" [~1] forall p t.
658 dropWhile p t = unstream (S.dropWhile p (stream t))
659"TEXT dropWhile -> unfused" [1] forall p t.
660 unstream (S.dropWhile p (stream t)) = dropWhile p t
663-- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a
664-- prefix of @t@ of length @n@, and whose second is the remainder of
665-- the string. It is equivalent to @('take' n t, 'drop' n t)@.
666splitAt :: Int -> Text -> (Text, Text)
667splitAt n t@(Text arr off len)
668 | n <= 0 = (empty, t)
669 | n >= len = (t, empty)
670 | otherwise = (Text arr off k, Text arr (off+k) (len-k))
673 | i >= len || cnt >= n = i
674 | otherwise = loop (i+d) (cnt+1)
676{-# INLINE splitAt #-}
678-- | /O(n)/ 'span', applied to a predicate @p@ and text @t@, returns a
679-- pair whose first element is the longest prefix (possibly empty) of
680-- @t@ of elements that satisfy @p@, and whose second is the remainder
682span :: (Char -> Bool) -> Text -> (Text, Text)
683span p t@(Text arr off len) = (textP arr off k, textP arr (off+k) (len-k))
685 loop !i | i >= len || not (p c) = i
686 | otherwise = loop (i+d)
687 where (c,d) = iter t i
690-- | /O(n)/ 'break' is like 'span', but the prefix returned is over
691-- elements that fail the predicate @p@.
692break :: (Char -> Bool) -> Text -> (Text, Text)
693break p = span (not . p)
696-- | /O(n)/ Group characters in a string according to a predicate.
697groupBy :: (Char -> Char -> Bool) -> Text -> [Text]
700 loop t@(Text arr off len)
702 | otherwise = text arr off n : loop (text arr (off+n) (len-n))
703 where (c,d) = iter t 0
704 n = d + findAIndexOrEnd (not . p c) (Text arr (off+d) (len-d))
706-- | Returns the /array/ index (in units of 'Word16') at which a
707-- character may be found. This is /not/ the same as the logical
708-- index returned by e.g. 'findIndex'.
709findAIndexOrEnd :: (Char -> Bool) -> Text -> Int
710findAIndexOrEnd q t@(Text _arr _off len) = go 0
711 where go !i | i >= len || q c = i
712 | otherwise = go (i+d)
713 where (c,d) = iter t i
715-- | /O(n)/ Group characters in a string by equality.
716group :: Text -> [Text]
719-- | /O(n)/ Return all initial segments of the given 'Text', shortest
721inits :: Text -> [Text]
722inits t@(Text arr off len) = loop 0
723 where loop i | i >= len = [t]
724 | otherwise = Text arr off i : loop (i + iter_ t i)
726-- | /O(n)/ Return all final segments of the given 'Text', longest
728tails :: Text -> [Text]
729tails t | null t = [empty]
730 | otherwise = t : tails (unsafeTail t)
732-- | /O(n)/ Break a 'Text' into pieces separated by the 'Char'
733-- argument, consuming the delimiter. I.e.
735-- > split '\n' "a\nb\nd\ne" == ["a","b","d","e"]
736-- > split 'a' "aXaXaXa" == ["","X","X","X",""]
737-- > split 'x' "x" == ["",""]
741-- > intercalate (singleton c) . split c == id
742-- > split == splitWith . (==)
744-- As for all splitting functions in this library, this function does
745-- not copy the substrings, it just constructs new 'Text's that are
746-- slices of the original.
747split :: Char -> Text -> [Text]
748split c = splitWith (==c)
751-- | /O(n)/ Splits a 'Text' into components delimited by separators,
752-- where the predicate returns True for a separator element. The
753-- resulting components do not contain the separators. Two adjacent
754-- separators result in an empty component in the output. eg.
756-- > splitWith (=='a') "aabbaca" == ["","","bb","c",""]
757-- > splitWith (=='a') [] == []
758splitWith :: (Char -> Bool) -> Text -> [Text]
760 where loop s | null s = []
761 | otherwise = if null s'
763 else l : loop (unsafeTail s')
764 where (l, s') = break p s
765{-# INLINE splitWith #-}
767-- ----------------------------------------------------------------------------
770-------------------------------------------------------------------------------
771-- ** Searching by equality
773-- | /O(n)/ 'elem' is the 'Text' membership predicate.
774elem :: Char -> Text -> Bool
775elem c t = S.elem c (stream t)
778-------------------------------------------------------------------------------
779-- ** Searching with a predicate
781-- | /O(n)/ The 'find' function takes a predicate and a 'Text',
782-- and returns the first element in matching the predicate, or 'Nothing'
783-- if there is no such element.
784find :: (Char -> Bool) -> Text -> Maybe Char
785find p t = S.find p (stream t)
788-- | /O(n)/ The 'partition' function takes a predicate and a 'Text',
789-- and returns the pair of 'Text's with elements which do and do not
790-- satisfy the predicate, respectively; i.e.
792-- > partition p t == (filter p t, filter (not . p) t)
793partition :: (Char -> Bool) -> Text -> (Text, Text)
794partition p t = (filter p t, filter (not . p) t)
795{-# INLINE partition #-}
797-- | /O(n)/ Break a string on a substring, returning a pair of the
798-- part of the string prior to the match, and the rest of the string.
800-- The following relationship holds:
802-- > break (==c) l == breakSubstring (singleton c) l
804-- For example, to tokenise a string, dropping delimiters:
806-- > tokenise x y = h : if null t then [] else tokenise x (drop (length x) t)
807-- > where (h,t) = breakSubstring x y
809-- To skip to the first occurence of a string:
811-- > snd (breakSubstring x y)
813-- To take the parts of a string before a delimiter:
815-- > fst (breakSubstring x y)
817breakSubstring :: Text -- ^ String to search for
818 -> Text -- ^ String to search in
819 -> (Text,Text) -- ^ Head and tail of string broken at substring
821breakSubstring pat src = search 0 src
824 | null s = (src,empty) -- not found
825 | pat `isPrefixOf` s = (take n src,s)
826 | otherwise = search (n+1) (unsafeTail s)
827{-# INLINE breakSubstring #-}
829-- | /O(n)/ 'filter', applied to a predicate and a 'Text',
830-- returns a 'Text' containing those characters that satisfy the
832filter :: (Char -> Bool) -> Text -> Text
833filter p t = unstream (S.filter p (stream t))
837-------------------------------------------------------------------------------
838-- ** Indexing 'Text's
840-- | /O(1)/ 'Text' index (subscript) operator, starting from 0.
841index :: Text -> Int -> Char
842index t n = S.index (stream t) n
845-- | /O(n)/ The 'findIndex' function takes a predicate and a 'Text'
846-- and returns the index of the first element in the 'Text' satisfying
847-- the predicate. This function is subject to fusion.
848findIndex :: (Char -> Bool) -> Text -> Maybe Int
849findIndex p t = S.findIndex p (stream t)
850{-# INLINE findIndex #-}
852-- | The 'findIndices' function extends 'findIndex', by returning the
853-- indices of all elements satisfying the predicate, in ascending
854-- order. This function is subject to fusion.
855findIndices :: (Char -> Bool) -> Text -> [Int]
856findIndices p t = S.findIndices p (stream t)
857{-# INLINE findIndices #-}
859-- | /O(n)/ The 'elemIndex' function returns the index of the first
860-- element in the given 'Text' which is equal to the query element, or
861-- 'Nothing' if there is no such element. This function is subject to
863elemIndex :: Char -> Text -> Maybe Int
864elemIndex c t = S.elemIndex c (stream t)
865{-# INLINE elemIndex #-}
867-- | /O(n)/ The 'elemIndices' function returns the index of every
868-- element in the given 'Text' which is equal to the query
869-- element. This function is subject to fusion.
870elemIndices :: Char -> Text -> [Int]
871elemIndices c t = S.elemIndices c (stream t)
872{-# INLINE elemIndices #-}
874-- | /O(n)/ The 'count' function returns the number of times the query
875-- element appears in the given 'Text'. This function is subject to
877count :: Char -> Text -> Int
878count c t = S.count c (stream t)
881-------------------------------------------------------------------------------
884-- | /O(n)/ 'zipWith' generalises 'zip' by zipping with the function
885-- given as the first argument, instead of a tupling function.
886zipWith :: (Char -> Char -> Char) -> Text -> Text -> Text
887zipWith f t1 t2 = unstream (S.zipWith f (stream t1) (stream t2))
889-- | /O(n)/ Breaks a 'Text' up into a list of words, delimited by 'Char's
890-- representing white space.
891words :: Text -> [Text]
892words t@(Text arr off len) = loop 0 0
895 | n >= len = if start == n
897 else [Text arr (start+off) (n-start)]
900 then loop (start+1) (start+1)
901 else Text arr (start+off) (n-start) : loop (n+d) (n+d)
902 | otherwise = loop start (n+d)
903 where (c,d) = iter t n
906-- | /O(n)/ Breaks a 'Text' up into a list of 'Text's at
907-- newline 'Char's. The resulting strings do not contain newlines.
908lines :: Text -> [Text]
909lines ps | null ps = []
910 | otherwise = h : if null t
912 else lines (unsafeTail t)
913 where (h,t) = span (/= '\n') ps
916-- | /O(n)/ Portably breaks a 'Text' up into a list of 'Text's at line
919-- A line boundary is considered to be either a line feed, a carriage
920-- return immediately followed by a line feed, or a carriage return.
921-- This accounts for both Unix and Windows line ending conventions,
922-- and for the old convention used on Mac OS 9 and earlier.
924lines' :: Text -> [Text]
925lines' ps | null ps = []
926 | otherwise = h : case uncons t of
929 | c == '\n' -> lines t'
930 | c == '\r' -> case uncons t' of
931 Just ('\n',t'') -> lines t''
933 where (h,t) = span notEOL ps
934 notEOL c = c /= '\n' && c /= '\r'
938-- | /O(n)/ Joins lines, after appending a terminating newline to
940unlines :: [Text] -> Text
941unlines = concat . L.map (`snoc` '\n')
942{-# INLINE unlines #-}
944-- | /O(n)/ Joins words using single space characters.
945unwords :: [Text] -> Text
946unwords = intercalate (singleton ' ')
947{-# INLINE unwords #-}
949-- | /O(n)/ The 'isPrefixOf' function takes two 'Text's and returns
950-- 'True' iff the first is a prefix of the second. This function is
952isPrefixOf :: Text -> Text -> Bool
953isPrefixOf a@(Text _ _ alen) b@(Text _ _ blen) =
954 alen <= blen && S.isPrefixOf (stream a) (stream b)
955{-# INLINE [1] isPrefixOf #-}
958"TEXT isPrefixOf -> fused" [~1] forall s t.
959 isPrefixOf s t = S.isPrefixOf (stream s) (stream t)
960"TEXT isPrefixOf -> unfused" [1] forall s t.
961 S.isPrefixOf (stream s) (stream t) = isPrefixOf s t
964-- | /O(n)/ The 'isSuffixOf' function takes two 'Text's and returns
965-- 'True' iff the first is a suffix of the second.
966isSuffixOf :: Text -> Text -> Bool
967isSuffixOf a@(Text _aarr _aoff alen) b@(Text barr boff blen) =
969 where d = blen - alen
971 | otherwise = Text barr (boff+d) alen
972{-# INLINE isSuffixOf #-}
974-- | /O(n)/ The 'isInfixOf' function takes two 'Text's and returns
975-- 'True' iff the first is contained, wholly and intact, anywhere
977isInfixOf :: Text -> Text -> Bool
978isInfixOf needle haystack = L.any (isPrefixOf needle) (tails haystack)
979{-# INLINE isInfixOf #-}
981emptyError :: String -> a
982emptyError fun = P.error ("Data.Text." ++ fun ++ ": empty input")
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list