@@ -1,1404 +0,0 @@
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 #-}