on text-jsstring help sign in
text/Data/Text.hs
1925 lines 66 kB history raw
1{-# LANGUAGE BangPatterns, CPP, MagicHash, Rank2Types, UnboxedTuples #-}
2{-# OPTIONS_GHC -fno-warn-orphans #-}
3#if __GLASGOW_HASKELL__ >= 702
4{-# LANGUAGE Trustworthy #-}
5#endif
6#if __GLASGOW_HASKELL__ >= 708
7{-# LANGUAGE TypeFamilies #-}
8#endif
9{-# LANGUAGE ForeignFunctionInterface, JavaScriptFFI, UnliftedFFITypes #-}
10-- |
11-- Module : Data.Text
12-- Copyright : (c) 2009, 2010, 2011, 2012 Bryan O'Sullivan,
13-- (c) 2009 Duncan Coutts,
14-- (c) 2008, 2009 Tom Harper
15--
16-- License : BSD-style
17-- Maintainer : bos@serpentine.com
18-- Stability : experimental
19-- Portability : GHC
20--
21-- A time and space-efficient implementation of Unicode text.
22-- Suitable for performance critical use, both in terms of large data
23-- quantities and high speed.
24--
25-- /Note/: Read below the synopsis for important notes on the use of
26-- this module.
27--
28-- This module is intended to be imported @qualified@, to avoid name
29-- clashes with "Prelude" functions, e.g.
30--
31-- > import qualified Data.Text as T
32--
33-- To use an extended and very rich family of functions for working
34-- with Unicode text (including normalization, regular expressions,
35-- non-standard encodings, text breaking, and locales), see
36-- <http://hackage.haskell.org/package/text-icu the text-icu package >.
38module Data.Text
39 (
40 -- * Strict vs lazy types
41 -- $strict
43 -- * Acceptable data
44 -- $replacement
46 -- * Fusion
47 -- $fusion
49 -- * Types
50 Text
52 -- * Creation and elimination
53 , pack
54 , unpack
55 , singleton
56 , empty
58 -- * Basic interface
59 , cons
60 , snoc
61 , append
62 , uncons
63 , head
64 , last
65 , tail
66 , init
67 , null
68 , length
69 , compareLength
71 -- * Transformations
72 , map
73 , intercalate
74 , intersperse
75 , transpose
76 , reverse
77 , replace
79 -- ** Case conversion
80 -- $case
81 , toCaseFold
82 , toLower
83 , toUpper
84 , toTitle
86 -- ** Justification
87 , justifyLeft
88 , justifyRight
89 , center
91 -- * Folds
92 , foldl
93 , foldl'
94 , foldl1
95 , foldl1'
96 , foldr
97 , foldr1
99 -- ** Special folds
100 , concat
101 , concatMap
102 , any
103 , all
104 , maximum
105 , minimum
107 -- * Construction
109 -- ** Scans
110 , scanl
111 , scanl1
112 , scanr
113 , scanr1
115 -- ** Accumulating maps
116 , mapAccumL
117 , mapAccumR
119 -- ** Generation and unfolding
120 , replicate
121 , unfoldr
122 , unfoldrN
124 -- * Substrings
126 -- ** Breaking strings
127 , take
128 , takeEnd
129 , drop
130 , dropEnd
131 , takeWhile
132 , takeWhileEnd
133 , dropWhile
134 , dropWhileEnd
135 , dropAround
136 , strip
137 , stripStart
138 , stripEnd
139 , splitAt
140 , breakOn
141 , breakOnEnd
142 , break
143 , span
144 , group
145 , groupBy
146 , inits
147 , tails
149 -- ** Breaking into many substrings
150 -- $split
151 , splitOn
152 , split
153 , chunksOf
155 -- ** Breaking into lines and words
156 , lines
157 --, lines'
158 , words
159 , unlines
160 , unwords
162 -- * Predicates
163 , isPrefixOf
164 , isSuffixOf
165 , isInfixOf
167 -- ** View patterns
168 , stripPrefix
169 , stripSuffix
170 , commonPrefixes
172 -- * Searching
173 , filter
174 , breakOnAll
175 , find
176 , partition
178 -- , findSubstring
180 -- * Indexing
181 -- $index
182 , index
183 , findIndex
184 , count
186 -- * Zipping
187 , zip
188 , zipWith
190 -- -* Ordered text
191 -- , sort
193 -- * Low level operations
194 , copy
195 , unpackCString#
196 ) where
198import Prelude (Char, Bool(..), Int, Maybe(..), String,
199 Eq(..), Ord(..), Ordering(..), (++),
200 Read(..),
201 (&&), (||), (+), (-), (.), ($), ($!), (>>),
202 not, return, otherwise, quot)
203#if defined(HAVE_DEEPSEQ)
204import Control.DeepSeq (NFData(rnf))
205#endif
206#if defined(ASSERTS)
207import Control.Exception (assert)
208#endif
209import Data.Char (isSpace)
210import Data.Data (Data(gfoldl, toConstr, gunfold, dataTypeOf), constrIndex,
211 Constr, mkConstr, DataType, mkDataType, Fixity(Prefix))
212import Control.Monad (foldM)
213import Control.Monad.ST (ST)
214import qualified Data.Text.Array as A
215import qualified Data.List as L
216import Data.Binary (Binary(get, put))
217import Data.Monoid (Monoid(..))
218#if MIN_VERSION_base(4,9,0)
219import Data.Semigroup (Semigroup(..))
220#endif
221import Data.String (IsString(..))
222import qualified Data.Text.Internal.Fusion as S
223import qualified Data.Text.Internal.Fusion.Common as S
224import Data.Text.Encoding (decodeUtf8', encodeUtf8)
225import Data.Text.Internal.Fusion (stream, reverseStream, unstream)
226-- import Data.Text.Internal.Private (span_)
227import Data.Text.Internal (Text(..), empty, empty_, firstf, mul, safe, text)
228-- import Data.Text.Show (singleton, unpack, unpackCString#)
229import qualified Prelude as P
230import Data.Text.Unsafe (Iter(..), iter, iter_, lengthWord16, reverseIter,
231 reverseIter_, unsafeHead, unsafeTail)
232import Data.Text.Internal.Unsafe.Char (unsafeChr)
233import qualified Data.Text.Internal.Functions as F
234import qualified Data.Text.Internal.Encoding.Utf16 as U16
235-- import Data.Text.Internal.Search (indices)
236#if defined(__HADDOCK__)
237import Data.ByteString (ByteString)
238import qualified Data.Text.Lazy as L
239import Data.Int (Int64)
240#endif
241import GHC.Base (eqInt, neInt, gtInt, geInt, ltInt, leInt)
242#if __GLASGOW_HASKELL__ >= 708
243import qualified GHC.Exts as Exts
244#endif
245#if MIN_VERSION_base(4,7,0)
246import Text.Printf (PrintfArg, formatArg, formatString)
247#endif
249-- GHCJS ------------------------------------------------------------
250import Data.JSString.Internal.Type (JSString (..))
251import qualified Data.JSString as JSS
252import qualified Data.JSString.Internal.Fusion as SJS
253import qualified Data.JSString.Internal.Fusion.Common as SJS
254import Data.Coerce
255import GHC.Base (build)
256import qualified GHC.CString as GHC
257import GHC.Exts (Addr#, ByteArray#)
258import GHCJS.Prim (JSVal (..))
260unpack :: Text -> String
261unpack = coerce JSS.unpack
262{-# INLINE [1] unpack #-}
264singleton :: Char -> Text
265singleton = coerce JSS.singleton
266{-# INLINE [1] singleton #-}
268{-# RULES
269"JSSTRING singleton -> fused" [~1] forall a.
270 singleton a = unstream (S.singleton (safe a))
271"JSSTRING singleton -> unfused" [1] forall a.
272 unstream (S.singleton (safe a)) = singleton a
273 #-}
275foreign import javascript unsafe "$r = $1;" addrToByteArray :: Addr# -> ByteArray#
277{-# RULES "inlineJSString" forall s. pack (GHC.Base.build (GHC.unpackFoldrCString# s)) = Text (JSString (JSVal (addrToByteArray s))) #-}
279-- | /O(n)/ Convert a literal string into a JSString. Subject to fusion.
280unpackCString# :: Addr# -> Text
281unpackCString# addr# = Text $ SJS.unstream (SJS.streamCString# addr#)
282{-# NOINLINE unpackCString# #-}
284{-# RULES "TEXT literal" forall a.
285 unstream (S.map safe (S.streamList (GHC.unpackCString# a)))
286 = unpackCString# a #-}
288{-# RULES "TEXT literal UTF8" [1] forall a.
289 unstream (S.map safe (S.streamList (GHC.unpackCStringUtf8# a)))
290 = unpackCString# a #-}
292{-# RULES "TEXT empty literal" [1]
293 unstream (S.map safe (S.streamList []))
294 = empty_ #-}
296{-# RULES "TEXT singleton literal" [1] forall a.
297 unstream (S.map safe (S.streamList [a]))
298 = singleton a #-}
300---------------------------------------------------------------------
302-- $strict
303--
304-- This package provides both strict and lazy 'Text' types. The
305-- strict type is provided by the "Data.Text" module, while the lazy
306-- type is provided by the "Data.Text.Lazy" module. Internally, the
307-- lazy @Text@ type consists of a list of strict chunks.
308--
309-- The strict 'Text' type requires that an entire string fit into
310-- memory at once. The lazy 'Data.Text.Lazy.Text' type is capable of
311-- streaming strings that are larger than memory using a small memory
312-- footprint. In many cases, the overhead of chunked streaming makes
313-- the lazy 'Data.Text.Lazy.Text' type slower than its strict
314-- counterpart, but this is not always the case. Sometimes, the time
315-- complexity of a function in one module may be different from the
316-- other, due to their differing internal structures.
317--
318-- Each module provides an almost identical API, with the main
319-- difference being that the strict module uses 'Int' values for
320-- lengths and counts, while the lazy module uses 'Data.Int.Int64'
321-- lengths.
323-- $replacement
324--
325-- A 'Text' value is a sequence of Unicode scalar values, as defined
326-- in
327-- <http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#page=35 §3.9, definition D76 of the Unicode 5.2 standard >.
328-- As such, a 'Text' cannot contain values in the range U+D800 to
329-- U+DFFF inclusive. Haskell implementations admit all Unicode code
330-- points
331-- (<http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#page=13 §3.4, definition D10 >)
332-- as 'Char' values, including code points from this invalid range.
333-- This means that there are some 'Char' values that are not valid
334-- Unicode scalar values, and the functions in this module must handle
335-- those cases.
336--
337-- Within this module, many functions construct a 'Text' from one or
338-- more 'Char' values. Those functions will substitute 'Char' values
339-- that are not valid Unicode scalar values with the replacement
340-- character \"&#xfffd;\" (U+FFFD). Functions that perform this
341-- inspection and replacement are documented with the phrase
342-- \"Performs replacement on invalid scalar values\".
343--
344-- (One reason for this policy of replacement is that internally, a
345-- 'Text' value is represented as packed UTF-16 data. Values in the
346-- range U+D800 through U+DFFF are used by UTF-16 to denote surrogate
347-- code points, and so cannot be represented. The functions replace
348-- invalid scalar values, instead of dropping them, as a security
349-- measure. For details, see
350-- <http://unicode.org/reports/tr36/#Deletion_of_Noncharacters Unicode Technical Report 36, §3.5 >.)
352-- $fusion
353--
354-- Most of the functions in this module are subject to /fusion/,
355-- meaning that a pipeline of such functions will usually allocate at
356-- most one 'Text' value.
357--
358-- As an example, consider the following pipeline:
359--
360-- > import Data.Text as T
361-- > import Data.Text.Encoding as E
362-- > import Data.ByteString (ByteString)
363-- >
364-- > countChars :: ByteString -> Int
365-- > countChars = T.length . T.toUpper . E.decodeUtf8
366--
367-- From the type signatures involved, this looks like it should
368-- allocate one 'Data.ByteString.ByteString' value, and two 'Text'
369-- values. However, when a module is compiled with optimisation
370-- enabled under GHC, the two intermediate 'Text' values will be
371-- optimised away, and the function will be compiled down to a single
372-- loop over the source 'Data.ByteString.ByteString'.
373--
374-- Functions that can be fused by the compiler are documented with the
375-- phrase \"Subject to fusion\".
377-- instance Eq Text where
378-- Text arrA offA lenA == Text arrB offB lenB
379-- | lenA == lenB = A.equal arrA offA arrB offB lenA
380-- | otherwise = False
381-- {-# INLINE (==) #-}
382instance Eq Text where
383 Text x == Text y = x == y
385-- instance Ord Text where
386-- compare = compareText
388instance Ord Text where
389 compare (Text x) (Text y) = compare x y
391instance Read Text where
392 readsPrec p str = [(pack x,y) | (x,y) <- readsPrec p str]
394#if MIN_VERSION_base(4,9,0)
395-- Semigroup orphan instances for older GHCs are provided by
396-- 'semigroups` package
398instance Semigroup Text where
399 (<>) = append
400#endif
402instance Monoid Text where
403 mempty = empty
404#if MIN_VERSION_base(4,9,0)
405 mappend = (<>) -- future-proof definition
406#else
407 mappend = append
408#endif
409 mconcat = concat
411instance IsString Text where
412 fromString = pack
414#if __GLASGOW_HASKELL__ >= 708
415instance Exts.IsList Text where
416 type Item Text = Char
417 fromList = pack
418 toList = unpack
419#endif
421#if defined(HAVE_DEEPSEQ)
422instance NFData Text where rnf !_ = ()
423#endif
425instance Binary Text where
426 put t = put (encodeUtf8 t)
427 get = do
428 bs <- get
429 case decodeUtf8' bs of
430 P.Left exn -> P.fail (P.show exn)
431 P.Right a -> P.return a
433-- | This instance preserves data abstraction at the cost of inefficiency.
434-- We omit reflection services for the sake of data abstraction.
435--
436-- This instance was created by copying the updated behavior of
437-- @"Data.Set".@'Data.Set.Set' and @"Data.Map".@'Data.Map.Map'. If you
438-- feel a mistake has been made, please feel free to submit
439-- improvements.
440--
441-- The original discussion is archived here:
442-- <http://groups.google.com/group/haskell-cafe/browse_thread/thread/b5bbb1b28a7e525d/0639d46852575b93 could we get a Data instance for Data.Text.Text? >
443--
444-- The followup discussion that changed the behavior of 'Data.Set.Set'
445-- and 'Data.Map.Map' is archived here:
446-- <http://markmail.org/message/trovdc6zkphyi3cr#query:+page:1+mid:a46der3iacwjcf6n+state:results Proposal: Allow gunfold for Data.Map, ... >
448instance Data Text where
449 gfoldl f z txt = z pack `f` (unpack txt)
450 toConstr _ = packConstr
451 gunfold k z c = case constrIndex c of
452 1 -> k (z pack)
453 _ -> P.error "gunfold"
454 dataTypeOf _ = textDataType
456#if MIN_VERSION_base(4,7,0)
457-- | Only defined for @base-4.7.0.0@ and later
458instance PrintfArg Text where
459 formatArg t = formatString $ unpack t
460#endif
462packConstr :: Constr
463packConstr = mkConstr textDataType "pack" [] Prefix
465textDataType :: DataType
466textDataType = mkDataType "Data.Text.Text" [packConstr]
468-- -- | /O(n)/ Compare two 'Text' values lexicographically.
469-- compareText :: Text -> Text -> Ordering
470-- compareText ta@(Text _arrA _offA lenA) tb@(Text _arrB _offB lenB)
471-- | lenA == 0 && lenB == 0 = EQ
472-- | otherwise = go 0 0
473-- where
474-- go !i !j
475-- | i >= lenA || j >= lenB = compare lenA lenB
476-- | a < b = LT
477-- | a > b = GT
478-- | otherwise = go (i+di) (j+dj)
479-- where Iter a di = iter ta i
480-- Iter b dj = iter tb j
482-- -----------------------------------------------------------------------------
483-- * Conversion to/from 'Text'
485-- | /O(n)/ Convert a 'String' into a 'Text'. Subject to
486-- fusion. Performs replacement on invalid scalar values.
487pack :: String -> Text
488pack = coerce JSS.pack
489-- pack = unstream . S.map safe . S.streamList
490{-# INLINE [1] pack #-}
492-- -----------------------------------------------------------------------------
493-- * Basic functions
495-- | /O(n)/ Adds a character to the front of a 'Text'. This function
496-- is more costly than its 'List' counterpart because it requires
497-- copying a new array. Subject to fusion. Performs replacement on
498-- invalid scalar values.
499cons :: Char -> Text -> Text
500cons = coerce JSS.cons
501-- cons c t = unstream (S.cons (safe c) (stream t))
502{-# INLINE cons #-}
504infixr 5 `cons`
506-- | /O(n)/ Adds a character to the end of a 'Text'. This copies the
507-- entire array in the process, unless fused. Subject to fusion.
508-- Performs replacement on invalid scalar values.
509snoc :: Text -> Char -> Text
510snoc = coerce JSS.snoc
511-- snoc t c = unstream (S.snoc (stream t) (safe c))
512{-# INLINE snoc #-}
514-- | /O(n)/ Appends one 'Text' to the other by copying both of them
515-- into a new 'Text'. Subject to fusion.
516append :: Text -> Text -> Text
517append = coerce JSS.append
518-- append a@(Text arr1 off1 len1) b@(Text arr2 off2 len2)
519-- | len1 == 0 = b
520-- | len2 == 0 = a
521-- | len > 0 = Text (A.run x) 0 len
522-- | otherwise = overflowError "append"
523-- where
524-- len = len1+len2
525-- x :: ST s (A.MArray s)
526-- x = do
527-- arr <- A.new len
528-- A.copyI arr 0 arr1 off1 len1
529-- A.copyI arr len1 arr2 off2 len
530-- return arr
531{-# NOINLINE append #-}
533{-# RULES
534"TEXT append -> fused" [~1] forall t1 t2.
535 append t1 t2 = unstream (S.append (stream t1) (stream t2))
536"TEXT append -> unfused" [1] forall t1 t2.
537 unstream (S.append (stream t1) (stream t2)) = append t1 t2
538 #-}
540-- | /O(1)/ Returns the first character of a 'Text', which must be
541-- non-empty. Subject to fusion.
542head :: Text -> Char
543head = coerce JSS.head
544-- head t = S.head (stream t)
545{-# INLINE head #-}
547-- | /O(1)/ Returns the first character and rest of a 'Text', or
548-- 'Nothing' if empty. Subject to fusion.
549uncons :: Text -> Maybe (Char, Text)
550uncons = coerce JSS.uncons
551-- uncons t@(Text arr off len)
552-- | len <= 0 = Nothing
553-- | otherwise = Just $ let !(Iter c d) = iter t 0
554-- in (c, text arr (off+d) (len-d))
555{-# INLINE [1] uncons #-}
557-- | Lifted from Control.Arrow and specialized.
558second :: (b -> c) -> (a,b) -> (a,c)
559second f (a, b) = (a, f b)
561-- | /O(1)/ Returns the last character of a 'Text', which must be
562-- non-empty. Subject to fusion.
563last :: Text -> Char
564last = coerce JSS.last
565-- last (Text arr off len)
566-- | len <= 0 = emptyError "last"
567-- | n < 0xDC00 || n > 0xDFFF = unsafeChr n
568-- | otherwise = U16.chr2 n0 n
569-- where n = A.unsafeIndex arr (off+len-1)
570-- n0 = A.unsafeIndex arr (off+len-2)
571{-# INLINE [1] last #-}
573{-# RULES
574"TEXT last -> fused" [~1] forall t.
575 last t = S.last (stream t)
576"TEXT last -> unfused" [1] forall t.
577 S.last (stream t) = last t
578 #-}
580-- | /O(1)/ Returns all characters after the head of a 'Text', which
581-- must be non-empty. Subject to fusion.
582tail :: Text -> Text
583tail = coerce JSS.tail
584-- tail t@(Text arr off len)
585-- | len <= 0 = emptyError "tail"
586-- | otherwise = text arr (off+d) (len-d)
587-- where d = iter_ t 0
588{-# INLINE [1] tail #-}
590{-# RULES
591"TEXT tail -> fused" [~1] forall t.
592 tail t = unstream (S.tail (stream t))
593"TEXT tail -> unfused" [1] forall t.
594 unstream (S.tail (stream t)) = tail t
595 #-}
597-- | /O(1)/ Returns all but the last character of a 'Text', which must
598-- be non-empty. Subject to fusion.
599init :: Text -> Text
600init = coerce JSS.init
601-- init (Text arr off len) | len <= 0 = emptyError "init"
602-- | n >= 0xDC00 && n <= 0xDFFF = text arr off (len-2)
603-- | otherwise = text arr off (len-1)
604-- where
605-- n = A.unsafeIndex arr (off+len-1)
606{-# INLINE [1] init #-}
608{-# RULES
609"TEXT init -> fused" [~1] forall t.
610 init t = unstream (S.init (stream t))
611"TEXT init -> unfused" [1] forall t.
612 unstream (S.init (stream t)) = init t
613 #-}
615-- | /O(1)/ Tests whether a 'Text' is empty or not. Subject to
616-- fusion.
617null :: Text -> Bool
618null = coerce JSS.null
619-- null (Text _arr _off len) =
620-- #if defined(ASSERTS)
621-- assert (len >= 0) $
622-- #endif
623-- len <= 0
624{-# INLINE [1] null #-}
626{-# RULES
627"TEXT null -> fused" [~1] forall t.
628 null t = S.null (stream t)
629"TEXT null -> unfused" [1] forall t.
630 S.null (stream t) = null t
631 #-}
633-- | /O(1)/ Tests whether a 'Text' contains exactly one character.
634-- Subject to fusion.
635-- isSingleton :: Text -> Bool
636-- isSingleton = S.isSingleton . stream
637-- {-# INLINE isSingleton #-}
639-- | /O(n)/ Returns the number of characters in a 'Text'.
640-- Subject to fusion.
641length :: Text -> Int
642length = coerce JSS.length
643-- length t = S.length (stream t)
644{-# INLINE [0] length #-}
645-- length needs to be phased after the compareN/length rules otherwise
646-- it may inline before the rules have an opportunity to fire.
648-- | /O(n)/ Compare the count of characters in a 'Text' to a number.
649-- Subject to fusion.
650--
651-- This function gives the same answer as comparing against the result
652-- of 'length', but can short circuit if the count of characters is
653-- greater than the number, and hence be more efficient.
654compareLength :: Text -> Int -> Ordering
655compareLength t n = S.compareLengthI (stream t) n
656{-# INLINE [1] compareLength #-}
658{-# RULES
659"TEXT compareN/length -> compareLength" [~1] forall t n.
660 compare (length t) n = compareLength t n
661 #-}
663{-# RULES
664"TEXT ==N/length -> compareLength/==EQ" [~1] forall t n.
665 eqInt (length t) n = compareLength t n == EQ
666 #-}
668{-# RULES
669"TEXT /=N/length -> compareLength//=EQ" [~1] forall t n.
670 neInt (length t) n = compareLength t n /= EQ
671 #-}
673{-# RULES
674"TEXT <N/length -> compareLength/==LT" [~1] forall t n.
675 ltInt (length t) n = compareLength t n == LT
676 #-}
678{-# RULES
679"TEXT <=N/length -> compareLength//=GT" [~1] forall t n.
680 leInt (length t) n = compareLength t n /= GT
681 #-}
683{-# RULES
684"TEXT >N/length -> compareLength/==GT" [~1] forall t n.
685 gtInt (length t) n = compareLength t n == GT
686 #-}
688{-# RULES
689"TEXT >=N/length -> compareLength//=LT" [~1] forall t n.
690 geInt (length t) n = compareLength t n /= LT
691 #-}
693-- -----------------------------------------------------------------------------
694-- * Transformations
695-- | /O(n)/ 'map' @f@ @t@ is the 'Text' obtained by applying @f@ to
696-- each element of @t@. Subject to fusion. Performs replacement on
697-- invalid scalar values.
698map :: (Char -> Char) -> Text -> Text
699map = coerce JSS.map
700-- map f t = unstream (S.map (safe . f) (stream t))
701{-# INLINE [1] map #-}
703-- | /O(n)/ The 'intercalate' function takes a 'Text' and a list of
704-- 'Text's and concatenates the list after interspersing the first
705-- argument between each element of the list.
706intercalate :: Text -> [Text] -> Text
707intercalate = coerce JSS.intercalate
708-- intercalate t = concat . (F.intersperse t)
709{-# INLINE intercalate #-}
711-- | /O(n)/ The 'intersperse' function takes a character and places it
712-- between the characters of a 'Text'. Subject to fusion. Performs
713-- replacement on invalid scalar values.
714intersperse :: Char -> Text -> Text
715intersperse = coerce JSS.intersperse
716-- intersperse c t = unstream (S.intersperse (safe c) (stream t))
717{-# INLINE intersperse #-}
719-- | /O(n)/ Reverse the characters of a string. Subject to fusion.
720reverse :: Text -> Text
721reverse = coerce JSS.reverse
722-- reverse t = S.reverse (stream t)
723{-# INLINE reverse #-}
725-- | /O(m+n)/ Replace every non-overlapping occurrence of @needle@ in
726-- @haystack@ with @replacement@.
727--
728-- This function behaves as though it was defined as follows:
729--
730-- @
731-- replace needle replacement haystack =
732-- 'intercalate' replacement ('splitOn' needle haystack)
733-- @
734--
735-- As this suggests, each occurrence is replaced exactly once. So if
736-- @needle@ occurs in @replacement@, that occurrence will /not/ itself
737-- be replaced recursively:
738--
739-- > replace "oo" "foo" "oo" == "foo"
740--
741-- In cases where several instances of @needle@ overlap, only the
742-- first one will be replaced:
743--
744-- > replace "ofo" "bar" "ofofo" == "barfo"
745--
746-- In (unlikely) bad cases, this function's time complexity degrades
747-- towards /O(n*m)/.
748replace :: Text
749 -- ^ @needle@ to search for. If this string is empty, an
750 -- error will occur.
751 -> Text
752 -- ^ @replacement@ to replace @needle@ with.
753 -> Text
754 -- ^ @haystack@ in which to search.
755 -> Text
756replace = coerce JSS.replace
757-- replace needle@(Text _ _ neeLen)
758-- (Text repArr repOff repLen)
759-- haystack@(Text hayArr hayOff hayLen)
760-- | neeLen == 0 = emptyError "replace"
761-- | L.null ixs = haystack
762-- | len > 0 = Text (A.run x) 0 len
763-- | otherwise = empty
764-- where
765-- ixs = indices needle haystack
766-- len = hayLen - (neeLen - repLen) `mul` L.length ixs
767-- x :: ST s (A.MArray s)
768-- x = do
769-- marr <- A.new len
770-- let loop (i:is) o d = do
771-- let d0 = d + i - o
772-- d1 = d0 + repLen
773-- A.copyI marr d hayArr (hayOff+o) d0
774-- A.copyI marr d0 repArr repOff d1
775-- loop is (i + neeLen) d1
776-- loop [] o d = A.copyI marr d hayArr (hayOff+o) len
777-- loop ixs 0 0
778-- return marr
780-- ----------------------------------------------------------------------------
781-- ** Case conversions (folds)
783-- $case
784--
785-- When case converting 'Text' values, do not use combinators like
786-- @map toUpper@ to case convert each character of a string
787-- individually, as this gives incorrect results according to the
788-- rules of some writing systems. The whole-string case conversion
789-- functions from this module, such as @toUpper@, obey the correct
790-- case conversion rules. As a result, these functions may map one
791-- input character to two or three output characters. For examples,
792-- see the documentation of each function.
793--
794-- /Note/: In some languages, case conversion is a locale- and
795-- context-dependent operation. The case conversion functions in this
796-- module are /not/ locale sensitive. Programs that require locale
797-- sensitivity should use appropriate versions of the
798-- <http://hackage.haskell.org/package/text-icu-0.6.3.7/docs/Data-Text-ICU.html#g:4 case mapping functions from the text-icu package >.
800-- | /O(n)/ Convert a string to folded case. Subject to fusion.
801--
802-- This function is mainly useful for performing caseless (also known
803-- as case insensitive) string comparisons.
804--
805-- A string @x@ is a caseless match for a string @y@ if and only if:
806--
807-- @toCaseFold x == toCaseFold y@
808--
809-- The result string may be longer than the input string, and may
810-- differ from applying 'toLower' to the input string. For instance,
811-- the Armenian small ligature \"&#xfb13;\" (men now, U+FB13) is case
812-- folded to the sequence \"&#x574;\" (men, U+0574) followed by
813-- \"&#x576;\" (now, U+0576), while the Greek \"&#xb5;\" (micro sign,
814-- U+00B5) is case folded to \"&#x3bc;\" (small letter mu, U+03BC)
815-- instead of itself.
816toCaseFold :: Text -> Text
817-- toCaseFold t = unstream (S.toCaseFold (stream t))
818toCaseFold = coerce JSS.toCaseFold
819{-# INLINE toCaseFold #-}
821-- | /O(n)/ Convert a string to lower case, using simple case
822-- conversion. Subject to fusion.
823--
824-- The result string may be longer than the input string. For
825-- instance, \"&#x130;\" (Latin capital letter I with dot above,
826-- U+0130) maps to the sequence \"i\" (Latin small letter i, U+0069)
827-- followed by \" &#x307;\" (combining dot above, U+0307).
828toLower :: Text -> Text
829-- toLower t = unstream (S.toLower (stream t))
830toLower = coerce JSS.toLower
831{-# INLINE toLower #-}
833-- | /O(n)/ Convert a string to upper case, using simple case
834-- conversion. Subject to fusion.
835--
836-- The result string may be longer than the input string. For
837-- instance, the German \"&#xdf;\" (eszett, U+00DF) maps to the
838-- two-letter sequence \"SS\".
839toUpper :: Text -> Text
840-- toUpper t = unstream (S.toUpper (stream t))
841toUpper = coerce JSS.toUpper
842{-# INLINE toUpper #-}
844-- | /O(n)/ Convert a string to title case, using simple case
845-- conversion. Subject to fusion.
846--
847-- The first letter of the input is converted to title case, as is
848-- every subsequent letter that immediately follows a non-letter.
849-- Every letter that immediately follows another letter is converted
850-- to lower case.
851--
852-- The result string may be longer than the input string. For example,
853-- the Latin small ligature &#xfb02; (U+FB02) is converted to the
854-- sequence Latin capital letter F (U+0046) followed by Latin small
855-- letter l (U+006C).
856--
857-- /Note/: this function does not take language or culture specific
858-- rules into account. For instance, in English, different style
859-- guides disagree on whether the book name \"The Hill of the Red
860-- Fox\" is correctly title cased&#x2014;but this function will
861-- capitalize /every/ word.
862toTitle :: Text -> Text
863toTitle = coerce JSS.toTitle
864-- toTitle t = unstream (S.toTitle (stream t))
865{-# INLINE toTitle #-}
867-- | /O(n)/ Left-justify a string to the given length, using the
868-- specified fill character on the right. Subject to fusion.
869-- Performs replacement on invalid scalar values.
870--
871-- Examples:
872--
873-- > justifyLeft 7 'x' "foo" == "fooxxxx"
874-- > justifyLeft 3 'x' "foobar" == "foobar"
875justifyLeft :: Int -> Char -> Text -> Text
876justifyLeft = coerce JSS.justifyLeft
877-- justifyLeft k c t
878-- | len >= k = t
879-- | otherwise = t `append` replicateChar (k-len) c
880-- where len = length t
881{-# INLINE [1] justifyLeft #-}
883{-# RULES
884"TEXT justifyLeft -> fused" [~1] forall k c t.
885 justifyLeft k c t = unstream (S.justifyLeftI k c (stream t))
886"TEXT justifyLeft -> unfused" [1] forall k c t.
887 unstream (S.justifyLeftI k c (stream t)) = justifyLeft k c t
888 #-}
890-- | /O(n)/ Right-justify a string to the given length, using the
891-- specified fill character on the left. Performs replacement on
892-- invalid scalar values.
893--
894-- Examples:
895--
896-- > justifyRight 7 'x' "bar" == "xxxxbar"
897-- > justifyRight 3 'x' "foobar" == "foobar"
898justifyRight :: Int -> Char -> Text -> Text
899justifyRight = coerce JSS.justifyRight
900-- justifyRight k c t
901-- | len >= k = t
902-- | otherwise = replicateChar (k-len) c `append` t
903-- where len = length t
904{-# INLINE justifyRight #-}
906-- | /O(n)/ Center a string to the given length, using the specified
907-- fill character on either side. Performs replacement on invalid
908-- scalar values.
909--
910-- Examples:
911--
912-- > center 8 'x' "HS" = "xxxHSxxx"
913center :: Int -> Char -> Text -> Text
914center = coerce JSS.center
915-- center k c t
916-- | len >= k = t
917-- | otherwise = replicateChar l c `append` t `append` replicateChar r c
918-- where len = length t
919-- d = k - len
920-- r = d `quot` 2
921-- l = d - r
922{-# INLINE center #-}
924-- | /O(n)/ The 'transpose' function transposes the rows and columns
925-- of its 'Text' argument. Note that this function uses 'pack',
926-- 'unpack', and the list version of transpose, and is thus not very
927-- efficient.
928transpose :: [Text] -> [Text]
929transpose = coerce JSS.transpose
930-- transpose ts = P.map pack (L.transpose (P.map unpack ts))
932-- -----------------------------------------------------------------------------
933-- * Reducing 'Text's (folds)
935-- | /O(n)/ 'foldl', applied to a binary operator, a starting value
936-- (typically the left-identity of the operator), and a 'Text',
937-- reduces the 'Text' using the binary operator, from left to right.
938-- Subject to fusion.
939foldl :: (a -> Char -> a) -> a -> Text -> a
940foldl f a0 (Text t) = JSS.foldl f a0 t
941-- foldl f z t = S.foldl f z (stream t)
942{-# INLINE foldl #-}
944-- | /O(n)/ A strict version of 'foldl'. Subject to fusion.
945foldl' :: (a -> Char -> a) -> a -> Text -> a
946foldl' f a0 (Text t) = JSS.foldl' f a0 t
947-- foldl' f z t = S.foldl' f z (stream t)
948{-# INLINE foldl' #-}
950-- | /O(n)/ A variant of 'foldl' that has no starting value argument,
951-- and thus must be applied to a non-empty 'Text'. Subject to fusion.
952foldl1 :: (Char -> Char -> Char) -> Text -> Char
953foldl1 = coerce JSS.foldl1
954-- foldl1 f t = S.foldl1 f (stream t)
955{-# INLINE foldl1 #-}
957-- | /O(n)/ A strict version of 'foldl1'. Subject to fusion.
958foldl1' :: (Char -> Char -> Char) -> Text -> Char
959foldl1' = coerce JSS.foldl1'
960-- foldl1' f t = S.foldl1' f (stream t)
961{-# INLINE foldl1' #-}
963-- | /O(n)/ 'foldr', applied to a binary operator, a starting value
964-- (typically the right-identity of the operator), and a 'Text',
965-- reduces the 'Text' using the binary operator, from right to left.
966-- Subject to fusion.
967foldr :: (Char -> a -> a) -> a -> Text -> a
968foldr f a0 (Text t) = JSS.foldr f a0 t
969-- foldr f z t = S.foldr f z (stream t)
970{-# INLINE foldr #-}
972-- | /O(n)/ A variant of 'foldr' that has no starting value argument,
973-- and thus must be applied to a non-empty 'Text'. Subject to
974-- fusion.
975foldr1 :: (Char -> Char -> Char) -> Text -> Char
976foldr1 = coerce JSS.foldr1
977-- foldr1 f t = S.foldr1 f (stream t)
978{-# INLINE foldr1 #-}
980-- -----------------------------------------------------------------------------
981-- ** Special folds
983-- | /O(n)/ Concatenate a list of 'Text's.
984concat :: [Text] -> Text
985concat = coerce JSS.concat
986-- concat ts = case ts' of
987-- [] -> empty
988-- [t] -> t
989-- _ -> Text (A.run go) 0 len
990-- where
991-- ts' = L.filter (not . null) ts
992-- len = sumP "concat" $ L.map lengthWord16 ts'
993-- go :: ST s (A.MArray s)
994-- go = do
995-- arr <- A.new len
996-- let step i (Text a o l) =
997-- let !j = i + l in A.copyI arr i a o j >> return j
998-- foldM step 0 ts' >> return arr
1000-- | /O(n)/ Map a function over a 'Text' that results in a 'Text', and
1001-- concatenate the results.
1002concatMap :: (Char -> Text) -> Text -> Text
1003concatMap = coerce JSS.concatMap
1004-- concatMap f = concat . foldr ((:) . f) []
1005{-# INLINE concatMap #-}
1007-- | /O(n)/ 'any' @p@ @t@ determines whether any character in the
1008-- 'Text' @t@ satisfies the predicate @p@. Subject to fusion.
1009any :: (Char -> Bool) -> Text -> Bool
1010any = coerce JSS.any
1011-- any p t = S.any p (stream t)
1012{-# INLINE any #-}
1014-- | /O(n)/ 'all' @p@ @t@ determines whether all characters in the
1015-- 'Text' @t@ satisfy the predicate @p@. Subject to fusion.
1016all :: (Char -> Bool) -> Text -> Bool
1017all = coerce JSS.all
1018-- all p t = S.all p (stream t)
1019{-# INLINE all #-}
1021-- | /O(n)/ 'maximum' returns the maximum value from a 'Text', which
1022-- must be non-empty. Subject to fusion.
1023maximum :: Text -> Char
1024maximum = coerce JSS.maximum
1025-- maximum t = S.maximum (stream t)
1026{-# INLINE maximum #-}
1028-- | /O(n)/ 'minimum' returns the minimum value from a 'Text', which
1029-- must be non-empty. Subject to fusion.
1030minimum :: Text -> Char
1031minimum = coerce JSS.minimum
1032-- minimum t = S.minimum (stream t)
1033{-# INLINE minimum #-}
1035-- -----------------------------------------------------------------------------
1036-- * Building 'Text's
1038-- | /O(n)/ 'scanl' is similar to 'foldl', but returns a list of
1039-- successive reduced values from the left. Subject to fusion.
1040-- Performs replacement on invalid scalar values.
1042-- > scanl f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...]
1044-- Note that
1046-- > last (scanl f z xs) == foldl f z xs.
1047scanl :: (Char -> Char -> Char) -> Char -> Text -> Text
1048scanl = coerce JSS.scanl
1049-- scanl f z t = unstream (S.scanl g z (stream t))
1050-- where g a b = safe (f a b)
1051{-# INLINE scanl #-}
1053-- | /O(n)/ 'scanl1' is a variant of 'scanl' that has no starting
1054-- value argument. Subject to fusion. Performs replacement on
1055-- invalid scalar values.
1057-- > scanl1 f [x1, x2, ...] == [x1, x1 `f` x2, ...]
1058scanl1 :: (Char -> Char -> Char) -> Text -> Text
1059scanl1 = coerce JSS.scanl1
1060-- scanl1 f t | null t = empty
1061-- | otherwise = scanl f (unsafeHead t) (unsafeTail t)
1062{-# INLINE scanl1 #-}
1064-- | /O(n)/ 'scanr' is the right-to-left dual of 'scanl'. Performs
1065-- replacement on invalid scalar values.
1067-- > scanr f v == reverse . scanl (flip f) v . reverse
1068scanr :: (Char -> Char -> Char) -> Char -> Text -> Text
1069scanr = coerce JSS.scanr
1070-- scanr f z = S.reverse . S.reverseScanr g z . reverseStream
1071-- where g a b = safe (f a b)
1072{-# INLINE scanr #-}
1074-- | /O(n)/ 'scanr1' is a variant of 'scanr' that has no starting
1075-- value argument. Subject to fusion. Performs replacement on
1076-- invalid scalar values.
1077scanr1 :: (Char -> Char -> Char) -> Text -> Text
1078scanr1 = coerce JSS.scanr1
1079-- scanr1 f t | null t = empty
1080-- | otherwise = scanr f (last t) (init t)
1081{-# INLINE scanr1 #-}
1083-- | /O(n)/ Like a combination of 'map' and 'foldl''. Applies a
1084-- function to each element of a 'Text', passing an accumulating
1085-- parameter from left to right, and returns a final 'Text'. Performs
1086-- replacement on invalid scalar values.
1087mapAccumL :: (a -> Char -> (a,Char)) -> a -> Text -> (a, Text)
1088mapAccumL f z0 (Text a) =
1089 let (a', t) = JSS.mapAccumL f z0 a
1090 in (a', Text t)
1091-- mapAccumL f z0 = S.mapAccumL g z0 . stream
1092-- where g a b = second safe (f a b)
1093{-# INLINE mapAccumL #-}
1095-- | The 'mapAccumR' function behaves like a combination of 'map' and
1096-- a strict 'foldr'; it applies a function to each element of a
1097-- 'Text', passing an accumulating parameter from right to left, and
1098-- returning a final value of this accumulator together with the new
1099-- 'Text'.
1100-- Performs replacement on invalid scalar values.
1101mapAccumR :: (a -> Char -> (a,Char)) -> a -> Text -> (a, Text)
1102mapAccumR f z0 (Text a) =
1103 let (a', t) = JSS.mapAccumR f z0 a
1104 in (a', Text t)
1105-- mapAccumR f z0 = second reverse . S.mapAccumL g z0 . reverseStream
1106-- where g a b = second safe (f a b)
1107{-# INLINE mapAccumR #-}
1109-- -----------------------------------------------------------------------------
1110-- ** Generating and unfolding 'Text's
1112-- | /O(n*m)/ 'replicate' @n@ @t@ is a 'Text' consisting of the input
1113-- @t@ repeated @n@ times.
1114replicate :: Int -> Text -> Text
1115replicate = coerce JSS.replicate
1116-- replicate n t@(Text a o l)
1117-- | n <= 0 || l <= 0 = empty
1118-- | n == 1 = t
1119-- | isSingleton t = replicateChar n (unsafeHead t)
1120-- | otherwise = Text (A.run x) 0 len
1121-- where
1122-- len = l `mul` n
1123-- x :: ST s (A.MArray s)
1124-- x = do
1125-- arr <- A.new len
1126-- let loop !d !i | i >= n = return arr
1127-- | otherwise = let m = d + l
1128-- in A.copyI arr d a o m >> loop m (i+1)
1129-- loop 0 0
1130{-# INLINE [1] replicate #-}
1132{-# RULES
1133"TEXT replicate/singleton -> replicateChar" [~1] forall n c.
1134 replicate n (singleton c) = replicateChar n c
1135 #-}
1137-- | /O(n)/ 'replicateChar' @n@ @c@ is a 'Text' of length @n@ with @c@ the
1138-- value of every element. Subject to fusion.
1139replicateChar :: Int -> Char -> Text
1140#ifndef __GHCJS__
1141replicateChar n c = unstream (S.replicateCharI n (safe c))
1142{-# INLINE replicateChar #-}
1143#else
1144replicateChar n c = Text $ js_replicateChar n c
1145{-# INLINE [1] replicateChar #-}
1146{-# RULES
1147"JSSTRING replicateChar -> fused" [~1] forall n c.
1148 replicateChar n c = unstream (S.replicateCharI n (safe c))
1149"JSSTRING replicateChar -> unfused" [1] forall n c.
1150 unstream (S.replicateCharI n (safe c)) = replicateChar n c
1151 #-}
1152#endif
1154-- | /O(n)/, where @n@ is the length of the result. The 'unfoldr'
1155-- function is analogous to the List 'L.unfoldr'. 'unfoldr' builds a
1156-- 'Text' from a seed value. The function takes the element and
1157-- returns 'Nothing' if it is done producing the 'Text', otherwise
1158-- 'Just' @(a,b)@. In this case, @a@ is the next 'Char' in the
1159-- string, and @b@ is the seed value for further production. Subject
1160-- to fusion. Performs replacement on invalid scalar values.
1161unfoldr :: (a -> Maybe (Char,a)) -> a -> Text
1162unfoldr f a = Text $ JSS.unfoldr f a
1163-- unfoldr f s = unstream (S.unfoldr (firstf safe . f) s)
1164{-# INLINE unfoldr #-}
1166-- | /O(n)/ Like 'unfoldr', 'unfoldrN' builds a 'Text' from a seed
1167-- value. However, the length of the result should be limited by the
1168-- first argument to 'unfoldrN'. This function is more efficient than
1169-- 'unfoldr' when the maximum length of the result is known and
1170-- correct, otherwise its performance is similar to 'unfoldr'. Subject
1171-- to fusion. Performs replacement on invalid scalar values.
1172unfoldrN :: Int -> (a -> Maybe (Char,a)) -> a -> Text
1173unfoldrN n f a0 = Text $ JSS.unfoldrN n f a0
1174-- unfoldrN n f s = unstream (S.unfoldrN n (firstf safe . f) s)
1175{-# INLINE unfoldrN #-}
1177-- -----------------------------------------------------------------------------
1178-- * Substrings
1180-- | /O(n)/ 'take' @n@, applied to a 'Text', returns the prefix of the
1181-- 'Text' of length @n@, or the 'Text' itself if @n@ is greater than
1182-- the length of the Text. Subject to fusion.
1183take :: Int -> Text -> Text
1184take = coerce JSS.take
1185-- take n t@(Text arr off len)
1186-- | n <= 0 = empty
1187-- | n >= len = t
1188-- | otherwise = text arr off (iterN n t)
1189{-# INLINE [1] take #-}
1191-- iterN :: Int -> Text -> Int
1192-- iterN n t@(Text _arr _off len) = loop 0 0
1193-- where loop !i !cnt
1194-- | i >= len || cnt >= n = i
1195-- | otherwise = loop (i+d) (cnt+1)
1196-- where d = iter_ t i
1198{-# RULES
1199"TEXT take -> fused" [~1] forall n t.
1200 take n t = unstream (S.take n (stream t))
1201"TEXT take -> unfused" [1] forall n t.
1202 unstream (S.take n (stream t)) = take n t
1203 #-}
1205-- | /O(n)/ 'takeEnd' @n@ @t@ returns the suffix remaining after
1206-- taking @n@ characters from the end of @t@.
1208-- Examples:
1210-- > takeEnd 3 "foobar" == "bar"
1211takeEnd :: Int -> Text -> Text
1212takeEnd = coerce JSS.takeEnd
1213-- takeEnd n t@(Text arr off len)
1214-- | n <= 0 = empty
1215-- | n >= len = t
1216-- | otherwise = text arr (off+i) (len-i)
1217-- where i = iterNEnd n t
1219-- iterNEnd :: Int -> Text -> Int
1220-- iterNEnd n t@(Text _arr _off len) = loop (len-1) n
1221-- where loop i !m
1222-- | i <= 0 = 0
1223-- | m <= 1 = i
1224-- | otherwise = loop (i+d) (m-1)
1225-- where d = reverseIter_ t i
1227-- | /O(n)/ 'drop' @n@, applied to a 'Text', returns the suffix of the
1228-- 'Text' after the first @n@ characters, or the empty 'Text' if @n@
1229-- is greater than the length of the 'Text'. Subject to fusion.
1230drop :: Int -> Text -> Text
1231drop = coerce JSS.drop
1232-- drop n t@(Text arr off len)
1233-- | n <= 0 = t
1234-- | n >= len = empty
1235-- | otherwise = text arr (off+i) (len-i)
1236-- where i = iterN n t
1237{-# INLINE [1] drop #-}
1239{-# RULES
1240"TEXT drop -> fused" [~1] forall n t.
1241 drop n t = unstream (S.drop n (stream t))
1242"TEXT drop -> unfused" [1] forall n t.
1243 unstream (S.drop n (stream t)) = drop n t
1244 #-}
1246-- | /O(n)/ 'dropEnd' @n@ @t@ returns the prefix remaining after
1247-- dropping @n@ characters from the end of @t@.
1249-- Examples:
1251-- > dropEnd 3 "foobar" == "foo"
1252dropEnd :: Int -> Text -> Text
1253dropEnd = coerce JSS.dropEnd
1254-- dropEnd n t@(Text arr off len)
1255-- | n <= 0 = t
1256-- | n >= len = empty
1257-- | otherwise = text arr off (iterNEnd n t)
1259-- | /O(n)/ 'takeWhile', applied to a predicate @p@ and a 'Text',
1260-- returns the longest prefix (possibly empty) of elements that
1261-- satisfy @p@. Subject to fusion.
1262takeWhile :: (Char -> Bool) -> Text -> Text
1263takeWhile = coerce JSS.takeWhile
1264-- takeWhile p t@(Text arr off len) = loop 0
1265-- where loop !i | i >= len = t
1266-- | p c = loop (i+d)
1267-- | otherwise = text arr off i
1268-- where Iter c d = iter t i
1269{-# INLINE [1] takeWhile #-}
1271{-# RULES
1272"TEXT takeWhile -> fused" [~1] forall p t.
1273 takeWhile p t = unstream (S.takeWhile p (stream t))
1274"TEXT takeWhile -> unfused" [1] forall p t.
1275 unstream (S.takeWhile p (stream t)) = takeWhile p t
1276 #-}
1278-- | /O(n)/ 'takeWhileEnd', applied to a predicate @p@ and a 'Text',
1279-- returns the longest suffix (possibly empty) of elements that
1280-- satisfy @p@. Subject to fusion.
1281-- Examples:
1283-- > takeWhileEnd (=='o') "foo" == "oo"
1284takeWhileEnd :: (Char -> Bool) -> Text -> Text
1285#ifndef __GHCJS__
1286takeWhileEnd p t@(Text arr off len) = loop (len-1) len
1287 where loop !i !l | l <= 0 = t
1288 | p c = loop (i+d) (l+d)
1289 | otherwise = text arr (off+l) (len-l)
1290 where (c,d) = reverseIter t i
1291#else
1292takeWhileEnd p t@(Text jst) = loop (len-1) len
1293 where loop !i !l | l <= 0 = t
1294 | p c = loop (i+d) (l+d)
1295 | otherwise = Text $ js_substr1 l jst
1296 where (c,d) = reverseIter t i
1297 len = length t
1298#endif
1299{-# INLINE [1] takeWhileEnd #-}
1301{-# RULES
1302"TEXT takeWhileEnd -> fused" [~1] forall p t.
1303 takeWhileEnd p t = S.reverse (S.takeWhile p (S.reverseStream t))
1304"TEXT takeWhileEnd -> unfused" [1] forall p t.
1305 S.reverse (S.takeWhile p (S.reverseStream t)) = takeWhileEnd p t
1306 #-}
1308-- | /O(n)/ 'dropWhile' @p@ @t@ returns the suffix remaining after
1309-- 'takeWhile' @p@ @t@. Subject to fusion.
1310dropWhile :: (Char -> Bool) -> Text -> Text
1311dropWhile = coerce JSS.dropWhile
1312-- dropWhile p t@(Text arr off len) = loop 0 0
1313-- where loop !i !l | l >= len = empty
1314-- | p c = loop (i+d) (l+d)
1315-- | otherwise = Text arr (off+i) (len-l)
1317{-# INLINE [1] dropWhile #-}
1319{-# RULES
1320"TEXT dropWhile -> fused" [~1] forall p t.
1321 dropWhile p t = unstream (S.dropWhile p (stream t))
1322"TEXT dropWhile -> unfused" [1] forall p t.
1323 unstream (S.dropWhile p (stream t)) = dropWhile p t
1324 #-}
1326-- | /O(n)/ 'dropWhileEnd' @p@ @t@ returns the prefix remaining after
1327-- dropping characters that satisfy the predicate @p@ from the end of
1328-- @t@. Subject to fusion.
1330-- Examples:
1332-- > dropWhileEnd (=='.') "foo..." == "foo"
1333dropWhileEnd :: (Char -> Bool) -> Text -> Text
1334dropWhileEnd = coerce JSS.dropWhileEnd
1335-- dropWhileEnd p t@(Text arr off len) = loop (len-1) len
1336-- where loop !i !l | l <= 0 = empty
1337-- | p c = loop (i+d) (l+d)
1338-- | otherwise = Text arr off l
1339-- where (c,d) = reverseIter t i
1340{-# INLINE [1] dropWhileEnd #-}
1342{-# RULES
1343"TEXT dropWhileEnd -> fused" [~1] forall p t.
1344 dropWhileEnd p t = S.reverse (S.dropWhile p (S.reverseStream t))
1345"TEXT dropWhileEnd -> unfused" [1] forall p t.
1346 S.reverse (S.dropWhile p (S.reverseStream t)) = dropWhileEnd p t
1347 #-}
1349-- | /O(n)/ 'dropAround' @p@ @t@ returns the substring remaining after
1350-- dropping characters that satisfy the predicate @p@ from both the
1351-- beginning and end of @t@. Subject to fusion.
1352dropAround :: (Char -> Bool) -> Text -> Text
1353dropAround p = dropWhile p . dropWhileEnd p
1354{-# INLINE [1] dropAround #-}
1356-- | /O(n)/ Remove leading white space from a string. Equivalent to:
1358-- > dropWhile isSpace
1359stripStart :: Text -> Text
1360stripStart = dropWhile isSpace
1361{-# INLINE [1] stripStart #-}
1363-- | /O(n)/ Remove trailing white space from a string. Equivalent to:
1365-- > dropWhileEnd isSpace
1366stripEnd :: Text -> Text
1367stripEnd = dropWhileEnd isSpace
1368{-# INLINE [1] stripEnd #-}
1370-- | /O(n)/ Remove leading and trailing white space from a string.
1371-- Equivalent to:
1373-- > dropAround isSpace
1374strip :: Text -> Text
1375strip = dropAround isSpace
1376{-# INLINE [1] strip #-}
1378-- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a
1379-- prefix of @t@ of length @n@, and whose second is the remainder of
1380-- the string. It is equivalent to @('take' n t, 'drop' n t)@.
1381splitAt :: Int -> Text -> (Text, Text)
1382splitAt = coerce JSS.splitAt
1383-- splitAt n t@(Text arr off len)
1384-- | n <= 0 = (empty, t)
1385-- | n >= len = (t, empty)
1386-- | otherwise = let k = iterN n t
1387-- in (text arr off k, text arr (off+k) (len-k))
1389-- | /O(n)/ 'span', applied to a predicate @p@ and text @t@, returns
1390-- a pair whose first element is the longest prefix (possibly empty)
1391-- of @t@ of elements that satisfy @p@, and whose second is the
1392-- remainder of the list.
1393span :: (Char -> Bool) -> Text -> (Text, Text)
1394span = coerce JSS.span
1395-- span p t = case span_ p t of
1396-- (# hd,tl #) -> (hd,tl)
1397{-# INLINE span #-}
1399-- | /O(n)/ 'break' is like 'span', but the prefix returned is
1400-- over elements that fail the predicate @p@.
1401break :: (Char -> Bool) -> Text -> (Text, Text)
1402break = coerce JSS.break
1403-- break p = span (not . p)
1404{-# INLINE break #-}
1406-- | /O(n)/ Group characters in a string according to a predicate.
1407groupBy :: (Char -> Char -> Bool) -> Text -> [Text]
1408groupBy = coerce JSS.groupBy
1409-- groupBy p = loop
1410-- where
1411-- loop t@(Text arr off len)
1412-- | null t = []
1413-- | otherwise = text arr off n : loop (text arr (off+n) (len-n))
1414-- where Iter c d = iter t 0
1415-- n = d + findAIndexOrEnd (not . p c) (Text arr (off+d) (len-d))
1417-- | Returns the /array/ index (in units of 'Word16') at which a
1418-- character may be found. This is /not/ the same as the logical
1419-- index returned by e.g. 'findIndex'.
1420-- findAIndexOrEnd :: (Char -> Bool) -> Text -> Int
1421-- findAIndexOrEnd q t@(Text _arr _off len) = go 0
1422-- where go !i | i >= len || q c = i
1423-- | otherwise = go (i+d)
1424-- where Iter c d = iter t i
1426-- | /O(n)/ Group characters in a string by equality.
1427group :: Text -> [Text]
1428group = groupBy (==)
1430-- | /O(n)/ Return all initial segments of the given 'Text', shortest
1431-- first.
1432inits :: Text -> [Text]
1433inits = coerce JSS.inits
1434-- inits t@(Text arr off len) = loop 0
1435-- where loop i | i >= len = [t]
1436-- | otherwise = Text arr off i : loop (i + iter_ t i)
1438-- | /O(n)/ Return all final segments of the given 'Text', longest
1439-- first.
1440tails :: Text -> [Text]
1441tails = coerce JSS.tails
1442-- tails t | null t = [empty]
1443-- | otherwise = t : tails (unsafeTail t)
1445-- $split
1447-- Splitting functions in this library do not perform character-wise
1448-- copies to create substrings; they just construct new 'Text's that
1449-- are slices of the original.
1451-- | /O(m+n)/ Break a 'Text' into pieces separated by the first 'Text'
1452-- argument (which cannot be empty), consuming the delimiter. An empty
1453-- delimiter is invalid, and will cause an error to be raised.
1455-- Examples:
1457-- > splitOn "\r\n" "a\r\nb\r\nd\r\ne" == ["a","b","d","e"]
1458-- > splitOn "aaa" "aaaXaaaXaaaXaaa" == ["","X","X","X",""]
1459-- > splitOn "x" "x" == ["",""]
1461-- and
1463-- > intercalate s . splitOn s == id
1464-- > splitOn (singleton c) == split (==c)
1466-- (Note: the string @s@ to split on above cannot be empty.)
1468-- In (unlikely) bad cases, this function's time complexity degrades
1469-- towards /O(n*m)/.
1470splitOn :: Text
1471 -- ^ String to split on. If this string is empty, an error
1472 -- will occur.
1473 -> Text
1474 -- ^ Input text.
1475 -> [Text]
1476splitOn = coerce JSS.splitOn
1477-- splitOn pat@(Text _ _ l) src@(Text arr off len)
1478-- | l <= 0 = emptyError "splitOn"
1479-- | isSingleton pat = split (== unsafeHead pat) src
1480-- | otherwise = go 0 (indices pat src)
1481-- where
1482-- go !s (x:xs) = text arr (s+off) (x-s) : go (x+l) xs
1483-- go s _ = [text arr (s+off) (len-s)]
1484{-# INLINE [1] splitOn #-}
1486{-# RULES
1487"TEXT splitOn/singleton -> split/==" [~1] forall c t.
1488 splitOn (singleton c) t = split (==c) t
1489 #-}
1491-- | /O(n)/ Splits a 'Text' into components delimited by separators,
1492-- where the predicate returns True for a separator element. The
1493-- resulting components do not contain the separators. Two adjacent
1494-- separators result in an empty component in the output. eg.
1496-- > split (=='a') "aabbaca" == ["","","bb","c",""]
1497-- > split (=='a') "" == [""]
1498split :: (Char -> Bool) -> Text -> [Text]
1499split = coerce JSS.split
1500-- split _ t@(Text _off _arr 0) = [t]
1501-- split p t = loop t
1502-- where loop s | null s' = [l]
1503-- | otherwise = l : loop (unsafeTail s')
1504-- where (# l, s' #) = span_ (not . p) s
1505{-# INLINE split #-}
1507-- | /O(n)/ Splits a 'Text' into components of length @k@. The last
1508-- element may be shorter than the other chunks, depending on the
1509-- length of the input. Examples:
1511-- > chunksOf 3 "foobarbaz" == ["foo","bar","baz"]
1512-- > chunksOf 4 "haskell.org" == ["hask","ell.","org"]
1513chunksOf :: Int -> Text -> [Text]
1514chunksOf = coerce JSS.chunksOf
1515-- chunksOf k = go
1516-- where
1517-- go t = case splitAt k t of
1518-- (a,b) | null a -> []
1519-- | otherwise -> a : go b
1520{-# INLINE chunksOf #-}
1522-- ----------------------------------------------------------------------------
1523-- * Searching
1525-------------------------------------------------------------------------------
1526-- ** Searching with a predicate
1528-- | /O(n)/ The 'find' function takes a predicate and a 'Text', and
1529-- returns the first element matching the predicate, or 'Nothing' if
1530-- there is no such element.
1531find :: (Char -> Bool) -> Text -> Maybe Char
1532find = coerce JSS.find
1533-- find p t = S.findBy p (stream t)
1534{-# INLINE find #-}
1536-- | /O(n)/ The 'partition' function takes a predicate and a 'Text',
1537-- and returns the pair of 'Text's with elements which do and do not
1538-- satisfy the predicate, respectively; i.e.
1540-- > partition p t == (filter p t, filter (not . p) t)
1541partition :: (Char -> Bool) -> Text -> (Text, Text)
1542partition = coerce JSS.partition
1543-- partition p t = (filter p t, filter (not . p) t)
1544{-# INLINE partition #-}
1546-- | /O(n)/ 'filter', applied to a predicate and a 'Text',
1547-- returns a 'Text' containing those characters that satisfy the
1548-- predicate.
1549filter :: (Char -> Bool) -> Text -> Text
1550filter = coerce JSS.filter
1551-- filter p t = unstream (S.filter p (stream t))
1552{-# INLINE filter #-}
1554-- | /O(n+m)/ Find the first instance of @needle@ (which must be
1555-- non-'null') in @haystack@. The first element of the returned tuple
1556-- is the prefix of @haystack@ before @needle@ is matched. The second
1557-- is the remainder of @haystack@, starting with the match.
1559-- Examples:
1561-- > breakOn "::" "a::b::c" ==> ("a", "::b::c")
1562-- > breakOn "/" "foobar" ==> ("foobar", "")
1564-- Laws:
1566-- > append prefix match == haystack
1567-- > where (prefix, match) = breakOn needle haystack
1569-- If you need to break a string by a substring repeatedly (e.g. you
1570-- want to break on every instance of a substring), use 'breakOnAll'
1571-- instead, as it has lower startup overhead.
1573-- In (unlikely) bad cases, this function's time complexity degrades
1574-- towards /O(n*m)/.
1575breakOn :: Text -> Text -> (Text, Text)
1576breakOn = coerce JSS.breakOn
1577-- breakOn pat src@(Text arr off len)
1578-- | null pat = emptyError "breakOn"
1579-- | otherwise = case indices pat src of
1580-- [] -> (src, empty)
1581-- (x:_) -> (text arr off x, text arr (off+x) (len-x))
1582{-# INLINE breakOn #-}
1584-- | /O(n+m)/ Similar to 'breakOn', but searches from the end of the
1585-- string.
1587-- The first element of the returned tuple is the prefix of @haystack@
1588-- up to and including the last match of @needle@. The second is the
1589-- remainder of @haystack@, following the match.
1591-- > breakOnEnd "::" "a::b::c" ==> ("a::b::", "c")
1592breakOnEnd :: Text -> Text -> (Text, Text)
1593breakOnEnd = coerce JSS.breakOnEnd
1594-- breakOnEnd pat src = (reverse b, reverse a)
1595-- where (a,b) = breakOn (reverse pat) (reverse src)
1596{-# INLINE breakOnEnd #-}
1598-- | /O(n+m)/ Find all non-overlapping instances of @needle@ in
1599-- @haystack@. Each element of the returned list consists of a pair:
1601-- * The entire string prior to the /k/th match (i.e. the prefix)
1603-- * The /k/th match, followed by the remainder of the string
1605-- Examples:
1607-- > breakOnAll "::" ""
1608-- > ==> []
1609-- > breakOnAll "/" "a/b/c/"
1610-- > ==> [("a", "/b/c/"), ("a/b", "/c/"), ("a/b/c", "/")]
1612-- In (unlikely) bad cases, this function's time complexity degrades
1613-- towards /O(n*m)/.
1615-- The @needle@ parameter may not be empty.
1616breakOnAll :: Text -- ^ @needle@ to search for
1617 -> Text -- ^ @haystack@ in which to search
1618 -> [(Text, Text)]
1619breakOnAll = coerce JSS.breakOnAll
1620-- breakOnAll pat src@(Text arr off slen)
1621-- | null pat = emptyError "breakOnAll"
1622-- | otherwise = L.map step (indices pat src)
1623-- where
1624-- step x = (chunk 0 x, chunk x (slen-x))
1625-- chunk !n !l = text arr (n+off) l
1626{-# INLINE breakOnAll #-}
1628-------------------------------------------------------------------------------
1629-- ** Indexing 'Text's
1631-- $index
1633-- If you think of a 'Text' value as an array of 'Char' values (which
1634-- it is not), you run the risk of writing inefficient code.
1636-- An idiom that is common in some languages is to find the numeric
1637-- offset of a character or substring, then use that number to split
1638-- or trim the searched string. With a 'Text' value, this approach
1639-- would require two /O(n)/ operations: one to perform the search, and
1640-- one to operate from wherever the search ended.
1642-- For example, suppose you have a string that you want to split on
1643-- the substring @\"::\"@, such as @\"foo::bar::quux\"@. Instead of
1644-- searching for the index of @\"::\"@ and taking the substrings
1645-- before and after that index, you would instead use @breakOnAll \"::\"@.
1647-- | /O(n)/ 'Text' index (subscript) operator, starting from 0.
1648index :: Text -> Int -> Char
1649index = coerce JSS.index
1650-- index t n = S.index (stream t) n
1651{-# INLINE index #-}
1653-- | /O(n)/ The 'findIndex' function takes a predicate and a 'Text'
1654-- and returns the index of the first element in the 'Text' satisfying
1655-- the predicate. Subject to fusion.
1656findIndex :: (Char -> Bool) -> Text -> Maybe Int
1657findIndex = coerce JSS.findIndex
1658-- findIndex p t = S.findIndex p (stream t)
1659{-# INLINE findIndex #-}
1661-- | /O(n+m)/ The 'count' function returns the number of times the
1662-- query string appears in the given 'Text'. An empty query string is
1663-- invalid, and will cause an error to be raised.
1665-- In (unlikely) bad cases, this function's time complexity degrades
1666-- towards /O(n*m)/.
1667count :: Text -> Text -> Int
1668count = coerce JSS.count
1669-- count pat src
1670-- | null pat = emptyError "count"
1671-- | isSingleton pat = countChar (unsafeHead pat) src
1672-- | otherwise = L.length (indices pat src)
1673{-# INLINE [1] count #-}
1675{-# RULES
1676"TEXT count/singleton -> countChar" [~1] forall c t.
1677 count (singleton c) t = countChar c t
1678 #-}
1680-- | /O(n)/ The 'countChar' function returns the number of times the
1681-- query element appears in the given 'Text'. Subject to fusion.
1682countChar :: Char -> Text -> Int
1683countChar c t = S.countChar c (stream t)
1684{-# INLINE countChar #-}
1686-------------------------------------------------------------------------------
1687-- * Zipping
1689-- | /O(n)/ 'zip' takes two 'Text's and returns a list of
1690-- corresponding pairs of bytes. If one input 'Text' is short,
1691-- excess elements of the longer 'Text' are discarded. This is
1692-- equivalent to a pair of 'unpack' operations.
1693zip :: Text -> Text -> [(Char,Char)]
1694zip = coerce JSS.zip
1695-- zip a b = S.unstreamList $ S.zipWith (,) (stream a) (stream b)
1696{-# INLINE zip #-}
1698-- | /O(n)/ 'zipWith' generalises 'zip' by zipping with the function
1699-- given as the first argument, instead of a tupling function.
1700-- Performs replacement on invalid scalar values.
1701zipWith :: (Char -> Char -> Char) -> Text -> Text -> Text
1702zipWith = coerce JSS.zipWith
1703-- zipWith f t1 t2 = unstream (S.zipWith g (stream t1) (stream t2))
1704-- where g a b = safe (f a b)
1705{-# INLINE zipWith #-}
1707-- | /O(n)/ Breaks a 'Text' up into a list of words, delimited by 'Char's
1708-- representing white space.
1709words :: Text -> [Text]
1710words = coerce JSS.words
1711-- words t@(Text arr off len) = loop 0 0
1712-- where
1713-- loop !start !n
1714-- | n >= len = if start == n
1715-- then []
1716-- else [Text arr (start+off) (n-start)]
1717-- | isSpace c =
1718-- if start == n
1719-- then loop (start+1) (start+1)
1720-- else Text arr (start+off) (n-start) : loop (n+d) (n+d)
1721-- | otherwise = loop start (n+d)
1722-- where Iter c d = iter t n
1723{-# INLINE words #-}
1725-- | /O(n)/ Breaks a 'Text' up into a list of 'Text's at
1726-- newline 'Char's. The resulting strings do not contain newlines.
1727lines :: Text -> [Text]
1728lines = coerce JSS.lines
1729-- lines ps | null ps = []
1730-- | otherwise = h : if null t
1731-- then []
1732-- else lines (unsafeTail t)
1733-- where (# h,t #) = span_ (/= '\n') ps
1734{-# INLINE lines #-}
1737-- | /O(n)/ Portably breaks a 'Text' up into a list of 'Text's at line
1738-- boundaries.
1740-- A line boundary is considered to be either a line feed, a carriage
1741-- return immediately followed by a line feed, or a carriage return.
1742-- This accounts for both Unix and Windows line ending conventions,
1743-- and for the old convention used on Mac OS 9 and earlier.
1744lines' :: Text -> [Text]
1745lines' ps | null ps = []
1746 | otherwise = h : case uncons t of
1747 Nothing -> []
1748 Just (c,t')
1749 | c == '\n' -> lines t'
1750 | c == '\r' -> case uncons t' of
1751 Just ('\n',t'') -> lines t''
1752 _ -> lines t'
1753 where (h,t) = span notEOL ps
1754 notEOL c = c /= '\n' && c /= '\r'
1755{-# INLINE lines' #-}
1758-- | /O(n)/ Joins lines, after appending a terminating newline to
1759-- each.
1760unlines :: [Text] -> Text
1761unlines = coerce JSS.unlines
1762-- unlines = concat . L.map (`snoc` '\n')
1763{-# INLINE unlines #-}
1765-- | /O(n)/ Joins words using single space characters.
1766unwords :: [Text] -> Text
1767unwords = coerce JSS.unwords
1768-- unwords = intercalate (singleton ' ')
1769{-# INLINE unwords #-}
1771-- | /O(n)/ The 'isPrefixOf' function takes two 'Text's and returns
1772-- 'True' iff the first is a prefix of the second. Subject to fusion.
1773isPrefixOf :: Text -> Text -> Bool
1774isPrefixOf = coerce JSS.isPrefixOf
1775-- isPrefixOf a@(Text _ _ alen) b@(Text _ _ blen) =
1776-- alen <= blen && S.isPrefixOf (stream a) (stream b)
1777{-# INLINE [1] isPrefixOf #-}
1779{-# RULES
1780"TEXT isPrefixOf -> fused" [~1] forall s t.
1781 isPrefixOf s t = S.isPrefixOf (stream s) (stream t)
1782"JSSTRING isPrefixOf -> unfused" [1] forall x y.
1783 S.isPrefixOf (stream x) (stream y) = isPrefixOf x y
1784 #-}
1786-- | /O(n)/ The 'isSuffixOf' function takes two 'Text's and returns
1787-- 'True' iff the first is a suffix of the second.
1788isSuffixOf :: Text -> Text -> Bool
1789isSuffixOf = coerce JSS.isSuffixOf
1790-- isSuffixOf a@(Text _aarr _aoff alen) b@(Text barr boff blen) =
1791-- d >= 0 && a == b'
1792-- where d = blen - alen
1793-- b' | d == 0 = b
1794-- | otherwise = Text barr (boff+d) alen
1795{-# INLINE isSuffixOf #-}
1797-- | /O(n+m)/ The 'isInfixOf' function takes two 'Text's and returns
1798-- 'True' iff the first is contained, wholly and intact, anywhere
1799-- within the second.
1801-- In (unlikely) bad cases, this function's time complexity degrades
1802-- towards /O(n*m)/.
1803isInfixOf :: Text -> Text -> Bool
1804isInfixOf = coerce JSS.isInfixOf
1805-- isInfixOf needle haystack
1806-- | null needle = True
1807-- | isSingleton needle = S.elem (unsafeHead needle) . S.stream $ haystack
1808-- | otherwise = not . L.null . indices needle $ haystack
1809{-# INLINE [1] isInfixOf #-}
1811{-# RULES
1812"TEXT isInfixOf/singleton -> S.elem/S.stream" [~1] forall n h.
1813 isInfixOf (singleton n) h = S.elem n (S.stream h)
1814 #-}
1816-------------------------------------------------------------------------------
1817-- * View patterns
1819-- | /O(n)/ Return the suffix of the second string if its prefix
1820-- matches the entire first string.
1822-- Examples:
1824-- > stripPrefix "foo" "foobar" == Just "bar"
1825-- > stripPrefix "" "baz" == Just "baz"
1826-- > stripPrefix "foo" "quux" == Nothing
1828-- This is particularly useful with the @ViewPatterns@ extension to
1829-- GHC, as follows:
1831-- > {-# LANGUAGE ViewPatterns #-}
1832-- > import Data.Text as T
1833-- >
1834-- > fnordLength :: Text -> Int
1835-- > fnordLength (stripPrefix "fnord" -> Just suf) = T.length suf
1836-- > fnordLength _ = -1
1837stripPrefix :: Text -> Text -> Maybe Text
1838stripPrefix = coerce JSS.stripPrefix
1839-- stripPrefix p@(Text _arr _off plen) t@(Text arr off len)
1840-- | p `isPrefixOf` t = Just $! text arr (off+plen) (len-plen)
1841-- | otherwise = Nothing
1843-- | /O(n)/ Find the longest non-empty common prefix of two strings
1844-- and return it, along with the suffixes of each string at which they
1845-- no longer match.
1847-- If the strings do not have a common prefix or either one is empty,
1848-- this function returns 'Nothing'.
1850-- Examples:
1852-- > commonPrefixes "foobar" "fooquux" == Just ("foo","bar","quux")
1853-- > commonPrefixes "veeble" "fetzer" == Nothing
1854-- > commonPrefixes "" "baz" == Nothing
1855commonPrefixes :: Text -> Text -> Maybe (Text,Text,Text)
1856commonPrefixes = coerce JSS.commonPrefixes
1857-- commonPrefixes t0@(Text arr0 off0 len0) t1@(Text arr1 off1 len1) = go 0 0
1858-- where
1859-- go !i !j | i < len0 && j < len1 && a == b = go (i+d0) (j+d1)
1860-- | i > 0 = Just (Text arr0 off0 i,
1861-- text arr0 (off0+i) (len0-i),
1862-- text arr1 (off1+j) (len1-j))
1863-- | otherwise = Nothing
1864-- where Iter a d0 = iter t0 i
1865-- Iter b d1 = iter t1 j
1867-- | /O(n)/ Return the prefix of the second string if its suffix
1868-- matches the entire first string.
1870-- Examples:
1872-- > stripSuffix "bar" "foobar" == Just "foo"
1873-- > stripSuffix "" "baz" == Just "baz"
1874-- > stripSuffix "foo" "quux" == Nothing
1876-- This is particularly useful with the @ViewPatterns@ extension to
1877-- GHC, as follows:
1879-- > {-# LANGUAGE ViewPatterns #-}
1880-- > import Data.Text as T
1881-- >
1882-- > quuxLength :: Text -> Int
1883-- > quuxLength (stripSuffix "quux" -> Just pre) = T.length pre
1884-- > quuxLength _ = -1
1885stripSuffix :: Text -> Text -> Maybe Text
1886stripSuffix = coerce JSS.stripSuffix
1887-- stripSuffix p@(Text _arr _off plen) t@(Text arr off len)
1888-- | p `isSuffixOf` t = Just $! text arr off (len-plen)
1889-- | otherwise = Nothing
1891-- -- | Add a list of non-negative numbers. Errors out on overflow.
1892-- sumP :: String -> [Int] -> Int
1893-- sumP fun = go 0
1894-- where go !a (x:xs)
1895-- | ax >= 0 = go ax xs
1896-- | otherwise = overflowError fun
1897-- where ax = a + x
1898-- go a _ = a
1900-- emptyError :: String -> a
1901-- emptyError fun = P.error $ "Data.Text." ++ fun ++ ": empty input"
1903overflowError :: String -> a
1904overflowError fun = P.error $ "Data.Text." ++ fun ++ ": size overflow"
1906-- | /O(n)/ Make a distinct copy of the given string, sharing no
1907-- storage with the original string.
1909-- As an example, suppose you read a large string, of which you need
1910-- only a small portion. If you do not use 'copy', the entire original
1911-- array will be kept alive in memory by the smaller string. Making a
1912-- copy \"breaks the link\" to the original array, allowing it to be
1913-- garbage collected if there are no other live references to it.
1914copy :: Text -> Text
1915copy = P.id -- TODO
1916-- copy (Text arr off len) = Text (A.run go) 0 len
1917-- where
1918-- go :: ST s (A.MArray s)
1919-- go = do
1920-- marr <- A.new len
1922foreign import javascript unsafe
1923 "h$jsstringReplicateChar" js_replicateChar :: Int -> Char -> JSString
1924foreign import javascript unsafe
1925 "$2.substr($1)" js_substr1 :: Int -> JSString -> JSString