@@ -0,0 +1,1404 @@
1+{-# LANGUAGE MagicHash, BangPatterns, UnboxedTuples, TypeFamilies
3+{-# OPTIONS_GHC -fno-warn-orphans #-}
4+{-| Manipulation of JavaScript strings, API and fusion implementation
5+ based on Data.Text by Tom Harper, Duncan Coutts, Bryan O'Sullivan e.a.
7+module Data.JSString ( JSString
9+ -- * Creation and elimination
36+ -- ** Case conversion
71+ -- ** Accumulating maps
75+ -- ** Generation and unfolding
82+ -- ** Breaking strings
105+ -- ** Breaking into many substrings
108+ , chunksOf, chunksOf'
110+ -- ** Breaking into lines and words
128+ , breakOnAll, breakOnAll'
143+ ( Char, Bool(..), Int, Maybe(..), String, Eq(..), Ord(..), Ordering(..), (++)
144+ , Read(..), Show(..), (&&), (||), (+), (-), (.), ($), ($!), (>>)
145+ , not, seq, return, otherwise, quot)
146+import qualified Prelude as P
148+import Control.DeepSeq (NFData(..))
149+import Data.Char (isSpace)
150+import Data.Coerce (coerce)
151+import qualified Data.List as L
153+import qualified Data.Text as T
154+import qualified Data.Text.Internal.Fusion as TF
155+import qualified Data.Text.Internal.Fusion.Common as TF
158+ ( Int#, (+#), (-#), (>=#), (>#), isTrue#, chr#, Char(..)
159+ , Int(..), Addr#, tagToEnum#)
160+import qualified GHC.Exts as Exts
161+import qualified GHC.CString as GHC
165+import GHCJS.Prim (JSVal)
167+import Data.JSString.Internal.Type
168+import Data.JSString.Internal.Fusion (stream, unstream)
169+import qualified Data.JSString.Internal.Fusion as S
170+import qualified Data.JSString.Internal.Fusion.Common as S
172+instance Exts.IsList JSString where
173+ type Item JSString = Char
177+-- -----------------------------------------------------------------------------
178+-- * Conversion to/from 'JSString'
180+-- | /O(n)/ Convert a 'String' into a 'JSString'. Subject to
182+pack :: String -> JSString
184+{-# INLINE [1] pack #-}
187+"JSSTRING pack -> fused" [~1] forall x.
188+ pack x = unstream (S.map safe (S.streamList x))
189+"JSSTRING pack -> unfused" [1] forall x.
190+ unstream (S.map safe (S.streamList x)) = pack x
193+-- | /O(n)/ Convert a 'JSString' into a 'String'. Subject to fusion.
194+unpack :: JSString -> String
195+unpack = S.unstreamList . stream
196+{-# INLINE [1] unpack #-}
198+unpack' :: JSString -> String
199+unpack' = coerce T.unpack
200+{-# INLINE unpack' #-}
202+-- | /O(n)/ Convert a literal string into a JSString. Subject to fusion.
203+unpackCString# :: Addr# -> JSString
204+unpackCString# = coerce T.unpackCString#
205+{-# NOINLINE unpackCString# #-}
207+{-# RULES "JSSTRING literal" forall a.
208+ unstream (S.map safe (S.streamList (GHC.unpackCString# a)))
209+ = unpackCString# a #-}
211+{-# RULES "JSSTRING literal UTF8" forall a.
212+ unstream (S.map safe (S.streamList (GHC.unpackCStringUtf8# a)))
213+ = unpackCString# a #-}
215+{-# RULES "JSSTRING empty literal"
216+ unstream (S.map safe (S.streamList []))
219+{-# RULES "JSSTRING singleton literal" forall a.
220+ unstream (S.map safe (S.streamList [a]))
224+-- | /O(1)/ Convert a character into a 'JSString'. Subject to fusion.
225+-- Performs replacement on invalid scalar values.
226+singleton :: Char -> JSString
227+singleton = coerce T.singleton
228+{-# INLINE [1] singleton #-}
231+"JSSTRING singleton -> fused" [~1] forall a.
232+ singleton a = unstream (S.singleton (safe a))
233+"JSSTRING singleton -> unfused" [1] forall a.
234+ unstream (S.singleton (safe a)) = singleton a
237+-- This is intended to reduce inlining bloat.
238+-- singleton_ :: Char -> Text
239+-- singleton_ c = js_singleton c
241+-- Text (A.run x) 0 len
242+-- where x :: ST s (A.MArray s)
243+-- x = do arr <- A.new len
244+-- _ <- unsafeWrite arr 0 d
246+-- len | d < '\x10000' = 1
249+-- {-# NOINLINE singleton_ #-}
251+-- -----------------------------------------------------------------------------
254+-- | /O(n)/ Adds a character to the front of a 'JSString'. This function
255+-- is more costly than its 'List' counterpart because it requires
256+-- copying a new array. Subject to fusion. Performs replacement on
257+-- invalid scalar values.
258+cons :: Char -> JSString -> JSString
260+{-# INLINE [1] cons #-}
263+"JSSTRING cons -> fused" [~1] forall c x.
264+ cons c x = unstream (S.cons (safe c) (stream x))
265+"JSSTRING cons -> unfused" [1] forall c x.
266+ unstream (S.cons (safe c) (stream x)) = cons c x
271+-- | /O(n)/ Adds a character to the end of a 'JSString'. This copies the
272+-- entire array in the process, unless fused. Subject to fusion.
273+-- Performs replacement on invalid scalar values.
274+snoc :: JSString -> Char -> JSString
276+ -- unstream (S.snoc (stream t) (safe c))
277+{-# INLINE [1] snoc #-}
280+"JSSTRING snoc -> fused" [~1] forall x c.
281+ snoc x c = unstream (S.snoc (stream x) (safe c))
282+"JSSTRING snoc -> unfused" [1] forall x c.
283+ unstream (S.snoc (stream x) (safe c)) = snoc x c
286+-- | /O(n)/ Appends one 'JSString' to the other by copying both of them
287+-- into a new 'JSString'. Subject to fusion.
288+append :: JSString -> JSString -> JSString
289+append = coerce T.append
290+{-# INLINE [1] append #-}
293+"JSSTRING append -> fused" [~1] forall x1 x2.
294+ append x1 x2 = unstream (S.append (stream x1) (stream x2))
295+"JSSTRING append -> unfused" [1] forall x1 x2.
296+ unstream (S.append (stream x1) (stream x2)) = append x1 x2
299+-- | /O(1)/ Returns the first character of a 'JSString', which must be
300+-- non-empty. Subject to fusion.
301+head :: JSString -> Char
303+{-# INLINE [1] head #-}
306+"JSSTRING head -> fused" [~1] forall x.
307+ head x = S.head (stream x)
308+"JSSTRING head -> unfused" [1] forall x.
309+ S.head (stream x) = head x
313+-- | /O(1)/ Returns the first character and rest of a 'JSString', or
314+-- 'Nothing' if empty. Subject to fusion.
315+uncons :: JSString -> Maybe (Char, JSString)
316+uncons = coerce T.uncons
317+{-# INLINE [1] uncons #-}
319+-- | Lifted from Control.Arrow and specialized.
320+second :: (b -> c) -> (a,b) -> (a,c)
321+second f (a, b) = (a, f b)
323+-- | /O(1)/ Returns the last character of a 'JSString', which must be
324+-- non-empty. Subject to fusion.
325+last :: JSString -> Char
327+{-# INLINE [1] last #-}
330+"JSSTRING last -> fused" [~1] forall x.
331+ last x = S.last (stream x)
332+"JSSTRING last -> unfused" [1] forall x.
333+ S.last (stream x) = last x
336+-- | /O(1)/ Returns all characters after the head of a 'JSString', which
337+-- must be non-empty. Subject to fusion.
338+tail :: JSString -> JSString
340+{-# INLINE [1] tail #-}
343+"JSSTRING tail -> fused" [~1] forall x.
344+ tail x = unstream (S.tail (stream x))
345+"JSSTRING tail -> unfused" [1] forall x.
346+ unstream (S.tail (stream x)) = tail x
349+-- | /O(1)/ Returns all but the last character of a 'JSString', which must
350+-- be non-empty. Subject to fusion.
351+init :: JSString -> JSString
353+{-# INLINE [1] init #-}
356+"JSSTRING init -> fused" [~1] forall t.
357+ init t = unstream (S.init (stream t))
358+"JSSTRING init -> unfused" [1] forall t.
359+ unstream (S.init (stream t)) = init t
362+-- | /O(1)/ Tests whether a 'JSString' is empty or not. Subject to
364+null :: JSString -> Bool
366+{-# INLINE [1] null #-}
369+"JSSTRING null -> fused" [~1] forall t.
370+ null t = S.null (stream t)
371+"JSSTRING null -> unfused" [1] forall t.
372+ S.null (stream t) = null t
375+-- | /O(n)/ Returns the number of characters in a 'JSString'.
376+-- Subject to fusion.
377+length :: JSString -> Int
378+length = coerce T.length
379+{-# INLINE [1] length #-}
382+"JSSTRING length -> fused" [~1] forall x.
383+ length x = S.length (stream x)
384+"JSSTRING length -> unfused" [1] forall x.
385+ S.length (stream x) = length x
388+-- | /O(n)/ Compare the count of characters in a 'JSString' to a number.
389+-- Subject to fusion.
391+-- This function gives the same answer as comparing against the result
392+-- of 'length', but can short circuit if the count of characters is
393+-- greater than the number, and hence be more efficient.
394+compareLength :: JSString -> Int -> Ordering
395+compareLength = coerce T.compareLength
396+{-# INLINE [1] compareLength #-}
399+"JSSTRING compareN/length -> compareLength" [~1] forall t n.
400+ compare (length t) n = compareLength t n
404+"JSSTRING ==N/length -> compareLength/==EQ" [~1] forall t n.
405+ (==) (length t) n = compareLength t n == EQ
409+"JSSTRING /=N/length -> compareLength//=EQ" [~1] forall t n.
410+ (/=) (length t) n = compareLength t n /= EQ
414+"JSSTRING <N/length -> compareLength/==LT" [~1] forall t n.
415+ (<) (length t) n = compareLength t n == LT
419+"JSSTRING <=N/length -> compareLength//=GT" [~1] forall t n.
420+ (<=) (length t) n = compareLength t n /= GT
424+"JSSTRING >N/length -> compareLength/==GT" [~1] forall t n.
425+ (>) (length t) n = compareLength t n == GT
429+"JSSTRING >=N/length -> compareLength//=LT" [~1] forall t n.
430+ (>=) (length t) n = compareLength t n /= LT
433+-- -----------------------------------------------------------------------------
435+-- | /O(n)/ 'map' @f@ @t@ is the 'JSString' obtained by applying @f@ to
436+-- each element of @t@. Subject to fusion. Performs replacement on
437+-- invalid scalar values.
438+map :: (Char -> Char) -> JSString -> JSString
440+{-# INLINE [1] map #-}
442+-- | /O(n)/ The 'intercalate' function takes a 'JSString' and a list of
443+-- 'JSString's and concatenates the list after interspersing the first
444+-- argument between each element of the list.
445+intercalate :: JSString -> [JSString] -> JSString
446+intercalate = coerce T.intercalate
447+{-# INLINE [1] intercalate #-}
449+-- | /O(n)/ The 'intersperse' function takes a character and places it
450+-- between the characters of a 'JSString'. Subject to fusion. Performs
451+-- replacement on invalid scalar values.
452+intersperse :: Char -> JSString -> JSString
453+intersperse = coerce T.intersperse
454+{-# INLINE [1] intersperse #-}
457+"JSSTRING intersperse -> fused" [~1] forall c x.
458+ intersperse c x = unstream (S.intersperse (safe c) (stream x))
459+"JSSTRING intersperse -> unfused" [1] forall c x.
460+ unstream (S.intersperse (safe c) (stream x)) = intersperse c x
463+-- | /O(n)/ Reverse the characters of a string. Subject to fusion.
464+reverse :: JSString -> JSString
465+reverse = coerce T.reverse
466+{-# INLINE [1] reverse #-}
469+"JSSTRING reverse -> fused" [~1] forall x.
470+ reverse x = S.reverse (stream x)
471+"JSSTRING reverse -> unfused" [1] forall x.
472+ S.reverse (stream x) = reverse x
475+-- | /O(m+n)/ Replace every non-overlapping occurrence of @needle@ in
476+-- @haystack@ with @replacement@.
478+-- This function behaves as though it was defined as follows:
481+-- replace needle replacement haystack =
482+-- 'intercalate' replacement ('splitOn' needle haystack)
485+-- As this suggests, each occurrence is replaced exactly once. So if
486+-- @needle@ occurs in @replacement@, that occurrence will /not/ itself
487+-- be replaced recursively:
489+-- > replace "oo" "foo" "oo" == "foo"
491+-- In cases where several instances of @needle@ overlap, only the
492+-- first one will be replaced:
494+-- > replace "ofo" "bar" "ofofo" == "barfo"
496+-- In (unlikely) bad cases, this function's time complexity degrades
499+ -- ^ @needle@ to search for. If this string is empty, an
500+ -- error will occur.
502+ -- ^ @replacement@ to replace @needle@ with.
504+ -- ^ @haystack@ in which to search.
506+replace = coerce T.replace
507+{-# INLINE replace #-}
509+-- ----------------------------------------------------------------------------
510+-- ** Case conversions (folds)
514+-- When case converting 'JSString' values, do not use combinators like
515+-- @map toUpper@ to case convert each character of a string
516+-- individually, as this gives incorrect results according to the
517+-- rules of some writing systems. The whole-string case conversion
518+-- functions from this module, such as @toUpper@, obey the correct
519+-- case conversion rules. As a result, these functions may map one
520+-- input character to two or three output characters. For examples,
521+-- see the documentation of each function.
523+-- /Note/: In some languages, case conversion is a locale- and
524+-- context-dependent operation. The case conversion functions in this
525+-- module are /not/ locale sensitive. Programs that require locale
526+-- sensitivity should use appropriate versions of the
527+-- <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 >.
529+-- | /O(n)/ Convert a string to folded case. Subject to fusion.
531+-- This function is mainly useful for performing caseless (also known
532+-- as case insensitive) string comparisons.
534+-- A string @x@ is a caseless match for a string @y@ if and only if:
536+-- @toCaseFold x == toCaseFold y@
538+-- The result string may be longer than the input string, and may
539+-- differ from applying 'toLower' to the input string. For instance,
540+-- the Armenian small ligature \"ﬓ\" (men now, U+FB13) is case
541+-- folded to the sequence \"մ\" (men, U+0574) followed by
542+-- \"ն\" (now, U+0576), while the Greek \"µ\" (micro sign,
543+-- U+00B5) is case folded to \"μ\" (small letter mu, U+03BC)
544+-- instead of itself.
545+toCaseFold :: JSString -> JSString
546+toCaseFold = coerce T.toCaseFold
547+{-# INLINE [0] toCaseFold #-}
549+-- | /O(n)/ Convert a string to lower case, using simple case
550+-- conversion. Subject to fusion.
552+-- The result string may be longer than the input string. For
553+-- instance, \"İ\" (Latin capital letter I with dot above,
554+-- U+0130) maps to the sequence \"i\" (Latin small letter i, U+0069)
555+-- followed by \" ̇\" (combining dot above, U+0307).
556+toLower :: JSString -> JSString
557+toLower = coerce T.toLower
558+{-# INLINE [1] toLower #-}
561+"JSSTRING toLower -> fused" [~1] forall x.
562+ toLower x = unstream (S.toLower (stream x))
563+"JSSTRING toLower -> unfused" [1] forall x.
564+ unstream (S.toLower (stream x)) = toLower x
567+-- | /O(n)/ Convert a string to upper case, using simple case
568+-- conversion. Subject to fusion.
570+-- The result string may be longer than the input string. For
571+-- instance, the German \"ß\" (eszett, U+00DF) maps to the
572+-- two-letter sequence \"SS\".
573+toUpper :: JSString -> JSString
574+toUpper = coerce T.toUpper
575+{-# INLINE [1] toUpper #-}
578+"JSSTRING toUpper -> fused" [~1] forall x.
579+ toUpper x = unstream (S.toUpper(stream x))
580+"JSSTRING toUpper -> unfused" [1] forall x.
581+ unstream (S.toUpper (stream x)) = toUpper x
584+-- | /O(n)/ Convert a string to title case, using simple case
585+-- conversion. Subject to fusion.
587+-- The first letter of the input is converted to title case, as is
588+-- every subsequent letter that immediately follows a non-letter.
589+-- Every letter that immediately follows another letter is converted
592+-- The result string may be longer than the input string. For example,
593+-- the Latin small ligature fl (U+FB02) is converted to the
594+-- sequence Latin capital letter F (U+0046) followed by Latin small
595+-- letter l (U+006C).
597+-- /Note/: this function does not take language or culture specific
598+-- rules into account. For instance, in English, different style
599+-- guides disagree on whether the book name \"The Hill of the Red
600+-- Fox\" is correctly title cased—but this function will
601+-- capitalize /every/ word.
602+toTitle :: JSString -> JSString
603+toTitle = coerce T.toTitle
604+{-# INLINE toTitle #-}
606+-- | /O(n)/ Left-justify a string to the given length, using the
607+-- specified fill character on the right. Subject to fusion.
608+-- Performs replacement on invalid scalar values.
612+-- > justifyLeft 7 'x' "foo" == "fooxxxx"
613+-- > justifyLeft 3 'x' "foobar" == "foobar"
614+justifyLeft :: Int -> Char -> JSString -> JSString
615+justifyLeft = coerce T.justifyLeft
616+{-# INLINE [1] justifyLeft #-}
619+"JSSTRING justifyLeft -> fused" [~1] forall k c t.
620+ justifyLeft k c t = unstream (S.justifyLeftI k c (stream t))
621+"JSSTRING justifyLeft -> unfused" [1] forall k c t.
622+ unstream (S.justifyLeftI k c (stream t)) = justifyLeft k c t
625+-- | /O(n)/ Right-justify a string to the given length, using the
626+-- specified fill character on the left. Performs replacement on
627+-- invalid scalar values.
631+-- > justifyRight 7 'x' "bar" == "xxxxbar"
632+-- > justifyRight 3 'x' "foobar" == "foobar"
633+justifyRight :: Int -> Char -> JSString -> JSString
634+justifyRight = coerce T.justifyRight
635+{-# INLINE justifyRight #-}
637+-- | /O(n)/ Center a string to the given length, using the specified
638+-- fill character on either side. Performs replacement on invalid
643+-- > center 8 'x' "HS" = "xxxHSxxx"
644+center :: Int -> Char -> JSString -> JSString
645+center = coerce T.center
646+{-# INLINE center #-}
648+-- | /O(n)/ The 'transpose' function transposes the rows and columns
649+-- of its 'JSString' argument. Note that this function uses 'pack',
650+-- 'unpack', and the list version of transpose, and is thus not very
652+transpose :: [JSString] -> [JSString]
653+transpose = coerce T.transpose
655+-- -----------------------------------------------------------------------------
656+-- * Reducing 'JSString's (folds)
658+-- | /O(n)/ 'foldl', applied to a binary operator, a starting value
659+-- (typically the left-identity of the operator), and a 'JSString',
660+-- reduces the 'JSString' using the binary operator, from left to right.
661+-- Subject to fusion.
662+foldl :: (a -> Char -> a) -> a -> JSString -> a
663+foldl f = coerce (T.foldl f)
666+-- | /O(n)/ A strict version of 'foldl'. Subject to fusion.
667+foldl' :: (a -> Char -> a) -> a -> JSString -> a
668+foldl' f = coerce (T.foldl' f)
669+{-# INLINE foldl' #-}
671+-- | /O(n)/ A variant of 'foldl' that has no starting value argument,
672+-- and thus must be applied to a non-empty 'JSString'. Subject to fusion.
673+foldl1 :: (Char -> Char -> Char) -> JSString -> Char
674+foldl1 = coerce T.foldl1
675+{-# INLINE foldl1 #-}
677+-- | /O(n)/ A strict version of 'foldl1'. Subject to fusion.
678+foldl1' :: (Char -> Char -> Char) -> JSString -> Char
679+foldl1' = coerce T.foldl1'
680+{-# INLINE foldl1' #-}
682+-- | /O(n)/ 'foldr', applied to a binary operator, a starting value
683+-- (typically the right-identity of the operator), and a 'JSString',
684+-- reduces the 'JSString' using the binary operator, from right to left.
685+-- Subject to fusion.
686+foldr :: (Char -> a -> a) -> a -> JSString -> a
687+foldr f = coerce (T.foldr f)
690+-- | /O(n)/ A variant of 'foldr' that has no starting value argument,
691+-- and thus must be applied to a non-empty 'JSString'. Subject to
693+foldr1 :: (Char -> Char -> Char) -> JSString -> Char
694+foldr1 = coerce T.foldr1
695+{-# INLINE foldr1 #-}
697+-- -----------------------------------------------------------------------------
700+-- | /O(n)/ Concatenate a list of 'JSString's.
701+concat :: [JSString] -> JSString
702+concat = coerce T.concat
704+-- | /O(n)/ Map a function over a 'JSString' that results in a 'JSString', and
705+-- concatenate the results.
706+concatMap :: (Char -> JSString) -> JSString -> JSString
707+concatMap = coerce T.concatMap
708+{-# INLINE concatMap #-}
710+-- | /O(n)/ 'any' @p@ @t@ determines whether any character in the
711+-- 'JSString' @t@ satisifes the predicate @p@. Subject to fusion.
712+any :: (Char -> Bool) -> JSString -> Bool
716+-- | /O(n)/ 'all' @p@ @t@ determines whether all characters in the
717+-- 'JSString' @t@ satisify the predicate @p@. Subject to fusion.
718+all :: (Char -> Bool) -> JSString -> Bool
722+-- | /O(n)/ 'maximum' returns the maximum value from a 'JSString', which
723+-- must be non-empty. Subject to fusion.
724+maximum :: JSString -> Char
725+maximum = coerce T.maximum
726+{-# INLINE maximum #-}
728+-- | /O(n)/ 'minimum' returns the minimum value from a 'JSString', which
729+-- must be non-empty. Subject to fusion.
730+minimum :: JSString -> Char
731+minimum = coerce T.minimum
732+{-# INLINE minimum #-}
734+-- -----------------------------------------------------------------------------
735+-- * Building 'JSString's
737+-- | /O(n)/ 'scanl' is similar to 'foldl', but returns a list of
738+-- successive reduced values from the left. Subject to fusion.
739+-- Performs replacement on invalid scalar values.
741+-- > scanl f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...]
745+-- > last (scanl f z xs) == foldl f z xs.
746+scanl :: (Char -> Char -> Char) -> Char -> JSString -> JSString
747+scanl = coerce T.scanl
750+-- | /O(n)/ 'scanl1' is a variant of 'scanl' that has no starting
751+-- value argument. Subject to fusion. Performs replacement on
752+-- invalid scalar values.
754+-- > scanl1 f [x1, x2, ...] == [x1, x1 `f` x2, ...]
755+scanl1 :: (Char -> Char -> Char) -> JSString -> JSString
756+scanl1 = coerce T.scanl1
757+{-# INLINE scanl1 #-}
759+-- | /O(n)/ 'scanr' is the right-to-left dual of 'scanl'. Performs
760+-- replacement on invalid scalar values.
762+-- > scanr f v == reverse . scanl (flip f) v . reverse
763+scanr :: (Char -> Char -> Char) -> Char -> JSString -> JSString
764+scanr = coerce T.scanr
767+-- | /O(n)/ 'scanr1' is a variant of 'scanr' that has no starting
768+-- value argument. Subject to fusion. Performs replacement on
769+-- invalid scalar values.
770+scanr1 :: (Char -> Char -> Char) -> JSString -> JSString
771+scanr1 = coerce T.scanr1
772+{-# INLINE scanr1 #-}
774+-- | /O(n)/ Like a combination of 'map' and 'foldl''. Applies a
775+-- function to each element of a 'JSString', passing an accumulating
776+-- parameter from left to right, and returns a final 'JSString'. Performs
777+-- replacement on invalid scalar values.
778+mapAccumL :: (a -> Char -> (a,Char)) -> a -> JSString -> (a, JSString)
779+mapAccumL f = coerce (T.mapAccumL f)
780+{-# INLINE mapAccumL #-}
782+-- | The 'mapAccumR' function behaves like a combination of 'map' and
783+-- a strict 'foldr'; it applies a function to each element of a
784+-- 'JSString', passing an accumulating parameter from right to left, and
785+-- returning a final value of this accumulator together with the new
787+-- Performs replacement on invalid scalar values.
788+mapAccumR :: (a -> Char -> (a,Char)) -> a -> JSString -> (a, JSString)
789+mapAccumR f = coerce (T.mapAccumR f)
790+{-# INLINE mapAccumR #-}
792+-- -----------------------------------------------------------------------------
793+-- ** Generating and unfolding 'JSString's
795+-- | /O(n*m)/ 'replicate' @n@ @t@ is a 'JSString' consisting of the input
796+-- @t@ repeated @n@ times.
797+replicate :: Int -> JSString -> JSString
798+replicate = coerce T.replicate
799+{-# INLINE [1] replicate #-}
801+-- | /O(n)/, where @n@ is the length of the result. The 'unfoldr'
802+-- function is analogous to the List 'L.unfoldr'. 'unfoldr' builds a
803+-- 'JSString' from a seed value. The function takes the element and
804+-- returns 'Nothing' if it is done producing the 'JSString', otherwise
805+-- 'Just' @(a,b)@. In this case, @a@ is the next 'Char' in the
806+-- string, and @b@ is the seed value for further production. Subject
807+-- to fusion. Performs replacement on invalid scalar values.
808+unfoldr :: (a -> Maybe (Char,a)) -> a -> JSString
809+unfoldr f = coerce (T.unfoldr f)
810+{-# INLINE unfoldr #-}
812+-- | /O(n)/ Like 'unfoldr', 'unfoldrN' builds a 'JSString' from a seed
813+-- value. However, the length of the result should be limited by the
814+-- first argument to 'unfoldrN'. This function is more efficient than
815+-- 'unfoldr' when the maximum length of the result is known and
816+-- correct, otherwise its performance is similar to 'unfoldr'. Subject
817+-- to fusion. Performs replacement on invalid scalar values.
818+unfoldrN :: Int -> (a -> Maybe (Char,a)) -> a -> JSString
819+unfoldrN n f = coerce (T.unfoldrN n f)
820+{-# INLINE unfoldrN #-}
822+-- -----------------------------------------------------------------------------
825+-- | /O(n)/ 'take' @n@, applied to a 'JSString', returns the prefix of the
826+-- 'JSString' of length @n@, or the 'JSString' itself if @n@ is greater than
827+-- the length of the JSString. Subject to fusion.
828+take :: Int -> JSString -> JSString
830+{-# INLINE [1] take #-}
832+iterN :: Int -> JSString -> Int
833+iterN n t@(Text _arr _off len) = loop 0 0
835+ | i >= len || cnt >= n = i
836+ | otherwise = loop (i+d) (cnt+1)
840+"JSSTRING take -> fused" [~1] forall n t.
841+ take n t = unstream (S.take n (stream t))
842+"JSSTRING take -> unfused" [1] forall n t.
843+ unstream (S.take n (stream t)) = take n t
846+-- | /O(n)/ 'takeEnd' @n@ @t@ returns the suffix remaining after
847+-- taking @n@ characters from the end of @t@.
851+-- > takeEnd 3 "foobar" == "bar"
852+takeEnd :: Int -> JSString -> JSString
853+takeEnd = coerce T.takeEnd
855+-- | /O(n)/ 'drop' @n@, applied to a 'JSString', returns the suffix of the
856+-- 'JSString' after the first @n@ characters, or the empty 'JSString' if @n@
857+-- is greater than the length of the 'JSString'. Subject to fusion.
858+drop :: Int -> JSString -> JSString
860+{-# INLINE [1] drop #-}
863+"JSSTRING drop -> fused" [~1] forall n t.
864+ drop n t = unstream (S.drop n (stream t))
865+"JSSTRING drop -> unfused" [1] forall n t.
866+ unstream (S.drop n (stream t)) = drop n t
869+-- | /O(n)/ 'dropEnd' @n@ @t@ returns the prefix remaining after
870+-- dropping @n@ characters from the end of @t@.
874+-- > dropEnd 3 "foobar" == "foo"
875+dropEnd :: Int -> JSString -> JSString
876+dropEnd = coerce T.dropEnd
878+-- | /O(n)/ 'takeWhile', applied to a predicate @p@ and a 'JSString',
879+-- returns the longest prefix (possibly empty) of elements that
880+-- satisfy @p@. Subject to fusion.
881+takeWhile :: (Char -> Bool) -> JSString -> JSString
882+takeWhile = coerce T.takeWhile
883+{-# INLINE [1] takeWhile #-}
886+"TEXT takeWhile -> fused" [~1] forall p t.
887+ takeWhile p t = unstream (S.takeWhile p (stream t))
888+"TEXT takeWhile -> unfused" [1] forall p t.
889+ unstream (S.takeWhile p (stream t)) = takeWhile p t
892+-- | /O(n)/ 'dropWhile' @p@ @t@ returns the suffix remaining after
893+-- 'takeWhile' @p@ @t@. Subject to fusion.
894+dropWhile :: (Char -> Bool) -> JSString -> JSString
895+dropWhile = coerce T.dropWhile
896+{-# INLINE [1] dropWhile #-}
899+"TEXT dropWhile -> fused" [~1] forall p t.
900+ dropWhile p t = unstream (S.dropWhile p (stream t))
901+"TEXT dropWhile -> unfused" [1] forall p t.
902+ unstream (S.dropWhile p (stream t)) = dropWhile p t
905+-- | /O(n)/ 'dropWhileEnd' @p@ @t@ returns the prefix remaining after
906+-- dropping characters that fail the predicate @p@ from the end of
907+-- @t@. Subject to fusion.
910+-- > dropWhileEnd (=='.') "foo..." == "foo"
911+dropWhileEnd :: (Char -> Bool) -> JSString -> JSString
912+dropWhileEnd = coerce T.dropWhileEnd
913+{-# INLINE [1] dropWhileEnd #-}
916+"TEXT dropWhileEnd -> fused" [~1] forall p t.
917+ dropWhileEnd p t = S.reverse (S.dropWhile p (S.reverseStream t))
918+"TEXT dropWhileEnd -> unfused" [1] forall p t.
919+ S.reverse (S.dropWhile p (S.reverseStream t)) = dropWhileEnd p t
922+-- | /O(n)/ 'dropAround' @p@ @t@ returns the substring remaining after
923+-- dropping characters that fail the predicate @p@ from both the
924+-- beginning and end of @t@. Subject to fusion.
925+dropAround :: (Char -> Bool) -> JSString -> JSString
926+dropAround = coerce T.dropAround
927+{-# INLINE [1] dropAround #-}
929+-- | /O(n)/ Remove leading white space from a string. Equivalent to:
931+-- > dropWhile isSpace
932+stripStart :: JSString -> JSString
933+stripStart = coerce T.stripStart
934+{-# INLINE [1] stripStart #-}
936+-- | /O(n)/ Remove trailing white space from a string. Equivalent to:
938+-- > dropWhileEnd isSpace
939+stripEnd :: JSString -> JSString
940+stripEnd = coerce T.stripEnd
941+{-# INLINE [1] stripEnd #-}
943+-- | /O(n)/ Remove leading and trailing white space from a string.
946+-- > dropAround isSpace
947+strip :: JSString -> JSString
948+strip = coerce T.strip
949+{-# INLINE [1] strip #-}
951+-- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a
952+-- prefix of @t@ of length @n@, and whose second is the remainder of
953+-- the string. It is equivalent to @('take' n t, 'drop' n t)@.
954+splitAt :: Int -> JSString -> (JSString, JSString)
955+splitAt = coerce T.splitAt
956+{-# INLINE splitAt #-}
958+-- | /O(n)/ 'span', applied to a predicate @p@ and text @t@, returns
959+-- a pair whose first element is the longest prefix (possibly empty)
960+-- of @t@ of elements that satisfy @p@, and whose second is the
961+-- remainder of the list.
962+span :: (Char -> Bool) -> JSString -> (JSString, JSString)
966+-- | /O(n)/ 'break' is like 'span', but the prefix returned is
967+-- over elements that fail the predicate @p@.
968+break :: (Char -> Bool) -> JSString -> (JSString, JSString)
969+break = coerce T.break
972+-- | /O(n)/ Group characters in a string according to a predicate.
973+groupBy :: (Char -> Char -> Bool) -> JSString -> [JSString]
974+groupBy = coerce T.groupBy
976+-- | /O(n)/ Group characters in a string by equality.
977+group :: JSString -> [JSString]
978+group = coerce T.group
981+group' :: JSString -> [JSString]
982+group' = coerce T.group
983+{-# INLINE group' #-}
985+-- | /O(n^2)/ Return all initial segments of the given 'JSString', shortest
987+inits :: JSString -> [JSString]
988+inits = coerce T.inits
990+-- | /O(n^2)/ Return all final segments of the given 'JSString', longest
992+tails :: JSString -> [JSString]
993+tails = coerce T.tails
997+-- Splitting functions in this library do not perform character-wise
998+-- copies to create substrings; they just construct new 'JSString's that
999+-- are slices of the original.
1001+-- | /O(m+n)/ Break a 'JSString' into pieces separated by the first 'JSString'
1002+-- argument (which cannot be empty), consuming the delimiter. An empty
1003+-- delimiter is invalid, and will cause an error to be raised.
1007+-- > splitOn "\r\n" "a\r\nb\r\nd\r\ne" == ["a","b","d","e"]
1008+-- > splitOn "aaa" "aaaXaaaXaaaXaaa" == ["","X","X","X",""]
1009+-- > splitOn "x" "x" == ["",""]
1013+-- > intercalate s . splitOn s == id
1014+-- > splitOn (singleton c) == split (==c)
1016+-- (Note: the string @s@ to split on above cannot be empty.)
1018+-- In (unlikely) bad cases, this function's time complexity degrades
1019+-- towards /O(n*m)/.
1021+ -- ^ String to split on. If this string is empty, an error
1026+splitOn = coerce T.splitOn
1027+{-# INLINE [1] splitOn #-}
1030+-- "JSSTRING splitOn/singleton -> split/==" [~1] forall c t.
1031+-- splitOn (singleton c) t = split (==c) t
1034+splitOn' :: JSString
1035+ -- ^ String to split on. If this string is empty, an error
1040+splitOn' = coerce T.splitOn
1041+{-# NOINLINE splitOn' #-}
1042+--- {-# INLINE [1] splitOn' #-}
1044+-- | /O(n)/ Splits a 'JSString' into components delimited by separators,
1045+-- where the predicate returns True for a separator element. The
1046+-- resulting components do not contain the separators. Two adjacent
1047+-- separators result in an empty component in the output. eg.
1049+-- > split (=='a') "aabbaca" == ["","","bb","c",""]
1050+-- > split (=='a') "" == [""]
1051+split :: (Char -> Bool) -> JSString -> [JSString]
1052+split = coerce T.split
1053+{-# INLINE split #-}
1055+-- | /O(n)/ Splits a 'JSString' into components of length @k@. The last
1056+-- element may be shorter than the other chunks, depending on the
1057+-- length of the input. Examples:
1059+-- > chunksOf 3 "foobarbaz" == ["foo","bar","baz"]
1060+-- > chunksOf 4 "haskell.org" == ["hask","ell.","org"]
1061+chunksOf :: Int -> JSString -> [JSString]
1062+chunksOf = coerce T.chunksOf
1063+{-# INLINE chunksOf #-}
1065+-- | /O(n)/ Splits a 'JSString' into components of length @k@. The last
1066+-- element may be shorter than the other chunks, depending on the
1067+-- length of the input. Examples:
1069+-- > chunksOf 3 "foobarbaz" == ["foo","bar","baz"]
1070+-- > chunksOf 4 "haskell.org" == ["hask","ell.","org"]
1071+chunksOf' :: Int -> JSString -> [JSString]
1072+chunksOf' = coerce T.chunksOf
1073+{-# INLINE chunksOf' #-}
1075+-- ----------------------------------------------------------------------------
1078+-------------------------------------------------------------------------------
1079+-- ** Searching with a predicate
1081+-- | /O(n)/ The 'find' function takes a predicate and a 'JSString', and
1082+-- returns the first element matching the predicate, or 'Nothing' if
1083+-- there is no such element.
1084+find :: (Char -> Bool) -> JSString -> Maybe Char
1085+find = coerce T.find
1088+-- | /O(n)/ The 'partition' function takes a predicate and a 'JSString',
1089+-- and returns the pair of 'JSString's with elements which do and do not
1090+-- satisfy the predicate, respectively; i.e.
1092+-- > partition p t == (filter p t, filter (not . p) t)
1093+partition :: (Char -> Bool) -> JSString -> (JSString, JSString)
1094+partition = coerce T.partition
1095+{-# INLINE partition #-}
1097+-- | /O(n)/ 'filter', applied to a predicate and a 'JSString',
1098+-- returns a 'JSString' containing those characters that satisfy the
1100+filter :: (Char -> Bool) -> JSString -> JSString
1101+filter = coerce T.filter
1102+{-# INLINE filter #-}
1104+-- | /O(n+m)/ Find the first instance of @needle@ (which must be
1105+-- non-'null') in @haystack@. The first element of the returned tuple
1106+-- is the prefix of @haystack@ before @needle@ is matched. The second
1107+-- is the remainder of @haystack@, starting with the match.
1111+-- > breakOn "::" "a::b::c" ==> ("a", "::b::c")
1112+-- > breakOn "/" "foobar" ==> ("foobar", "")
1116+-- > append prefix match == haystack
1117+-- > where (prefix, match) = breakOn needle haystack
1119+-- If you need to break a string by a substring repeatedly (e.g. you
1120+-- want to break on every instance of a substring), use 'breakOnAll'
1121+-- instead, as it has lower startup overhead.
1123+-- In (unlikely) bad cases, this function's time complexity degrades
1124+-- towards /O(n*m)/.
1125+breakOn :: JSString -> JSString -> (JSString, JSString)
1126+breakOn = coerce T.breakOn
1127+{-# INLINE breakOn #-}
1129+-- | /O(n+m)/ Similar to 'breakOn', but searches from the end of the
1132+-- The first element of the returned tuple is the prefix of @haystack@
1133+-- up to and including the last match of @needle@. The second is the
1134+-- remainder of @haystack@, following the match.
1136+-- > breakOnEnd "::" "a::b::c" ==> ("a::b::", "c")
1137+breakOnEnd :: JSString -> JSString -> (JSString, JSString)
1138+breakOnEnd = coerce T.breakOnEnd
1139+{-# INLINE breakOnEnd #-}
1141+-- | /O(n+m)/ Find all non-overlapping instances of @needle@ in
1142+-- @haystack@. Each element of the returned list consists of a pair:
1144+-- * The entire string prior to the /k/th match (i.e. the prefix)
1146+-- * The /k/th match, followed by the remainder of the string
1150+-- > breakOnAll "::" ""
1152+-- > breakOnAll "/" "a/b/c/"
1153+-- > ==> [("a", "/b/c/"), ("a/b", "/c/"), ("a/b/c", "/")]
1155+-- In (unlikely) bad cases, this function's time complexity degrades
1156+-- towards /O(n*m)/.
1158+-- The @needle@ parameter may not be empty.
1159+breakOnAll :: JSString -- ^ @needle@ to search for
1160+ -> JSString -- ^ @haystack@ in which to search
1161+ -> [(JSString, JSString)]
1162+breakOnAll = coerce T.breakOnAll
1163+{-# INLINE breakOnAll #-}
1165+breakOnAll' :: JSString -- ^ @needle@ to search for
1166+ -> JSString -- ^ @haystack@ in which to search
1167+ -> [(JSString, JSString)]
1168+breakOnAll' = coerce T.breakOnAll
1169+{-# INLINE breakOnAll' #-}
1171+-------------------------------------------------------------------------------
1172+-- ** Indexing 'JSString's
1176+-- If you think of a 'JSString' value as an array of 'Char' values (which
1177+-- it is not), you run the risk of writing inefficient code.
1179+-- An idiom that is common in some languages is to find the numeric
1180+-- offset of a character or substring, then use that number to split
1181+-- or trim the searched string. With a 'JSString' value, this approach
1182+-- would require two /O(n)/ operations: one to perform the search, and
1183+-- one to operate from wherever the search ended.
1185+-- For example, suppose you have a string that you want to split on
1186+-- the substring @\"::\"@, such as @\"foo::bar::quux\"@. Instead of
1187+-- searching for the index of @\"::\"@ and taking the substrings
1188+-- before and after that index, you would instead use @breakOnAll \"::\"@.
1190+-- | /O(n)/ 'JSString' index (subscript) operator, starting from 0.
1191+index :: JSString -> Int -> Char
1192+index = coerce T.index
1193+{-# INLINE index #-}
1195+-- | /O(n)/ The 'findIndex' function takes a predicate and a 'JSString'
1196+-- and returns the index of the first element in the 'JSString' satisfying
1197+-- the predicate. Subject to fusion.
1198+findIndex :: (Char -> Bool) -> JSString -> Maybe Int
1199+findIndex = coerce T.findIndex
1200+{-# INLINE findIndex #-}
1202+-- | /O(n+m)/ The 'count' function returns the number of times the
1203+-- query string appears in the given 'JSString'. An empty query string is
1204+-- invalid, and will cause an error to be raised.
1206+-- In (unlikely) bad cases, this function's time complexity degrades
1207+-- towards /O(n*m)/.
1208+count :: JSString -> JSString -> Int
1209+count = coerce T.count
1210+{-# INLINE [1] count #-}
1213+-- "JSSTRING count/singleton -> countChar" [~1] forall c t.
1214+-- count (singleton c) t = countChar c t
1217+-------------------------------------------------------------------------------
1220+-- | /O(n)/ 'zip' takes two 'JSString's and returns a list of
1221+-- corresponding pairs of bytes. If one input 'JSString' is short,
1222+-- excess elements of the longer 'JSString' are discarded. This is
1223+-- equivalent to a pair of 'unpack' operations.
1224+zip :: JSString -> JSString -> [(Char,Char)]
1226+{-# INLINE [0] zip #-}
1228+-- | /O(n)/ 'zipWith' generalises 'zip' by zipping with the function
1229+-- given as the first argument, instead of a tupling function.
1230+-- Performs replacement on invalid scalar values.
1231+zipWith :: (Char -> Char -> Char) -> JSString -> JSString -> JSString
1232+zipWith = coerce T.zipWith
1233+{-# INLINE [0] zipWith #-}
1235+-- | /O(n)/ Breaks a 'JSString' up into a list of words, delimited by 'Char's
1236+-- representing white space.
1237+words :: JSString -> [JSString]
1238+words = coerce T.words
1239+{-# INLINE words #-}
1241+-- fixme: strict words' that allocates the whole list in one go
1242+words' :: JSString -> [JSString]
1243+words' = coerce T.words
1244+{-# INLINE words' #-}
1246+-- | /O(n)/ Breaks a 'JSString' up into a list of 'JSString's at
1247+-- newline 'Char's. The resulting strings do not contain newlines.
1248+lines :: JSString -> [JSString]
1249+lines = coerce T.lines
1250+{-# INLINE lines #-}
1252+lines' :: JSString -> [JSString]
1253+lines' = coerce T.lines
1254+{-# INLINE lines' #-}
1257+-- | /O(n)/ Portably breaks a 'JSString' up into a list of 'JSString's at line
1260+-- A line boundary is considered to be either a line feed, a carriage
1261+-- return immediately followed by a line feed, or a carriage return.
1262+-- This accounts for both Unix and Windows line ending conventions,
1263+-- and for the old convention used on Mac OS 9 and earlier.
1264+lines' :: Text -> [Text]
1265+lines' ps | null ps = []
1266+ | otherwise = h : case uncons t of
1269+ | c == '\n' -> lines t'
1270+ | c == '\r' -> case uncons t' of
1271+ Just ('\n',t'') -> lines t''
1273+ where (h,t) = span notEOL ps
1274+ notEOL c = c /= '\n' && c /= '\r'
1278+-- | /O(n)/ Joins lines, after appending a terminating newline to
1280+unlines :: [JSString] -> JSString
1281+unlines = coerce T.unlines
1282+{-# INLINE unlines #-}
1284+-- | /O(n)/ Joins words using single space characters.
1285+unwords :: [JSString] -> JSString
1286+unwords = coerce T.unwords
1287+{-# INLINE unwords #-}
1289+-- | /O(n)/ The 'isPrefixOf' function takes two 'JSString's and returns
1290+-- 'True' iff the first is a prefix of the second. Subject to fusion.
1291+isPrefixOf :: JSString -> JSString -> Bool
1292+isPrefixOf = coerce T.isPrefixOf
1293+{-# INLINE [1] isPrefixOf #-}
1296+"JSSTRING isPrefixOf -> fused" [~1] forall x y.
1297+ isPrefixOf x y = S.isPrefixOf (stream x) (stream y)
1298+"JSSTRING isPrefixOf -> unfused" [1] forall x y.
1299+ S.isPrefixOf (stream x) (stream y) = isPrefixOf x y
1302+-- | /O(n)/ The 'isSuffixOf' function takes two 'JSString's and returns
1303+-- 'True' iff the first is a suffix of the second.
1304+isSuffixOf :: JSString -> JSString -> Bool
1305+isSuffixOf = coerce T.isSuffixOf
1306+{-# INLINE isSuffixOf #-}
1308+-- | The 'isInfixOf' function takes two 'JSString's and returns
1309+-- 'True' iff the first is contained, wholly and intact, anywhere
1310+-- within the second.
1312+-- Complexity depends on how the JavaScript engine implements
1313+-- String.prototype.find.
1314+isInfixOf :: JSString -> JSString -> Bool
1315+isInfixOf = coerce T.isInfixOf
1316+{-# INLINE [1] isInfixOf #-}
1319+"JSSTRING isInfixOf/singleton -> S.elem/S.stream" [~1] forall n h.
1320+ isInfixOf (singleton n) h = S.elem n (S.stream h)
1323+-------------------------------------------------------------------------------
1326+-- | /O(n)/ Return the suffix of the second string if its prefix
1327+-- matches the entire first string.
1331+-- > stripPrefix "foo" "foobar" == Just "bar"
1332+-- > stripPrefix "" "baz" == Just "baz"
1333+-- > stripPrefix "foo" "quux" == Nothing
1335+-- This is particularly useful with the @ViewPatterns@ extension to
1338+-- > {-# LANGUAGE ViewPatterns #-}
1339+-- > import Data.Text as T
1341+-- > fnordLength :: JSString -> Int
1342+-- > fnordLength (stripPrefix "fnord" -> Just suf) = T.length suf
1343+-- > fnordLength _ = -1
1344+stripPrefix :: JSString -> JSString -> Maybe JSString
1345+stripPrefix = coerce T.stripPrefix
1346+{-# INLINE stripPrefix #-}
1348+-- | /O(n)/ Find the longest non-empty common prefix of two strings
1349+-- and return it, along with the suffixes of each string at which they
1352+-- If the strings do not have a common prefix or either one is empty,
1353+-- this function returns 'Nothing'.
1357+-- > commonPrefixes "foobar" "fooquux" == Just ("foo","bar","quux")
1358+-- > commonPrefixes "veeble" "fetzer" == Nothing
1359+-- > commonPrefixes "" "baz" == Nothing
1360+commonPrefixes :: JSString -> JSString -> Maybe (JSString,JSString,JSString)
1361+commonPrefixes = coerce T.commonPrefixes
1362+{-# INLINE commonPrefixes #-}
1364+-- | /O(n)/ Return the prefix of the second string if its suffix
1365+-- matches the entire first string.
1369+-- > stripSuffix "bar" "foobar" == Just "foo"
1370+-- > stripSuffix "" "baz" == Just "baz"
1371+-- > stripSuffix "foo" "quux" == Nothing
1373+-- This is particularly useful with the @ViewPatterns@ extension to
1376+-- > {-# LANGUAGE ViewPatterns #-}
1377+-- > import Data.Text as T
1379+-- > quuxLength :: Text -> Int
1380+-- > quuxLength (stripSuffix "quux" -> Just pre) = T.length pre
1381+-- > quuxLength _ = -1
1382+stripSuffix :: JSString -> JSString -> Maybe JSString
1383+stripSuffix = coerce T.stripSuffix
1384+{-# INLINE stripSuffix #-}
1386+---- | Add a list of non-negative numbers. Errors out on overflow.
1387+--sumP :: String -> [Int] -> Int
1389+-- where go !a (x:xs)
1390+-- | ax >= 0 = go ax xs
1391+-- | otherwise = overflowError fun
1395+--emptyError :: String -> a
1396+--emptyError fun = P.error $ "Data.JSString." ++ fun ++ ": empty input"
1398+--overflowError :: String -> a
1399+--overflowError fun = P.error $ "Data.JSString." ++ fun ++ ": size overflow"
1401+--charWidth :: Int# -> Int#
1402+--charWidth cp | isTrue# (cp >=# 0x10000#) = 2#
1404+--{-# INLINE charWidth #-}