@@ -0,0 +1,1404 @@
1+{-# LANGUAGE MagicHash, BangPatterns, UnboxedTuples, TypeFamilies
2+ #-}
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.
6+ -}
7+module Data.JSString ( JSString
8+
9+ -- * Creation and elimination
10+ , pack
11+ , unpack, unpack'
12+ , singleton
13+ , empty
14+
15+ -- * Basic interface
16+ , cons
17+ , snoc
18+ , append
19+ , uncons
20+ , head
21+ , last
22+ , tail
23+ , init
24+ , null
25+ , length
26+ , compareLength
27+
28+ -- * Transformations
29+ , map
30+ , intercalate
31+ , intersperse
32+ , transpose
33+ , reverse
34+ , replace
35+
36+ -- ** Case conversion
37+ , toCaseFold
38+ , toLower
39+ , toUpper
40+ , toTitle
41+
42+ -- ** Justification
43+ , justifyLeft
44+ , justifyRight
45+ , center
46+
47+ -- * Folds
48+ , foldl
49+ , foldl'
50+ , foldl1
51+ , foldl1'
52+ , foldr
53+ , foldr1
54+
55+ -- ** Special folds
56+ , concat
57+ , concatMap
58+ , any
59+ , all
60+ , maximum
61+ , minimum
62+
63+ -- * Construction
64+
65+ -- ** Scans
66+ , scanl
67+ , scanl1
68+ , scanr
69+ , scanr1
70+
71+ -- ** Accumulating maps
72+ , mapAccumL
73+ , mapAccumR
74+
75+ -- ** Generation and unfolding
76+ , replicate
77+ , unfoldr
78+ , unfoldrN
79+
80+ -- * Substrings
81+
82+ -- ** Breaking strings
83+ , take
84+ , takeEnd
85+ , drop
86+ , dropEnd
87+ , takeWhile
88+ , dropWhile
89+ , dropWhileEnd
90+ , dropAround
91+ , strip
92+ , stripStart
93+ , stripEnd
94+ , splitAt
95+ , breakOn
96+ , breakOnEnd
97+ , break
98+ , span
99+ , group
100+ , group'
101+ , groupBy
102+ , inits
103+ , tails
104+
105+ -- ** Breaking into many substrings
106+ , splitOn, splitOn'
107+ , split
108+ , chunksOf, chunksOf'
109+
110+ -- ** Breaking into lines and words
111+ , lines, lines'
112+ , words, words'
113+ , unlines
114+ , unwords
115+
116+ -- * Predicates
117+ , isPrefixOf
118+ , isSuffixOf
119+ , isInfixOf
120+
121+ -- ** View patterns
122+ , stripPrefix
123+ , stripSuffix
124+ , commonPrefixes
125+
126+ -- * Searching
127+ , filter
128+ , breakOnAll, breakOnAll'
129+ , find
130+ , partition
131+
132+ -- * Indexing
133+ , index
134+ , findIndex
135+ , count
136+
137+ -- * Zipping
138+ , zip
139+ , zipWith
140+ ) where
141+
142+import Prelude
143+ ( Char, Bool(..), Int, Maybe(..), String, Eq(..), Ord(..), Ordering(..), (++)
144+ , Read(..), Show(..), (&&), (||), (+), (-), (.), ($), ($!), (>>)
145+ , not, seq, return, otherwise, quot)
146+import qualified Prelude as P
147+
148+import Control.DeepSeq (NFData(..))
149+import Data.Char (isSpace)
150+import Data.Coerce (coerce)
151+import qualified Data.List as L
152+import Data.Data
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
156+
157+import GHC.Exts
158+ ( Int#, (+#), (-#), (>=#), (>#), isTrue#, chr#, Char(..)
159+ , Int(..), Addr#, tagToEnum#)
160+import qualified GHC.Exts as Exts
161+import qualified GHC.CString as GHC
162+
163+import Unsafe.Coerce
164+
165+import GHCJS.Prim (JSVal)
166+
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
171+
172+instance Exts.IsList JSString where
173+ type Item JSString = Char
174+ fromList = pack
175+ toList = unpack
176+
177+-- -----------------------------------------------------------------------------
178+-- * Conversion to/from 'JSString'
179+
180+-- | /O(n)/ Convert a 'String' into a 'JSString'. Subject to
181+-- fusion.
182+pack :: String -> JSString
183+pack = coerce T.pack
184+{-# INLINE [1] pack #-}
185+
186+{-# RULES
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
191+ #-}
192+
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 #-}
197+
198+unpack' :: JSString -> String
199+unpack' = coerce T.unpack
200+{-# INLINE unpack' #-}
201+
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# #-}
206+
207+{-# RULES "JSSTRING literal" forall a.
208+ unstream (S.map safe (S.streamList (GHC.unpackCString# a)))
209+ = unpackCString# a #-}
210+
211+{-# RULES "JSSTRING literal UTF8" forall a.
212+ unstream (S.map safe (S.streamList (GHC.unpackCStringUtf8# a)))
213+ = unpackCString# a #-}
214+
215+{-# RULES "JSSTRING empty literal"
216+ unstream (S.map safe (S.streamList []))
217+ = empty_ #-}
218+
219+{-# RULES "JSSTRING singleton literal" forall a.
220+ unstream (S.map safe (S.streamList [a]))
221+ = singleton a #-}
222+
223+
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 #-}
229+
230+{-# RULES
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
235+ #-}
236+
237+-- This is intended to reduce inlining bloat.
238+-- singleton_ :: Char -> Text
239+-- singleton_ c = js_singleton c
240+
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
245+-- return arr
246+-- len | d < '\x10000' = 1
247+-- x | otherwise = 2
248+-- d = safe c
249+-- {-# NOINLINE singleton_ #-}
250+
251+-- -----------------------------------------------------------------------------
252+-- * Basic functions
253+
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
259+cons = coerce T.cons
260+{-# INLINE [1] cons #-}
261+
262+{-# RULES
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
267+ #-}
268+
269+infixr 5 `cons`
270+
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
275+snoc = coerce T.snoc
276+ -- unstream (S.snoc (stream t) (safe c))
277+{-# INLINE [1] snoc #-}
278+
279+{-# RULES
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
284+ #-}
285+
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 #-}
291+
292+{-# RULES
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
297+ #-}
298+
299+-- | /O(1)/ Returns the first character of a 'JSString', which must be
300+-- non-empty. Subject to fusion.
301+head :: JSString -> Char
302+head = coerce T.head
303+{-# INLINE [1] head #-}
304+
305+{-# RULES
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
310+ #-}
311+
312+
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 #-}
318+
319+-- | Lifted from Control.Arrow and specialized.
320+second :: (b -> c) -> (a,b) -> (a,c)
321+second f (a, b) = (a, f b)
322+
323+-- | /O(1)/ Returns the last character of a 'JSString', which must be
324+-- non-empty. Subject to fusion.
325+last :: JSString -> Char
326+last = coerce T.last
327+{-# INLINE [1] last #-}
328+
329+{-# RULES
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
334+ #-}
335+
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
339+tail = coerce T.tail
340+{-# INLINE [1] tail #-}
341+
342+{-# RULES
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
347+ #-}
348+
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
352+init = coerce T.init
353+{-# INLINE [1] init #-}
354+
355+{-# RULES
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
360+ #-}
361+
362+-- | /O(1)/ Tests whether a 'JSString' is empty or not. Subject to
363+-- fusion.
364+null :: JSString -> Bool
365+null = coerce T.null
366+{-# INLINE [1] null #-}
367+
368+{-# RULES
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
373+ #-}
374+
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 #-}
380+
381+{-# RULES
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
386+ #-}
387+
388+-- | /O(n)/ Compare the count of characters in a 'JSString' to a number.
389+-- Subject to fusion.
390+--
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 #-}
397+
398+{-# RULES
399+"JSSTRING compareN/length -> compareLength" [~1] forall t n.
400+ compare (length t) n = compareLength t n
401+ #-}
402+
403+{-# RULES
404+"JSSTRING ==N/length -> compareLength/==EQ" [~1] forall t n.
405+ (==) (length t) n = compareLength t n == EQ
406+ #-}
407+
408+{-# RULES
409+"JSSTRING /=N/length -> compareLength//=EQ" [~1] forall t n.
410+ (/=) (length t) n = compareLength t n /= EQ
411+ #-}
412+
413+{-# RULES
414+"JSSTRING <N/length -> compareLength/==LT" [~1] forall t n.
415+ (<) (length t) n = compareLength t n == LT
416+ #-}
417+
418+{-# RULES
419+"JSSTRING <=N/length -> compareLength//=GT" [~1] forall t n.
420+ (<=) (length t) n = compareLength t n /= GT
421+ #-}
422+
423+{-# RULES
424+"JSSTRING >N/length -> compareLength/==GT" [~1] forall t n.
425+ (>) (length t) n = compareLength t n == GT
426+ #-}
427+
428+{-# RULES
429+"JSSTRING >=N/length -> compareLength//=LT" [~1] forall t n.
430+ (>=) (length t) n = compareLength t n /= LT
431+ #-}
432+
433+-- -----------------------------------------------------------------------------
434+-- * Transformations
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
439+map = coerce T.map
440+{-# INLINE [1] map #-}
441+
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 #-}
448+
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 #-}
455+
456+{-# RULES
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
461+ #-}
462+
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 #-}
467+
468+{-# RULES
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
473+ #-}
474+
475+-- | /O(m+n)/ Replace every non-overlapping occurrence of @needle@ in
476+-- @haystack@ with @replacement@.
477+--
478+-- This function behaves as though it was defined as follows:
479+--
480+-- @
481+-- replace needle replacement haystack =
482+-- 'intercalate' replacement ('splitOn' needle haystack)
483+-- @
484+--
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:
488+--
489+-- > replace "oo" "foo" "oo" == "foo"
490+--
491+-- In cases where several instances of @needle@ overlap, only the
492+-- first one will be replaced:
493+--
494+-- > replace "ofo" "bar" "ofofo" == "barfo"
495+--
496+-- In (unlikely) bad cases, this function's time complexity degrades
497+-- towards /O(n*m)/.
498+replace :: JSString
499+ -- ^ @needle@ to search for. If this string is empty, an
500+ -- error will occur.
501+ -> JSString
502+ -- ^ @replacement@ to replace @needle@ with.
503+ -> JSString
504+ -- ^ @haystack@ in which to search.
505+ -> JSString
506+replace = coerce T.replace
507+{-# INLINE replace #-}
508+
509+-- ----------------------------------------------------------------------------
510+-- ** Case conversions (folds)
511+
512+-- $case
513+--
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.
522+--
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 >.
528+
529+-- | /O(n)/ Convert a string to folded case. Subject to fusion.
530+--
531+-- This function is mainly useful for performing caseless (also known
532+-- as case insensitive) string comparisons.
533+--
534+-- A string @x@ is a caseless match for a string @y@ if and only if:
535+--
536+-- @toCaseFold x == toCaseFold y@
537+--
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 #-}
548+
549+-- | /O(n)/ Convert a string to lower case, using simple case
550+-- conversion. Subject to fusion.
551+--
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 #-}
559+
560+{-# RULES
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
565+ #-}
566+
567+-- | /O(n)/ Convert a string to upper case, using simple case
568+-- conversion. Subject to fusion.
569+--
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 #-}
576+
577+{-# RULES
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
582+ #-}
583+
584+-- | /O(n)/ Convert a string to title case, using simple case
585+-- conversion. Subject to fusion.
586+--
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
590+-- to lower case.
591+--
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).
596+--
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 #-}
605+
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.
609+--
610+-- Examples:
611+--
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 #-}
617+
618+{-# RULES
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
623+ #-}
624+
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.
628+--
629+-- Examples:
630+--
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 #-}
636+
637+-- | /O(n)/ Center a string to the given length, using the specified
638+-- fill character on either side. Performs replacement on invalid
639+-- scalar values.
640+--
641+-- Examples:
642+--
643+-- > center 8 'x' "HS" = "xxxHSxxx"
644+center :: Int -> Char -> JSString -> JSString
645+center = coerce T.center
646+{-# INLINE center #-}
647+
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
651+-- efficient.
652+transpose :: [JSString] -> [JSString]
653+transpose = coerce T.transpose
654+
655+-- -----------------------------------------------------------------------------
656+-- * Reducing 'JSString's (folds)
657+
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)
664+{-# INLINE foldl #-}
665+
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' #-}
670+
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 #-}
676+
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' #-}
681+
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)
688+{-# INLINE foldr #-}
689+
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
692+-- fusion.
693+foldr1 :: (Char -> Char -> Char) -> JSString -> Char
694+foldr1 = coerce T.foldr1
695+{-# INLINE foldr1 #-}
696+
697+-- -----------------------------------------------------------------------------
698+-- ** Special folds
699+
700+-- | /O(n)/ Concatenate a list of 'JSString's.
701+concat :: [JSString] -> JSString
702+concat = coerce T.concat
703+
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 #-}
709+
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
713+any = coerce T.any
714+{-# INLINE any #-}
715+
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
719+all = coerce T.all
720+{-# INLINE all #-}
721+
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 #-}
727+
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 #-}
733+
734+-- -----------------------------------------------------------------------------
735+-- * Building 'JSString's
736+
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.
740+--
741+-- > scanl f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...]
742+--
743+-- Note that
744+--
745+-- > last (scanl f z xs) == foldl f z xs.
746+scanl :: (Char -> Char -> Char) -> Char -> JSString -> JSString
747+scanl = coerce T.scanl
748+{-# INLINE scanl #-}
749+
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.
753+--
754+-- > scanl1 f [x1, x2, ...] == [x1, x1 `f` x2, ...]
755+scanl1 :: (Char -> Char -> Char) -> JSString -> JSString
756+scanl1 = coerce T.scanl1
757+{-# INLINE scanl1 #-}
758+
759+-- | /O(n)/ 'scanr' is the right-to-left dual of 'scanl'. Performs
760+-- replacement on invalid scalar values.
761+--
762+-- > scanr f v == reverse . scanl (flip f) v . reverse
763+scanr :: (Char -> Char -> Char) -> Char -> JSString -> JSString
764+scanr = coerce T.scanr
765+{-# INLINE scanr #-}
766+
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 #-}
773+
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 #-}
781+
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
786+-- 'JSString'.
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 #-}
791+
792+-- -----------------------------------------------------------------------------
793+-- ** Generating and unfolding 'JSString's
794+
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 #-}
800+
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 #-}
811+
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 #-}
821+
822+-- -----------------------------------------------------------------------------
823+-- * Substrings
824+
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
829+take = coerce T.take
830+{-# INLINE [1] take #-}
831+{-
832+iterN :: Int -> JSString -> Int
833+iterN n t@(Text _arr _off len) = loop 0 0
834+ where loop !i !cnt
835+ | i >= len || cnt >= n = i
836+ | otherwise = loop (i+d) (cnt+1)
837+ where d = iter_ t i
838+-}
839+{-# RULES
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
844+ #-}
845+
846+-- | /O(n)/ 'takeEnd' @n@ @t@ returns the suffix remaining after
847+-- taking @n@ characters from the end of @t@.
848+--
849+-- Examples:
850+--
851+-- > takeEnd 3 "foobar" == "bar"
852+takeEnd :: Int -> JSString -> JSString
853+takeEnd = coerce T.takeEnd
854+
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
859+drop = coerce T.drop
860+{-# INLINE [1] drop #-}
861+
862+{-# RULES
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
867+ #-}
868+
869+-- | /O(n)/ 'dropEnd' @n@ @t@ returns the prefix remaining after
870+-- dropping @n@ characters from the end of @t@.
871+--
872+-- Examples:
873+--
874+-- > dropEnd 3 "foobar" == "foo"
875+dropEnd :: Int -> JSString -> JSString
876+dropEnd = coerce T.dropEnd
877+
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 #-}
884+
885+{-# RULES
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
890+ #-}
891+
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 #-}
897+
898+{-# RULES
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
903+ #-}
904+
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.
908+-- Examples:
909+--
910+-- > dropWhileEnd (=='.') "foo..." == "foo"
911+dropWhileEnd :: (Char -> Bool) -> JSString -> JSString
912+dropWhileEnd = coerce T.dropWhileEnd
913+{-# INLINE [1] dropWhileEnd #-}
914+
915+{-# RULES
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
920+ #-}
921+
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 #-}
928+
929+-- | /O(n)/ Remove leading white space from a string. Equivalent to:
930+--
931+-- > dropWhile isSpace
932+stripStart :: JSString -> JSString
933+stripStart = coerce T.stripStart
934+{-# INLINE [1] stripStart #-}
935+
936+-- | /O(n)/ Remove trailing white space from a string. Equivalent to:
937+--
938+-- > dropWhileEnd isSpace
939+stripEnd :: JSString -> JSString
940+stripEnd = coerce T.stripEnd
941+{-# INLINE [1] stripEnd #-}
942+
943+-- | /O(n)/ Remove leading and trailing white space from a string.
944+-- Equivalent to:
945+--
946+-- > dropAround isSpace
947+strip :: JSString -> JSString
948+strip = coerce T.strip
949+{-# INLINE [1] strip #-}
950+
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 #-}
957+
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)
963+span = coerce T.span
964+{-# INLINE span #-}
965+
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
970+{-# INLINE break #-}
971+
972+-- | /O(n)/ Group characters in a string according to a predicate.
973+groupBy :: (Char -> Char -> Bool) -> JSString -> [JSString]
974+groupBy = coerce T.groupBy
975+
976+-- | /O(n)/ Group characters in a string by equality.
977+group :: JSString -> [JSString]
978+group = coerce T.group
979+{-# INLINE group #-}
980+
981+group' :: JSString -> [JSString]
982+group' = coerce T.group
983+{-# INLINE group' #-}
984+
985+-- | /O(n^2)/ Return all initial segments of the given 'JSString', shortest
986+-- first.
987+inits :: JSString -> [JSString]
988+inits = coerce T.inits
989+
990+-- | /O(n^2)/ Return all final segments of the given 'JSString', longest
991+-- first.
992+tails :: JSString -> [JSString]
993+tails = coerce T.tails
994+
995+-- $split
996+--
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.
1000+
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.
1004+--
1005+-- Examples:
1006+--
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" == ["",""]
1010+--
1011+-- and
1012+--
1013+-- > intercalate s . splitOn s == id
1014+-- > splitOn (singleton c) == split (==c)
1015+--
1016+-- (Note: the string @s@ to split on above cannot be empty.)
1017+--
1018+-- In (unlikely) bad cases, this function's time complexity degrades
1019+-- towards /O(n*m)/.
1020+splitOn :: JSString
1021+ -- ^ String to split on. If this string is empty, an error
1022+ -- will occur.
1023+ -> JSString
1024+ -- ^ Input text.
1025+ -> [JSString]
1026+splitOn = coerce T.splitOn
1027+{-# INLINE [1] splitOn #-}
1028+
1029+-- RULES
1030+-- "JSSTRING splitOn/singleton -> split/==" [~1] forall c t.
1031+-- splitOn (singleton c) t = split (==c) t
1032+--
1033+
1034+splitOn' :: JSString
1035+ -- ^ String to split on. If this string is empty, an error
1036+ -- will occur.
1037+ -> JSString
1038+ -- ^ Input text.
1039+ -> [JSString]
1040+splitOn' = coerce T.splitOn
1041+{-# NOINLINE splitOn' #-}
1042+--- {-# INLINE [1] splitOn' #-}
1043+
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.
1048+--
1049+-- > split (=='a') "aabbaca" == ["","","bb","c",""]
1050+-- > split (=='a') "" == [""]
1051+split :: (Char -> Bool) -> JSString -> [JSString]
1052+split = coerce T.split
1053+{-# INLINE split #-}
1054+
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:
1058+--
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 #-}
1064+
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:
1068+--
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' #-}
1074+
1075+-- ----------------------------------------------------------------------------
1076+-- * Searching
1077+
1078+-------------------------------------------------------------------------------
1079+-- ** Searching with a predicate
1080+
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
1086+{-# INLINE find #-}
1087+
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.
1091+--
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 #-}
1096+
1097+-- | /O(n)/ 'filter', applied to a predicate and a 'JSString',
1098+-- returns a 'JSString' containing those characters that satisfy the
1099+-- predicate.
1100+filter :: (Char -> Bool) -> JSString -> JSString
1101+filter = coerce T.filter
1102+{-# INLINE filter #-}
1103+
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.
1108+--
1109+-- Examples:
1110+--
1111+-- > breakOn "::" "a::b::c" ==> ("a", "::b::c")
1112+-- > breakOn "/" "foobar" ==> ("foobar", "")
1113+--
1114+-- Laws:
1115+--
1116+-- > append prefix match == haystack
1117+-- > where (prefix, match) = breakOn needle haystack
1118+--
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.
1122+--
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 #-}
1128+
1129+-- | /O(n+m)/ Similar to 'breakOn', but searches from the end of the
1130+-- string.
1131+--
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.
1135+--
1136+-- > breakOnEnd "::" "a::b::c" ==> ("a::b::", "c")
1137+breakOnEnd :: JSString -> JSString -> (JSString, JSString)
1138+breakOnEnd = coerce T.breakOnEnd
1139+{-# INLINE breakOnEnd #-}
1140+
1141+-- | /O(n+m)/ Find all non-overlapping instances of @needle@ in
1142+-- @haystack@. Each element of the returned list consists of a pair:
1143+--
1144+-- * The entire string prior to the /k/th match (i.e. the prefix)
1145+--
1146+-- * The /k/th match, followed by the remainder of the string
1147+--
1148+-- Examples:
1149+--
1150+-- > breakOnAll "::" ""
1151+-- > ==> []
1152+-- > breakOnAll "/" "a/b/c/"
1153+-- > ==> [("a", "/b/c/"), ("a/b", "/c/"), ("a/b/c", "/")]
1154+--
1155+-- In (unlikely) bad cases, this function's time complexity degrades
1156+-- towards /O(n*m)/.
1157+--
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 #-}
1164+
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' #-}
1170+
1171+-------------------------------------------------------------------------------
1172+-- ** Indexing 'JSString's
1173+
1174+-- $index
1175+--
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.
1178+--
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.
1184+--
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 \"::\"@.
1189+
1190+-- | /O(n)/ 'JSString' index (subscript) operator, starting from 0.
1191+index :: JSString -> Int -> Char
1192+index = coerce T.index
1193+{-# INLINE index #-}
1194+
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 #-}
1201+
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.
1205+--
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 #-}
1211+
1212+-- RULES
1213+-- "JSSTRING count/singleton -> countChar" [~1] forall c t.
1214+-- count (singleton c) t = countChar c t
1215+--
1216+
1217+-------------------------------------------------------------------------------
1218+-- * Zipping
1219+
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)]
1225+zip = coerce T.zip
1226+{-# INLINE [0] zip #-}
1227+
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 #-}
1234+
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 #-}
1240+
1241+-- fixme: strict words' that allocates the whole list in one go
1242+words' :: JSString -> [JSString]
1243+words' = coerce T.words
1244+{-# INLINE words' #-}
1245+
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 #-}
1251+
1252+lines' :: JSString -> [JSString]
1253+lines' = coerce T.lines
1254+{-# INLINE lines' #-}
1255+
1256+{-
1257+-- | /O(n)/ Portably breaks a 'JSString' up into a list of 'JSString's at line
1258+-- boundaries.
1259+--
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
1267+ Nothing -> []
1268+ Just (c,t')
1269+ | c == '\n' -> lines t'
1270+ | c == '\r' -> case uncons t' of
1271+ Just ('\n',t'') -> lines t''
1272+ _ -> lines t'
1273+ where (h,t) = span notEOL ps
1274+ notEOL c = c /= '\n' && c /= '\r'
1275+
1276+-}
1277+
1278+-- | /O(n)/ Joins lines, after appending a terminating newline to
1279+-- each.
1280+unlines :: [JSString] -> JSString
1281+unlines = coerce T.unlines
1282+{-# INLINE unlines #-}
1283+
1284+-- | /O(n)/ Joins words using single space characters.
1285+unwords :: [JSString] -> JSString
1286+unwords = coerce T.unwords
1287+{-# INLINE unwords #-}
1288+
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 #-}
1294+
1295+{-# RULES
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
1300+ #-}
1301+
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 #-}
1307+
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.
1311+--
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 #-}
1317+
1318+{-# RULES
1319+"JSSTRING isInfixOf/singleton -> S.elem/S.stream" [~1] forall n h.
1320+ isInfixOf (singleton n) h = S.elem n (S.stream h)
1321+ #-}
1322+
1323+-------------------------------------------------------------------------------
1324+-- * View patterns
1325+
1326+-- | /O(n)/ Return the suffix of the second string if its prefix
1327+-- matches the entire first string.
1328+--
1329+-- Examples:
1330+--
1331+-- > stripPrefix "foo" "foobar" == Just "bar"
1332+-- > stripPrefix "" "baz" == Just "baz"
1333+-- > stripPrefix "foo" "quux" == Nothing
1334+--
1335+-- This is particularly useful with the @ViewPatterns@ extension to
1336+-- GHC, as follows:
1337+--
1338+-- > {-# LANGUAGE ViewPatterns #-}
1339+-- > import Data.Text as T
1340+-- >
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 #-}
1347+
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
1350+-- no longer match.
1351+--
1352+-- If the strings do not have a common prefix or either one is empty,
1353+-- this function returns 'Nothing'.
1354+--
1355+-- Examples:
1356+--
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 #-}
1363+
1364+-- | /O(n)/ Return the prefix of the second string if its suffix
1365+-- matches the entire first string.
1366+--
1367+-- Examples:
1368+--
1369+-- > stripSuffix "bar" "foobar" == Just "foo"
1370+-- > stripSuffix "" "baz" == Just "baz"
1371+-- > stripSuffix "foo" "quux" == Nothing
1372+--
1373+-- This is particularly useful with the @ViewPatterns@ extension to
1374+-- GHC, as follows:
1375+--
1376+-- > {-# LANGUAGE ViewPatterns #-}
1377+-- > import Data.Text as T
1378+-- >
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 #-}
1385+
1386+---- | Add a list of non-negative numbers. Errors out on overflow.
1387+--sumP :: String -> [Int] -> Int
1388+--sumP fun = go 0
1389+-- where go !a (x:xs)
1390+-- | ax >= 0 = go ax xs
1391+-- | otherwise = overflowError fun
1392+-- where ax = a + x
1393+-- go a _ = a
1394+--
1395+--emptyError :: String -> a
1396+--emptyError fun = P.error $ "Data.JSString." ++ fun ++ ": empty input"
1397+--
1398+--overflowError :: String -> a
1399+--overflowError fun = P.error $ "Data.JSString." ++ fun ++ ": size overflow"
1400+--
1401+--charWidth :: Int# -> Int#
1402+--charWidth cp | isTrue# (cp >=# 0x10000#) = 2#
1403+-- | otherwise = 1#
1404+--{-# INLINE charWidth #-}