@@ -0,0 +1,1403 @@
1+{-# LANGUAGE MagicHash, BangPatterns, UnboxedTuples, TypeFamilies
2+ #-}
3+{-| Manipulation of JavaScript strings, API and fusion implementation
4+ based on Data.Text by Tom Harper, Duncan Coutts, Bryan O'Sullivan e.a.
5+ -}
6+module Data.JSString ( JSString
7+
8+ -- * Creation and elimination
9+ , pack
10+ , unpack, unpack'
11+ , singleton
12+ , empty
13+
14+ -- * Basic interface
15+ , cons
16+ , snoc
17+ , append
18+ , uncons
19+ , head
20+ , last
21+ , tail
22+ , init
23+ , null
24+ , length
25+ , compareLength
26+
27+ -- * Transformations
28+ , map
29+ , intercalate
30+ , intersperse
31+ , transpose
32+ , reverse
33+ , replace
34+
35+ -- ** Case conversion
36+ , toCaseFold
37+ , toLower
38+ , toUpper
39+ , toTitle
40+
41+ -- ** Justification
42+ , justifyLeft
43+ , justifyRight
44+ , center
45+
46+ -- * Folds
47+ , foldl
48+ , foldl'
49+ , foldl1
50+ , foldl1'
51+ , foldr
52+ , foldr1
53+
54+ -- ** Special folds
55+ , concat
56+ , concatMap
57+ , any
58+ , all
59+ , maximum
60+ , minimum
61+
62+ -- * Construction
63+
64+ -- ** Scans
65+ , scanl
66+ , scanl1
67+ , scanr
68+ , scanr1
69+
70+ -- ** Accumulating maps
71+ , mapAccumL
72+ , mapAccumR
73+
74+ -- ** Generation and unfolding
75+ , replicate
76+ , unfoldr
77+ , unfoldrN
78+
79+ -- * Substrings
80+
81+ -- ** Breaking strings
82+ , take
83+ , takeEnd
84+ , drop
85+ , dropEnd
86+ , takeWhile
87+ , dropWhile
88+ , dropWhileEnd
89+ , dropAround
90+ , strip
91+ , stripStart
92+ , stripEnd
93+ , splitAt
94+ , breakOn
95+ , breakOnEnd
96+ , break
97+ , span
98+ , group
99+ , group'
100+ , groupBy
101+ , inits
102+ , tails
103+
104+ -- ** Breaking into many substrings
105+ , splitOn, splitOn'
106+ , split
107+ , chunksOf, chunksOf'
108+
109+ -- ** Breaking into lines and words
110+ , lines, lines'
111+ , words, words'
112+ , unlines
113+ , unwords
114+
115+ -- * Predicates
116+ , isPrefixOf
117+ , isSuffixOf
118+ , isInfixOf
119+
120+ -- ** View patterns
121+ , stripPrefix
122+ , stripSuffix
123+ , commonPrefixes
124+
125+ -- * Searching
126+ , filter
127+ , breakOnAll, breakOnAll'
128+ , find
129+ , partition
130+
131+ -- * Indexing
132+ , index
133+ , findIndex
134+ , count
135+
136+ -- * Zipping
137+ , zip
138+ , zipWith
139+ ) where
140+
141+import Prelude
142+ ( Char, Bool(..), Int, Maybe(..), String, Eq(..), Ord(..), Ordering(..), (++)
143+ , Read(..), Show(..), (&&), (||), (+), (-), (.), ($), ($!), (>>)
144+ , not, seq, return, otherwise, quot)
145+import qualified Prelude as P
146+
147+import Control.DeepSeq (NFData(..))
148+import Data.Char (isSpace)
149+import Data.Coerce (coerce)
150+import qualified Data.List as L
151+import Data.Data
152+import qualified Data.Text as T
153+import qualified Data.Text.Internal.Fusion as TF
154+import qualified Data.Text.Internal.Fusion.Common as TF
155+
156+import GHC.Exts
157+ ( Int#, (+#), (-#), (>=#), (>#), isTrue#, chr#, Char(..)
158+ , Int(..), Addr#, tagToEnum#)
159+import qualified GHC.Exts as Exts
160+import qualified GHC.CString as GHC
161+
162+import Unsafe.Coerce
163+
164+import GHCJS.Prim (JSVal)
165+
166+import Data.JSString.Internal.Type
167+import Data.JSString.Internal.Fusion (stream, unstream)
168+import qualified Data.JSString.Internal.Fusion as S
169+import qualified Data.JSString.Internal.Fusion.Common as S
170+
171+instance Exts.IsList JSString where
172+ type Item JSString = Char
173+ fromList = pack
174+ toList = unpack
175+
176+-- -----------------------------------------------------------------------------
177+-- * Conversion to/from 'JSString'
178+
179+-- | /O(n)/ Convert a 'String' into a 'JSString'. Subject to
180+-- fusion.
181+pack :: String -> JSString
182+pack = coerce T.pack
183+{-# INLINE [1] pack #-}
184+
185+{-# RULES
186+"JSSTRING pack -> fused" [~1] forall x.
187+ pack x = unstream (S.map safe (S.streamList x))
188+"JSSTRING pack -> unfused" [1] forall x.
189+ unstream (S.map safe (S.streamList x)) = pack x
190+ #-}
191+
192+-- | /O(n)/ Convert a 'JSString' into a 'String'. Subject to fusion.
193+unpack :: JSString -> String
194+unpack = S.unstreamList . stream
195+{-# INLINE [1] unpack #-}
196+
197+unpack' :: JSString -> String
198+unpack' = coerce T.unpack
199+{-# INLINE unpack' #-}
200+
201+-- | /O(n)/ Convert a literal string into a JSString. Subject to fusion.
202+unpackCString# :: Addr# -> JSString
203+unpackCString# = coerce T.unpackCString#
204+{-# NOINLINE unpackCString# #-}
205+
206+{-# RULES "JSSTRING literal" forall a.
207+ unstream (S.map safe (S.streamList (GHC.unpackCString# a)))
208+ = unpackCString# a #-}
209+
210+{-# RULES "JSSTRING literal UTF8" forall a.
211+ unstream (S.map safe (S.streamList (GHC.unpackCStringUtf8# a)))
212+ = unpackCString# a #-}
213+
214+{-# RULES "JSSTRING empty literal"
215+ unstream (S.map safe (S.streamList []))
216+ = empty_ #-}
217+
218+{-# RULES "JSSTRING singleton literal" forall a.
219+ unstream (S.map safe (S.streamList [a]))
220+ = singleton a #-}
221+
222+
223+-- | /O(1)/ Convert a character into a 'JSString'. Subject to fusion.
224+-- Performs replacement on invalid scalar values.
225+singleton :: Char -> JSString
226+singleton = coerce T.singleton
227+{-# INLINE [1] singleton #-}
228+
229+{-# RULES
230+"JSSTRING singleton -> fused" [~1] forall a.
231+ singleton a = unstream (S.singleton (safe a))
232+"JSSTRING singleton -> unfused" [1] forall a.
233+ unstream (S.singleton (safe a)) = singleton a
234+ #-}
235+
236+-- This is intended to reduce inlining bloat.
237+-- singleton_ :: Char -> Text
238+-- singleton_ c = js_singleton c
239+
240+-- Text (A.run x) 0 len
241+-- where x :: ST s (A.MArray s)
242+-- x = do arr <- A.new len
243+-- _ <- unsafeWrite arr 0 d
244+-- return arr
245+-- len | d < '\x10000' = 1
246+-- x | otherwise = 2
247+-- d = safe c
248+-- {-# NOINLINE singleton_ #-}
249+
250+-- -----------------------------------------------------------------------------
251+-- * Basic functions
252+
253+-- | /O(n)/ Adds a character to the front of a 'JSString'. This function
254+-- is more costly than its 'List' counterpart because it requires
255+-- copying a new array. Subject to fusion. Performs replacement on
256+-- invalid scalar values.
257+cons :: Char -> JSString -> JSString
258+cons = coerce T.cons
259+{-# INLINE [1] cons #-}
260+
261+{-# RULES
262+"JSSTRING cons -> fused" [~1] forall c x.
263+ cons c x = unstream (S.cons (safe c) (stream x))
264+"JSSTRING cons -> unfused" [1] forall c x.
265+ unstream (S.cons (safe c) (stream x)) = cons c x
266+ #-}
267+
268+infixr 5 `cons`
269+
270+-- | /O(n)/ Adds a character to the end of a 'JSString'. This copies the
271+-- entire array in the process, unless fused. Subject to fusion.
272+-- Performs replacement on invalid scalar values.
273+snoc :: JSString -> Char -> JSString
274+snoc = coerce T.snoc
275+ -- unstream (S.snoc (stream t) (safe c))
276+{-# INLINE [1] snoc #-}
277+
278+{-# RULES
279+"JSSTRING snoc -> fused" [~1] forall x c.
280+ snoc x c = unstream (S.snoc (stream x) (safe c))
281+"JSSTRING snoc -> unfused" [1] forall x c.
282+ unstream (S.snoc (stream x) (safe c)) = snoc x c
283+ #-}
284+
285+-- | /O(n)/ Appends one 'JSString' to the other by copying both of them
286+-- into a new 'JSString'. Subject to fusion.
287+append :: JSString -> JSString -> JSString
288+append = coerce T.append
289+{-# INLINE [1] append #-}
290+
291+{-# RULES
292+"JSSTRING append -> fused" [~1] forall x1 x2.
293+ append x1 x2 = unstream (S.append (stream x1) (stream x2))
294+"JSSTRING append -> unfused" [1] forall x1 x2.
295+ unstream (S.append (stream x1) (stream x2)) = append x1 x2
296+ #-}
297+
298+-- | /O(1)/ Returns the first character of a 'JSString', which must be
299+-- non-empty. Subject to fusion.
300+head :: JSString -> Char
301+head = coerce T.head
302+{-# INLINE [1] head #-}
303+
304+{-# RULES
305+"JSSTRING head -> fused" [~1] forall x.
306+ head x = S.head (stream x)
307+"JSSTRING head -> unfused" [1] forall x.
308+ S.head (stream x) = head x
309+ #-}
310+
311+
312+-- | /O(1)/ Returns the first character and rest of a 'JSString', or
313+-- 'Nothing' if empty. Subject to fusion.
314+uncons :: JSString -> Maybe (Char, JSString)
315+uncons = coerce T.uncons
316+{-# INLINE [1] uncons #-}
317+
318+-- | Lifted from Control.Arrow and specialized.
319+second :: (b -> c) -> (a,b) -> (a,c)
320+second f (a, b) = (a, f b)
321+
322+-- | /O(1)/ Returns the last character of a 'JSString', which must be
323+-- non-empty. Subject to fusion.
324+last :: JSString -> Char
325+last = coerce T.last
326+{-# INLINE [1] last #-}
327+
328+{-# RULES
329+"JSSTRING last -> fused" [~1] forall x.
330+ last x = S.last (stream x)
331+"JSSTRING last -> unfused" [1] forall x.
332+ S.last (stream x) = last x
333+ #-}
334+
335+-- | /O(1)/ Returns all characters after the head of a 'JSString', which
336+-- must be non-empty. Subject to fusion.
337+tail :: JSString -> JSString
338+tail = coerce T.tail
339+{-# INLINE [1] tail #-}
340+
341+{-# RULES
342+"JSSTRING tail -> fused" [~1] forall x.
343+ tail x = unstream (S.tail (stream x))
344+"JSSTRING tail -> unfused" [1] forall x.
345+ unstream (S.tail (stream x)) = tail x
346+ #-}
347+
348+-- | /O(1)/ Returns all but the last character of a 'JSString', which must
349+-- be non-empty. Subject to fusion.
350+init :: JSString -> JSString
351+init = coerce T.init
352+{-# INLINE [1] init #-}
353+
354+{-# RULES
355+"JSSTRING init -> fused" [~1] forall t.
356+ init t = unstream (S.init (stream t))
357+"JSSTRING init -> unfused" [1] forall t.
358+ unstream (S.init (stream t)) = init t
359+ #-}
360+
361+-- | /O(1)/ Tests whether a 'JSString' is empty or not. Subject to
362+-- fusion.
363+null :: JSString -> Bool
364+null = coerce T.null
365+{-# INLINE [1] null #-}
366+
367+{-# RULES
368+"JSSTRING null -> fused" [~1] forall t.
369+ null t = S.null (stream t)
370+"JSSTRING null -> unfused" [1] forall t.
371+ S.null (stream t) = null t
372+ #-}
373+
374+-- | /O(n)/ Returns the number of characters in a 'JSString'.
375+-- Subject to fusion.
376+length :: JSString -> Int
377+length = coerce T.length
378+{-# INLINE [1] length #-}
379+
380+{-# RULES
381+"JSSTRING length -> fused" [~1] forall x.
382+ length x = S.length (stream x)
383+"JSSTRING length -> unfused" [1] forall x.
384+ S.length (stream x) = length x
385+ #-}
386+
387+-- | /O(n)/ Compare the count of characters in a 'JSString' to a number.
388+-- Subject to fusion.
389+--
390+-- This function gives the same answer as comparing against the result
391+-- of 'length', but can short circuit if the count of characters is
392+-- greater than the number, and hence be more efficient.
393+compareLength :: JSString -> Int -> Ordering
394+compareLength = coerce T.compareLength
395+{-# INLINE [1] compareLength #-}
396+
397+{-# RULES
398+"JSSTRING compareN/length -> compareLength" [~1] forall t n.
399+ compare (length t) n = compareLength t n
400+ #-}
401+
402+{-# RULES
403+"JSSTRING ==N/length -> compareLength/==EQ" [~1] forall t n.
404+ (==) (length t) n = compareLength t n == EQ
405+ #-}
406+
407+{-# RULES
408+"JSSTRING /=N/length -> compareLength//=EQ" [~1] forall t n.
409+ (/=) (length t) n = compareLength t n /= EQ
410+ #-}
411+
412+{-# RULES
413+"JSSTRING <N/length -> compareLength/==LT" [~1] forall t n.
414+ (<) (length t) n = compareLength t n == LT
415+ #-}
416+
417+{-# RULES
418+"JSSTRING <=N/length -> compareLength//=GT" [~1] forall t n.
419+ (<=) (length t) n = compareLength t n /= GT
420+ #-}
421+
422+{-# RULES
423+"JSSTRING >N/length -> compareLength/==GT" [~1] forall t n.
424+ (>) (length t) n = compareLength t n == GT
425+ #-}
426+
427+{-# RULES
428+"JSSTRING >=N/length -> compareLength//=LT" [~1] forall t n.
429+ (>=) (length t) n = compareLength t n /= LT
430+ #-}
431+
432+-- -----------------------------------------------------------------------------
433+-- * Transformations
434+-- | /O(n)/ 'map' @f@ @t@ is the 'JSString' obtained by applying @f@ to
435+-- each element of @t@. Subject to fusion. Performs replacement on
436+-- invalid scalar values.
437+map :: (Char -> Char) -> JSString -> JSString
438+map = coerce T.map
439+{-# INLINE [1] map #-}
440+
441+-- | /O(n)/ The 'intercalate' function takes a 'JSString' and a list of
442+-- 'JSString's and concatenates the list after interspersing the first
443+-- argument between each element of the list.
444+intercalate :: JSString -> [JSString] -> JSString
445+intercalate = coerce T.intercalate
446+{-# INLINE [1] intercalate #-}
447+
448+-- | /O(n)/ The 'intersperse' function takes a character and places it
449+-- between the characters of a 'JSString'. Subject to fusion. Performs
450+-- replacement on invalid scalar values.
451+intersperse :: Char -> JSString -> JSString
452+intersperse = coerce T.intersperse
453+{-# INLINE [1] intersperse #-}
454+
455+{-# RULES
456+"JSSTRING intersperse -> fused" [~1] forall c x.
457+ intersperse c x = unstream (S.intersperse (safe c) (stream x))
458+"JSSTRING intersperse -> unfused" [1] forall c x.
459+ unstream (S.intersperse (safe c) (stream x)) = intersperse c x
460+ #-}
461+
462+-- | /O(n)/ Reverse the characters of a string. Subject to fusion.
463+reverse :: JSString -> JSString
464+reverse = coerce T.reverse
465+{-# INLINE [1] reverse #-}
466+
467+{-# RULES
468+"JSSTRING reverse -> fused" [~1] forall x.
469+ reverse x = S.reverse (stream x)
470+"JSSTRING reverse -> unfused" [1] forall x.
471+ S.reverse (stream x) = reverse x
472+ #-}
473+
474+-- | /O(m+n)/ Replace every non-overlapping occurrence of @needle@ in
475+-- @haystack@ with @replacement@.
476+--
477+-- This function behaves as though it was defined as follows:
478+--
479+-- @
480+-- replace needle replacement haystack =
481+-- 'intercalate' replacement ('splitOn' needle haystack)
482+-- @
483+--
484+-- As this suggests, each occurrence is replaced exactly once. So if
485+-- @needle@ occurs in @replacement@, that occurrence will /not/ itself
486+-- be replaced recursively:
487+--
488+-- > replace "oo" "foo" "oo" == "foo"
489+--
490+-- In cases where several instances of @needle@ overlap, only the
491+-- first one will be replaced:
492+--
493+-- > replace "ofo" "bar" "ofofo" == "barfo"
494+--
495+-- In (unlikely) bad cases, this function's time complexity degrades
496+-- towards /O(n*m)/.
497+replace :: JSString
498+ -- ^ @needle@ to search for. If this string is empty, an
499+ -- error will occur.
500+ -> JSString
501+ -- ^ @replacement@ to replace @needle@ with.
502+ -> JSString
503+ -- ^ @haystack@ in which to search.
504+ -> JSString
505+replace = coerce T.replace
506+{-# INLINE replace #-}
507+
508+-- ----------------------------------------------------------------------------
509+-- ** Case conversions (folds)
510+
511+-- $case
512+--
513+-- When case converting 'JSString' values, do not use combinators like
514+-- @map toUpper@ to case convert each character of a string
515+-- individually, as this gives incorrect results according to the
516+-- rules of some writing systems. The whole-string case conversion
517+-- functions from this module, such as @toUpper@, obey the correct
518+-- case conversion rules. As a result, these functions may map one
519+-- input character to two or three output characters. For examples,
520+-- see the documentation of each function.
521+--
522+-- /Note/: In some languages, case conversion is a locale- and
523+-- context-dependent operation. The case conversion functions in this
524+-- module are /not/ locale sensitive. Programs that require locale
525+-- sensitivity should use appropriate versions of the
526+-- <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 >.
527+
528+-- | /O(n)/ Convert a string to folded case. Subject to fusion.
529+--
530+-- This function is mainly useful for performing caseless (also known
531+-- as case insensitive) string comparisons.
532+--
533+-- A string @x@ is a caseless match for a string @y@ if and only if:
534+--
535+-- @toCaseFold x == toCaseFold y@
536+--
537+-- The result string may be longer than the input string, and may
538+-- differ from applying 'toLower' to the input string. For instance,
539+-- the Armenian small ligature \"ﬓ\" (men now, U+FB13) is case
540+-- folded to the sequence \"մ\" (men, U+0574) followed by
541+-- \"ն\" (now, U+0576), while the Greek \"µ\" (micro sign,
542+-- U+00B5) is case folded to \"μ\" (small letter mu, U+03BC)
543+-- instead of itself.
544+toCaseFold :: JSString -> JSString
545+toCaseFold = coerce T.toCaseFold
546+{-# INLINE [0] toCaseFold #-}
547+
548+-- | /O(n)/ Convert a string to lower case, using simple case
549+-- conversion. Subject to fusion.
550+--
551+-- The result string may be longer than the input string. For
552+-- instance, \"İ\" (Latin capital letter I with dot above,
553+-- U+0130) maps to the sequence \"i\" (Latin small letter i, U+0069)
554+-- followed by \" ̇\" (combining dot above, U+0307).
555+toLower :: JSString -> JSString
556+toLower = coerce T.toLower
557+{-# INLINE [1] toLower #-}
558+
559+{-# RULES
560+"JSSTRING toLower -> fused" [~1] forall x.
561+ toLower x = unstream (S.toLower (stream x))
562+"JSSTRING toLower -> unfused" [1] forall x.
563+ unstream (S.toLower (stream x)) = toLower x
564+ #-}
565+
566+-- | /O(n)/ Convert a string to upper case, using simple case
567+-- conversion. Subject to fusion.
568+--
569+-- The result string may be longer than the input string. For
570+-- instance, the German \"ß\" (eszett, U+00DF) maps to the
571+-- two-letter sequence \"SS\".
572+toUpper :: JSString -> JSString
573+toUpper = coerce T.toUpper
574+{-# INLINE [1] toUpper #-}
575+
576+{-# RULES
577+"JSSTRING toUpper -> fused" [~1] forall x.
578+ toUpper x = unstream (S.toUpper(stream x))
579+"JSSTRING toUpper -> unfused" [1] forall x.
580+ unstream (S.toUpper (stream x)) = toUpper x
581+ #-}
582+
583+-- | /O(n)/ Convert a string to title case, using simple case
584+-- conversion. Subject to fusion.
585+--
586+-- The first letter of the input is converted to title case, as is
587+-- every subsequent letter that immediately follows a non-letter.
588+-- Every letter that immediately follows another letter is converted
589+-- to lower case.
590+--
591+-- The result string may be longer than the input string. For example,
592+-- the Latin small ligature fl (U+FB02) is converted to the
593+-- sequence Latin capital letter F (U+0046) followed by Latin small
594+-- letter l (U+006C).
595+--
596+-- /Note/: this function does not take language or culture specific
597+-- rules into account. For instance, in English, different style
598+-- guides disagree on whether the book name \"The Hill of the Red
599+-- Fox\" is correctly title cased—but this function will
600+-- capitalize /every/ word.
601+toTitle :: JSString -> JSString
602+toTitle = coerce T.toTitle
603+{-# INLINE toTitle #-}
604+
605+-- | /O(n)/ Left-justify a string to the given length, using the
606+-- specified fill character on the right. Subject to fusion.
607+-- Performs replacement on invalid scalar values.
608+--
609+-- Examples:
610+--
611+-- > justifyLeft 7 'x' "foo" == "fooxxxx"
612+-- > justifyLeft 3 'x' "foobar" == "foobar"
613+justifyLeft :: Int -> Char -> JSString -> JSString
614+justifyLeft = coerce T.justifyLeft
615+{-# INLINE [1] justifyLeft #-}
616+
617+{-# RULES
618+"JSSTRING justifyLeft -> fused" [~1] forall k c t.
619+ justifyLeft k c t = unstream (S.justifyLeftI k c (stream t))
620+"JSSTRING justifyLeft -> unfused" [1] forall k c t.
621+ unstream (S.justifyLeftI k c (stream t)) = justifyLeft k c t
622+ #-}
623+
624+-- | /O(n)/ Right-justify a string to the given length, using the
625+-- specified fill character on the left. Performs replacement on
626+-- invalid scalar values.
627+--
628+-- Examples:
629+--
630+-- > justifyRight 7 'x' "bar" == "xxxxbar"
631+-- > justifyRight 3 'x' "foobar" == "foobar"
632+justifyRight :: Int -> Char -> JSString -> JSString
633+justifyRight = coerce T.justifyRight
634+{-# INLINE justifyRight #-}
635+
636+-- | /O(n)/ Center a string to the given length, using the specified
637+-- fill character on either side. Performs replacement on invalid
638+-- scalar values.
639+--
640+-- Examples:
641+--
642+-- > center 8 'x' "HS" = "xxxHSxxx"
643+center :: Int -> Char -> JSString -> JSString
644+center = coerce T.center
645+{-# INLINE center #-}
646+
647+-- | /O(n)/ The 'transpose' function transposes the rows and columns
648+-- of its 'JSString' argument. Note that this function uses 'pack',
649+-- 'unpack', and the list version of transpose, and is thus not very
650+-- efficient.
651+transpose :: [JSString] -> [JSString]
652+transpose = coerce T.transpose
653+
654+-- -----------------------------------------------------------------------------
655+-- * Reducing 'JSString's (folds)
656+
657+-- | /O(n)/ 'foldl', applied to a binary operator, a starting value
658+-- (typically the left-identity of the operator), and a 'JSString',
659+-- reduces the 'JSString' using the binary operator, from left to right.
660+-- Subject to fusion.
661+foldl :: (a -> Char -> a) -> a -> JSString -> a
662+foldl f = coerce (T.foldl f)
663+{-# INLINE foldl #-}
664+
665+-- | /O(n)/ A strict version of 'foldl'. Subject to fusion.
666+foldl' :: (a -> Char -> a) -> a -> JSString -> a
667+foldl' f = coerce (T.foldl' f)
668+{-# INLINE foldl' #-}
669+
670+-- | /O(n)/ A variant of 'foldl' that has no starting value argument,
671+-- and thus must be applied to a non-empty 'JSString'. Subject to fusion.
672+foldl1 :: (Char -> Char -> Char) -> JSString -> Char
673+foldl1 = coerce T.foldl1
674+{-# INLINE foldl1 #-}
675+
676+-- | /O(n)/ A strict version of 'foldl1'. Subject to fusion.
677+foldl1' :: (Char -> Char -> Char) -> JSString -> Char
678+foldl1' = coerce T.foldl1'
679+{-# INLINE foldl1' #-}
680+
681+-- | /O(n)/ 'foldr', applied to a binary operator, a starting value
682+-- (typically the right-identity of the operator), and a 'JSString',
683+-- reduces the 'JSString' using the binary operator, from right to left.
684+-- Subject to fusion.
685+foldr :: (Char -> a -> a) -> a -> JSString -> a
686+foldr f = coerce (T.foldr f)
687+{-# INLINE foldr #-}
688+
689+-- | /O(n)/ A variant of 'foldr' that has no starting value argument,
690+-- and thus must be applied to a non-empty 'JSString'. Subject to
691+-- fusion.
692+foldr1 :: (Char -> Char -> Char) -> JSString -> Char
693+foldr1 = coerce T.foldr1
694+{-# INLINE foldr1 #-}
695+
696+-- -----------------------------------------------------------------------------
697+-- ** Special folds
698+
699+-- | /O(n)/ Concatenate a list of 'JSString's.
700+concat :: [JSString] -> JSString
701+concat = coerce T.concat
702+
703+-- | /O(n)/ Map a function over a 'JSString' that results in a 'JSString', and
704+-- concatenate the results.
705+concatMap :: (Char -> JSString) -> JSString -> JSString
706+concatMap = coerce T.concatMap
707+{-# INLINE concatMap #-}
708+
709+-- | /O(n)/ 'any' @p@ @t@ determines whether any character in the
710+-- 'JSString' @t@ satisifes the predicate @p@. Subject to fusion.
711+any :: (Char -> Bool) -> JSString -> Bool
712+any = coerce T.any
713+{-# INLINE any #-}
714+
715+-- | /O(n)/ 'all' @p@ @t@ determines whether all characters in the
716+-- 'JSString' @t@ satisify the predicate @p@. Subject to fusion.
717+all :: (Char -> Bool) -> JSString -> Bool
718+all = coerce T.all
719+{-# INLINE all #-}
720+
721+-- | /O(n)/ 'maximum' returns the maximum value from a 'JSString', which
722+-- must be non-empty. Subject to fusion.
723+maximum :: JSString -> Char
724+maximum = coerce T.maximum
725+{-# INLINE maximum #-}
726+
727+-- | /O(n)/ 'minimum' returns the minimum value from a 'JSString', which
728+-- must be non-empty. Subject to fusion.
729+minimum :: JSString -> Char
730+minimum = coerce T.minimum
731+{-# INLINE minimum #-}
732+
733+-- -----------------------------------------------------------------------------
734+-- * Building 'JSString's
735+
736+-- | /O(n)/ 'scanl' is similar to 'foldl', but returns a list of
737+-- successive reduced values from the left. Subject to fusion.
738+-- Performs replacement on invalid scalar values.
739+--
740+-- > scanl f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...]
741+--
742+-- Note that
743+--
744+-- > last (scanl f z xs) == foldl f z xs.
745+scanl :: (Char -> Char -> Char) -> Char -> JSString -> JSString
746+scanl = coerce T.scanl
747+{-# INLINE scanl #-}
748+
749+-- | /O(n)/ 'scanl1' is a variant of 'scanl' that has no starting
750+-- value argument. Subject to fusion. Performs replacement on
751+-- invalid scalar values.
752+--
753+-- > scanl1 f [x1, x2, ...] == [x1, x1 `f` x2, ...]
754+scanl1 :: (Char -> Char -> Char) -> JSString -> JSString
755+scanl1 = coerce T.scanl1
756+{-# INLINE scanl1 #-}
757+
758+-- | /O(n)/ 'scanr' is the right-to-left dual of 'scanl'. Performs
759+-- replacement on invalid scalar values.
760+--
761+-- > scanr f v == reverse . scanl (flip f) v . reverse
762+scanr :: (Char -> Char -> Char) -> Char -> JSString -> JSString
763+scanr = coerce T.scanr
764+{-# INLINE scanr #-}
765+
766+-- | /O(n)/ 'scanr1' is a variant of 'scanr' that has no starting
767+-- value argument. Subject to fusion. Performs replacement on
768+-- invalid scalar values.
769+scanr1 :: (Char -> Char -> Char) -> JSString -> JSString
770+scanr1 = coerce T.scanr1
771+{-# INLINE scanr1 #-}
772+
773+-- | /O(n)/ Like a combination of 'map' and 'foldl''. Applies a
774+-- function to each element of a 'JSString', passing an accumulating
775+-- parameter from left to right, and returns a final 'JSString'. Performs
776+-- replacement on invalid scalar values.
777+mapAccumL :: (a -> Char -> (a,Char)) -> a -> JSString -> (a, JSString)
778+mapAccumL f = coerce (T.mapAccumL f)
779+{-# INLINE mapAccumL #-}
780+
781+-- | The 'mapAccumR' function behaves like a combination of 'map' and
782+-- a strict 'foldr'; it applies a function to each element of a
783+-- 'JSString', passing an accumulating parameter from right to left, and
784+-- returning a final value of this accumulator together with the new
785+-- 'JSString'.
786+-- Performs replacement on invalid scalar values.
787+mapAccumR :: (a -> Char -> (a,Char)) -> a -> JSString -> (a, JSString)
788+mapAccumR f = coerce (T.mapAccumR f)
789+{-# INLINE mapAccumR #-}
790+
791+-- -----------------------------------------------------------------------------
792+-- ** Generating and unfolding 'JSString's
793+
794+-- | /O(n*m)/ 'replicate' @n@ @t@ is a 'JSString' consisting of the input
795+-- @t@ repeated @n@ times.
796+replicate :: Int -> JSString -> JSString
797+replicate = coerce T.replicate
798+{-# INLINE [1] replicate #-}
799+
800+-- | /O(n)/, where @n@ is the length of the result. The 'unfoldr'
801+-- function is analogous to the List 'L.unfoldr'. 'unfoldr' builds a
802+-- 'JSString' from a seed value. The function takes the element and
803+-- returns 'Nothing' if it is done producing the 'JSString', otherwise
804+-- 'Just' @(a,b)@. In this case, @a@ is the next 'Char' in the
805+-- string, and @b@ is the seed value for further production. Subject
806+-- to fusion. Performs replacement on invalid scalar values.
807+unfoldr :: (a -> Maybe (Char,a)) -> a -> JSString
808+unfoldr f = coerce (T.unfoldr f)
809+{-# INLINE unfoldr #-}
810+
811+-- | /O(n)/ Like 'unfoldr', 'unfoldrN' builds a 'JSString' from a seed
812+-- value. However, the length of the result should be limited by the
813+-- first argument to 'unfoldrN'. This function is more efficient than
814+-- 'unfoldr' when the maximum length of the result is known and
815+-- correct, otherwise its performance is similar to 'unfoldr'. Subject
816+-- to fusion. Performs replacement on invalid scalar values.
817+unfoldrN :: Int -> (a -> Maybe (Char,a)) -> a -> JSString
818+unfoldrN n f = coerce (T.unfoldrN n f)
819+{-# INLINE unfoldrN #-}
820+
821+-- -----------------------------------------------------------------------------
822+-- * Substrings
823+
824+-- | /O(n)/ 'take' @n@, applied to a 'JSString', returns the prefix of the
825+-- 'JSString' of length @n@, or the 'JSString' itself if @n@ is greater than
826+-- the length of the JSString. Subject to fusion.
827+take :: Int -> JSString -> JSString
828+take = coerce T.take
829+{-# INLINE [1] take #-}
830+{-
831+iterN :: Int -> JSString -> Int
832+iterN n t@(Text _arr _off len) = loop 0 0
833+ where loop !i !cnt
834+ | i >= len || cnt >= n = i
835+ | otherwise = loop (i+d) (cnt+1)
836+ where d = iter_ t i
837+-}
838+{-# RULES
839+"JSSTRING take -> fused" [~1] forall n t.
840+ take n t = unstream (S.take n (stream t))
841+"JSSTRING take -> unfused" [1] forall n t.
842+ unstream (S.take n (stream t)) = take n t
843+ #-}
844+
845+-- | /O(n)/ 'takeEnd' @n@ @t@ returns the suffix remaining after
846+-- taking @n@ characters from the end of @t@.
847+--
848+-- Examples:
849+--
850+-- > takeEnd 3 "foobar" == "bar"
851+takeEnd :: Int -> JSString -> JSString
852+takeEnd = coerce T.takeEnd
853+
854+-- | /O(n)/ 'drop' @n@, applied to a 'JSString', returns the suffix of the
855+-- 'JSString' after the first @n@ characters, or the empty 'JSString' if @n@
856+-- is greater than the length of the 'JSString'. Subject to fusion.
857+drop :: Int -> JSString -> JSString
858+drop = coerce T.drop
859+{-# INLINE [1] drop #-}
860+
861+{-# RULES
862+"JSSTRING drop -> fused" [~1] forall n t.
863+ drop n t = unstream (S.drop n (stream t))
864+"JSSTRING drop -> unfused" [1] forall n t.
865+ unstream (S.drop n (stream t)) = drop n t
866+ #-}
867+
868+-- | /O(n)/ 'dropEnd' @n@ @t@ returns the prefix remaining after
869+-- dropping @n@ characters from the end of @t@.
870+--
871+-- Examples:
872+--
873+-- > dropEnd 3 "foobar" == "foo"
874+dropEnd :: Int -> JSString -> JSString
875+dropEnd = coerce T.dropEnd
876+
877+-- | /O(n)/ 'takeWhile', applied to a predicate @p@ and a 'JSString',
878+-- returns the longest prefix (possibly empty) of elements that
879+-- satisfy @p@. Subject to fusion.
880+takeWhile :: (Char -> Bool) -> JSString -> JSString
881+takeWhile = coerce T.takeWhile
882+{-# INLINE [1] takeWhile #-}
883+
884+{-# RULES
885+"TEXT takeWhile -> fused" [~1] forall p t.
886+ takeWhile p t = unstream (S.takeWhile p (stream t))
887+"TEXT takeWhile -> unfused" [1] forall p t.
888+ unstream (S.takeWhile p (stream t)) = takeWhile p t
889+ #-}
890+
891+-- | /O(n)/ 'dropWhile' @p@ @t@ returns the suffix remaining after
892+-- 'takeWhile' @p@ @t@. Subject to fusion.
893+dropWhile :: (Char -> Bool) -> JSString -> JSString
894+dropWhile = coerce T.dropWhile
895+{-# INLINE [1] dropWhile #-}
896+
897+{-# RULES
898+"TEXT dropWhile -> fused" [~1] forall p t.
899+ dropWhile p t = unstream (S.dropWhile p (stream t))
900+"TEXT dropWhile -> unfused" [1] forall p t.
901+ unstream (S.dropWhile p (stream t)) = dropWhile p t
902+ #-}
903+
904+-- | /O(n)/ 'dropWhileEnd' @p@ @t@ returns the prefix remaining after
905+-- dropping characters that fail the predicate @p@ from the end of
906+-- @t@. Subject to fusion.
907+-- Examples:
908+--
909+-- > dropWhileEnd (=='.') "foo..." == "foo"
910+dropWhileEnd :: (Char -> Bool) -> JSString -> JSString
911+dropWhileEnd = coerce T.dropWhileEnd
912+{-# INLINE [1] dropWhileEnd #-}
913+
914+{-# RULES
915+"TEXT dropWhileEnd -> fused" [~1] forall p t.
916+ dropWhileEnd p t = S.reverse (S.dropWhile p (S.reverseStream t))
917+"TEXT dropWhileEnd -> unfused" [1] forall p t.
918+ S.reverse (S.dropWhile p (S.reverseStream t)) = dropWhileEnd p t
919+ #-}
920+
921+-- | /O(n)/ 'dropAround' @p@ @t@ returns the substring remaining after
922+-- dropping characters that fail the predicate @p@ from both the
923+-- beginning and end of @t@. Subject to fusion.
924+dropAround :: (Char -> Bool) -> JSString -> JSString
925+dropAround = coerce T.dropAround
926+{-# INLINE [1] dropAround #-}
927+
928+-- | /O(n)/ Remove leading white space from a string. Equivalent to:
929+--
930+-- > dropWhile isSpace
931+stripStart :: JSString -> JSString
932+stripStart = coerce T.stripStart
933+{-# INLINE [1] stripStart #-}
934+
935+-- | /O(n)/ Remove trailing white space from a string. Equivalent to:
936+--
937+-- > dropWhileEnd isSpace
938+stripEnd :: JSString -> JSString
939+stripEnd = coerce T.stripEnd
940+{-# INLINE [1] stripEnd #-}
941+
942+-- | /O(n)/ Remove leading and trailing white space from a string.
943+-- Equivalent to:
944+--
945+-- > dropAround isSpace
946+strip :: JSString -> JSString
947+strip = coerce T.strip
948+{-# INLINE [1] strip #-}
949+
950+-- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a
951+-- prefix of @t@ of length @n@, and whose second is the remainder of
952+-- the string. It is equivalent to @('take' n t, 'drop' n t)@.
953+splitAt :: Int -> JSString -> (JSString, JSString)
954+splitAt = coerce T.splitAt
955+{-# INLINE splitAt #-}
956+
957+-- | /O(n)/ 'span', applied to a predicate @p@ and text @t@, returns
958+-- a pair whose first element is the longest prefix (possibly empty)
959+-- of @t@ of elements that satisfy @p@, and whose second is the
960+-- remainder of the list.
961+span :: (Char -> Bool) -> JSString -> (JSString, JSString)
962+span = coerce T.span
963+{-# INLINE span #-}
964+
965+-- | /O(n)/ 'break' is like 'span', but the prefix returned is
966+-- over elements that fail the predicate @p@.
967+break :: (Char -> Bool) -> JSString -> (JSString, JSString)
968+break = coerce T.break
969+{-# INLINE break #-}
970+
971+-- | /O(n)/ Group characters in a string according to a predicate.
972+groupBy :: (Char -> Char -> Bool) -> JSString -> [JSString]
973+groupBy = coerce T.groupBy
974+
975+-- | /O(n)/ Group characters in a string by equality.
976+group :: JSString -> [JSString]
977+group = coerce T.group
978+{-# INLINE group #-}
979+
980+group' :: JSString -> [JSString]
981+group' = coerce T.group
982+{-# INLINE group' #-}
983+
984+-- | /O(n^2)/ Return all initial segments of the given 'JSString', shortest
985+-- first.
986+inits :: JSString -> [JSString]
987+inits = coerce T.inits
988+
989+-- | /O(n^2)/ Return all final segments of the given 'JSString', longest
990+-- first.
991+tails :: JSString -> [JSString]
992+tails = coerce T.tails
993+
994+-- $split
995+--
996+-- Splitting functions in this library do not perform character-wise
997+-- copies to create substrings; they just construct new 'JSString's that
998+-- are slices of the original.
999+
1000+-- | /O(m+n)/ Break a 'JSString' into pieces separated by the first 'JSString'
1001+-- argument (which cannot be empty), consuming the delimiter. An empty
1002+-- delimiter is invalid, and will cause an error to be raised.
1003+--
1004+-- Examples:
1005+--
1006+-- > splitOn "\r\n" "a\r\nb\r\nd\r\ne" == ["a","b","d","e"]
1007+-- > splitOn "aaa" "aaaXaaaXaaaXaaa" == ["","X","X","X",""]
1008+-- > splitOn "x" "x" == ["",""]
1009+--
1010+-- and
1011+--
1012+-- > intercalate s . splitOn s == id
1013+-- > splitOn (singleton c) == split (==c)
1014+--
1015+-- (Note: the string @s@ to split on above cannot be empty.)
1016+--
1017+-- In (unlikely) bad cases, this function's time complexity degrades
1018+-- towards /O(n*m)/.
1019+splitOn :: JSString
1020+ -- ^ String to split on. If this string is empty, an error
1021+ -- will occur.
1022+ -> JSString
1023+ -- ^ Input text.
1024+ -> [JSString]
1025+splitOn = coerce T.splitOn
1026+{-# INLINE [1] splitOn #-}
1027+
1028+-- RULES
1029+-- "JSSTRING splitOn/singleton -> split/==" [~1] forall c t.
1030+-- splitOn (singleton c) t = split (==c) t
1031+--
1032+
1033+splitOn' :: JSString
1034+ -- ^ String to split on. If this string is empty, an error
1035+ -- will occur.
1036+ -> JSString
1037+ -- ^ Input text.
1038+ -> [JSString]
1039+splitOn' = coerce T.splitOn
1040+{-# NOINLINE splitOn' #-}
1041+--- {-# INLINE [1] splitOn' #-}
1042+
1043+-- | /O(n)/ Splits a 'JSString' into components delimited by separators,
1044+-- where the predicate returns True for a separator element. The
1045+-- resulting components do not contain the separators. Two adjacent
1046+-- separators result in an empty component in the output. eg.
1047+--
1048+-- > split (=='a') "aabbaca" == ["","","bb","c",""]
1049+-- > split (=='a') "" == [""]
1050+split :: (Char -> Bool) -> JSString -> [JSString]
1051+split = coerce T.split
1052+{-# INLINE split #-}
1053+
1054+-- | /O(n)/ Splits a 'JSString' into components of length @k@. The last
1055+-- element may be shorter than the other chunks, depending on the
1056+-- length of the input. Examples:
1057+--
1058+-- > chunksOf 3 "foobarbaz" == ["foo","bar","baz"]
1059+-- > chunksOf 4 "haskell.org" == ["hask","ell.","org"]
1060+chunksOf :: Int -> JSString -> [JSString]
1061+chunksOf = coerce T.chunksOf
1062+{-# INLINE chunksOf #-}
1063+
1064+-- | /O(n)/ Splits a 'JSString' into components of length @k@. The last
1065+-- element may be shorter than the other chunks, depending on the
1066+-- length of the input. Examples:
1067+--
1068+-- > chunksOf 3 "foobarbaz" == ["foo","bar","baz"]
1069+-- > chunksOf 4 "haskell.org" == ["hask","ell.","org"]
1070+chunksOf' :: Int -> JSString -> [JSString]
1071+chunksOf' = coerce T.chunksOf
1072+{-# INLINE chunksOf' #-}
1073+
1074+-- ----------------------------------------------------------------------------
1075+-- * Searching
1076+
1077+-------------------------------------------------------------------------------
1078+-- ** Searching with a predicate
1079+
1080+-- | /O(n)/ The 'find' function takes a predicate and a 'JSString', and
1081+-- returns the first element matching the predicate, or 'Nothing' if
1082+-- there is no such element.
1083+find :: (Char -> Bool) -> JSString -> Maybe Char
1084+find = coerce T.find
1085+{-# INLINE find #-}
1086+
1087+-- | /O(n)/ The 'partition' function takes a predicate and a 'JSString',
1088+-- and returns the pair of 'JSString's with elements which do and do not
1089+-- satisfy the predicate, respectively; i.e.
1090+--
1091+-- > partition p t == (filter p t, filter (not . p) t)
1092+partition :: (Char -> Bool) -> JSString -> (JSString, JSString)
1093+partition = coerce T.partition
1094+{-# INLINE partition #-}
1095+
1096+-- | /O(n)/ 'filter', applied to a predicate and a 'JSString',
1097+-- returns a 'JSString' containing those characters that satisfy the
1098+-- predicate.
1099+filter :: (Char -> Bool) -> JSString -> JSString
1100+filter = coerce T.filter
1101+{-# INLINE filter #-}
1102+
1103+-- | /O(n+m)/ Find the first instance of @needle@ (which must be
1104+-- non-'null') in @haystack@. The first element of the returned tuple
1105+-- is the prefix of @haystack@ before @needle@ is matched. The second
1106+-- is the remainder of @haystack@, starting with the match.
1107+--
1108+-- Examples:
1109+--
1110+-- > breakOn "::" "a::b::c" ==> ("a", "::b::c")
1111+-- > breakOn "/" "foobar" ==> ("foobar", "")
1112+--
1113+-- Laws:
1114+--
1115+-- > append prefix match == haystack
1116+-- > where (prefix, match) = breakOn needle haystack
1117+--
1118+-- If you need to break a string by a substring repeatedly (e.g. you
1119+-- want to break on every instance of a substring), use 'breakOnAll'
1120+-- instead, as it has lower startup overhead.
1121+--
1122+-- In (unlikely) bad cases, this function's time complexity degrades
1123+-- towards /O(n*m)/.
1124+breakOn :: JSString -> JSString -> (JSString, JSString)
1125+breakOn = coerce T.breakOn
1126+{-# INLINE breakOn #-}
1127+
1128+-- | /O(n+m)/ Similar to 'breakOn', but searches from the end of the
1129+-- string.
1130+--
1131+-- The first element of the returned tuple is the prefix of @haystack@
1132+-- up to and including the last match of @needle@. The second is the
1133+-- remainder of @haystack@, following the match.
1134+--
1135+-- > breakOnEnd "::" "a::b::c" ==> ("a::b::", "c")
1136+breakOnEnd :: JSString -> JSString -> (JSString, JSString)
1137+breakOnEnd = coerce T.breakOnEnd
1138+{-# INLINE breakOnEnd #-}
1139+
1140+-- | /O(n+m)/ Find all non-overlapping instances of @needle@ in
1141+-- @haystack@. Each element of the returned list consists of a pair:
1142+--
1143+-- * The entire string prior to the /k/th match (i.e. the prefix)
1144+--
1145+-- * The /k/th match, followed by the remainder of the string
1146+--
1147+-- Examples:
1148+--
1149+-- > breakOnAll "::" ""
1150+-- > ==> []
1151+-- > breakOnAll "/" "a/b/c/"
1152+-- > ==> [("a", "/b/c/"), ("a/b", "/c/"), ("a/b/c", "/")]
1153+--
1154+-- In (unlikely) bad cases, this function's time complexity degrades
1155+-- towards /O(n*m)/.
1156+--
1157+-- The @needle@ parameter may not be empty.
1158+breakOnAll :: JSString -- ^ @needle@ to search for
1159+ -> JSString -- ^ @haystack@ in which to search
1160+ -> [(JSString, JSString)]
1161+breakOnAll = coerce T.breakOnAll
1162+{-# INLINE breakOnAll #-}
1163+
1164+breakOnAll' :: JSString -- ^ @needle@ to search for
1165+ -> JSString -- ^ @haystack@ in which to search
1166+ -> [(JSString, JSString)]
1167+breakOnAll' = coerce T.breakOnAll
1168+{-# INLINE breakOnAll' #-}
1169+
1170+-------------------------------------------------------------------------------
1171+-- ** Indexing 'JSString's
1172+
1173+-- $index
1174+--
1175+-- If you think of a 'JSString' value as an array of 'Char' values (which
1176+-- it is not), you run the risk of writing inefficient code.
1177+--
1178+-- An idiom that is common in some languages is to find the numeric
1179+-- offset of a character or substring, then use that number to split
1180+-- or trim the searched string. With a 'JSString' value, this approach
1181+-- would require two /O(n)/ operations: one to perform the search, and
1182+-- one to operate from wherever the search ended.
1183+--
1184+-- For example, suppose you have a string that you want to split on
1185+-- the substring @\"::\"@, such as @\"foo::bar::quux\"@. Instead of
1186+-- searching for the index of @\"::\"@ and taking the substrings
1187+-- before and after that index, you would instead use @breakOnAll \"::\"@.
1188+
1189+-- | /O(n)/ 'JSString' index (subscript) operator, starting from 0.
1190+index :: JSString -> Int -> Char
1191+index = coerce T.index
1192+{-# INLINE index #-}
1193+
1194+-- | /O(n)/ The 'findIndex' function takes a predicate and a 'JSString'
1195+-- and returns the index of the first element in the 'JSString' satisfying
1196+-- the predicate. Subject to fusion.
1197+findIndex :: (Char -> Bool) -> JSString -> Maybe Int
1198+findIndex = coerce T.findIndex
1199+{-# INLINE findIndex #-}
1200+
1201+-- | /O(n+m)/ The 'count' function returns the number of times the
1202+-- query string appears in the given 'JSString'. An empty query string is
1203+-- invalid, and will cause an error to be raised.
1204+--
1205+-- In (unlikely) bad cases, this function's time complexity degrades
1206+-- towards /O(n*m)/.
1207+count :: JSString -> JSString -> Int
1208+count = coerce T.count
1209+{-# INLINE [1] count #-}
1210+
1211+-- RULES
1212+-- "JSSTRING count/singleton -> countChar" [~1] forall c t.
1213+-- count (singleton c) t = countChar c t
1214+--
1215+
1216+-------------------------------------------------------------------------------
1217+-- * Zipping
1218+
1219+-- | /O(n)/ 'zip' takes two 'JSString's and returns a list of
1220+-- corresponding pairs of bytes. If one input 'JSString' is short,
1221+-- excess elements of the longer 'JSString' are discarded. This is
1222+-- equivalent to a pair of 'unpack' operations.
1223+zip :: JSString -> JSString -> [(Char,Char)]
1224+zip = coerce T.zip
1225+{-# INLINE [0] zip #-}
1226+
1227+-- | /O(n)/ 'zipWith' generalises 'zip' by zipping with the function
1228+-- given as the first argument, instead of a tupling function.
1229+-- Performs replacement on invalid scalar values.
1230+zipWith :: (Char -> Char -> Char) -> JSString -> JSString -> JSString
1231+zipWith = coerce T.zipWith
1232+{-# INLINE [0] zipWith #-}
1233+
1234+-- | /O(n)/ Breaks a 'JSString' up into a list of words, delimited by 'Char's
1235+-- representing white space.
1236+words :: JSString -> [JSString]
1237+words = coerce T.words
1238+{-# INLINE words #-}
1239+
1240+-- fixme: strict words' that allocates the whole list in one go
1241+words' :: JSString -> [JSString]
1242+words' = coerce T.words
1243+{-# INLINE words' #-}
1244+
1245+-- | /O(n)/ Breaks a 'JSString' up into a list of 'JSString's at
1246+-- newline 'Char's. The resulting strings do not contain newlines.
1247+lines :: JSString -> [JSString]
1248+lines = coerce T.lines
1249+{-# INLINE lines #-}
1250+
1251+lines' :: JSString -> [JSString]
1252+lines' = coerce T.lines
1253+{-# INLINE lines' #-}
1254+
1255+{-
1256+-- | /O(n)/ Portably breaks a 'JSString' up into a list of 'JSString's at line
1257+-- boundaries.
1258+--
1259+-- A line boundary is considered to be either a line feed, a carriage
1260+-- return immediately followed by a line feed, or a carriage return.
1261+-- This accounts for both Unix and Windows line ending conventions,
1262+-- and for the old convention used on Mac OS 9 and earlier.
1263+lines' :: Text -> [Text]
1264+lines' ps | null ps = []
1265+ | otherwise = h : case uncons t of
1266+ Nothing -> []
1267+ Just (c,t')
1268+ | c == '\n' -> lines t'
1269+ | c == '\r' -> case uncons t' of
1270+ Just ('\n',t'') -> lines t''
1271+ _ -> lines t'
1272+ where (h,t) = span notEOL ps
1273+ notEOL c = c /= '\n' && c /= '\r'
1274+
1275+-}
1276+
1277+-- | /O(n)/ Joins lines, after appending a terminating newline to
1278+-- each.
1279+unlines :: [JSString] -> JSString
1280+unlines = coerce T.unlines
1281+{-# INLINE unlines #-}
1282+
1283+-- | /O(n)/ Joins words using single space characters.
1284+unwords :: [JSString] -> JSString
1285+unwords = coerce T.unwords
1286+{-# INLINE unwords #-}
1287+
1288+-- | /O(n)/ The 'isPrefixOf' function takes two 'JSString's and returns
1289+-- 'True' iff the first is a prefix of the second. Subject to fusion.
1290+isPrefixOf :: JSString -> JSString -> Bool
1291+isPrefixOf = coerce T.isPrefixOf
1292+{-# INLINE [1] isPrefixOf #-}
1293+
1294+{-# RULES
1295+"JSSTRING isPrefixOf -> fused" [~1] forall x y.
1296+ isPrefixOf x y = S.isPrefixOf (stream x) (stream y)
1297+"JSSTRING isPrefixOf -> unfused" [1] forall x y.
1298+ S.isPrefixOf (stream x) (stream y) = isPrefixOf x y
1299+ #-}
1300+
1301+-- | /O(n)/ The 'isSuffixOf' function takes two 'JSString's and returns
1302+-- 'True' iff the first is a suffix of the second.
1303+isSuffixOf :: JSString -> JSString -> Bool
1304+isSuffixOf = coerce T.isSuffixOf
1305+{-# INLINE isSuffixOf #-}
1306+
1307+-- | The 'isInfixOf' function takes two 'JSString's and returns
1308+-- 'True' iff the first is contained, wholly and intact, anywhere
1309+-- within the second.
1310+--
1311+-- Complexity depends on how the JavaScript engine implements
1312+-- String.prototype.find.
1313+isInfixOf :: JSString -> JSString -> Bool
1314+isInfixOf = coerce T.isInfixOf
1315+{-# INLINE [1] isInfixOf #-}
1316+
1317+{-# RULES
1318+"JSSTRING isInfixOf/singleton -> S.elem/S.stream" [~1] forall n h.
1319+ isInfixOf (singleton n) h = S.elem n (S.stream h)
1320+ #-}
1321+
1322+-------------------------------------------------------------------------------
1323+-- * View patterns
1324+
1325+-- | /O(n)/ Return the suffix of the second string if its prefix
1326+-- matches the entire first string.
1327+--
1328+-- Examples:
1329+--
1330+-- > stripPrefix "foo" "foobar" == Just "bar"
1331+-- > stripPrefix "" "baz" == Just "baz"
1332+-- > stripPrefix "foo" "quux" == Nothing
1333+--
1334+-- This is particularly useful with the @ViewPatterns@ extension to
1335+-- GHC, as follows:
1336+--
1337+-- > {-# LANGUAGE ViewPatterns #-}
1338+-- > import Data.Text as T
1339+-- >
1340+-- > fnordLength :: JSString -> Int
1341+-- > fnordLength (stripPrefix "fnord" -> Just suf) = T.length suf
1342+-- > fnordLength _ = -1
1343+stripPrefix :: JSString -> JSString -> Maybe JSString
1344+stripPrefix = coerce T.stripPrefix
1345+{-# INLINE stripPrefix #-}
1346+
1347+-- | /O(n)/ Find the longest non-empty common prefix of two strings
1348+-- and return it, along with the suffixes of each string at which they
1349+-- no longer match.
1350+--
1351+-- If the strings do not have a common prefix or either one is empty,
1352+-- this function returns 'Nothing'.
1353+--
1354+-- Examples:
1355+--
1356+-- > commonPrefixes "foobar" "fooquux" == Just ("foo","bar","quux")
1357+-- > commonPrefixes "veeble" "fetzer" == Nothing
1358+-- > commonPrefixes "" "baz" == Nothing
1359+commonPrefixes :: JSString -> JSString -> Maybe (JSString,JSString,JSString)
1360+commonPrefixes = coerce T.commonPrefixes
1361+{-# INLINE commonPrefixes #-}
1362+
1363+-- | /O(n)/ Return the prefix of the second string if its suffix
1364+-- matches the entire first string.
1365+--
1366+-- Examples:
1367+--
1368+-- > stripSuffix "bar" "foobar" == Just "foo"
1369+-- > stripSuffix "" "baz" == Just "baz"
1370+-- > stripSuffix "foo" "quux" == Nothing
1371+--
1372+-- This is particularly useful with the @ViewPatterns@ extension to
1373+-- GHC, as follows:
1374+--
1375+-- > {-# LANGUAGE ViewPatterns #-}
1376+-- > import Data.Text as T
1377+-- >
1378+-- > quuxLength :: Text -> Int
1379+-- > quuxLength (stripSuffix "quux" -> Just pre) = T.length pre
1380+-- > quuxLength _ = -1
1381+stripSuffix :: JSString -> JSString -> Maybe JSString
1382+stripSuffix = coerce T.stripSuffix
1383+{-# INLINE stripSuffix #-}
1384+
1385+---- | Add a list of non-negative numbers. Errors out on overflow.
1386+--sumP :: String -> [Int] -> Int
1387+--sumP fun = go 0
1388+-- where go !a (x:xs)
1389+-- | ax >= 0 = go ax xs
1390+-- | otherwise = overflowError fun
1391+-- where ax = a + x
1392+-- go a _ = a
1393+--
1394+--emptyError :: String -> a
1395+--emptyError fun = P.error $ "Data.JSString." ++ fun ++ ": empty input"
1396+--
1397+--overflowError :: String -> a
1398+--overflowError fun = P.error $ "Data.JSString." ++ fun ++ ": size overflow"
1399+--
1400+--charWidth :: Int# -> Int#
1401+--charWidth cp | isTrue# (cp >=# 0x10000#) = 2#
1402+-- | otherwise = 1#
1403+--{-# INLINE charWidth #-}