packages feed

text 1.2.4.0 → 1.2.4.1

raw patch · 101 files changed

+12094/−12013 lines, 101 filesdep +ghc-bignumdep −HUnitdep −QuickCheckdep −directorydep ~arraydep ~basedep ~binary

Dependencies added: ghc-bignum

Dependencies removed: HUnit, QuickCheck, directory, quickcheck-unicode, random, test-framework, test-framework-hunit, test-framework-quickcheck2

Dependency ranges changed: array, base, binary, bytestring, bytestring-builder, deepseq, ghc-prim, integer-gmp, template-haskell

Files

− Data/Text.hs
@@ -1,1887 +0,0 @@-{-# LANGUAGE BangPatterns, CPP, MagicHash, Rank2Types, UnboxedTuples, TypeFamilies #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}-#if __GLASGOW_HASKELL__ >= 702-{-# LANGUAGE Trustworthy #-}-#endif--- Using TemplateHaskell in text unconditionally is unacceptable, as--- it's a GHC boot library. TemplateHaskellQuotes was added in 8.0, so--- this would seem to be a problem. However, GHC's policy of only--- needing to be able to compile itself from the last few releases--- allows us to use full-fat TH on older versions, while using THQ for--- GHC versions that may be used for bootstrapping.-#if __GLASGOW_HASKELL__ >= 800-{-# LANGUAGE TemplateHaskellQuotes #-}-#else-{-# LANGUAGE TemplateHaskell #-}-#endif---- |--- Module      : Data.Text--- Copyright   : (c) 2009, 2010, 2011, 2012 Bryan O'Sullivan,---               (c) 2009 Duncan Coutts,---               (c) 2008, 2009 Tom Harper------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Portability : GHC------ A time and space-efficient implementation of Unicode text.--- Suitable for performance critical use, both in terms of large data--- quantities and high speed.------ /Note/: Read below the synopsis for important notes on the use of--- this module.------ This module is intended to be imported @qualified@, to avoid name--- clashes with "Prelude" functions, e.g.------ > import qualified Data.Text as T------ To use an extended and very rich family of functions for working--- with Unicode text (including normalization, regular expressions,--- non-standard encodings, text breaking, and locales), see the--- <http://hackage.haskell.org/package/text-icu text-icu package >.-----module Data.Text-    (-    -- * Strict vs lazy types-    -- $strict--    -- * Acceptable data-    -- $replacement--    -- * Definition of character-    -- $character_definition--    -- * Fusion-    -- $fusion--    -- * Types-      Text--    -- * Creation and elimination-    , pack-    , unpack-    , singleton-    , empty--    -- * Basic interface-    , cons-    , snoc-    , append-    , uncons-    , unsnoc-    , head-    , last-    , tail-    , init-    , null-    , length-    , compareLength--    -- * Transformations-    , map-    , intercalate-    , intersperse-    , transpose-    , reverse-    , replace--    -- ** Case conversion-    -- $case-    , toCaseFold-    , toLower-    , toUpper-    , toTitle--    -- ** Justification-    , justifyLeft-    , justifyRight-    , center--    -- * Folds-    , foldl-    , foldl'-    , foldl1-    , foldl1'-    , foldr-    , foldr1--    -- ** Special folds-    , concat-    , concatMap-    , any-    , all-    , maximum-    , minimum--    -- * Construction--    -- ** Scans-    , scanl-    , scanl1-    , scanr-    , scanr1--    -- ** Accumulating maps-    , mapAccumL-    , mapAccumR--    -- ** Generation and unfolding-    , replicate-    , unfoldr-    , unfoldrN--    -- * Substrings--    -- ** Breaking strings-    , take-    , takeEnd-    , drop-    , dropEnd-    , takeWhile-    , takeWhileEnd-    , dropWhile-    , dropWhileEnd-    , dropAround-    , strip-    , stripStart-    , stripEnd-    , splitAt-    , breakOn-    , breakOnEnd-    , break-    , span-    , group-    , groupBy-    , inits-    , tails--    -- ** Breaking into many substrings-    -- $split-    , splitOn-    , split-    , chunksOf--    -- ** Breaking into lines and words-    , lines-    --, lines'-    , words-    , unlines-    , unwords--    -- * Predicates-    , isPrefixOf-    , isSuffixOf-    , isInfixOf--    -- ** View patterns-    , stripPrefix-    , stripSuffix-    , commonPrefixes--    -- * Searching-    , filter-    , breakOnAll-    , find-    , partition--    -- , findSubstring--    -- * Indexing-    -- $index-    , index-    , findIndex-    , count--    -- * Zipping-    , zip-    , zipWith--    -- -* Ordered text-    -- , sort--    -- * Low level operations-    , copy-    , unpackCString#-    ) where--import Prelude (Char, Bool(..), Int, Maybe(..), String,-                Eq(..), Ord(..), Ordering(..), (++),-                Read(..),-                (&&), (||), (+), (-), (.), ($), ($!), (>>),-                not, return, otherwise, quot)-import Control.DeepSeq (NFData(rnf))-#if defined(ASSERTS)-import Control.Exception (assert)-#endif-import Data.Char (isSpace)-import Data.Data (Data(gfoldl, toConstr, gunfold, dataTypeOf), constrIndex,-                  Constr, mkConstr, DataType, mkDataType, Fixity(Prefix))-import Control.Monad (foldM)-import Control.Monad.ST (ST)-import qualified Data.Text.Array as A-import qualified Data.List as L-import Data.Binary (Binary(get, put))-import Data.Monoid (Monoid(..))-#if MIN_VERSION_base(4,9,0)-import Data.Semigroup (Semigroup(..))-#endif-import Data.String (IsString(..))-import qualified Data.Text.Internal.Fusion as S-import qualified Data.Text.Internal.Fusion.Common as S-import Data.Text.Encoding (decodeUtf8', encodeUtf8)-import Data.Text.Internal.Fusion (stream, reverseStream, unstream)-import Data.Text.Internal.Private (span_)-import Data.Text.Internal (Text(..), empty, firstf, mul, safe, text)-import Data.Text.Show (singleton, unpack, unpackCString#)-import qualified Prelude as P-import Data.Text.Unsafe (Iter(..), iter, iter_, lengthWord16, reverseIter,-                         reverseIter_, unsafeHead, unsafeTail)-import Data.Text.Internal.Unsafe.Char (unsafeChr)-import qualified Data.Text.Internal.Functions as F-import qualified Data.Text.Internal.Encoding.Utf16 as U16-import Data.Text.Internal.Search (indices)-import Data.Text.Internal.Unsafe.Shift (UnsafeShift(..))-#if defined(__HADDOCK__)-import Data.ByteString (ByteString)-import qualified Data.Text.Lazy as L-import Data.Int (Int64)-#endif-import GHC.Base (eqInt, neInt, gtInt, geInt, ltInt, leInt)-#if MIN_VERSION_base(4,7,0)-import qualified GHC.Exts as Exts-#endif-import qualified Language.Haskell.TH.Lib as TH-import Language.Haskell.TH.Syntax (Lift, lift)-#if MIN_VERSION_base(4,7,0)-import Text.Printf (PrintfArg, formatArg, formatString)-#endif---- $character_definition------ This package uses the term /character/ to denote Unicode /code points/.------ Note that this is not the same thing as a grapheme (e.g. a--- composition of code points that form one visual symbol). For--- instance, consider the grapheme \"&#x00e4;\". This symbol has two--- Unicode representations: a single code-point representation--- @U+00E4@ (the @LATIN SMALL LETTER A WITH DIAERESIS@ code point),--- and a two code point representation @U+0061@ (the \"@A@\" code--- point) and @U+0308@ (the @COMBINING DIAERESIS@ code point).---- $strict------ This package provides both strict and lazy 'Text' types.  The--- strict type is provided by the "Data.Text" module, while the lazy--- type is provided by the "Data.Text.Lazy" module. Internally, the--- lazy @Text@ type consists of a list of strict chunks.------ The strict 'Text' type requires that an entire string fit into--- memory at once.  The lazy 'Data.Text.Lazy.Text' type is capable of--- streaming strings that are larger than memory using a small memory--- footprint.  In many cases, the overhead of chunked streaming makes--- the lazy 'Data.Text.Lazy.Text' type slower than its strict--- counterpart, but this is not always the case.  Sometimes, the time--- complexity of a function in one module may be different from the--- other, due to their differing internal structures.------ Each module provides an almost identical API, with the main--- difference being that the strict module uses 'Int' values for--- lengths and counts, while the lazy module uses 'Data.Int.Int64'--- lengths.---- $replacement------ A 'Text' value is a sequence of Unicode scalar values, as defined--- in--- <http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#page=35 §3.9, definition D76 of the Unicode 5.2 standard >.--- As such, a 'Text' cannot contain values in the range U+D800 to--- U+DFFF inclusive. Haskell implementations admit all Unicode code--- points--- (<http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#page=13 §3.4, definition D10 >)--- as 'Char' values, including code points from this invalid range.--- This means that there are some 'Char' values that are not valid--- Unicode scalar values, and the functions in this module must handle--- those cases.------ Within this module, many functions construct a 'Text' from one or--- more 'Char' values. Those functions will substitute 'Char' values--- that are not valid Unicode scalar values with the replacement--- character \"&#xfffd;\" (U+FFFD).  Functions that perform this--- inspection and replacement are documented with the phrase--- \"Performs replacement on invalid scalar values\".------ (One reason for this policy of replacement is that internally, a--- 'Text' value is represented as packed UTF-16 data. Values in the--- range U+D800 through U+DFFF are used by UTF-16 to denote surrogate--- code points, and so cannot be represented. The functions replace--- invalid scalar values, instead of dropping them, as a security--- measure. For details, see--- <http://unicode.org/reports/tr36/#Deletion_of_Noncharacters Unicode Technical Report 36, §3.5 >.)---- $fusion------ Most of the functions in this module are subject to /fusion/,--- meaning that a pipeline of such functions will usually allocate at--- most one 'Text' value.------ As an example, consider the following pipeline:------ > import Data.Text as T--- > import Data.Text.Encoding as E--- > import Data.ByteString (ByteString)--- >--- > countChars :: ByteString -> Int--- > countChars = T.length . T.toUpper . E.decodeUtf8------ From the type signatures involved, this looks like it should--- allocate one 'Data.ByteString.ByteString' value, and two 'Text'--- values. However, when a module is compiled with optimisation--- enabled under GHC, the two intermediate 'Text' values will be--- optimised away, and the function will be compiled down to a single--- loop over the source 'Data.ByteString.ByteString'.------ Functions that can be fused by the compiler are documented with the--- phrase \"Subject to fusion\".--instance Eq Text where-    Text arrA offA lenA == Text arrB offB lenB-        | lenA == lenB = A.equal arrA offA arrB offB lenA-        | otherwise    = False-    {-# INLINE (==) #-}--instance Ord Text where-    compare = compareText--instance Read Text where-    readsPrec p str = [(pack x,y) | (x,y) <- readsPrec p str]--#if MIN_VERSION_base(4,9,0)--- | Non-orphan 'Semigroup' instance only defined for--- @base-4.9.0.0@ and later; orphan instances for older GHCs are--- provided by--- the [semigroups](http://hackage.haskell.org/package/semigroups)--- package------ @since 1.2.2.0-instance Semigroup Text where-    (<>) = append-#endif--instance Monoid Text where-    mempty  = empty-#if MIN_VERSION_base(4,9,0)-    mappend = (<>) -- future-proof definition-#else-    mappend = append-#endif-    mconcat = concat--instance IsString Text where-    fromString = pack--#if MIN_VERSION_base(4,7,0)--- | @since 1.2.0.0-instance Exts.IsList Text where-    type Item Text = Char-    fromList       = pack-    toList         = unpack-#endif--instance NFData Text where rnf !_ = ()---- | @since 1.2.1.0-instance Binary Text where-    put t = put (encodeUtf8 t)-    get   = do-      bs <- get-      case decodeUtf8' bs of-        P.Left exn -> P.fail (P.show exn)-        P.Right a -> P.return a---- | This instance preserves data abstraction at the cost of inefficiency.--- We omit reflection services for the sake of data abstraction.------ This instance was created by copying the updated behavior of--- @"Data.Set".@'Data.Set.Set' and @"Data.Map".@'Data.Map.Map'. If you--- feel a mistake has been made, please feel free to submit--- improvements.------ The original discussion is archived here:--- <https://mail.haskell.org/pipermail/haskell-cafe/2010-January/072379.html could we get a Data instance for Data.Text.Text? >------ The followup discussion that changed the behavior of 'Data.Set.Set'--- and 'Data.Map.Map' is archived here:--- <http://markmail.org/message/trovdc6zkphyi3cr#query:+page:1+mid:a46der3iacwjcf6n+state:results Proposal: Allow gunfold for Data.Map, ... >--instance Data Text where-  gfoldl f z txt = z pack `f` (unpack txt)-  toConstr _ = packConstr-  gunfold k z c = case constrIndex c of-    1 -> k (z pack)-    _ -> P.error "gunfold"-  dataTypeOf _ = textDataType---- | This instance has similar considerations to the 'Data' instance:--- it preserves abstraction at the cost of inefficiency.------ @since 1.2.4.0-instance Lift Text where-  lift = TH.appE (TH.varE 'pack) . TH.stringE . unpack--#if MIN_VERSION_base(4,7,0)--- | Only defined for @base-4.7.0.0@ and later------ @since 1.2.2.0-instance PrintfArg Text where-  formatArg txt = formatString $ unpack txt-#endif--packConstr :: Constr-packConstr = mkConstr textDataType "pack" [] Prefix--textDataType :: DataType-textDataType = mkDataType "Data.Text.Text" [packConstr]---- | /O(n)/ Compare two 'Text' values lexicographically.-compareText :: Text -> Text -> Ordering-compareText ta@(Text _arrA _offA lenA) tb@(Text _arrB _offB lenB)-    | lenA == 0 && lenB == 0 = EQ-    | otherwise              = go 0 0-  where-    go !i !j-        | i >= lenA || j >= lenB = compare lenA lenB-        | a < b                  = LT-        | a > b                  = GT-        | otherwise              = go (i+di) (j+dj)-      where Iter a di = iter ta i-            Iter b dj = iter tb j---- -------------------------------------------------------------------------------- * Conversion to/from 'Text'---- | /O(n)/ Convert a 'String' into a 'Text'.  Subject to--- fusion.  Performs replacement on invalid scalar values.-pack :: String -> Text-pack = unstream . S.map safe . S.streamList-{-# INLINE [1] pack #-}---- -------------------------------------------------------------------------------- * Basic functions---- | /O(n)/ Adds a character to the front of a 'Text'.  This function--- is more costly than its 'List' counterpart because it requires--- copying a new array.  Subject to fusion.  Performs replacement on--- invalid scalar values.-cons :: Char -> Text -> Text-cons c t = unstream (S.cons (safe c) (stream t))-{-# INLINE cons #-}--infixr 5 `cons`---- | /O(n)/ Adds a character to the end of a 'Text'.  This copies the--- entire array in the process, unless fused.  Subject to fusion.--- Performs replacement on invalid scalar values.-snoc :: Text -> Char -> Text-snoc t c = unstream (S.snoc (stream t) (safe c))-{-# INLINE snoc #-}---- | /O(n)/ Appends one 'Text' to the other by copying both of them--- into a new 'Text'.  Subject to fusion.-append :: Text -> Text -> Text-append a@(Text arr1 off1 len1) b@(Text arr2 off2 len2)-    | len1 == 0 = b-    | len2 == 0 = a-    | len > 0   = Text (A.run x) 0 len-    | otherwise = overflowError "append"-    where-      len = len1+len2-      x :: ST s (A.MArray s)-      x = do-        arr <- A.new len-        A.copyI arr 0 arr1 off1 len1-        A.copyI arr len1 arr2 off2 len-        return arr-{-# NOINLINE append #-}--{-# RULES-"TEXT append -> fused" [~1] forall t1 t2.-    append t1 t2 = unstream (S.append (stream t1) (stream t2))-"TEXT append -> unfused" [1] forall t1 t2.-    unstream (S.append (stream t1) (stream t2)) = append t1 t2- #-}---- | /O(1)/ Returns the first character of a 'Text', which must be--- non-empty.  Subject to fusion.-head :: Text -> Char-head t = S.head (stream t)-{-# INLINE head #-}---- | /O(1)/ Returns the first character and rest of a 'Text', or--- 'Nothing' if empty. Subject to fusion.-uncons :: Text -> Maybe (Char, Text)-uncons t@(Text arr off len)-    | len <= 0  = Nothing-    | otherwise = Just $ let !(Iter c d) = iter t 0-                         in (c, text arr (off+d) (len-d))-{-# INLINE [1] uncons #-}---- | Lifted from Control.Arrow and specialized.-second :: (b -> c) -> (a,b) -> (a,c)-second f (a, b) = (a, f b)---- | /O(1)/ Returns the last character of a 'Text', which must be--- non-empty.  Subject to fusion.-last :: Text -> Char-last (Text arr off len)-    | len <= 0                 = emptyError "last"-    | n < 0xDC00 || n > 0xDFFF = unsafeChr n-    | otherwise                = U16.chr2 n0 n-    where n  = A.unsafeIndex arr (off+len-1)-          n0 = A.unsafeIndex arr (off+len-2)-{-# INLINE [1] last #-}--{-# RULES-"TEXT last -> fused" [~1] forall t.-    last t = S.last (stream t)-"TEXT last -> unfused" [1] forall t.-    S.last (stream t) = last t-  #-}---- | /O(1)/ Returns all characters after the head of a 'Text', which--- must be non-empty.  Subject to fusion.-tail :: Text -> Text-tail t@(Text arr off len)-    | len <= 0  = emptyError "tail"-    | otherwise = text arr (off+d) (len-d)-    where d = iter_ t 0-{-# INLINE [1] tail #-}--{-# RULES-"TEXT tail -> fused" [~1] forall t.-    tail t = unstream (S.tail (stream t))-"TEXT tail -> unfused" [1] forall t.-    unstream (S.tail (stream t)) = tail t- #-}---- | /O(1)/ Returns all but the last character of a 'Text', which must--- be non-empty.  Subject to fusion.-init :: Text -> Text-init (Text arr off len) | len <= 0                   = emptyError "init"-                        | n >= 0xDC00 && n <= 0xDFFF = text arr off (len-2)-                        | otherwise                  = text arr off (len-1)-    where-      n = A.unsafeIndex arr (off+len-1)-{-# INLINE [1] init #-}--{-# RULES-"TEXT init -> fused" [~1] forall t.-    init t = unstream (S.init (stream t))-"TEXT init -> unfused" [1] forall t.-    unstream (S.init (stream t)) = init t- #-}---- | /O(1)/ Returns all but the last character and the last character of a--- 'Text', or 'Nothing' if empty.------ @since 1.2.3.0-unsnoc :: Text -> Maybe (Text, Char)-unsnoc (Text arr off len)-    | len <= 0                 = Nothing-    | n < 0xDC00 || n > 0xDFFF = Just (text arr off (len-1), unsafeChr n)-    | otherwise                = Just (text arr off (len-2), U16.chr2 n0 n)-    where n  = A.unsafeIndex arr (off+len-1)-          n0 = A.unsafeIndex arr (off+len-2)-{-# INLINE [1] unsnoc #-}---- | /O(1)/ Tests whether a 'Text' is empty or not.  Subject to--- fusion.-null :: Text -> Bool-null (Text _arr _off len) =-#if defined(ASSERTS)-    assert (len >= 0) $-#endif-    len <= 0-{-# INLINE [1] null #-}--{-# RULES-"TEXT null -> fused" [~1] forall t.-    null t = S.null (stream t)-"TEXT null -> unfused" [1] forall t.-    S.null (stream t) = null t- #-}---- | /O(1)/ Tests whether a 'Text' contains exactly one character.--- Subject to fusion.-isSingleton :: Text -> Bool-isSingleton = S.isSingleton . stream-{-# INLINE isSingleton #-}---- | /O(n)/ Returns the number of characters in a 'Text'.--- Subject to fusion.-length :: Text -> Int-length t = S.length (stream t)-{-# INLINE [1] length #-}--- length needs to be phased after the compareN/length rules otherwise--- it may inline before the rules have an opportunity to fire.---- | /O(n)/ Compare the count of characters in a 'Text' to a number.--- Subject to fusion.------ This function gives the same answer as comparing against the result--- of 'length', but can short circuit if the count of characters is--- greater than the number, and hence be more efficient.-compareLength :: Text -> Int -> Ordering-compareLength t n = S.compareLengthI (stream t) n-{-# INLINE [1] compareLength #-}--{-# RULES-"TEXT compareN/length -> compareLength" [~1] forall t n.-    compare (length t) n = compareLength t n-  #-}--{-# RULES-"TEXT ==N/length -> compareLength/==EQ" [~1] forall t n.-    eqInt (length t) n = compareLength t n == EQ-  #-}--{-# RULES-"TEXT /=N/length -> compareLength//=EQ" [~1] forall t n.-    neInt (length t) n = compareLength t n /= EQ-  #-}--{-# RULES-"TEXT <N/length -> compareLength/==LT" [~1] forall t n.-    ltInt (length t) n = compareLength t n == LT-  #-}--{-# RULES-"TEXT <=N/length -> compareLength//=GT" [~1] forall t n.-    leInt (length t) n = compareLength t n /= GT-  #-}--{-# RULES-"TEXT >N/length -> compareLength/==GT" [~1] forall t n.-    gtInt (length t) n = compareLength t n == GT-  #-}--{-# RULES-"TEXT >=N/length -> compareLength//=LT" [~1] forall t n.-    geInt (length t) n = compareLength t n /= LT-  #-}---- -------------------------------------------------------------------------------- * Transformations--- | /O(n)/ 'map' @f@ @t@ is the 'Text' obtained by applying @f@ to--- each element of @t@.------ Example:------ >>> let message = pack "I am not angry. Not at all."--- >>> T.map (\c -> if c == '.' then '!' else c) message--- "I am not angry! Not at all!"------ Subject to fusion.  Performs replacement on invalid scalar values.-map :: (Char -> Char) -> Text -> Text-map f t = unstream (S.map (safe . f) (stream t))-{-# INLINE [1] map #-}---- | /O(n)/ The 'intercalate' function takes a 'Text' and a list of--- 'Text's and concatenates the list after interspersing the first--- argument between each element of the list.------ Example:------ >>> T.intercalate "NI!" ["We", "seek", "the", "Holy", "Grail"]--- "WeNI!seekNI!theNI!HolyNI!Grail"-intercalate :: Text -> [Text] -> Text-intercalate t = concat . (F.intersperse t)-{-# INLINE intercalate #-}---- | /O(n)/ The 'intersperse' function takes a character and places it--- between the characters of a 'Text'.------ Example:------ >>> T.intersperse '.' "SHIELD"--- "S.H.I.E.L.D"------ Subject to fusion.  Performs replacement on invalid scalar values.-intersperse     :: Char -> Text -> Text-intersperse c t = unstream (S.intersperse (safe c) (stream t))-{-# INLINE intersperse #-}---- | /O(n)/ Reverse the characters of a string.------ Example:------ >>> T.reverse "desrever"--- "reversed"------ Subject to fusion (fuses with its argument).-reverse :: Text -> Text-reverse t = S.reverse (stream t)-{-# INLINE reverse #-}---- | /O(m+n)/ Replace every non-overlapping occurrence of @needle@ in--- @haystack@ with @replacement@.------ This function behaves as though it was defined as follows:------ @--- replace needle replacement haystack =---   'intercalate' replacement ('splitOn' needle haystack)--- @------ As this suggests, each occurrence is replaced exactly once.  So if--- @needle@ occurs in @replacement@, that occurrence will /not/ itself--- be replaced recursively:------ >>> replace "oo" "foo" "oo"--- "foo"------ In cases where several instances of @needle@ overlap, only the--- first one will be replaced:------ >>> replace "ofo" "bar" "ofofo"--- "barfo"------ In (unlikely) bad cases, this function's time complexity degrades--- towards /O(n*m)/.-replace :: Text-        -- ^ @needle@ to search for.  If this string is empty, an-        -- error will occur.-        -> Text-        -- ^ @replacement@ to replace @needle@ with.-        -> Text-        -- ^ @haystack@ in which to search.-        -> Text-replace needle@(Text _      _      neeLen)-               (Text repArr repOff repLen)-      haystack@(Text hayArr hayOff hayLen)-  | neeLen == 0 = emptyError "replace"-  | L.null ixs  = haystack-  | len > 0     = Text (A.run x) 0 len-  | otherwise   = empty-  where-    ixs = indices needle haystack-    len = hayLen - (neeLen - repLen) `mul` L.length ixs-    x :: ST s (A.MArray s)-    x = do-      marr <- A.new len-      let loop (i:is) o d = do-            let d0 = d + i - o-                d1 = d0 + repLen-            A.copyI marr d  hayArr (hayOff+o) d0-            A.copyI marr d0 repArr repOff d1-            loop is (i + neeLen) d1-          loop []     o d = A.copyI marr d hayArr (hayOff+o) len-      loop ixs 0 0-      return marr---- ------------------------------------------------------------------------------- ** Case conversions (folds)---- $case------ When case converting 'Text' values, do not use combinators like--- @map toUpper@ to case convert each character of a string--- individually, as this gives incorrect results according to the--- rules of some writing systems.  The whole-string case conversion--- functions from this module, such as @toUpper@, obey the correct--- case conversion rules.  As a result, these functions may map one--- input character to two or three output characters. For examples,--- see the documentation of each function.------ /Note/: In some languages, case conversion is a locale- and--- context-dependent operation. The case conversion functions in this--- module are /not/ locale sensitive. Programs that require locale--- sensitivity should use appropriate versions of the--- <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 >.---- | /O(n)/ Convert a string to folded case.  Subject to fusion.------ This function is mainly useful for performing caseless (also known--- as case insensitive) string comparisons.------ A string @x@ is a caseless match for a string @y@ if and only if:------ @toCaseFold x == toCaseFold y@------ The result string may be longer than the input string, and may--- differ from applying 'toLower' to the input string.  For instance,--- the Armenian small ligature \"&#xfb13;\" (men now, U+FB13) is case--- folded to the sequence \"&#x574;\" (men, U+0574) followed by--- \"&#x576;\" (now, U+0576), while the Greek \"&#xb5;\" (micro sign,--- U+00B5) is case folded to \"&#x3bc;\" (small letter mu, U+03BC)--- instead of itself.-toCaseFold :: Text -> Text-toCaseFold t = unstream (S.toCaseFold (stream t))-{-# INLINE toCaseFold #-}---- | /O(n)/ Convert a string to lower case, using simple case--- conversion.  Subject to fusion.------ The result string may be longer than the input string.  For--- instance, \"&#x130;\" (Latin capital letter I with dot above,--- U+0130) maps to the sequence \"i\" (Latin small letter i, U+0069)--- followed by \" &#x307;\" (combining dot above, U+0307).-toLower :: Text -> Text-toLower t = unstream (S.toLower (stream t))-{-# INLINE toLower #-}---- | /O(n)/ Convert a string to upper case, using simple case--- conversion.  Subject to fusion.------ The result string may be longer than the input string.  For--- instance, the German \"&#xdf;\" (eszett, U+00DF) maps to the--- two-letter sequence \"SS\".-toUpper :: Text -> Text-toUpper t = unstream (S.toUpper (stream t))-{-# INLINE toUpper #-}---- | /O(n)/ Convert a string to title case, using simple case--- conversion. Subject to fusion.------ The first letter of the input is converted to title case, as is--- every subsequent letter that immediately follows a non-letter.--- Every letter that immediately follows another letter is converted--- to lower case.------ The result string may be longer than the input string. For example,--- the Latin small ligature &#xfb02; (U+FB02) is converted to the--- sequence Latin capital letter F (U+0046) followed by Latin small--- letter l (U+006C).------ /Note/: this function does not take language or culture specific--- rules into account. For instance, in English, different style--- guides disagree on whether the book name \"The Hill of the Red--- Fox\" is correctly title cased&#x2014;but this function will--- capitalize /every/ word.------ @since 1.0.0.0-toTitle :: Text -> Text-toTitle t = unstream (S.toTitle (stream t))-{-# INLINE toTitle #-}---- | /O(n)/ Left-justify a string to the given length, using the--- specified fill character on the right. Subject to fusion.--- Performs replacement on invalid scalar values.------ Examples:------ >>> justifyLeft 7 'x' "foo"--- "fooxxxx"------ >>> justifyLeft 3 'x' "foobar"--- "foobar"-justifyLeft :: Int -> Char -> Text -> Text-justifyLeft k c t-    | len >= k  = t-    | otherwise = t `append` replicateChar (k-len) c-  where len = length t-{-# INLINE [1] justifyLeft #-}--{-# RULES-"TEXT justifyLeft -> fused" [~1] forall k c t.-    justifyLeft k c t = unstream (S.justifyLeftI k c (stream t))-"TEXT justifyLeft -> unfused" [1] forall k c t.-    unstream (S.justifyLeftI k c (stream t)) = justifyLeft k c t-  #-}---- | /O(n)/ Right-justify a string to the given length, using the--- specified fill character on the left.  Performs replacement on--- invalid scalar values.------ Examples:------ >>> justifyRight 7 'x' "bar"--- "xxxxbar"------ >>> justifyRight 3 'x' "foobar"--- "foobar"-justifyRight :: Int -> Char -> Text -> Text-justifyRight k c t-    | len >= k  = t-    | otherwise = replicateChar (k-len) c `append` t-  where len = length t-{-# INLINE justifyRight #-}---- | /O(n)/ Center a string to the given length, using the specified--- fill character on either side.  Performs replacement on invalid--- scalar values.------ Examples:------ >>> center 8 'x' "HS"--- "xxxHSxxx"-center :: Int -> Char -> Text -> Text-center k c t-    | len >= k  = t-    | otherwise = replicateChar l c `append` t `append` replicateChar r c-  where len = length t-        d   = k - len-        r   = d `quot` 2-        l   = d - r-{-# INLINE center #-}---- | /O(n)/ The 'transpose' function transposes the rows and columns--- of its 'Text' argument.  Note that this function uses 'pack',--- 'unpack', and the list version of transpose, and is thus not very--- efficient.------ Examples:------ >>> transpose ["green","orange"]--- ["go","rr","ea","en","ng","e"]------ >>> transpose ["blue","red"]--- ["br","le","ud","e"]-transpose :: [Text] -> [Text]-transpose ts = P.map pack (L.transpose (P.map unpack ts))---- -------------------------------------------------------------------------------- * Reducing 'Text's (folds)---- | /O(n)/ 'foldl', applied to a binary operator, a starting value--- (typically the left-identity of the operator), and a 'Text',--- reduces the 'Text' using the binary operator, from left to right.--- Subject to fusion.-foldl :: (a -> Char -> a) -> a -> Text -> a-foldl f z t = S.foldl f z (stream t)-{-# INLINE foldl #-}---- | /O(n)/ A strict version of 'foldl'.  Subject to fusion.-foldl' :: (a -> Char -> a) -> a -> Text -> a-foldl' f z t = S.foldl' f z (stream t)-{-# INLINE foldl' #-}---- | /O(n)/ A variant of 'foldl' that has no starting value argument,--- and thus must be applied to a non-empty 'Text'.  Subject to fusion.-foldl1 :: (Char -> Char -> Char) -> Text -> Char-foldl1 f t = S.foldl1 f (stream t)-{-# INLINE foldl1 #-}---- | /O(n)/ A strict version of 'foldl1'.  Subject to fusion.-foldl1' :: (Char -> Char -> Char) -> Text -> Char-foldl1' f t = S.foldl1' f (stream t)-{-# INLINE foldl1' #-}---- | /O(n)/ 'foldr', applied to a binary operator, a starting value--- (typically the right-identity of the operator), and a 'Text',--- reduces the 'Text' using the binary operator, from right to left.--- Subject to fusion.-foldr :: (Char -> a -> a) -> a -> Text -> a-foldr f z t = S.foldr f z (stream t)-{-# INLINE foldr #-}---- | /O(n)/ A variant of 'foldr' that has no starting value argument,--- and thus must be applied to a non-empty 'Text'.  Subject to--- fusion.-foldr1 :: (Char -> Char -> Char) -> Text -> Char-foldr1 f t = S.foldr1 f (stream t)-{-# INLINE foldr1 #-}---- -------------------------------------------------------------------------------- ** Special folds---- | /O(n)/ Concatenate a list of 'Text's.-concat :: [Text] -> Text-concat ts = case ts' of-              [] -> empty-              [t] -> t-              _ -> Text (A.run go) 0 len-  where-    ts' = L.filter (not . null) ts-    len = sumP "concat" $ L.map lengthWord16 ts'-    go :: ST s (A.MArray s)-    go = do-      arr <- A.new len-      let step i (Text a o l) =-            let !j = i + l in A.copyI arr i a o j >> return j-      foldM step 0 ts' >> return arr---- | /O(n)/ Map a function over a 'Text' that results in a 'Text', and--- concatenate the results.-concatMap :: (Char -> Text) -> Text -> Text-concatMap f = concat . foldr ((:) . f) []-{-# INLINE concatMap #-}---- | /O(n)/ 'any' @p@ @t@ determines whether any character in the--- 'Text' @t@ satisfies the predicate @p@. Subject to fusion.-any :: (Char -> Bool) -> Text -> Bool-any p t = S.any p (stream t)-{-# INLINE any #-}---- | /O(n)/ 'all' @p@ @t@ determines whether all characters in the--- 'Text' @t@ satisfy the predicate @p@. Subject to fusion.-all :: (Char -> Bool) -> Text -> Bool-all p t = S.all p (stream t)-{-# INLINE all #-}---- | /O(n)/ 'maximum' returns the maximum value from a 'Text', which--- must be non-empty. Subject to fusion.-maximum :: Text -> Char-maximum t = S.maximum (stream t)-{-# INLINE maximum #-}---- | /O(n)/ 'minimum' returns the minimum value from a 'Text', which--- must be non-empty. Subject to fusion.-minimum :: Text -> Char-minimum t = S.minimum (stream t)-{-# INLINE minimum #-}---- -------------------------------------------------------------------------------- * Building 'Text's---- | /O(n)/ 'scanl' is similar to 'foldl', but returns a list of--- successive reduced values from the left. Subject to fusion.--- Performs replacement on invalid scalar values.------ > scanl f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...]------ Note that------ > last (scanl f z xs) == foldl f z xs.-scanl :: (Char -> Char -> Char) -> Char -> Text -> Text-scanl f z t = unstream (S.scanl g z (stream t))-    where g a b = safe (f a b)-{-# INLINE scanl #-}---- | /O(n)/ 'scanl1' is a variant of 'scanl' that has no starting--- value argument. Performs replacement on invalid scalar values.------ > scanl1 f [x1, x2, ...] == [x1, x1 `f` x2, ...]-scanl1 :: (Char -> Char -> Char) -> Text -> Text-scanl1 f t | null t    = empty-           | otherwise = scanl f (unsafeHead t) (unsafeTail t)-{-# INLINE scanl1 #-}---- | /O(n)/ 'scanr' is the right-to-left dual of 'scanl'.  Performs--- replacement on invalid scalar values.------ > scanr f v == reverse . scanl (flip f) v . reverse-scanr :: (Char -> Char -> Char) -> Char -> Text -> Text-scanr f z = S.reverse . S.reverseScanr g z . reverseStream-    where g a b = safe (f a b)-{-# INLINE scanr #-}---- | /O(n)/ 'scanr1' is a variant of 'scanr' that has no starting--- value argument. Performs replacement on invalid scalar values.-scanr1 :: (Char -> Char -> Char) -> Text -> Text-scanr1 f t | null t    = empty-           | otherwise = scanr f (last t) (init t)-{-# INLINE scanr1 #-}---- | /O(n)/ Like a combination of 'map' and 'foldl''. Applies a--- function to each element of a 'Text', passing an accumulating--- parameter from left to right, and returns a final 'Text'.  Performs--- replacement on invalid scalar values.-mapAccumL :: (a -> Char -> (a,Char)) -> a -> Text -> (a, Text)-mapAccumL f z0 = S.mapAccumL g z0 . stream-    where g a b = second safe (f a b)-{-# INLINE mapAccumL #-}---- | The 'mapAccumR' function behaves like a combination of 'map' and--- a strict 'foldr'; it applies a function to each element of a--- 'Text', passing an accumulating parameter from right to left, and--- returning a final value of this accumulator together with the new--- 'Text'.--- Performs replacement on invalid scalar values.-mapAccumR :: (a -> Char -> (a,Char)) -> a -> Text -> (a, Text)-mapAccumR f z0 = second reverse . S.mapAccumL g z0 . reverseStream-    where g a b = second safe (f a b)-{-# INLINE mapAccumR #-}---- -------------------------------------------------------------------------------- ** Generating and unfolding 'Text's---- | /O(n*m)/ 'replicate' @n@ @t@ is a 'Text' consisting of the input--- @t@ repeated @n@ times.-replicate :: Int -> Text -> Text-replicate n t@(Text a o l)-    | n <= 0 || l <= 0       = empty-    | n == 1                 = t-    | isSingleton t          = replicateChar n (unsafeHead t)-    | otherwise              = Text (A.run x) 0 len-  where-    len = l `mul` n -- TODO: detect overflows-    x :: ST s (A.MArray s)-    x = do-      arr <- A.new len-      A.copyI arr 0 a o l-      let loop !l1 =-            let rest = len - l1 in-            if rest <= l1 then A.copyM arr l1 arr 0 rest >> return arr-            else A.copyM arr l1 arr 0 l1 >> loop (l1 `shiftL` 1)-      loop l-{-# INLINE [1] replicate #-}---{-# RULES-"TEXT replicate/singleton -> replicateChar" [~1] forall n c.-    replicate n (singleton c) = replicateChar n c-  #-}---- | /O(n)/ 'replicateChar' @n@ @c@ is a 'Text' of length @n@ with @c@ the--- value of every element. Subject to fusion.-replicateChar :: Int -> Char -> Text-replicateChar n c = unstream (S.replicateCharI n (safe c))-{-# INLINE replicateChar #-}---- | /O(n)/, where @n@ is the length of the result. The 'unfoldr'--- function is analogous to the List 'L.unfoldr'. 'unfoldr' builds a--- 'Text' from a seed value. The function takes the element and--- returns 'Nothing' if it is done producing the 'Text', otherwise--- 'Just' @(a,b)@.  In this case, @a@ is the next 'Char' in the--- string, and @b@ is the seed value for further production. Subject--- to fusion.  Performs replacement on invalid scalar values.-unfoldr     :: (a -> Maybe (Char,a)) -> a -> Text-unfoldr f s = unstream (S.unfoldr (firstf safe . f) s)-{-# INLINE unfoldr #-}---- | /O(n)/ Like 'unfoldr', 'unfoldrN' builds a 'Text' from a seed--- value. However, the length of the result should be limited by the--- first argument to 'unfoldrN'. This function is more efficient than--- 'unfoldr' when the maximum length of the result is known and--- correct, otherwise its performance is similar to 'unfoldr'. Subject--- to fusion.  Performs replacement on invalid scalar values.-unfoldrN     :: Int -> (a -> Maybe (Char,a)) -> a -> Text-unfoldrN n f s = unstream (S.unfoldrN n (firstf safe . f) s)-{-# INLINE unfoldrN #-}---- -------------------------------------------------------------------------------- * Substrings---- | /O(n)/ 'take' @n@, applied to a 'Text', returns the prefix of the--- 'Text' of length @n@, or the 'Text' itself if @n@ is greater than--- the length of the Text. Subject to fusion.-take :: Int -> Text -> Text-take n t@(Text arr off len)-    | n <= 0    = empty-    | n >= len  = t-    | otherwise = text arr off (iterN n t)-{-# INLINE [1] take #-}--iterN :: Int -> Text -> Int-iterN n t@(Text _arr _off len) = loop 0 0-  where loop !i !cnt-            | i >= len || cnt >= n = i-            | otherwise            = loop (i+d) (cnt+1)-          where d = iter_ t i--{-# RULES-"TEXT take -> fused" [~1] forall n t.-    take n t = unstream (S.take n (stream t))-"TEXT take -> unfused" [1] forall n t.-    unstream (S.take n (stream t)) = take n t-  #-}---- | /O(n)/ 'takeEnd' @n@ @t@ returns the suffix remaining after--- taking @n@ characters from the end of @t@.------ Examples:------ >>> takeEnd 3 "foobar"--- "bar"------ @since 1.1.1.0-takeEnd :: Int -> Text -> Text-takeEnd n t@(Text arr off len)-    | n <= 0    = empty-    | n >= len  = t-    | otherwise = text arr (off+i) (len-i)-  where i = iterNEnd n t--iterNEnd :: Int -> Text -> Int-iterNEnd n t@(Text _arr _off len) = loop (len-1) n-  where loop i !m-          | m <= 0    = i+1-          | i <= 0    = 0-          | otherwise = loop (i+d) (m-1)-          where d = reverseIter_ t i---- | /O(n)/ 'drop' @n@, applied to a 'Text', returns the suffix of the--- 'Text' after the first @n@ characters, or the empty 'Text' if @n@--- is greater than the length of the 'Text'. Subject to fusion.-drop :: Int -> Text -> Text-drop n t@(Text arr off len)-    | n <= 0    = t-    | n >= len  = empty-    | otherwise = text arr (off+i) (len-i)-  where i = iterN n t-{-# INLINE [1] drop #-}--{-# RULES-"TEXT drop -> fused" [~1] forall n t.-    drop n t = unstream (S.drop n (stream t))-"TEXT drop -> unfused" [1] forall n t.-    unstream (S.drop n (stream t)) = drop n t-  #-}---- | /O(n)/ 'dropEnd' @n@ @t@ returns the prefix remaining after--- dropping @n@ characters from the end of @t@.------ Examples:------ >>> dropEnd 3 "foobar"--- "foo"------ @since 1.1.1.0-dropEnd :: Int -> Text -> Text-dropEnd n t@(Text arr off len)-    | n <= 0    = t-    | n >= len  = empty-    | otherwise = text arr off (iterNEnd n t)---- | /O(n)/ 'takeWhile', applied to a predicate @p@ and a 'Text',--- returns the longest prefix (possibly empty) of elements that--- satisfy @p@.  Subject to fusion.-takeWhile :: (Char -> Bool) -> Text -> Text-takeWhile p t@(Text arr off len) = loop 0-  where loop !i | i >= len    = t-                | p c         = loop (i+d)-                | otherwise   = text arr off i-            where Iter c d    = iter t i-{-# INLINE [1] takeWhile #-}--{-# RULES-"TEXT takeWhile -> fused" [~1] forall p t.-    takeWhile p t = unstream (S.takeWhile p (stream t))-"TEXT takeWhile -> unfused" [1] forall p t.-    unstream (S.takeWhile p (stream t)) = takeWhile p t-  #-}---- | /O(n)/ 'takeWhileEnd', applied to a predicate @p@ and a 'Text',--- returns the longest suffix (possibly empty) of elements that--- satisfy @p@.--- Examples:------ >>> takeWhileEnd (=='o') "foo"--- "oo"------ @since 1.2.2.0-takeWhileEnd :: (Char -> Bool) -> Text -> Text-takeWhileEnd p t@(Text arr off len) = loop (len-1) len-  where loop !i !l | l <= 0    = t-                   | p c       = loop (i+d) (l+d)-                   | otherwise = text arr (off+l) (len-l)-            where (c,d)        = reverseIter t i-{-# INLINE [1] takeWhileEnd #-}---- | /O(n)/ 'dropWhile' @p@ @t@ returns the suffix remaining after--- 'takeWhile' @p@ @t@. Subject to fusion.-dropWhile :: (Char -> Bool) -> Text -> Text-dropWhile p t@(Text arr off len) = loop 0 0-  where loop !i !l | l >= len  = empty-                   | p c       = loop (i+d) (l+d)-                   | otherwise = Text arr (off+i) (len-l)-            where Iter c d     = iter t i-{-# INLINE [1] dropWhile #-}--{-# RULES-"TEXT dropWhile -> fused" [~1] forall p t.-    dropWhile p t = unstream (S.dropWhile p (stream t))-"TEXT dropWhile -> unfused" [1] forall p t.-    unstream (S.dropWhile p (stream t)) = dropWhile p t-  #-}---- | /O(n)/ 'dropWhileEnd' @p@ @t@ returns the prefix remaining after--- dropping characters that satisfy the predicate @p@ from the end of--- @t@.------ Examples:------ >>> dropWhileEnd (=='.') "foo..."--- "foo"-dropWhileEnd :: (Char -> Bool) -> Text -> Text-dropWhileEnd p t@(Text arr off len) = loop (len-1) len-  where loop !i !l | l <= 0    = empty-                   | p c       = loop (i+d) (l+d)-                   | otherwise = Text arr off l-            where (c,d)        = reverseIter t i-{-# INLINE [1] dropWhileEnd #-}---- | /O(n)/ 'dropAround' @p@ @t@ returns the substring remaining after--- dropping characters that satisfy the predicate @p@ from both the--- beginning and end of @t@.  Subject to fusion.-dropAround :: (Char -> Bool) -> Text -> Text-dropAround p = dropWhile p . dropWhileEnd p-{-# INLINE [1] dropAround #-}---- | /O(n)/ Remove leading white space from a string.  Equivalent to:------ > dropWhile isSpace-stripStart :: Text -> Text-stripStart = dropWhile isSpace-{-# INLINE stripStart #-}---- | /O(n)/ Remove trailing white space from a string.  Equivalent to:------ > dropWhileEnd isSpace-stripEnd :: Text -> Text-stripEnd = dropWhileEnd isSpace-{-# INLINE [1] stripEnd #-}---- | /O(n)/ Remove leading and trailing white space from a string.--- Equivalent to:------ > dropAround isSpace-strip :: Text -> Text-strip = dropAround isSpace-{-# INLINE [1] strip #-}---- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a--- prefix of @t@ of length @n@, and whose second is the remainder of--- the string. It is equivalent to @('take' n t, 'drop' n t)@.-splitAt :: Int -> Text -> (Text, Text)-splitAt n t@(Text arr off len)-    | n <= 0    = (empty, t)-    | n >= len  = (t, empty)-    | otherwise = let k = iterN n t-                  in (text arr off k, text arr (off+k) (len-k))---- | /O(n)/ 'span', applied to a predicate @p@ and text @t@, returns--- a pair whose first element is the longest prefix (possibly empty)--- of @t@ of elements that satisfy @p@, and whose second is the--- remainder of the list.-span :: (Char -> Bool) -> Text -> (Text, Text)-span p t = case span_ p t of-             (# hd,tl #) -> (hd,tl)-{-# INLINE span #-}---- | /O(n)/ 'break' is like 'span', but the prefix returned is--- over elements that fail the predicate @p@.-break :: (Char -> Bool) -> Text -> (Text, Text)-break p = span (not . p)-{-# INLINE break #-}---- | /O(n)/ Group characters in a string according to a predicate.-groupBy :: (Char -> Char -> Bool) -> Text -> [Text]-groupBy p = loop-  where-    loop t@(Text arr off len)-        | null t    = []-        | otherwise = text arr off n : loop (text arr (off+n) (len-n))-        where Iter c d = iter t 0-              n     = d + findAIndexOrEnd (not . p c) (Text arr (off+d) (len-d))---- | Returns the /array/ index (in units of 'Word16') at which a--- character may be found.  This is /not/ the same as the logical--- index returned by e.g. 'findIndex'.-findAIndexOrEnd :: (Char -> Bool) -> Text -> Int-findAIndexOrEnd q t@(Text _arr _off len) = go 0-    where go !i | i >= len || q c       = i-                | otherwise             = go (i+d)-                where Iter c d          = iter t i---- | /O(n)/ Group characters in a string by equality.-group :: Text -> [Text]-group = groupBy (==)---- | /O(n)/ Return all initial segments of the given 'Text', shortest--- first.-inits :: Text -> [Text]-inits t@(Text arr off len) = loop 0-    where loop i | i >= len = [t]-                 | otherwise = Text arr off i : loop (i + iter_ t i)---- | /O(n)/ Return all final segments of the given 'Text', longest--- first.-tails :: Text -> [Text]-tails t | null t    = [empty]-        | otherwise = t : tails (unsafeTail t)---- $split------ Splitting functions in this library do not perform character-wise--- copies to create substrings; they just construct new 'Text's that--- are slices of the original.---- | /O(m+n)/ Break a 'Text' into pieces separated by the first 'Text'--- argument (which cannot be empty), consuming the delimiter. An empty--- delimiter is invalid, and will cause an error to be raised.------ Examples:------ >>> splitOn "\r\n" "a\r\nb\r\nd\r\ne"--- ["a","b","d","e"]------ >>> splitOn "aaa"  "aaaXaaaXaaaXaaa"--- ["","X","X","X",""]------ >>> splitOn "x"    "x"--- ["",""]------ and------ > intercalate s . splitOn s         == id--- > splitOn (singleton c)             == split (==c)------ (Note: the string @s@ to split on above cannot be empty.)------ In (unlikely) bad cases, this function's time complexity degrades--- towards /O(n*m)/.-splitOn :: Text-        -- ^ String to split on. If this string is empty, an error-        -- will occur.-        -> Text-        -- ^ Input text.-        -> [Text]-splitOn pat@(Text _ _ l) src@(Text arr off len)-    | l <= 0          = emptyError "splitOn"-    | isSingleton pat = split (== unsafeHead pat) src-    | otherwise       = go 0 (indices pat src)-  where-    go !s (x:xs) =  text arr (s+off) (x-s) : go (x+l) xs-    go  s _      = [text arr (s+off) (len-s)]-{-# INLINE [1] splitOn #-}--{-# RULES-"TEXT splitOn/singleton -> split/==" [~1] forall c t.-    splitOn (singleton c) t = split (==c) t-  #-}---- | /O(n)/ Splits a 'Text' into components delimited by separators,--- where the predicate returns True for a separator element.  The--- resulting components do not contain the separators.  Two adjacent--- separators result in an empty component in the output.  eg.------ >>> split (=='a') "aabbaca"--- ["","","bb","c",""]------ >>> split (=='a') ""--- [""]-split :: (Char -> Bool) -> Text -> [Text]-split _ t@(Text _off _arr 0) = [t]-split p t = loop t-    where loop s | null s'   = [l]-                 | otherwise = l : loop (unsafeTail s')-              where (# l, s' #) = span_ (not . p) s-{-# INLINE split #-}---- | /O(n)/ Splits a 'Text' into components of length @k@.  The last--- element may be shorter than the other chunks, depending on the--- length of the input. Examples:------ >>> chunksOf 3 "foobarbaz"--- ["foo","bar","baz"]------ >>> chunksOf 4 "haskell.org"--- ["hask","ell.","org"]-chunksOf :: Int -> Text -> [Text]-chunksOf k = go-  where-    go t = case splitAt k t of-             (a,b) | null a    -> []-                   | otherwise -> a : go b-{-# INLINE chunksOf #-}---- ------------------------------------------------------------------------------- * Searching------------------------------------------------------------------------------------ ** Searching with a predicate---- | /O(n)/ The 'find' function takes a predicate and a 'Text', and--- returns the first element matching the predicate, or 'Nothing' if--- there is no such element. Subject to fusion.-find :: (Char -> Bool) -> Text -> Maybe Char-find p t = S.findBy p (stream t)-{-# INLINE find #-}---- | /O(n)/ The 'partition' function takes a predicate and a 'Text',--- and returns the pair of 'Text's with elements which do and do not--- satisfy the predicate, respectively; i.e.------ > partition p t == (filter p t, filter (not . p) t)-partition :: (Char -> Bool) -> Text -> (Text, Text)-partition p t = (filter p t, filter (not . p) t)-{-# INLINE partition #-}---- | /O(n)/ 'filter', applied to a predicate and a 'Text',--- returns a 'Text' containing those characters that satisfy the--- predicate.-filter :: (Char -> Bool) -> Text -> Text-filter p t = unstream (S.filter p (stream t))-{-# INLINE filter #-}---- | /O(n+m)/ Find the first instance of @needle@ (which must be--- non-'null') in @haystack@.  The first element of the returned tuple--- is the prefix of @haystack@ before @needle@ is matched.  The second--- is the remainder of @haystack@, starting with the match.------ Examples:------ >>> breakOn "::" "a::b::c"--- ("a","::b::c")------ >>> breakOn "/" "foobar"--- ("foobar","")------ Laws:------ > append prefix match == haystack--- >   where (prefix, match) = breakOn needle haystack------ If you need to break a string by a substring repeatedly (e.g. you--- want to break on every instance of a substring), use 'breakOnAll'--- instead, as it has lower startup overhead.------ In (unlikely) bad cases, this function's time complexity degrades--- towards /O(n*m)/.-breakOn :: Text -> Text -> (Text, Text)-breakOn pat src@(Text arr off len)-    | null pat  = emptyError "breakOn"-    | otherwise = case indices pat src of-                    []    -> (src, empty)-                    (x:_) -> (text arr off x, text arr (off+x) (len-x))-{-# INLINE breakOn #-}---- | /O(n+m)/ Similar to 'breakOn', but searches from the end of the--- string.------ The first element of the returned tuple is the prefix of @haystack@--- up to and including the last match of @needle@.  The second is the--- remainder of @haystack@, following the match.------ >>> breakOnEnd "::" "a::b::c"--- ("a::b::","c")-breakOnEnd :: Text -> Text -> (Text, Text)-breakOnEnd pat src = (reverse b, reverse a)-    where (a,b) = breakOn (reverse pat) (reverse src)-{-# INLINE breakOnEnd #-}---- | /O(n+m)/ Find all non-overlapping instances of @needle@ in--- @haystack@.  Each element of the returned list consists of a pair:------ * The entire string prior to the /k/th match (i.e. the prefix)------ * The /k/th match, followed by the remainder of the string------ Examples:------ >>> breakOnAll "::" ""--- []------ >>> breakOnAll "/" "a/b/c/"--- [("a","/b/c/"),("a/b","/c/"),("a/b/c","/")]------ In (unlikely) bad cases, this function's time complexity degrades--- towards /O(n*m)/.------ The @needle@ parameter may not be empty.-breakOnAll :: Text              -- ^ @needle@ to search for-           -> Text              -- ^ @haystack@ in which to search-           -> [(Text, Text)]-breakOnAll pat src@(Text arr off slen)-    | null pat  = emptyError "breakOnAll"-    | otherwise = L.map step (indices pat src)-  where-    step       x = (chunk 0 x, chunk x (slen-x))-    chunk !n !l  = text arr (n+off) l-{-# INLINE breakOnAll #-}------------------------------------------------------------------------------------ ** Indexing 'Text's---- $index------ If you think of a 'Text' value as an array of 'Char' values (which--- it is not), you run the risk of writing inefficient code.------ An idiom that is common in some languages is to find the numeric--- offset of a character or substring, then use that number to split--- or trim the searched string.  With a 'Text' value, this approach--- would require two /O(n)/ operations: one to perform the search, and--- one to operate from wherever the search ended.------ For example, suppose you have a string that you want to split on--- the substring @\"::\"@, such as @\"foo::bar::quux\"@. Instead of--- searching for the index of @\"::\"@ and taking the substrings--- before and after that index, you would instead use @breakOnAll \"::\"@.---- | /O(n)/ 'Text' index (subscript) operator, starting from 0. Subject to fusion.-index :: Text -> Int -> Char-index t n = S.index (stream t) n-{-# INLINE index #-}---- | /O(n)/ The 'findIndex' function takes a predicate and a 'Text'--- and returns the index of the first element in the 'Text' satisfying--- the predicate. Subject to fusion.-findIndex :: (Char -> Bool) -> Text -> Maybe Int-findIndex p t = S.findIndex p (stream t)-{-# INLINE findIndex #-}---- | /O(n+m)/ The 'count' function returns the number of times the--- query string appears in the given 'Text'. An empty query string is--- invalid, and will cause an error to be raised.------ In (unlikely) bad cases, this function's time complexity degrades--- towards /O(n*m)/.-count :: Text -> Text -> Int-count pat src-    | null pat        = emptyError "count"-    | isSingleton pat = countChar (unsafeHead pat) src-    | otherwise       = L.length (indices pat src)-{-# INLINE [1] count #-}--{-# RULES-"TEXT count/singleton -> countChar" [~1] forall c t.-    count (singleton c) t = countChar c t-  #-}---- | /O(n)/ The 'countChar' function returns the number of times the--- query element appears in the given 'Text'. Subject to fusion.-countChar :: Char -> Text -> Int-countChar c t = S.countChar c (stream t)-{-# INLINE countChar #-}------------------------------------------------------------------------------------ * Zipping---- | /O(n)/ 'zip' takes two 'Text's and returns a list of--- corresponding pairs of bytes. If one input 'Text' is short,--- excess elements of the longer 'Text' are discarded. This is--- equivalent to a pair of 'unpack' operations.-zip :: Text -> Text -> [(Char,Char)]-zip a b = S.unstreamList $ S.zipWith (,) (stream a) (stream b)-{-# INLINE zip #-}---- | /O(n)/ 'zipWith' generalises 'zip' by zipping with the function--- given as the first argument, instead of a tupling function.--- Performs replacement on invalid scalar values.-zipWith :: (Char -> Char -> Char) -> Text -> Text -> Text-zipWith f t1 t2 = unstream (S.zipWith g (stream t1) (stream t2))-    where g a b = safe (f a b)-{-# INLINE zipWith #-}---- | /O(n)/ Breaks a 'Text' up into a list of words, delimited by 'Char's--- representing white space.-words :: Text -> [Text]-words t@(Text arr off len) = loop 0 0-  where-    loop !start !n-        | n >= len = if start == n-                     then []-                     else [Text arr (start+off) (n-start)]-        | isSpace c =-            if start == n-            then loop (start+1) (start+1)-            else Text arr (start+off) (n-start) : loop (n+d) (n+d)-        | otherwise = loop start (n+d)-        where Iter c d = iter t n-{-# INLINE words #-}---- | /O(n)/ Breaks a 'Text' up into a list of 'Text's at--- newline 'Char's. The resulting strings do not contain newlines.-lines :: Text -> [Text]-lines ps | null ps   = []-         | otherwise = h : if null t-                           then []-                           else lines (unsafeTail t)-    where (# h,t #) = span_ (/= '\n') ps-{-# INLINE lines #-}--{---- | /O(n)/ Portably breaks a 'Text' up into a list of 'Text's at line--- boundaries.------ A line boundary is considered to be either a line feed, a carriage--- return immediately followed by a line feed, or a carriage return.--- This accounts for both Unix and Windows line ending conventions,--- and for the old convention used on Mac OS 9 and earlier.-lines' :: Text -> [Text]-lines' ps | null ps   = []-          | otherwise = h : case uncons t of-                              Nothing -> []-                              Just (c,t')-                                  | c == '\n' -> lines t'-                                  | c == '\r' -> case uncons t' of-                                                   Just ('\n',t'') -> lines t''-                                                   _               -> lines t'-    where (h,t)    = span notEOL ps-          notEOL c = c /= '\n' && c /= '\r'-{-# INLINE lines' #-}--}---- | /O(n)/ Joins lines, after appending a terminating newline to--- each.-unlines :: [Text] -> Text-unlines = concat . L.map (`snoc` '\n')-{-# INLINE unlines #-}---- | /O(n)/ Joins words using single space characters.-unwords :: [Text] -> Text-unwords = intercalate (singleton ' ')-{-# INLINE unwords #-}---- | /O(n)/ The 'isPrefixOf' function takes two 'Text's and returns--- 'True' iff the first is a prefix of the second.  Subject to fusion.-isPrefixOf :: Text -> Text -> Bool-isPrefixOf a@(Text _ _ alen) b@(Text _ _ blen) =-    alen <= blen && S.isPrefixOf (stream a) (stream b)-{-# INLINE [1] isPrefixOf #-}--{-# RULES-"TEXT isPrefixOf -> fused" [~1] forall s t.-    isPrefixOf s t = S.isPrefixOf (stream s) (stream t)-  #-}---- | /O(n)/ The 'isSuffixOf' function takes two 'Text's and returns--- 'True' iff the first is a suffix of the second.-isSuffixOf :: Text -> Text -> Bool-isSuffixOf a@(Text _aarr _aoff alen) b@(Text barr boff blen) =-    d >= 0 && a == b'-  where d              = blen - alen-        b' | d == 0    = b-           | otherwise = Text barr (boff+d) alen-{-# INLINE isSuffixOf #-}---- | /O(n+m)/ The 'isInfixOf' function takes two 'Text's and returns--- 'True' iff the first is contained, wholly and intact, anywhere--- within the second.------ In (unlikely) bad cases, this function's time complexity degrades--- towards /O(n*m)/.-isInfixOf :: Text -> Text -> Bool-isInfixOf needle haystack-    | null needle        = True-    | isSingleton needle = S.elem (unsafeHead needle) . S.stream $ haystack-    | otherwise          = not . L.null . indices needle $ haystack-{-# INLINE [1] isInfixOf #-}--{-# RULES-"TEXT isInfixOf/singleton -> S.elem/S.stream" [~1] forall n h.-    isInfixOf (singleton n) h = S.elem n (S.stream h)-  #-}------------------------------------------------------------------------------------ * View patterns---- | /O(n)/ Return the suffix of the second string if its prefix--- matches the entire first string.------ Examples:------ >>> stripPrefix "foo" "foobar"--- Just "bar"------ >>> stripPrefix ""    "baz"--- Just "baz"------ >>> stripPrefix "foo" "quux"--- Nothing------ This is particularly useful with the @ViewPatterns@ extension to--- GHC, as follows:------ > {-# LANGUAGE ViewPatterns #-}--- > import Data.Text as T--- >--- > fnordLength :: Text -> Int--- > fnordLength (stripPrefix "fnord" -> Just suf) = T.length suf--- > fnordLength _                                 = -1-stripPrefix :: Text -> Text -> Maybe Text-stripPrefix p@(Text _arr _off plen) t@(Text arr off len)-    | p `isPrefixOf` t = Just $! text arr (off+plen) (len-plen)-    | otherwise        = Nothing---- | /O(n)/ Find the longest non-empty common prefix of two strings--- and return it, along with the suffixes of each string at which they--- no longer match.------ If the strings do not have a common prefix or either one is empty,--- this function returns 'Nothing'.------ Examples:------ >>> commonPrefixes "foobar" "fooquux"--- Just ("foo","bar","quux")------ >>> commonPrefixes "veeble" "fetzer"--- Nothing------ >>> commonPrefixes "" "baz"--- Nothing-commonPrefixes :: Text -> Text -> Maybe (Text,Text,Text)-commonPrefixes t0@(Text arr0 off0 len0) t1@(Text arr1 off1 len1) = go 0 0-  where-    go !i !j | i < len0 && j < len1 && a == b = go (i+d0) (j+d1)-             | i > 0     = Just (Text arr0 off0 i,-                                 text arr0 (off0+i) (len0-i),-                                 text arr1 (off1+j) (len1-j))-             | otherwise = Nothing-      where Iter a d0 = iter t0 i-            Iter b d1 = iter t1 j---- | /O(n)/ Return the prefix of the second string if its suffix--- matches the entire first string.------ Examples:------ >>> stripSuffix "bar" "foobar"--- Just "foo"------ >>> stripSuffix ""    "baz"--- Just "baz"------ >>> stripSuffix "foo" "quux"--- Nothing------ This is particularly useful with the @ViewPatterns@ extension to--- GHC, as follows:------ > {-# LANGUAGE ViewPatterns #-}--- > import Data.Text as T--- >--- > quuxLength :: Text -> Int--- > quuxLength (stripSuffix "quux" -> Just pre) = T.length pre--- > quuxLength _                                = -1-stripSuffix :: Text -> Text -> Maybe Text-stripSuffix p@(Text _arr _off plen) t@(Text arr off len)-    | p `isSuffixOf` t = Just $! text arr off (len-plen)-    | otherwise        = Nothing---- | Add a list of non-negative numbers.  Errors out on overflow.-sumP :: String -> [Int] -> Int-sumP fun = go 0-  where go !a (x:xs)-            | ax >= 0   = go ax xs-            | otherwise = overflowError fun-          where ax = a + x-        go a  _         = a--emptyError :: String -> a-emptyError fun = P.error $ "Data.Text." ++ fun ++ ": empty input"--overflowError :: String -> a-overflowError fun = P.error $ "Data.Text." ++ fun ++ ": size overflow"---- | /O(n)/ Make a distinct copy of the given string, sharing no--- storage with the original string.------ As an example, suppose you read a large string, of which you need--- only a small portion.  If you do not use 'copy', the entire original--- array will be kept alive in memory by the smaller string. Making a--- copy \"breaks the link\" to the original array, allowing it to be--- garbage collected if there are no other live references to it.-copy :: Text -> Text-copy (Text arr off len) = Text (A.run go) 0 len-  where-    go :: ST s (A.MArray s)-    go = do-      marr <- A.new len-      A.copyI marr 0 arr off len-      return marr------------------------------------------------------- NOTE: the named chunk below used by doctest;---       verify the doctests via `doctest -fobject-code Data/Text.hs`---- $setup--- >>> :set -XOverloadedStrings--- >>> import qualified Data.Text as T
− Data/Text/Array.hs
@@ -1,249 +0,0 @@-{-# LANGUAGE BangPatterns, CPP, MagicHash, Rank2Types,-    RecordWildCards, UnboxedTuples, UnliftedFFITypes #-}-{-# OPTIONS_GHC -fno-warn-unused-matches #-}--- |--- Module      : Data.Text.Array--- Copyright   : (c) 2009, 2010, 2011 Bryan O'Sullivan------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Portability : portable------ Packed, unboxed, heap-resident arrays.  Suitable for performance--- critical use, both in terms of large data quantities and high--- speed.------ This module is intended to be imported @qualified@, to avoid name--- clashes with "Prelude" functions, e.g.------ > import qualified Data.Text.Array as A------ The names in this module resemble those in the 'Data.Array' family--- of modules, but are shorter due to the assumption of qualified--- naming.-module Data.Text.Array-    (-    -- * Types-      Array(Array, aBA)-    , MArray(MArray, maBA)--    -- * Functions-    , copyM-    , copyI-    , empty-    , equal-#if defined(ASSERTS)-    , length-#endif-    , run-    , run2-    , toList-    , unsafeFreeze-    , unsafeIndex-    , new-    , unsafeWrite-    ) where--#if defined(ASSERTS)--- This fugly hack is brought by GHC's apparent reluctance to deal--- with MagicHash and UnboxedTuples when inferring types. Eek!-# define CHECK_BOUNDS(_func_,_len_,_k_) \-if (_k_) < 0 || (_k_) >= (_len_) then error ("Data.Text.Array." ++ (_func_) ++ ": bounds error, offset " ++ show (_k_) ++ ", length " ++ show (_len_)) else-#else-# define CHECK_BOUNDS(_func_,_len_,_k_)-#endif--#include "MachDeps.h"--#if defined(ASSERTS)-import Control.Exception (assert)-#endif-#if MIN_VERSION_base(4,4,0)-import Control.Monad.ST.Unsafe (unsafeIOToST)-#else-import Control.Monad.ST (unsafeIOToST)-#endif-import Data.Bits ((.&.), xor)-import Data.Text.Internal.Unsafe (inlinePerformIO)-import Data.Text.Internal.Unsafe.Shift (shiftL, shiftR)-#if MIN_VERSION_base(4,5,0)-import Foreign.C.Types (CInt(CInt), CSize(CSize))-#else-import Foreign.C.Types (CInt, CSize)-#endif-import GHC.Base (ByteArray#, MutableByteArray#, Int(..),-                 indexWord16Array#, newByteArray#,-                 unsafeFreezeByteArray#, writeWord16Array#)-import GHC.ST (ST(..), runST)-import GHC.Word (Word16(..))-import Prelude hiding (length, read)---- | Immutable array type.------ The 'Array' constructor is exposed since @text-1.1.1.3@-data Array = Array {-      aBA :: ByteArray#-#if defined(ASSERTS)-    , aLen :: {-# UNPACK #-} !Int -- length (in units of Word16, not bytes)-#endif-    }---- | Mutable array type, for use in the ST monad.------ The 'MArray' constructor is exposed since @text-1.1.1.3@-data MArray s = MArray {-      maBA :: MutableByteArray# s-#if defined(ASSERTS)-    , maLen :: {-# UNPACK #-} !Int -- length (in units of Word16, not bytes)-#endif-    }--#if defined(ASSERTS)--- | Operations supported by all arrays.-class IArray a where-    -- | Return the length of an array.-    length :: a -> Int--instance IArray Array where-    length = aLen-    {-# INLINE length #-}--instance IArray (MArray s) where-    length = maLen-    {-# INLINE length #-}-#endif---- | Create an uninitialized mutable array.-new :: forall s. Int -> ST s (MArray s)-new n-  | n < 0 || n .&. highBit /= 0 = array_size_error-  | otherwise = ST $ \s1# ->-       case newByteArray# len# s1# of-         (# s2#, marr# #) -> (# s2#, MArray marr#-#if defined(ASSERTS)-                                n-#endif-                                #)-  where !(I# len#) = bytesInArray n-        highBit    = maxBound `xor` (maxBound `shiftR` 1)-{-# INLINE new #-}--array_size_error :: a-array_size_error = error "Data.Text.Array.new: size overflow"---- | Freeze a mutable array. Do not mutate the 'MArray' afterwards!-unsafeFreeze :: MArray s -> ST s Array-unsafeFreeze MArray{..} = ST $ \s1# ->-    case unsafeFreezeByteArray# maBA s1# of-        (# s2#, ba# #) -> (# s2#, Array ba#-#if defined(ASSERTS)-                             maLen-#endif-                             #)-{-# INLINE unsafeFreeze #-}---- | Indicate how many bytes would be used for an array of the given--- size.-bytesInArray :: Int -> Int-bytesInArray n = n `shiftL` 1-{-# INLINE bytesInArray #-}---- | Unchecked read of an immutable array.  May return garbage or--- crash on an out-of-bounds access.-unsafeIndex :: Array -> Int -> Word16-unsafeIndex Array{..} i@(I# i#) =-  CHECK_BOUNDS("unsafeIndex",aLen,i)-    case indexWord16Array# aBA i# of r# -> (W16# r#)-{-# INLINE unsafeIndex #-}---- | Unchecked write of a mutable array.  May return garbage or crash--- on an out-of-bounds access.-unsafeWrite :: MArray s -> Int -> Word16 -> ST s ()-unsafeWrite MArray{..} i@(I# i#) (W16# e#) = ST $ \s1# ->-  CHECK_BOUNDS("unsafeWrite",maLen,i)-  case writeWord16Array# maBA i# e# s1# of-    s2# -> (# s2#, () #)-{-# INLINE unsafeWrite #-}---- | Convert an immutable array to a list.-toList :: Array -> Int -> Int -> [Word16]-toList ary off len = loop 0-    where loop i | i < len   = unsafeIndex ary (off+i) : loop (i+1)-                 | otherwise = []---- | An empty immutable array.-empty :: Array-empty = runST (new 0 >>= unsafeFreeze)---- | Run an action in the ST monad and return an immutable array of--- its result.-run :: (forall s. ST s (MArray s)) -> Array-run k = runST (k >>= unsafeFreeze)---- | Run an action in the ST monad and return an immutable array of--- its result paired with whatever else the action returns.-run2 :: (forall s. ST s (MArray s, a)) -> (Array, a)-run2 k = runST (do-                 (marr,b) <- k-                 arr <- unsafeFreeze marr-                 return (arr,b))-{-# INLINE run2 #-}---- | Copy some elements of a mutable array.-copyM :: MArray s               -- ^ Destination-      -> Int                    -- ^ Destination offset-      -> MArray s               -- ^ Source-      -> Int                    -- ^ Source offset-      -> Int                    -- ^ Count-      -> ST s ()-copyM dest didx src sidx count-    | count <= 0 = return ()-    | otherwise =-#if defined(ASSERTS)-    assert (sidx + count <= length src) .-    assert (didx + count <= length dest) .-#endif-    unsafeIOToST $ memcpyM (maBA dest) (fromIntegral didx)-                           (maBA src) (fromIntegral sidx)-                           (fromIntegral count)-{-# INLINE copyM #-}---- | Copy some elements of an immutable array.-copyI :: MArray s               -- ^ Destination-      -> Int                    -- ^ Destination offset-      -> Array                  -- ^ Source-      -> Int                    -- ^ Source offset-      -> Int                    -- ^ First offset in destination /not/ to-                                -- copy (i.e. /not/ length)-      -> ST s ()-copyI dest i0 src j0 top-    | i0 >= top = return ()-    | otherwise = unsafeIOToST $-                  memcpyI (maBA dest) (fromIntegral i0)-                          (aBA src) (fromIntegral j0)-                          (fromIntegral (top-i0))-{-# INLINE copyI #-}---- | Compare portions of two arrays for equality.  No bounds checking--- is performed.-equal :: Array                  -- ^ First-      -> Int                    -- ^ Offset into first-      -> Array                  -- ^ Second-      -> Int                    -- ^ Offset into second-      -> Int                    -- ^ Count-      -> Bool-equal arrA offA arrB offB count = inlinePerformIO $ do-  i <- memcmp (aBA arrA) (fromIntegral offA)-                     (aBA arrB) (fromIntegral offB) (fromIntegral count)-  return $! i == 0-{-# INLINE equal #-}--foreign import ccall unsafe "_hs_text_memcpy" memcpyI-    :: MutableByteArray# s -> CSize -> ByteArray# -> CSize -> CSize -> IO ()--foreign import ccall unsafe "_hs_text_memcmp" memcmp-    :: ByteArray# -> CSize -> ByteArray# -> CSize -> CSize -> IO CInt--foreign import ccall unsafe "_hs_text_memcpy" memcpyM-    :: MutableByteArray# s -> CSize -> MutableByteArray# s -> CSize -> CSize-    -> IO ()
− Data/Text/Encoding.hs
@@ -1,535 +0,0 @@-{-# LANGUAGE BangPatterns, CPP, GeneralizedNewtypeDeriving, MagicHash,-    UnliftedFFITypes #-}-#if __GLASGOW_HASKELL__ >= 702-{-# LANGUAGE Trustworthy #-}-#endif--- |--- Module      : Data.Text.Encoding--- Copyright   : (c) 2009, 2010, 2011 Bryan O'Sullivan,---               (c) 2009 Duncan Coutts,---               (c) 2008, 2009 Tom Harper------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Portability : portable------ Functions for converting 'Text' values to and from 'ByteString',--- using several standard encodings.------ To gain access to a much larger family of encodings, use the--- <http://hackage.haskell.org/package/text-icu text-icu package>.--module Data.Text.Encoding-    (-    -- * Decoding ByteStrings to Text-    -- $strict-      decodeASCII-    , decodeLatin1-    , decodeUtf8-    , decodeUtf16LE-    , decodeUtf16BE-    , decodeUtf32LE-    , decodeUtf32BE--    -- ** Catchable failure-    , decodeUtf8'--    -- ** Controllable error handling-    , decodeUtf8With-    , decodeUtf16LEWith-    , decodeUtf16BEWith-    , decodeUtf32LEWith-    , decodeUtf32BEWith--    -- ** Stream oriented decoding-    -- $stream-    , streamDecodeUtf8-    , streamDecodeUtf8With-    , Decoding(..)--    -- * Encoding Text to ByteStrings-    , encodeUtf8-    , encodeUtf16LE-    , encodeUtf16BE-    , encodeUtf32LE-    , encodeUtf32BE--    -- * Encoding Text using ByteString Builders-    , encodeUtf8Builder-    , encodeUtf8BuilderEscaped-    ) where--#if MIN_VERSION_base(4,4,0)-import Control.Monad.ST.Unsafe (unsafeIOToST, unsafeSTToIO)-#else-import Control.Monad.ST (unsafeIOToST, unsafeSTToIO)-#endif--import Control.Exception (evaluate, try, throwIO, ErrorCall(ErrorCall))-import Control.Monad.ST (runST)-import Data.Bits ((.&.))-import Data.ByteString as B-import Data.ByteString.Internal as B hiding (c2w)-import Data.Text.Encoding.Error (OnDecodeError, UnicodeException, strictDecode)-import Data.Text.Internal (Text(..), safe, text)-import Data.Text.Internal.Private (runText)-import Data.Text.Internal.Unsafe.Char (ord, unsafeWrite)-import Data.Text.Internal.Unsafe.Shift (shiftR)-import Data.Text.Show ()-import Data.Text.Unsafe (unsafeDupablePerformIO)-import Data.Word (Word8, Word32)-#if MIN_VERSION_base(4,5,0)-import Foreign.C.Types (CSize(CSize))-#else-import Foreign.C.Types (CSize)-#endif-import Foreign.ForeignPtr (withForeignPtr)-import Foreign.Marshal.Utils (with)-import Foreign.Ptr (Ptr, minusPtr, nullPtr, plusPtr)-import Foreign.Storable (Storable, peek, poke)-import GHC.Base (ByteArray#, MutableByteArray#)-import qualified Data.ByteString.Builder as B-import qualified Data.ByteString.Builder.Internal as B hiding (empty, append)-import qualified Data.ByteString.Builder.Prim as BP-import qualified Data.ByteString.Builder.Prim.Internal as BP-import qualified Data.Text.Array as A-import qualified Data.Text.Internal.Encoding.Fusion as E-import qualified Data.Text.Internal.Encoding.Utf16 as U16-import qualified Data.Text.Internal.Fusion as F--#include "text_cbits.h"---- $strict------ All of the single-parameter functions for decoding bytestrings--- encoded in one of the Unicode Transformation Formats (UTF) operate--- in a /strict/ mode: each will throw an exception if given invalid--- input.------ Each function has a variant, whose name is suffixed with -'With',--- that gives greater control over the handling of decoding errors.--- For instance, 'decodeUtf8' will throw an exception, but--- 'decodeUtf8With' allows the programmer to determine what to do on a--- decoding error.---- | /Deprecated/.  Decode a 'ByteString' containing 7-bit ASCII--- encoded text.-decodeASCII :: ByteString -> Text-decodeASCII = decodeUtf8-{-# DEPRECATED decodeASCII "Use decodeUtf8 instead" #-}---- | Decode a 'ByteString' containing Latin-1 (aka ISO-8859-1) encoded text.------ 'decodeLatin1' is semantically equivalent to---  @Data.Text.pack . Data.ByteString.Char8.unpack@-decodeLatin1 :: ByteString -> Text-decodeLatin1 (PS fp off len) = text a 0 len- where-  a = A.run (A.new len >>= unsafeIOToST . go)-  go dest = withForeignPtr fp $ \ptr -> do-    c_decode_latin1 (A.maBA dest) (ptr `plusPtr` off) (ptr `plusPtr` (off+len))-    return dest---- | Decode a 'ByteString' containing UTF-8 encoded text.------ __NOTE__: The replacement character returned by 'OnDecodeError'--- MUST be within the BMP plane; surrogate code points will--- automatically be remapped to the replacement char @U+FFFD@--- (/since 0.11.3.0/), whereas code points beyond the BMP will throw an--- 'error' (/since 1.2.3.1/); For earlier versions of @text@ using--- those unsupported code points would result in undefined behavior.-decodeUtf8With :: OnDecodeError -> ByteString -> Text-decodeUtf8With onErr (PS fp off len) = runText $ \done -> do-  let go dest = withForeignPtr fp $ \ptr ->-        with (0::CSize) $ \destOffPtr -> do-          let end = ptr `plusPtr` (off + len)-              loop curPtr = do-                curPtr' <- c_decode_utf8 (A.maBA dest) destOffPtr curPtr end-                if curPtr' == end-                  then do-                    n <- peek destOffPtr-                    unsafeSTToIO (done dest (fromIntegral n))-                  else do-                    x <- peek curPtr'-                    case onErr desc (Just x) of-                      Nothing -> loop $ curPtr' `plusPtr` 1-                      Just c-                        | c > '\xFFFF' -> throwUnsupportedReplChar-                        | otherwise -> do-                            destOff <- peek destOffPtr-                            w <- unsafeSTToIO $-                                 unsafeWrite dest (fromIntegral destOff)-                                             (safe c)-                            poke destOffPtr (destOff + fromIntegral w)-                            loop $ curPtr' `plusPtr` 1-          loop (ptr `plusPtr` off)-  (unsafeIOToST . go) =<< A.new len- where-  desc = "Data.Text.Internal.Encoding.decodeUtf8: Invalid UTF-8 stream"--  throwUnsupportedReplChar = throwIO $-    ErrorCall "decodeUtf8With: non-BMP replacement characters not supported"-  -- TODO: The code currently assumes that the transcoded UTF-16-  -- stream is at most twice as long (in bytes) as the input UTF-8-  -- stream. To justify this assumption one has to assume that the-  -- error handler replacement character also satisfies this-  -- invariant, by emitting at most one UTF16 code unit.-  ---  -- One easy way to support the full range of code-points for-  -- replacement characters in the error handler is to simply change-  -- the (over-)allocation to `A.new (2*len)` and then shrink back the-  -- `ByteArray#` to the real size (recent GHCs have a cheap-  -- `ByteArray#` resize-primop for that which allow the GC to reclaim-  -- the overallocation). However, this would require 4 times as much-  -- (temporary) storage as the original UTF-8 required.-  ---  -- Another strategy would be to optimistically assume that-  -- replacement characters are within the BMP, and if the case of a-  -- non-BMP replacement occurs reallocate the target buffer (or throw-  -- an exception, and fallback to a pessimistic codepath, like e.g.-  -- `decodeUtf8With onErr bs = F.unstream (E.streamUtf8 onErr bs)`)-  ---  -- Alternatively, `OnDecodeError` could become a datastructure which-  -- statically encodes the replacement-character range,-  -- e.g. something isomorphic to-  ---  --   Either (... -> Maybe Word16) (... -> Maybe Char)-  ---  -- And allow to statically switch between the BMP/non-BMP-  -- replacement-character codepaths. There's multiple ways to address-  -- this with different tradeoffs; but ideally we should optimise for-  -- the optimistic/error-free case.-{- INLINE[0] decodeUtf8With #-}---- $stream------ The 'streamDecodeUtf8' and 'streamDecodeUtf8With' functions accept--- a 'ByteString' that represents a possibly incomplete input (e.g. a--- packet from a network stream) that may not end on a UTF-8 boundary.------ 1. The maximal prefix of 'Text' that could be decoded from the---    given input.------ 2. The suffix of the 'ByteString' that could not be decoded due to---    insufficient input.------ 3. A function that accepts another 'ByteString'.  That string will---    be assumed to directly follow the string that was passed as---    input to the original function, and it will in turn be decoded.------ To help understand the use of these functions, consider the Unicode--- string @\"hi &#9731;\"@. If encoded as UTF-8, this becomes @\"hi--- \\xe2\\x98\\x83\"@; the final @\'&#9731;\'@ is encoded as 3 bytes.------ Now suppose that we receive this encoded string as 3 packets that--- are split up on untidy boundaries: @[\"hi \\xe2\", \"\\x98\",--- \"\\x83\"]@. We cannot decode the entire Unicode string until we--- have received all three packets, but we would like to make progress--- as we receive each one.------ @--- ghci> let s0\@('Some' _ _ f0) = 'streamDecodeUtf8' \"hi \\xe2\"--- ghci> s0--- 'Some' \"hi \" \"\\xe2\" _--- @------ We use the continuation @f0@ to decode our second packet.------ @--- ghci> let s1\@('Some' _ _ f1) = f0 \"\\x98\"--- ghci> s1--- 'Some' \"\" \"\\xe2\\x98\"--- @------ We could not give @f0@ enough input to decode anything, so it--- returned an empty string. Once we feed our second continuation @f1@--- the last byte of input, it will make progress.------ @--- ghci> let s2\@('Some' _ _ f2) = f1 \"\\x83\"--- ghci> s2--- 'Some' \"\\x2603\" \"\" _--- @------ If given invalid input, an exception will be thrown by the function--- or continuation where it is encountered.---- | A stream oriented decoding result.------ @since 1.0.0.0-data Decoding = Some Text ByteString (ByteString -> Decoding)--instance Show Decoding where-    showsPrec d (Some t bs _) = showParen (d > prec) $-                                showString "Some " . showsPrec prec' t .-                                showChar ' ' . showsPrec prec' bs .-                                showString " _"-      where prec = 10; prec' = prec + 1--newtype CodePoint = CodePoint Word32 deriving (Eq, Show, Num, Storable)-newtype DecoderState = DecoderState Word32 deriving (Eq, Show, Num, Storable)---- | Decode, in a stream oriented way, a 'ByteString' containing UTF-8--- encoded text that is known to be valid.------ If the input contains any invalid UTF-8 data, an exception will be--- thrown (either by this function or a continuation) that cannot be--- caught in pure code.  For more control over the handling of invalid--- data, use 'streamDecodeUtf8With'.------ @since 1.0.0.0-streamDecodeUtf8 :: ByteString -> Decoding-streamDecodeUtf8 = streamDecodeUtf8With strictDecode---- | Decode, in a stream oriented way, a 'ByteString' containing UTF-8--- encoded text.------ @since 1.0.0.0-streamDecodeUtf8With :: OnDecodeError -> ByteString -> Decoding-streamDecodeUtf8With onErr = decodeChunk B.empty 0 0- where-  -- We create a slightly larger than necessary buffer to accommodate a-  -- potential surrogate pair started in the last buffer-  decodeChunk :: ByteString -> CodePoint -> DecoderState -> ByteString-              -> Decoding-  decodeChunk undecoded0 codepoint0 state0 bs@(PS fp off len) =-    runST $ (unsafeIOToST . decodeChunkToBuffer) =<< A.new (len+1)-   where-    decodeChunkToBuffer :: A.MArray s -> IO Decoding-    decodeChunkToBuffer dest = withForeignPtr fp $ \ptr ->-      with (0::CSize) $ \destOffPtr ->-      with codepoint0 $ \codepointPtr ->-      with state0 $ \statePtr ->-      with nullPtr $ \curPtrPtr ->-        let end = ptr `plusPtr` (off + len)-            loop curPtr = do-              poke curPtrPtr curPtr-              curPtr' <- c_decode_utf8_with_state (A.maBA dest) destOffPtr-                         curPtrPtr end codepointPtr statePtr-              state <- peek statePtr-              case state of-                UTF8_REJECT -> do-                  -- We encountered an encoding error-                  x <- peek curPtr'-                  poke statePtr 0-                  case onErr desc (Just x) of-                    Nothing -> loop $ curPtr' `plusPtr` 1-                    Just c -> do-                      destOff <- peek destOffPtr-                      w <- unsafeSTToIO $-                           unsafeWrite dest (fromIntegral destOff) (safe c)-                      poke destOffPtr (destOff + fromIntegral w)-                      loop $ curPtr' `plusPtr` 1--                _ -> do-                  -- We encountered the end of the buffer while decoding-                  n <- peek destOffPtr-                  codepoint <- peek codepointPtr-                  chunkText <- unsafeSTToIO $ do-                      arr <- A.unsafeFreeze dest-                      return $! text arr 0 (fromIntegral n)-                  lastPtr <- peek curPtrPtr-                  let left = lastPtr `minusPtr` curPtr-                      !undecoded = case state of-                        UTF8_ACCEPT -> B.empty-                        _           -> B.append undecoded0 (B.drop left bs)-                  return $ Some chunkText undecoded-                           (decodeChunk undecoded codepoint state)-        in loop (ptr `plusPtr` off)-  desc = "Data.Text.Internal.Encoding.streamDecodeUtf8With: Invalid UTF-8 stream"---- | Decode a 'ByteString' containing UTF-8 encoded text that is known--- to be valid.------ If the input contains any invalid UTF-8 data, an exception will be--- thrown that cannot be caught in pure code.  For more control over--- the handling of invalid data, use 'decodeUtf8'' or--- 'decodeUtf8With'.-decodeUtf8 :: ByteString -> Text-decodeUtf8 = decodeUtf8With strictDecode-{-# INLINE[0] decodeUtf8 #-}-{-# RULES "STREAM stream/decodeUtf8 fusion" [1]-    forall bs. F.stream (decodeUtf8 bs) = E.streamUtf8 strictDecode bs #-}---- | Decode a 'ByteString' containing UTF-8 encoded text.------ If the input contains any invalid UTF-8 data, the relevant--- exception will be returned, otherwise the decoded text.-decodeUtf8' :: ByteString -> Either UnicodeException Text-decodeUtf8' = unsafeDupablePerformIO . try . evaluate . decodeUtf8With strictDecode-{-# INLINE decodeUtf8' #-}---- | Encode text to a ByteString 'B.Builder' using UTF-8 encoding.------ @since 1.1.0.0-encodeUtf8Builder :: Text -> B.Builder-encodeUtf8Builder = encodeUtf8BuilderEscaped (BP.liftFixedToBounded BP.word8)---- | Encode text using UTF-8 encoding and escape the ASCII characters using--- a 'BP.BoundedPrim'.------ Use this function is to implement efficient encoders for text-based formats--- like JSON or HTML.------ @since 1.1.0.0-{-# INLINE encodeUtf8BuilderEscaped #-}--- TODO: Extend documentation with references to source code in @blaze-html@--- or @aeson@ that uses this function.-encodeUtf8BuilderEscaped :: BP.BoundedPrim Word8 -> Text -> B.Builder-encodeUtf8BuilderEscaped be =-    -- manual eta-expansion to ensure inlining works as expected-    \txt -> B.builder (mkBuildstep txt)-  where-    bound = max 4 $ BP.sizeBound be--    mkBuildstep (Text arr off len) !k =-        outerLoop off-      where-        iend = off + len--        outerLoop !i0 !br@(B.BufferRange op0 ope)-          | i0 >= iend       = k br-          | outRemaining > 0 = goPartial (i0 + min outRemaining inpRemaining)-          -- TODO: Use a loop with an integrated bound's check if outRemaining-          -- is smaller than 8, as this will save on divisions.-          | otherwise        = return $ B.bufferFull bound op0 (outerLoop i0)-          where-            outRemaining = (ope `minusPtr` op0) `div` bound-            inpRemaining = iend - i0--            goPartial !iendTmp = go i0 op0-              where-                go !i !op-                  | i < iendTmp = case A.unsafeIndex arr i of-                      w | w <= 0x7F -> do-                            BP.runB be (fromIntegral w) op >>= go (i + 1)-                        | w <= 0x7FF -> do-                            poke8 0 $ (w `shiftR` 6) + 0xC0-                            poke8 1 $ (w .&. 0x3f) + 0x80-                            go (i + 1) (op `plusPtr` 2)-                        | 0xD800 <= w && w <= 0xDBFF -> do-                            let c = ord $ U16.chr2 w (A.unsafeIndex arr (i+1))-                            poke8 0 $ (c `shiftR` 18) + 0xF0-                            poke8 1 $ ((c `shiftR` 12) .&. 0x3F) + 0x80-                            poke8 2 $ ((c `shiftR` 6) .&. 0x3F) + 0x80-                            poke8 3 $ (c .&. 0x3F) + 0x80-                            go (i + 2) (op `plusPtr` 4)-                        | otherwise -> do-                            poke8 0 $ (w `shiftR` 12) + 0xE0-                            poke8 1 $ ((w `shiftR` 6) .&. 0x3F) + 0x80-                            poke8 2 $ (w .&. 0x3F) + 0x80-                            go (i + 1) (op `plusPtr` 3)-                  | otherwise =-                      outerLoop i (B.BufferRange op ope)-                  where-                    poke8 j v = poke (op `plusPtr` j) (fromIntegral v :: Word8)---- | Encode text using UTF-8 encoding.-encodeUtf8 :: Text -> ByteString-encodeUtf8 (Text arr off len)-  | len == 0  = B.empty-  | otherwise = unsafeDupablePerformIO $ do-  fp <- mallocByteString (len*3) -- see https://github.com/haskell/text/issues/194 for why len*3 is enough-  withForeignPtr fp $ \ptr ->-    with ptr $ \destPtr -> do-      c_encode_utf8 destPtr (A.aBA arr) (fromIntegral off) (fromIntegral len)-      newDest <- peek destPtr-      let utf8len = newDest `minusPtr` ptr-      if utf8len >= len `shiftR` 1-        then return (PS fp 0 utf8len)-        else do-          fp' <- mallocByteString utf8len-          withForeignPtr fp' $ \ptr' -> do-            memcpy ptr' ptr (fromIntegral utf8len)-            return (PS fp' 0 utf8len)---- | Decode text from little endian UTF-16 encoding.-decodeUtf16LEWith :: OnDecodeError -> ByteString -> Text-decodeUtf16LEWith onErr bs = F.unstream (E.streamUtf16LE onErr bs)-{-# INLINE decodeUtf16LEWith #-}---- | Decode text from little endian UTF-16 encoding.------ If the input contains any invalid little endian UTF-16 data, an--- exception will be thrown.  For more control over the handling of--- invalid data, use 'decodeUtf16LEWith'.-decodeUtf16LE :: ByteString -> Text-decodeUtf16LE = decodeUtf16LEWith strictDecode-{-# INLINE decodeUtf16LE #-}---- | Decode text from big endian UTF-16 encoding.-decodeUtf16BEWith :: OnDecodeError -> ByteString -> Text-decodeUtf16BEWith onErr bs = F.unstream (E.streamUtf16BE onErr bs)-{-# INLINE decodeUtf16BEWith #-}---- | Decode text from big endian UTF-16 encoding.------ If the input contains any invalid big endian UTF-16 data, an--- exception will be thrown.  For more control over the handling of--- invalid data, use 'decodeUtf16BEWith'.-decodeUtf16BE :: ByteString -> Text-decodeUtf16BE = decodeUtf16BEWith strictDecode-{-# INLINE decodeUtf16BE #-}---- | Encode text using little endian UTF-16 encoding.-encodeUtf16LE :: Text -> ByteString-encodeUtf16LE txt = E.unstream (E.restreamUtf16LE (F.stream txt))-{-# INLINE encodeUtf16LE #-}---- | Encode text using big endian UTF-16 encoding.-encodeUtf16BE :: Text -> ByteString-encodeUtf16BE txt = E.unstream (E.restreamUtf16BE (F.stream txt))-{-# INLINE encodeUtf16BE #-}---- | Decode text from little endian UTF-32 encoding.-decodeUtf32LEWith :: OnDecodeError -> ByteString -> Text-decodeUtf32LEWith onErr bs = F.unstream (E.streamUtf32LE onErr bs)-{-# INLINE decodeUtf32LEWith #-}---- | Decode text from little endian UTF-32 encoding.------ If the input contains any invalid little endian UTF-32 data, an--- exception will be thrown.  For more control over the handling of--- invalid data, use 'decodeUtf32LEWith'.-decodeUtf32LE :: ByteString -> Text-decodeUtf32LE = decodeUtf32LEWith strictDecode-{-# INLINE decodeUtf32LE #-}---- | Decode text from big endian UTF-32 encoding.-decodeUtf32BEWith :: OnDecodeError -> ByteString -> Text-decodeUtf32BEWith onErr bs = F.unstream (E.streamUtf32BE onErr bs)-{-# INLINE decodeUtf32BEWith #-}---- | Decode text from big endian UTF-32 encoding.------ If the input contains any invalid big endian UTF-32 data, an--- exception will be thrown.  For more control over the handling of--- invalid data, use 'decodeUtf32BEWith'.-decodeUtf32BE :: ByteString -> Text-decodeUtf32BE = decodeUtf32BEWith strictDecode-{-# INLINE decodeUtf32BE #-}---- | Encode text using little endian UTF-32 encoding.-encodeUtf32LE :: Text -> ByteString-encodeUtf32LE txt = E.unstream (E.restreamUtf32LE (F.stream txt))-{-# INLINE encodeUtf32LE #-}---- | Encode text using big endian UTF-32 encoding.-encodeUtf32BE :: Text -> ByteString-encodeUtf32BE txt = E.unstream (E.restreamUtf32BE (F.stream txt))-{-# INLINE encodeUtf32BE #-}--foreign import ccall unsafe "_hs_text_decode_utf8" c_decode_utf8-    :: MutableByteArray# s -> Ptr CSize-    -> Ptr Word8 -> Ptr Word8 -> IO (Ptr Word8)--foreign import ccall unsafe "_hs_text_decode_utf8_state" c_decode_utf8_with_state-    :: MutableByteArray# s -> Ptr CSize-    -> Ptr (Ptr Word8) -> Ptr Word8-    -> Ptr CodePoint -> Ptr DecoderState -> IO (Ptr Word8)--foreign import ccall unsafe "_hs_text_decode_latin1" c_decode_latin1-    :: MutableByteArray# s -> Ptr Word8 -> Ptr Word8 -> IO ()--foreign import ccall unsafe "_hs_text_encode_utf8" c_encode_utf8-    :: Ptr (Ptr Word8) -> ByteArray# -> CSize -> CSize -> IO ()
− Data/Text/Encoding/Error.hs
@@ -1,124 +0,0 @@-{-# LANGUAGE CPP, DeriveDataTypeable #-}-#if __GLASGOW_HASKELL__ >= 704-{-# LANGUAGE Safe #-}-#elif __GLASGOW_HASKELL__ >= 702-{-# LANGUAGE Trustworthy #-}-#endif--- |--- Module      : Data.Text.Encoding.Error--- Copyright   : (c) Bryan O'Sullivan 2009------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Portability : GHC------ Types and functions for dealing with encoding and decoding errors--- in Unicode text.------ The standard functions for encoding and decoding text are strict,--- which is to say that they throw exceptions on invalid input.  This--- is often unhelpful on real world input, so alternative functions--- exist that accept custom handlers for dealing with invalid inputs.--- These 'OnError' handlers are normal Haskell functions.  You can use--- one of the presupplied functions in this module, or you can write a--- custom handler of your own.--module Data.Text.Encoding.Error-    (-    -- * Error handling types-      UnicodeException(..)-    , OnError-    , OnDecodeError-    , OnEncodeError-    -- * Useful error handling functions-    , lenientDecode-    , strictDecode-    , strictEncode-    , ignore-    , replace-    ) where--import Control.DeepSeq (NFData (..))-import Control.Exception (Exception, throw)-import Data.Typeable (Typeable)-import Data.Word (Word8)-import Numeric (showHex)---- | Function type for handling a coding error.  It is supplied with--- two inputs:------ * A 'String' that describes the error.------ * The input value that caused the error.  If the error arose---   because the end of input was reached or could not be identified---   precisely, this value will be 'Nothing'.------ If the handler returns a value wrapped with 'Just', that value will--- be used in the output as the replacement for the invalid input.  If--- it returns 'Nothing', no value will be used in the output.------ Should the handler need to abort processing, it should use 'error'--- or 'throw' an exception (preferably a 'UnicodeException').  It may--- use the description provided to construct a more helpful error--- report.-type OnError a b = String -> Maybe a -> Maybe b---- | A handler for a decoding error.-type OnDecodeError = OnError Word8 Char---- | A handler for an encoding error.-{-# DEPRECATED OnEncodeError "This exception is never used in practice, and will be removed." #-}-type OnEncodeError = OnError Char Word8---- | An exception type for representing Unicode encoding errors.-data UnicodeException =-    DecodeError String (Maybe Word8)-    -- ^ Could not decode a byte sequence because it was invalid under-    -- the given encoding, or ran out of input in mid-decode.-  | EncodeError String (Maybe Char)-    -- ^ Tried to encode a character that could not be represented-    -- under the given encoding, or ran out of input in mid-encode.-    deriving (Eq, Typeable)--{-# DEPRECATED EncodeError "This constructor is never used, and will be removed." #-}--showUnicodeException :: UnicodeException -> String-showUnicodeException (DecodeError desc (Just w))-    = "Cannot decode byte '\\x" ++ showHex w ("': " ++ desc)-showUnicodeException (DecodeError desc Nothing)-    = "Cannot decode input: " ++ desc-showUnicodeException (EncodeError desc (Just c))-    = "Cannot encode character '\\x" ++ showHex (fromEnum c) ("': " ++ desc)-showUnicodeException (EncodeError desc Nothing)-    = "Cannot encode input: " ++ desc--instance Show UnicodeException where-    show = showUnicodeException--instance Exception UnicodeException--instance NFData UnicodeException where-    rnf (DecodeError desc w) = rnf desc `seq` rnf w `seq` ()-    rnf (EncodeError desc c) = rnf desc `seq` rnf c `seq` ()---- | Throw a 'UnicodeException' if decoding fails.-strictDecode :: OnDecodeError-strictDecode desc c = throw (DecodeError desc c)---- | Replace an invalid input byte with the Unicode replacement--- character U+FFFD.-lenientDecode :: OnDecodeError-lenientDecode _ _ = Just '\xfffd'---- | Throw a 'UnicodeException' if encoding fails.-{-# DEPRECATED strictEncode "This function always throws an exception, and will be removed." #-}-strictEncode :: OnEncodeError-strictEncode desc c = throw (EncodeError desc c)---- | Ignore an invalid input, substituting nothing in the output.-ignore :: OnError a b-ignore _ _ = Nothing---- | Replace an invalid input with a valid output.-replace :: b -> OnError a b-replace c _ _ = Just c
− Data/Text/Foreign.hs
@@ -1,176 +0,0 @@-{-# LANGUAGE BangPatterns, CPP, GeneralizedNewtypeDeriving #-}--- |--- Module      : Data.Text.Foreign--- Copyright   : (c) 2009, 2010 Bryan O'Sullivan------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Portability : GHC------ Support for using 'Text' data with native code via the Haskell--- foreign function interface.--module Data.Text.Foreign-    (-    -- * Interoperability with native code-    -- $interop-      I16-    -- * Safe conversion functions-    , fromPtr-    , useAsPtr-    , asForeignPtr-    -- ** Encoding as UTF-8-    , peekCStringLen-    , withCStringLen-    -- * Unsafe conversion code-    , lengthWord16-    , unsafeCopyToPtr-    -- * Low-level manipulation-    -- $lowlevel-    , dropWord16-    , takeWord16-    ) where--#if defined(ASSERTS)-import Control.Exception (assert)-#endif-#if MIN_VERSION_base(4,4,0)-import Control.Monad.ST.Unsafe (unsafeIOToST)-#else-import Control.Monad.ST (unsafeIOToST)-#endif-import Data.ByteString.Unsafe (unsafePackCStringLen, unsafeUseAsCStringLen)-import Data.Text.Encoding (decodeUtf8, encodeUtf8)-import Data.Text.Internal (Text(..), empty)-import Data.Text.Unsafe (lengthWord16)-import Data.Word (Word16)-import Foreign.C.String (CStringLen)-import Foreign.ForeignPtr (ForeignPtr, mallocForeignPtrArray, withForeignPtr)-import Foreign.Marshal.Alloc (allocaBytes)-import Foreign.Ptr (Ptr, castPtr, plusPtr)-import Foreign.Storable (peek, poke)-import qualified Data.Text.Array as A---- $interop------ The 'Text' type is implemented using arrays that are not guaranteed--- to have a fixed address in the Haskell heap. All communication with--- native code must thus occur by copying data back and forth.------ The 'Text' type's internal representation is UTF-16, using the--- platform's native endianness.  This makes copied data suitable for--- use with native libraries that use a similar representation, such--- as ICU.  To interoperate with native libraries that use different--- internal representations, such as UTF-8 or UTF-32, consider using--- the functions in the 'Data.Text.Encoding' module.---- | A type representing a number of UTF-16 code units.-newtype I16 = I16 Int-    deriving (Bounded, Enum, Eq, Integral, Num, Ord, Read, Real, Show)---- | /O(n)/ Create a new 'Text' from a 'Ptr' 'Word16' by copying the--- contents of the array.-fromPtr :: Ptr Word16           -- ^ source array-        -> I16                  -- ^ length of source array (in 'Word16' units)-        -> IO Text-fromPtr _   (I16 0)   = return empty-fromPtr ptr (I16 len) =-#if defined(ASSERTS)-    assert (len > 0) $-#endif-    return $! Text arr 0 len-  where-    arr = A.run (A.new len >>= copy)-    copy marr = loop ptr 0-      where-        loop !p !i | i == len = return marr-                   | otherwise = do-          A.unsafeWrite marr i =<< unsafeIOToST (peek p)-          loop (p `plusPtr` 2) (i + 1)---- $lowlevel------ Foreign functions that use UTF-16 internally may return indices in--- units of 'Word16' instead of characters.  These functions may--- safely be used with such indices, as they will adjust offsets if--- necessary to preserve the validity of a Unicode string.---- | /O(1)/ Return the prefix of the 'Text' of @n@ 'Word16' units in--- length.------ If @n@ would cause the 'Text' to end inside a surrogate pair, the--- end of the prefix will be advanced by one additional 'Word16' unit--- to maintain its validity.-takeWord16 :: I16 -> Text -> Text-takeWord16 (I16 n) t@(Text arr off len)-    | n <= 0               = empty-    | n >= len || m >= len = t-    | otherwise            = Text arr off m-  where-    m | w < 0xD800 || w > 0xDBFF = n-      | otherwise                = n+1-    w = A.unsafeIndex arr (off+n-1)---- | /O(1)/ Return the suffix of the 'Text', with @n@ 'Word16' units--- dropped from its beginning.------ If @n@ would cause the 'Text' to begin inside a surrogate pair, the--- beginning of the suffix will be advanced by one additional 'Word16'--- unit to maintain its validity.-dropWord16 :: I16 -> Text -> Text-dropWord16 (I16 n) t@(Text arr off len)-    | n <= 0               = t-    | n >= len || m >= len = empty-    | otherwise            = Text arr (off+m) (len-m)-  where-    m | w < 0xD800 || w > 0xDBFF = n-      | otherwise                = n+1-    w = A.unsafeIndex arr (off+n-1)---- | /O(n)/ Copy a 'Text' to an array.  The array is assumed to be big--- enough to hold the contents of the entire 'Text'.-unsafeCopyToPtr :: Text -> Ptr Word16 -> IO ()-unsafeCopyToPtr (Text arr off len) ptr = loop ptr off-  where-    end = off + len-    loop !p !i | i == end  = return ()-               | otherwise = do-      poke p (A.unsafeIndex arr i)-      loop (p `plusPtr` 2) (i + 1)---- | /O(n)/ Perform an action on a temporary, mutable copy of a--- 'Text'.  The copy is freed as soon as the action returns.-useAsPtr :: Text -> (Ptr Word16 -> I16 -> IO a) -> IO a-useAsPtr t@(Text _arr _off len) action =-    allocaBytes (len * 2) $ \buf -> do-      unsafeCopyToPtr t buf-      action (castPtr buf) (fromIntegral len)---- | /O(n)/ Make a mutable copy of a 'Text'.-asForeignPtr :: Text -> IO (ForeignPtr Word16, I16)-asForeignPtr t@(Text _arr _off len) = do-  fp <- mallocForeignPtrArray len-  withForeignPtr fp $ unsafeCopyToPtr t-  return (fp, I16 len)---- | /O(n)/ Decode a C string with explicit length, which is assumed--- to have been encoded as UTF-8. If decoding fails, a--- 'UnicodeException' is thrown.------ @since 1.0.0.0-peekCStringLen :: CStringLen -> IO Text-peekCStringLen cs = do-  bs <- unsafePackCStringLen cs-  return $! decodeUtf8 bs---- | Marshal a 'Text' into a C string encoded as UTF-8 in temporary--- storage, with explicit length information. The encoded string may--- contain NUL bytes, and is not followed by a trailing NUL byte.------ The temporary storage is freed when the subcomputation terminates--- (either normally or via an exception), so the pointer to the--- temporary storage must /not/ be used after this function returns.------ @since 1.0.0.0-withCStringLen :: Text -> (CStringLen -> IO a) -> IO a-withCStringLen t act = unsafeUseAsCStringLen (encodeUtf8 t) act
− Data/Text/IO.hs
@@ -1,350 +0,0 @@-{-# LANGUAGE BangPatterns, CPP, RecordWildCards, ScopedTypeVariables #-}-#if __GLASGOW_HASKELL__ >= 702-{-# LANGUAGE Trustworthy #-}-#endif--- |--- Module      : Data.Text.IO--- Copyright   : (c) 2009, 2010 Bryan O'Sullivan,---               (c) 2009 Simon Marlow--- License     : BSD-style--- Maintainer  : bos@serpentine.com--- Portability : GHC------ Efficient locale-sensitive support for text I\/O.------ Skip past the synopsis for some important notes on performance and--- portability across different versions of GHC.--module Data.Text.IO-    (-    -- * Performance-    -- $performance--    -- * Locale support-    -- $locale-    -- * File-at-a-time operations-      readFile-    , writeFile-    , appendFile-    -- * Operations on handles-    , hGetContents-    , hGetChunk-    , hGetLine-    , hPutStr-    , hPutStrLn-    -- * Special cases for standard input and output-    , interact-    , getContents-    , getLine-    , putStr-    , putStrLn-    ) where--import Data.Text (Text)-import Prelude hiding (appendFile, getContents, getLine, interact,-                       putStr, putStrLn, readFile, writeFile)-import System.IO (Handle, IOMode(..), hPutChar, openFile, stdin, stdout,-                  withFile)-import qualified Control.Exception as E-import Control.Monad (liftM2, when)-import Data.IORef (readIORef, writeIORef)-import qualified Data.Text as T-import Data.Text.Internal.Fusion (stream)-import Data.Text.Internal.Fusion.Types (Step(..), Stream(..))-import Data.Text.Internal.IO (hGetLineWith, readChunk)-import GHC.IO.Buffer (Buffer(..), BufferState(..), CharBufElem, CharBuffer,-                      RawCharBuffer, emptyBuffer, isEmptyBuffer, newCharBuffer,-                      writeCharBuf)-import GHC.IO.Exception (IOException(ioe_type), IOErrorType(InappropriateType))-import GHC.IO.Handle.Internals (augmentIOError, hClose_help, wantReadableHandle,-                                wantWritableHandle)-import GHC.IO.Handle.Text (commitBuffer')-import GHC.IO.Handle.Types (BufferList(..), BufferMode(..), Handle__(..),-                            HandleType(..), Newline(..))-import System.IO (hGetBuffering, hFileSize, hSetBuffering, hTell)-import System.IO.Error (isEOFError)---- $performance--- #performance#------ The functions in this module obey the runtime system's locale,--- character set encoding, and line ending conversion settings.------ If you know in advance that you will be working with data that has--- a specific encoding (e.g. UTF-8), and your application is highly--- performance sensitive, you may find that it is faster to perform--- I\/O with bytestrings and to encode and decode yourself than to use--- the functions in this module.------ Whether this will hold depends on the version of GHC you are using,--- the platform you are working on, the data you are working with, and--- the encodings you are using, so be sure to test for yourself.---- | The 'readFile' function reads a file and returns the contents of--- the file as a string.  The entire file is read strictly, as with--- 'getContents'.-readFile :: FilePath -> IO Text-readFile name = openFile name ReadMode >>= hGetContents---- | Write a string to a file.  The file is truncated to zero length--- before writing begins.-writeFile :: FilePath -> Text -> IO ()-writeFile p = withFile p WriteMode . flip hPutStr---- | Write a string the end of a file.-appendFile :: FilePath -> Text -> IO ()-appendFile p = withFile p AppendMode . flip hPutStr--catchError :: String -> Handle -> Handle__ -> IOError -> IO (Text, Bool)-catchError caller h Handle__{..} err-    | isEOFError err = do-        buf <- readIORef haCharBuffer-        return $ if isEmptyBuffer buf-                 then (T.empty, True)-                 else (T.singleton '\r', True)-    | otherwise = E.throwIO (augmentIOError err caller h)---- | Wrap readChunk and return a value indicating if we're reached the EOF.--- This is needed because unpack_nl is unable to discern the difference--- between a buffer with just \r due to EOF or because not enough data was left--- for decoding. e.g. the final character decoded from the byte buffer was \r.-readChunkEof :: Handle__ -> CharBuffer -> IO (Text, Bool)-readChunkEof hh buf = do t <- readChunk hh buf-                         return (t, False)---- | /Experimental./ Read a single chunk of strict text from a--- 'Handle'. The size of the chunk depends on the amount of input--- currently buffered.------ This function blocks only if there is no data available, and EOF--- has not yet been reached. Once EOF is reached, this function--- returns an empty string instead of throwing an exception.-hGetChunk :: Handle -> IO Text-hGetChunk h = wantReadableHandle "hGetChunk" h readSingleChunk- where-  readSingleChunk hh@Handle__{..} = do-    buf <- readIORef haCharBuffer-    (t, _) <- readChunkEof hh buf `E.catch` catchError "hGetChunk" h hh-    return (hh, t)---- | Read the remaining contents of a 'Handle' as a string.  The--- 'Handle' is closed once the contents have been read, or if an--- exception is thrown.------ Internally, this function reads a chunk at a time from the--- lower-level buffering abstraction, and concatenates the chunks into--- a single string once the entire file has been read.------ As a result, it requires approximately twice as much memory as its--- result to construct its result.  For files more than a half of--- available RAM in size, this may result in memory exhaustion.-hGetContents :: Handle -> IO Text-hGetContents h = do-  chooseGoodBuffering h-  wantReadableHandle "hGetContents" h readAll- where-  readAll hh@Handle__{..} = do-    let readChunks = do-          buf <- readIORef haCharBuffer-          (t, eof) <- readChunkEof hh buf-                         `E.catch` catchError "hGetContents" h hh-          if eof-            then return [t]-            else (t:) `fmap` readChunks-    ts <- readChunks-    (hh', _) <- hClose_help hh-    return (hh'{haType=ClosedHandle}, T.concat ts)---- | Use a more efficient buffer size if we're reading in--- block-buffered mode with the default buffer size.  When we can--- determine the size of the handle we're reading, set the buffer size--- to that, so that we can read the entire file in one chunk.--- Otherwise, use a buffer size of at least 16KB.-chooseGoodBuffering :: Handle -> IO ()-chooseGoodBuffering h = do-  bufMode <- hGetBuffering h-  case bufMode of-    BlockBuffering Nothing -> do-      d <- E.catch (liftM2 (-) (hFileSize h) (hTell h)) $ \(e::IOException) ->-           if ioe_type e == InappropriateType-           then return 16384 -- faster than the 2KB default-           else E.throwIO e-      when (d > 0) . hSetBuffering h . BlockBuffering . Just . fromIntegral $ d-    _ -> return ()---- | Read a single line from a handle.-hGetLine :: Handle -> IO Text-hGetLine = hGetLineWith T.concat---- | Write a string to a handle.-hPutStr :: Handle -> Text -> IO ()--- This function is lifted almost verbatim from GHC.IO.Handle.Text.-hPutStr h t = do-  (buffer_mode, nl) <--       wantWritableHandle "hPutStr" h $ \h_ -> do-                     bmode <- getSpareBuffer h_-                     return (bmode, haOutputNL h_)-  let str = stream t-  case buffer_mode of-     (NoBuffering, _)        -> hPutChars h str-     (LineBuffering, buf)    -> writeLines h nl buf str-     (BlockBuffering _, buf)-         | nl == CRLF        -> writeBlocksCRLF h buf str-         | otherwise         -> writeBlocksRaw h buf str--hPutChars :: Handle -> Stream Char -> IO ()-hPutChars h (Stream next0 s0 _len) = loop s0-  where-    loop !s = case next0 s of-                Done       -> return ()-                Skip s'    -> loop s'-                Yield x s' -> hPutChar h x >> loop s'---- The following functions are largely lifted from GHC.IO.Handle.Text,--- but adapted to a coinductive stream of data instead of an inductive--- list.------ We have several variations of more or less the same code for--- performance reasons.  Splitting the original buffered write--- function into line- and block-oriented versions gave us a 2.1x--- performance improvement.  Lifting out the raw/cooked newline--- handling gave a few more percent on top.--writeLines :: Handle -> Newline -> Buffer CharBufElem -> Stream Char -> IO ()-writeLines h nl buf0 (Stream next0 s0 _len) = outer s0 buf0- where-  outer s1 Buffer{bufRaw=raw, bufSize=len} = inner s1 (0::Int)-   where-    inner !s !n =-      case next0 s of-        Done -> commit n False{-no flush-} True{-release-} >> return ()-        Skip s' -> inner s' n-        Yield x s'-          | n + 1 >= len -> commit n True{-needs flush-} False >>= outer s-          | x == '\n'    -> do-                   n' <- if nl == CRLF-                         then do n1 <- writeCharBuf raw n '\r'-                                 writeCharBuf raw n1 '\n'-                         else writeCharBuf raw n x-                   commit n' True{-needs flush-} False >>= outer s'-          | otherwise    -> writeCharBuf raw n x >>= inner s'-    commit = commitBuffer h raw len--writeBlocksCRLF :: Handle -> Buffer CharBufElem -> Stream Char -> IO ()-writeBlocksCRLF h buf0 (Stream next0 s0 _len) = outer s0 buf0- where-  outer s1 Buffer{bufRaw=raw, bufSize=len} = inner s1 (0::Int)-   where-    inner !s !n =-      case next0 s of-        Done -> commit n False{-no flush-} True{-release-} >> return ()-        Skip s' -> inner s' n-        Yield x s'-          | n + 1 >= len -> commit n True{-needs flush-} False >>= outer s-          | x == '\n'    -> do n1 <- writeCharBuf raw n '\r'-                               writeCharBuf raw n1 '\n' >>= inner s'-          | otherwise    -> writeCharBuf raw n x >>= inner s'-    commit = commitBuffer h raw len--writeBlocksRaw :: Handle -> Buffer CharBufElem -> Stream Char -> IO ()-writeBlocksRaw h buf0 (Stream next0 s0 _len) = outer s0 buf0- where-  outer s1 Buffer{bufRaw=raw, bufSize=len} = inner s1 (0::Int)-   where-    inner !s !n =-      case next0 s of-        Done -> commit n False{-no flush-} True{-release-} >> return ()-        Skip s' -> inner s' n-        Yield x s'-          | n + 1 >= len -> commit n True{-needs flush-} False >>= outer s-          | otherwise    -> writeCharBuf raw n x >>= inner s'-    commit = commitBuffer h raw len---- This function is completely lifted from GHC.IO.Handle.Text.-getSpareBuffer :: Handle__ -> IO (BufferMode, CharBuffer)-getSpareBuffer Handle__{haCharBuffer=ref,-                        haBuffers=spare_ref,-                        haBufferMode=mode}- = do-   case mode of-     NoBuffering -> return (mode, error "no buffer!")-     _ -> do-          bufs <- readIORef spare_ref-          buf  <- readIORef ref-          case bufs of-            BufferListCons b rest -> do-                writeIORef spare_ref rest-                return ( mode, emptyBuffer b (bufSize buf) WriteBuffer)-            BufferListNil -> do-                new_buf <- newCharBuffer (bufSize buf) WriteBuffer-                return (mode, new_buf)----- This function is completely lifted from GHC.IO.Handle.Text.-commitBuffer :: Handle -> RawCharBuffer -> Int -> Int -> Bool -> Bool-             -> IO CharBuffer-commitBuffer hdl !raw !sz !count flush release =-  wantWritableHandle "commitAndReleaseBuffer" hdl $-     commitBuffer' raw sz count flush release-{-# INLINE commitBuffer #-}---- | Write a string to a handle, followed by a newline.-hPutStrLn :: Handle -> Text -> IO ()-hPutStrLn h t = hPutStr h t >> hPutChar h '\n'---- | The 'interact' function takes a function of type @Text -> Text@--- as its argument. The entire input from the standard input device is--- passed to this function as its argument, and the resulting string--- is output on the standard output device.-interact :: (Text -> Text) -> IO ()-interact f = putStr . f =<< getContents---- | Read all user input on 'stdin' as a single string.-getContents :: IO Text-getContents = hGetContents stdin---- | Read a single line of user input from 'stdin'.-getLine :: IO Text-getLine = hGetLine stdin---- | Write a string to 'stdout'.-putStr :: Text -> IO ()-putStr = hPutStr stdout---- | Write a string to 'stdout', followed by a newline.-putStrLn :: Text -> IO ()-putStrLn = hPutStrLn stdout---- $locale------ /Note/: The behaviour of functions in this module depends on the--- version of GHC you are using.------ Beginning with GHC 6.12, text I\/O is performed using the system or--- handle's current locale and line ending conventions.------ Under GHC 6.10 and earlier, the system I\/O libraries do not--- support locale-sensitive I\/O or line ending conversion.  On these--- versions of GHC, functions in this library all use UTF-8.  What--- does this mean in practice?------ * All data that is read will be decoded as UTF-8.------ * Before data is written, it is first encoded as UTF-8.------ * On both reading and writing, the platform's native newline---   conversion is performed.------ If you must use a non-UTF-8 locale on an older version of GHC, you--- will have to perform the transcoding yourself, e.g. as follows:------ > import qualified Data.ByteString as B--- > import Data.Text (Text)--- > import Data.Text.Encoding (encodeUtf16)--- >--- > putStr_Utf16LE :: Text -> IO ()--- > putStr_Utf16LE t = B.putStr (encodeUtf16LE t)------ On transcoding errors, an 'IOError' exception is thrown. You can--- use the API in "Data.Text.Encoding" if you need more control over--- error handling or transcoding.
− Data/Text/Internal.hs
@@ -1,188 +0,0 @@-{-# LANGUAGE CPP, DeriveDataTypeable, UnboxedTuples #-}-{-# OPTIONS_HADDOCK not-home #-}---- |--- Module      : Data.Text.Internal--- Copyright   : (c) 2008, 2009 Tom Harper,---               (c) 2009, 2010 Bryan O'Sullivan,---               (c) 2009 Duncan Coutts------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : GHC------ A module containing private 'Text' internals. This exposes the--- 'Text' representation and low level construction functions.--- Modules which extend the 'Text' system may need to use this module.------ You should not use this module unless you are determined to monkey--- with the internals, as the functions here do just about nothing to--- preserve data invariants.  You have been warned!--#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__)-#include "MachDeps.h"-#endif--module Data.Text.Internal-    (-    -- * Types-    -- $internals-      Text(..)-    -- * Construction-    , text-    , textP-    -- * Safety-    , safe-    -- * Code that must be here for accessibility-    , empty-    , empty_-    -- * Utilities-    , firstf-    -- * Checked multiplication-    , mul-    , mul32-    , mul64-    -- * Debugging-    , showText-    ) where--#if defined(ASSERTS)-import Control.Exception (assert)-#endif-import Data.Bits-import Data.Int (Int32, Int64)-import Data.Text.Internal.Unsafe.Char (ord)-import Data.Typeable (Typeable)-import qualified Data.Text.Array as A---- | A space efficient, packed, unboxed Unicode text type.-data Text = Text-    {-# UNPACK #-} !A.Array          -- payload (Word16 elements)-    {-# UNPACK #-} !Int              -- offset (units of Word16, not Char)-    {-# UNPACK #-} !Int              -- length (units of Word16, not Char)-    deriving (Typeable)---- | Smart constructor.-text_ :: A.Array -> Int -> Int -> Text-text_ arr off len =-#if defined(ASSERTS)-  let c    = A.unsafeIndex arr off-      alen = A.length arr-  in assert (len >= 0) .-     assert (off >= 0) .-     assert (alen == 0 || len == 0 || off < alen) .-     assert (len == 0 || c < 0xDC00 || c > 0xDFFF) $-#endif-     Text arr off len-{-# INLINE text_ #-}---- | /O(1)/ The empty 'Text'.-empty :: Text-empty = Text A.empty 0 0-{-# INLINE [1] empty #-}---- | A non-inlined version of 'empty'.-empty_ :: Text-empty_ = Text A.empty 0 0-{-# NOINLINE empty_ #-}---- | Construct a 'Text' without invisibly pinning its byte array in--- memory if its length has dwindled to zero.-text :: A.Array -> Int -> Int -> Text-text arr off len | len == 0  = empty-                 | otherwise = text_ arr off len-{-# INLINE text #-}--textP :: A.Array -> Int -> Int -> Text-{-# DEPRECATED textP "Use text instead" #-}-textP = text---- | A useful 'show'-like function for debugging purposes.-showText :: Text -> String-showText (Text arr off len) =-    "Text " ++ show (A.toList arr off len) ++ ' ' :-            show off ++ ' ' : show len---- | Map a 'Char' to a 'Text'-safe value.------ UTF-16 surrogate code points are not included in the set of Unicode--- scalar values, but are unfortunately admitted as valid 'Char'--- values by Haskell.  They cannot be represented in a 'Text'.  This--- function remaps those code points to the Unicode replacement--- character (U+FFFD, \'&#xfffd;\'), and leaves other code points--- unchanged.-safe :: Char -> Char-safe c-    | ord c .&. 0x1ff800 /= 0xd800 = c-    | otherwise                    = '\xfffd'-{-# INLINE [0] safe #-}---- | Apply a function to the first element of an optional pair.-firstf :: (a -> c) -> Maybe (a,b) -> Maybe (c,b)-firstf f (Just (a, b)) = Just (f a, b)-firstf _  Nothing      = Nothing---- | Checked multiplication.  Calls 'error' if the result would--- overflow.-mul :: Int -> Int -> Int-#if WORD_SIZE_IN_BITS == 64-mul a b = fromIntegral $ fromIntegral a `mul64` fromIntegral b-#else-mul a b = fromIntegral $ fromIntegral a `mul32` fromIntegral b-#endif-{-# INLINE mul #-}-infixl 7 `mul`---- | Checked multiplication.  Calls 'error' if the result would--- overflow.-mul64 :: Int64 -> Int64 -> Int64-mul64 a b-  | a >= 0 && b >= 0 =  mul64_ a b-  | a >= 0           = -mul64_ a (-b)-  | b >= 0           = -mul64_ (-a) b-  | otherwise        =  mul64_ (-a) (-b)-{-# INLINE mul64 #-}-infixl 7 `mul64`--mul64_ :: Int64 -> Int64 -> Int64-mul64_ a b-  | ahi > 0 && bhi > 0 = error "overflow"-  | top > 0x7fffffff   = error "overflow"-  | total < 0          = error "overflow"-  | otherwise          = total-  where (# ahi, alo #) = (# a `shiftR` 32, a .&. 0xffffffff #)-        (# bhi, blo #) = (# b `shiftR` 32, b .&. 0xffffffff #)-        top            = ahi * blo + alo * bhi-        total          = (top `shiftL` 32) + alo * blo-{-# INLINE mul64_ #-}---- | Checked multiplication.  Calls 'error' if the result would--- overflow.-mul32 :: Int32 -> Int32 -> Int32-mul32 a b = case fromIntegral a * fromIntegral b of-              ab | ab < min32 || ab > max32 -> error "overflow"-                 | otherwise                -> fromIntegral ab-  where min32 = -0x80000000 :: Int64-        max32 =  0x7fffffff-{-# INLINE mul32 #-}-infixl 7 `mul32`---- $internals------ Internally, the 'Text' type is represented as an array of 'Word16'--- UTF-16 code units. The offset and length fields in the constructor--- are in these units, /not/ units of 'Char'.------ Invariants that all functions must maintain:------ * Since the 'Text' type uses UTF-16 internally, it cannot represent---   characters in the reserved surrogate code point range U+D800 to---   U+DFFF. To maintain this invariant, the 'safe' function maps---   'Char' values in this range to the replacement character (U+FFFD,---   \'&#xfffd;\').------ * A leading (or \"high\") surrogate code unit (0xD800–0xDBFF) must---   always be followed by a trailing (or \"low\") surrogate code unit---   (0xDC00-0xDFFF). A trailing surrogate code unit must always be---   preceded by a leading surrogate code unit.
− Data/Text/Internal/Builder.hs
@@ -1,329 +0,0 @@-{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}-{-# OPTIONS_HADDOCK not-home #-}---------------------------------------------------------------------------------- |--- Module      : Data.Text.Internal.Builder--- Copyright   : (c) 2013 Bryan O'Sullivan---               (c) 2010 Johan Tibell--- License     : BSD-style (see LICENSE)------ Maintainer  : Johan Tibell <johan.tibell@gmail.com>--- Stability   : experimental--- Portability : portable to Hugs and GHC------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ Efficient construction of lazy @Text@ values.  The principal--- operations on a @Builder@ are @singleton@, @fromText@, and--- @fromLazyText@, which construct new builders, and 'mappend', which--- concatenates two builders.------ To get maximum performance when building lazy @Text@ values using a--- builder, associate @mappend@ calls to the right.  For example,--- prefer------ > singleton 'a' `mappend` (singleton 'b' `mappend` singleton 'c')------ to------ > singleton 'a' `mappend` singleton 'b' `mappend` singleton 'c'------ as the latter associates @mappend@ to the left.-----------------------------------------------------------------------------------module Data.Text.Internal.Builder-   ( -- * Public API-     -- ** The Builder type-     Builder-   , toLazyText-   , toLazyTextWith--     -- ** Constructing Builders-   , singleton-   , fromText-   , fromLazyText-   , fromString--     -- ** Flushing the buffer state-   , flush--     -- * Internal functions-   , append'-   , ensureFree-   , writeN-   ) where--import Control.Monad.ST (ST, runST)-import Data.Monoid (Monoid(..))-#if !MIN_VERSION_base(4,11,0) && MIN_VERSION_base(4,9,0)-import Data.Semigroup (Semigroup(..))-#endif-import Data.Text.Internal (Text(..))-import Data.Text.Internal.Lazy (smallChunkSize)-import Data.Text.Unsafe (inlineInterleaveST)-import Data.Text.Internal.Unsafe.Char (unsafeWrite)-import Prelude hiding (map, putChar)--import qualified Data.String as String-import qualified Data.Text as S-import qualified Data.Text.Array as A-import qualified Data.Text.Lazy as L------------------------------------------------------------------------------ | A @Builder@ is an efficient way to build lazy @Text@ values.--- There are several functions for constructing builders, but only one--- to inspect them: to extract any data, you have to turn them into--- lazy @Text@ values using @toLazyText@.------ Internally, a builder constructs a lazy @Text@ by filling arrays--- piece by piece.  As each buffer is filled, it is \'popped\' off, to--- become a new chunk of the resulting lazy @Text@.  All this is--- hidden from the user of the @Builder@.-newtype Builder = Builder {-     -- Invariant (from Data.Text.Lazy):-     --      The lists include no null Texts.-     runBuilder :: forall s. (Buffer s -> ST s [S.Text])-                -> Buffer s-                -> ST s [S.Text]-   }--#if MIN_VERSION_base(4,9,0)-instance Semigroup Builder where-   (<>) = append-   {-# INLINE (<>) #-}-#endif--instance Monoid Builder where-   mempty  = empty-   {-# INLINE mempty #-}-#if MIN_VERSION_base(4,9,0)-   mappend = (<>) -- future-proof definition-#else-   mappend = append-#endif-   {-# INLINE mappend #-}-   mconcat = foldr mappend Data.Monoid.mempty-   {-# INLINE mconcat #-}--instance String.IsString Builder where-    fromString = fromString-    {-# INLINE fromString #-}--instance Show Builder where-    show = show . toLazyText--instance Eq Builder where-    a == b = toLazyText a == toLazyText b--instance Ord Builder where-    a <= b = toLazyText a <= toLazyText b------------------------------------------------------------------------------ | /O(1)./ The empty @Builder@, satisfying------  * @'toLazyText' 'empty' = 'L.empty'@----empty :: Builder-empty = Builder (\ k buf -> k buf)-{-# INLINE empty #-}---- | /O(1)./ A @Builder@ taking a single character, satisfying------  * @'toLazyText' ('singleton' c) = 'L.singleton' c@----singleton :: Char -> Builder-singleton c = writeAtMost 2 $ \ marr o -> unsafeWrite marr o c-{-# INLINE singleton #-}------------------------------------------------------------------------------ | /O(1)./ The concatenation of two builders, an associative--- operation with identity 'empty', satisfying------  * @'toLazyText' ('append' x y) = 'L.append' ('toLazyText' x) ('toLazyText' y)@----append :: Builder -> Builder -> Builder-append (Builder f) (Builder g) = Builder (f . g)-{-# INLINE [0] append #-}---- TODO: Experiment to find the right threshold.-copyLimit :: Int-copyLimit = 128---- This function attempts to merge small @Text@ values instead of--- treating each value as its own chunk.  We may not always want this.---- | /O(1)./ A @Builder@ taking a 'S.Text', satisfying------  * @'toLazyText' ('fromText' t) = 'L.fromChunks' [t]@----fromText :: S.Text -> Builder-fromText t@(Text arr off l)-    | S.null t       = empty-    | l <= copyLimit = writeN l $ \marr o -> A.copyI marr o arr off (l+o)-    | otherwise      = flush `append` mapBuilder (t :)-{-# INLINE [1] fromText #-}--{-# RULES-"fromText/pack" forall s .-        fromText (S.pack s) = fromString s- #-}---- | /O(1)./ A Builder taking a @String@, satisfying------  * @'toLazyText' ('fromString' s) = 'L.fromChunks' [S.pack s]@----fromString :: String -> Builder-fromString str = Builder $ \k (Buffer p0 o0 u0 l0) ->-    let loop !marr !o !u !l [] = k (Buffer marr o u l)-        loop marr o u l s@(c:cs)-            | l <= 1 = do-                arr <- A.unsafeFreeze marr-                let !t = Text arr o u-                marr' <- A.new chunkSize-                ts <- inlineInterleaveST (loop marr' 0 0 chunkSize s)-                return $ t : ts-            | otherwise = do-                n <- unsafeWrite marr (o+u) c-                loop marr o (u+n) (l-n) cs-    in loop p0 o0 u0 l0 str-  where-    chunkSize = smallChunkSize-{-# INLINE fromString #-}---- | /O(1)./ A @Builder@ taking a lazy @Text@, satisfying------  * @'toLazyText' ('fromLazyText' t) = t@----fromLazyText :: L.Text -> Builder-fromLazyText ts = flush `append` mapBuilder (L.toChunks ts ++)-{-# INLINE fromLazyText #-}------------------------------------------------------------------------------ Our internal buffer type-data Buffer s = Buffer {-# UNPACK #-} !(A.MArray s)-                       {-# UNPACK #-} !Int  -- offset-                       {-# UNPACK #-} !Int  -- used units-                       {-# UNPACK #-} !Int  -- length left------------------------------------------------------------------------------ | /O(n)./ Extract a lazy @Text@ from a @Builder@ with a default--- buffer size.  The construction work takes place if and when the--- relevant part of the lazy @Text@ is demanded.-toLazyText :: Builder -> L.Text-toLazyText = toLazyTextWith smallChunkSize---- | /O(n)./ Extract a lazy @Text@ from a @Builder@, using the given--- size for the initial buffer.  The construction work takes place if--- and when the relevant part of the lazy @Text@ is demanded.------ If the initial buffer is too small to hold all data, subsequent--- buffers will be the default buffer size.-toLazyTextWith :: Int -> Builder -> L.Text-toLazyTextWith chunkSize m = L.fromChunks (runST $-  newBuffer chunkSize >>= runBuilder (m `append` flush) (const (return [])))---- | /O(1)./ Pop the strict @Text@ we have constructed so far, if any,--- yielding a new chunk in the result lazy @Text@.-flush :: Builder-flush = Builder $ \ k buf@(Buffer p o u l) ->-    if u == 0-    then k buf-    else do arr <- A.unsafeFreeze p-            let !b = Buffer p (o+u) 0 l-                !t = Text arr o u-            ts <- inlineInterleaveST (k b)-            return $! t : ts-{-# INLINE [1] flush #-}--- defer inlining so that flush/flush rule may fire.------------------------------------------------------------------------------ | Sequence an ST operation on the buffer-withBuffer :: (forall s. Buffer s -> ST s (Buffer s)) -> Builder-withBuffer f = Builder $ \k buf -> f buf >>= k-{-# INLINE withBuffer #-}---- | Get the size of the buffer-withSize :: (Int -> Builder) -> Builder-withSize f = Builder $ \ k buf@(Buffer _ _ _ l) ->-    runBuilder (f l) k buf-{-# INLINE withSize #-}---- | Map the resulting list of texts.-mapBuilder :: ([S.Text] -> [S.Text]) -> Builder-mapBuilder f = Builder (fmap f .)------------------------------------------------------------------------------ | Ensure that there are at least @n@ many elements available.-ensureFree :: Int -> Builder-ensureFree !n = withSize $ \ l ->-    if n <= l-    then empty-    else flush `append'` withBuffer (const (newBuffer (max n smallChunkSize)))-{-# INLINE [0] ensureFree #-}--writeAtMost :: Int -> (forall s. A.MArray s -> Int -> ST s Int) -> Builder-writeAtMost n f = ensureFree n `append'` withBuffer (writeBuffer f)-{-# INLINE [0] writeAtMost #-}---- | Ensure that @n@ many elements are available, and then use @f@ to--- write some elements into the memory.-writeN :: Int -> (forall s. A.MArray s -> Int -> ST s ()) -> Builder-writeN n f = writeAtMost n (\ p o -> f p o >> return n)-{-# INLINE writeN #-}--writeBuffer :: (A.MArray s -> Int -> ST s Int) -> Buffer s -> ST s (Buffer s)-writeBuffer f (Buffer p o u l) = do-    n <- f p (o+u)-    return $! Buffer p o (u+n) (l-n)-{-# INLINE writeBuffer #-}--newBuffer :: Int -> ST s (Buffer s)-newBuffer size = do-    arr <- A.new size-    return $! Buffer arr 0 0 size-{-# INLINE newBuffer #-}----------------------------------------------------------------------------- Some nice rules for Builder---- This function makes GHC understand that 'writeN' and 'ensureFree'--- are *not* recursive in the precense of the rewrite rules below.--- This is not needed with GHC 7+.-append' :: Builder -> Builder -> Builder-append' (Builder f) (Builder g) = Builder (f . g)-{-# INLINE append' #-}--{-# RULES--"append/writeAtMost" forall a b (f::forall s. A.MArray s -> Int -> ST s Int)-                           (g::forall s. A.MArray s -> Int -> ST s Int) ws.-    append (writeAtMost a f) (append (writeAtMost b g) ws) =-        append (writeAtMost (a+b) (\marr o -> f marr o >>= \ n ->-                                    g marr (o+n) >>= \ m ->-                                    let s = n+m in s `seq` return s)) ws--"writeAtMost/writeAtMost" forall a b (f::forall s. A.MArray s -> Int -> ST s Int)-                           (g::forall s. A.MArray s -> Int -> ST s Int).-    append (writeAtMost a f) (writeAtMost b g) =-        writeAtMost (a+b) (\marr o -> f marr o >>= \ n ->-                            g marr (o+n) >>= \ m ->-                            let s = n+m in s `seq` return s)--"ensureFree/ensureFree" forall a b .-    append (ensureFree a) (ensureFree b) = ensureFree (max a b)--"flush/flush"-    append flush flush = flush-- #-}
− Data/Text/Internal/Builder/Functions.hs
@@ -1,40 +0,0 @@-{-# LANGUAGE MagicHash #-}---- |--- Module      : Data.Text.Internal.Builder.Functions--- Copyright   : (c) 2011 MailRank, Inc.------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : GHC------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ Useful functions and combinators.--module Data.Text.Internal.Builder.Functions-    (-      (<>)-    , i2d-    ) where--import Data.Monoid (mappend)-import Data.Text.Lazy.Builder (Builder)-import GHC.Base (chr#,ord#,(+#),Int(I#),Char(C#))-import Prelude ()---- | Unsafe conversion for decimal digits.-{-# INLINE i2d #-}-i2d :: Int -> Char-i2d (I# i#) = C# (chr# (ord# '0'# +# i#))---- | The normal 'mappend' function with right associativity instead of--- left.-(<>) :: Builder -> Builder -> Builder-(<>) = mappend-{-# INLINE (<>) #-}--infixr 4 <>
− Data/Text/Internal/Builder/Int/Digits.hs
@@ -1,26 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}---- Module:      Data.Text.Internal.Builder.Int.Digits--- Copyright:   (c) 2013 Bryan O'Sullivan--- License:     BSD-style--- Maintainer:  Bryan O'Sullivan <bos@serpentine.com>--- Stability:   experimental--- Portability: portable------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ This module exists because the C preprocessor does things that we--- shall not speak of when confronted with Haskell multiline strings.--module Data.Text.Internal.Builder.Int.Digits (digits) where--import Data.ByteString.Char8 (ByteString)--digits :: ByteString-digits = "0001020304050607080910111213141516171819\-         \2021222324252627282930313233343536373839\-         \4041424344454647484950515253545556575859\-         \6061626364656667686970717273747576777879\-         \8081828384858687888990919293949596979899"
− Data/Text/Internal/Builder/RealFloat/Functions.hs
@@ -1,57 +0,0 @@-{-# LANGUAGE CPP #-}---- |--- Module:    Data.Text.Internal.Builder.RealFloat.Functions--- Copyright: (c) The University of Glasgow 1994-2002--- License:   see libraries/base/LICENSE------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!--module Data.Text.Internal.Builder.RealFloat.Functions-    (-      roundTo-    ) where--roundTo :: Int -> [Int] -> (Int,[Int])--#if MIN_VERSION_base(4,6,0)--roundTo d is =-  case f d True is of-    x@(0,_) -> x-    (1,xs)  -> (1, 1:xs)-    _       -> error "roundTo: bad Value"- where-  b2 = base `quot` 2--  f n _ []     = (0, replicate n 0)-  f 0 e (x:xs) | x == b2 && e && all (== 0) xs = (0, [])   -- Round to even when at exactly half the base-               | otherwise = (if x >= b2 then 1 else 0, [])-  f n _ (i:xs)-     | i' == base = (1,0:ds)-     | otherwise  = (0,i':ds)-      where-       (c,ds) = f (n-1) (even i) xs-       i'     = c + i-  base = 10--#else--roundTo d is =-  case f d is of-    x@(0,_) -> x-    (1,xs)  -> (1, 1:xs)-    _       -> error "roundTo: bad Value"- where-  f n []     = (0, replicate n 0)-  f 0 (x:_)  = (if x >= 5 then 1 else 0, [])-  f n (i:xs)-     | i' == 10  = (1,0:ds)-     | otherwise = (0,i':ds)-      where-       (c,ds) = f (n-1) xs-       i'     = c + i--#endif
− Data/Text/Internal/Encoding/Fusion.hs
@@ -1,208 +0,0 @@-{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}---- |--- Module      : Data.Text.Internal.Encoding.Fusion--- Copyright   : (c) Tom Harper 2008-2009,---               (c) Bryan O'Sullivan 2009,---               (c) Duncan Coutts 2009------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : portable------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ Fusible 'Stream'-oriented functions for converting between 'Text'--- and several common encodings.--module Data.Text.Internal.Encoding.Fusion-    (-    -- * Streaming-      streamASCII-    , streamUtf8-    , streamUtf16LE-    , streamUtf16BE-    , streamUtf32LE-    , streamUtf32BE--    -- * Unstreaming-    , unstream--    , module Data.Text.Internal.Encoding.Fusion.Common-    ) where--#if defined(ASSERTS)-import Control.Exception (assert)-#endif-import Data.ByteString.Internal (ByteString(..), mallocByteString, memcpy)-import Data.Text.Internal.Fusion (Step(..), Stream(..))-import Data.Text.Internal.Fusion.Size-import Data.Text.Encoding.Error-import Data.Text.Internal.Encoding.Fusion.Common-import Data.Text.Internal.Unsafe.Char (unsafeChr, unsafeChr8, unsafeChr32)-import Data.Text.Internal.Unsafe.Shift (shiftL, shiftR)-import Data.Word (Word8, Word16, Word32)-import Foreign.ForeignPtr (withForeignPtr, ForeignPtr)-import Foreign.Storable (pokeByteOff)-import qualified Data.ByteString as B-import qualified Data.ByteString.Unsafe as B-import qualified Data.Text.Internal.Encoding.Utf8 as U8-import qualified Data.Text.Internal.Encoding.Utf16 as U16-import qualified Data.Text.Internal.Encoding.Utf32 as U32-import Data.Text.Unsafe (unsafeDupablePerformIO)--streamASCII :: ByteString -> Stream Char-streamASCII bs = Stream next 0 (maxSize l)-    where-      l = B.length bs-      {-# INLINE next #-}-      next i-          | i >= l    = Done-          | otherwise = Yield (unsafeChr8 x1) (i+1)-          where-            x1 = B.unsafeIndex bs i-{-# DEPRECATED streamASCII "Do not use this function" #-}-{-# INLINE [0] streamASCII #-}---- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using UTF-8--- encoding.-streamUtf8 :: OnDecodeError -> ByteString -> Stream Char-streamUtf8 onErr bs = Stream next 0 (maxSize l)-    where-      l = B.length bs-      next i-          | i >= l = Done-          | U8.validate1 x1 = Yield (unsafeChr8 x1) (i+1)-          | i+1 < l && U8.validate2 x1 x2 = Yield (U8.chr2 x1 x2) (i+2)-          | i+2 < l && U8.validate3 x1 x2 x3 = Yield (U8.chr3 x1 x2 x3) (i+3)-          | i+3 < l && U8.validate4 x1 x2 x3 x4 = Yield (U8.chr4 x1 x2 x3 x4) (i+4)-          | otherwise = decodeError "streamUtf8" "UTF-8" onErr (Just x1) (i+1)-          where-            x1 = idx i-            x2 = idx (i + 1)-            x3 = idx (i + 2)-            x4 = idx (i + 3)-            idx = B.unsafeIndex bs-{-# INLINE [0] streamUtf8 #-}---- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using little--- endian UTF-16 encoding.-streamUtf16LE :: OnDecodeError -> ByteString -> Stream Char-streamUtf16LE onErr bs = Stream next 0 (maxSize (l `shiftR` 1))-    where-      l = B.length bs-      {-# INLINE next #-}-      next i-          | i >= l                         = Done-          | i+1 < l && U16.validate1 x1    = Yield (unsafeChr x1) (i+2)-          | i+3 < l && U16.validate2 x1 x2 = Yield (U16.chr2 x1 x2) (i+4)-          | otherwise = decodeError "streamUtf16LE" "UTF-16LE" onErr Nothing (i+1)-          where-            x1    = idx i       + (idx (i + 1) `shiftL` 8)-            x2    = idx (i + 2) + (idx (i + 3) `shiftL` 8)-            idx = fromIntegral . B.unsafeIndex bs :: Int -> Word16-{-# INLINE [0] streamUtf16LE #-}---- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using big--- endian UTF-16 encoding.-streamUtf16BE :: OnDecodeError -> ByteString -> Stream Char-streamUtf16BE onErr bs = Stream next 0 (maxSize (l `shiftR` 1))-    where-      l = B.length bs-      {-# INLINE next #-}-      next i-          | i >= l                         = Done-          | i+1 < l && U16.validate1 x1    = Yield (unsafeChr x1) (i+2)-          | i+3 < l && U16.validate2 x1 x2 = Yield (U16.chr2 x1 x2) (i+4)-          | otherwise = decodeError "streamUtf16BE" "UTF-16BE" onErr Nothing (i+1)-          where-            x1    = (idx i `shiftL` 8)       + idx (i + 1)-            x2    = (idx (i + 2) `shiftL` 8) + idx (i + 3)-            idx = fromIntegral . B.unsafeIndex bs :: Int -> Word16-{-# INLINE [0] streamUtf16BE #-}---- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using big--- endian UTF-32 encoding.-streamUtf32BE :: OnDecodeError -> ByteString -> Stream Char-streamUtf32BE onErr bs = Stream next 0 (maxSize (l `shiftR` 2))-    where-      l = B.length bs-      {-# INLINE next #-}-      next i-          | i >= l                    = Done-          | i+3 < l && U32.validate x = Yield (unsafeChr32 x) (i+4)-          | otherwise = decodeError "streamUtf32BE" "UTF-32BE" onErr Nothing (i+1)-          where-            x     = shiftL x1 24 + shiftL x2 16 + shiftL x3 8 + x4-            x1    = idx i-            x2    = idx (i+1)-            x3    = idx (i+2)-            x4    = idx (i+3)-            idx = fromIntegral . B.unsafeIndex bs :: Int -> Word32-{-# INLINE [0] streamUtf32BE #-}---- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using little--- endian UTF-32 encoding.-streamUtf32LE :: OnDecodeError -> ByteString -> Stream Char-streamUtf32LE onErr bs = Stream next 0 (maxSize (l `shiftR` 2))-    where-      l = B.length bs-      {-# INLINE next #-}-      next i-          | i >= l                    = Done-          | i+3 < l && U32.validate x = Yield (unsafeChr32 x) (i+4)-          | otherwise = decodeError "streamUtf32LE" "UTF-32LE" onErr Nothing (i+1)-          where-            x     = shiftL x4 24 + shiftL x3 16 + shiftL x2 8 + x1-            x1    = idx i-            x2    = idx $ i+1-            x3    = idx $ i+2-            x4    = idx $ i+3-            idx = fromIntegral . B.unsafeIndex bs :: Int -> Word32-{-# INLINE [0] streamUtf32LE #-}---- | /O(n)/ Convert a 'Stream' 'Word8' to a 'ByteString'.-unstream :: Stream Word8 -> ByteString-unstream (Stream next s0 len) = unsafeDupablePerformIO $ do-    let mlen = upperBound 4 len-    mallocByteString mlen >>= loop mlen 0 s0-    where-      loop !n !off !s fp = case next s of-          Done -> trimUp fp n off-          Skip s' -> loop n off s' fp-          Yield x s'-              | off == n -> realloc fp n off s' x-              | otherwise -> do-            withForeignPtr fp $ \p -> pokeByteOff p off x-            loop n (off+1) s' fp-      {-# NOINLINE realloc #-}-      realloc fp n off s x = do-        let n' = n+n-        fp' <- copy0 fp n n'-        withForeignPtr fp' $ \p -> pokeByteOff p off x-        loop n' (off+1) s fp'-      {-# NOINLINE trimUp #-}-      trimUp fp _ off = return $! PS fp 0 off-      copy0 :: ForeignPtr Word8 -> Int -> Int -> IO (ForeignPtr Word8)-      copy0 !src !srcLen !destLen =-#if defined(ASSERTS)-        assert (srcLen <= destLen) $-#endif-        do-          dest <- mallocByteString destLen-          withForeignPtr src  $ \src'  ->-              withForeignPtr dest $ \dest' ->-                  memcpy dest' src' (fromIntegral srcLen)-          return dest--decodeError :: forall s. String -> String -> OnDecodeError -> Maybe Word8-            -> s -> Step s Char-decodeError func kind onErr mb i =-    case onErr desc mb of-      Nothing -> Skip i-      Just c  -> Yield c i-    where desc = "Data.Text.Internal.Encoding.Fusion." ++ func ++ ": Invalid " ++-                 kind ++ " stream"
− Data/Text/Internal/Encoding/Fusion/Common.hs
@@ -1,123 +0,0 @@-{-# LANGUAGE BangPatterns #-}---- |--- Module      : Data.Text.Internal.Encoding.Fusion.Common--- Copyright   : (c) Tom Harper 2008-2009,---               (c) Bryan O'Sullivan 2009,---               (c) Duncan Coutts 2009,---               (c) Jasper Van der Jeugt 2011------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : portable------ /Warning/: this is an internal module, and does not have a stable--- API or name. Use at your own risk!------ Fusible 'Stream'-oriented functions for converting between 'Text'--- and several common encodings.--module Data.Text.Internal.Encoding.Fusion.Common-    (-    -- * Restreaming-    -- Restreaming is the act of converting from one 'Stream'-    -- representation to another.-      restreamUtf16LE-    , restreamUtf16BE-    , restreamUtf32LE-    , restreamUtf32BE-    ) where--import Data.Bits ((.&.))-import Data.Text.Internal.Fusion (Step(..), Stream(..))-import Data.Text.Internal.Fusion.Types (RS(..))-import Data.Text.Internal.Unsafe.Char (ord)-import Data.Text.Internal.Unsafe.Shift (shiftR)-import Data.Word (Word8)--restreamUtf16BE :: Stream Char -> Stream Word8-restreamUtf16BE (Stream next0 s0 len) = Stream next (RS0 s0) (len * 2)-  where-    next (RS0 s) = case next0 s of-        Done -> Done-        Skip s' -> Skip (RS0 s')-        Yield x s'-            | n < 0x10000 -> Yield (fromIntegral $ n `shiftR` 8) $-                             RS1 s' (fromIntegral n)-            | otherwise   -> Yield c1 $ RS3 s' c2 c3 c4-            where-              n  = ord x-              n1 = n - 0x10000-              c1 = fromIntegral (n1 `shiftR` 18 + 0xD8)-              c2 = fromIntegral (n1 `shiftR` 10)-              n2 = n1 .&. 0x3FF-              c3 = fromIntegral (n2 `shiftR` 8 + 0xDC)-              c4 = fromIntegral n2-    next (RS1 s x2)       = Yield x2 (RS0 s)-    next (RS2 s x2 x3)    = Yield x2 (RS1 s x3)-    next (RS3 s x2 x3 x4) = Yield x2 (RS2 s x3 x4)-    {-# INLINE next #-}-{-# INLINE restreamUtf16BE #-}--restreamUtf16LE :: Stream Char -> Stream Word8-restreamUtf16LE (Stream next0 s0 len) = Stream next (RS0 s0) (len * 2)-  where-    next (RS0 s) = case next0 s of-        Done -> Done-        Skip s' -> Skip (RS0 s')-        Yield x s'-            | n < 0x10000 -> Yield (fromIntegral n) $-                             RS1 s' (fromIntegral $ shiftR n 8)-            | otherwise   -> Yield c1 $ RS3 s' c2 c3 c4-          where-            n  = ord x-            n1 = n - 0x10000-            c2 = fromIntegral (shiftR n1 18 + 0xD8)-            c1 = fromIntegral (shiftR n1 10)-            n2 = n1 .&. 0x3FF-            c4 = fromIntegral (shiftR n2 8 + 0xDC)-            c3 = fromIntegral n2-    next (RS1 s x2)       = Yield x2 (RS0 s)-    next (RS2 s x2 x3)    = Yield x2 (RS1 s x3)-    next (RS3 s x2 x3 x4) = Yield x2 (RS2 s x3 x4)-    {-# INLINE next #-}-{-# INLINE restreamUtf16LE #-}--restreamUtf32BE :: Stream Char -> Stream Word8-restreamUtf32BE (Stream next0 s0 len) = Stream next (RS0 s0) (len * 2)-  where-    next (RS0 s) = case next0 s of-        Done       -> Done-        Skip s'    -> Skip (RS0 s')-        Yield x s' -> Yield c1 (RS3 s' c2 c3 c4)-          where-            n  = ord x-            c1 = fromIntegral $ shiftR n 24-            c2 = fromIntegral $ shiftR n 16-            c3 = fromIntegral $ shiftR n 8-            c4 = fromIntegral n-    next (RS1 s x2)       = Yield x2 (RS0 s)-    next (RS2 s x2 x3)    = Yield x2 (RS1 s x3)-    next (RS3 s x2 x3 x4) = Yield x2 (RS2 s x3 x4)-    {-# INLINE next #-}-{-# INLINE restreamUtf32BE #-}--restreamUtf32LE :: Stream Char -> Stream Word8-restreamUtf32LE (Stream next0 s0 len) = Stream next (RS0 s0) (len * 2)-  where-    next (RS0 s) = case next0 s of-        Done       -> Done-        Skip s'    -> Skip (RS0 s')-        Yield x s' -> Yield c1 (RS3 s' c2 c3 c4)-          where-            n  = ord x-            c4 = fromIntegral $ shiftR n 24-            c3 = fromIntegral $ shiftR n 16-            c2 = fromIntegral $ shiftR n 8-            c1 = fromIntegral n-    next (RS1 s x2)       = Yield x2 (RS0 s)-    next (RS2 s x2 x3)    = Yield x2 (RS1 s x3)-    next (RS3 s x2 x3 x4) = Yield x2 (RS2 s x3 x4)-    {-# INLINE next #-}-{-# INLINE restreamUtf32LE #-}
− Data/Text/Internal/Encoding/Utf16.hs
@@ -1,45 +0,0 @@-{-# LANGUAGE MagicHash, BangPatterns #-}---- |--- Module      : Data.Text.Internal.Encoding.Utf16--- Copyright   : (c) 2008, 2009 Tom Harper,---               (c) 2009 Bryan O'Sullivan,---               (c) 2009 Duncan Coutts------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : GHC------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ Basic UTF-16 validation and character manipulation.-module Data.Text.Internal.Encoding.Utf16-    (-      chr2-    , validate1-    , validate2-    ) where--import GHC.Exts-import GHC.Word (Word16(..))--chr2 :: Word16 -> Word16 -> Char-chr2 (W16# a#) (W16# b#) = C# (chr# (upper# +# lower# +# 0x10000#))-    where-      !x# = word2Int# a#-      !y# = word2Int# b#-      !upper# = uncheckedIShiftL# (x# -# 0xD800#) 10#-      !lower# = y# -# 0xDC00#-{-# INLINE chr2 #-}--validate1    :: Word16 -> Bool-validate1 x1 = x1 < 0xD800 || x1 > 0xDFFF-{-# INLINE validate1 #-}--validate2       ::  Word16 -> Word16 -> Bool-validate2 x1 x2 = x1 >= 0xD800 && x1 <= 0xDBFF &&-                  x2 >= 0xDC00 && x2 <= 0xDFFF-{-# INLINE validate2 #-}
− Data/Text/Internal/Encoding/Utf32.hs
@@ -1,26 +0,0 @@--- |--- Module      : Data.Text.Internal.Encoding.Utf32--- Copyright   : (c) 2008, 2009 Tom Harper,---               (c) 2009, 2010 Bryan O'Sullivan,---               (c) 2009 Duncan Coutts------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : portable------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ Basic UTF-32 validation.-module Data.Text.Internal.Encoding.Utf32-    (-      validate-    ) where--import Data.Word (Word32)--validate    :: Word32 -> Bool-validate x1 = x1 < 0xD800 || (x1 > 0xDFFF && x1 <= 0x10FFFF)-{-# INLINE validate #-}
− Data/Text/Internal/Encoding/Utf8.hs
@@ -1,168 +0,0 @@-{-# LANGUAGE CPP, MagicHash, BangPatterns #-}---- |--- Module      : Data.Text.Internal.Encoding.Utf8--- Copyright   : (c) 2008, 2009 Tom Harper,---               (c) 2009, 2010 Bryan O'Sullivan,---               (c) 2009 Duncan Coutts------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : GHC------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ Basic UTF-8 validation and character manipulation.-module Data.Text.Internal.Encoding.Utf8-    (-    -- Decomposition-      ord2-    , ord3-    , ord4-    -- Construction-    , chr2-    , chr3-    , chr4-    -- * Validation-    , validate1-    , validate2-    , validate3-    , validate4-    ) where--#if defined(TEST_SUITE)-# undef ASSERTS-#endif--#if defined(ASSERTS)-import Control.Exception (assert)-#endif-import Data.Bits ((.&.))-import Data.Text.Internal.Unsafe.Char (ord)-import Data.Text.Internal.Unsafe.Shift (shiftR)-import GHC.Exts-import GHC.Word (Word8(..))--default(Int)--between :: Word8                -- ^ byte to check-        -> Word8                -- ^ lower bound-        -> Word8                -- ^ upper bound-        -> Bool-between x y z = x >= y && x <= z-{-# INLINE between #-}--ord2 :: Char -> (Word8,Word8)-ord2 c =-#if defined(ASSERTS)-    assert (n >= 0x80 && n <= 0x07ff)-#endif-    (x1,x2)-    where-      n  = ord c-      x1 = fromIntegral $ (n `shiftR` 6) + 0xC0-      x2 = fromIntegral $ (n .&. 0x3F)   + 0x80--ord3 :: Char -> (Word8,Word8,Word8)-ord3 c =-#if defined(ASSERTS)-    assert (n >= 0x0800 && n <= 0xffff)-#endif-    (x1,x2,x3)-    where-      n  = ord c-      x1 = fromIntegral $ (n `shiftR` 12) + 0xE0-      x2 = fromIntegral $ ((n `shiftR` 6) .&. 0x3F) + 0x80-      x3 = fromIntegral $ (n .&. 0x3F) + 0x80--ord4 :: Char -> (Word8,Word8,Word8,Word8)-ord4 c =-#if defined(ASSERTS)-    assert (n >= 0x10000)-#endif-    (x1,x2,x3,x4)-    where-      n  = ord c-      x1 = fromIntegral $ (n `shiftR` 18) + 0xF0-      x2 = fromIntegral $ ((n `shiftR` 12) .&. 0x3F) + 0x80-      x3 = fromIntegral $ ((n `shiftR` 6) .&. 0x3F) + 0x80-      x4 = fromIntegral $ (n .&. 0x3F) + 0x80--chr2 :: Word8 -> Word8 -> Char-chr2 (W8# x1#) (W8# x2#) = C# (chr# (z1# +# z2#))-    where-      !y1# = word2Int# x1#-      !y2# = word2Int# x2#-      !z1# = uncheckedIShiftL# (y1# -# 0xC0#) 6#-      !z2# = y2# -# 0x80#-{-# INLINE chr2 #-}--chr3 :: Word8 -> Word8 -> Word8 -> Char-chr3 (W8# x1#) (W8# x2#) (W8# x3#) = C# (chr# (z1# +# z2# +# z3#))-    where-      !y1# = word2Int# x1#-      !y2# = word2Int# x2#-      !y3# = word2Int# x3#-      !z1# = uncheckedIShiftL# (y1# -# 0xE0#) 12#-      !z2# = uncheckedIShiftL# (y2# -# 0x80#) 6#-      !z3# = y3# -# 0x80#-{-# INLINE chr3 #-}--chr4             :: Word8 -> Word8 -> Word8 -> Word8 -> Char-chr4 (W8# x1#) (W8# x2#) (W8# x3#) (W8# x4#) =-    C# (chr# (z1# +# z2# +# z3# +# z4#))-    where-      !y1# = word2Int# x1#-      !y2# = word2Int# x2#-      !y3# = word2Int# x3#-      !y4# = word2Int# x4#-      !z1# = uncheckedIShiftL# (y1# -# 0xF0#) 18#-      !z2# = uncheckedIShiftL# (y2# -# 0x80#) 12#-      !z3# = uncheckedIShiftL# (y3# -# 0x80#) 6#-      !z4# = y4# -# 0x80#-{-# INLINE chr4 #-}--validate1 :: Word8 -> Bool-validate1 x1 = x1 <= 0x7F-{-# INLINE validate1 #-}--validate2 :: Word8 -> Word8 -> Bool-validate2 x1 x2 = between x1 0xC2 0xDF && between x2 0x80 0xBF-{-# INLINE validate2 #-}--validate3 :: Word8 -> Word8 -> Word8 -> Bool-{-# INLINE validate3 #-}-validate3 x1 x2 x3 = validate3_1 || validate3_2 || validate3_3 || validate3_4-  where-    validate3_1 = (x1 == 0xE0) &&-                  between x2 0xA0 0xBF &&-                  between x3 0x80 0xBF-    validate3_2 = between x1 0xE1 0xEC &&-                  between x2 0x80 0xBF &&-                  between x3 0x80 0xBF-    validate3_3 = x1 == 0xED &&-                  between x2 0x80 0x9F &&-                  between x3 0x80 0xBF-    validate3_4 = between x1 0xEE 0xEF &&-                  between x2 0x80 0xBF &&-                  between x3 0x80 0xBF--validate4 :: Word8 -> Word8 -> Word8 -> Word8 -> Bool-{-# INLINE validate4 #-}-validate4 x1 x2 x3 x4 = validate4_1 || validate4_2 || validate4_3-  where-    validate4_1 = x1 == 0xF0 &&-                  between x2 0x90 0xBF &&-                  between x3 0x80 0xBF &&-                  between x4 0x80 0xBF-    validate4_2 = between x1 0xF1 0xF3 &&-                  between x2 0x80 0xBF &&-                  between x3 0x80 0xBF &&-                  between x4 0x80 0xBF-    validate4_3 = x1 == 0xF4 &&-                  between x2 0x80 0x8F &&-                  between x3 0x80 0xBF &&-                  between x4 0x80 0xBF
− Data/Text/Internal/Functions.hs
@@ -1,29 +0,0 @@--- |--- Module      : Data.Text.Internal.Functions--- Copyright   : 2010 Bryan O'Sullivan------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : GHC------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ Useful functions.--module Data.Text.Internal.Functions-    (-      intersperse-    ) where---- | A lazier version of Data.List.intersperse.  The other version--- causes space leaks!-intersperse :: a -> [a] -> [a]-intersperse _   []     = []-intersperse sep (x:xs) = x : go xs-  where-    go []     = []-    go (y:ys) = sep : y: go ys-{-# INLINE intersperse #-}
− Data/Text/Internal/Fusion.hs
@@ -1,244 +0,0 @@-{-# LANGUAGE BangPatterns, MagicHash #-}---- |--- Module      : Data.Text.Internal.Fusion--- Copyright   : (c) Tom Harper 2008-2009,---               (c) Bryan O'Sullivan 2009-2010,---               (c) Duncan Coutts 2009------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : GHC------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ Text manipulation functions represented as fusible operations over--- streams.-module Data.Text.Internal.Fusion-    (-    -- * Types-      Stream(..)-    , Step(..)--    -- * Creation and elimination-    , stream-    , unstream-    , reverseStream--    , length--    -- * Transformations-    , reverse--    -- * Construction-    -- ** Scans-    , reverseScanr--    -- ** Accumulating maps-    , mapAccumL--    -- ** Generation and unfolding-    , unfoldrN--    -- * Indexing-    , index-    , findIndex-    , countChar-    ) where--import Prelude (Bool(..), Char, Maybe(..), Monad(..), Int,-                Num(..), Ord(..), ($), (&&),-                fromIntegral, otherwise)-import Data.Bits ((.&.))-import Data.Text.Internal (Text(..))-import Data.Text.Internal.Private (runText)-import Data.Text.Internal.Unsafe.Char (ord, unsafeChr, unsafeWrite)-import Data.Text.Internal.Unsafe.Shift (shiftL, shiftR)-import qualified Data.Text.Array as A-import qualified Data.Text.Internal.Fusion.Common as S-import Data.Text.Internal.Fusion.Types-import Data.Text.Internal.Fusion.Size-import qualified Data.Text.Internal as I-import qualified Data.Text.Internal.Encoding.Utf16 as U16--default(Int)---- | /O(n)/ Convert a 'Text' into a 'Stream Char'.-stream :: Text -> Stream Char-stream (Text arr off len) = Stream next off (betweenSize (len `shiftR` 1) len)-    where-      !end = off+len-      next !i-          | i >= end                   = Done-          | n >= 0xD800 && n <= 0xDBFF = Yield (U16.chr2 n n2) (i + 2)-          | otherwise                  = Yield (unsafeChr n) (i + 1)-          where-            n  = A.unsafeIndex arr i-            n2 = A.unsafeIndex arr (i + 1)-{-# INLINE [0] stream #-}---- | /O(n)/ Convert a 'Text' into a 'Stream Char', but iterate--- backwards.-reverseStream :: Text -> Stream Char-reverseStream (Text arr off len) = Stream next (off+len-1) (betweenSize (len `shiftR` 1) len)-    where-      {-# INLINE next #-}-      next !i-          | i < off                    = Done-          | n >= 0xDC00 && n <= 0xDFFF = Yield (U16.chr2 n2 n) (i - 2)-          | otherwise                  = Yield (unsafeChr n) (i - 1)-          where-            n  = A.unsafeIndex arr i-            n2 = A.unsafeIndex arr (i - 1)-{-# INLINE [0] reverseStream #-}---- | /O(n)/ Convert a 'Stream Char' into a 'Text'.-unstream :: Stream Char -> Text-unstream (Stream next0 s0 len) = runText $ \done -> do-  -- Before encoding each char we perform a buffer realloc check assuming-  -- worst case encoding size of two 16-bit units for the char. Just add an-  -- extra space to the buffer so that we do not end up reallocating even when-  -- all the chars are encoded as single unit.-  let mlen = upperBound 4 len + 1-  arr0 <- A.new mlen-  let outer !arr !maxi = encode-       where-        -- keep the common case loop as small as possible-        encode !si !di =-            case next0 si of-                Done        -> done arr di-                Skip si'    -> encode si' di-                Yield c si'-                    -- simply check for the worst case-                    | maxi < di + 1 -> realloc si di-                    | otherwise -> do-                            n <- unsafeWrite arr di c-                            encode si' (di + n)--        -- keep uncommon case separate from the common case code-        {-# NOINLINE realloc #-}-        realloc !si !di = do-            let newlen = (maxi + 1) * 2-            arr' <- A.new newlen-            A.copyM arr' 0 arr 0 di-            outer arr' (newlen - 1) si di--  outer arr0 (mlen - 1) s0 0-{-# INLINE [0] unstream #-}-{-# RULES "STREAM stream/unstream fusion" forall s. stream (unstream s) = s #-}----- ------------------------------------------------------------------------------- * Basic stream functions--length :: Stream Char -> Int-length = S.lengthI-{-# INLINE[0] length #-}---- | /O(n)/ Reverse the characters of a string.-reverse :: Stream Char -> Text-reverse (Stream next s len0)-    | isEmpty len0 = I.empty-    | otherwise    = I.text arr off' len'-  where-    len0' = upperBound 4 (larger len0 4)-    (arr, (off', len')) = A.run2 (A.new len0' >>= loop s (len0'-1) len0')-    loop !s0 !i !len marr =-        case next s0 of-          Done -> return (marr, (j, len-j))-              where j = i + 1-          Skip s1    -> loop s1 i len marr-          Yield x s1 | i < least -> {-# SCC "reverse/resize" #-} do-                       let newLen = len `shiftL` 1-                       marr' <- A.new newLen-                       A.copyM marr' (newLen-len) marr 0 len-                       write s1 (len+i) newLen marr'-                     | otherwise -> write s1 i len marr-            where n = ord x-                  least | n < 0x10000 = 0-                        | otherwise   = 1-                  m = n - 0x10000-                  lo = fromIntegral $ (m `shiftR` 10) + 0xD800-                  hi = fromIntegral $ (m .&. 0x3FF) + 0xDC00-                  write t j l mar-                      | n < 0x10000 = do-                          A.unsafeWrite mar j (fromIntegral n)-                          loop t (j-1) l mar-                      | otherwise = do-                          A.unsafeWrite mar (j-1) lo-                          A.unsafeWrite mar j hi-                          loop t (j-2) l mar-{-# INLINE [0] reverse #-}---- | /O(n)/ Perform the equivalent of 'scanr' over a list, only with--- the input and result reversed.-reverseScanr :: (Char -> Char -> Char) -> Char -> Stream Char -> Stream Char-reverseScanr f z0 (Stream next0 s0 len) = Stream next (Scan1 z0 s0) (len+1) -- HINT maybe too low-  where-    {-# INLINE next #-}-    next (Scan1 z s) = Yield z (Scan2 z s)-    next (Scan2 z s) = case next0 s of-                         Yield x s' -> let !x' = f x z-                                       in Yield x' (Scan2 x' s')-                         Skip s'    -> Skip (Scan2 z s')-                         Done       -> Done-{-# INLINE reverseScanr #-}---- | /O(n)/ Like 'unfoldr', 'unfoldrN' builds a stream from a seed--- value. However, the length of the result is limited by the--- first argument to 'unfoldrN'. This function is more efficient than--- 'unfoldr' when the length of the result is known.-unfoldrN :: Int -> (a -> Maybe (Char,a)) -> a -> Stream Char-unfoldrN n = S.unfoldrNI n-{-# INLINE [0] unfoldrN #-}------------------------------------------------------------------------------------ ** Indexing streams---- | /O(n)/ stream index (subscript) operator, starting from 0.-index :: Stream Char -> Int -> Char-index = S.indexI-{-# INLINE [0] index #-}---- | The 'findIndex' function takes a predicate and a stream and--- returns the index of the first element in the stream--- satisfying the predicate.-findIndex :: (Char -> Bool) -> Stream Char -> Maybe Int-findIndex = S.findIndexI-{-# INLINE [0] findIndex #-}---- | /O(n)/ The 'count' function returns the number of times the query--- element appears in the given stream.-countChar :: Char -> Stream Char -> Int-countChar = S.countCharI-{-# INLINE [0] countChar #-}---- | /O(n)/ Like a combination of 'map' and 'foldl''. Applies a--- function to each element of a 'Text', passing an accumulating--- parameter from left to right, and returns a final 'Text'.-mapAccumL :: (a -> Char -> (a,Char)) -> a -> Stream Char -> (a, Text)-mapAccumL f z0 (Stream next0 s0 len) = (nz, I.text na 0 nl)-  where-    (na,(nz,nl)) = A.run2 (A.new mlen >>= \arr -> outer arr mlen z0 s0 0)-      where mlen = upperBound 4 len-    outer arr top = loop-      where-        loop !z !s !i =-            case next0 s of-              Done          -> return (arr, (z,i))-              Skip s'       -> loop z s' i-              Yield x s'-                | j >= top  -> {-# SCC "mapAccumL/resize" #-} do-                               let top' = (top + 1) `shiftL` 1-                               arr' <- A.new top'-                               A.copyM arr' 0 arr 0 top-                               outer arr' top' z s i-                | otherwise -> do d <- unsafeWrite arr i c-                                  loop z' s' (i+d)-                where (z',c) = f z x-                      j | ord c < 0x10000 = i-                        | otherwise       = i + 1-{-# INLINE [0] mapAccumL #-}
− Data/Text/Internal/Fusion/CaseMapping.hs
@@ -1,1002 +0,0 @@-{-# LANGUAGE Rank2Types #-}--- AUTOMATICALLY GENERATED - DO NOT EDIT--- Generated by scripts/CaseMapping.hs--- CaseFolding-9.0.0.txt--- Date: 2016-03-02, 18:54:54 GMT--- SpecialCasing-9.0.0.txt--- Date: 2016-03-02, 18:55:13 GMT--module Data.Text.Internal.Fusion.CaseMapping where-import Data.Char-import Data.Text.Internal.Fusion.Types--upperMapping :: forall s. Char -> s -> Step (CC s) Char-{-# NOINLINE upperMapping #-}--- LATIN SMALL LETTER SHARP S-upperMapping '\x00df' s = Yield '\x0053' (CC s '\x0053' '\x0000')--- LATIN SMALL LIGATURE FF-upperMapping '\xfb00' s = Yield '\x0046' (CC s '\x0046' '\x0000')--- LATIN SMALL LIGATURE FI-upperMapping '\xfb01' s = Yield '\x0046' (CC s '\x0049' '\x0000')--- LATIN SMALL LIGATURE FL-upperMapping '\xfb02' s = Yield '\x0046' (CC s '\x004c' '\x0000')--- LATIN SMALL LIGATURE FFI-upperMapping '\xfb03' s = Yield '\x0046' (CC s '\x0046' '\x0049')--- LATIN SMALL LIGATURE FFL-upperMapping '\xfb04' s = Yield '\x0046' (CC s '\x0046' '\x004c')--- LATIN SMALL LIGATURE LONG S T-upperMapping '\xfb05' s = Yield '\x0053' (CC s '\x0054' '\x0000')--- LATIN SMALL LIGATURE ST-upperMapping '\xfb06' s = Yield '\x0053' (CC s '\x0054' '\x0000')--- ARMENIAN SMALL LIGATURE ECH YIWN-upperMapping '\x0587' s = Yield '\x0535' (CC s '\x0552' '\x0000')--- ARMENIAN SMALL LIGATURE MEN NOW-upperMapping '\xfb13' s = Yield '\x0544' (CC s '\x0546' '\x0000')--- ARMENIAN SMALL LIGATURE MEN ECH-upperMapping '\xfb14' s = Yield '\x0544' (CC s '\x0535' '\x0000')--- ARMENIAN SMALL LIGATURE MEN INI-upperMapping '\xfb15' s = Yield '\x0544' (CC s '\x053b' '\x0000')--- ARMENIAN SMALL LIGATURE VEW NOW-upperMapping '\xfb16' s = Yield '\x054e' (CC s '\x0546' '\x0000')--- ARMENIAN SMALL LIGATURE MEN XEH-upperMapping '\xfb17' s = Yield '\x0544' (CC s '\x053d' '\x0000')--- LATIN SMALL LETTER N PRECEDED BY APOSTROPHE-upperMapping '\x0149' s = Yield '\x02bc' (CC s '\x004e' '\x0000')--- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS-upperMapping '\x0390' s = Yield '\x0399' (CC s '\x0308' '\x0301')--- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS-upperMapping '\x03b0' s = Yield '\x03a5' (CC s '\x0308' '\x0301')--- LATIN SMALL LETTER J WITH CARON-upperMapping '\x01f0' s = Yield '\x004a' (CC s '\x030c' '\x0000')--- LATIN SMALL LETTER H WITH LINE BELOW-upperMapping '\x1e96' s = Yield '\x0048' (CC s '\x0331' '\x0000')--- LATIN SMALL LETTER T WITH DIAERESIS-upperMapping '\x1e97' s = Yield '\x0054' (CC s '\x0308' '\x0000')--- LATIN SMALL LETTER W WITH RING ABOVE-upperMapping '\x1e98' s = Yield '\x0057' (CC s '\x030a' '\x0000')--- LATIN SMALL LETTER Y WITH RING ABOVE-upperMapping '\x1e99' s = Yield '\x0059' (CC s '\x030a' '\x0000')--- LATIN SMALL LETTER A WITH RIGHT HALF RING-upperMapping '\x1e9a' s = Yield '\x0041' (CC s '\x02be' '\x0000')--- GREEK SMALL LETTER UPSILON WITH PSILI-upperMapping '\x1f50' s = Yield '\x03a5' (CC s '\x0313' '\x0000')--- GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA-upperMapping '\x1f52' s = Yield '\x03a5' (CC s '\x0313' '\x0300')--- GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA-upperMapping '\x1f54' s = Yield '\x03a5' (CC s '\x0313' '\x0301')--- GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI-upperMapping '\x1f56' s = Yield '\x03a5' (CC s '\x0313' '\x0342')--- GREEK SMALL LETTER ALPHA WITH PERISPOMENI-upperMapping '\x1fb6' s = Yield '\x0391' (CC s '\x0342' '\x0000')--- GREEK SMALL LETTER ETA WITH PERISPOMENI-upperMapping '\x1fc6' s = Yield '\x0397' (CC s '\x0342' '\x0000')--- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA-upperMapping '\x1fd2' s = Yield '\x0399' (CC s '\x0308' '\x0300')--- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA-upperMapping '\x1fd3' s = Yield '\x0399' (CC s '\x0308' '\x0301')--- GREEK SMALL LETTER IOTA WITH PERISPOMENI-upperMapping '\x1fd6' s = Yield '\x0399' (CC s '\x0342' '\x0000')--- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI-upperMapping '\x1fd7' s = Yield '\x0399' (CC s '\x0308' '\x0342')--- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA-upperMapping '\x1fe2' s = Yield '\x03a5' (CC s '\x0308' '\x0300')--- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA-upperMapping '\x1fe3' s = Yield '\x03a5' (CC s '\x0308' '\x0301')--- GREEK SMALL LETTER RHO WITH PSILI-upperMapping '\x1fe4' s = Yield '\x03a1' (CC s '\x0313' '\x0000')--- GREEK SMALL LETTER UPSILON WITH PERISPOMENI-upperMapping '\x1fe6' s = Yield '\x03a5' (CC s '\x0342' '\x0000')--- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI-upperMapping '\x1fe7' s = Yield '\x03a5' (CC s '\x0308' '\x0342')--- GREEK SMALL LETTER OMEGA WITH PERISPOMENI-upperMapping '\x1ff6' s = Yield '\x03a9' (CC s '\x0342' '\x0000')--- GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI-upperMapping '\x1f80' s = Yield '\x1f08' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI-upperMapping '\x1f81' s = Yield '\x1f09' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI-upperMapping '\x1f82' s = Yield '\x1f0a' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI-upperMapping '\x1f83' s = Yield '\x1f0b' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI-upperMapping '\x1f84' s = Yield '\x1f0c' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI-upperMapping '\x1f85' s = Yield '\x1f0d' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI-upperMapping '\x1f86' s = Yield '\x1f0e' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI-upperMapping '\x1f87' s = Yield '\x1f0f' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI-upperMapping '\x1f88' s = Yield '\x1f08' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI-upperMapping '\x1f89' s = Yield '\x1f09' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI-upperMapping '\x1f8a' s = Yield '\x1f0a' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI-upperMapping '\x1f8b' s = Yield '\x1f0b' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI-upperMapping '\x1f8c' s = Yield '\x1f0c' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI-upperMapping '\x1f8d' s = Yield '\x1f0d' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI-upperMapping '\x1f8e' s = Yield '\x1f0e' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI-upperMapping '\x1f8f' s = Yield '\x1f0f' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI-upperMapping '\x1f90' s = Yield '\x1f28' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI-upperMapping '\x1f91' s = Yield '\x1f29' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI-upperMapping '\x1f92' s = Yield '\x1f2a' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI-upperMapping '\x1f93' s = Yield '\x1f2b' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI-upperMapping '\x1f94' s = Yield '\x1f2c' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI-upperMapping '\x1f95' s = Yield '\x1f2d' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI-upperMapping '\x1f96' s = Yield '\x1f2e' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI-upperMapping '\x1f97' s = Yield '\x1f2f' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI-upperMapping '\x1f98' s = Yield '\x1f28' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI-upperMapping '\x1f99' s = Yield '\x1f29' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI-upperMapping '\x1f9a' s = Yield '\x1f2a' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI-upperMapping '\x1f9b' s = Yield '\x1f2b' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI-upperMapping '\x1f9c' s = Yield '\x1f2c' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI-upperMapping '\x1f9d' s = Yield '\x1f2d' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI-upperMapping '\x1f9e' s = Yield '\x1f2e' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI-upperMapping '\x1f9f' s = Yield '\x1f2f' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI-upperMapping '\x1fa0' s = Yield '\x1f68' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI-upperMapping '\x1fa1' s = Yield '\x1f69' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI-upperMapping '\x1fa2' s = Yield '\x1f6a' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI-upperMapping '\x1fa3' s = Yield '\x1f6b' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI-upperMapping '\x1fa4' s = Yield '\x1f6c' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI-upperMapping '\x1fa5' s = Yield '\x1f6d' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI-upperMapping '\x1fa6' s = Yield '\x1f6e' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI-upperMapping '\x1fa7' s = Yield '\x1f6f' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI-upperMapping '\x1fa8' s = Yield '\x1f68' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI-upperMapping '\x1fa9' s = Yield '\x1f69' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI-upperMapping '\x1faa' s = Yield '\x1f6a' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI-upperMapping '\x1fab' s = Yield '\x1f6b' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI-upperMapping '\x1fac' s = Yield '\x1f6c' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI-upperMapping '\x1fad' s = Yield '\x1f6d' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI-upperMapping '\x1fae' s = Yield '\x1f6e' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI-upperMapping '\x1faf' s = Yield '\x1f6f' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI-upperMapping '\x1fb3' s = Yield '\x0391' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI-upperMapping '\x1fbc' s = Yield '\x0391' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI-upperMapping '\x1fc3' s = Yield '\x0397' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI-upperMapping '\x1fcc' s = Yield '\x0397' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI-upperMapping '\x1ff3' s = Yield '\x03a9' (CC s '\x0399' '\x0000')--- GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI-upperMapping '\x1ffc' s = Yield '\x03a9' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI-upperMapping '\x1fb2' s = Yield '\x1fba' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI-upperMapping '\x1fb4' s = Yield '\x0386' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI-upperMapping '\x1fc2' s = Yield '\x1fca' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI-upperMapping '\x1fc4' s = Yield '\x0389' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI-upperMapping '\x1ff2' s = Yield '\x1ffa' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI-upperMapping '\x1ff4' s = Yield '\x038f' (CC s '\x0399' '\x0000')--- GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI-upperMapping '\x1fb7' s = Yield '\x0391' (CC s '\x0342' '\x0399')--- GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI-upperMapping '\x1fc7' s = Yield '\x0397' (CC s '\x0342' '\x0399')--- GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI-upperMapping '\x1ff7' s = Yield '\x03a9' (CC s '\x0342' '\x0399')-upperMapping c s = Yield (toUpper c) (CC s '\0' '\0')-lowerMapping :: forall s. Char -> s -> Step (CC s) Char-{-# NOINLINE lowerMapping #-}--- LATIN CAPITAL LETTER I WITH DOT ABOVE-lowerMapping '\x0130' s = Yield '\x0069' (CC s '\x0307' '\x0000')-lowerMapping c s = Yield (toLower c) (CC s '\0' '\0')-titleMapping :: forall s. Char -> s -> Step (CC s) Char-{-# NOINLINE titleMapping #-}--- LATIN SMALL LETTER SHARP S-titleMapping '\x00df' s = Yield '\x0053' (CC s '\x0073' '\x0000')--- LATIN SMALL LIGATURE FF-titleMapping '\xfb00' s = Yield '\x0046' (CC s '\x0066' '\x0000')--- LATIN SMALL LIGATURE FI-titleMapping '\xfb01' s = Yield '\x0046' (CC s '\x0069' '\x0000')--- LATIN SMALL LIGATURE FL-titleMapping '\xfb02' s = Yield '\x0046' (CC s '\x006c' '\x0000')--- LATIN SMALL LIGATURE FFI-titleMapping '\xfb03' s = Yield '\x0046' (CC s '\x0066' '\x0069')--- LATIN SMALL LIGATURE FFL-titleMapping '\xfb04' s = Yield '\x0046' (CC s '\x0066' '\x006c')--- LATIN SMALL LIGATURE LONG S T-titleMapping '\xfb05' s = Yield '\x0053' (CC s '\x0074' '\x0000')--- LATIN SMALL LIGATURE ST-titleMapping '\xfb06' s = Yield '\x0053' (CC s '\x0074' '\x0000')--- ARMENIAN SMALL LIGATURE ECH YIWN-titleMapping '\x0587' s = Yield '\x0535' (CC s '\x0582' '\x0000')--- ARMENIAN SMALL LIGATURE MEN NOW-titleMapping '\xfb13' s = Yield '\x0544' (CC s '\x0576' '\x0000')--- ARMENIAN SMALL LIGATURE MEN ECH-titleMapping '\xfb14' s = Yield '\x0544' (CC s '\x0565' '\x0000')--- ARMENIAN SMALL LIGATURE MEN INI-titleMapping '\xfb15' s = Yield '\x0544' (CC s '\x056b' '\x0000')--- ARMENIAN SMALL LIGATURE VEW NOW-titleMapping '\xfb16' s = Yield '\x054e' (CC s '\x0576' '\x0000')--- ARMENIAN SMALL LIGATURE MEN XEH-titleMapping '\xfb17' s = Yield '\x0544' (CC s '\x056d' '\x0000')--- LATIN SMALL LETTER N PRECEDED BY APOSTROPHE-titleMapping '\x0149' s = Yield '\x02bc' (CC s '\x004e' '\x0000')--- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS-titleMapping '\x0390' s = Yield '\x0399' (CC s '\x0308' '\x0301')--- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS-titleMapping '\x03b0' s = Yield '\x03a5' (CC s '\x0308' '\x0301')--- LATIN SMALL LETTER J WITH CARON-titleMapping '\x01f0' s = Yield '\x004a' (CC s '\x030c' '\x0000')--- LATIN SMALL LETTER H WITH LINE BELOW-titleMapping '\x1e96' s = Yield '\x0048' (CC s '\x0331' '\x0000')--- LATIN SMALL LETTER T WITH DIAERESIS-titleMapping '\x1e97' s = Yield '\x0054' (CC s '\x0308' '\x0000')--- LATIN SMALL LETTER W WITH RING ABOVE-titleMapping '\x1e98' s = Yield '\x0057' (CC s '\x030a' '\x0000')--- LATIN SMALL LETTER Y WITH RING ABOVE-titleMapping '\x1e99' s = Yield '\x0059' (CC s '\x030a' '\x0000')--- LATIN SMALL LETTER A WITH RIGHT HALF RING-titleMapping '\x1e9a' s = Yield '\x0041' (CC s '\x02be' '\x0000')--- GREEK SMALL LETTER UPSILON WITH PSILI-titleMapping '\x1f50' s = Yield '\x03a5' (CC s '\x0313' '\x0000')--- GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA-titleMapping '\x1f52' s = Yield '\x03a5' (CC s '\x0313' '\x0300')--- GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA-titleMapping '\x1f54' s = Yield '\x03a5' (CC s '\x0313' '\x0301')--- GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI-titleMapping '\x1f56' s = Yield '\x03a5' (CC s '\x0313' '\x0342')--- GREEK SMALL LETTER ALPHA WITH PERISPOMENI-titleMapping '\x1fb6' s = Yield '\x0391' (CC s '\x0342' '\x0000')--- GREEK SMALL LETTER ETA WITH PERISPOMENI-titleMapping '\x1fc6' s = Yield '\x0397' (CC s '\x0342' '\x0000')--- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA-titleMapping '\x1fd2' s = Yield '\x0399' (CC s '\x0308' '\x0300')--- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA-titleMapping '\x1fd3' s = Yield '\x0399' (CC s '\x0308' '\x0301')--- GREEK SMALL LETTER IOTA WITH PERISPOMENI-titleMapping '\x1fd6' s = Yield '\x0399' (CC s '\x0342' '\x0000')--- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI-titleMapping '\x1fd7' s = Yield '\x0399' (CC s '\x0308' '\x0342')--- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA-titleMapping '\x1fe2' s = Yield '\x03a5' (CC s '\x0308' '\x0300')--- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA-titleMapping '\x1fe3' s = Yield '\x03a5' (CC s '\x0308' '\x0301')--- GREEK SMALL LETTER RHO WITH PSILI-titleMapping '\x1fe4' s = Yield '\x03a1' (CC s '\x0313' '\x0000')--- GREEK SMALL LETTER UPSILON WITH PERISPOMENI-titleMapping '\x1fe6' s = Yield '\x03a5' (CC s '\x0342' '\x0000')--- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI-titleMapping '\x1fe7' s = Yield '\x03a5' (CC s '\x0308' '\x0342')--- GREEK SMALL LETTER OMEGA WITH PERISPOMENI-titleMapping '\x1ff6' s = Yield '\x03a9' (CC s '\x0342' '\x0000')--- GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI-titleMapping '\x1fb2' s = Yield '\x1fba' (CC s '\x0345' '\x0000')--- GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI-titleMapping '\x1fb4' s = Yield '\x0386' (CC s '\x0345' '\x0000')--- GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI-titleMapping '\x1fc2' s = Yield '\x1fca' (CC s '\x0345' '\x0000')--- GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI-titleMapping '\x1fc4' s = Yield '\x0389' (CC s '\x0345' '\x0000')--- GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI-titleMapping '\x1ff2' s = Yield '\x1ffa' (CC s '\x0345' '\x0000')--- GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI-titleMapping '\x1ff4' s = Yield '\x038f' (CC s '\x0345' '\x0000')--- GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI-titleMapping '\x1fb7' s = Yield '\x0391' (CC s '\x0342' '\x0345')--- GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI-titleMapping '\x1fc7' s = Yield '\x0397' (CC s '\x0342' '\x0345')--- GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI-titleMapping '\x1ff7' s = Yield '\x03a9' (CC s '\x0342' '\x0345')-titleMapping c s = Yield (toTitle c) (CC s '\0' '\0')-foldMapping :: forall s. Char -> s -> Step (CC s) Char-{-# NOINLINE foldMapping #-}--- MICRO SIGN-foldMapping '\x00b5' s = Yield '\x03bc' (CC s '\x0000' '\x0000')--- LATIN SMALL LETTER SHARP S-foldMapping '\x00df' s = Yield '\x0073' (CC s '\x0073' '\x0000')--- LATIN CAPITAL LETTER I WITH DOT ABOVE-foldMapping '\x0130' s = Yield '\x0069' (CC s '\x0307' '\x0000')--- LATIN SMALL LETTER N PRECEDED BY APOSTROPHE-foldMapping '\x0149' s = Yield '\x02bc' (CC s '\x006e' '\x0000')--- LATIN SMALL LETTER LONG S-foldMapping '\x017f' s = Yield '\x0073' (CC s '\x0000' '\x0000')--- LATIN SMALL LETTER J WITH CARON-foldMapping '\x01f0' s = Yield '\x006a' (CC s '\x030c' '\x0000')--- COMBINING GREEK YPOGEGRAMMENI-foldMapping '\x0345' s = Yield '\x03b9' (CC s '\x0000' '\x0000')--- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS-foldMapping '\x0390' s = Yield '\x03b9' (CC s '\x0308' '\x0301')--- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS-foldMapping '\x03b0' s = Yield '\x03c5' (CC s '\x0308' '\x0301')--- GREEK SMALL LETTER FINAL SIGMA-foldMapping '\x03c2' s = Yield '\x03c3' (CC s '\x0000' '\x0000')--- GREEK BETA SYMBOL-foldMapping '\x03d0' s = Yield '\x03b2' (CC s '\x0000' '\x0000')--- GREEK THETA SYMBOL-foldMapping '\x03d1' s = Yield '\x03b8' (CC s '\x0000' '\x0000')--- GREEK PHI SYMBOL-foldMapping '\x03d5' s = Yield '\x03c6' (CC s '\x0000' '\x0000')--- GREEK PI SYMBOL-foldMapping '\x03d6' s = Yield '\x03c0' (CC s '\x0000' '\x0000')--- GREEK KAPPA SYMBOL-foldMapping '\x03f0' s = Yield '\x03ba' (CC s '\x0000' '\x0000')--- GREEK RHO SYMBOL-foldMapping '\x03f1' s = Yield '\x03c1' (CC s '\x0000' '\x0000')--- GREEK LUNATE EPSILON SYMBOL-foldMapping '\x03f5' s = Yield '\x03b5' (CC s '\x0000' '\x0000')--- ARMENIAN SMALL LIGATURE ECH YIWN-foldMapping '\x0587' s = Yield '\x0565' (CC s '\x0582' '\x0000')--- CHEROKEE SMALL LETTER YE-foldMapping '\x13f8' s = Yield '\x13f0' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER YI-foldMapping '\x13f9' s = Yield '\x13f1' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER YO-foldMapping '\x13fa' s = Yield '\x13f2' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER YU-foldMapping '\x13fb' s = Yield '\x13f3' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER YV-foldMapping '\x13fc' s = Yield '\x13f4' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER MV-foldMapping '\x13fd' s = Yield '\x13f5' (CC s '\x0000' '\x0000')--- CYRILLIC SMALL LETTER ROUNDED VE-foldMapping '\x1c80' s = Yield '\x0432' (CC s '\x0000' '\x0000')--- CYRILLIC SMALL LETTER LONG-LEGGED DE-foldMapping '\x1c81' s = Yield '\x0434' (CC s '\x0000' '\x0000')--- CYRILLIC SMALL LETTER NARROW O-foldMapping '\x1c82' s = Yield '\x043e' (CC s '\x0000' '\x0000')--- CYRILLIC SMALL LETTER WIDE ES-foldMapping '\x1c83' s = Yield '\x0441' (CC s '\x0000' '\x0000')--- CYRILLIC SMALL LETTER TALL TE-foldMapping '\x1c84' s = Yield '\x0442' (CC s '\x0000' '\x0000')--- CYRILLIC SMALL LETTER THREE-LEGGED TE-foldMapping '\x1c85' s = Yield '\x0442' (CC s '\x0000' '\x0000')--- CYRILLIC SMALL LETTER TALL HARD SIGN-foldMapping '\x1c86' s = Yield '\x044a' (CC s '\x0000' '\x0000')--- CYRILLIC SMALL LETTER TALL YAT-foldMapping '\x1c87' s = Yield '\x0463' (CC s '\x0000' '\x0000')--- CYRILLIC SMALL LETTER UNBLENDED UK-foldMapping '\x1c88' s = Yield '\xa64b' (CC s '\x0000' '\x0000')--- LATIN SMALL LETTER H WITH LINE BELOW-foldMapping '\x1e96' s = Yield '\x0068' (CC s '\x0331' '\x0000')--- LATIN SMALL LETTER T WITH DIAERESIS-foldMapping '\x1e97' s = Yield '\x0074' (CC s '\x0308' '\x0000')--- LATIN SMALL LETTER W WITH RING ABOVE-foldMapping '\x1e98' s = Yield '\x0077' (CC s '\x030a' '\x0000')--- LATIN SMALL LETTER Y WITH RING ABOVE-foldMapping '\x1e99' s = Yield '\x0079' (CC s '\x030a' '\x0000')--- LATIN SMALL LETTER A WITH RIGHT HALF RING-foldMapping '\x1e9a' s = Yield '\x0061' (CC s '\x02be' '\x0000')--- LATIN SMALL LETTER LONG S WITH DOT ABOVE-foldMapping '\x1e9b' s = Yield '\x1e61' (CC s '\x0000' '\x0000')--- LATIN CAPITAL LETTER SHARP S-foldMapping '\x1e9e' s = Yield '\x0073' (CC s '\x0073' '\x0000')--- GREEK SMALL LETTER UPSILON WITH PSILI-foldMapping '\x1f50' s = Yield '\x03c5' (CC s '\x0313' '\x0000')--- GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA-foldMapping '\x1f52' s = Yield '\x03c5' (CC s '\x0313' '\x0300')--- GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA-foldMapping '\x1f54' s = Yield '\x03c5' (CC s '\x0313' '\x0301')--- GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI-foldMapping '\x1f56' s = Yield '\x03c5' (CC s '\x0313' '\x0342')--- GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI-foldMapping '\x1f80' s = Yield '\x1f00' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI-foldMapping '\x1f81' s = Yield '\x1f01' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI-foldMapping '\x1f82' s = Yield '\x1f02' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI-foldMapping '\x1f83' s = Yield '\x1f03' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI-foldMapping '\x1f84' s = Yield '\x1f04' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI-foldMapping '\x1f85' s = Yield '\x1f05' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI-foldMapping '\x1f86' s = Yield '\x1f06' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI-foldMapping '\x1f87' s = Yield '\x1f07' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI-foldMapping '\x1f88' s = Yield '\x1f00' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI-foldMapping '\x1f89' s = Yield '\x1f01' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI-foldMapping '\x1f8a' s = Yield '\x1f02' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI-foldMapping '\x1f8b' s = Yield '\x1f03' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI-foldMapping '\x1f8c' s = Yield '\x1f04' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI-foldMapping '\x1f8d' s = Yield '\x1f05' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI-foldMapping '\x1f8e' s = Yield '\x1f06' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI-foldMapping '\x1f8f' s = Yield '\x1f07' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI-foldMapping '\x1f90' s = Yield '\x1f20' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI-foldMapping '\x1f91' s = Yield '\x1f21' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI-foldMapping '\x1f92' s = Yield '\x1f22' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI-foldMapping '\x1f93' s = Yield '\x1f23' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI-foldMapping '\x1f94' s = Yield '\x1f24' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI-foldMapping '\x1f95' s = Yield '\x1f25' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI-foldMapping '\x1f96' s = Yield '\x1f26' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI-foldMapping '\x1f97' s = Yield '\x1f27' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI-foldMapping '\x1f98' s = Yield '\x1f20' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI-foldMapping '\x1f99' s = Yield '\x1f21' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI-foldMapping '\x1f9a' s = Yield '\x1f22' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI-foldMapping '\x1f9b' s = Yield '\x1f23' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI-foldMapping '\x1f9c' s = Yield '\x1f24' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI-foldMapping '\x1f9d' s = Yield '\x1f25' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI-foldMapping '\x1f9e' s = Yield '\x1f26' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI-foldMapping '\x1f9f' s = Yield '\x1f27' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI-foldMapping '\x1fa0' s = Yield '\x1f60' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI-foldMapping '\x1fa1' s = Yield '\x1f61' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI-foldMapping '\x1fa2' s = Yield '\x1f62' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI-foldMapping '\x1fa3' s = Yield '\x1f63' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI-foldMapping '\x1fa4' s = Yield '\x1f64' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI-foldMapping '\x1fa5' s = Yield '\x1f65' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI-foldMapping '\x1fa6' s = Yield '\x1f66' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI-foldMapping '\x1fa7' s = Yield '\x1f67' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI-foldMapping '\x1fa8' s = Yield '\x1f60' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI-foldMapping '\x1fa9' s = Yield '\x1f61' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI-foldMapping '\x1faa' s = Yield '\x1f62' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI-foldMapping '\x1fab' s = Yield '\x1f63' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI-foldMapping '\x1fac' s = Yield '\x1f64' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI-foldMapping '\x1fad' s = Yield '\x1f65' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI-foldMapping '\x1fae' s = Yield '\x1f66' (CC s '\x03b9' '\x0000')--- GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI-foldMapping '\x1faf' s = Yield '\x1f67' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI-foldMapping '\x1fb2' s = Yield '\x1f70' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI-foldMapping '\x1fb3' s = Yield '\x03b1' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI-foldMapping '\x1fb4' s = Yield '\x03ac' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ALPHA WITH PERISPOMENI-foldMapping '\x1fb6' s = Yield '\x03b1' (CC s '\x0342' '\x0000')--- GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI-foldMapping '\x1fb7' s = Yield '\x03b1' (CC s '\x0342' '\x03b9')--- GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI-foldMapping '\x1fbc' s = Yield '\x03b1' (CC s '\x03b9' '\x0000')--- GREEK PROSGEGRAMMENI-foldMapping '\x1fbe' s = Yield '\x03b9' (CC s '\x0000' '\x0000')--- GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI-foldMapping '\x1fc2' s = Yield '\x1f74' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI-foldMapping '\x1fc3' s = Yield '\x03b7' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI-foldMapping '\x1fc4' s = Yield '\x03ae' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER ETA WITH PERISPOMENI-foldMapping '\x1fc6' s = Yield '\x03b7' (CC s '\x0342' '\x0000')--- GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI-foldMapping '\x1fc7' s = Yield '\x03b7' (CC s '\x0342' '\x03b9')--- GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI-foldMapping '\x1fcc' s = Yield '\x03b7' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA-foldMapping '\x1fd2' s = Yield '\x03b9' (CC s '\x0308' '\x0300')--- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA-foldMapping '\x1fd3' s = Yield '\x03b9' (CC s '\x0308' '\x0301')--- GREEK SMALL LETTER IOTA WITH PERISPOMENI-foldMapping '\x1fd6' s = Yield '\x03b9' (CC s '\x0342' '\x0000')--- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI-foldMapping '\x1fd7' s = Yield '\x03b9' (CC s '\x0308' '\x0342')--- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA-foldMapping '\x1fe2' s = Yield '\x03c5' (CC s '\x0308' '\x0300')--- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA-foldMapping '\x1fe3' s = Yield '\x03c5' (CC s '\x0308' '\x0301')--- GREEK SMALL LETTER RHO WITH PSILI-foldMapping '\x1fe4' s = Yield '\x03c1' (CC s '\x0313' '\x0000')--- GREEK SMALL LETTER UPSILON WITH PERISPOMENI-foldMapping '\x1fe6' s = Yield '\x03c5' (CC s '\x0342' '\x0000')--- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI-foldMapping '\x1fe7' s = Yield '\x03c5' (CC s '\x0308' '\x0342')--- GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI-foldMapping '\x1ff2' s = Yield '\x1f7c' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI-foldMapping '\x1ff3' s = Yield '\x03c9' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI-foldMapping '\x1ff4' s = Yield '\x03ce' (CC s '\x03b9' '\x0000')--- GREEK SMALL LETTER OMEGA WITH PERISPOMENI-foldMapping '\x1ff6' s = Yield '\x03c9' (CC s '\x0342' '\x0000')--- GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI-foldMapping '\x1ff7' s = Yield '\x03c9' (CC s '\x0342' '\x03b9')--- GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI-foldMapping '\x1ffc' s = Yield '\x03c9' (CC s '\x03b9' '\x0000')--- LATIN CAPITAL LETTER SMALL CAPITAL I-foldMapping '\xa7ae' s = Yield '\x026a' (CC s '\x0000' '\x0000')--- LATIN CAPITAL LETTER J WITH CROSSED-TAIL-foldMapping '\xa7b2' s = Yield '\x029d' (CC s '\x0000' '\x0000')--- LATIN CAPITAL LETTER CHI-foldMapping '\xa7b3' s = Yield '\xab53' (CC s '\x0000' '\x0000')--- LATIN CAPITAL LETTER BETA-foldMapping '\xa7b4' s = Yield '\xa7b5' (CC s '\x0000' '\x0000')--- LATIN CAPITAL LETTER OMEGA-foldMapping '\xa7b6' s = Yield '\xa7b7' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER A-foldMapping '\xab70' s = Yield '\x13a0' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER E-foldMapping '\xab71' s = Yield '\x13a1' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER I-foldMapping '\xab72' s = Yield '\x13a2' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER O-foldMapping '\xab73' s = Yield '\x13a3' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER U-foldMapping '\xab74' s = Yield '\x13a4' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER V-foldMapping '\xab75' s = Yield '\x13a5' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER GA-foldMapping '\xab76' s = Yield '\x13a6' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER KA-foldMapping '\xab77' s = Yield '\x13a7' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER GE-foldMapping '\xab78' s = Yield '\x13a8' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER GI-foldMapping '\xab79' s = Yield '\x13a9' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER GO-foldMapping '\xab7a' s = Yield '\x13aa' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER GU-foldMapping '\xab7b' s = Yield '\x13ab' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER GV-foldMapping '\xab7c' s = Yield '\x13ac' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER HA-foldMapping '\xab7d' s = Yield '\x13ad' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER HE-foldMapping '\xab7e' s = Yield '\x13ae' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER HI-foldMapping '\xab7f' s = Yield '\x13af' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER HO-foldMapping '\xab80' s = Yield '\x13b0' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER HU-foldMapping '\xab81' s = Yield '\x13b1' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER HV-foldMapping '\xab82' s = Yield '\x13b2' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER LA-foldMapping '\xab83' s = Yield '\x13b3' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER LE-foldMapping '\xab84' s = Yield '\x13b4' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER LI-foldMapping '\xab85' s = Yield '\x13b5' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER LO-foldMapping '\xab86' s = Yield '\x13b6' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER LU-foldMapping '\xab87' s = Yield '\x13b7' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER LV-foldMapping '\xab88' s = Yield '\x13b8' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER MA-foldMapping '\xab89' s = Yield '\x13b9' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER ME-foldMapping '\xab8a' s = Yield '\x13ba' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER MI-foldMapping '\xab8b' s = Yield '\x13bb' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER MO-foldMapping '\xab8c' s = Yield '\x13bc' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER MU-foldMapping '\xab8d' s = Yield '\x13bd' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER NA-foldMapping '\xab8e' s = Yield '\x13be' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER HNA-foldMapping '\xab8f' s = Yield '\x13bf' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER NAH-foldMapping '\xab90' s = Yield '\x13c0' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER NE-foldMapping '\xab91' s = Yield '\x13c1' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER NI-foldMapping '\xab92' s = Yield '\x13c2' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER NO-foldMapping '\xab93' s = Yield '\x13c3' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER NU-foldMapping '\xab94' s = Yield '\x13c4' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER NV-foldMapping '\xab95' s = Yield '\x13c5' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER QUA-foldMapping '\xab96' s = Yield '\x13c6' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER QUE-foldMapping '\xab97' s = Yield '\x13c7' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER QUI-foldMapping '\xab98' s = Yield '\x13c8' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER QUO-foldMapping '\xab99' s = Yield '\x13c9' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER QUU-foldMapping '\xab9a' s = Yield '\x13ca' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER QUV-foldMapping '\xab9b' s = Yield '\x13cb' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER SA-foldMapping '\xab9c' s = Yield '\x13cc' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER S-foldMapping '\xab9d' s = Yield '\x13cd' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER SE-foldMapping '\xab9e' s = Yield '\x13ce' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER SI-foldMapping '\xab9f' s = Yield '\x13cf' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER SO-foldMapping '\xaba0' s = Yield '\x13d0' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER SU-foldMapping '\xaba1' s = Yield '\x13d1' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER SV-foldMapping '\xaba2' s = Yield '\x13d2' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER DA-foldMapping '\xaba3' s = Yield '\x13d3' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER TA-foldMapping '\xaba4' s = Yield '\x13d4' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER DE-foldMapping '\xaba5' s = Yield '\x13d5' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER TE-foldMapping '\xaba6' s = Yield '\x13d6' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER DI-foldMapping '\xaba7' s = Yield '\x13d7' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER TI-foldMapping '\xaba8' s = Yield '\x13d8' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER DO-foldMapping '\xaba9' s = Yield '\x13d9' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER DU-foldMapping '\xabaa' s = Yield '\x13da' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER DV-foldMapping '\xabab' s = Yield '\x13db' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER DLA-foldMapping '\xabac' s = Yield '\x13dc' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER TLA-foldMapping '\xabad' s = Yield '\x13dd' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER TLE-foldMapping '\xabae' s = Yield '\x13de' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER TLI-foldMapping '\xabaf' s = Yield '\x13df' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER TLO-foldMapping '\xabb0' s = Yield '\x13e0' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER TLU-foldMapping '\xabb1' s = Yield '\x13e1' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER TLV-foldMapping '\xabb2' s = Yield '\x13e2' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER TSA-foldMapping '\xabb3' s = Yield '\x13e3' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER TSE-foldMapping '\xabb4' s = Yield '\x13e4' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER TSI-foldMapping '\xabb5' s = Yield '\x13e5' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER TSO-foldMapping '\xabb6' s = Yield '\x13e6' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER TSU-foldMapping '\xabb7' s = Yield '\x13e7' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER TSV-foldMapping '\xabb8' s = Yield '\x13e8' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER WA-foldMapping '\xabb9' s = Yield '\x13e9' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER WE-foldMapping '\xabba' s = Yield '\x13ea' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER WI-foldMapping '\xabbb' s = Yield '\x13eb' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER WO-foldMapping '\xabbc' s = Yield '\x13ec' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER WU-foldMapping '\xabbd' s = Yield '\x13ed' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER WV-foldMapping '\xabbe' s = Yield '\x13ee' (CC s '\x0000' '\x0000')--- CHEROKEE SMALL LETTER YA-foldMapping '\xabbf' s = Yield '\x13ef' (CC s '\x0000' '\x0000')--- LATIN SMALL LIGATURE FF-foldMapping '\xfb00' s = Yield '\x0066' (CC s '\x0066' '\x0000')--- LATIN SMALL LIGATURE FI-foldMapping '\xfb01' s = Yield '\x0066' (CC s '\x0069' '\x0000')--- LATIN SMALL LIGATURE FL-foldMapping '\xfb02' s = Yield '\x0066' (CC s '\x006c' '\x0000')--- LATIN SMALL LIGATURE FFI-foldMapping '\xfb03' s = Yield '\x0066' (CC s '\x0066' '\x0069')--- LATIN SMALL LIGATURE FFL-foldMapping '\xfb04' s = Yield '\x0066' (CC s '\x0066' '\x006c')--- LATIN SMALL LIGATURE LONG S T-foldMapping '\xfb05' s = Yield '\x0073' (CC s '\x0074' '\x0000')--- LATIN SMALL LIGATURE ST-foldMapping '\xfb06' s = Yield '\x0073' (CC s '\x0074' '\x0000')--- ARMENIAN SMALL LIGATURE MEN NOW-foldMapping '\xfb13' s = Yield '\x0574' (CC s '\x0576' '\x0000')--- ARMENIAN SMALL LIGATURE MEN ECH-foldMapping '\xfb14' s = Yield '\x0574' (CC s '\x0565' '\x0000')--- ARMENIAN SMALL LIGATURE MEN INI-foldMapping '\xfb15' s = Yield '\x0574' (CC s '\x056b' '\x0000')--- ARMENIAN SMALL LIGATURE VEW NOW-foldMapping '\xfb16' s = Yield '\x057e' (CC s '\x0576' '\x0000')--- ARMENIAN SMALL LIGATURE MEN XEH-foldMapping '\xfb17' s = Yield '\x0574' (CC s '\x056d' '\x0000')--- OSAGE CAPITAL LETTER A-foldMapping '\x104b0' s = Yield '\x104d8' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER AI-foldMapping '\x104b1' s = Yield '\x104d9' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER AIN-foldMapping '\x104b2' s = Yield '\x104da' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER AH-foldMapping '\x104b3' s = Yield '\x104db' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER BRA-foldMapping '\x104b4' s = Yield '\x104dc' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER CHA-foldMapping '\x104b5' s = Yield '\x104dd' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER EHCHA-foldMapping '\x104b6' s = Yield '\x104de' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER E-foldMapping '\x104b7' s = Yield '\x104df' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER EIN-foldMapping '\x104b8' s = Yield '\x104e0' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER HA-foldMapping '\x104b9' s = Yield '\x104e1' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER HYA-foldMapping '\x104ba' s = Yield '\x104e2' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER I-foldMapping '\x104bb' s = Yield '\x104e3' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER KA-foldMapping '\x104bc' s = Yield '\x104e4' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER EHKA-foldMapping '\x104bd' s = Yield '\x104e5' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER KYA-foldMapping '\x104be' s = Yield '\x104e6' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER LA-foldMapping '\x104bf' s = Yield '\x104e7' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER MA-foldMapping '\x104c0' s = Yield '\x104e8' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER NA-foldMapping '\x104c1' s = Yield '\x104e9' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER O-foldMapping '\x104c2' s = Yield '\x104ea' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER OIN-foldMapping '\x104c3' s = Yield '\x104eb' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER PA-foldMapping '\x104c4' s = Yield '\x104ec' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER EHPA-foldMapping '\x104c5' s = Yield '\x104ed' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER SA-foldMapping '\x104c6' s = Yield '\x104ee' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER SHA-foldMapping '\x104c7' s = Yield '\x104ef' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER TA-foldMapping '\x104c8' s = Yield '\x104f0' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER EHTA-foldMapping '\x104c9' s = Yield '\x104f1' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER TSA-foldMapping '\x104ca' s = Yield '\x104f2' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER EHTSA-foldMapping '\x104cb' s = Yield '\x104f3' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER TSHA-foldMapping '\x104cc' s = Yield '\x104f4' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER DHA-foldMapping '\x104cd' s = Yield '\x104f5' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER U-foldMapping '\x104ce' s = Yield '\x104f6' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER WA-foldMapping '\x104cf' s = Yield '\x104f7' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER KHA-foldMapping '\x104d0' s = Yield '\x104f8' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER GHA-foldMapping '\x104d1' s = Yield '\x104f9' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER ZA-foldMapping '\x104d2' s = Yield '\x104fa' (CC s '\x0000' '\x0000')--- OSAGE CAPITAL LETTER ZHA-foldMapping '\x104d3' s = Yield '\x104fb' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER A-foldMapping '\x10c80' s = Yield '\x10cc0' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER AA-foldMapping '\x10c81' s = Yield '\x10cc1' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER EB-foldMapping '\x10c82' s = Yield '\x10cc2' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER AMB-foldMapping '\x10c83' s = Yield '\x10cc3' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER EC-foldMapping '\x10c84' s = Yield '\x10cc4' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER ENC-foldMapping '\x10c85' s = Yield '\x10cc5' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER ECS-foldMapping '\x10c86' s = Yield '\x10cc6' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER ED-foldMapping '\x10c87' s = Yield '\x10cc7' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER AND-foldMapping '\x10c88' s = Yield '\x10cc8' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER E-foldMapping '\x10c89' s = Yield '\x10cc9' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER CLOSE E-foldMapping '\x10c8a' s = Yield '\x10cca' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER EE-foldMapping '\x10c8b' s = Yield '\x10ccb' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER EF-foldMapping '\x10c8c' s = Yield '\x10ccc' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER EG-foldMapping '\x10c8d' s = Yield '\x10ccd' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER EGY-foldMapping '\x10c8e' s = Yield '\x10cce' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER EH-foldMapping '\x10c8f' s = Yield '\x10ccf' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER I-foldMapping '\x10c90' s = Yield '\x10cd0' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER II-foldMapping '\x10c91' s = Yield '\x10cd1' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER EJ-foldMapping '\x10c92' s = Yield '\x10cd2' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER EK-foldMapping '\x10c93' s = Yield '\x10cd3' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER AK-foldMapping '\x10c94' s = Yield '\x10cd4' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER UNK-foldMapping '\x10c95' s = Yield '\x10cd5' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER EL-foldMapping '\x10c96' s = Yield '\x10cd6' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER ELY-foldMapping '\x10c97' s = Yield '\x10cd7' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER EM-foldMapping '\x10c98' s = Yield '\x10cd8' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER EN-foldMapping '\x10c99' s = Yield '\x10cd9' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER ENY-foldMapping '\x10c9a' s = Yield '\x10cda' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER O-foldMapping '\x10c9b' s = Yield '\x10cdb' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER OO-foldMapping '\x10c9c' s = Yield '\x10cdc' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG OE-foldMapping '\x10c9d' s = Yield '\x10cdd' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER RUDIMENTA OE-foldMapping '\x10c9e' s = Yield '\x10cde' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER OEE-foldMapping '\x10c9f' s = Yield '\x10cdf' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER EP-foldMapping '\x10ca0' s = Yield '\x10ce0' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER EMP-foldMapping '\x10ca1' s = Yield '\x10ce1' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER ER-foldMapping '\x10ca2' s = Yield '\x10ce2' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER SHORT ER-foldMapping '\x10ca3' s = Yield '\x10ce3' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER ES-foldMapping '\x10ca4' s = Yield '\x10ce4' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER ESZ-foldMapping '\x10ca5' s = Yield '\x10ce5' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER ET-foldMapping '\x10ca6' s = Yield '\x10ce6' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER ENT-foldMapping '\x10ca7' s = Yield '\x10ce7' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER ETY-foldMapping '\x10ca8' s = Yield '\x10ce8' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER ECH-foldMapping '\x10ca9' s = Yield '\x10ce9' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER U-foldMapping '\x10caa' s = Yield '\x10cea' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER UU-foldMapping '\x10cab' s = Yield '\x10ceb' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG UE-foldMapping '\x10cac' s = Yield '\x10cec' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER RUDIMENTA UE-foldMapping '\x10cad' s = Yield '\x10ced' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER EV-foldMapping '\x10cae' s = Yield '\x10cee' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER EZ-foldMapping '\x10caf' s = Yield '\x10cef' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER EZS-foldMapping '\x10cb0' s = Yield '\x10cf0' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER ENT-SHAPED SIGN-foldMapping '\x10cb1' s = Yield '\x10cf1' (CC s '\x0000' '\x0000')--- OLD HUNGARIAN CAPITAL LETTER US-foldMapping '\x10cb2' s = Yield '\x10cf2' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER ALIF-foldMapping '\x1e900' s = Yield '\x1e922' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER DAALI-foldMapping '\x1e901' s = Yield '\x1e923' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER LAAM-foldMapping '\x1e902' s = Yield '\x1e924' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER MIIM-foldMapping '\x1e903' s = Yield '\x1e925' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER BA-foldMapping '\x1e904' s = Yield '\x1e926' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER SINNYIIYHE-foldMapping '\x1e905' s = Yield '\x1e927' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER PE-foldMapping '\x1e906' s = Yield '\x1e928' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER BHE-foldMapping '\x1e907' s = Yield '\x1e929' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER RA-foldMapping '\x1e908' s = Yield '\x1e92a' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER E-foldMapping '\x1e909' s = Yield '\x1e92b' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER FA-foldMapping '\x1e90a' s = Yield '\x1e92c' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER I-foldMapping '\x1e90b' s = Yield '\x1e92d' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER O-foldMapping '\x1e90c' s = Yield '\x1e92e' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER DHA-foldMapping '\x1e90d' s = Yield '\x1e92f' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER YHE-foldMapping '\x1e90e' s = Yield '\x1e930' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER WAW-foldMapping '\x1e90f' s = Yield '\x1e931' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER NUN-foldMapping '\x1e910' s = Yield '\x1e932' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER KAF-foldMapping '\x1e911' s = Yield '\x1e933' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER YA-foldMapping '\x1e912' s = Yield '\x1e934' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER U-foldMapping '\x1e913' s = Yield '\x1e935' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER JIIM-foldMapping '\x1e914' s = Yield '\x1e936' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER CHI-foldMapping '\x1e915' s = Yield '\x1e937' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER HA-foldMapping '\x1e916' s = Yield '\x1e938' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER QAAF-foldMapping '\x1e917' s = Yield '\x1e939' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER GA-foldMapping '\x1e918' s = Yield '\x1e93a' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER NYA-foldMapping '\x1e919' s = Yield '\x1e93b' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER TU-foldMapping '\x1e91a' s = Yield '\x1e93c' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER NHA-foldMapping '\x1e91b' s = Yield '\x1e93d' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER VA-foldMapping '\x1e91c' s = Yield '\x1e93e' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER KHA-foldMapping '\x1e91d' s = Yield '\x1e93f' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER GBE-foldMapping '\x1e91e' s = Yield '\x1e940' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER ZAL-foldMapping '\x1e91f' s = Yield '\x1e941' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER KPO-foldMapping '\x1e920' s = Yield '\x1e942' (CC s '\x0000' '\x0000')--- ADLAM CAPITAL LETTER SHA-foldMapping '\x1e921' s = Yield '\x1e943' (CC s '\x0000' '\x0000')-foldMapping c s = Yield (toLower c) (CC s '\0' '\0')
− Data/Text/Internal/Fusion/Common.hs
@@ -1,949 +0,0 @@-{-# LANGUAGE BangPatterns, MagicHash, Rank2Types #-}--- |--- Module      : Data.Text.Internal.Fusion.Common--- Copyright   : (c) Bryan O'Sullivan 2009, 2012------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : GHC------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ Common stream fusion functionality for text.--module Data.Text.Internal.Fusion.Common-    (-    -- * Creation and elimination-      singleton-    , streamList-    , unstreamList-    , streamCString#--    -- * Basic interface-    , cons-    , snoc-    , append-    , head-    , uncons-    , last-    , tail-    , init-    , null-    , lengthI-    , compareLengthI-    , isSingleton--    -- * Transformations-    , map-    , intercalate-    , intersperse--    -- ** Case conversion-    -- $case-    , toCaseFold-    , toLower-    , toTitle-    , toUpper--    -- ** Justification-    , justifyLeftI--    -- * Folds-    , foldl-    , foldl'-    , foldl1-    , foldl1'-    , foldr-    , foldr1--    -- ** Special folds-    , concat-    , concatMap-    , any-    , all-    , maximum-    , minimum--    -- * Construction-    -- ** Scans-    , scanl--    -- ** Generation and unfolding-    , replicateCharI-    , replicateI-    , unfoldr-    , unfoldrNI--    -- * Substrings-    -- ** Breaking strings-    , take-    , drop-    , takeWhile-    , dropWhile--    -- * Predicates-    , isPrefixOf--    -- * Searching-    , elem-    , filter--    -- * Indexing-    , findBy-    , indexI-    , findIndexI-    , countCharI--    -- * Zipping and unzipping-    , zipWith-    ) where--import Prelude (Bool(..), Char, Eq(..), Int, Integral, Maybe(..),-                Ord(..), Ordering(..), String, (.), ($), (+), (-), (*), (++),-                (&&), fromIntegral, otherwise)-import qualified Data.List as L-import qualified Prelude as P-import Data.Bits (shiftL)-import Data.Char (isLetter, isSpace)-import Data.Int (Int64)-import Data.Text.Internal.Fusion.Types-import Data.Text.Internal.Fusion.CaseMapping (foldMapping, lowerMapping, titleMapping,-                                     upperMapping)-import Data.Text.Internal.Fusion.Size-import GHC.Prim (Addr#, chr#, indexCharOffAddr#, ord#)-import GHC.Types (Char(..), Int(..))--singleton :: Char -> Stream Char-singleton c = Stream next False (codePointsSize 1)-    where next False = Yield c True-          next True  = Done-{-# INLINE [0] singleton #-}--streamList :: [a] -> Stream a-{-# INLINE [0] streamList #-}-streamList s  = Stream next s unknownSize-    where next []       = Done-          next (x:xs)   = Yield x xs--unstreamList :: Stream a -> [a]-unstreamList (Stream next s0 _len) = unfold s0-    where unfold !s = case next s of-                        Done       -> []-                        Skip s'    -> unfold s'-                        Yield x s' -> x : unfold s'-{-# INLINE [0] unstreamList #-}--{-# RULES "STREAM streamList/unstreamList fusion" forall s. streamList (unstreamList s) = s #-}---- | Stream the UTF-8-like packed encoding used by GHC to represent--- constant strings in generated code.------ This encoding uses the byte sequence "\xc0\x80" to represent NUL,--- and the string is NUL-terminated.-streamCString# :: Addr# -> Stream Char-streamCString# addr = Stream step 0 unknownSize-  where-    step !i-        | b == 0    = Done-        | b <= 0x7f = Yield (C# b#) (i+1)-        | b <= 0xdf = let !c = chr $ ((b-0xc0) `shiftL` 6) + next 1-                      in Yield c (i+2)-        | b <= 0xef = let !c = chr $ ((b-0xe0) `shiftL` 12) +-                                      (next 1  `shiftL` 6) +-                                       next 2-                      in Yield c (i+3)-        | otherwise = let !c = chr $ ((b-0xf0) `shiftL` 18) +-                                      (next 1  `shiftL` 12) +-                                      (next 2  `shiftL` 6) +-                                       next 3-                      in Yield c (i+4)-      where b      = I# (ord# b#)-            next n = I# (ord# (at# (i+n))) - 0x80-            !b#    = at# i-    at# (I# i#) = indexCharOffAddr# addr i#-    chr (I# i#) = C# (chr# i#)-{-# INLINE [0] streamCString# #-}---- ------------------------------------------------------------------------------- * Basic stream functions--data C s = C0 !s-         | C1 !s---- | /O(n)/ Adds a character to the front of a Stream Char.-cons :: Char -> Stream Char -> Stream Char-cons !w (Stream next0 s0 len) = Stream next (C1 s0) (len + codePointsSize 1)-    where-      next (C1 s) = Yield w (C0 s)-      next (C0 s) = case next0 s of-                          Done -> Done-                          Skip s' -> Skip (C0 s')-                          Yield x s' -> Yield x (C0 s')-{-# INLINE [0] cons #-}--data Snoc a = N-            | J !a---- | /O(n)/ Adds a character to the end of a stream.-snoc :: Stream Char -> Char -> Stream Char-snoc (Stream next0 xs0 len) w = Stream next (J xs0) (len + codePointsSize 1)-  where-    next (J xs) = case next0 xs of-      Done        -> Yield w N-      Skip xs'    -> Skip    (J xs')-      Yield x xs' -> Yield x (J xs')-    next N = Done-{-# INLINE [0] snoc #-}--data E l r = L !l-           | R !r---- | /O(n)/ Appends one Stream to the other.-append :: Stream Char -> Stream Char -> Stream Char-append (Stream next0 s01 len1) (Stream next1 s02 len2) =-    Stream next (L s01) (len1 + len2)-    where-      next (L s1) = case next0 s1 of-                         Done        -> Skip    (R s02)-                         Skip s1'    -> Skip    (L s1')-                         Yield x s1' -> Yield x (L s1')-      next (R s2) = case next1 s2 of-                          Done        -> Done-                          Skip s2'    -> Skip    (R s2')-                          Yield x s2' -> Yield x (R s2')-{-# INLINE [0] append #-}---- | /O(1)/ Returns the first character of a Text, which must be non-empty.--- Subject to array fusion.-head :: Stream Char -> Char-head (Stream next s0 _len) = loop_head s0-    where-      loop_head !s = case next s of-                      Yield x _ -> x-                      Skip s'   -> loop_head s'-                      Done      -> head_empty-{-# INLINE [0] head #-}--head_empty :: a-head_empty = streamError "head" "Empty stream"-{-# NOINLINE head_empty #-}---- | /O(1)/ Returns the first character and remainder of a 'Stream--- Char', or 'Nothing' if empty.  Subject to array fusion.-uncons :: Stream Char -> Maybe (Char, Stream Char)-uncons (Stream next s0 len) = loop_uncons s0-    where-      loop_uncons !s = case next s of-                         Yield x s1 -> Just (x, Stream next s1 (len - codePointsSize 1))-                         Skip s'    -> loop_uncons s'-                         Done       -> Nothing-{-# INLINE [0] uncons #-}---- | /O(n)/ Returns the last character of a 'Stream Char', which must--- be non-empty.-last :: Stream Char -> Char-last (Stream next s0 _len) = loop0_last s0-    where-      loop0_last !s = case next s of-                        Done       -> emptyError "last"-                        Skip s'    -> loop0_last  s'-                        Yield x s' -> loop_last x s'-      loop_last !x !s = case next s of-                         Done        -> x-                         Skip s'     -> loop_last x  s'-                         Yield x' s' -> loop_last x' s'-{-# INLINE[0] last #-}---- | /O(1)/ Returns all characters after the head of a Stream Char, which must--- be non-empty.-tail :: Stream Char -> Stream Char-tail (Stream next0 s0 len) = Stream next (C0 s0) (len - codePointsSize 1)-    where-      next (C0 s) = case next0 s of-                      Done       -> emptyError "tail"-                      Skip s'    -> Skip (C0 s')-                      Yield _ s' -> Skip (C1 s')-      next (C1 s) = case next0 s of-                      Done       -> Done-                      Skip s'    -> Skip    (C1 s')-                      Yield x s' -> Yield x (C1 s')-{-# INLINE [0] tail #-}--data Init s = Init0 !s-            | Init1 {-# UNPACK #-} !Char !s---- | /O(1)/ Returns all but the last character of a Stream Char, which--- must be non-empty.-init :: Stream Char -> Stream Char-init (Stream next0 s0 len) = Stream next (Init0 s0) (len - codePointsSize 1)-    where-      next (Init0 s) = case next0 s of-                         Done       -> emptyError "init"-                         Skip s'    -> Skip (Init0 s')-                         Yield x s' -> Skip (Init1 x s')-      next (Init1 x s)  = case next0 s of-                            Done        -> Done-                            Skip s'     -> Skip    (Init1 x s')-                            Yield x' s' -> Yield x (Init1 x' s')-{-# INLINE [0] init #-}---- | /O(1)/ Tests whether a Stream Char is empty or not.-null :: Stream Char -> Bool-null (Stream next s0 _len) = loop_null s0-    where-      loop_null !s = case next s of-                       Done      -> True-                       Yield _ _ -> False-                       Skip s'   -> loop_null s'-{-# INLINE[0] null #-}---- | /O(n)/ Returns the number of characters in a string.-lengthI :: Integral a => Stream Char -> a-lengthI (Stream next s0 _len) = loop_length 0 s0-    where-      loop_length !z s  = case next s of-                           Done       -> z-                           Skip    s' -> loop_length z s'-                           Yield _ s' -> loop_length (z + 1) s'-{-# INLINE[0] lengthI #-}---- | /O(n)/ Compares the count of characters in a string to a number.--- Subject to fusion.------ This function gives the same answer as comparing against the result--- of 'lengthI', but can short circuit if the count of characters is--- greater than the number or if the stream can't possibly be as long--- as the number supplied, and hence be more efficient.-compareLengthI :: Integral a => Stream Char -> a -> Ordering-compareLengthI (Stream next s0 len) n-    -- Note that @len@ tracks code units whereas we want to compare the length-    -- in code points. Specifically, a stream with hint @len@ may consist of-    -- anywhere from @len/2@ to @len@ code points.-  | Just r <- compareSize len n' = r-  | otherwise = loop_cmp 0 s0-    where-      n' = codePointsSize $ fromIntegral n-      loop_cmp !z s  = case next s of-                         Done       -> compare z n-                         Skip    s' -> loop_cmp z s'-                         Yield _ s' | z > n     -> GT-                                    | otherwise -> loop_cmp (z + 1) s'-{-# INLINE[0] compareLengthI #-}---- | /O(n)/ Indicate whether a string contains exactly one element.-isSingleton :: Stream Char -> Bool-isSingleton (Stream next s0 _len) = loop 0 s0-    where-      loop !z s  = case next s of-                     Done            -> z == (1::Int)-                     Skip    s'      -> loop z s'-                     Yield _ s'-                         | z >= 1    -> False-                         | otherwise -> loop (z+1) s'-{-# INLINE[0] isSingleton #-}---- ------------------------------------------------------------------------------- * Stream transformations---- | /O(n)/ 'map' @f @xs is the Stream Char obtained by applying @f@--- to each element of @xs@.-map :: (Char -> Char) -> Stream Char -> Stream Char-map f (Stream next0 s0 len) = Stream next s0 len-    where-      next !s = case next0 s of-                  Done       -> Done-                  Skip s'    -> Skip s'-                  Yield x s' -> Yield (f x) s'-{-# INLINE [0] map #-}--{-#-  RULES "STREAM map/map fusion" forall f g s.-     map f (map g s) = map (\x -> f (g x)) s- #-}--data I s = I1 !s-         | I2 !s {-# UNPACK #-} !Char-         | I3 !s---- | /O(n)/ Take a character and place it between each of the--- characters of a 'Stream Char'.-intersperse :: Char -> Stream Char -> Stream Char-intersperse c (Stream next0 s0 len) = Stream next (I1 s0) (len + unknownSize)-    where-      next (I1 s) = case next0 s of-        Done       -> Done-        Skip s'    -> Skip (I1 s')-        Yield x s' -> Skip (I2 s' x)-      next (I2 s x)  = Yield x (I3 s)-      next (I3 s) = case next0 s of-        Done       -> Done-        Skip s'    -> Skip    (I3 s')-        Yield x s' -> Yield c (I2 s' x)-{-# INLINE [0] intersperse #-}---- ------------------------------------------------------------------------------- ** Case conversions (folds)---- $case------ With Unicode text, it is incorrect to use combinators like @map--- toUpper@ to case convert each character of a string individually.--- Instead, use the whole-string case conversion functions from this--- module.  For correctness in different writing systems, these--- functions may map one input character to two or three output--- characters.---- | Map a 'Stream' through the given case-mapping function.-caseConvert :: (forall s. Char -> s -> Step (CC s) Char)-            -> Stream Char -> Stream Char-caseConvert remap (Stream next0 s0 len) =-    Stream next (CC s0 '\0' '\0') (len `unionSize` (3*len))-  where-    next (CC s '\0' _) =-        case next0 s of-          Done       -> Done-          Skip s'    -> Skip (CC s' '\0' '\0')-          Yield c s' -> remap c s'-    next (CC s a b)  =  Yield a (CC s b '\0')---- | /O(n)/ Convert a string to folded case.  This function is mainly--- useful for performing caseless (or case insensitive) string--- comparisons.------ A string @x@ is a caseless match for a string @y@ if and only if:------ @toCaseFold x == toCaseFold y@------ The result string may be longer than the input string, and may--- differ from applying 'toLower' to the input string.  For instance,--- the Armenian small ligature men now (U+FB13) is case folded to the--- bigram men now (U+0574 U+0576), while the micro sign (U+00B5) is--- case folded to the Greek small letter letter mu (U+03BC) instead of--- itself.-toCaseFold :: Stream Char -> Stream Char-toCaseFold = caseConvert foldMapping-{-# INLINE [0] toCaseFold #-}---- | /O(n)/ Convert a string to upper case, using simple case--- conversion.  The result string may be longer than the input string.--- For instance, the German eszett (U+00DF) maps to the two-letter--- sequence SS.-toUpper :: Stream Char -> Stream Char-toUpper = caseConvert upperMapping-{-# INLINE [0] toUpper #-}---- | /O(n)/ Convert a string to lower case, using simple case--- conversion.  The result string may be longer than the input string.--- For instance, the Latin capital letter I with dot above (U+0130)--- maps to the sequence Latin small letter i (U+0069) followed by--- combining dot above (U+0307).-toLower :: Stream Char -> Stream Char-toLower = caseConvert lowerMapping-{-# INLINE [0] toLower #-}---- | /O(n)/ Convert a string to title case, using simple case--- conversion.------ The first letter of the input is converted to title case, as is--- every subsequent letter that immediately follows a non-letter.--- Every letter that immediately follows another letter is converted--- to lower case.------ The result string may be longer than the input string. For example,--- the Latin small ligature &#xfb02; (U+FB02) is converted to the--- sequence Latin capital letter F (U+0046) followed by Latin small--- letter l (U+006C).------ /Note/: this function does not take language or culture specific--- rules into account. For instance, in English, different style--- guides disagree on whether the book name \"The Hill of the Red--- Fox\" is correctly title cased&#x2014;but this function will--- capitalize /every/ word.-toTitle :: Stream Char -> Stream Char-toTitle (Stream next0 s0 len) = Stream next (CC (False :*: s0) '\0' '\0') (len + unknownSize)-  where-    next (CC (letter :*: s) '\0' _) =-      case next0 s of-        Done            -> Done-        Skip s'         -> Skip (CC (letter :*: s') '\0' '\0')-        Yield c s'-          | nonSpace    -> if letter-                           then lowerMapping c (nonSpace :*: s')-                           else titleMapping c (letter' :*: s')-          | otherwise   -> Yield c (CC (letter' :*: s') '\0' '\0')-          where nonSpace = P.not (isSpace c)-                letter'  = isLetter c-    next (CC s a b)      = Yield a (CC s b '\0')-{-# INLINE [0] toTitle #-}--data Justify i s = Just1 !i !s-                 | Just2 !i !s--justifyLeftI :: Integral a => a -> Char -> Stream Char -> Stream Char-justifyLeftI k c (Stream next0 s0 len) =-    Stream next (Just1 0 s0) (larger (fromIntegral k * charSize c + len) len)-  where-    next (Just1 n s) =-        case next0 s of-          Done       -> next (Just2 n s)-          Skip s'    -> Skip (Just1 n s')-          Yield x s' -> Yield x (Just1 (n+1) s')-    next (Just2 n s)-        | n < k       = Yield c (Just2 (n+1) s)-        | otherwise   = Done-    {-# INLINE next #-}-{-# INLINE [0] justifyLeftI #-}---- ------------------------------------------------------------------------------- * Reducing Streams (folds)---- | foldl, applied to a binary operator, a starting value (typically the--- left-identity of the operator), and a Stream, reduces the Stream using the--- binary operator, from left to right.-foldl :: (b -> Char -> b) -> b -> Stream Char -> b-foldl f z0 (Stream next s0 _len) = loop_foldl z0 s0-    where-      loop_foldl z !s = case next s of-                          Done -> z-                          Skip s' -> loop_foldl z s'-                          Yield x s' -> loop_foldl (f z x) s'-{-# INLINE [0] foldl #-}---- | A strict version of foldl.-foldl' :: (b -> Char -> b) -> b -> Stream Char -> b-foldl' f z0 (Stream next s0 _len) = loop_foldl' z0 s0-    where-      loop_foldl' !z !s = case next s of-                            Done -> z-                            Skip s' -> loop_foldl' z s'-                            Yield x s' -> loop_foldl' (f z x) s'-{-# INLINE [0] foldl' #-}---- | foldl1 is a variant of foldl that has no starting value argument,--- and thus must be applied to non-empty Streams.-foldl1 :: (Char -> Char -> Char) -> Stream Char -> Char-foldl1 f (Stream next s0 _len) = loop0_foldl1 s0-    where-      loop0_foldl1 !s = case next s of-                          Skip s' -> loop0_foldl1 s'-                          Yield x s' -> loop_foldl1 x s'-                          Done -> emptyError "foldl1"-      loop_foldl1 z !s = case next s of-                           Done -> z-                           Skip s' -> loop_foldl1 z s'-                           Yield x s' -> loop_foldl1 (f z x) s'-{-# INLINE [0] foldl1 #-}---- | A strict version of foldl1.-foldl1' :: (Char -> Char -> Char) -> Stream Char -> Char-foldl1' f (Stream next s0 _len) = loop0_foldl1' s0-    where-      loop0_foldl1' !s = case next s of-                           Skip s' -> loop0_foldl1' s'-                           Yield x s' -> loop_foldl1' x s'-                           Done -> emptyError "foldl1"-      loop_foldl1' !z !s = case next s of-                             Done -> z-                             Skip s' -> loop_foldl1' z s'-                             Yield x s' -> loop_foldl1' (f z x) s'-{-# INLINE [0] foldl1' #-}---- | 'foldr', applied to a binary operator, a starting value (typically the--- right-identity of the operator), and a stream, reduces the stream using the--- binary operator, from right to left.-foldr :: (Char -> b -> b) -> b -> Stream Char -> b-foldr f z (Stream next s0 _len) = loop_foldr s0-    where-      loop_foldr !s = case next s of-                        Done -> z-                        Skip s' -> loop_foldr s'-                        Yield x s' -> f x (loop_foldr s')-{-# INLINE [0] foldr #-}---- | foldr1 is a variant of 'foldr' that has no starting value argument,--- and thus must be applied to non-empty streams.--- Subject to array fusion.-foldr1 :: (Char -> Char -> Char) -> Stream Char -> Char-foldr1 f (Stream next s0 _len) = loop0_foldr1 s0-  where-    loop0_foldr1 !s = case next s of-      Done       -> emptyError "foldr1"-      Skip    s' -> loop0_foldr1  s'-      Yield x s' -> loop_foldr1 x s'--    loop_foldr1 x !s = case next s of-      Done        -> x-      Skip     s' -> loop_foldr1 x s'-      Yield x' s' -> f x (loop_foldr1 x' s')-{-# INLINE [0] foldr1 #-}--intercalate :: Stream Char -> [Stream Char] -> Stream Char-intercalate s = concat . (L.intersperse s)-{-# INLINE [0] intercalate #-}---- ------------------------------------------------------------------------------- ** Special folds---- | /O(n)/ Concatenate a list of streams. Subject to array fusion.-concat :: [Stream Char] -> Stream Char-concat = L.foldr append empty-{-# INLINE [0] concat #-}---- | Map a function over a stream that results in a stream and concatenate the--- results.-concatMap :: (Char -> Stream Char) -> Stream Char -> Stream Char-concatMap f = foldr (append . f) empty-{-# INLINE [0] concatMap #-}---- | /O(n)/ any @p @xs determines if any character in the stream--- @xs@ satisfies the predicate @p@.-any :: (Char -> Bool) -> Stream Char -> Bool-any p (Stream next0 s0 _len) = loop_any s0-    where-      loop_any !s = case next0 s of-                      Done                   -> False-                      Skip s'                -> loop_any s'-                      Yield x s' | p x       -> True-                                 | otherwise -> loop_any s'-{-# INLINE [0] any #-}---- | /O(n)/ all @p @xs determines if all characters in the 'Text'--- @xs@ satisfy the predicate @p@.-all :: (Char -> Bool) -> Stream Char -> Bool-all p (Stream next0 s0 _len) = loop_all s0-    where-      loop_all !s = case next0 s of-                      Done                   -> True-                      Skip s'                -> loop_all s'-                      Yield x s' | p x       -> loop_all s'-                                 | otherwise -> False-{-# INLINE [0] all #-}---- | /O(n)/ maximum returns the maximum value from a stream, which must be--- non-empty.-maximum :: Stream Char -> Char-maximum (Stream next0 s0 _len) = loop0_maximum s0-    where-      loop0_maximum !s   = case next0 s of-                             Done       -> emptyError "maximum"-                             Skip s'    -> loop0_maximum s'-                             Yield x s' -> loop_maximum x s'-      loop_maximum !z !s = case next0 s of-                             Done            -> z-                             Skip s'         -> loop_maximum z s'-                             Yield x s'-                                 | x > z     -> loop_maximum x s'-                                 | otherwise -> loop_maximum z s'-{-# INLINE [0] maximum #-}---- | /O(n)/ minimum returns the minimum value from a 'Text', which must be--- non-empty.-minimum :: Stream Char -> Char-minimum (Stream next0 s0 _len) = loop0_minimum s0-    where-      loop0_minimum !s   = case next0 s of-                             Done       -> emptyError "minimum"-                             Skip s'    -> loop0_minimum s'-                             Yield x s' -> loop_minimum x s'-      loop_minimum !z !s = case next0 s of-                             Done            -> z-                             Skip s'         -> loop_minimum z s'-                             Yield x s'-                                 | x < z     -> loop_minimum x s'-                                 | otherwise -> loop_minimum z s'-{-# INLINE [0] minimum #-}---- -------------------------------------------------------------------------------- * Building streams--scanl :: (Char -> Char -> Char) -> Char -> Stream Char -> Stream Char-scanl f z0 (Stream next0 s0 len) = Stream next (Scan1 z0 s0) (len+1) -- HINT maybe too low-  where-    {-# INLINE next #-}-    next (Scan1 z s) = Yield z (Scan2 z s)-    next (Scan2 z s) = case next0 s of-                         Yield x s' -> let !x' = f z x-                                       in Yield x' (Scan2 x' s')-                         Skip s'    -> Skip (Scan2 z s')-                         Done       -> Done-{-# INLINE [0] scanl #-}---- -------------------------------------------------------------------------------- ** Generating and unfolding streams--replicateCharI :: Integral a => a -> Char -> Stream Char-replicateCharI !n !c-    | n < 0     = empty-    | otherwise = Stream next 0 (fromIntegral n) -- HINT maybe too low-  where-    next !i | i >= n    = Done-            | otherwise = Yield c (i + 1)-{-# INLINE [0] replicateCharI #-}--data RI s = RI !s {-# UNPACK #-} !Int64--replicateI :: Int64 -> Stream Char -> Stream Char-replicateI n (Stream next0 s0 len) =-    Stream next (RI s0 0) (fromIntegral (max 0 n) * len)-  where-    next (RI s k)-        | k >= n = Done-        | otherwise = case next0 s of-                        Done       -> Skip    (RI s0 (k+1))-                        Skip s'    -> Skip    (RI s' k)-                        Yield x s' -> Yield x (RI s' k)-{-# INLINE [0] replicateI #-}---- | /O(n)/, where @n@ is the length of the result. The unfoldr function--- is analogous to the List 'unfoldr'. unfoldr builds a stream--- from a seed value. The function takes the element and returns--- Nothing if it is done producing the stream or returns Just--- (a,b), in which case, a is the next Char in the string, and b is--- the seed value for further production.-unfoldr :: (a -> Maybe (Char,a)) -> a -> Stream Char-unfoldr f s0 = Stream next s0 unknownSize-    where-      {-# INLINE next #-}-      next !s = case f s of-                 Nothing      -> Done-                 Just (w, s') -> Yield w s'-{-# INLINE [0] unfoldr #-}---- | /O(n)/ Like 'unfoldr', 'unfoldrNI' builds a stream from a seed--- value. However, the length of the result is limited by the--- first argument to 'unfoldrNI'. This function is more efficient than--- 'unfoldr' when the length of the result is known.-unfoldrNI :: Integral a => a -> (b -> Maybe (Char,b)) -> b -> Stream Char-unfoldrNI n f s0 | n <  0    = empty-                 | otherwise = Stream next (0 :*: s0) (maxSize $ fromIntegral (n*2))-    where-      {-# INLINE next #-}-      next (z :*: s) = case f s of-          Nothing                  -> Done-          Just (w, s') | z >= n    -> Done-                       | otherwise -> Yield w ((z + 1) :*: s')-{-# INLINE unfoldrNI #-}------------------------------------------------------------------------------------  * Substreams---- | /O(n)/ @'take' n@, applied to a stream, returns the prefix of the--- stream of length @n@, or the stream itself if @n@ is greater than the--- length of the stream.-take :: Integral a => a -> Stream Char -> Stream Char-take n0 (Stream next0 s0 len) =-    Stream next (n0' :*: s0) (smaller len (codePointsSize $ fromIntegral n0'))-    where-      n0' = max n0 0--      {-# INLINE next #-}-      next (n :*: s) | n <= 0    = Done-                     | otherwise = case next0 s of-                                     Done -> Done-                                     Skip s' -> Skip (n :*: s')-                                     Yield x s' -> Yield x ((n-1) :*: s')-{-# INLINE [0] take #-}--data Drop a s = NS !s-              | JS !a !s---- | /O(n)/ @'drop' n@, applied to a stream, returns the suffix of the--- stream after the first @n@ characters, or the empty stream if @n@--- is greater than the length of the stream.-drop :: Integral a => a -> Stream Char -> Stream Char-drop n0 (Stream next0 s0 len) =-    Stream next (JS n0' s0) (len - codePointsSize (fromIntegral n0'))-  where-    n0' = max n0 0--    {-# INLINE next #-}-    next (JS n s)-      | n <= 0    = Skip (NS s)-      | otherwise = case next0 s of-          Done       -> Done-          Skip    s' -> Skip (JS n    s')-          Yield _ s' -> Skip (JS (n-1) s')-    next (NS s) = case next0 s of-      Done       -> Done-      Skip    s' -> Skip    (NS s')-      Yield x s' -> Yield x (NS s')-{-# INLINE [0] drop #-}---- | 'takeWhile', applied to a predicate @p@ and a stream, returns the--- longest prefix (possibly empty) of elements that satisfy @p@.-takeWhile :: (Char -> Bool) -> Stream Char -> Stream Char-takeWhile p (Stream next0 s0 len) = Stream next s0 (len - unknownSize)-    where-      {-# INLINE next #-}-      next !s = case next0 s of-                  Done    -> Done-                  Skip s' -> Skip s'-                  Yield x s' | p x       -> Yield x s'-                             | otherwise -> Done-{-# INLINE [0] takeWhile #-}---- | @'dropWhile' p xs@ returns the suffix remaining after @'takeWhile' p xs@.-dropWhile :: (Char -> Bool) -> Stream Char -> Stream Char-dropWhile p (Stream next0 s0 len) = Stream next (L s0) (len - unknownSize)-    where-    {-# INLINE next #-}-    next (L s)  = case next0 s of-      Done                   -> Done-      Skip    s'             -> Skip    (L s')-      Yield x s' | p x       -> Skip    (L s')-                 | otherwise -> Yield x (R s')-    next (R s) = case next0 s of-      Done       -> Done-      Skip    s' -> Skip    (R s')-      Yield x s' -> Yield x (R s')-{-# INLINE [0] dropWhile #-}---- | /O(n)/ The 'isPrefixOf' function takes two 'Stream's and returns--- 'True' iff the first is a prefix of the second.-isPrefixOf :: (Eq a) => Stream a -> Stream a -> Bool-isPrefixOf (Stream next1 s1 _) (Stream next2 s2 _) = loop (next1 s1) (next2 s2)-    where-      loop Done      _ = True-      loop _    Done = False-      loop (Skip s1')     (Skip s2')     = loop (next1 s1') (next2 s2')-      loop (Skip s1')     x2             = loop (next1 s1') x2-      loop x1             (Skip s2')     = loop x1          (next2 s2')-      loop (Yield x1 s1') (Yield x2 s2') = x1 == x2 &&-                                           loop (next1 s1') (next2 s2')-{-# INLINE [0] isPrefixOf #-}---- ------------------------------------------------------------------------------- * Searching------------------------------------------------------------------------------------ ** Searching by equality---- | /O(n)/ 'elem' is the stream membership predicate.-elem :: Char -> Stream Char -> Bool-elem w (Stream next s0 _len) = loop_elem s0-    where-      loop_elem !s = case next s of-                       Done -> False-                       Skip s' -> loop_elem s'-                       Yield x s' | x == w -> True-                                  | otherwise -> loop_elem s'-{-# INLINE [0] elem #-}------------------------------------------------------------------------------------ ** Searching with a predicate---- | /O(n)/ The 'findBy' function takes a predicate and a stream,--- and returns the first element in matching the predicate, or 'Nothing'--- if there is no such element.--findBy :: (Char -> Bool) -> Stream Char -> Maybe Char-findBy p (Stream next s0 _len) = loop_find s0-    where-      loop_find !s = case next s of-                       Done -> Nothing-                       Skip s' -> loop_find s'-                       Yield x s' | p x -> Just x-                                  | otherwise -> loop_find s'-{-# INLINE [0] findBy #-}---- | /O(n)/ Stream index (subscript) operator, starting from 0.-indexI :: Integral a => Stream Char -> a -> Char-indexI (Stream next s0 _len) n0-  | n0 < 0    = streamError "index" "Negative index"-  | otherwise = loop_index n0 s0-  where-    loop_index !n !s = case next s of-      Done                   -> streamError "index" "Index too large"-      Skip    s'             -> loop_index  n    s'-      Yield x s' | n == 0    -> x-                 | otherwise -> loop_index (n-1) s'-{-# INLINE [0] indexI #-}---- | /O(n)/ 'filter', applied to a predicate and a stream,--- returns a stream containing those characters that satisfy the--- predicate.-filter :: (Char -> Bool) -> Stream Char -> Stream Char-filter p (Stream next0 s0 len) =-    Stream next s0 (len - unknownSize) -- HINT maybe too high-  where-    next !s = case next0 s of-                Done                   -> Done-                Skip    s'             -> Skip    s'-                Yield x s' | p x       -> Yield x s'-                           | otherwise -> Skip    s'-{-# INLINE [0] filter #-}--{-# RULES-  "STREAM filter/filter fusion" forall p q s.-  filter p (filter q s) = filter (\x -> q x && p x) s-  #-}---- | The 'findIndexI' function takes a predicate and a stream and--- returns the index of the first element in the stream satisfying the--- predicate.-findIndexI :: Integral a => (Char -> Bool) -> Stream Char -> Maybe a-findIndexI p s = case findIndicesI p s of-                  (i:_) -> Just i-                  _     -> Nothing-{-# INLINE [0] findIndexI #-}---- | The 'findIndicesI' function takes a predicate and a stream and--- returns all indices of the elements in the stream satisfying the--- predicate.-findIndicesI :: Integral a => (Char -> Bool) -> Stream Char -> [a]-findIndicesI p (Stream next s0 _len) = loop_findIndex 0 s0-  where-    loop_findIndex !i !s = case next s of-      Done                   -> []-      Skip    s'             -> loop_findIndex i     s' -- hmm. not caught by QC-      Yield x s' | p x       -> i : loop_findIndex (i+1) s'-                 | otherwise -> loop_findIndex (i+1) s'-{-# INLINE [0] findIndicesI #-}------------------------------------------------------------------------------------ * Zipping---- | Strict triple.-data Zip a b m = Z1 !a !b-               | Z2 !a !b !m---- | zipWith generalises 'zip' by zipping with the function given as--- the first argument, instead of a tupling function.-zipWith :: (a -> a -> b) -> Stream a -> Stream a -> Stream b-zipWith f (Stream next0 sa0 len1) (Stream next1 sb0 len2) =-    Stream next (Z1 sa0 sb0) (smaller len1 len2)-    where-      next (Z1 sa sb) = case next0 sa of-                          Done -> Done-                          Skip sa' -> Skip (Z1 sa' sb)-                          Yield a sa' -> Skip (Z2 sa' sb a)--      next (Z2 sa' sb a) = case next1 sb of-                             Done -> Done-                             Skip sb' -> Skip (Z2 sa' sb' a)-                             Yield b sb' -> Yield (f a b) (Z1 sa' sb')-{-# INLINE [0] zipWith #-}---- | /O(n)/ The 'countCharI' function returns the number of times the--- query element appears in the given stream.-countCharI :: Integral a => Char -> Stream Char -> a-countCharI a (Stream next s0 _len) = loop 0 s0-  where-    loop !i !s = case next s of-      Done                   -> i-      Skip    s'             -> loop i s'-      Yield x s' | a == x    -> loop (i+1) s'-                 | otherwise -> loop i s'-{-# INLINE [0] countCharI #-}--streamError :: String -> String -> a-streamError func msg = P.error $ "Data.Text.Internal.Fusion.Common." ++ func ++ ": " ++ msg--emptyError :: String -> a-emptyError func = internalError func "Empty input"--internalError :: String -> a-internalError func = streamError func "Internal error"
− Data/Text/Internal/Fusion/Size.hs
@@ -1,187 +0,0 @@-{-# LANGUAGE CPP #-}-{-# OPTIONS_GHC -fno-warn-missing-methods #-}--- |--- Module      : Data.Text.Internal.Fusion.Internal--- Copyright   : (c) Roman Leshchinskiy 2008,---               (c) Bryan O'Sullivan 2009------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : portable------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ Size hints.--module Data.Text.Internal.Fusion.Size-    (-      Size-      -- * Sizes-    , exactSize-    , maxSize-    , betweenSize-    , unknownSize-    , unionSize-    , charSize-    , codePointsSize-      -- * Querying sizes-    , exactly-    , smaller-    , larger-    , upperBound-    , lowerBound-    , compareSize-    , isEmpty-    ) where--import Data.Char (ord)-import Data.Text.Internal (mul)-#if defined(ASSERTS)-import Control.Exception (assert)-#endif---- | A size in UTF-16 code units.-data Size = Between {-# UNPACK #-} !Int {-# UNPACK #-} !Int -- ^ Lower and upper bounds on size.-          | Unknown                                         -- ^ Unknown size.-            deriving (Eq, Show)--exactly :: Size -> Maybe Int-exactly (Between na nb) | na == nb = Just na-exactly _ = Nothing-{-# INLINE exactly #-}---- | The 'Size' of the given code point.-charSize :: Char -> Size-charSize c-  | ord c < 0x10000 = exactSize 1-  | otherwise       = exactSize 2---- | The 'Size' of @n@ code points.-codePointsSize :: Int -> Size-codePointsSize n =-#if defined(ASSERTS)-    assert (n >= 0)-#endif-    Between n (2*n)-{-# INLINE codePointsSize #-}--exactSize :: Int -> Size-exactSize n =-#if defined(ASSERTS)-    assert (n >= 0)-#endif-    Between n n-{-# INLINE exactSize #-}--maxSize :: Int -> Size-maxSize n =-#if defined(ASSERTS)-    assert (n >= 0)-#endif-    Between 0 n-{-# INLINE maxSize #-}--betweenSize :: Int -> Int -> Size-betweenSize m n =-#if defined(ASSERTS)-    assert (m >= 0)-    assert (n >= m)-#endif-    Between m n-{-# INLINE betweenSize #-}--unionSize :: Size -> Size -> Size-unionSize (Between a b) (Between c d) = Between (min a c) (max b d)-unionSize _ _ = Unknown--unknownSize :: Size-unknownSize = Unknown-{-# INLINE unknownSize #-}--instance Num Size where-    (+) = addSize-    (-) = subtractSize-    (*) = mulSize--    fromInteger = f where f = exactSize . fromInteger-                          {-# INLINE f #-}--add :: Int -> Int -> Int-add m n | mn >=   0 = mn-        | otherwise = overflowError-  where mn = m + n-{-# INLINE add #-}--addSize :: Size -> Size -> Size-addSize (Between ma mb) (Between na nb) = Between (add ma na) (add mb nb)-addSize _               _               = Unknown-{-# INLINE addSize #-}--subtractSize :: Size -> Size -> Size-subtractSize (Between ma mb) (Between na nb) = Between (max (ma-nb) 0) (max (mb-na) 0)-subtractSize a@(Between 0 _) Unknown         = a-subtractSize (Between _ mb)  Unknown         = Between 0 mb-subtractSize _               _               = Unknown-{-# INLINE subtractSize #-}--mulSize :: Size -> Size -> Size-mulSize (Between ma mb) (Between na nb) = Between (mul ma na) (mul mb nb)-mulSize _               _               = Unknown-{-# INLINE mulSize #-}---- | Minimum of two size hints.-smaller :: Size -> Size -> Size-smaller a@(Between ma mb) b@(Between na nb)-    | mb <= na  = a-    | nb <= ma  = b-    | otherwise = Between (ma `min` na) (mb `min` nb)-smaller a@(Between 0 _) Unknown         = a-smaller (Between _ mb)  Unknown         = Between 0 mb-smaller Unknown         b@(Between 0 _) = b-smaller Unknown         (Between _ nb)  = Between 0 nb-smaller Unknown         Unknown         = Unknown-{-# INLINE smaller #-}---- | Maximum of two size hints.-larger :: Size -> Size -> Size-larger a@(Between ma mb) b@(Between na nb)-    | ma >= nb  = a-    | na >= mb  = b-    | otherwise = Between (ma `max` na) (mb `max` nb)-larger _ _ = Unknown-{-# INLINE larger #-}---- | Compute the maximum size from a size hint, if possible.-upperBound :: Int -> Size -> Int-upperBound _ (Between _ n) = n-upperBound k _             = k-{-# INLINE upperBound #-}---- | Compute the maximum size from a size hint, if possible.-lowerBound :: Int -> Size -> Int-lowerBound _ (Between n _) = n-lowerBound k _             = k-{-# INLINE lowerBound #-}---- | Determine the ordering relationship between two 'Size's, or 'Nothing' in--- the indeterminate case.-compareSize :: Size -> Size -> Maybe Ordering-compareSize (Between ma mb) (Between na nb)-  | mb < na            = Just LT-  | ma > nb            = Just GT-  | ma == mb-  , ma == na-  , ma == nb           = Just EQ-compareSize _ _        = Nothing---isEmpty :: Size -> Bool-isEmpty (Between _ n) = n <= 0-isEmpty _             = False-{-# INLINE isEmpty #-}--overflowError :: Int-overflowError = error "Data.Text.Internal.Fusion.Size: size overflow"
− Data/Text/Internal/Fusion/Types.hs
@@ -1,122 +0,0 @@-{-# LANGUAGE BangPatterns, ExistentialQuantification #-}--- |--- Module      : Data.Text.Internal.Fusion.Types--- Copyright   : (c) Tom Harper 2008-2009,---               (c) Bryan O'Sullivan 2009,---               (c) Duncan Coutts 2009,---               (c) Jasper Van der Jeugt 2011------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : GHC------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ Core stream fusion functionality for text.--module Data.Text.Internal.Fusion.Types-    (-      CC(..)-    , PairS(..)-    , Scan(..)-    , RS(..)-    , Step(..)-    , Stream(..)-    , empty-    ) where--import Data.Text.Internal.Fusion.Size-import Data.Word (Word8)---- | Specialised tuple for case conversion.-data CC s = CC !s {-# UNPACK #-} !Char {-# UNPACK #-} !Char---- | Restreaming state.-data RS s-    = RS0 !s-    | RS1 !s {-# UNPACK #-} !Word8-    | RS2 !s {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8-    | RS3 !s {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8---- | Strict pair.-data PairS a b = !a :*: !b-                 -- deriving (Eq, Ord, Show)-infixl 2 :*:---- | An intermediate result in a scan.-data Scan s = Scan1 {-# UNPACK #-} !Char !s-            | Scan2 {-# UNPACK #-} !Char !s---- | Intermediate result in a processing pipeline.-data Step s a = Done-              | Skip !s-              | Yield !a !s--{--instance (Show a) => Show (Step s a)-    where show Done        = "Done"-          show (Skip _)    = "Skip"-          show (Yield x _) = "Yield " ++ show x--}--instance (Eq a) => Eq (Stream a) where-    (==) = eq--instance (Ord a) => Ord (Stream a) where-    compare = cmp---- The length hint in a Stream has two roles.  If its value is zero,--- we trust it, and treat the stream as empty.  Otherwise, we treat it--- as a hint: it should usually be accurate, so we use it when--- unstreaming to decide what size array to allocate.  However, the--- unstreaming functions must be able to cope with the hint being too--- small or too large.------ The size hint tries to track the UTF-16 code units in a stream,--- but often counts the number of code points instead.  It can easily--- undercount if, for instance, a transformed stream contains astral--- plane code points (those above 0x10000).--data Stream a =-    forall s. Stream-    (s -> Step s a)             -- stepper function-    !s                          -- current state-    !Size                       -- size hint in code units---- | /O(n)/ Determines if two streams are equal.-eq :: (Eq a) => Stream a -> Stream a -> Bool-eq (Stream next1 s1 _) (Stream next2 s2 _) = loop (next1 s1) (next2 s2)-    where-      loop Done Done                     = True-      loop (Skip s1')     (Skip s2')     = loop (next1 s1') (next2 s2')-      loop (Skip s1')     x2             = loop (next1 s1') x2-      loop x1             (Skip s2')     = loop x1          (next2 s2')-      loop Done _                        = False-      loop _    Done                     = False-      loop (Yield x1 s1') (Yield x2 s2') = x1 == x2 &&-                                           loop (next1 s1') (next2 s2')-{-# INLINE [0] eq #-}--cmp :: (Ord a) => Stream a -> Stream a -> Ordering-cmp (Stream next1 s1 _) (Stream next2 s2 _) = loop (next1 s1) (next2 s2)-    where-      loop Done Done                     = EQ-      loop (Skip s1')     (Skip s2')     = loop (next1 s1') (next2 s2')-      loop (Skip s1')     x2             = loop (next1 s1') x2-      loop x1             (Skip s2')     = loop x1          (next2 s2')-      loop Done _                        = LT-      loop _    Done                     = GT-      loop (Yield x1 s1') (Yield x2 s2') =-          case compare x1 x2 of-            EQ    -> loop (next1 s1') (next2 s2')-            other -> other-{-# INLINE [0] cmp #-}---- | The empty stream.-empty :: Stream a-empty = Stream next () 0-    where next _ = Done-{-# INLINE [0] empty #-}
− Data/Text/Internal/IO.hs
@@ -1,166 +0,0 @@-{-# LANGUAGE BangPatterns, RecordWildCards #-}--- |--- Module      : Data.Text.Internal.IO--- Copyright   : (c) 2009, 2010 Bryan O'Sullivan,---               (c) 2009 Simon Marlow--- License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : GHC------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ Low-level support for text I\/O.--module Data.Text.Internal.IO-    (-      hGetLineWith-    , readChunk-    ) where--import qualified Control.Exception as E-import Data.IORef (readIORef, writeIORef)-import Data.Text (Text)-import Data.Text.Internal.Fusion (unstream)-import Data.Text.Internal.Fusion.Types (Step(..), Stream(..))-import Data.Text.Internal.Fusion.Size (exactSize, maxSize)-import Data.Text.Unsafe (inlinePerformIO)-import Foreign.Storable (peekElemOff)-import GHC.IO.Buffer (Buffer(..), CharBuffer, RawCharBuffer, bufferAdjustL,-                      bufferElems, charSize, isEmptyBuffer, readCharBuf,-                      withRawBuffer, writeCharBuf)-import GHC.IO.Handle.Internals (ioe_EOF, readTextDevice, wantReadableHandle_)-import GHC.IO.Handle.Types (Handle__(..), Newline(..))-import System.IO (Handle)-import System.IO.Error (isEOFError)-import qualified Data.Text as T---- | Read a single line of input from a handle, constructing a list of--- decoded chunks as we go.  When we're done, transform them into the--- destination type.-hGetLineWith :: ([Text] -> t) -> Handle -> IO t-hGetLineWith f h = wantReadableHandle_ "hGetLine" h go-  where-    go hh@Handle__{..} = readIORef haCharBuffer >>= fmap f . hGetLineLoop hh []--hGetLineLoop :: Handle__ -> [Text] -> CharBuffer -> IO [Text]-hGetLineLoop hh@Handle__{..} = go where- go ts buf@Buffer{ bufL=r0, bufR=w, bufRaw=raw0 } = do-  let findEOL raw r | r == w    = return (False, w)-                    | otherwise = do-        (c,r') <- readCharBuf raw r-        if c == '\n'-          then return (True, r)-          else findEOL raw r'-  (eol, off) <- findEOL raw0 r0-  (t,r') <- if haInputNL == CRLF-            then unpack_nl raw0 r0 off-            else do t <- unpack raw0 r0 off-                    return (t,off)-  if eol-    then do writeIORef haCharBuffer (bufferAdjustL (off+1) buf)-            return $ reverse (t:ts)-    else do-      let buf1 = bufferAdjustL r' buf-      maybe_buf <- maybeFillReadBuffer hh buf1-      case maybe_buf of-         -- Nothing indicates we caught an EOF, and we may have a-         -- partial line to return.-         Nothing -> do-              -- we reached EOF.  There might be a lone \r left-              -- in the buffer, so check for that and-              -- append it to the line if necessary.-              let pre | isEmptyBuffer buf1 = T.empty-                      | otherwise          = T.singleton '\r'-              writeIORef haCharBuffer buf1{ bufL=0, bufR=0 }-              let str = reverse . filter (not . T.null) $ pre:t:ts-              if null str-                then ioe_EOF-                else return str-         Just new_buf -> go (t:ts) new_buf---- This function is lifted almost verbatim from GHC.IO.Handle.Text.-maybeFillReadBuffer :: Handle__ -> CharBuffer -> IO (Maybe CharBuffer)-maybeFillReadBuffer handle_ buf-  = E.catch (Just `fmap` getSomeCharacters handle_ buf) $ \e ->-      if isEOFError e-      then return Nothing-      else ioError e--unpack :: RawCharBuffer -> Int -> Int -> IO Text-unpack !buf !r !w- | charSize /= 4 = sizeError "unpack"- | r >= w        = return T.empty- | otherwise     = withRawBuffer buf go- where-  go pbuf = return $! unstream (Stream next r (exactSize (w-r)))-   where-    next !i | i >= w    = Done-            | otherwise = Yield (ix i) (i+1)-    ix i = inlinePerformIO $ peekElemOff pbuf i--unpack_nl :: RawCharBuffer -> Int -> Int -> IO (Text, Int)-unpack_nl !buf !r !w- | charSize /= 4 = sizeError "unpack_nl"- | r >= w        = return (T.empty, 0)- | otherwise     = withRawBuffer buf $ go- where-  go pbuf = do-    let !t = unstream (Stream next r (maxSize (w-r)))-        w' = w - 1-    return $ if ix w' == '\r'-             then (t,w')-             else (t,w)-   where-    next !i | i >= w = Done-            | c == '\r' = let i' = i + 1-                          in if i' < w-                             then if ix i' == '\n'-                                  then Yield '\n' (i+2)-                                  else Yield '\n' i'-                             else Done-            | otherwise = Yield c (i+1)-            where c = ix i-    ix i = inlinePerformIO $ peekElemOff pbuf i---- This function is completely lifted from GHC.IO.Handle.Text.-getSomeCharacters :: Handle__ -> CharBuffer -> IO CharBuffer-getSomeCharacters handle_@Handle__{..} buf@Buffer{..} =-  case bufferElems buf of-    -- buffer empty: read some more-    0 -> {-# SCC "readTextDevice" #-} readTextDevice handle_ buf--    -- if the buffer has a single '\r' in it and we're doing newline-    -- translation: read some more-    1 | haInputNL == CRLF -> do-      (c,_) <- readCharBuf bufRaw bufL-      if c == '\r'-         then do -- shuffle the '\r' to the beginning.  This is only safe-                 -- if we're about to call readTextDevice, otherwise it-                 -- would mess up flushCharBuffer.-                 -- See [note Buffer Flushing], GHC.IO.Handle.Types-                 _ <- writeCharBuf bufRaw 0 '\r'-                 let buf' = buf{ bufL=0, bufR=1 }-                 readTextDevice handle_ buf'-         else do-                 return buf--    -- buffer has some chars in it already: just return it-    _otherwise -> {-# SCC "otherwise" #-} return buf---- | Read a single chunk of strict text from a buffer. Used by both--- the strict and lazy implementations of hGetContents.-readChunk :: Handle__ -> CharBuffer -> IO Text-readChunk hh@Handle__{..} buf = do-  buf'@Buffer{..} <- getSomeCharacters hh buf-  (t,r) <- if haInputNL == CRLF-           then unpack_nl bufRaw bufL bufR-           else do t <- unpack bufRaw bufL bufR-                   return (t,bufR)-  writeIORef haCharBuffer (bufferAdjustL r buf')-  return t--sizeError :: String -> a-sizeError loc = error $ "Data.Text.IO." ++ loc ++ ": bad internal buffer size"
− Data/Text/Internal/Lazy.hs
@@ -1,119 +0,0 @@-{-# LANGUAGE BangPatterns, DeriveDataTypeable #-}-{-# OPTIONS_HADDOCK not-home #-}---- |--- Module      : Data.Text.Internal.Lazy--- Copyright   : (c) 2009, 2010 Bryan O'Sullivan------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : GHC------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ A module containing private 'Text' internals. This exposes the--- 'Text' representation and low level construction functions.--- Modules which extend the 'Text' system may need to use this module.--module Data.Text.Internal.Lazy-    (-      Text(..)-    , chunk-    , empty-    , foldrChunks-    , foldlChunks-    -- * Data type invariant and abstraction functions--    -- $invariant-    , strictInvariant-    , lazyInvariant-    , showStructure--    -- * Chunk allocation sizes-    , defaultChunkSize-    , smallChunkSize-    , chunkOverhead-    ) where--import Data.Text ()-import Data.Text.Internal.Unsafe.Shift (shiftL)-import Data.Typeable (Typeable)-import Foreign.Storable (sizeOf)-import qualified Data.Text.Internal as T--data Text = Empty-          | Chunk {-# UNPACK #-} !T.Text Text-            deriving (Typeable)---- $invariant------ The data type invariant for lazy 'Text': Every 'Text' is either 'Empty' or--- consists of non-null 'T.Text's.  All functions must preserve this,--- and the QC properties must check this.---- | Check the invariant strictly.-strictInvariant :: Text -> Bool-strictInvariant Empty = True-strictInvariant x@(Chunk (T.Text _ _ len) cs)-    | len > 0   = strictInvariant cs-    | otherwise = error $ "Data.Text.Lazy: invariant violation: "-                  ++ showStructure x---- | Check the invariant lazily.-lazyInvariant :: Text -> Text-lazyInvariant Empty = Empty-lazyInvariant x@(Chunk c@(T.Text _ _ len) cs)-    | len > 0   = Chunk c (lazyInvariant cs)-    | otherwise = error $ "Data.Text.Lazy: invariant violation: "-                  ++ showStructure x---- | Display the internal structure of a lazy 'Text'.-showStructure :: Text -> String-showStructure Empty           = "Empty"-showStructure (Chunk t Empty) = "Chunk " ++ show t ++ " Empty"-showStructure (Chunk t ts)    =-    "Chunk " ++ show t ++ " (" ++ showStructure ts ++ ")"---- | Smart constructor for 'Chunk'. Guarantees the data type invariant.-chunk :: T.Text -> Text -> Text-{-# INLINE chunk #-}-chunk t@(T.Text _ _ len) ts | len == 0 = ts-                            | otherwise = Chunk t ts---- | Smart constructor for 'Empty'.-empty :: Text-{-# INLINE [0] empty #-}-empty = Empty---- | Consume the chunks of a lazy 'Text' with a natural right fold.-foldrChunks :: (T.Text -> a -> a) -> a -> Text -> a-foldrChunks f z = go-  where go Empty        = z-        go (Chunk c cs) = f c (go cs)-{-# INLINE foldrChunks #-}---- | Consume the chunks of a lazy 'Text' with a strict, tail-recursive,--- accumulating left fold.-foldlChunks :: (a -> T.Text -> a) -> a -> Text -> a-foldlChunks f z = go z-  where go !a Empty        = a-        go !a (Chunk c cs) = go (f a c) cs-{-# INLINE foldlChunks #-}---- | Currently set to 16 KiB, less the memory management overhead.-defaultChunkSize :: Int-defaultChunkSize = 16384 - chunkOverhead-{-# INLINE defaultChunkSize #-}---- | Currently set to 128 bytes, less the memory management overhead.-smallChunkSize :: Int-smallChunkSize = 128 - chunkOverhead-{-# INLINE smallChunkSize #-}---- | The memory management overhead. Currently this is tuned for GHC only.-chunkOverhead :: Int-chunkOverhead = sizeOf (undefined :: Int) `shiftL` 1-{-# INLINE chunkOverhead #-}
− Data/Text/Internal/Lazy/Encoding/Fusion.hs
@@ -1,324 +0,0 @@-{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}---- |--- Module      : Data.Text.Lazy.Encoding.Fusion--- Copyright   : (c) 2009, 2010 Bryan O'Sullivan------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : portable------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ Fusible 'Stream'-oriented functions for converting between lazy--- 'Text' and several common encodings.--module Data.Text.Internal.Lazy.Encoding.Fusion-    (-    -- * Streaming-    --  streamASCII-      streamUtf8-    , streamUtf16LE-    , streamUtf16BE-    , streamUtf32LE-    , streamUtf32BE--    -- * Unstreaming-    , unstream--    , module Data.Text.Internal.Encoding.Fusion.Common-    ) where--import Data.ByteString.Lazy.Internal (ByteString(..), defaultChunkSize)-import qualified Data.ByteString as B-import qualified Data.ByteString.Unsafe as B-import Data.Text.Internal.Encoding.Fusion.Common-import Data.Text.Encoding.Error-import Data.Text.Internal.Fusion (Step(..), Stream(..))-import Data.Text.Internal.Fusion.Size-import Data.Text.Internal.Unsafe.Char (unsafeChr, unsafeChr8, unsafeChr32)-import Data.Text.Internal.Unsafe.Shift (shiftL)-import Data.Word (Word8, Word16, Word32)-import qualified Data.Text.Internal.Encoding.Utf8 as U8-import qualified Data.Text.Internal.Encoding.Utf16 as U16-import qualified Data.Text.Internal.Encoding.Utf32 as U32-import Data.Text.Unsafe (unsafeDupablePerformIO)-import Foreign.ForeignPtr (withForeignPtr, ForeignPtr)-import Foreign.Storable (pokeByteOff)-import Data.ByteString.Internal (mallocByteString, memcpy)-#if defined(ASSERTS)-import Control.Exception (assert)-#endif-import qualified Data.ByteString.Internal as B--data S = S0-       | S1 {-# UNPACK #-} !Word8-       | S2 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8-       | S3 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8-       | S4 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8--data T = T !ByteString !S {-# UNPACK #-} !Int---- | /O(n)/ Convert a lazy 'ByteString' into a 'Stream Char', using--- UTF-8 encoding.-streamUtf8 :: OnDecodeError -> ByteString -> Stream Char-streamUtf8 onErr bs0 = Stream next (T bs0 S0 0) unknownSize-  where-    next (T bs@(Chunk ps _) S0 i)-      | i < len && U8.validate1 a =-          Yield (unsafeChr8 a)    (T bs S0 (i+1))-      | i + 1 < len && U8.validate2 a b =-          Yield (U8.chr2 a b)     (T bs S0 (i+2))-      | i + 2 < len && U8.validate3 a b c =-          Yield (U8.chr3 a b c)   (T bs S0 (i+3))-      | i + 3 < len && U8.validate4 a b c d =-          Yield (U8.chr4 a b c d) (T bs S0 (i+4))-      where len = B.length ps-            a = B.unsafeIndex ps i-            b = B.unsafeIndex ps (i+1)-            c = B.unsafeIndex ps (i+2)-            d = B.unsafeIndex ps (i+3)-    next st@(T bs s i) =-      case s of-        S1 a       | U8.validate1 a       -> Yield (unsafeChr8 a)    es-        S2 a b     | U8.validate2 a b     -> Yield (U8.chr2 a b)     es-        S3 a b c   | U8.validate3 a b c   -> Yield (U8.chr3 a b c)   es-        S4 a b c d | U8.validate4 a b c d -> Yield (U8.chr4 a b c d) es-        _ -> consume st-       where es = T bs S0 i-    consume (T bs@(Chunk ps rest) s i)-        | i >= B.length ps = consume (T rest s 0)-        | otherwise =-      case s of-        S0         -> next (T bs (S1 x)       (i+1))-        S1 a       -> next (T bs (S2 a x)     (i+1))-        S2 a b     -> next (T bs (S3 a b x)   (i+1))-        S3 a b c   -> next (T bs (S4 a b c x) (i+1))-        S4 a b c d -> decodeError "streamUtf8" "UTF-8" onErr (Just a)-                           (T bs (S3 b c d)   (i+1))-        where x = B.unsafeIndex ps i-    consume (T Empty S0 _) = Done-    consume st             = decodeError "streamUtf8" "UTF-8" onErr Nothing st-{-# INLINE [0] streamUtf8 #-}---- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using little--- endian UTF-16 encoding.-streamUtf16LE :: OnDecodeError -> ByteString -> Stream Char-streamUtf16LE onErr bs0 = Stream next (T bs0 S0 0) unknownSize-  where-    next (T bs@(Chunk ps _) S0 i)-      | i + 1 < len && U16.validate1 x1 =-          Yield (unsafeChr x1)         (T bs S0 (i+2))-      | i + 3 < len && U16.validate2 x1 x2 =-          Yield (U16.chr2 x1 x2)       (T bs S0 (i+4))-      where len = B.length ps-            x1   = c (idx  i)      (idx (i + 1))-            x2   = c (idx (i + 2)) (idx (i + 3))-            c w1 w2 = w1 + (w2 `shiftL` 8)-            idx = fromIntegral . B.unsafeIndex ps :: Int -> Word16-    next st@(T bs s i) =-      case s of-        S2 w1 w2       | U16.validate1 (c w1 w2)           ->-          Yield (unsafeChr (c w1 w2))   es-        S4 w1 w2 w3 w4 | U16.validate2 (c w1 w2) (c w3 w4) ->-          Yield (U16.chr2 (c w1 w2) (c w3 w4)) es-        _ -> consume st-       where es = T bs S0 i-             c :: Word8 -> Word8 -> Word16-             c w1 w2 = fromIntegral w1 + (fromIntegral w2 `shiftL` 8)-    consume (T bs@(Chunk ps rest) s i)-        | i >= B.length ps = consume (T rest s 0)-        | otherwise =-      case s of-        S0             -> next (T bs (S1 x)          (i+1))-        S1 w1          -> next (T bs (S2 w1 x)       (i+1))-        S2 w1 w2       -> next (T bs (S3 w1 w2 x)    (i+1))-        S3 w1 w2 w3    -> next (T bs (S4 w1 w2 w3 x) (i+1))-        S4 w1 w2 w3 w4 -> decodeError "streamUtf16LE" "UTF-16LE" onErr (Just w1)-                           (T bs (S3 w2 w3 w4)       (i+1))-        where x = B.unsafeIndex ps i-    consume (T Empty S0 _) = Done-    consume st             = decodeError "streamUtf16LE" "UTF-16LE" onErr Nothing st-{-# INLINE [0] streamUtf16LE #-}---- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using big--- endian UTF-16 encoding.-streamUtf16BE :: OnDecodeError -> ByteString -> Stream Char-streamUtf16BE onErr bs0 = Stream next (T bs0 S0 0) unknownSize-  where-    next (T bs@(Chunk ps _) S0 i)-      | i + 1 < len && U16.validate1 x1 =-          Yield (unsafeChr x1)         (T bs S0 (i+2))-      | i + 3 < len && U16.validate2 x1 x2 =-          Yield (U16.chr2 x1 x2)       (T bs S0 (i+4))-      where len = B.length ps-            x1   = c (idx  i)      (idx (i + 1))-            x2   = c (idx (i + 2)) (idx (i + 3))-            c w1 w2 = (w1 `shiftL` 8) + w2-            idx = fromIntegral . B.unsafeIndex ps :: Int -> Word16-    next st@(T bs s i) =-      case s of-        S2 w1 w2       | U16.validate1 (c w1 w2)           ->-          Yield (unsafeChr (c w1 w2))   es-        S4 w1 w2 w3 w4 | U16.validate2 (c w1 w2) (c w3 w4) ->-          Yield (U16.chr2 (c w1 w2) (c w3 w4)) es-        _ -> consume st-       where es = T bs S0 i-             c :: Word8 -> Word8 -> Word16-             c w1 w2 = (fromIntegral w1 `shiftL` 8) + fromIntegral w2-    consume (T bs@(Chunk ps rest) s i)-        | i >= B.length ps = consume (T rest s 0)-        | otherwise =-      case s of-        S0             -> next (T bs (S1 x)          (i+1))-        S1 w1          -> next (T bs (S2 w1 x)       (i+1))-        S2 w1 w2       -> next (T bs (S3 w1 w2 x)    (i+1))-        S3 w1 w2 w3    -> next (T bs (S4 w1 w2 w3 x) (i+1))-        S4 w1 w2 w3 w4 -> decodeError "streamUtf16BE" "UTF-16BE" onErr (Just w1)-                           (T bs (S3 w2 w3 w4)       (i+1))-        where x = B.unsafeIndex ps i-    consume (T Empty S0 _) = Done-    consume st             = decodeError "streamUtf16BE" "UTF-16BE" onErr Nothing st-{-# INLINE [0] streamUtf16BE #-}---- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using big--- endian UTF-32 encoding.-streamUtf32BE :: OnDecodeError -> ByteString -> Stream Char-streamUtf32BE onErr bs0 = Stream next (T bs0 S0 0) unknownSize-  where-    next (T bs@(Chunk ps _) S0 i)-      | i + 3 < len && U32.validate x =-          Yield (unsafeChr32 x)       (T bs S0 (i+4))-      where len = B.length ps-            x = shiftL x1 24 + shiftL x2 16 + shiftL x3 8 + x4-            x1    = idx i-            x2    = idx (i+1)-            x3    = idx (i+2)-            x4    = idx (i+3)-            idx = fromIntegral . B.unsafeIndex ps :: Int -> Word32-    next st@(T bs s i) =-      case s of-        S4 w1 w2 w3 w4 | U32.validate (c w1 w2 w3 w4) ->-          Yield (unsafeChr32 (c w1 w2 w3 w4)) es-        _ -> consume st-       where es = T bs S0 i-             c :: Word8 -> Word8 -> Word8 -> Word8 -> Word32-             c w1 w2 w3 w4 = shifted-              where-               shifted = shiftL x1 24 + shiftL x2 16 + shiftL x3 8 + x4-               x1 = fromIntegral w1-               x2 = fromIntegral w2-               x3 = fromIntegral w3-               x4 = fromIntegral w4-    consume (T bs@(Chunk ps rest) s i)-        | i >= B.length ps = consume (T rest s 0)-        | otherwise =-      case s of-        S0             -> next (T bs (S1 x)          (i+1))-        S1 w1          -> next (T bs (S2 w1 x)       (i+1))-        S2 w1 w2       -> next (T bs (S3 w1 w2 x)    (i+1))-        S3 w1 w2 w3    -> next (T bs (S4 w1 w2 w3 x) (i+1))-        S4 w1 w2 w3 w4 -> decodeError "streamUtf32BE" "UTF-32BE" onErr (Just w1)-                           (T bs (S3 w2 w3 w4)       (i+1))-        where x = B.unsafeIndex ps i-    consume (T Empty S0 _) = Done-    consume st             = decodeError "streamUtf32BE" "UTF-32BE" onErr Nothing st-{-# INLINE [0] streamUtf32BE #-}---- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using little--- endian UTF-32 encoding.-streamUtf32LE :: OnDecodeError -> ByteString -> Stream Char-streamUtf32LE onErr bs0 = Stream next (T bs0 S0 0) unknownSize-  where-    next (T bs@(Chunk ps _) S0 i)-      | i + 3 < len && U32.validate x =-          Yield (unsafeChr32 x)       (T bs S0 (i+4))-      where len = B.length ps-            x = shiftL x4 24 + shiftL x3 16 + shiftL x2 8 + x1-            x1    = idx i-            x2    = idx (i+1)-            x3    = idx (i+2)-            x4    = idx (i+3)-            idx = fromIntegral . B.unsafeIndex ps :: Int -> Word32-    next st@(T bs s i) =-      case s of-        S4 w1 w2 w3 w4 | U32.validate (c w1 w2 w3 w4) ->-          Yield (unsafeChr32 (c w1 w2 w3 w4)) es-        _ -> consume st-       where es = T bs S0 i-             c :: Word8 -> Word8 -> Word8 -> Word8 -> Word32-             c w1 w2 w3 w4 = shifted-              where-               shifted = shiftL x4 24 + shiftL x3 16 + shiftL x2 8 + x1-               x1 = fromIntegral w1-               x2 = fromIntegral w2-               x3 = fromIntegral w3-               x4 = fromIntegral w4-    consume (T bs@(Chunk ps rest) s i)-        | i >= B.length ps = consume (T rest s 0)-        | otherwise =-      case s of-        S0             -> next (T bs (S1 x)          (i+1))-        S1 w1          -> next (T bs (S2 w1 x)       (i+1))-        S2 w1 w2       -> next (T bs (S3 w1 w2 x)    (i+1))-        S3 w1 w2 w3    -> next (T bs (S4 w1 w2 w3 x) (i+1))-        S4 w1 w2 w3 w4 -> decodeError "streamUtf32LE" "UTF-32LE" onErr (Just w1)-                           (T bs (S3 w2 w3 w4)       (i+1))-        where x = B.unsafeIndex ps i-    consume (T Empty S0 _) = Done-    consume st             = decodeError "streamUtf32LE" "UTF-32LE" onErr Nothing st-{-# INLINE [0] streamUtf32LE #-}---- | /O(n)/ Convert a 'Stream' 'Word8' to a lazy 'ByteString'.-unstreamChunks :: Int -> Stream Word8 -> ByteString-unstreamChunks chunkSize (Stream next s0 len0) = chunk s0 (upperBound 4 len0)-  where chunk s1 len1 = unsafeDupablePerformIO $ do-          let len = max 4 (min len1 chunkSize)-          mallocByteString len >>= loop len 0 s1-          where-            loop !n !off !s fp = case next s of-                Done | off == 0 -> return Empty-                     | otherwise -> return $! Chunk (trimUp fp off) Empty-                Skip s' -> loop n off s' fp-                Yield x s'-                    | off == chunkSize -> do-                      let !newLen = n - off-                      return $! Chunk (trimUp fp off) (chunk s newLen)-                    | off == n -> realloc fp n off s' x-                    | otherwise -> do-                      withForeignPtr fp $ \p -> pokeByteOff p off x-                      loop n (off+1) s' fp-            {-# NOINLINE realloc #-}-            realloc fp n off s x = do-              let n' = min (n+n) chunkSize-              fp' <- copy0 fp n n'-              withForeignPtr fp' $ \p -> pokeByteOff p off x-              loop n' (off+1) s fp'-            trimUp fp off = B.PS fp 0 off-            copy0 :: ForeignPtr Word8 -> Int -> Int -> IO (ForeignPtr Word8)-            copy0 !src !srcLen !destLen =-#if defined(ASSERTS)-              assert (srcLen <= destLen) $-#endif-              do-                dest <- mallocByteString destLen-                withForeignPtr src  $ \src'  ->-                    withForeignPtr dest $ \dest' ->-                        memcpy dest' src' (fromIntegral srcLen)-                return dest---- | /O(n)/ Convert a 'Stream' 'Word8' to a lazy 'ByteString'.-unstream :: Stream Word8 -> ByteString-unstream = unstreamChunks defaultChunkSize--decodeError :: forall s. String -> String -> OnDecodeError -> Maybe Word8-            -> s -> Step s Char-decodeError func kind onErr mb i =-    case onErr desc mb of-      Nothing -> Skip i-      Just c  -> Yield c i-    where desc = "Data.Text.Lazy.Encoding.Fusion." ++ func ++ ": Invalid " ++-                 kind ++ " stream"
− Data/Text/Internal/Lazy/Fusion.hs
@@ -1,120 +0,0 @@-{-# LANGUAGE BangPatterns #-}--- |--- Module      : Data.Text.Lazy.Fusion--- Copyright   : (c) 2009, 2010 Bryan O'Sullivan------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : GHC------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ Core stream fusion functionality for text.--module Data.Text.Internal.Lazy.Fusion-    (-      stream-    , unstream-    , unstreamChunks-    , length-    , unfoldrN-    , index-    , countChar-    ) where--import Prelude hiding (length)-import qualified Data.Text.Internal.Fusion.Common as S-import Control.Monad.ST (runST)-import Data.Text.Internal.Fusion.Types-import Data.Text.Internal.Fusion.Size (isEmpty, unknownSize)-import Data.Text.Internal.Lazy-import qualified Data.Text.Internal as I-import qualified Data.Text.Array as A-import Data.Text.Internal.Unsafe.Char (unsafeWrite)-import Data.Text.Internal.Unsafe.Shift (shiftL)-import Data.Text.Unsafe (Iter(..), iter)-import Data.Int (Int64)--default(Int64)---- | /O(n)/ Convert a 'Text' into a 'Stream Char'.-stream :: Text -> Stream Char-stream text = Stream next (text :*: 0) unknownSize-  where-    next (Empty :*: _) = Done-    next (txt@(Chunk t@(I.Text _ _ len) ts) :*: i)-        | i >= len  = next (ts :*: 0)-        | otherwise = Yield c (txt :*: i+d)-        where Iter c d = iter t i-{-# INLINE [0] stream #-}---- | /O(n)/ Convert a 'Stream Char' into a 'Text', using the given--- chunk size.-unstreamChunks :: Int -> Stream Char -> Text-unstreamChunks !chunkSize (Stream next s0 len0)-  | isEmpty len0 = Empty-  | otherwise    = outer s0-  where-    outer so = {-# SCC "unstreamChunks/outer" #-}-              case next so of-                Done       -> Empty-                Skip s'    -> outer s'-                Yield x s' -> runST $ do-                                a <- A.new unknownLength-                                unsafeWrite a 0 x >>= inner a unknownLength s'-                    where unknownLength = 4-      where-        inner marr !len s !i-            | i + 1 >= chunkSize = finish marr i s-            | i + 1 >= len       = {-# SCC "unstreamChunks/resize" #-} do-                let newLen = min (len `shiftL` 1) chunkSize-                marr' <- A.new newLen-                A.copyM marr' 0 marr 0 len-                inner marr' newLen s i-            | otherwise =-                {-# SCC "unstreamChunks/inner" #-}-                case next s of-                  Done        -> finish marr i s-                  Skip s'     -> inner marr len s' i-                  Yield x s'  -> do d <- unsafeWrite marr i x-                                    inner marr len s' (i+d)-        finish marr len s' = do-          arr <- A.unsafeFreeze marr-          return (I.Text arr 0 len `Chunk` outer s')-{-# INLINE [0] unstreamChunks #-}---- | /O(n)/ Convert a 'Stream Char' into a 'Text', using--- 'defaultChunkSize'.-unstream :: Stream Char -> Text-unstream = unstreamChunks defaultChunkSize-{-# INLINE [0] unstream #-}---- | /O(n)/ Returns the number of characters in a text.-length :: Stream Char -> Int64-length = S.lengthI-{-# INLINE[0] length #-}--{-# RULES "LAZY STREAM stream/unstream fusion" forall s.-    stream (unstream s) = s #-}---- | /O(n)/ Like 'unfoldr', 'unfoldrN' builds a stream from a seed--- value. However, the length of the result is limited by the--- first argument to 'unfoldrN'. This function is more efficient than--- 'unfoldr' when the length of the result is known.-unfoldrN :: Int64 -> (a -> Maybe (Char,a)) -> a -> Stream Char-unfoldrN n = S.unfoldrNI n-{-# INLINE [0] unfoldrN #-}---- | /O(n)/ stream index (subscript) operator, starting from 0.-index :: Stream Char -> Int64 -> Char-index = S.indexI-{-# INLINE [0] index #-}---- | /O(n)/ The 'count' function returns the number of times the query--- element appears in the given stream.-countChar :: Char -> Stream Char -> Int64-countChar = S.countCharI-{-# INLINE [0] countChar #-}
− Data/Text/Internal/Lazy/Search.hs
@@ -1,134 +0,0 @@-{-# LANGUAGE BangPatterns, ScopedTypeVariables #-}---- |--- Module      : Data.Text.Lazy.Search--- Copyright   : (c) 2009, 2010 Bryan O'Sullivan------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : GHC------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ Fast substring search for lazy 'Text', based on work by Boyer,--- Moore, Horspool, Sunday, and Lundh.  Adapted from the strict--- implementation.--module Data.Text.Internal.Lazy.Search-    (-      indices-    ) where--import qualified Data.Text.Array as A-import Data.Int (Int64)-import Data.Word (Word16, Word64)-import qualified Data.Text.Internal as T-import Data.Text.Internal.Fusion.Types (PairS(..))-import Data.Text.Internal.Lazy (Text(..), foldlChunks)-import Data.Bits ((.|.), (.&.))-import Data.Text.Internal.Unsafe.Shift (shiftL)---- | /O(n+m)/ Find the offsets of all non-overlapping indices of--- @needle@ within @haystack@.------ This function is strict in @needle@, and lazy (as far as possible)--- in the chunks of @haystack@.------ In (unlikely) bad cases, this algorithm's complexity degrades--- towards /O(n*m)/.-indices :: Text              -- ^ Substring to search for (@needle@)-        -> Text              -- ^ Text to search in (@haystack@)-        -> [Int64]-indices needle@(Chunk n ns) _haystack@(Chunk k ks)-    | nlen <= 0  = []-    | nlen == 1  = indicesOne (nindex 0) 0 k ks-    | otherwise  = advance k ks 0 0-  where-    advance x@(T.Text _ _ l) xs = scan-     where-      scan !g !i-         | i >= m = case xs of-                      Empty           -> []-                      Chunk y ys      -> advance y ys g (i-m)-         | lackingHay (i + nlen) x xs  = []-         | c == z && candidateMatch 0  = g : scan (g+nlen) (i+nlen)-         | otherwise                   = scan (g+delta) (i+delta)-       where-         m = fromIntegral l-         c = hindex (i + nlast)-         delta | nextInPattern = nlen + 1-               | c == z        = skip + 1-               | otherwise     = 1-         nextInPattern         = mask .&. swizzle (hindex (i+nlen)) == 0-         candidateMatch !j-             | j >= nlast               = True-             | hindex (i+j) /= nindex j = False-             | otherwise                = candidateMatch (j+1)-         hindex                         = index x xs-    nlen      = wordLength needle-    nlast     = nlen - 1-    nindex    = index n ns-    z         = foldlChunks fin 0 needle-        where fin _ (T.Text farr foff flen) = A.unsafeIndex farr (foff+flen-1)-    (mask :: Word64) :*: skip = buildTable n ns 0 0 0 (nlen-2)-    swizzle w = 1 `shiftL` (fromIntegral w .&. 0x3f)-    buildTable (T.Text xarr xoff xlen) xs = go-      where-        go !(g::Int64) !i !msk !skp-            | i >= xlast = case xs of-                             Empty      -> (msk .|. swizzle z) :*: skp-                             Chunk y ys -> buildTable y ys g 0 msk' skp'-            | otherwise = go (g+1) (i+1) msk' skp'-            where c                = A.unsafeIndex xarr (xoff+i)-                  msk'             = msk .|. swizzle c-                  skp' | c == z    = nlen - g - 2-                       | otherwise = skp-                  xlast = xlen - 1-    -- | Check whether an attempt to index into the haystack at the-    -- given offset would fail.-    lackingHay q = go 0-      where-        go p (T.Text _ _ l) ps = p' < q && case ps of-                                             Empty      -> True-                                             Chunk r rs -> go p' r rs-            where p' = p + fromIntegral l-indices _ _ = []---- | Fast index into a partly unpacked 'Text'.  We take into account--- the possibility that the caller might try to access one element--- past the end.-index :: T.Text -> Text -> Int64 -> Word16-index (T.Text arr off len) xs !i-    | j < len   = A.unsafeIndex arr (off+j)-    | otherwise = case xs of-                    Empty-                        -- out of bounds, but legal-                        | j == len  -> 0-                        -- should never happen, due to lackingHay above-                        | otherwise -> emptyError "index"-                    Chunk c cs -> index c cs (i-fromIntegral len)-    where j = fromIntegral i---- | A variant of 'indices' that scans linearly for a single 'Word16'.-indicesOne :: Word16 -> Int64 -> T.Text -> Text -> [Int64]-indicesOne c = chunk-  where-    chunk !i (T.Text oarr ooff olen) os = go 0-      where-        go h | h >= olen = case os of-                             Empty      -> []-                             Chunk y ys -> chunk (i+fromIntegral olen) y ys-             | on == c = i + fromIntegral h : go (h+1)-             | otherwise = go (h+1)-             where on = A.unsafeIndex oarr (ooff+h)---- | The number of 'Word16' values in a 'Text'.-wordLength :: Text -> Int64-wordLength = foldlChunks sumLength 0-    where sumLength i (T.Text _ _ l) = i + fromIntegral l--emptyError :: String -> a-emptyError fun = error ("Data.Text.Lazy.Search." ++ fun ++ ": empty input")
− Data/Text/Internal/Private.hs
@@ -1,37 +0,0 @@-{-# LANGUAGE BangPatterns, Rank2Types, UnboxedTuples #-}---- |--- Module      : Data.Text.Internal.Private--- Copyright   : (c) 2011 Bryan O'Sullivan------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : GHC--module Data.Text.Internal.Private-    (-      runText-    , span_-    ) where--import Control.Monad.ST (ST, runST)-import Data.Text.Internal (Text(..), text)-import Data.Text.Unsafe (Iter(..), iter)-import qualified Data.Text.Array as A--span_ :: (Char -> Bool) -> Text -> (# Text, Text #)-span_ p t@(Text arr off len) = (# hd,tl #)-  where hd = text arr off k-        tl = text arr (off+k) (len-k)-        !k = loop 0-        loop !i | i < len && p c = loop (i+d)-                | otherwise      = i-            where Iter c d       = iter t i-{-# INLINE span_ #-}--runText :: (forall s. (A.MArray s -> Int -> ST s Text) -> ST s Text) -> Text-runText act = runST (act $ \ !marr !len -> do-                             arr <- A.unsafeFreeze marr-                             return $! text arr 0 len)-{-# INLINE runText #-}
− Data/Text/Internal/Read.hs
@@ -1,69 +0,0 @@--- |--- Module      : Data.Text.Internal.Read--- Copyright   : (c) 2014 Bryan O'Sullivan------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : GHC------ Common internal functions for reading textual data.-module Data.Text.Internal.Read-    (-      IReader-    , IParser(..)-    , T(..)-    , digitToInt-    , hexDigitToInt-    , perhaps-    ) where--import Control.Applicative as App (Applicative(..))-import Control.Arrow (first)-import Control.Monad (ap)-import Data.Char (ord)--type IReader t a = t -> Either String (a,t)--newtype IParser t a = P {-      runP :: IReader t a-    }--instance Functor (IParser t) where-    fmap f m = P $ fmap (first f) . runP m--instance Applicative (IParser t) where-    pure a = P $ \t -> Right (a,t)-    {-# INLINE pure #-}-    (<*>) = ap--instance Monad (IParser t) where-    return = App.pure-    m >>= k  = P $ \t -> case runP m t of-                           Left err     -> Left err-                           Right (a,t') -> runP (k a) t'-    {-# INLINE (>>=) #-}---- If we ever need a `MonadFail` instance the definition below can be used------ > instance MonadFail (IParser t) where--- >   fail msg = P $ \_ -> Left msg------ But given the code compiles fine with a post-MFP GHC 8.6+ we don't need--- one just yet.--data T = T !Integer !Int--perhaps :: a -> IParser t a -> IParser t a-perhaps def m = P $ \t -> case runP m t of-                            Left _      -> Right (def,t)-                            r@(Right _) -> r--hexDigitToInt :: Char -> Int-hexDigitToInt c-    | c >= '0' && c <= '9' = ord c - ord '0'-    | c >= 'a' && c <= 'f' = ord c - (ord 'a' - 10)-    | otherwise            = ord c - (ord 'A' - 10)--digitToInt :: Char -> Int-digitToInt c = ord c - ord '0'
− Data/Text/Internal/Search.hs
@@ -1,89 +0,0 @@-{-# LANGUAGE BangPatterns, ScopedTypeVariables #-}---- |--- Module      : Data.Text.Internal.Search--- Copyright   : (c) Bryan O'Sullivan 2009------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : GHC------ Fast substring search for 'Text', based on work by Boyer, Moore,--- Horspool, Sunday, and Lundh.------ References:------ * R. S. Boyer, J. S. Moore: A Fast String Searching Algorithm.---   Communications of the ACM, 20, 10, 762-772 (1977)------ * R. N. Horspool: Practical Fast Searching in Strings.  Software ----   Practice and Experience 10, 501-506 (1980)------ * D. M. Sunday: A Very Fast Substring Search Algorithm.---   Communications of the ACM, 33, 8, 132-142 (1990)------ * F. Lundh: The Fast Search Algorithm.---   <http://effbot.org/zone/stringlib.htm> (2006)--module Data.Text.Internal.Search-    (-      indices-    ) where--import qualified Data.Text.Array as A-import Data.Word (Word64)-import Data.Text.Internal (Text(..))-import Data.Bits ((.|.), (.&.))-import Data.Text.Internal.Unsafe.Shift (shiftL)--data T = {-# UNPACK #-} !Word64 :* {-# UNPACK #-} !Int---- | /O(n+m)/ Find the offsets of all non-overlapping indices of--- @needle@ within @haystack@.  The offsets returned represent--- uncorrected indices in the low-level \"needle\" array, to which its--- offset must be added.------ In (unlikely) bad cases, this algorithm's complexity degrades--- towards /O(n*m)/.-indices :: Text                -- ^ Substring to search for (@needle@)-        -> Text                -- ^ Text to search in (@haystack@)-        -> [Int]-indices _needle@(Text narr noff nlen) _haystack@(Text harr hoff hlen)-    | nlen == 1              = scanOne (nindex 0)-    | nlen <= 0 || ldiff < 0 = []-    | otherwise              = scan 0-  where-    ldiff    = hlen - nlen-    nlast    = nlen - 1-    z        = nindex nlast-    nindex k = A.unsafeIndex narr (noff+k)-    hindex k = A.unsafeIndex harr (hoff+k)-    hindex' k | k == hlen  = 0-              | otherwise = A.unsafeIndex harr (hoff+k)-    buildTable !i !msk !skp-        | i >= nlast           = (msk .|. swizzle z) :* skp-        | otherwise            = buildTable (i+1) (msk .|. swizzle c) skp'-        where c                = nindex i-              skp' | c == z    = nlen - i - 2-                   | otherwise = skp-    swizzle k = 1 `shiftL` (fromIntegral k .&. 0x3f)-    scan !i-        | i > ldiff                  = []-        | c == z && candidateMatch 0 = i : scan (i + nlen)-        | otherwise                  = scan (i + delta)-        where c = hindex (i + nlast)-              candidateMatch !j-                    | j >= nlast               = True-                    | hindex (i+j) /= nindex j = False-                    | otherwise                = candidateMatch (j+1)-              delta | nextInPattern = nlen + 1-                    | c == z        = skip + 1-                    | otherwise     = 1-                where nextInPattern = mask .&. swizzle (hindex' (i+nlen)) == 0-              !(mask :* skip)       = buildTable 0 0 (nlen-2)-    scanOne c = loop 0-        where loop !i | i >= hlen     = []-                      | hindex i == c = i : loop (i+1)-                      | otherwise     = loop (i+1)-{-# INLINE indices #-}
− Data/Text/Internal/Unsafe.hs
@@ -1,56 +0,0 @@-{-# LANGUAGE CPP, MagicHash, UnboxedTuples #-}-{-# OPTIONS_HADDOCK not-home #-}---- |--- Module      : Data.Text.Internal.Unsafe--- Copyright   : (c) 2009, 2010, 2011 Bryan O'Sullivan--- License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : portable------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ A module containing /unsafe/ operations, for /very very careful/ use--- in /heavily tested/ code.-module Data.Text.Internal.Unsafe-    (-      inlineInterleaveST-    , inlinePerformIO-    ) where--import GHC.ST (ST(..))-#if defined(__GLASGOW_HASKELL__)-import GHC.IO (IO(IO))-import GHC.Base (realWorld#)-#endif----- | Just like unsafePerformIO, but we inline it. Big performance gains as--- it exposes lots of things to further inlining. /Very unsafe/. In--- particular, you should do no memory allocation inside an--- 'inlinePerformIO' block. On Hugs this is just @unsafePerformIO@.----{-# INLINE inlinePerformIO #-}-inlinePerformIO :: IO a -> a-#if defined(__GLASGOW_HASKELL__)-inlinePerformIO (IO m) = case m realWorld# of (# _, r #) -> r-#else-inlinePerformIO = unsafePerformIO-#endif---- | Allow an 'ST' computation to be deferred lazily. When passed an--- action of type 'ST' @s@ @a@, the action will only be performed when--- the value of @a@ is demanded.------ This function is identical to the normal unsafeInterleaveST, but is--- inlined and hence faster.------ /Note/: This operation is highly unsafe, as it can introduce--- externally visible non-determinism into an 'ST' action.-inlineInterleaveST :: ST s a -> ST s a-inlineInterleaveST (ST m) = ST $ \ s ->-    let r = case m s of (# _, res #) -> res in (# s, r #)-{-# INLINE inlineInterleaveST #-}
− Data/Text/Internal/Unsafe/Char.hs
@@ -1,95 +0,0 @@-{-# LANGUAGE CPP, MagicHash #-}---- |--- Module      : Data.Text.Internal.Unsafe.Char--- Copyright   : (c) 2008, 2009 Tom Harper,---               (c) 2009, 2010 Bryan O'Sullivan,---               (c) 2009 Duncan Coutts------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : GHC------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ Fast character manipulation functions.-module Data.Text.Internal.Unsafe.Char-    (-      ord-    , unsafeChr-    , unsafeChr8-    , unsafeChr32-    , unsafeWrite-    -- , unsafeWriteRev-    ) where--#ifdef ASSERTS-import Control.Exception (assert)-#endif-import Control.Monad.ST (ST)-import Data.Bits ((.&.))-import Data.Text.Internal.Unsafe.Shift (shiftR)-import GHC.Exts (Char(..), Int(..), chr#, ord#, word2Int#)-import GHC.Word (Word8(..), Word16(..), Word32(..))-import qualified Data.Text.Array as A--ord :: Char -> Int-ord (C# c#) = I# (ord# c#)-{-# INLINE ord #-}--unsafeChr :: Word16 -> Char-unsafeChr (W16# w#) = C# (chr# (word2Int# w#))-{-# INLINE unsafeChr #-}--unsafeChr8 :: Word8 -> Char-unsafeChr8 (W8# w#) = C# (chr# (word2Int# w#))-{-# INLINE unsafeChr8 #-}--unsafeChr32 :: Word32 -> Char-unsafeChr32 (W32# w#) = C# (chr# (word2Int# w#))-{-# INLINE unsafeChr32 #-}---- | Write a character into the array at the given offset.  Returns--- the number of 'Word16's written.-unsafeWrite :: A.MArray s -> Int -> Char -> ST s Int-unsafeWrite marr i c-    | n < 0x10000 = do-#if defined(ASSERTS)-        assert (i >= 0) . assert (i < A.length marr) $ return ()-#endif-        A.unsafeWrite marr i (fromIntegral n)-        return 1-    | otherwise = do-#if defined(ASSERTS)-        assert (i >= 0) . assert (i < A.length marr - 1) $ return ()-#endif-        A.unsafeWrite marr i lo-        A.unsafeWrite marr (i+1) hi-        return 2-    where n = ord c-          m = n - 0x10000-          lo = fromIntegral $ (m `shiftR` 10) + 0xD800-          hi = fromIntegral $ (m .&. 0x3FF) + 0xDC00-{-# INLINE unsafeWrite #-}--{--unsafeWriteRev :: A.MArray s Word16 -> Int -> Char -> ST s Int-unsafeWriteRev marr i c-    | n < 0x10000 = do-        assert (i >= 0) . assert (i < A.length marr) $-          A.unsafeWrite marr i (fromIntegral n)-        return (i-1)-    | otherwise = do-        assert (i >= 1) . assert (i < A.length marr) $-          A.unsafeWrite marr (i-1) lo-        A.unsafeWrite marr i hi-        return (i-2)-    where n = ord c-          m = n - 0x10000-          lo = fromIntegral $ (m `shiftR` 10) + 0xD800-          hi = fromIntegral $ (m .&. 0x3FF) + 0xDC00-{-# INLINE unsafeWriteRev #-}--}
− Data/Text/Internal/Unsafe/Shift.hs
@@ -1,72 +0,0 @@-{-# LANGUAGE MagicHash #-}---- |--- Module      : Data.Text.Internal.Unsafe.Shift--- Copyright   : (c) Bryan O'Sullivan 2009------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : GHC------ /Warning/: this is an internal module, and does not have a stable--- API or name. Functions in this module may not check or enforce--- preconditions expected by public modules. Use at your own risk!------ Fast, unchecked bit shifting functions.--module Data.Text.Internal.Unsafe.Shift-    (-      UnsafeShift(..)-    ) where---- import qualified Data.Bits as Bits-import GHC.Base-import GHC.Word---- | This is a workaround for poor optimisation in GHC 6.8.2.  It--- fails to notice constant-width shifts, and adds a test and branch--- to every shift.  This imposes about a 10% performance hit.------ These functions are undefined when the amount being shifted by is--- greater than the size in bits of a machine Int#.-class UnsafeShift a where-    shiftL :: a -> Int -> a-    shiftR :: a -> Int -> a--instance UnsafeShift Word16 where-    {-# INLINE shiftL #-}-    shiftL (W16# x#) (I# i#) = W16# (narrow16Word# (x# `uncheckedShiftL#` i#))--    {-# INLINE shiftR #-}-    shiftR (W16# x#) (I# i#) = W16# (x# `uncheckedShiftRL#` i#)--instance UnsafeShift Word32 where-    {-# INLINE shiftL #-}-    shiftL (W32# x#) (I# i#) = W32# (narrow32Word# (x# `uncheckedShiftL#` i#))--    {-# INLINE shiftR #-}-    shiftR (W32# x#) (I# i#) = W32# (x# `uncheckedShiftRL#` i#)--instance UnsafeShift Word64 where-    {-# INLINE shiftL #-}-    shiftL (W64# x#) (I# i#) = W64# (x# `uncheckedShiftL64#` i#)--    {-# INLINE shiftR #-}-    shiftR (W64# x#) (I# i#) = W64# (x# `uncheckedShiftRL64#` i#)--instance UnsafeShift Int where-    {-# INLINE shiftL #-}-    shiftL (I# x#) (I# i#) = I# (x# `iShiftL#` i#)--    {-# INLINE shiftR #-}-    shiftR (I# x#) (I# i#) = I# (x# `iShiftRA#` i#)--{--instance UnsafeShift Integer where-    {-# INLINE shiftL #-}-    shiftL = Bits.shiftL--    {-# INLINE shiftR #-}-    shiftR = Bits.shiftR--}
− Data/Text/Lazy.hs
@@ -1,1746 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE BangPatterns, MagicHash, CPP, TypeFamilies #-}-#if __GLASGOW_HASKELL__ >= 702-{-# LANGUAGE Trustworthy #-}-#endif--- Using TemplateHaskell in text unconditionally is unacceptable, as--- it's a GHC boot library. TemplateHaskellQuotes was added in 8.0, so--- this would seem to be a problem. However, GHC's policy of only--- needing to be able to compile itself from the last few releases--- allows us to use full-fat TH on older versions, while using THQ for--- GHC versions that may be used for bootstrapping.-#if __GLASGOW_HASKELL__ >= 800-{-# LANGUAGE TemplateHaskellQuotes #-}-#else-{-# LANGUAGE TemplateHaskell #-}-#endif---- |--- Module      : Data.Text.Lazy--- Copyright   : (c) 2009, 2010, 2012 Bryan O'Sullivan------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Portability : GHC------ A time and space-efficient implementation of Unicode text using--- lists of packed arrays.------ /Note/: Read below the synopsis for important notes on the use of--- this module.------ The representation used by this module is suitable for high--- performance use and for streaming large quantities of data.  It--- provides a means to manipulate a large body of text without--- requiring that the entire content be resident in memory.------ Some operations, such as 'concat', 'append', 'reverse' and 'cons',--- have better time complexity than their "Data.Text" equivalents, due--- to the underlying representation being a list of chunks. For other--- operations, lazy 'Text's are usually within a few percent of strict--- ones, but often with better heap usage if used in a streaming--- fashion. For data larger than available memory, or if you have--- tight memory constraints, this module will be the only option.------ This module is intended to be imported @qualified@, to avoid name--- clashes with "Prelude" functions.  eg.------ > import qualified Data.Text.Lazy as L--module Data.Text.Lazy-    (-    -- * Fusion-    -- $fusion--    -- * Acceptable data-    -- $replacement--    -- * Types-      Text--    -- * Creation and elimination-    , pack-    , unpack-    , singleton-    , empty-    , fromChunks-    , toChunks-    , toStrict-    , fromStrict-    , foldrChunks-    , foldlChunks--    -- * Basic interface-    , cons-    , snoc-    , append-    , uncons-    , unsnoc-    , head-    , last-    , tail-    , init-    , null-    , length-    , compareLength--    -- * Transformations-    , map-    , intercalate-    , intersperse-    , transpose-    , reverse-    , replace--    -- ** Case conversion-    -- $case-    , toCaseFold-    , toLower-    , toUpper-    , toTitle--    -- ** Justification-    , justifyLeft-    , justifyRight-    , center--    -- * Folds-    , foldl-    , foldl'-    , foldl1-    , foldl1'-    , foldr-    , foldr1--    -- ** Special folds-    , concat-    , concatMap-    , any-    , all-    , maximum-    , minimum--    -- * Construction--    -- ** Scans-    , scanl-    , scanl1-    , scanr-    , scanr1--    -- ** Accumulating maps-    , mapAccumL-    , mapAccumR--    -- ** Generation and unfolding-    , repeat-    , replicate-    , cycle-    , iterate-    , unfoldr-    , unfoldrN--    -- * Substrings--    -- ** Breaking strings-    , take-    , takeEnd-    , drop-    , dropEnd-    , takeWhile-    , takeWhileEnd-    , dropWhile-    , dropWhileEnd-    , dropAround-    , strip-    , stripStart-    , stripEnd-    , splitAt-    , span-    , breakOn-    , breakOnEnd-    , break-    , group-    , groupBy-    , inits-    , tails--    -- ** Breaking into many substrings-    -- $split-    , splitOn-    , split-    , chunksOf-    -- , breakSubstring--    -- ** Breaking into lines and words-    , lines-    , words-    , unlines-    , unwords--    -- * Predicates-    , isPrefixOf-    , isSuffixOf-    , isInfixOf--    -- ** View patterns-    , stripPrefix-    , stripSuffix-    , commonPrefixes--    -- * Searching-    , filter-    , find-    , breakOnAll-    , partition--    -- , findSubstring--    -- * Indexing-    , index-    , count--    -- * Zipping and unzipping-    , zip-    , zipWith--    -- -* Ordered text-    -- , sort-    ) where--import Prelude (Char, Bool(..), Maybe(..), String,-                Eq(..), Ord(..), Ordering(..), Read(..), Show(..),-                (&&), (||), (+), (-), (.), ($), (++),-                error, flip, fmap, fromIntegral, not, otherwise, quot)-import qualified Prelude as P-import Control.DeepSeq (NFData(..))-import Data.Int (Int64)-import qualified Data.List as L-import Data.Char (isSpace)-import Data.Data (Data(gfoldl, toConstr, gunfold, dataTypeOf), constrIndex,-                  Constr, mkConstr, DataType, mkDataType, Fixity(Prefix))-import Data.Binary (Binary(get, put))-import Data.Monoid (Monoid(..))-#if MIN_VERSION_base(4,9,0)-import Data.Semigroup (Semigroup(..))-#endif-import Data.String (IsString(..))-import qualified Data.Text as T-import qualified Data.Text.Internal as T-import qualified Data.Text.Internal.Fusion.Common as S-import qualified Data.Text.Unsafe as T-import qualified Data.Text.Internal.Lazy.Fusion as S-import Data.Text.Internal.Fusion.Types (PairS(..))-import Data.Text.Internal.Lazy.Fusion (stream, unstream)-import Data.Text.Internal.Lazy (Text(..), chunk, empty, foldlChunks,-                                foldrChunks, smallChunkSize)-import Data.Text.Internal (firstf, safe, text)-import Data.Text.Lazy.Encoding (decodeUtf8', encodeUtf8)-import qualified Data.Text.Internal.Functions as F-import Data.Text.Internal.Lazy.Search (indices)-#if __GLASGOW_HASKELL__ >= 702-import qualified GHC.CString as GHC-#else-import qualified GHC.Base as GHC-#endif-#if MIN_VERSION_base(4,7,0)-import qualified GHC.Exts as Exts-#endif-import GHC.Prim (Addr#)-import qualified Language.Haskell.TH.Lib as TH-import Language.Haskell.TH.Syntax (Lift, lift)-#if MIN_VERSION_base(4,7,0)-import Text.Printf (PrintfArg, formatArg, formatString)-#endif---- $fusion------ Most of the functions in this module are subject to /fusion/,--- meaning that a pipeline of such functions will usually allocate at--- most one 'Text' value.------ As an example, consider the following pipeline:------ > import Data.Text.Lazy as T--- > import Data.Text.Lazy.Encoding as E--- > import Data.ByteString.Lazy (ByteString)--- >--- > countChars :: ByteString -> Int--- > countChars = T.length . T.toUpper . E.decodeUtf8------ From the type signatures involved, this looks like it should--- allocate one 'ByteString' value, and two 'Text' values. However,--- when a module is compiled with optimisation enabled under GHC, the--- two intermediate 'Text' values will be optimised away, and the--- function will be compiled down to a single loop over the source--- 'ByteString'.------ Functions that can be fused by the compiler are documented with the--- phrase \"Subject to fusion\".---- $replacement------ A 'Text' value is a sequence of Unicode scalar values, as defined--- in--- <http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#page=35 §3.9, definition D76 of the Unicode 5.2 standard >.--- As such, a 'Text' cannot contain values in the range U+D800 to--- U+DFFF inclusive. Haskell implementations admit all Unicode code--- points--- (<http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#page=13 §3.4, definition D10 >)--- as 'Char' values, including code points from this invalid range.--- This means that there are some 'Char' values that are not valid--- Unicode scalar values, and the functions in this module must handle--- those cases.------ Within this module, many functions construct a 'Text' from one or--- more 'Char' values. Those functions will substitute 'Char' values--- that are not valid Unicode scalar values with the replacement--- character \"&#xfffd;\" (U+FFFD).  Functions that perform this--- inspection and replacement are documented with the phrase--- \"Performs replacement on invalid scalar values\".------ (One reason for this policy of replacement is that internally, a--- 'Text' value is represented as packed UTF-16 data. Values in the--- range U+D800 through U+DFFF are used by UTF-16 to denote surrogate--- code points, and so cannot be represented. The functions replace--- invalid scalar values, instead of dropping them, as a security--- measure. For details, see--- <http://unicode.org/reports/tr36/#Deletion_of_Noncharacters Unicode Technical Report 36, §3.5 >.)--equal :: Text -> Text -> Bool-equal Empty Empty = True-equal Empty _     = False-equal _ Empty     = False-equal (Chunk a as) (Chunk b bs) =-    case compare lenA lenB of-      LT -> a == (T.takeWord16 lenA b) &&-            as `equal` Chunk (T.dropWord16 lenA b) bs-      EQ -> a == b && as `equal` bs-      GT -> T.takeWord16 lenB a == b &&-            Chunk (T.dropWord16 lenB a) as `equal` bs-  where lenA = T.lengthWord16 a-        lenB = T.lengthWord16 b--instance Eq Text where-    (==) = equal-    {-# INLINE (==) #-}--instance Ord Text where-    compare = compareText--compareText :: Text -> Text -> Ordering-compareText Empty Empty = EQ-compareText Empty _     = LT-compareText _     Empty = GT-compareText (Chunk a0 as) (Chunk b0 bs) = outer a0 b0- where-  outer ta@(T.Text arrA offA lenA) tb@(T.Text arrB offB lenB) = go 0 0-   where-    go !i !j-      | i >= lenA = compareText as (chunk (T.Text arrB (offB+j) (lenB-j)) bs)-      | j >= lenB = compareText (chunk (T.Text arrA (offA+i) (lenA-i)) as) bs-      | a < b     = LT-      | a > b     = GT-      | otherwise = go (i+di) (j+dj)-      where T.Iter a di = T.iter ta i-            T.Iter b dj = T.iter tb j--instance Show Text where-    showsPrec p ps r = showsPrec p (unpack ps) r--instance Read Text where-    readsPrec p str = [(pack x,y) | (x,y) <- readsPrec p str]--#if MIN_VERSION_base(4,9,0)--- | Non-orphan 'Semigroup' instance only defined for--- @base-4.9.0.0@ and later; orphan instances for older GHCs are--- provided by--- the [semigroups](http://hackage.haskell.org/package/semigroups)--- package------ @since 1.2.2.0-instance Semigroup Text where-    (<>) = append-#endif--instance Monoid Text where-    mempty  = empty-#if MIN_VERSION_base(4,9,0)-    mappend = (<>) -- future-proof definition-#else-    mappend = append-#endif-    mconcat = concat--instance IsString Text where-    fromString = pack--#if MIN_VERSION_base(4,7,0)--- | @since 1.2.0.0-instance Exts.IsList Text where-    type Item Text = Char-    fromList       = pack-    toList         = unpack-#endif--instance NFData Text where-    rnf Empty        = ()-    rnf (Chunk _ ts) = rnf ts---- | @since 1.2.1.0-instance Binary Text where-    put t = put (encodeUtf8 t)-    get   = do-      bs <- get-      case decodeUtf8' bs of-        P.Left exn -> P.fail (P.show exn)-        P.Right a -> P.return a---- | This instance preserves data abstraction at the cost of inefficiency.--- We omit reflection services for the sake of data abstraction.------ This instance was created by copying the updated behavior of--- @"Data.Text".@'Data.Text.Text'-instance Data Text where-  gfoldl f z txt = z pack `f` (unpack txt)-  toConstr _     = packConstr-  gunfold k z c  = case constrIndex c of-    1 -> k (z pack)-    _ -> error "Data.Text.Lazy.Text.gunfold"-  dataTypeOf _   = textDataType---- | This instance has similar considerations to the 'Data' instance:--- it preserves abstraction at the cost of inefficiency.------ @since 1.2.4.0-instance Lift Text where-  lift = TH.appE (TH.varE 'pack) . TH.stringE . unpack--#if MIN_VERSION_base(4,7,0)--- | Only defined for @base-4.7.0.0@ and later------ @since 1.2.2.0-instance PrintfArg Text where-  formatArg txt = formatString $ unpack txt-#endif--packConstr :: Constr-packConstr = mkConstr textDataType "pack" [] Prefix--textDataType :: DataType-textDataType = mkDataType "Data.Text.Lazy.Text" [packConstr]---- | /O(n)/ Convert a 'String' into a 'Text'.------ Subject to fusion.  Performs replacement on invalid scalar values.-pack :: String -> Text-pack = unstream . S.streamList . L.map safe-{-# INLINE [1] pack #-}---- | /O(n)/ Convert a 'Text' into a 'String'.--- Subject to fusion.-unpack :: Text -> String-unpack t = S.unstreamList (stream t)-{-# INLINE [1] unpack #-}---- | /O(n)/ Convert a literal string into a Text.-unpackCString# :: Addr# -> Text-unpackCString# addr# = unstream (S.streamCString# addr#)-{-# NOINLINE unpackCString# #-}--{-# RULES "TEXT literal" forall a.-    unstream (S.streamList (L.map safe (GHC.unpackCString# a)))-      = unpackCString# a #-}--{-# RULES "TEXT literal UTF8" forall a.-    unstream (S.streamList (L.map safe (GHC.unpackCStringUtf8# a)))-      = unpackCString# a #-}--{-# RULES "LAZY TEXT empty literal"-    unstream (S.streamList (L.map safe []))-      = Empty #-}--{-# RULES "LAZY TEXT empty literal" forall a.-    unstream (S.streamList (L.map safe [a]))-      = Chunk (T.singleton a) Empty #-}---- | /O(1)/ Convert a character into a Text.  Subject to fusion.--- Performs replacement on invalid scalar values.-singleton :: Char -> Text-singleton c = Chunk (T.singleton c) Empty-{-# INLINE [1] singleton #-}--{-# RULES-"LAZY TEXT singleton -> fused" [~1] forall c.-    singleton c = unstream (S.singleton c)-"LAZY TEXT singleton -> unfused" [1] forall c.-    unstream (S.singleton c) = singleton c-  #-}---- | /O(c)/ Convert a list of strict 'T.Text's into a lazy 'Text'.-fromChunks :: [T.Text] -> Text-fromChunks cs = L.foldr chunk Empty cs---- | /O(n)/ Convert a lazy 'Text' into a list of strict 'T.Text's.-toChunks :: Text -> [T.Text]-toChunks cs = foldrChunks (:) [] cs---- | /O(n)/ Convert a lazy 'Text' into a strict 'T.Text'.-toStrict :: Text -> T.Text-toStrict t = T.concat (toChunks t)-{-# INLINE [1] toStrict #-}---- | /O(c)/ Convert a strict 'T.Text' into a lazy 'Text'.-fromStrict :: T.Text -> Text-fromStrict t = chunk t Empty-{-# INLINE [1] fromStrict #-}---- -------------------------------------------------------------------------------- * Basic functions---- | /O(1)/ Adds a character to the front of a 'Text'.  Subject to fusion.-cons :: Char -> Text -> Text-cons c t = Chunk (T.singleton c) t-{-# INLINE [1] cons #-}--infixr 5 `cons`--{-# RULES-"LAZY TEXT cons -> fused" [~1] forall c t.-    cons c t = unstream (S.cons c (stream t))-"LAZY TEXT cons -> unfused" [1] forall c t.-    unstream (S.cons c (stream t)) = cons c t- #-}---- | /O(n)/ Adds a character to the end of a 'Text'.  This copies the--- entire array in the process, unless fused.  Subject to fusion.-snoc :: Text -> Char -> Text-snoc t c = foldrChunks Chunk (singleton c) t-{-# INLINE [1] snoc #-}--{-# RULES-"LAZY TEXT snoc -> fused" [~1] forall t c.-    snoc t c = unstream (S.snoc (stream t) c)-"LAZY TEXT snoc -> unfused" [1] forall t c.-    unstream (S.snoc (stream t) c) = snoc t c- #-}---- | /O(n\/c)/ Appends one 'Text' to another.  Subject to fusion.-append :: Text -> Text -> Text-append xs ys = foldrChunks Chunk ys xs-{-# INLINE [1] append #-}--{-# RULES-"LAZY TEXT append -> fused" [~1] forall t1 t2.-    append t1 t2 = unstream (S.append (stream t1) (stream t2))-"LAZY TEXT append -> unfused" [1] forall t1 t2.-    unstream (S.append (stream t1) (stream t2)) = append t1 t2- #-}---- | /O(1)/ Returns the first character and rest of a 'Text', or--- 'Nothing' if empty. Subject to fusion.-uncons :: Text -> Maybe (Char, Text)-uncons Empty        = Nothing-uncons (Chunk t ts) = Just (T.unsafeHead t, ts')-  where ts' | T.compareLength t 1 == EQ = ts-            | otherwise                 = Chunk (T.unsafeTail t) ts-{-# INLINE uncons #-}---- | /O(1)/ Returns the first character of a 'Text', which must be--- non-empty.  Subject to fusion.-head :: Text -> Char-head t = S.head (stream t)-{-# INLINE head #-}---- | /O(1)/ Returns all characters after the head of a 'Text', which--- must be non-empty.  Subject to fusion.-tail :: Text -> Text-tail (Chunk t ts) = chunk (T.tail t) ts-tail Empty        = emptyError "tail"-{-# INLINE [1] tail #-}--{-# RULES-"LAZY TEXT tail -> fused" [~1] forall t.-    tail t = unstream (S.tail (stream t))-"LAZY TEXT tail -> unfused" [1] forall t.-    unstream (S.tail (stream t)) = tail t- #-}---- | /O(n\/c)/ Returns all but the last character of a 'Text', which must--- be non-empty.  Subject to fusion.-init :: Text -> Text-init (Chunk t0 ts0) = go t0 ts0-    where go t (Chunk t' ts) = Chunk t (go t' ts)-          go t Empty         = chunk (T.init t) Empty-init Empty = emptyError "init"-{-# INLINE [1] init #-}--{-# RULES-"LAZY TEXT init -> fused" [~1] forall t.-    init t = unstream (S.init (stream t))-"LAZY TEXT init -> unfused" [1] forall t.-    unstream (S.init (stream t)) = init t- #-}---- | /O(n\/c)/ Returns the 'init' and 'last' of a 'Text', or 'Nothing' if--- empty.------ * It is no faster than using 'init' and 'last'.------ @since 1.2.3.0-unsnoc :: Text -> Maybe (Text, Char)-unsnoc Empty          = Nothing-unsnoc ts@(Chunk _ _) = Just (init ts, last ts)-{-# INLINE unsnoc #-}---- | /O(1)/ Tests whether a 'Text' is empty or not.  Subject to--- fusion.-null :: Text -> Bool-null Empty = True-null _     = False-{-# INLINE [1] null #-}--{-# RULES-"LAZY TEXT null -> fused" [~1] forall t.-    null t = S.null (stream t)-"LAZY TEXT null -> unfused" [1] forall t.-    S.null (stream t) = null t- #-}---- | /O(1)/ Tests whether a 'Text' contains exactly one character.--- Subject to fusion.-isSingleton :: Text -> Bool-isSingleton = S.isSingleton . stream-{-# INLINE isSingleton #-}---- | /O(n\/c)/ Returns the last character of a 'Text', which must be--- non-empty.  Subject to fusion.-last :: Text -> Char-last Empty        = emptyError "last"-last (Chunk t ts) = go t ts-    where go _ (Chunk t' ts') = go t' ts'-          go t' Empty         = T.last t'-{-# INLINE [1] last #-}--{-# RULES-"LAZY TEXT last -> fused" [~1] forall t.-    last t = S.last (stream t)-"LAZY TEXT last -> unfused" [1] forall t.-    S.last (stream t) = last t-  #-}---- | /O(n)/ Returns the number of characters in a 'Text'.--- Subject to fusion.-length :: Text -> Int64-length = foldlChunks go 0-    where go l t = l + fromIntegral (T.length t)-{-# INLINE [1] length #-}--{-# RULES-"LAZY TEXT length -> fused" [~1] forall t.-    length t = S.length (stream t)-"LAZY TEXT length -> unfused" [1] forall t.-    S.length (stream t) = length t- #-}---- | /O(n)/ Compare the count of characters in a 'Text' to a number.--- Subject to fusion.------ This function gives the same answer as comparing against the result--- of 'length', but can short circuit if the count of characters is--- greater than the number, and hence be more efficient.-compareLength :: Text -> Int64 -> Ordering-compareLength t n = S.compareLengthI (stream t) n-{-# INLINE [1] compareLength #-}---- We don't apply those otherwise appealing length-to-compareLength--- rewrite rules here, because they can change the strictness--- properties of code.---- | /O(n)/ 'map' @f@ @t@ is the 'Text' obtained by applying @f@ to--- each element of @t@.  Subject to fusion.  Performs replacement on--- invalid scalar values.-map :: (Char -> Char) -> Text -> Text-map f t = unstream (S.map (safe . f) (stream t))-{-# INLINE [1] map #-}---- | /O(n)/ The 'intercalate' function takes a 'Text' and a list of--- 'Text's and concatenates the list after interspersing the first--- argument between each element of the list.-intercalate :: Text -> [Text] -> Text-intercalate t = concat . (F.intersperse t)-{-# INLINE intercalate #-}---- | /O(n)/ The 'intersperse' function takes a character and places it--- between the characters of a 'Text'.  Subject to fusion.  Performs--- replacement on invalid scalar values.-intersperse :: Char -> Text -> Text-intersperse c t = unstream (S.intersperse (safe c) (stream t))-{-# INLINE intersperse #-}---- | /O(n)/ Left-justify a string to the given length, using the--- specified fill character on the right. Subject to fusion.  Performs--- replacement on invalid scalar values.------ Examples:------ > justifyLeft 7 'x' "foo"    == "fooxxxx"--- > justifyLeft 3 'x' "foobar" == "foobar"-justifyLeft :: Int64 -> Char -> Text -> Text-justifyLeft k c t-    | len >= k  = t-    | otherwise = t `append` replicateChar (k-len) c-  where len = length t-{-# INLINE [1] justifyLeft #-}--{-# RULES-"LAZY TEXT justifyLeft -> fused" [~1] forall k c t.-    justifyLeft k c t = unstream (S.justifyLeftI k c (stream t))-"LAZY TEXT justifyLeft -> unfused" [1] forall k c t.-    unstream (S.justifyLeftI k c (stream t)) = justifyLeft k c t-  #-}---- | /O(n)/ Right-justify a string to the given length, using the--- specified fill character on the left.  Performs replacement on--- invalid scalar values.------ Examples:------ > justifyRight 7 'x' "bar"    == "xxxxbar"--- > justifyRight 3 'x' "foobar" == "foobar"-justifyRight :: Int64 -> Char -> Text -> Text-justifyRight k c t-    | len >= k  = t-    | otherwise = replicateChar (k-len) c `append` t-  where len = length t-{-# INLINE justifyRight #-}---- | /O(n)/ Center a string to the given length, using the specified--- fill character on either side.  Performs replacement on invalid--- scalar values.------ Examples:------ > center 8 'x' "HS" = "xxxHSxxx"-center :: Int64 -> Char -> Text -> Text-center k c t-    | len >= k  = t-    | otherwise = replicateChar l c `append` t `append` replicateChar r c-  where len = length t-        d   = k - len-        r   = d `quot` 2-        l   = d - r-{-# INLINE center #-}---- | /O(n)/ The 'transpose' function transposes the rows and columns--- of its 'Text' argument.  Note that this function uses 'pack',--- 'unpack', and the list version of transpose, and is thus not very--- efficient.-transpose :: [Text] -> [Text]-transpose ts = L.map (\ss -> Chunk (T.pack ss) Empty)-                     (L.transpose (L.map unpack ts))--- TODO: make this fast---- | /O(n)/ 'reverse' @t@ returns the elements of @t@ in reverse order.-reverse :: Text -> Text-reverse = rev Empty-  where rev a Empty        = a-        rev a (Chunk t ts) = rev (Chunk (T.reverse t) a) ts---- | /O(m+n)/ Replace every non-overlapping occurrence of @needle@ in--- @haystack@ with @replacement@.------ This function behaves as though it was defined as follows:------ @--- replace needle replacement haystack =---   'intercalate' replacement ('splitOn' needle haystack)--- @------ As this suggests, each occurrence is replaced exactly once.  So if--- @needle@ occurs in @replacement@, that occurrence will /not/ itself--- be replaced recursively:------ > replace "oo" "foo" "oo" == "foo"------ In cases where several instances of @needle@ overlap, only the--- first one will be replaced:------ > replace "ofo" "bar" "ofofo" == "barfo"------ In (unlikely) bad cases, this function's time complexity degrades--- towards /O(n*m)/.-replace :: Text-        -- ^ @needle@ to search for.  If this string is empty, an-        -- error will occur.-        -> Text-        -- ^ @replacement@ to replace @needle@ with.-        -> Text-        -- ^ @haystack@ in which to search.-        -> Text-replace s d = intercalate d . splitOn s-{-# INLINE replace #-}---- ------------------------------------------------------------------------------- ** Case conversions (folds)---- $case------ With Unicode text, it is incorrect to use combinators like @map--- toUpper@ to case convert each character of a string individually.--- Instead, use the whole-string case conversion functions from this--- module.  For correctness in different writing systems, these--- functions may map one input character to two or three output--- characters.---- | /O(n)/ Convert a string to folded case.  Subject to fusion.------ This function is mainly useful for performing caseless (or case--- insensitive) string comparisons.------ A string @x@ is a caseless match for a string @y@ if and only if:------ @toCaseFold x == toCaseFold y@------ The result string may be longer than the input string, and may--- differ from applying 'toLower' to the input string.  For instance,--- the Armenian small ligature men now (U+FB13) is case folded to the--- bigram men now (U+0574 U+0576), while the micro sign (U+00B5) is--- case folded to the Greek small letter letter mu (U+03BC) instead of--- itself.-toCaseFold :: Text -> Text-toCaseFold t = unstream (S.toCaseFold (stream t))-{-# INLINE toCaseFold #-}---- | /O(n)/ Convert a string to lower case, using simple case--- conversion.  Subject to fusion.------ The result string may be longer than the input string.  For--- instance, the Latin capital letter I with dot above (U+0130) maps--- to the sequence Latin small letter i (U+0069) followed by combining--- dot above (U+0307).-toLower :: Text -> Text-toLower t = unstream (S.toLower (stream t))-{-# INLINE toLower #-}---- | /O(n)/ Convert a string to upper case, using simple case--- conversion.  Subject to fusion.------ The result string may be longer than the input string.  For--- instance, the German eszett (U+00DF) maps to the two-letter--- sequence SS.-toUpper :: Text -> Text-toUpper t = unstream (S.toUpper (stream t))-{-# INLINE toUpper #-}----- | /O(n)/ Convert a string to title case, using simple case--- conversion.  Subject to fusion.------ The first letter of the input is converted to title case, as is--- every subsequent letter that immediately follows a non-letter.--- Every letter that immediately follows another letter is converted--- to lower case.------ The result string may be longer than the input string. For example,--- the Latin small ligature &#xfb02; (U+FB02) is converted to the--- sequence Latin capital letter F (U+0046) followed by Latin small--- letter l (U+006C).------ /Note/: this function does not take language or culture specific--- rules into account. For instance, in English, different style--- guides disagree on whether the book name \"The Hill of the Red--- Fox\" is correctly title cased&#x2014;but this function will--- capitalize /every/ word.------ @since 1.0.0.0-toTitle :: Text -> Text-toTitle t = unstream (S.toTitle (stream t))-{-# INLINE toTitle #-}---- | /O(n)/ 'foldl', applied to a binary operator, a starting value--- (typically the left-identity of the operator), and a 'Text',--- reduces the 'Text' using the binary operator, from left to right.--- Subject to fusion.-foldl :: (a -> Char -> a) -> a -> Text -> a-foldl f z t = S.foldl f z (stream t)-{-# INLINE foldl #-}---- | /O(n)/ A strict version of 'foldl'.--- Subject to fusion.-foldl' :: (a -> Char -> a) -> a -> Text -> a-foldl' f z t = S.foldl' f z (stream t)-{-# INLINE foldl' #-}---- | /O(n)/ A variant of 'foldl' that has no starting value argument,--- and thus must be applied to a non-empty 'Text'.  Subject to fusion.-foldl1 :: (Char -> Char -> Char) -> Text -> Char-foldl1 f t = S.foldl1 f (stream t)-{-# INLINE foldl1 #-}---- | /O(n)/ A strict version of 'foldl1'.  Subject to fusion.-foldl1' :: (Char -> Char -> Char) -> Text -> Char-foldl1' f t = S.foldl1' f (stream t)-{-# INLINE foldl1' #-}---- | /O(n)/ 'foldr', applied to a binary operator, a starting value--- (typically the right-identity of the operator), and a 'Text',--- reduces the 'Text' using the binary operator, from right to left.--- Subject to fusion.-foldr :: (Char -> a -> a) -> a -> Text -> a-foldr f z t = S.foldr f z (stream t)-{-# INLINE foldr #-}---- | /O(n)/ A variant of 'foldr' that has no starting value argument,--- and thus must be applied to a non-empty 'Text'.  Subject to--- fusion.-foldr1 :: (Char -> Char -> Char) -> Text -> Char-foldr1 f t = S.foldr1 f (stream t)-{-# INLINE foldr1 #-}---- | /O(n)/ Concatenate a list of 'Text's.-concat :: [Text] -> Text-concat = to-  where-    go Empty        css = to css-    go (Chunk c cs) css = Chunk c (go cs css)-    to []               = Empty-    to (cs:css)         = go cs css-{-# INLINE concat #-}---- | /O(n)/ Map a function over a 'Text' that results in a 'Text', and--- concatenate the results.-concatMap :: (Char -> Text) -> Text -> Text-concatMap f = concat . foldr ((:) . f) []-{-# INLINE concatMap #-}---- | /O(n)/ 'any' @p@ @t@ determines whether any character in the--- 'Text' @t@ satisfies the predicate @p@. Subject to fusion.-any :: (Char -> Bool) -> Text -> Bool-any p t = S.any p (stream t)-{-# INLINE any #-}---- | /O(n)/ 'all' @p@ @t@ determines whether all characters in the--- 'Text' @t@ satisfy the predicate @p@. Subject to fusion.-all :: (Char -> Bool) -> Text -> Bool-all p t = S.all p (stream t)-{-# INLINE all #-}---- | /O(n)/ 'maximum' returns the maximum value from a 'Text', which--- must be non-empty. Subject to fusion.-maximum :: Text -> Char-maximum t = S.maximum (stream t)-{-# INLINE maximum #-}---- | /O(n)/ 'minimum' returns the minimum value from a 'Text', which--- must be non-empty. Subject to fusion.-minimum :: Text -> Char-minimum t = S.minimum (stream t)-{-# INLINE minimum #-}---- | /O(n)/ 'scanl' is similar to 'foldl', but returns a list of--- successive reduced values from the left. Subject to fusion.--- Performs replacement on invalid scalar values.------ > scanl f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...]------ Note that------ > last (scanl f z xs) == foldl f z xs.-scanl :: (Char -> Char -> Char) -> Char -> Text -> Text-scanl f z t = unstream (S.scanl g z (stream t))-    where g a b = safe (f a b)-{-# INLINE scanl #-}---- | /O(n)/ 'scanl1' is a variant of 'scanl' that has no starting--- value argument.  Performs replacement on invalid scalar values.------ > scanl1 f [x1, x2, ...] == [x1, x1 `f` x2, ...]-scanl1 :: (Char -> Char -> Char) -> Text -> Text-scanl1 f t0 = case uncons t0 of-                Nothing -> empty-                Just (t,ts) -> scanl f t ts-{-# INLINE scanl1 #-}---- | /O(n)/ 'scanr' is the right-to-left dual of 'scanl'.  Performs--- replacement on invalid scalar values.------ > scanr f v == reverse . scanl (flip f) v . reverse-scanr :: (Char -> Char -> Char) -> Char -> Text -> Text-scanr f v = reverse . scanl g v . reverse-    where g a b = safe (f b a)---- | /O(n)/ 'scanr1' is a variant of 'scanr' that has no starting--- value argument.  Performs replacement on invalid scalar values.-scanr1 :: (Char -> Char -> Char) -> Text -> Text-scanr1 f t | null t    = empty-           | otherwise = scanr f (last t) (init t)---- | /O(n)/ Like a combination of 'map' and 'foldl''. Applies a--- function to each element of a 'Text', passing an accumulating--- parameter from left to right, and returns a final 'Text'.  Performs--- replacement on invalid scalar values.-mapAccumL :: (a -> Char -> (a,Char)) -> a -> Text -> (a, Text)-mapAccumL f = go-  where-    go z (Chunk c cs)    = (z'', Chunk c' cs')-        where (z',  c')  = T.mapAccumL f z c-              (z'', cs') = go z' cs-    go z Empty           = (z, Empty)-{-# INLINE mapAccumL #-}---- | The 'mapAccumR' function behaves like a combination of 'map' and--- a strict 'foldr'; it applies a function to each element of a--- 'Text', passing an accumulating parameter from right to left, and--- returning a final value of this accumulator together with the new--- 'Text'.  Performs replacement on invalid scalar values.-mapAccumR :: (a -> Char -> (a,Char)) -> a -> Text -> (a, Text)-mapAccumR f = go-  where-    go z (Chunk c cs)   = (z'', Chunk c' cs')-        where (z'', c') = T.mapAccumR f z' c-              (z', cs') = go z cs-    go z Empty          = (z, Empty)-{-# INLINE mapAccumR #-}---- | @'repeat' x@ is an infinite 'Text', with @x@ the value of every--- element.------ @since 1.2.0.5-repeat :: Char -> Text-repeat c = let t = Chunk (T.replicate smallChunkSize (T.singleton c)) t-            in t---- | /O(n*m)/ 'replicate' @n@ @t@ is a 'Text' consisting of the input--- @t@ repeated @n@ times.-replicate :: Int64 -> Text -> Text-replicate n t-    | null t || n <= 0 = empty-    | isSingleton t    = replicateChar n (head t)-    | otherwise        = concat (rep 0)-    where rep !i | i >= n    = []-                 | otherwise = t : rep (i+1)-{-# INLINE [1] replicate #-}---- | 'cycle' ties a finite, non-empty 'Text' into a circular one, or--- equivalently, the infinite repetition of the original 'Text'.------ @since 1.2.0.5-cycle :: Text -> Text-cycle Empty = emptyError "cycle"-cycle t     = let t' = foldrChunks Chunk t' t-               in t'---- | @'iterate' f x@ returns an infinite 'Text' of repeated applications--- of @f@ to @x@:------ > iterate f x == [x, f x, f (f x), ...]------ @since 1.2.0.5-iterate :: (Char -> Char) -> Char -> Text-iterate f c = let t c' = Chunk (T.singleton c') (t (f c'))-               in t c---- | /O(n)/ 'replicateChar' @n@ @c@ is a 'Text' of length @n@ with @c@ the--- value of every element. Subject to fusion.-replicateChar :: Int64 -> Char -> Text-replicateChar n c = unstream (S.replicateCharI n (safe c))-{-# INLINE replicateChar #-}--{-# RULES-"LAZY TEXT replicate/singleton -> replicateChar" [~1] forall n c.-    replicate n (singleton c) = replicateChar n c-"LAZY TEXT replicate/unstream/singleton -> replicateChar" [~1] forall n c.-    replicate n (unstream (S.singleton c)) = replicateChar n c-  #-}---- | /O(n)/, where @n@ is the length of the result. The 'unfoldr'--- function is analogous to the List 'L.unfoldr'. 'unfoldr' builds a--- 'Text' from a seed value. The function takes the element and--- returns 'Nothing' if it is done producing the 'Text', otherwise--- 'Just' @(a,b)@.  In this case, @a@ is the next 'Char' in the--- string, and @b@ is the seed value for further production.--- Subject to fusion.--- Performs replacement on invalid scalar values.-unfoldr :: (a -> Maybe (Char,a)) -> a -> Text-unfoldr f s = unstream (S.unfoldr (firstf safe . f) s)-{-# INLINE unfoldr #-}---- | /O(n)/ Like 'unfoldr', 'unfoldrN' builds a 'Text' from a seed--- value. However, the length of the result should be limited by the--- first argument to 'unfoldrN'. This function is more efficient than--- 'unfoldr' when the maximum length of the result is known and--- correct, otherwise its performance is similar to 'unfoldr'.--- Subject to fusion.--- Performs replacement on invalid scalar values.-unfoldrN :: Int64 -> (a -> Maybe (Char,a)) -> a -> Text-unfoldrN n f s = unstream (S.unfoldrN n (firstf safe . f) s)-{-# INLINE unfoldrN #-}---- | /O(n)/ 'take' @n@, applied to a 'Text', returns the prefix of the--- 'Text' of length @n@, or the 'Text' itself if @n@ is greater than--- the length of the Text. Subject to fusion.-take :: Int64 -> Text -> Text-take i _ | i <= 0 = Empty-take i t0         = take' i t0-  where take' 0 _            = Empty-        take' _ Empty        = Empty-        take' n (Chunk t ts)-            | n < len   = Chunk (T.take (fromIntegral n) t) Empty-            | otherwise = Chunk t (take' (n - len) ts)-            where len = fromIntegral (T.length t)-{-# INLINE [1] take #-}--{-# RULES-"LAZY TEXT take -> fused" [~1] forall n t.-    take n t = unstream (S.take n (stream t))-"LAZY TEXT take -> unfused" [1] forall n t.-    unstream (S.take n (stream t)) = take n t-  #-}---- | /O(n)/ 'takeEnd' @n@ @t@ returns the suffix remaining after--- taking @n@ characters from the end of @t@.------ Examples:------ > takeEnd 3 "foobar" == "bar"------ @since 1.1.1.0-takeEnd :: Int64 -> Text -> Text-takeEnd n t0-    | n <= 0    = empty-    | otherwise = takeChunk n empty . L.reverse . toChunks $ t0-  where takeChunk _ acc [] = acc-        takeChunk i acc (t:ts)-          | i <= l    = chunk (T.takeEnd (fromIntegral i) t) acc-          | otherwise = takeChunk (i-l) (Chunk t acc) ts-          where l = fromIntegral (T.length t)---- | /O(n)/ 'drop' @n@, applied to a 'Text', returns the suffix of the--- 'Text' after the first @n@ characters, or the empty 'Text' if @n@--- is greater than the length of the 'Text'. Subject to fusion.-drop :: Int64 -> Text -> Text-drop i t0-    | i <= 0    = t0-    | otherwise = drop' i t0-  where drop' 0 ts           = ts-        drop' _ Empty        = Empty-        drop' n (Chunk t ts)-            | n < len   = Chunk (T.drop (fromIntegral n) t) ts-            | otherwise = drop' (n - len) ts-            where len   = fromIntegral (T.length t)-{-# INLINE [1] drop #-}--{-# RULES-"LAZY TEXT drop -> fused" [~1] forall n t.-    drop n t = unstream (S.drop n (stream t))-"LAZY TEXT drop -> unfused" [1] forall n t.-    unstream (S.drop n (stream t)) = drop n t-  #-}---- | /O(n)/ 'dropEnd' @n@ @t@ returns the prefix remaining after--- dropping @n@ characters from the end of @t@.------ Examples:------ > dropEnd 3 "foobar" == "foo"------ @since 1.1.1.0-dropEnd :: Int64 -> Text -> Text-dropEnd n t0-    | n <= 0    = t0-    | otherwise = dropChunk n . L.reverse . toChunks $ t0-  where dropChunk _ [] = empty-        dropChunk m (t:ts)-          | m >= l    = dropChunk (m-l) ts-          | otherwise = fromChunks . L.reverse $-                        T.dropEnd (fromIntegral m) t : ts-          where l = fromIntegral (T.length t)---- | /O(n)/ 'dropWords' @n@ returns the suffix with @n@ 'Word16'--- values dropped, or the empty 'Text' if @n@ is greater than the--- number of 'Word16' values present.-dropWords :: Int64 -> Text -> Text-dropWords i t0-    | i <= 0    = t0-    | otherwise = drop' i t0-  where drop' 0 ts           = ts-        drop' _ Empty        = Empty-        drop' n (Chunk (T.Text arr off len) ts)-            | n < len'  = chunk (text arr (off+n') (len-n')) ts-            | otherwise = drop' (n - len') ts-            where len'  = fromIntegral len-                  n'    = fromIntegral n---- | /O(n)/ 'takeWhile', applied to a predicate @p@ and a 'Text',--- returns the longest prefix (possibly empty) of elements that--- satisfy @p@.  Subject to fusion.-takeWhile :: (Char -> Bool) -> Text -> Text-takeWhile p t0 = takeWhile' t0-  where takeWhile' Empty        = Empty-        takeWhile' (Chunk t ts) =-          case T.findIndex (not . p) t of-            Just n | n > 0     -> Chunk (T.take n t) Empty-                   | otherwise -> Empty-            Nothing            -> Chunk t (takeWhile' ts)-{-# INLINE [1] takeWhile #-}--{-# RULES-"LAZY TEXT takeWhile -> fused" [~1] forall p t.-    takeWhile p t = unstream (S.takeWhile p (stream t))-"LAZY TEXT takeWhile -> unfused" [1] forall p t.-    unstream (S.takeWhile p (stream t)) = takeWhile p t-  #-}--- | /O(n)/ 'takeWhileEnd', applied to a predicate @p@ and a 'Text',--- returns the longest suffix (possibly empty) of elements that--- satisfy @p@.--- Examples:------ > takeWhileEnd (=='o') "foo" == "oo"------ @since 1.2.2.0-takeWhileEnd :: (Char -> Bool) -> Text -> Text-takeWhileEnd p = takeChunk empty . L.reverse . toChunks-  where takeChunk acc []     = acc-        takeChunk acc (t:ts)-          | T.lengthWord16 t' < T.lengthWord16 t-                             = chunk t' acc-          | otherwise        = takeChunk (Chunk t' acc) ts-          where t' = T.takeWhileEnd p t-{-# INLINE takeWhileEnd #-}---- | /O(n)/ 'dropWhile' @p@ @t@ returns the suffix remaining after--- 'takeWhile' @p@ @t@.  Subject to fusion.-dropWhile :: (Char -> Bool) -> Text -> Text-dropWhile p t0 = dropWhile' t0-  where dropWhile' Empty        = Empty-        dropWhile' (Chunk t ts) =-          case T.findIndex (not . p) t of-            Just n  -> Chunk (T.drop n t) ts-            Nothing -> dropWhile' ts-{-# INLINE [1] dropWhile #-}--{-# RULES-"LAZY TEXT dropWhile -> fused" [~1] forall p t.-    dropWhile p t = unstream (S.dropWhile p (stream t))-"LAZY TEXT dropWhile -> unfused" [1] forall p t.-    unstream (S.dropWhile p (stream t)) = dropWhile p t-  #-}---- | /O(n)/ 'dropWhileEnd' @p@ @t@ returns the prefix remaining after--- dropping characters that satisfy the predicate @p@ from the end of--- @t@.------ Examples:------ > dropWhileEnd (=='.') "foo..." == "foo"-dropWhileEnd :: (Char -> Bool) -> Text -> Text-dropWhileEnd p = go-  where go Empty = Empty-        go (Chunk t Empty) = if T.null t'-                             then Empty-                             else Chunk t' Empty-            where t' = T.dropWhileEnd p t-        go (Chunk t ts) = case go ts of-                            Empty -> go (Chunk t Empty)-                            ts' -> Chunk t ts'-{-# INLINE dropWhileEnd #-}---- | /O(n)/ 'dropAround' @p@ @t@ returns the substring remaining after--- dropping characters that satisfy the predicate @p@ from both the--- beginning and end of @t@.-dropAround :: (Char -> Bool) -> Text -> Text-dropAround p = dropWhile p . dropWhileEnd p-{-# INLINE [1] dropAround #-}---- | /O(n)/ Remove leading white space from a string.  Equivalent to:------ > dropWhile isSpace-stripStart :: Text -> Text-stripStart = dropWhile isSpace-{-# INLINE stripStart #-}---- | /O(n)/ Remove trailing white space from a string.  Equivalent to:------ > dropWhileEnd isSpace-stripEnd :: Text -> Text-stripEnd = dropWhileEnd isSpace-{-# INLINE [1] stripEnd #-}---- | /O(n)/ Remove leading and trailing white space from a string.--- Equivalent to:------ > dropAround isSpace-strip :: Text -> Text-strip = dropAround isSpace-{-# INLINE [1] strip #-}---- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a--- prefix of @t@ of length @n@, and whose second is the remainder of--- the string. It is equivalent to @('take' n t, 'drop' n t)@.-splitAt :: Int64 -> Text -> (Text, Text)-splitAt = loop-  where loop _ Empty      = (empty, empty)-        loop n t | n <= 0 = (empty, t)-        loop n (Chunk t ts)-             | n < len   = let (t',t'') = T.splitAt (fromIntegral n) t-                           in (Chunk t' Empty, Chunk t'' ts)-             | otherwise = let (ts',ts'') = loop (n - len) ts-                           in (Chunk t ts', ts'')-             where len = fromIntegral (T.length t)---- | /O(n)/ 'splitAtWord' @n t@ returns a strict pair whose first--- element is a prefix of @t@ whose chunks contain @n@ 'Word16'--- values, and whose second is the remainder of the string.-splitAtWord :: Int64 -> Text -> PairS Text Text-splitAtWord _ Empty = empty :*: empty-splitAtWord x (Chunk c@(T.Text arr off len) cs)-    | y >= len  = let h :*: t = splitAtWord (x-fromIntegral len) cs-                  in  Chunk c h :*: t-    | otherwise = chunk (text arr off y) empty :*:-                  chunk (text arr (off+y) (len-y)) cs-    where y = fromIntegral x---- | /O(n+m)/ Find the first instance of @needle@ (which must be--- non-'null') in @haystack@.  The first element of the returned tuple--- is the prefix of @haystack@ before @needle@ is matched.  The second--- is the remainder of @haystack@, starting with the match.------ Examples:------ > breakOn "::" "a::b::c" ==> ("a", "::b::c")--- > breakOn "/" "foobar"   ==> ("foobar", "")------ Laws:------ > append prefix match == haystack--- >   where (prefix, match) = breakOn needle haystack------ If you need to break a string by a substring repeatedly (e.g. you--- want to break on every instance of a substring), use 'breakOnAll'--- instead, as it has lower startup overhead.------ This function is strict in its first argument, and lazy in its--- second.------ In (unlikely) bad cases, this function's time complexity degrades--- towards /O(n*m)/.-breakOn :: Text -> Text -> (Text, Text)-breakOn pat src-    | null pat  = emptyError "breakOn"-    | otherwise = case indices pat src of-                    []    -> (src, empty)-                    (x:_) -> let h :*: t = splitAtWord x src-                             in  (h, t)---- | /O(n+m)/ Similar to 'breakOn', but searches from the end of the string.------ The first element of the returned tuple is the prefix of @haystack@--- up to and including the last match of @needle@.  The second is the--- remainder of @haystack@, following the match.------ > breakOnEnd "::" "a::b::c" ==> ("a::b::", "c")-breakOnEnd :: Text -> Text -> (Text, Text)-breakOnEnd pat src = let (a,b) = breakOn (reverse pat) (reverse src)-                   in  (reverse b, reverse a)-{-# INLINE breakOnEnd #-}---- | /O(n+m)/ Find all non-overlapping instances of @needle@ in--- @haystack@.  Each element of the returned list consists of a pair:------ * The entire string prior to the /k/th match (i.e. the prefix)------ * The /k/th match, followed by the remainder of the string------ Examples:------ > breakOnAll "::" ""--- > ==> []--- > breakOnAll "/" "a/b/c/"--- > ==> [("a", "/b/c/"), ("a/b", "/c/"), ("a/b/c", "/")]------ This function is strict in its first argument, and lazy in its--- second.------ In (unlikely) bad cases, this function's time complexity degrades--- towards /O(n*m)/.------ The @needle@ parameter may not be empty.-breakOnAll :: Text              -- ^ @needle@ to search for-           -> Text              -- ^ @haystack@ in which to search-           -> [(Text, Text)]-breakOnAll pat src-    | null pat  = emptyError "breakOnAll"-    | otherwise = go 0 empty src (indices pat src)-  where-    go !n p s (x:xs) = let h :*: t = splitAtWord (x-n) s-                           h'      = append p h-                       in (h',t) : go x h' t xs-    go _  _ _ _      = []---- | /O(n)/ 'break' is like 'span', but the prefix returned is over--- elements that fail the predicate @p@.-break :: (Char -> Bool) -> Text -> (Text, Text)-break p t0 = break' t0-  where break' Empty          = (empty, empty)-        break' c@(Chunk t ts) =-          case T.findIndex p t of-            Nothing      -> let (ts', ts'') = break' ts-                            in (Chunk t ts', ts'')-            Just n | n == 0    -> (Empty, c)-                   | otherwise -> let (a,b) = T.splitAt n t-                                  in (Chunk a Empty, Chunk b ts)---- | /O(n)/ 'span', applied to a predicate @p@ and text @t@, returns--- a pair whose first element is the longest prefix (possibly empty)--- of @t@ of elements that satisfy @p@, and whose second is the--- remainder of the list.-span :: (Char -> Bool) -> Text -> (Text, Text)-span p = break (not . p)-{-# INLINE span #-}---- | The 'group' function takes a 'Text' and returns a list of 'Text's--- such that the concatenation of the result is equal to the argument.--- Moreover, each sublist in the result contains only equal elements.--- For example,------ > group "Mississippi" = ["M","i","ss","i","ss","i","pp","i"]------ It is a special case of 'groupBy', which allows the programmer to--- supply their own equality test.-group :: Text -> [Text]-group =  groupBy (==)-{-# INLINE group #-}---- | The 'groupBy' function is the non-overloaded version of 'group'.-groupBy :: (Char -> Char -> Bool) -> Text -> [Text]-groupBy _  Empty        = []-groupBy eq (Chunk t ts) = cons x ys : groupBy eq zs-                          where (ys,zs) = span (eq x) xs-                                x  = T.unsafeHead t-                                xs = chunk (T.unsafeTail t) ts---- | /O(n)/ Return all initial segments of the given 'Text',--- shortest first.-inits :: Text -> [Text]-inits = (Empty :) . inits'-  where inits' Empty        = []-        inits' (Chunk t ts) = L.map (\t' -> Chunk t' Empty) (L.tail (T.inits t))-                           ++ L.map (Chunk t) (inits' ts)---- | /O(n)/ Return all final segments of the given 'Text', longest--- first.-tails :: Text -> [Text]-tails Empty         = Empty : []-tails ts@(Chunk t ts')-  | T.length t == 1 = ts : tails ts'-  | otherwise       = ts : tails (Chunk (T.unsafeTail t) ts')---- $split------ Splitting functions in this library do not perform character-wise--- copies to create substrings; they just construct new 'Text's that--- are slices of the original.---- | /O(m+n)/ Break a 'Text' into pieces separated by the first 'Text'--- argument (which cannot be an empty string), consuming the--- delimiter. An empty delimiter is invalid, and will cause an error--- to be raised.------ Examples:------ > splitOn "\r\n" "a\r\nb\r\nd\r\ne" == ["a","b","d","e"]--- > splitOn "aaa"  "aaaXaaaXaaaXaaa"  == ["","X","X","X",""]--- > splitOn "x"    "x"                == ["",""]------ and------ > intercalate s . splitOn s         == id--- > splitOn (singleton c)             == split (==c)------ (Note: the string @s@ to split on above cannot be empty.)------ This function is strict in its first argument, and lazy in its--- second.------ In (unlikely) bad cases, this function's time complexity degrades--- towards /O(n*m)/.-splitOn :: Text-        -- ^ String to split on. If this string is empty, an error-        -- will occur.-        -> Text-        -- ^ Input text.-        -> [Text]-splitOn pat src-    | null pat        = emptyError "splitOn"-    | isSingleton pat = split (== head pat) src-    | otherwise       = go 0 (indices pat src) src-  where-    go  _ []     cs = [cs]-    go !i (x:xs) cs = let h :*: t = splitAtWord (x-i) cs-                      in  h : go (x+l) xs (dropWords l t)-    l = foldlChunks (\a (T.Text _ _ b) -> a + fromIntegral b) 0 pat-{-# INLINE [1] splitOn #-}--{-# RULES-"LAZY TEXT splitOn/singleton -> split/==" [~1] forall c t.-    splitOn (singleton c) t = split (==c) t-  #-}---- | /O(n)/ Splits a 'Text' into components delimited by separators,--- where the predicate returns True for a separator element.  The--- resulting components do not contain the separators.  Two adjacent--- separators result in an empty component in the output.  eg.------ > split (=='a') "aabbaca" == ["","","bb","c",""]--- > split (=='a') []        == [""]-split :: (Char -> Bool) -> Text -> [Text]-split _ Empty = [Empty]-split p (Chunk t0 ts0) = comb [] (T.split p t0) ts0-  where comb acc (s:[]) Empty        = revChunks (s:acc) : []-        comb acc (s:[]) (Chunk t ts) = comb (s:acc) (T.split p t) ts-        comb acc (s:ss) ts           = revChunks (s:acc) : comb [] ss ts-        comb _   []     _            = impossibleError "split"-{-# INLINE split #-}---- | /O(n)/ Splits a 'Text' into components of length @k@.  The last--- element may be shorter than the other chunks, depending on the--- length of the input. Examples:------ > chunksOf 3 "foobarbaz"   == ["foo","bar","baz"]--- > chunksOf 4 "haskell.org" == ["hask","ell.","org"]-chunksOf :: Int64 -> Text -> [Text]-chunksOf k = go-  where-    go t = case splitAt k t of-             (a,b) | null a    -> []-                   | otherwise -> a : go b-{-# INLINE chunksOf #-}---- | /O(n)/ Breaks a 'Text' up into a list of 'Text's at--- newline 'Char's. The resulting strings do not contain newlines.-lines :: Text -> [Text]-lines Empty = []-lines t = let (l,t') = break ((==) '\n') t-          in l : if null t' then []-                 else lines (tail t')---- | /O(n)/ Breaks a 'Text' up into a list of words, delimited by 'Char's--- representing white space.-words :: Text -> [Text]-words = L.filter (not . null) . split isSpace-{-# INLINE words #-}---- | /O(n)/ Joins lines, after appending a terminating newline to--- each.-unlines :: [Text] -> Text-unlines = concat . L.map (`snoc` '\n')-{-# INLINE unlines #-}---- | /O(n)/ Joins words using single space characters.-unwords :: [Text] -> Text-unwords = intercalate (singleton ' ')-{-# INLINE unwords #-}---- | /O(n)/ The 'isPrefixOf' function takes two 'Text's and returns--- 'True' iff the first is a prefix of the second.  Subject to fusion.-isPrefixOf :: Text -> Text -> Bool-isPrefixOf Empty _  = True-isPrefixOf _ Empty  = False-isPrefixOf (Chunk x xs) (Chunk y ys)-    | lx == ly  = x == y  && isPrefixOf xs ys-    | lx <  ly  = x == yh && isPrefixOf xs (Chunk yt ys)-    | otherwise = xh == y && isPrefixOf (Chunk xt xs) ys-  where (xh,xt) = T.splitAt ly x-        (yh,yt) = T.splitAt lx y-        lx = T.length x-        ly = T.length y-{-# INLINE [1] isPrefixOf #-}--{-# RULES-"LAZY TEXT isPrefixOf -> fused" [~1] forall s t.-    isPrefixOf s t = S.isPrefixOf (stream s) (stream t)-"LAZY TEXT isPrefixOf -> unfused" [1] forall s t.-    S.isPrefixOf (stream s) (stream t) = isPrefixOf s t-  #-}---- | /O(n)/ The 'isSuffixOf' function takes two 'Text's and returns--- 'True' iff the first is a suffix of the second.-isSuffixOf :: Text -> Text -> Bool-isSuffixOf x y = reverse x `isPrefixOf` reverse y-{-# INLINE isSuffixOf #-}--- TODO: a better implementation---- | /O(n+m)/ The 'isInfixOf' function takes two 'Text's and returns--- 'True' iff the first is contained, wholly and intact, anywhere--- within the second.------ This function is strict in its first argument, and lazy in its--- second.------ In (unlikely) bad cases, this function's time complexity degrades--- towards /O(n*m)/.-isInfixOf :: Text -> Text -> Bool-isInfixOf needle haystack-    | null needle        = True-    | isSingleton needle = S.elem (head needle) . S.stream $ haystack-    | otherwise          = not . L.null . indices needle $ haystack-{-# INLINE [1] isInfixOf #-}--{-# RULES-"LAZY TEXT isInfixOf/singleton -> S.elem/S.stream" [~1] forall n h.-    isInfixOf (singleton n) h = S.elem n (S.stream h)-  #-}------------------------------------------------------------------------------------ * View patterns---- | /O(n)/ Return the suffix of the second string if its prefix--- matches the entire first string.------ Examples:------ > stripPrefix "foo" "foobar" == Just "bar"--- > stripPrefix ""    "baz"    == Just "baz"--- > stripPrefix "foo" "quux"   == Nothing------ This is particularly useful with the @ViewPatterns@ extension to--- GHC, as follows:------ > {-# LANGUAGE ViewPatterns #-}--- > import Data.Text.Lazy as T--- >--- > fnordLength :: Text -> Int--- > fnordLength (stripPrefix "fnord" -> Just suf) = T.length suf--- > fnordLength _                                 = -1-stripPrefix :: Text -> Text -> Maybe Text-stripPrefix p t-    | null p    = Just t-    | otherwise = case commonPrefixes p t of-                    Just (_,c,r) | null c -> Just r-                    _                     -> Nothing---- | /O(n)/ Find the longest non-empty common prefix of two strings--- and return it, along with the suffixes of each string at which they--- no longer match.------ If the strings do not have a common prefix or either one is empty,--- this function returns 'Nothing'.------ Examples:------ > commonPrefixes "foobar" "fooquux" == Just ("foo","bar","quux")--- > commonPrefixes "veeble" "fetzer"  == Nothing--- > commonPrefixes "" "baz"           == Nothing-commonPrefixes :: Text -> Text -> Maybe (Text,Text,Text)-commonPrefixes Empty _ = Nothing-commonPrefixes _ Empty = Nothing-commonPrefixes a0 b0   = Just (go a0 b0 [])-  where-    go t0@(Chunk x xs) t1@(Chunk y ys) ps-        = case T.commonPrefixes x y of-            Just (p,a,b)-              | T.null a  -> go xs (chunk b ys) (p:ps)-              | T.null b  -> go (chunk a xs) ys (p:ps)-              | otherwise -> (fromChunks (L.reverse (p:ps)),chunk a xs, chunk b ys)-            Nothing       -> (fromChunks (L.reverse ps),t0,t1)-    go t0 t1 ps = (fromChunks (L.reverse ps),t0,t1)---- | /O(n)/ Return the prefix of the second string if its suffix--- matches the entire first string.------ Examples:------ > stripSuffix "bar" "foobar" == Just "foo"--- > stripSuffix ""    "baz"    == Just "baz"--- > stripSuffix "foo" "quux"   == Nothing------ This is particularly useful with the @ViewPatterns@ extension to--- GHC, as follows:------ > {-# LANGUAGE ViewPatterns #-}--- > import Data.Text.Lazy as T--- >--- > quuxLength :: Text -> Int--- > quuxLength (stripSuffix "quux" -> Just pre) = T.length pre--- > quuxLength _                                = -1-stripSuffix :: Text -> Text -> Maybe Text-stripSuffix p t = reverse `fmap` stripPrefix (reverse p) (reverse t)---- | /O(n)/ 'filter', applied to a predicate and a 'Text',--- returns a 'Text' containing those characters that satisfy the--- predicate.-filter :: (Char -> Bool) -> Text -> Text-filter p t = unstream (S.filter p (stream t))-{-# INLINE filter #-}---- | /O(n)/ The 'find' function takes a predicate and a 'Text', and--- returns the first element in matching the predicate, or 'Nothing'--- if there is no such element. Subject to fusion.-find :: (Char -> Bool) -> Text -> Maybe Char-find p t = S.findBy p (stream t)-{-# INLINE find #-}---- | /O(n)/ The 'partition' function takes a predicate and a 'Text',--- and returns the pair of 'Text's with elements which do and do not--- satisfy the predicate, respectively; i.e.------ > partition p t == (filter p t, filter (not . p) t)-partition :: (Char -> Bool) -> Text -> (Text, Text)-partition p t = (filter p t, filter (not . p) t)-{-# INLINE partition #-}---- | /O(n)/ 'Text' index (subscript) operator, starting from 0.--- Subject to fusion.-index :: Text -> Int64 -> Char-index t n = S.index (stream t) n-{-# INLINE index #-}---- | /O(n+m)/ The 'count' function returns the number of times the--- query string appears in the given 'Text'. An empty query string is--- invalid, and will cause an error to be raised.------ In (unlikely) bad cases, this function's time complexity degrades--- towards /O(n*m)/.-count :: Text -> Text -> Int64-count pat src-    | null pat        = emptyError "count"-    | otherwise       = go 0 (indices pat src)-  where go !n []     = n-        go !n (_:xs) = go (n+1) xs-{-# INLINE [1] count #-}--{-# RULES-"LAZY TEXT count/singleton -> countChar" [~1] forall c t.-    count (singleton c) t = countChar c t-  #-}---- | /O(n)/ The 'countChar' function returns the number of times the--- query element appears in the given 'Text'.  Subject to fusion.-countChar :: Char -> Text -> Int64-countChar c t = S.countChar c (stream t)---- | /O(n)/ 'zip' takes two 'Text's and returns a list of--- corresponding pairs of bytes. If one input 'Text' is short,--- excess elements of the longer 'Text' are discarded. This is--- equivalent to a pair of 'unpack' operations.-zip :: Text -> Text -> [(Char,Char)]-zip a b = S.unstreamList $ S.zipWith (,) (stream a) (stream b)-{-# INLINE [0] zip #-}---- | /O(n)/ 'zipWith' generalises 'zip' by zipping with the function--- given as the first argument, instead of a tupling function.--- Performs replacement on invalid scalar values.-zipWith :: (Char -> Char -> Char) -> Text -> Text -> Text-zipWith f t1 t2 = unstream (S.zipWith g (stream t1) (stream t2))-    where g a b = safe (f a b)-{-# INLINE [0] zipWith #-}--revChunks :: [T.Text] -> Text-revChunks = L.foldl' (flip chunk) Empty--emptyError :: String -> a-emptyError fun = P.error ("Data.Text.Lazy." ++ fun ++ ": empty input")--impossibleError :: String -> a-impossibleError fun = P.error ("Data.Text.Lazy." ++ fun ++ ": impossible case")
− Data/Text/Lazy/Builder.hs
@@ -1,57 +0,0 @@-{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}-#if __GLASGOW_HASKELL__ >= 702-{-# LANGUAGE Trustworthy #-}-#endif---------------------------------------------------------------------------------- |--- Module      : Data.Text.Lazy.Builder--- Copyright   : (c) 2013 Bryan O'Sullivan---               (c) 2010 Johan Tibell--- License     : BSD-style (see LICENSE)------ Maintainer  : Johan Tibell <johan.tibell@gmail.com>--- Portability : portable to Hugs and GHC------ Efficient construction of lazy @Text@ values.  The principal--- operations on a @Builder@ are @singleton@, @fromText@, and--- @fromLazyText@, which construct new builders, and 'mappend', which--- concatenates two builders.------ To get maximum performance when building lazy @Text@ values using a--- builder, associate @mappend@ calls to the right.  For example,--- prefer------ > singleton 'a' `mappend` (singleton 'b' `mappend` singleton 'c')------ to------ > singleton 'a' `mappend` singleton 'b' `mappend` singleton 'c'------ as the latter associates @mappend@ to the left. Or, equivalently,--- prefer------  > singleton 'a' <> singleton 'b' <> singleton 'c'------ since the '<>' from recent versions of 'Data.Monoid' associates--- to the right.---------------------------------------------------------------------------------module Data.Text.Lazy.Builder-   ( -- * The Builder type-     Builder-   , toLazyText-   , toLazyTextWith--     -- * Constructing Builders-   , singleton-   , fromText-   , fromLazyText-   , fromString--     -- * Flushing the buffer state-   , flush-   ) where--import Data.Text.Internal.Builder
− Data/Text/Lazy/Builder/Int.hs
@@ -1,264 +0,0 @@-{-# LANGUAGE BangPatterns, CPP, MagicHash, RankNTypes, ScopedTypeVariables,-    UnboxedTuples #-}-#if __GLASGOW_HASKELL__ >= 702-{-# LANGUAGE Trustworthy #-}-#endif---- Module:      Data.Text.Lazy.Builder.Int--- Copyright:   (c) 2013 Bryan O'Sullivan---              (c) 2011 MailRank, Inc.--- License:     BSD-style--- Maintainer:  Bryan O'Sullivan <bos@serpentine.com>--- Portability: portable------ Efficiently write an integral value to a 'Builder'.--module Data.Text.Lazy.Builder.Int-    (-      decimal-    , hexadecimal-    ) where--import Data.Int (Int8, Int16, Int32, Int64)-import Data.Monoid (mempty)-import qualified Data.ByteString.Unsafe as B-import Data.Text.Internal.Builder.Functions ((<>), i2d)-import Data.Text.Internal.Builder-import Data.Text.Internal.Builder.Int.Digits (digits)-import Data.Text.Array-import Data.Word (Word, Word8, Word16, Word32, Word64)-import GHC.Base (quotInt, remInt)-import GHC.Num (quotRemInteger)-import GHC.Types (Int(..))-import Control.Monad.ST-#if MIN_VERSION_base(4,11,0)-import Prelude hiding ((<>))-#endif--#ifdef  __GLASGOW_HASKELL__-# if defined(INTEGER_GMP)-import GHC.Integer.GMP.Internals (Integer(S#))-# elif defined(INTEGER_SIMPLE)-import GHC.Integer-# else-# error "You need to use either GMP or integer-simple."-# endif-#endif--#if defined(INTEGER_GMP) || defined(INTEGER_SIMPLE)-# define PAIR(a,b) (# a,b #)-#else-# define PAIR(a,b) (a,b)-#endif--decimal :: Integral a => a -> Builder-{-# RULES "decimal/Int8" decimal = boundedDecimal :: Int8 -> Builder #-}-{-# RULES "decimal/Int" decimal = boundedDecimal :: Int -> Builder #-}-{-# RULES "decimal/Int16" decimal = boundedDecimal :: Int16 -> Builder #-}-{-# RULES "decimal/Int32" decimal = boundedDecimal :: Int32 -> Builder #-}-{-# RULES "decimal/Int64" decimal = boundedDecimal :: Int64 -> Builder #-}-{-# RULES "decimal/Word" decimal = positive :: Data.Word.Word -> Builder #-}-{-# RULES "decimal/Word8" decimal = positive :: Word8 -> Builder #-}-{-# RULES "decimal/Word16" decimal = positive :: Word16 -> Builder #-}-{-# RULES "decimal/Word32" decimal = positive :: Word32 -> Builder #-}-{-# RULES "decimal/Word64" decimal = positive :: Word64 -> Builder #-}-{-# RULES "decimal/Integer" decimal = integer 10 :: Integer -> Builder #-}-decimal i = decimal' (<= -128) i-{-# NOINLINE decimal #-}--boundedDecimal :: (Integral a, Bounded a) => a -> Builder-{-# SPECIALIZE boundedDecimal :: Int -> Builder #-}-{-# SPECIALIZE boundedDecimal :: Int8 -> Builder #-}-{-# SPECIALIZE boundedDecimal :: Int16 -> Builder #-}-{-# SPECIALIZE boundedDecimal :: Int32 -> Builder #-}-{-# SPECIALIZE boundedDecimal :: Int64 -> Builder #-}-boundedDecimal i = decimal' (== minBound) i--decimal' :: (Integral a) => (a -> Bool) -> a -> Builder-{-# INLINE decimal' #-}-decimal' p i-    | i < 0 = if p i-              then let (q, r) = i `quotRem` 10-                       qq = -q-                       !n = countDigits qq-                   in writeN (n + 2) $ \marr off -> do-                       unsafeWrite marr off minus-                       posDecimal marr (off+1) n qq-                       unsafeWrite marr (off+n+1) (i2w (-r))-              else let j = -i-                       !n = countDigits j-                   in writeN (n + 1) $ \marr off ->-                       unsafeWrite marr off minus >> posDecimal marr (off+1) n j-    | otherwise = positive i--positive :: (Integral a) => a -> Builder-{-# SPECIALIZE positive :: Int -> Builder #-}-{-# SPECIALIZE positive :: Int8 -> Builder #-}-{-# SPECIALIZE positive :: Int16 -> Builder #-}-{-# SPECIALIZE positive :: Int32 -> Builder #-}-{-# SPECIALIZE positive :: Int64 -> Builder #-}-{-# SPECIALIZE positive :: Word -> Builder #-}-{-# SPECIALIZE positive :: Word8 -> Builder #-}-{-# SPECIALIZE positive :: Word16 -> Builder #-}-{-# SPECIALIZE positive :: Word32 -> Builder #-}-{-# SPECIALIZE positive :: Word64 -> Builder #-}-positive i-    | i < 10    = writeN 1 $ \marr off -> unsafeWrite marr off (i2w i)-    | otherwise = let !n = countDigits i-                  in writeN n $ \marr off -> posDecimal marr off n i--posDecimal :: (Integral a) =>-              forall s. MArray s -> Int -> Int -> a -> ST s ()-{-# INLINE posDecimal #-}-posDecimal marr off0 ds v0 = go (off0 + ds - 1) v0-  where go off v-           | v >= 100 = do-               let (q, r) = v `quotRem` 100-               write2 off r-               go (off - 2) q-           | v < 10    = unsafeWrite marr off (i2w v)-           | otherwise = write2 off v-        write2 off i0 = do-          let i = fromIntegral i0; j = i + i-          unsafeWrite marr off $ get (j + 1)-          unsafeWrite marr (off - 1) $ get j-        get = fromIntegral . B.unsafeIndex digits--minus, zero :: Word16-{-# INLINE minus #-}-{-# INLINE zero #-}-minus = 45-zero = 48--i2w :: (Integral a) => a -> Word16-{-# INLINE i2w #-}-i2w v = zero + fromIntegral v--countDigits :: (Integral a) => a -> Int-{-# INLINE countDigits #-}-countDigits v0-  | fromIntegral v64 == v0 = go 1 v64-  | otherwise              = goBig 1 (fromIntegral v0)-  where v64 = fromIntegral v0-        goBig !k (v :: Integer)-           | v > big   = goBig (k + 19) (v `quot` big)-           | otherwise = go k (fromIntegral v)-        big = 10000000000000000000-        go !k (v :: Word64)-           | v < 10    = k-           | v < 100   = k + 1-           | v < 1000  = k + 2-           | v < 1000000000000 =-               k + if v < 100000000-                   then if v < 1000000-                        then if v < 10000-                             then 3-                             else 4 + fin v 100000-                        else 6 + fin v 10000000-                   else if v < 10000000000-                        then 8 + fin v 1000000000-                        else 10 + fin v 100000000000-           | otherwise = go (k + 12) (v `quot` 1000000000000)-        fin v n = if v >= n then 1 else 0--hexadecimal :: Integral a => a -> Builder-{-# SPECIALIZE hexadecimal :: Int -> Builder #-}-{-# SPECIALIZE hexadecimal :: Int8 -> Builder #-}-{-# SPECIALIZE hexadecimal :: Int16 -> Builder #-}-{-# SPECIALIZE hexadecimal :: Int32 -> Builder #-}-{-# SPECIALIZE hexadecimal :: Int64 -> Builder #-}-{-# SPECIALIZE hexadecimal :: Word -> Builder #-}-{-# SPECIALIZE hexadecimal :: Word8 -> Builder #-}-{-# SPECIALIZE hexadecimal :: Word16 -> Builder #-}-{-# SPECIALIZE hexadecimal :: Word32 -> Builder #-}-{-# SPECIALIZE hexadecimal :: Word64 -> Builder #-}-{-# RULES "hexadecimal/Integer"-    hexadecimal = hexInteger :: Integer -> Builder #-}-hexadecimal i-    | i < 0     = error hexErrMsg-    | otherwise = go i-  where-    go n | n < 16    = hexDigit n-         | otherwise = go (n `quot` 16) <> hexDigit (n `rem` 16)-{-# NOINLINE[0] hexadecimal #-}--hexInteger :: Integer -> Builder-hexInteger i-    | i < 0     = error hexErrMsg-    | otherwise = integer 16 i--hexErrMsg :: String-hexErrMsg = "Data.Text.Lazy.Builder.Int.hexadecimal: applied to negative number"--hexDigit :: Integral a => a -> Builder-hexDigit n-    | n <= 9    = singleton $! i2d (fromIntegral n)-    | otherwise = singleton $! toEnum (fromIntegral n + 87)-{-# INLINE hexDigit #-}--data T = T !Integer !Int--integer :: Int -> Integer -> Builder-#ifdef INTEGER_GMP-integer 10 (S# i#) = decimal (I# i#)-integer 16 (S# i#) = hexadecimal (I# i#)-#endif-integer base i-    | i < 0     = singleton '-' <> go (-i)-    | otherwise = go i-  where-    go n | n < maxInt = int (fromInteger n)-         | otherwise  = putH (splitf (maxInt * maxInt) n)--    splitf p n-      | p > n       = [n]-      | otherwise   = splith p (splitf (p*p) n)--    splith p (n:ns) = case n `quotRemInteger` p of-                        PAIR(q,r) | q > 0     -> q : r : splitb p ns-                                  | otherwise -> r : splitb p ns-    splith _ _      = error "splith: the impossible happened."--    splitb p (n:ns) = case n `quotRemInteger` p of-                        PAIR(q,r) -> q : r : splitb p ns-    splitb _ _      = []--    T maxInt10 maxDigits10 =-        until ((>mi) . (*10) . fstT) (\(T n d) -> T (n*10) (d+1)) (T 10 1)-      where mi = fromIntegral (maxBound :: Int)-    T maxInt16 maxDigits16 =-        until ((>mi) . (*16) . fstT) (\(T n d) -> T (n*16) (d+1)) (T 16 1)-      where mi = fromIntegral (maxBound :: Int)--    fstT (T a _) = a--    maxInt | base == 10 = maxInt10-           | otherwise  = maxInt16-    maxDigits | base == 10 = maxDigits10-              | otherwise  = maxDigits16--    putH (n:ns) = case n `quotRemInteger` maxInt of-                    PAIR(x,y)-                        | q > 0     -> int q <> pblock r <> putB ns-                        | otherwise -> int r <> putB ns-                        where q = fromInteger x-                              r = fromInteger y-    putH _ = error "putH: the impossible happened"--    putB (n:ns) = case n `quotRemInteger` maxInt of-                    PAIR(x,y) -> pblock q <> pblock r <> putB ns-                        where q = fromInteger x-                              r = fromInteger y-    putB _ = Data.Monoid.mempty--    int :: Int -> Builder-    int x | base == 10 = decimal x-          | otherwise  = hexadecimal x--    pblock = loop maxDigits-      where-        loop !d !n-            | d == 1    = hexDigit n-            | otherwise = loop (d-1) q <> hexDigit r-            where q = n `quotInt` base-                  r = n `remInt` base
− Data/Text/Lazy/Builder/RealFloat.hs
@@ -1,253 +0,0 @@-{-# LANGUAGE CPP, OverloadedStrings #-}-#if __GLASGOW_HASKELL__ >= 702-{-# LANGUAGE Trustworthy #-}-#endif---- |--- Module:    Data.Text.Lazy.Builder.RealFloat--- Copyright: (c) The University of Glasgow 1994-2002--- License:   see libraries/base/LICENSE------ Write a floating point value to a 'Builder'.--module Data.Text.Lazy.Builder.RealFloat-    (-      FPFormat(..)-    , realFloat-    , formatRealFloat-    ) where--import Data.Array.Base (unsafeAt)-import Data.Array.IArray-import Data.Text.Internal.Builder.Functions ((<>), i2d)-import Data.Text.Lazy.Builder.Int (decimal)-import Data.Text.Internal.Builder.RealFloat.Functions (roundTo)-import Data.Text.Lazy.Builder-import qualified Data.Text as T-#if MIN_VERSION_base(4,11,0)-import Prelude hiding ((<>))-#endif---- | Control the rendering of floating point numbers.-data FPFormat = Exponent-              -- ^ Scientific notation (e.g. @2.3e123@).-              | Fixed-              -- ^ Standard decimal notation.-              | Generic-              -- ^ Use decimal notation for values between @0.1@ and-              -- @9,999,999@, and scientific notation otherwise.-                deriving (Enum, Read, Show)---- | Show a signed 'RealFloat' value to full precision,--- using standard decimal notation for arguments whose absolute value lies--- between @0.1@ and @9,999,999@, and scientific notation otherwise.-realFloat :: (RealFloat a) => a -> Builder-{-# SPECIALIZE realFloat :: Float -> Builder #-}-{-# SPECIALIZE realFloat :: Double -> Builder #-}-realFloat x = formatRealFloat Generic Nothing x---- | Encode a signed 'RealFloat' according to 'FPFormat' and optionally requested precision.------ This corresponds to the @show{E,F,G}Float@ operations provided by @base@'s "Numeric" module.------ __NOTE__: The functions in @base-4.12@ changed the serialisation in--- case of a @Just 0@ precision; this version of @text@ still provides--- the serialisation as implemented in @base-4.11@. The next major--- version of @text@ will switch to the more correct @base-4.12@ serialisation.-formatRealFloat :: (RealFloat a) =>-                   FPFormat-                -> Maybe Int  -- ^ Number of decimal places to render.-                -> a-                -> Builder-{-# SPECIALIZE formatRealFloat :: FPFormat -> Maybe Int -> Float -> Builder #-}-{-# SPECIALIZE formatRealFloat :: FPFormat -> Maybe Int -> Double -> Builder #-}-formatRealFloat fmt decs x-   | isNaN x                   = "NaN"-   | isInfinite x              = if x < 0 then "-Infinity" else "Infinity"-   | x < 0 || isNegativeZero x = singleton '-' <> doFmt fmt (floatToDigits (-x))-   | otherwise                 = doFmt fmt (floatToDigits x)- where-  doFmt format (is, e) =-    let ds = map i2d is in-    case format of-     Generic ->-      doFmt (if e < 0 || e > 7 then Exponent else Fixed)-            (is,e)-     Exponent ->-      case decs of-       Nothing ->-        let show_e' = decimal (e-1) in-        case ds of-          "0"     -> "0.0e0"-          [d]     -> singleton d <> ".0e" <> show_e'-          (d:ds') -> singleton d <> singleton '.' <> fromString ds' <> singleton 'e' <> show_e'-          []      -> error "formatRealFloat/doFmt/Exponent/Nothing: []"-       Just dec ->-        let dec' = max dec 1 in-        case is of-         [0] -> "0." <> fromText (T.replicate dec' "0") <> "e0"-         _ ->-          let (ei,is') = roundTo (dec'+1) is-              is'' = map i2d (if ei > 0 then init is' else is')-          in case is'' of-               [] -> error "formatRealFloat/doFmt/Exponent/Just: []"-               (d:ds') -> singleton d <> singleton '.' <> fromString ds' <> singleton 'e' <> decimal (e-1+ei)-     Fixed ->-      let-       mk0 ls = case ls of { "" -> "0" ; _ -> fromString ls}-      in-      case decs of-       Nothing-          | e <= 0    -> "0." <> fromText (T.replicate (-e) "0") <> fromString ds-          | otherwise ->-             let-                f 0 s    rs  = mk0 (reverse s) <> singleton '.' <> mk0 rs-                f n s    ""  = f (n-1) ('0':s) ""-                f n s (r:rs) = f (n-1) (r:s) rs-             in-                f e "" ds-       Just dec ->-        let dec' = max dec 0 in-        if e >= 0 then-         let-          (ei,is') = roundTo (dec' + e) is-          (ls,rs)  = splitAt (e+ei) (map i2d is')-         in-         mk0 ls <> (if null rs then "" else singleton '.' <> fromString rs)-        else-         let (ei,is') = roundTo dec' (replicate (-e) 0 ++ is)-             is'' = map i2d (if ei > 0 then is' else 0:is')-         in case is'' of-              [] -> error "formatRealFloat/doFmt/Fixed: []"-              (d:ds') -> singleton d <> (if null ds' then "" else singleton '.' <> fromString ds')----- Based on "Printing Floating-Point Numbers Quickly and Accurately"--- by R.G. Burger and R.K. Dybvig in PLDI 96.--- This version uses a much slower logarithm estimator. It should be improved.---- | 'floatToDigits' takes a base and a non-negative 'RealFloat' number,--- and returns a list of digits and an exponent.--- In particular, if @x>=0@, and------ > floatToDigits base x = ([d1,d2,...,dn], e)------ then------      (1) @n >= 1@------      (2) @x = 0.d1d2...dn * (base**e)@------      (3) @0 <= di <= base-1@--floatToDigits :: (RealFloat a) => a -> ([Int], Int)-{-# SPECIALIZE floatToDigits :: Float -> ([Int], Int) #-}-{-# SPECIALIZE floatToDigits :: Double -> ([Int], Int) #-}-floatToDigits 0 = ([0], 0)-floatToDigits x =- let-  (f0, e0) = decodeFloat x-  (minExp0, _) = floatRange x-  p = floatDigits x-  b = floatRadix x-  minExp = minExp0 - p -- the real minimum exponent-  -- Haskell requires that f be adjusted so denormalized numbers-  -- will have an impossibly low exponent.  Adjust for this.-  (f, e) =-   let n = minExp - e0 in-   if n > 0 then (f0 `quot` (expt b n), e0+n) else (f0, e0)-  (r, s, mUp, mDn) =-   if e >= 0 then-    let be = expt b e in-    if f == expt b (p-1) then-      (f*be*b*2, 2*b, be*b, be)     -- according to Burger and Dybvig-    else-      (f*be*2, 2, be, be)-   else-    if e > minExp && f == expt b (p-1) then-      (f*b*2, expt b (-e+1)*2, b, 1)-    else-      (f*2, expt b (-e)*2, 1, 1)-  k :: Int-  k =-   let-    k0 :: Int-    k0 =-     if b == 2 then-        -- logBase 10 2 is very slightly larger than 8651/28738-        -- (about 5.3558e-10), so if log x >= 0, the approximation-        -- k1 is too small, hence we add one and need one fixup step less.-        -- If log x < 0, the approximation errs rather on the high side.-        -- That is usually more than compensated for by ignoring the-        -- fractional part of logBase 2 x, but when x is a power of 1/2-        -- or slightly larger and the exponent is a multiple of the-        -- denominator of the rational approximation to logBase 10 2,-        -- k1 is larger than logBase 10 x. If k1 > 1 + logBase 10 x,-        -- we get a leading zero-digit we don't want.-        -- With the approximation 3/10, this happened for-        -- 0.5^1030, 0.5^1040, ..., 0.5^1070 and values close above.-        -- The approximation 8651/28738 guarantees k1 < 1 + logBase 10 x-        -- for IEEE-ish floating point types with exponent fields-        -- <= 17 bits and mantissae of several thousand bits, earlier-        -- convergents to logBase 10 2 would fail for long double.-        -- Using quot instead of div is a little faster and requires-        -- fewer fixup steps for negative lx.-        let lx = p - 1 + e0-            k1 = (lx * 8651) `quot` 28738-        in if lx >= 0 then k1 + 1 else k1-     else-        -- f :: Integer, log :: Float -> Float,-        --               ceiling :: Float -> Int-        ceiling ((log (fromInteger (f+1) :: Float) +-                 fromIntegral e * log (fromInteger b)) /-                   log 10)---WAS:            fromInt e * log (fromInteger b))--    fixup n =-      if n >= 0 then-        if r + mUp <= expt 10 n * s then n else fixup (n+1)-      else-        if expt 10 (-n) * (r + mUp) <= s then n else fixup (n+1)-   in-   fixup k0--  gen ds rn sN mUpN mDnN =-   let-    (dn, rn') = (rn * 10) `quotRem` sN-    mUpN' = mUpN * 10-    mDnN' = mDnN * 10-   in-   case (rn' < mDnN', rn' + mUpN' > sN) of-    (True,  False) -> dn : ds-    (False, True)  -> dn+1 : ds-    (True,  True)  -> if rn' * 2 < sN then dn : ds else dn+1 : ds-    (False, False) -> gen (dn:ds) rn' sN mUpN' mDnN'--  rds =-   if k >= 0 then-      gen [] r (s * expt 10 k) mUp mDn-   else-     let bk = expt 10 (-k) in-     gen [] (r * bk) s (mUp * bk) (mDn * bk)- in- (map fromIntegral (reverse rds), k)---- Exponentiation with a cache for the most common numbers.-minExpt, maxExpt :: Int-minExpt = 0-maxExpt = 1100--expt :: Integer -> Int -> Integer-expt base n-    | base == 2 && n >= minExpt && n <= maxExpt = expts `unsafeAt` n-    | base == 10 && n <= maxExpt10              = expts10 `unsafeAt` n-    | otherwise                                 = base^n--expts :: Array Int Integer-expts = array (minExpt,maxExpt) [(n,2^n) | n <- [minExpt .. maxExpt]]--maxExpt10 :: Int-maxExpt10 = 324--expts10 :: Array Int Integer-expts10 = array (minExpt,maxExpt10) [(n,10^n) | n <- [minExpt .. maxExpt10]]
− Data/Text/Lazy/Encoding.hs
@@ -1,250 +0,0 @@-{-# LANGUAGE BangPatterns,CPP #-}-#if __GLASGOW_HASKELL__ >= 702-{-# LANGUAGE Trustworthy #-}-#endif--- |--- Module      : Data.Text.Lazy.Encoding--- Copyright   : (c) 2009, 2010 Bryan O'Sullivan------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Portability : portable------ Functions for converting lazy 'Text' values to and from lazy--- 'ByteString', using several standard encodings.------ To gain access to a much larger family of encodings, use the--- <http://hackage.haskell.org/package/text-icu text-icu package>.--module Data.Text.Lazy.Encoding-    (-    -- * Decoding ByteStrings to Text-    -- $strict-      decodeASCII-    , decodeLatin1-    , decodeUtf8-    , decodeUtf16LE-    , decodeUtf16BE-    , decodeUtf32LE-    , decodeUtf32BE--    -- ** Catchable failure-    , decodeUtf8'--    -- ** Controllable error handling-    , decodeUtf8With-    , decodeUtf16LEWith-    , decodeUtf16BEWith-    , decodeUtf32LEWith-    , decodeUtf32BEWith--    -- * Encoding Text to ByteStrings-    , encodeUtf8-    , encodeUtf16LE-    , encodeUtf16BE-    , encodeUtf32LE-    , encodeUtf32BE--    -- * Encoding Text using ByteString Builders-    , encodeUtf8Builder-    , encodeUtf8BuilderEscaped-    ) where--import Control.Exception (evaluate, try)-import Data.Monoid (Monoid(..))-import Data.Text.Encoding.Error (OnDecodeError, UnicodeException, strictDecode)-import Data.Text.Internal.Lazy (Text(..), chunk, empty, foldrChunks)-import Data.Word (Word8)-import qualified Data.ByteString as S-import qualified Data.ByteString.Builder as B-import qualified Data.ByteString.Builder.Extra as B (safeStrategy, toLazyByteStringWith)-import qualified Data.ByteString.Builder.Prim as BP-import qualified Data.ByteString.Lazy as B-import qualified Data.ByteString.Lazy.Internal as B-import qualified Data.ByteString.Unsafe as B-import qualified Data.Text as T-import qualified Data.Text.Encoding as TE-import qualified Data.Text.Internal.Lazy.Encoding.Fusion as E-import qualified Data.Text.Internal.Lazy.Fusion as F-import Data.Text.Unsafe (unsafeDupablePerformIO)---- $strict------ All of the single-parameter functions for decoding bytestrings--- encoded in one of the Unicode Transformation Formats (UTF) operate--- in a /strict/ mode: each will throw an exception if given invalid--- input.------ Each function has a variant, whose name is suffixed with -'With',--- that gives greater control over the handling of decoding errors.--- For instance, 'decodeUtf8' will throw an exception, but--- 'decodeUtf8With' allows the programmer to determine what to do on a--- decoding error.---- | /Deprecated/.  Decode a 'ByteString' containing 7-bit ASCII--- encoded text.-decodeASCII :: B.ByteString -> Text-decodeASCII = decodeUtf8-{-# DEPRECATED decodeASCII "Use decodeUtf8 instead" #-}---- | Decode a 'ByteString' containing Latin-1 (aka ISO-8859-1) encoded text.-decodeLatin1 :: B.ByteString -> Text-decodeLatin1 = foldr (chunk . TE.decodeLatin1) empty . B.toChunks---- | Decode a 'ByteString' containing UTF-8 encoded text.-decodeUtf8With :: OnDecodeError -> B.ByteString -> Text-decodeUtf8With onErr (B.Chunk b0 bs0) =-    case TE.streamDecodeUtf8With onErr b0 of-      TE.Some t l f -> chunk t (go f l bs0)-  where-    go f0 _ (B.Chunk b bs) =-      case f0 b of-        TE.Some t l f -> chunk t (go f l bs)-    go _ l _-      | S.null l  = empty-      | otherwise = case onErr desc (Just (B.unsafeHead l)) of-                      Nothing -> empty-                      Just c  -> Chunk (T.singleton c) Empty-    desc = "Data.Text.Lazy.Encoding.decodeUtf8With: Invalid UTF-8 stream"-decodeUtf8With _ _ = empty---- | Decode a 'ByteString' containing UTF-8 encoded text that is known--- to be valid.------ If the input contains any invalid UTF-8 data, an exception will be--- thrown that cannot be caught in pure code.  For more control over--- the handling of invalid data, use 'decodeUtf8'' or--- 'decodeUtf8With'.-decodeUtf8 :: B.ByteString -> Text-decodeUtf8 = decodeUtf8With strictDecode-{-# INLINE[0] decodeUtf8 #-}---- This rule seems to cause performance loss.-{- RULES "LAZY STREAM stream/decodeUtf8' fusion" [1]-   forall bs. F.stream (decodeUtf8' bs) = E.streamUtf8 strictDecode bs #-}---- | Decode a 'ByteString' containing UTF-8 encoded text..------ If the input contains any invalid UTF-8 data, the relevant--- exception will be returned, otherwise the decoded text.------ /Note/: this function is /not/ lazy, as it must decode its entire--- input before it can return a result.  If you need lazy (streaming)--- decoding, use 'decodeUtf8With' in lenient mode.-decodeUtf8' :: B.ByteString -> Either UnicodeException Text-decodeUtf8' bs = unsafeDupablePerformIO $ do-                   let t = decodeUtf8 bs-                   try (evaluate (rnf t `seq` t))-  where-    rnf Empty        = ()-    rnf (Chunk _ ts) = rnf ts-{-# INLINE decodeUtf8' #-}---- | Encode text using UTF-8 encoding.-encodeUtf8 :: Text -> B.ByteString-encodeUtf8    Empty       = B.empty-encodeUtf8 lt@(Chunk t _) =-    B.toLazyByteStringWith strategy B.empty $ encodeUtf8Builder lt-  where-    -- To improve our small string performance, we use a strategy that-    -- allocates a buffer that is guaranteed to be large enough for the-    -- encoding of the first chunk, but not larger than the default-    -- B.smallChunkSize. We clamp the firstChunkSize to ensure that we don't-    -- generate too large buffers which hamper streaming.-    firstChunkSize  = min B.smallChunkSize (4 * (T.length t + 1))-    strategy        = B.safeStrategy firstChunkSize B.defaultChunkSize---- | Encode text to a ByteString 'B.Builder' using UTF-8 encoding.------ @since 1.1.0.0-encodeUtf8Builder :: Text -> B.Builder-encodeUtf8Builder =-    foldrChunks (\c b -> TE.encodeUtf8Builder c `mappend` b) Data.Monoid.mempty---- | Encode text using UTF-8 encoding and escape the ASCII characters using--- a 'BP.BoundedPrim'.------ Use this function is to implement efficient encoders for text-based formats--- like JSON or HTML.------ @since 1.1.0.0-{-# INLINE encodeUtf8BuilderEscaped #-}-encodeUtf8BuilderEscaped :: BP.BoundedPrim Word8 -> Text -> B.Builder-encodeUtf8BuilderEscaped prim =-    foldrChunks (\c b -> TE.encodeUtf8BuilderEscaped prim c `mappend` b) mempty---- | Decode text from little endian UTF-16 encoding.-decodeUtf16LEWith :: OnDecodeError -> B.ByteString -> Text-decodeUtf16LEWith onErr bs = F.unstream (E.streamUtf16LE onErr bs)-{-# INLINE decodeUtf16LEWith #-}---- | Decode text from little endian UTF-16 encoding.------ If the input contains any invalid little endian UTF-16 data, an--- exception will be thrown.  For more control over the handling of--- invalid data, use 'decodeUtf16LEWith'.-decodeUtf16LE :: B.ByteString -> Text-decodeUtf16LE = decodeUtf16LEWith strictDecode-{-# INLINE decodeUtf16LE #-}---- | Decode text from big endian UTF-16 encoding.-decodeUtf16BEWith :: OnDecodeError -> B.ByteString -> Text-decodeUtf16BEWith onErr bs = F.unstream (E.streamUtf16BE onErr bs)-{-# INLINE decodeUtf16BEWith #-}---- | Decode text from big endian UTF-16 encoding.------ If the input contains any invalid big endian UTF-16 data, an--- exception will be thrown.  For more control over the handling of--- invalid data, use 'decodeUtf16BEWith'.-decodeUtf16BE :: B.ByteString -> Text-decodeUtf16BE = decodeUtf16BEWith strictDecode-{-# INLINE decodeUtf16BE #-}---- | Encode text using little endian UTF-16 encoding.-encodeUtf16LE :: Text -> B.ByteString-encodeUtf16LE txt = B.fromChunks (foldrChunks ((:) . TE.encodeUtf16LE) [] txt)-{-# INLINE encodeUtf16LE #-}---- | Encode text using big endian UTF-16 encoding.-encodeUtf16BE :: Text -> B.ByteString-encodeUtf16BE txt = B.fromChunks (foldrChunks ((:) . TE.encodeUtf16BE) [] txt)-{-# INLINE encodeUtf16BE #-}---- | Decode text from little endian UTF-32 encoding.-decodeUtf32LEWith :: OnDecodeError -> B.ByteString -> Text-decodeUtf32LEWith onErr bs = F.unstream (E.streamUtf32LE onErr bs)-{-# INLINE decodeUtf32LEWith #-}---- | Decode text from little endian UTF-32 encoding.------ If the input contains any invalid little endian UTF-32 data, an--- exception will be thrown.  For more control over the handling of--- invalid data, use 'decodeUtf32LEWith'.-decodeUtf32LE :: B.ByteString -> Text-decodeUtf32LE = decodeUtf32LEWith strictDecode-{-# INLINE decodeUtf32LE #-}---- | Decode text from big endian UTF-32 encoding.-decodeUtf32BEWith :: OnDecodeError -> B.ByteString -> Text-decodeUtf32BEWith onErr bs = F.unstream (E.streamUtf32BE onErr bs)-{-# INLINE decodeUtf32BEWith #-}---- | Decode text from big endian UTF-32 encoding.------ If the input contains any invalid big endian UTF-32 data, an--- exception will be thrown.  For more control over the handling of--- invalid data, use 'decodeUtf32BEWith'.-decodeUtf32BE :: B.ByteString -> Text-decodeUtf32BE = decodeUtf32BEWith strictDecode-{-# INLINE decodeUtf32BE #-}---- | Encode text using little endian UTF-32 encoding.-encodeUtf32LE :: Text -> B.ByteString-encodeUtf32LE txt = B.fromChunks (foldrChunks ((:) . TE.encodeUtf32LE) [] txt)-{-# INLINE encodeUtf32LE #-}---- | Encode text using big endian UTF-32 encoding.-encodeUtf32BE :: Text -> B.ByteString-encodeUtf32BE txt = B.fromChunks (foldrChunks ((:) . TE.encodeUtf32BE) [] txt)-{-# INLINE encodeUtf32BE #-}
− Data/Text/Lazy/IO.hs
@@ -1,195 +0,0 @@-{-# LANGUAGE BangPatterns, CPP, RecordWildCards #-}-#if __GLASGOW_HASKELL__ >= 702-{-# LANGUAGE Trustworthy #-}-#endif--- |--- Module      : Data.Text.Lazy.IO--- Copyright   : (c) 2009, 2010 Bryan O'Sullivan,---               (c) 2009 Simon Marlow--- License     : BSD-style--- Maintainer  : bos@serpentine.com--- Portability : GHC------ Efficient locale-sensitive support for lazy text I\/O.------ Skip past the synopsis for some important notes on performance and--- portability across different versions of GHC.--module Data.Text.Lazy.IO-    (-    -- * Performance-    -- $performance--    -- * Locale support-    -- $locale-    -- * File-at-a-time operations-      readFile-    , writeFile-    , appendFile-    -- * Operations on handles-    , hGetContents-    , hGetLine-    , hPutStr-    , hPutStrLn-    -- * Special cases for standard input and output-    , interact-    , getContents-    , getLine-    , putStr-    , putStrLn-    ) where--import Data.Text.Lazy (Text)-import Prelude hiding (appendFile, getContents, getLine, interact,-                       putStr, putStrLn, readFile, writeFile)-import System.IO (Handle, IOMode(..), hPutChar, openFile, stdin, stdout,-                  withFile)-import qualified Data.Text.IO as T-import qualified Data.Text.Lazy as L-import qualified Control.Exception as E-import Control.Monad (when)-import Data.IORef (readIORef)-import Data.Text.Internal.IO (hGetLineWith, readChunk)-import Data.Text.Internal.Lazy (chunk, empty)-import GHC.IO.Buffer (isEmptyBuffer)-import GHC.IO.Exception (IOException(..), IOErrorType(..), ioException)-import GHC.IO.Handle.Internals (augmentIOError, hClose_help,-                                wantReadableHandle, withHandle)-import GHC.IO.Handle.Types (Handle__(..), HandleType(..))-import System.IO (BufferMode(..), hGetBuffering, hSetBuffering)-import System.IO.Error (isEOFError)-import System.IO.Unsafe (unsafeInterleaveIO)---- $performance------ The functions in this module obey the runtime system's locale,--- character set encoding, and line ending conversion settings.------ If you know in advance that you will be working with data that has--- a specific encoding (e.g. UTF-8), and your application is highly--- performance sensitive, you may find that it is faster to perform--- I\/O with bytestrings and to encode and decode yourself than to use--- the functions in this module.------ Whether this will hold depends on the version of GHC you are using,--- the platform you are working on, the data you are working with, and--- the encodings you are using, so be sure to test for yourself.---- | Read a file and return its contents as a string.  The file is--- read lazily, as with 'getContents'.-readFile :: FilePath -> IO Text-readFile name = openFile name ReadMode >>= hGetContents---- | Write a string to a file.  The file is truncated to zero length--- before writing begins.-writeFile :: FilePath -> Text -> IO ()-writeFile p = withFile p WriteMode . flip hPutStr---- | Write a string the end of a file.-appendFile :: FilePath -> Text -> IO ()-appendFile p = withFile p AppendMode . flip hPutStr---- | Lazily read the remaining contents of a 'Handle'.  The 'Handle'--- will be closed after the read completes, or on error.-hGetContents :: Handle -> IO Text-hGetContents h = do-  chooseGoodBuffering h-  wantReadableHandle "hGetContents" h $ \hh -> do-    ts <- lazyRead h-    return (hh{haType=SemiClosedHandle}, ts)---- | Use a more efficient buffer size if we're reading in--- block-buffered mode with the default buffer size.-chooseGoodBuffering :: Handle -> IO ()-chooseGoodBuffering h = do-  bufMode <- hGetBuffering h-  when (bufMode == BlockBuffering Nothing) $-    hSetBuffering h (BlockBuffering (Just 16384))--lazyRead :: Handle -> IO Text-lazyRead h = unsafeInterleaveIO $-  withHandle "hGetContents" h $ \hh -> do-    case haType hh of-      ClosedHandle     -> return (hh, L.empty)-      SemiClosedHandle -> lazyReadBuffered h hh-      _                -> ioException-                          (IOError (Just h) IllegalOperation "hGetContents"-                           "illegal handle type" Nothing Nothing)--lazyReadBuffered :: Handle -> Handle__ -> IO (Handle__, Text)-lazyReadBuffered h hh@Handle__{..} = do-   buf <- readIORef haCharBuffer-   (do t <- readChunk hh buf-       ts <- lazyRead h-       return (hh, chunk t ts)) `E.catch` \e -> do-         (hh', _) <- hClose_help hh-         if isEOFError e-           then return $ if isEmptyBuffer buf-                         then (hh', empty)-                         else (hh', L.singleton '\r')-           else E.throwIO (augmentIOError e "hGetContents" h)---- | Read a single line from a handle.-hGetLine :: Handle -> IO Text-hGetLine = hGetLineWith L.fromChunks---- | Write a string to a handle.-hPutStr :: Handle -> Text -> IO ()-hPutStr h = mapM_ (T.hPutStr h) . L.toChunks---- | Write a string to a handle, followed by a newline.-hPutStrLn :: Handle -> Text -> IO ()-hPutStrLn h t = hPutStr h t >> hPutChar h '\n'---- | The 'interact' function takes a function of type @Text -> Text@--- as its argument. The entire input from the standard input device is--- passed (lazily) to this function as its argument, and the resulting--- string is output on the standard output device.-interact :: (Text -> Text) -> IO ()-interact f = putStr . f =<< getContents---- | Lazily read all user input on 'stdin' as a single string.-getContents :: IO Text-getContents = hGetContents stdin---- | Read a single line of user input from 'stdin'.-getLine :: IO Text-getLine = hGetLine stdin---- | Write a string to 'stdout'.-putStr :: Text -> IO ()-putStr = hPutStr stdout---- | Write a string to 'stdout', followed by a newline.-putStrLn :: Text -> IO ()-putStrLn = hPutStrLn stdout---- $locale------ /Note/: The behaviour of functions in this module depends on the--- version of GHC you are using.------ Beginning with GHC 6.12, text I\/O is performed using the system or--- handle's current locale and line ending conventions.------ Under GHC 6.10 and earlier, the system I\/O libraries /do not--- support/ locale-sensitive I\/O or line ending conversion.  On these--- versions of GHC, functions in this library all use UTF-8.  What--- does this mean in practice?------ * All data that is read will be decoded as UTF-8.------ * Before data is written, it is first encoded as UTF-8.------ * On both reading and writing, the platform's native newline---   conversion is performed.------ If you must use a non-UTF-8 locale on an older version of GHC, you--- will have to perform the transcoding yourself, e.g. as follows:------ > import qualified Data.ByteString.Lazy as B--- > import Data.Text.Lazy (Text)--- > import Data.Text.Lazy.Encoding (encodeUtf16)--- >--- > putStr_Utf16LE :: Text -> IO ()--- > putStr_Utf16LE t = B.putStr (encodeUtf16LE t)
− Data/Text/Lazy/Internal.hs
@@ -1,20 +0,0 @@-{-# LANGUAGE BangPatterns, DeriveDataTypeable #-}--- |--- Module      : Data.Text.Lazy.Internal--- Copyright   : (c) 2013 Bryan O'Sullivan------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : GHC------ This module has been renamed to 'Data.Text.Internal.Lazy'. This--- name for the module will be removed in the next major release.--module Data.Text.Lazy.Internal-    {-# DEPRECATED "Use Data.Text.Internal.Lazy instead" #-}-    (-      module Data.Text.Internal.Lazy-    ) where--import Data.Text.Internal.Lazy
− Data/Text/Lazy/Read.hs
@@ -1,192 +0,0 @@-{-# LANGUAGE OverloadedStrings, CPP #-}-#if __GLASGOW_HASKELL__ >= 704-{-# LANGUAGE Safe #-}-#elif __GLASGOW_HASKELL__ >= 702-{-# LANGUAGE Trustworthy #-}-#endif---- |--- Module      : Data.Text.Lazy.Read--- Copyright   : (c) 2010, 2011 Bryan O'Sullivan------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Portability : GHC------ Functions used frequently when reading textual data.-module Data.Text.Lazy.Read-    (-      Reader-    , decimal-    , hexadecimal-    , signed-    , rational-    , double-    ) where--import Control.Monad (liftM)-import Data.Char (isDigit, isHexDigit)-import Data.Int (Int8, Int16, Int32, Int64)-import Data.Ratio ((%))-import Data.Text.Internal.Read-import Data.Text.Lazy as T-import Data.Word (Word, Word8, Word16, Word32, Word64)---- | Read some text.  If the read succeeds, return its value and the--- remaining text, otherwise an error message.-type Reader a = IReader Text a-type Parser = IParser Text---- | Read a decimal integer.  The input must begin with at least one--- decimal digit, and is consumed until a non-digit or end of string--- is reached.------ This function does not handle leading sign characters.  If you need--- to handle signed input, use @'signed' 'decimal'@.------ /Note/: For fixed-width integer types, this function does not--- attempt to detect overflow, so a sufficiently long input may give--- incorrect results.  If you are worried about overflow, use--- 'Integer' for your result type.-decimal :: Integral a => Reader a-{-# SPECIALIZE decimal :: Reader Int #-}-{-# SPECIALIZE decimal :: Reader Int8 #-}-{-# SPECIALIZE decimal :: Reader Int16 #-}-{-# SPECIALIZE decimal :: Reader Int32 #-}-{-# SPECIALIZE decimal :: Reader Int64 #-}-{-# SPECIALIZE decimal :: Reader Integer #-}-{-# SPECIALIZE decimal :: Reader Data.Word.Word #-}-{-# SPECIALIZE decimal :: Reader Word8 #-}-{-# SPECIALIZE decimal :: Reader Word16 #-}-{-# SPECIALIZE decimal :: Reader Word32 #-}-{-# SPECIALIZE decimal :: Reader Word64 #-}-decimal txt-    | T.null h  = Left "input does not start with a digit"-    | otherwise = Right (T.foldl' go 0 h, t)-  where (h,t)  = T.span isDigit txt-        go n d = (n * 10 + fromIntegral (digitToInt d))---- | Read a hexadecimal integer, consisting of an optional leading--- @\"0x\"@ followed by at least one hexadecimal digit. Input is--- consumed until a non-hex-digit or end of string is reached.--- This function is case insensitive.------ This function does not handle leading sign characters.  If you need--- to handle signed input, use @'signed' 'hexadecimal'@.------ /Note/: For fixed-width integer types, this function does not--- attempt to detect overflow, so a sufficiently long input may give--- incorrect results.  If you are worried about overflow, use--- 'Integer' for your result type.-hexadecimal :: Integral a => Reader a-{-# SPECIALIZE hexadecimal :: Reader Int #-}-{-# SPECIALIZE hexadecimal :: Reader Integer #-}-hexadecimal txt-    | h == "0x" || h == "0X" = hex t-    | otherwise              = hex txt- where (h,t) = T.splitAt 2 txt--hex :: Integral a => Reader a-{-# SPECIALIZE hexadecimal :: Reader Int #-}-{-# SPECIALIZE hexadecimal :: Reader Int8 #-}-{-# SPECIALIZE hexadecimal :: Reader Int16 #-}-{-# SPECIALIZE hexadecimal :: Reader Int32 #-}-{-# SPECIALIZE hexadecimal :: Reader Int64 #-}-{-# SPECIALIZE hexadecimal :: Reader Integer #-}-{-# SPECIALIZE hexadecimal :: Reader Word #-}-{-# SPECIALIZE hexadecimal :: Reader Word8 #-}-{-# SPECIALIZE hexadecimal :: Reader Word16 #-}-{-# SPECIALIZE hexadecimal :: Reader Word32 #-}-{-# SPECIALIZE hexadecimal :: Reader Word64 #-}-hex txt-    | T.null h  = Left "input does not start with a hexadecimal digit"-    | otherwise = Right (T.foldl' go 0 h, t)-  where (h,t)  = T.span isHexDigit txt-        go n d = (n * 16 + fromIntegral (hexDigitToInt d))---- | Read an optional leading sign character (@\'-\'@ or @\'+\'@) and--- apply it to the result of applying the given reader.-signed :: Num a => Reader a -> Reader a-{-# INLINE signed #-}-signed f = runP (signa (P f))---- | Read a rational number.------ This function accepts an optional leading sign character, followed--- by at least one decimal digit.  The syntax similar to that accepted--- by the 'read' function, with the exception that a trailing @\'.\'@--- or @\'e\'@ /not/ followed by a number is not consumed.------ Examples:------ >rational "3"     == Right (3.0, "")--- >rational "3.1"   == Right (3.1, "")--- >rational "3e4"   == Right (30000.0, "")--- >rational "3.1e4" == Right (31000.0, "")--- >rational ".3"    == Left "input does not start with a digit"--- >rational "e3"    == Left "input does not start with a digit"------ Examples of differences from 'read':------ >rational "3.foo" == Right (3.0, ".foo")--- >rational "3e"    == Right (3.0, "e")-rational :: Fractional a => Reader a-{-# SPECIALIZE rational :: Reader Double #-}-rational = floaty $ \real frac fracDenom -> fromRational $-                     real % 1 + frac % fracDenom---- | Read a rational number.------ The syntax accepted by this function is the same as for 'rational'.------ /Note/: This function is almost ten times faster than 'rational',--- but is slightly less accurate.------ The 'Double' type supports about 16 decimal places of accuracy.--- For 94.2% of numbers, this function and 'rational' give identical--- results, but for the remaining 5.8%, this function loses precision--- around the 15th decimal place.  For 0.001% of numbers, this--- function will lose precision at the 13th or 14th decimal place.-double :: Reader Double-double = floaty $ \real frac fracDenom ->-                   fromIntegral real +-                   fromIntegral frac / fromIntegral fracDenom--signa :: Num a => Parser a -> Parser a-{-# SPECIALIZE signa :: Parser Int -> Parser Int #-}-{-# SPECIALIZE signa :: Parser Int8 -> Parser Int8 #-}-{-# SPECIALIZE signa :: Parser Int16 -> Parser Int16 #-}-{-# SPECIALIZE signa :: Parser Int32 -> Parser Int32 #-}-{-# SPECIALIZE signa :: Parser Int64 -> Parser Int64 #-}-{-# SPECIALIZE signa :: Parser Integer -> Parser Integer #-}-signa p = do-  sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')-  if sign == '+' then p else negate `liftM` p--char :: (Char -> Bool) -> Parser Char-char p = P $ \t -> case T.uncons t of-                     Just (c,t') | p c -> Right (c,t')-                     _                 -> Left "character does not match"--floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Reader a-{-# INLINE floaty #-}-floaty f = runP $ do-  sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')-  real <- P decimal-  T fraction fracDigits <- perhaps (T 0 0) $ do-    _ <- char (=='.')-    digits <- P $ \t -> Right (fromIntegral . T.length $ T.takeWhile isDigit t, t)-    n <- P decimal-    return $ T n digits-  let e c = c == 'e' || c == 'E'-  power <- perhaps 0 (char e >> signa (P decimal) :: Parser Int)-  let n = if fracDigits == 0-          then if power == 0-               then fromIntegral real-               else fromIntegral real * (10 ^^ power)-          else if power == 0-               then f real fraction (10 ^ fracDigits)-               else f real fraction (10 ^ fracDigits) * (10 ^^ power)-  return $! if sign == '+'-            then n-            else -n
− Data/Text/Read.hs
@@ -1,200 +0,0 @@-{-# LANGUAGE OverloadedStrings, UnboxedTuples, CPP #-}-#if __GLASGOW_HASKELL__ >= 702-{-# LANGUAGE Trustworthy #-}-#endif---- |--- Module      : Data.Text.Read--- Copyright   : (c) 2010, 2011 Bryan O'Sullivan------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Portability : GHC------ Functions used frequently when reading textual data.-module Data.Text.Read-    (-      Reader-    , decimal-    , hexadecimal-    , signed-    , rational-    , double-    ) where--import Control.Monad (liftM)-import Data.Char (isDigit, isHexDigit)-import Data.Int (Int8, Int16, Int32, Int64)-import Data.Ratio ((%))-import Data.Text as T-import Data.Text.Internal.Private (span_)-import Data.Text.Internal.Read-import Data.Word (Word, Word8, Word16, Word32, Word64)---- | Read some text.  If the read succeeds, return its value and the--- remaining text, otherwise an error message.-type Reader a = IReader Text a-type Parser a = IParser Text a---- | Read a decimal integer.  The input must begin with at least one--- decimal digit, and is consumed until a non-digit or end of string--- is reached.------ This function does not handle leading sign characters.  If you need--- to handle signed input, use @'signed' 'decimal'@.------ /Note/: For fixed-width integer types, this function does not--- attempt to detect overflow, so a sufficiently long input may give--- incorrect results.  If you are worried about overflow, use--- 'Integer' for your result type.-decimal :: Integral a => Reader a-{-# SPECIALIZE decimal :: Reader Int #-}-{-# SPECIALIZE decimal :: Reader Int8 #-}-{-# SPECIALIZE decimal :: Reader Int16 #-}-{-# SPECIALIZE decimal :: Reader Int32 #-}-{-# SPECIALIZE decimal :: Reader Int64 #-}-{-# SPECIALIZE decimal :: Reader Integer #-}-{-# SPECIALIZE decimal :: Reader Data.Word.Word #-}-{-# SPECIALIZE decimal :: Reader Word8 #-}-{-# SPECIALIZE decimal :: Reader Word16 #-}-{-# SPECIALIZE decimal :: Reader Word32 #-}-{-# SPECIALIZE decimal :: Reader Word64 #-}-decimal txt-    | T.null h  = Left "input does not start with a digit"-    | otherwise = Right (T.foldl' go 0 h, t)-  where (# h,t #)  = span_ isDigit txt-        go n d = (n * 10 + fromIntegral (digitToInt d))---- | Read a hexadecimal integer, consisting of an optional leading--- @\"0x\"@ followed by at least one hexadecimal digit. Input is--- consumed until a non-hex-digit or end of string is reached.--- This function is case insensitive.------ This function does not handle leading sign characters.  If you need--- to handle signed input, use @'signed' 'hexadecimal'@.------ /Note/: For fixed-width integer types, this function does not--- attempt to detect overflow, so a sufficiently long input may give--- incorrect results.  If you are worried about overflow, use--- 'Integer' for your result type.-hexadecimal :: Integral a => Reader a-{-# SPECIALIZE hexadecimal :: Reader Int #-}-{-# SPECIALIZE hexadecimal :: Reader Int8 #-}-{-# SPECIALIZE hexadecimal :: Reader Int16 #-}-{-# SPECIALIZE hexadecimal :: Reader Int32 #-}-{-# SPECIALIZE hexadecimal :: Reader Int64 #-}-{-# SPECIALIZE hexadecimal :: Reader Integer #-}-{-# SPECIALIZE hexadecimal :: Reader Word #-}-{-# SPECIALIZE hexadecimal :: Reader Word8 #-}-{-# SPECIALIZE hexadecimal :: Reader Word16 #-}-{-# SPECIALIZE hexadecimal :: Reader Word32 #-}-{-# SPECIALIZE hexadecimal :: Reader Word64 #-}-hexadecimal txt-    | h == "0x" || h == "0X" = hex t-    | otherwise              = hex txt- where (h,t) = T.splitAt 2 txt--hex :: Integral a => Reader a-{-# SPECIALIZE hex :: Reader Int #-}-{-# SPECIALIZE hex :: Reader Int8 #-}-{-# SPECIALIZE hex :: Reader Int16 #-}-{-# SPECIALIZE hex :: Reader Int32 #-}-{-# SPECIALIZE hex :: Reader Int64 #-}-{-# SPECIALIZE hex :: Reader Integer #-}-{-# SPECIALIZE hex :: Reader Word #-}-{-# SPECIALIZE hex :: Reader Word8 #-}-{-# SPECIALIZE hex :: Reader Word16 #-}-{-# SPECIALIZE hex :: Reader Word32 #-}-{-# SPECIALIZE hex :: Reader Word64 #-}-hex txt-    | T.null h  = Left "input does not start with a hexadecimal digit"-    | otherwise = Right (T.foldl' go 0 h, t)-  where (# h,t #)  = span_ isHexDigit txt-        go n d = (n * 16 + fromIntegral (hexDigitToInt d))---- | Read an optional leading sign character (@\'-\'@ or @\'+\'@) and--- apply it to the result of applying the given reader.-signed :: Num a => Reader a -> Reader a-{-# INLINE signed #-}-signed f = runP (signa (P f))---- | Read a rational number.------ This function accepts an optional leading sign character, followed--- by at least one decimal digit.  The syntax similar to that accepted--- by the 'read' function, with the exception that a trailing @\'.\'@--- or @\'e\'@ /not/ followed by a number is not consumed.------ Examples (with behaviour identical to 'read'):------ >rational "3"     == Right (3.0, "")--- >rational "3.1"   == Right (3.1, "")--- >rational "3e4"   == Right (30000.0, "")--- >rational "3.1e4" == Right (31000.0, "")--- >rational ".3"    == Left "input does not start with a digit"--- >rational "e3"    == Left "input does not start with a digit"------ Examples of differences from 'read':------ >rational "3.foo" == Right (3.0, ".foo")--- >rational "3e"    == Right (3.0, "e")-rational :: Fractional a => Reader a-{-# SPECIALIZE rational :: Reader Double #-}-rational = floaty $ \real frac fracDenom -> fromRational $-                     real % 1 + frac % fracDenom---- | Read a rational number.------ The syntax accepted by this function is the same as for 'rational'.------ /Note/: This function is almost ten times faster than 'rational',--- but is slightly less accurate.------ The 'Double' type supports about 16 decimal places of accuracy.--- For 94.2% of numbers, this function and 'rational' give identical--- results, but for the remaining 5.8%, this function loses precision--- around the 15th decimal place.  For 0.001% of numbers, this--- function will lose precision at the 13th or 14th decimal place.-double :: Reader Double-double = floaty $ \real frac fracDenom ->-                   fromIntegral real +-                   fromIntegral frac / fromIntegral fracDenom--signa :: Num a => Parser a -> Parser a-{-# SPECIALIZE signa :: Parser Int -> Parser Int #-}-{-# SPECIALIZE signa :: Parser Int8 -> Parser Int8 #-}-{-# SPECIALIZE signa :: Parser Int16 -> Parser Int16 #-}-{-# SPECIALIZE signa :: Parser Int32 -> Parser Int32 #-}-{-# SPECIALIZE signa :: Parser Int64 -> Parser Int64 #-}-{-# SPECIALIZE signa :: Parser Integer -> Parser Integer #-}-signa p = do-  sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')-  if sign == '+' then p else negate `liftM` p--char :: (Char -> Bool) -> Parser Char-char p = P $ \t -> case T.uncons t of-                     Just (c,t') | p c -> Right (c,t')-                     _                 -> Left "character does not match"--floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Reader a-{-# INLINE floaty #-}-floaty f = runP $ do-  sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')-  real <- P decimal-  T fraction fracDigits <- perhaps (T 0 0) $ do-    _ <- char (=='.')-    digits <- P $ \t -> Right (T.length $ T.takeWhile isDigit t, t)-    n <- P decimal-    return $ T n digits-  let e c = c == 'e' || c == 'E'-  power <- perhaps 0 (char e >> signa (P decimal) :: Parser Int)-  let n = if fracDigits == 0-          then if power == 0-               then fromIntegral real-               else fromIntegral real * (10 ^^ power)-          else if power == 0-               then f real fraction (10 ^ fracDigits)-               else f real fraction (10 ^ fracDigits) * (10 ^^ power)-  return $! if sign == '+'-            then n-            else -n
− Data/Text/Show.hs
@@ -1,90 +0,0 @@-{-# LANGUAGE CPP, MagicHash #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}-#if __GLASGOW_HASKELL__ >= 702-{-# LANGUAGE Trustworthy #-}-#endif---- |--- Module      : Data.Text.Show--- Copyright   : (c) 2009-2015 Bryan O'Sullivan------ License     : BSD-style--- Maintainer  : bos@serpentine.com--- Stability   : experimental--- Portability : GHC--module Data.Text.Show-    (-      singleton-    , unpack-    , unpackCString#-    ) where--import Control.Monad.ST (ST)-import Data.Text.Internal (Text(..), empty_, safe)-import Data.Text.Internal.Fusion (stream, unstream)-import Data.Text.Internal.Unsafe.Char (unsafeWrite)-import GHC.Prim (Addr#)-import qualified Data.Text.Array as A-import qualified Data.Text.Internal.Fusion.Common as S--#if __GLASGOW_HASKELL__ >= 702-import qualified GHC.CString as GHC-#else-import qualified GHC.Base as GHC-#endif--instance Show Text where-    showsPrec p ps r = showsPrec p (unpack ps) r---- | /O(n)/ Convert a 'Text' into a 'String'.  Subject to fusion.-unpack :: Text -> String-unpack = S.unstreamList . stream-{-# INLINE [1] unpack #-}---- | /O(n)/ Convert a literal string into a 'Text'.------ This is exposed solely for people writing GHC rewrite rules.------ @since 1.2.1.1-unpackCString# :: Addr# -> Text-unpackCString# addr# = unstream (S.streamCString# addr#)-{-# NOINLINE unpackCString# #-}--{-# RULES "TEXT literal" [1] forall a.-    unstream (S.map safe (S.streamList (GHC.unpackCString# a)))-      = unpackCString# a #-}--{-# RULES "TEXT literal UTF8" [1] forall a.-    unstream (S.map safe (S.streamList (GHC.unpackCStringUtf8# a)))-      = unpackCString# a #-}--{-# RULES "TEXT empty literal" [1]-    unstream (S.map safe (S.streamList []))-      = empty_ #-}--{-# RULES "TEXT singleton literal" [1] forall a.-    unstream (S.map safe (S.streamList [a]))-      = singleton_ a #-}---- | /O(1)/ Convert a character into a Text.  Subject to fusion.--- Performs replacement on invalid scalar values.-singleton :: Char -> Text-singleton = unstream . S.singleton . safe-{-# INLINE [1] singleton #-}--{-# RULES "TEXT singleton" forall a.-    unstream (S.singleton (safe a))-      = singleton_ a #-}---- This is intended to reduce inlining bloat.-singleton_ :: Char -> Text-singleton_ c = Text (A.run x) 0 len-  where x :: ST s (A.MArray s)-        x = do arr <- A.new len-               _ <- unsafeWrite arr 0 d-               return arr-        len | d < '\x10000' = 1-            | otherwise     = 2-        d = safe c-{-# NOINLINE singleton_ #-}
− Data/Text/Unsafe.hs
@@ -1,124 +0,0 @@-{-# LANGUAGE CPP, MagicHash, UnboxedTuples #-}--- |--- Module      : Data.Text.Unsafe--- Copyright   : (c) 2009, 2010, 2011 Bryan O'Sullivan--- License     : BSD-style--- Maintainer  : bos@serpentine.com--- Portability : portable------ A module containing unsafe 'Text' operations, for very very careful--- use in heavily tested code.-module Data.Text.Unsafe-    (-      inlineInterleaveST-    , inlinePerformIO-    , unsafeDupablePerformIO-    , Iter(..)-    , iter-    , iter_-    , reverseIter-    , reverseIter_-    , unsafeHead-    , unsafeTail-    , lengthWord16-    , takeWord16-    , dropWord16-    ) where--#if defined(ASSERTS)-import Control.Exception (assert)-#endif-import Data.Text.Internal.Encoding.Utf16 (chr2)-import Data.Text.Internal (Text(..))-import Data.Text.Internal.Unsafe (inlineInterleaveST, inlinePerformIO)-import Data.Text.Internal.Unsafe.Char (unsafeChr)-import qualified Data.Text.Array as A-import GHC.IO (unsafeDupablePerformIO)---- | /O(1)/ A variant of 'head' for non-empty 'Text'. 'unsafeHead'--- omits the check for the empty case, so there is an obligation on--- the programmer to provide a proof that the 'Text' is non-empty.-unsafeHead :: Text -> Char-unsafeHead (Text arr off _len)-    | m < 0xD800 || m > 0xDBFF = unsafeChr m-    | otherwise                = chr2 m n-    where m = A.unsafeIndex arr off-          n = A.unsafeIndex arr (off+1)-{-# INLINE unsafeHead #-}---- | /O(1)/ A variant of 'tail' for non-empty 'Text'. 'unsafeTail'--- omits the check for the empty case, so there is an obligation on--- the programmer to provide a proof that the 'Text' is non-empty.-unsafeTail :: Text -> Text-unsafeTail t@(Text arr off len) =-#if defined(ASSERTS)-    assert (d <= len) $-#endif-    Text arr (off+d) (len-d)-  where d = iter_ t 0-{-# INLINE unsafeTail #-}--data Iter = Iter {-# UNPACK #-} !Char {-# UNPACK #-} !Int---- | /O(1)/ Iterate (unsafely) one step forwards through a UTF-16--- array, returning the current character and the delta to add to give--- the next offset to iterate at.-iter :: Text -> Int -> Iter-iter (Text arr off _len) i-    | m < 0xD800 || m > 0xDBFF = Iter (unsafeChr m) 1-    | otherwise                = Iter (chr2 m n) 2-  where m = A.unsafeIndex arr j-        n = A.unsafeIndex arr k-        j = off + i-        k = j + 1-{-# INLINE iter #-}---- | /O(1)/ Iterate one step through a UTF-16 array, returning the--- delta to add to give the next offset to iterate at.-iter_ :: Text -> Int -> Int-iter_ (Text arr off _len) i | m < 0xD800 || m > 0xDBFF = 1-                            | otherwise                = 2-  where m = A.unsafeIndex arr (off+i)-{-# INLINE iter_ #-}---- | /O(1)/ Iterate one step backwards through a UTF-16 array,--- returning the current character and the delta to add (i.e. a--- negative number) to give the next offset to iterate at.-reverseIter :: Text -> Int -> (Char,Int)-reverseIter (Text arr off _len) i-    | m < 0xDC00 || m > 0xDFFF = (unsafeChr m, -1)-    | otherwise                = (chr2 n m,    -2)-  where m = A.unsafeIndex arr j-        n = A.unsafeIndex arr k-        j = off + i-        k = j - 1-{-# INLINE reverseIter #-}---- | /O(1)/ Iterate one step backwards through a UTF-16 array,--- returning the delta to add (i.e. a negative number) to give the--- next offset to iterate at.------ @since 1.1.1.0-reverseIter_ :: Text -> Int -> Int-reverseIter_ (Text arr off _len) i-    | m < 0xDC00 || m > 0xDFFF = -1-    | otherwise                = -2-  where m = A.unsafeIndex arr (off+i)-{-# INLINE reverseIter_ #-}---- | /O(1)/ Return the length of a 'Text' in units of 'Word16'.  This--- is useful for sizing a target array appropriately before using--- 'unsafeCopyToPtr'.-lengthWord16 :: Text -> Int-lengthWord16 (Text _arr _off len) = len-{-# INLINE lengthWord16 #-}---- | /O(1)/ Unchecked take of 'k' 'Word16's from the front of a 'Text'.-takeWord16 :: Int -> Text -> Text-takeWord16 k (Text arr off _len) = Text arr off k-{-# INLINE takeWord16 #-}---- | /O(1)/ Unchecked drop of 'k' 'Word16's from the front of a 'Text'.-dropWord16 :: Int -> Text -> Text-dropWord16 k (Text arr off len) = Text arr (off+k) (len-k)-{-# INLINE dropWord16 #-}
+ benchmarks/cbits-bench/time_iconv.c view
@@ -0,0 +1,35 @@+#include <iconv.h>+#include <stdlib.h>+#include <stdio.h>+#include <stdint.h>++int time_iconv(char *srcbuf, size_t srcbufsize)+{+  uint16_t *destbuf = NULL;+  size_t destbufsize;+  static uint16_t *origdestbuf;+  static size_t origdestbufsize;+  iconv_t ic = (iconv_t) -1;+  int ret = 0;++  if (ic == (iconv_t) -1) {+    ic = iconv_open("UTF-16LE", "UTF-8");+    if (ic == (iconv_t) -1) {+      ret = -1;+      goto done;+    }+  }+  +  destbufsize = srcbufsize * sizeof(uint16_t);+  if (destbufsize > origdestbufsize) {+    free(origdestbuf);+    origdestbuf = destbuf = malloc(origdestbufsize = destbufsize);+  } else {+    destbuf = origdestbuf;+  }++  iconv(ic, &srcbuf, &srcbufsize, (char**) &destbuf, &destbufsize);++ done:+  return ret;+}
− benchmarks/cbits/time_iconv.c
@@ -1,35 +0,0 @@-#include <iconv.h>-#include <stdlib.h>-#include <stdio.h>-#include <stdint.h>--int time_iconv(char *srcbuf, size_t srcbufsize)-{-  uint16_t *destbuf = NULL;-  size_t destbufsize;-  static uint16_t *origdestbuf;-  static size_t origdestbufsize;-  iconv_t ic = (iconv_t) -1;-  int ret = 0;--  if (ic == (iconv_t) -1) {-    ic = iconv_open("UTF-16LE", "UTF-8");-    if (ic == (iconv_t) -1) {-      ret = -1;-      goto done;-    }-  }-  -  destbufsize = srcbufsize * sizeof(uint16_t);-  if (destbufsize > origdestbufsize) {-    free(origdestbuf);-    origdestbuf = destbuf = malloc(origdestbufsize = destbufsize);-  } else {-    destbuf = origdestbuf;-  }--  iconv(ic, &srcbuf, &srcbufsize, (char**) &destbuf, &destbufsize);-- done:-  return ret;-}
benchmarks/python/cut.py view
@@ -1,4 +1,4 @@-#!/usr/bin/env python+#!/usr/bin/env python3  import utils, sys, codecs 
benchmarks/python/multilang.py view
@@ -1,4 +1,4 @@-#!/usr/bin/env python+#!/usr/bin/env python3  import math import sys@@ -12,23 +12,22 @@     a = 1e300     def g():         return-    for i in xrange(3):+    for i in range(3):         start = time.time()-        for j in xrange(count):+        for j in range(count):             g()         a = min(a, (time.time() - start) / count)      b = 1e300-    for i in xrange(3):+    for i in range(3):         start = time.time()-        for j in xrange(count):+        for j in range(count):             f()         b = min(b, (time.time() - start) / count)      return round(b - a, int(round(math.log(count, 10) - math.log(b - a, 10))))  contents = open('../../tests/text-test-data/yiwiki.xml', 'r').read()-contents = contents.decode('utf-8')  benchmarks = (     find_first,@@ -47,4 +46,4 @@ for b in bms:     sys.stdout.write(b.__name__ + ' ')     sys.stdout.flush()-    print b()+    print(b())
benchmarks/python/sort.py view
@@ -1,4 +1,4 @@-#!/usr/bin/env python+#!/usr/bin/env python3  import utils, sys, codecs 
benchmarks/python/strip_tags.py view
@@ -1,4 +1,4 @@-#!/usr/bin/env python+#!/usr/bin/env python3  import utils, sys 
benchmarks/python/utils.py view
@@ -1,4 +1,4 @@-#!/usr/bin/env python+#!/usr/bin/env python3  import sys, time 
benchmarks/text-benchmarks.cabal view
@@ -2,10 +2,10 @@ name:                text-benchmarks version:             0.0.0.0 synopsis:            Benchmarks for the text package-description:         Benchmarks for the text package+description:         Benchmarks for the text package. homepage:            https://bitbucket.org/bos/text license:             BSD2-license-file:        ../LICENSE+license-file:        LICENSE author:              Jasper Van der Jeugt <jaspervdj@gmail.com>,                      Bryan O'Sullivan <bos@serpentine.com>,                      Tom Harper <rtomharper@googlemail.com>,@@ -13,7 +13,12 @@ maintainer:          jaspervdj@gmail.com category:            Text build-type:          Simple+tested-with:    GHC==8.10.2, GHC==8.8.4, GHC==8.6.5, GHC==8.4.4,+                GHC==8.2.2, GHC==8.0.2, GHC==7.10.3 +extra-source-files:+    include/*.h+ flag bytestring-builder   description: Depend on the bytestring-builder package for backwards compatibility.   default: False@@ -54,7 +59,7 @@     build-depends: bytestring         >= 0.10.4    -- modules for benchmark proper-  c-sources:      cbits/time_iconv.c+  c-sources:      cbits-bench/time_iconv.c   hs-source-dirs: haskell   main-is:        Benchmarks.hs   other-modules:@@ -81,9 +86,9 @@    -- Source code for IUT (implementation under test)   -- "borrowed" from parent folder-  include-dirs:   ../include-  c-sources:      ../cbits/cbits.c-  hs-source-dirs: ..+  include-dirs:   include+  c-sources:      cbits/cbits.c+  hs-source-dirs: src   other-modules:     Data.Text     Data.Text.Array@@ -96,6 +101,7 @@     Data.Text.Internal.Builder.Functions     Data.Text.Internal.Builder.Int.Digits     Data.Text.Internal.Builder.RealFloat.Functions+    Data.Text.Internal.ByteStringCompat     Data.Text.Internal.Encoding.Fusion     Data.Text.Internal.Encoding.Fusion.Common     Data.Text.Internal.Encoding.Utf16@@ -132,6 +138,7 @@    default-language: Haskell2010   default-extensions: NondecreasingIndentation+  other-extensions: DeriveAnyClass   executable text-multilang
changelog.md view
@@ -1,3 +1,12 @@+See also http://pvp.haskell.org/faq++#### 1.2.4.1++* Support `template-haskell-2.17.0.0`+* Support `bytestring-0.11`+* Add `take . drop` related RULE+* Add doctest examples for `span` and `break`+ ### 1.2.4.0  * Add TH `Lift` instances for `Data.Text.Text` and `Data.Text.Lazy.Text` (gh-232)@@ -9,7 +18,7 @@  * Support `base-4.13.0.0` -### 1.2.3.1+#### 1.2.3.1  * Make `decodeUtf8With` fail explicitly for unsupported non-BMP   replacement characters instead silent undefined behaviour (gh-213)
+ src/Data/Text.hs view
@@ -0,0 +1,1905 @@+{-# LANGUAGE BangPatterns, CPP, MagicHash, Rank2Types, UnboxedTuples, TypeFamilies #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+#if __GLASGOW_HASKELL__ >= 702+{-# LANGUAGE Trustworthy #-}+#endif+-- Using TemplateHaskell in text unconditionally is unacceptable, as+-- it's a GHC boot library. TemplateHaskellQuotes was added in 8.0, so+-- this would seem to be a problem. However, GHC's policy of only+-- needing to be able to compile itself from the last few releases+-- allows us to use full-fat TH on older versions, while using THQ for+-- GHC versions that may be used for bootstrapping.+#if __GLASGOW_HASKELL__ >= 800+{-# LANGUAGE TemplateHaskellQuotes #-}+#else+{-# LANGUAGE TemplateHaskell #-}+#endif++-- |+-- Module      : Data.Text+-- Copyright   : (c) 2009, 2010, 2011, 2012 Bryan O'Sullivan,+--               (c) 2009 Duncan Coutts,+--               (c) 2008, 2009 Tom Harper+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Portability : GHC+--+-- A time and space-efficient implementation of Unicode text.+-- Suitable for performance critical use, both in terms of large data+-- quantities and high speed.+--+-- /Note/: Read below the synopsis for important notes on the use of+-- this module.+--+-- This module is intended to be imported @qualified@, to avoid name+-- clashes with "Prelude" functions, e.g.+--+-- > import qualified Data.Text as T+--+-- To use an extended and very rich family of functions for working+-- with Unicode text (including normalization, regular expressions,+-- non-standard encodings, text breaking, and locales), see the+-- <http://hackage.haskell.org/package/text-icu text-icu package >.+--++module Data.Text+    (+    -- * Strict vs lazy types+    -- $strict++    -- * Acceptable data+    -- $replacement++    -- * Definition of character+    -- $character_definition++    -- * Fusion+    -- $fusion++    -- * Types+      Text++    -- * Creation and elimination+    , pack+    , unpack+    , singleton+    , empty++    -- * Basic interface+    , cons+    , snoc+    , append+    , uncons+    , unsnoc+    , head+    , last+    , tail+    , init+    , null+    , length+    , compareLength++    -- * Transformations+    , map+    , intercalate+    , intersperse+    , transpose+    , reverse+    , replace++    -- ** Case conversion+    -- $case+    , toCaseFold+    , toLower+    , toUpper+    , toTitle++    -- ** Justification+    , justifyLeft+    , justifyRight+    , center++    -- * Folds+    , foldl+    , foldl'+    , foldl1+    , foldl1'+    , foldr+    , foldr1++    -- ** Special folds+    , concat+    , concatMap+    , any+    , all+    , maximum+    , minimum++    -- * Construction++    -- ** Scans+    , scanl+    , scanl1+    , scanr+    , scanr1++    -- ** Accumulating maps+    , mapAccumL+    , mapAccumR++    -- ** Generation and unfolding+    , replicate+    , unfoldr+    , unfoldrN++    -- * Substrings++    -- ** Breaking strings+    , take+    , takeEnd+    , drop+    , dropEnd+    , takeWhile+    , takeWhileEnd+    , dropWhile+    , dropWhileEnd+    , dropAround+    , strip+    , stripStart+    , stripEnd+    , splitAt+    , breakOn+    , breakOnEnd+    , break+    , span+    , group+    , groupBy+    , inits+    , tails++    -- ** Breaking into many substrings+    -- $split+    , splitOn+    , split+    , chunksOf++    -- ** Breaking into lines and words+    , lines+    --, lines'+    , words+    , unlines+    , unwords++    -- * Predicates+    , isPrefixOf+    , isSuffixOf+    , isInfixOf++    -- ** View patterns+    , stripPrefix+    , stripSuffix+    , commonPrefixes++    -- * Searching+    , filter+    , breakOnAll+    , find+    , partition++    -- , findSubstring++    -- * Indexing+    -- $index+    , index+    , findIndex+    , count++    -- * Zipping+    , zip+    , zipWith++    -- -* Ordered text+    -- , sort++    -- * Low level operations+    , copy+    , unpackCString#+    ) where++import Prelude (Char, Bool(..), Int, Maybe(..), String,+                Eq(..), Ord(..), Ordering(..), (++),+                Read(..),+                (&&), (||), (+), (-), (.), ($), ($!), (>>),+                not, return, otherwise, quot)+import Control.DeepSeq (NFData(rnf))+#if defined(ASSERTS)+import Control.Exception (assert)+#endif+import Data.Char (isSpace)+import Data.Data (Data(gfoldl, toConstr, gunfold, dataTypeOf), constrIndex,+                  Constr, mkConstr, DataType, mkDataType, Fixity(Prefix))+import Control.Monad (foldM)+import Control.Monad.ST (ST)+import qualified Data.Text.Array as A+import qualified Data.List as L+import Data.Binary (Binary(get, put))+import Data.Monoid (Monoid(..))+#if MIN_VERSION_base(4,9,0)+import Data.Semigroup (Semigroup(..))+#endif+import Data.String (IsString(..))+import qualified Data.Text.Internal.Fusion as S+import qualified Data.Text.Internal.Fusion.Common as S+import Data.Text.Encoding (decodeUtf8', encodeUtf8)+import Data.Text.Internal.Fusion (stream, reverseStream, unstream)+import Data.Text.Internal.Private (span_)+import Data.Text.Internal (Text(..), empty, firstf, mul, safe, text)+import Data.Text.Show (singleton, unpack, unpackCString#)+import qualified Prelude as P+import Data.Text.Unsafe (Iter(..), iter, iter_, lengthWord16, reverseIter,+                         reverseIter_, unsafeHead, unsafeTail)+import Data.Text.Internal.Unsafe.Char (unsafeChr)+import qualified Data.Text.Internal.Functions as F+import qualified Data.Text.Internal.Encoding.Utf16 as U16+import Data.Text.Internal.Search (indices)+import Data.Text.Internal.Unsafe.Shift (UnsafeShift(..))+#if defined(__HADDOCK__)+import Data.ByteString (ByteString)+import qualified Data.Text.Lazy as L+import Data.Int (Int64)+#endif+import GHC.Base (eqInt, neInt, gtInt, geInt, ltInt, leInt)+#if MIN_VERSION_base(4,7,0)+import qualified GHC.Exts as Exts+#endif+import qualified Language.Haskell.TH.Lib as TH+import qualified Language.Haskell.TH.Syntax as TH+#if MIN_VERSION_base(4,7,0)+import Text.Printf (PrintfArg, formatArg, formatString)+#endif++-- $setup+-- >>> import Data.Text+-- >>> import qualified Data.Text as T+-- >>> :seti -XOverloadedStrings++-- $character_definition+--+-- This package uses the term /character/ to denote Unicode /code points/.+--+-- Note that this is not the same thing as a grapheme (e.g. a+-- composition of code points that form one visual symbol). For+-- instance, consider the grapheme \"&#x00e4;\". This symbol has two+-- Unicode representations: a single code-point representation+-- @U+00E4@ (the @LATIN SMALL LETTER A WITH DIAERESIS@ code point),+-- and a two code point representation @U+0061@ (the \"@A@\" code+-- point) and @U+0308@ (the @COMBINING DIAERESIS@ code point).++-- $strict+--+-- This package provides both strict and lazy 'Text' types.  The+-- strict type is provided by the "Data.Text" module, while the lazy+-- type is provided by the "Data.Text.Lazy" module. Internally, the+-- lazy @Text@ type consists of a list of strict chunks.+--+-- The strict 'Text' type requires that an entire string fit into+-- memory at once.  The lazy 'Data.Text.Lazy.Text' type is capable of+-- streaming strings that are larger than memory using a small memory+-- footprint.  In many cases, the overhead of chunked streaming makes+-- the lazy 'Data.Text.Lazy.Text' type slower than its strict+-- counterpart, but this is not always the case.  Sometimes, the time+-- complexity of a function in one module may be different from the+-- other, due to their differing internal structures.+--+-- Each module provides an almost identical API, with the main+-- difference being that the strict module uses 'Int' values for+-- lengths and counts, while the lazy module uses 'Data.Int.Int64'+-- lengths.++-- $replacement+--+-- A 'Text' value is a sequence of Unicode scalar values, as defined+-- in+-- <http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#page=35 §3.9, definition D76 of the Unicode 5.2 standard >.+-- As such, a 'Text' cannot contain values in the range U+D800 to+-- U+DFFF inclusive. Haskell implementations admit all Unicode code+-- points+-- (<http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#page=13 §3.4, definition D10 >)+-- as 'Char' values, including code points from this invalid range.+-- This means that there are some 'Char' values that are not valid+-- Unicode scalar values, and the functions in this module must handle+-- those cases.+--+-- Within this module, many functions construct a 'Text' from one or+-- more 'Char' values. Those functions will substitute 'Char' values+-- that are not valid Unicode scalar values with the replacement+-- character \"&#xfffd;\" (U+FFFD).  Functions that perform this+-- inspection and replacement are documented with the phrase+-- \"Performs replacement on invalid scalar values\".+--+-- (One reason for this policy of replacement is that internally, a+-- 'Text' value is represented as packed UTF-16 data. Values in the+-- range U+D800 through U+DFFF are used by UTF-16 to denote surrogate+-- code points, and so cannot be represented. The functions replace+-- invalid scalar values, instead of dropping them, as a security+-- measure. For details, see+-- <http://unicode.org/reports/tr36/#Deletion_of_Noncharacters Unicode Technical Report 36, §3.5 >.)++-- $fusion+--+-- Most of the functions in this module are subject to /fusion/,+-- meaning that a pipeline of such functions will usually allocate at+-- most one 'Text' value.+--+-- As an example, consider the following pipeline:+--+-- > import Data.Text as T+-- > import Data.Text.Encoding as E+-- > import Data.ByteString (ByteString)+-- >+-- > countChars :: ByteString -> Int+-- > countChars = T.length . T.toUpper . E.decodeUtf8+--+-- From the type signatures involved, this looks like it should+-- allocate one 'Data.ByteString.ByteString' value, and two 'Text'+-- values. However, when a module is compiled with optimisation+-- enabled under GHC, the two intermediate 'Text' values will be+-- optimised away, and the function will be compiled down to a single+-- loop over the source 'Data.ByteString.ByteString'.+--+-- Functions that can be fused by the compiler are documented with the+-- phrase \"Subject to fusion\".++instance Eq Text where+    Text arrA offA lenA == Text arrB offB lenB+        | lenA == lenB = A.equal arrA offA arrB offB lenA+        | otherwise    = False+    {-# INLINE (==) #-}++instance Ord Text where+    compare = compareText++instance Read Text where+    readsPrec p str = [(pack x,y) | (x,y) <- readsPrec p str]++#if MIN_VERSION_base(4,9,0)+-- | Non-orphan 'Semigroup' instance only defined for+-- @base-4.9.0.0@ and later; orphan instances for older GHCs are+-- provided by+-- the [semigroups](http://hackage.haskell.org/package/semigroups)+-- package+--+-- @since 1.2.2.0+instance Semigroup Text where+    (<>) = append+#endif++instance Monoid Text where+    mempty  = empty+#if MIN_VERSION_base(4,9,0)+    mappend = (<>) -- future-proof definition+#else+    mappend = append+#endif+    mconcat = concat++instance IsString Text where+    fromString = pack++#if MIN_VERSION_base(4,7,0)+-- | @since 1.2.0.0+instance Exts.IsList Text where+    type Item Text = Char+    fromList       = pack+    toList         = unpack+#endif++instance NFData Text where rnf !_ = ()++-- | @since 1.2.1.0+instance Binary Text where+    put t = put (encodeUtf8 t)+    get   = do+      bs <- get+      case decodeUtf8' bs of+        P.Left exn -> P.fail (P.show exn)+        P.Right a -> P.return a++-- | This instance preserves data abstraction at the cost of inefficiency.+-- We omit reflection services for the sake of data abstraction.+--+-- This instance was created by copying the updated behavior of+-- @"Data.Set".@'Data.Set.Set' and @"Data.Map".@'Data.Map.Map'. If you+-- feel a mistake has been made, please feel free to submit+-- improvements.+--+-- The original discussion is archived here:+-- <https://mail.haskell.org/pipermail/haskell-cafe/2010-January/072379.html could we get a Data instance for Data.Text.Text? >+--+-- The followup discussion that changed the behavior of 'Data.Set.Set'+-- and 'Data.Map.Map' is archived here:+-- <http://markmail.org/message/trovdc6zkphyi3cr#query:+page:1+mid:a46der3iacwjcf6n+state:results Proposal: Allow gunfold for Data.Map, ... >++instance Data Text where+  gfoldl f z txt = z pack `f` (unpack txt)+  toConstr _ = packConstr+  gunfold k z c = case constrIndex c of+    1 -> k (z pack)+    _ -> P.error "gunfold"+  dataTypeOf _ = textDataType++-- | This instance has similar considerations to the 'Data' instance:+-- it preserves abstraction at the cost of inefficiency.+--+-- @since 1.2.4.0+instance TH.Lift Text where+  lift = TH.appE (TH.varE 'pack) . TH.stringE . unpack+#if MIN_VERSION_template_haskell(2,17,0)+  liftTyped = TH.unsafeCodeCoerce . TH.lift+#elif MIN_VERSION_template_haskell(2,16,0)+  liftTyped = TH.unsafeTExpCoerce . TH.lift+#endif++#if MIN_VERSION_base(4,7,0)+-- | Only defined for @base-4.7.0.0@ and later+--+-- @since 1.2.2.0+instance PrintfArg Text where+  formatArg txt = formatString $ unpack txt+#endif++packConstr :: Constr+packConstr = mkConstr textDataType "pack" [] Prefix++textDataType :: DataType+textDataType = mkDataType "Data.Text.Text" [packConstr]++-- | /O(n)/ Compare two 'Text' values lexicographically.+compareText :: Text -> Text -> Ordering+compareText ta@(Text _arrA _offA lenA) tb@(Text _arrB _offB lenB)+    | lenA == 0 && lenB == 0 = EQ+    | otherwise              = go 0 0+  where+    go !i !j+        | i >= lenA || j >= lenB = compare lenA lenB+        | a < b                  = LT+        | a > b                  = GT+        | otherwise              = go (i+di) (j+dj)+      where Iter a di = iter ta i+            Iter b dj = iter tb j++-- -----------------------------------------------------------------------------+-- * Conversion to/from 'Text'++-- | /O(n)/ Convert a 'String' into a 'Text'.  Subject to+-- fusion.  Performs replacement on invalid scalar values.+pack :: String -> Text+pack = unstream . S.map safe . S.streamList+{-# INLINE [1] pack #-}++-- -----------------------------------------------------------------------------+-- * Basic functions++-- | /O(n)/ Adds a character to the front of a 'Text'.  This function+-- is more costly than its 'List' counterpart because it requires+-- copying a new array.  Subject to fusion.  Performs replacement on+-- invalid scalar values.+cons :: Char -> Text -> Text+cons c t = unstream (S.cons (safe c) (stream t))+{-# INLINE cons #-}++infixr 5 `cons`++-- | /O(n)/ Adds a character to the end of a 'Text'.  This copies the+-- entire array in the process, unless fused.  Subject to fusion.+-- Performs replacement on invalid scalar values.+snoc :: Text -> Char -> Text+snoc t c = unstream (S.snoc (stream t) (safe c))+{-# INLINE snoc #-}++-- | /O(n)/ Appends one 'Text' to the other by copying both of them+-- into a new 'Text'.  Subject to fusion.+append :: Text -> Text -> Text+append a@(Text arr1 off1 len1) b@(Text arr2 off2 len2)+    | len1 == 0 = b+    | len2 == 0 = a+    | len > 0   = Text (A.run x) 0 len+    | otherwise = overflowError "append"+    where+      len = len1+len2+      x :: ST s (A.MArray s)+      x = do+        arr <- A.new len+        A.copyI arr 0 arr1 off1 len1+        A.copyI arr len1 arr2 off2 len+        return arr+{-# NOINLINE append #-}++{-# RULES+"TEXT append -> fused" [~1] forall t1 t2.+    append t1 t2 = unstream (S.append (stream t1) (stream t2))+"TEXT append -> unfused" [1] forall t1 t2.+    unstream (S.append (stream t1) (stream t2)) = append t1 t2+ #-}++-- | /O(1)/ Returns the first character of a 'Text', which must be+-- non-empty.  Subject to fusion.+head :: Text -> Char+head t = S.head (stream t)+{-# INLINE head #-}++-- | /O(1)/ Returns the first character and rest of a 'Text', or+-- 'Nothing' if empty. Subject to fusion.+uncons :: Text -> Maybe (Char, Text)+uncons t@(Text arr off len)+    | len <= 0  = Nothing+    | otherwise = Just $ let !(Iter c d) = iter t 0+                         in (c, text arr (off+d) (len-d))+{-# INLINE [1] uncons #-}++-- | Lifted from Control.Arrow and specialized.+second :: (b -> c) -> (a,b) -> (a,c)+second f (a, b) = (a, f b)++-- | /O(1)/ Returns the last character of a 'Text', which must be+-- non-empty.  Subject to fusion.+last :: Text -> Char+last (Text arr off len)+    | len <= 0                 = emptyError "last"+    | n < 0xDC00 || n > 0xDFFF = unsafeChr n+    | otherwise                = U16.chr2 n0 n+    where n  = A.unsafeIndex arr (off+len-1)+          n0 = A.unsafeIndex arr (off+len-2)+{-# INLINE [1] last #-}++{-# RULES+"TEXT last -> fused" [~1] forall t.+    last t = S.last (stream t)+"TEXT last -> unfused" [1] forall t.+    S.last (stream t) = last t+  #-}++-- | /O(1)/ Returns all characters after the head of a 'Text', which+-- must be non-empty.  Subject to fusion.+tail :: Text -> Text+tail t@(Text arr off len)+    | len <= 0  = emptyError "tail"+    | otherwise = text arr (off+d) (len-d)+    where d = iter_ t 0+{-# INLINE [1] tail #-}++{-# RULES+"TEXT tail -> fused" [~1] forall t.+    tail t = unstream (S.tail (stream t))+"TEXT tail -> unfused" [1] forall t.+    unstream (S.tail (stream t)) = tail t+ #-}++-- | /O(1)/ Returns all but the last character of a 'Text', which must+-- be non-empty.  Subject to fusion.+init :: Text -> Text+init (Text arr off len) | len <= 0                   = emptyError "init"+                        | n >= 0xDC00 && n <= 0xDFFF = text arr off (len-2)+                        | otherwise                  = text arr off (len-1)+    where+      n = A.unsafeIndex arr (off+len-1)+{-# INLINE [1] init #-}++{-# RULES+"TEXT init -> fused" [~1] forall t.+    init t = unstream (S.init (stream t))+"TEXT init -> unfused" [1] forall t.+    unstream (S.init (stream t)) = init t+ #-}++-- | /O(1)/ Returns all but the last character and the last character of a+-- 'Text', or 'Nothing' if empty.+--+-- @since 1.2.3.0+unsnoc :: Text -> Maybe (Text, Char)+unsnoc (Text arr off len)+    | len <= 0                 = Nothing+    | n < 0xDC00 || n > 0xDFFF = Just (text arr off (len-1), unsafeChr n)+    | otherwise                = Just (text arr off (len-2), U16.chr2 n0 n)+    where n  = A.unsafeIndex arr (off+len-1)+          n0 = A.unsafeIndex arr (off+len-2)+{-# INLINE [1] unsnoc #-}++-- | /O(1)/ Tests whether a 'Text' is empty or not.  Subject to+-- fusion.+null :: Text -> Bool+null (Text _arr _off len) =+#if defined(ASSERTS)+    assert (len >= 0) $+#endif+    len <= 0+{-# INLINE [1] null #-}++{-# RULES+"TEXT null -> fused" [~1] forall t.+    null t = S.null (stream t)+"TEXT null -> unfused" [1] forall t.+    S.null (stream t) = null t+ #-}++-- | /O(1)/ Tests whether a 'Text' contains exactly one character.+-- Subject to fusion.+isSingleton :: Text -> Bool+isSingleton = S.isSingleton . stream+{-# INLINE isSingleton #-}++-- | /O(n)/ Returns the number of characters in a 'Text'.+-- Subject to fusion.+length :: Text -> Int+length t = S.length (stream t)+{-# INLINE [1] length #-}+-- length needs to be phased after the compareN/length rules otherwise+-- it may inline before the rules have an opportunity to fire.++-- | /O(n)/ Compare the count of characters in a 'Text' to a number.+-- Subject to fusion.+--+-- This function gives the same answer as comparing against the result+-- of 'length', but can short circuit if the count of characters is+-- greater than the number, and hence be more efficient.+compareLength :: Text -> Int -> Ordering+compareLength t n = S.compareLengthI (stream t) n+{-# INLINE [1] compareLength #-}++{-# RULES+"TEXT compareN/length -> compareLength" [~1] forall t n.+    compare (length t) n = compareLength t n+  #-}++{-# RULES+"TEXT ==N/length -> compareLength/==EQ" [~1] forall t n.+    eqInt (length t) n = compareLength t n == EQ+  #-}++{-# RULES+"TEXT /=N/length -> compareLength//=EQ" [~1] forall t n.+    neInt (length t) n = compareLength t n /= EQ+  #-}++{-# RULES+"TEXT <N/length -> compareLength/==LT" [~1] forall t n.+    ltInt (length t) n = compareLength t n == LT+  #-}++{-# RULES+"TEXT <=N/length -> compareLength//=GT" [~1] forall t n.+    leInt (length t) n = compareLength t n /= GT+  #-}++{-# RULES+"TEXT >N/length -> compareLength/==GT" [~1] forall t n.+    gtInt (length t) n = compareLength t n == GT+  #-}++{-# RULES+"TEXT >=N/length -> compareLength//=LT" [~1] forall t n.+    geInt (length t) n = compareLength t n /= LT+  #-}++-- -----------------------------------------------------------------------------+-- * Transformations+-- | /O(n)/ 'map' @f@ @t@ is the 'Text' obtained by applying @f@ to+-- each element of @t@.+--+-- Example:+--+-- >>> let message = pack "I am not angry. Not at all."+-- >>> T.map (\c -> if c == '.' then '!' else c) message+-- "I am not angry! Not at all!"+--+-- Subject to fusion.  Performs replacement on invalid scalar values.+map :: (Char -> Char) -> Text -> Text+map f t = unstream (S.map (safe . f) (stream t))+{-# INLINE [1] map #-}++-- | /O(n)/ The 'intercalate' function takes a 'Text' and a list of+-- 'Text's and concatenates the list after interspersing the first+-- argument between each element of the list.+--+-- Example:+--+-- >>> T.intercalate "NI!" ["We", "seek", "the", "Holy", "Grail"]+-- "WeNI!seekNI!theNI!HolyNI!Grail"+intercalate :: Text -> [Text] -> Text+intercalate t = concat . (F.intersperse t)+{-# INLINE intercalate #-}++-- | /O(n)/ The 'intersperse' function takes a character and places it+-- between the characters of a 'Text'.+--+-- Example:+--+-- >>> T.intersperse '.' "SHIELD"+-- "S.H.I.E.L.D"+--+-- Subject to fusion.  Performs replacement on invalid scalar values.+intersperse     :: Char -> Text -> Text+intersperse c t = unstream (S.intersperse (safe c) (stream t))+{-# INLINE intersperse #-}++-- | /O(n)/ Reverse the characters of a string.+--+-- Example:+--+-- >>> T.reverse "desrever"+-- "reversed"+--+-- Subject to fusion (fuses with its argument).+reverse :: Text -> Text+reverse t = S.reverse (stream t)+{-# INLINE reverse #-}++-- | /O(m+n)/ Replace every non-overlapping occurrence of @needle@ in+-- @haystack@ with @replacement@.+--+-- This function behaves as though it was defined as follows:+--+-- @+-- replace needle replacement haystack =+--   'intercalate' replacement ('splitOn' needle haystack)+-- @+--+-- As this suggests, each occurrence is replaced exactly once.  So if+-- @needle@ occurs in @replacement@, that occurrence will /not/ itself+-- be replaced recursively:+--+-- >>> replace "oo" "foo" "oo"+-- "foo"+--+-- In cases where several instances of @needle@ overlap, only the+-- first one will be replaced:+--+-- >>> replace "ofo" "bar" "ofofo"+-- "barfo"+--+-- In (unlikely) bad cases, this function's time complexity degrades+-- towards /O(n*m)/.+replace :: Text+        -- ^ @needle@ to search for.  If this string is empty, an+        -- error will occur.+        -> Text+        -- ^ @replacement@ to replace @needle@ with.+        -> Text+        -- ^ @haystack@ in which to search.+        -> Text+replace needle@(Text _      _      neeLen)+               (Text repArr repOff repLen)+      haystack@(Text hayArr hayOff hayLen)+  | neeLen == 0 = emptyError "replace"+  | L.null ixs  = haystack+  | len > 0     = Text (A.run x) 0 len+  | otherwise   = empty+  where+    ixs = indices needle haystack+    len = hayLen - (neeLen - repLen) `mul` L.length ixs+    x :: ST s (A.MArray s)+    x = do+      marr <- A.new len+      let loop (i:is) o d = do+            let d0 = d + i - o+                d1 = d0 + repLen+            A.copyI marr d  hayArr (hayOff+o) d0+            A.copyI marr d0 repArr repOff d1+            loop is (i + neeLen) d1+          loop []     o d = A.copyI marr d hayArr (hayOff+o) len+      loop ixs 0 0+      return marr++-- ----------------------------------------------------------------------------+-- ** Case conversions (folds)++-- $case+--+-- When case converting 'Text' values, do not use combinators like+-- @map toUpper@ to case convert each character of a string+-- individually, as this gives incorrect results according to the+-- rules of some writing systems.  The whole-string case conversion+-- functions from this module, such as @toUpper@, obey the correct+-- case conversion rules.  As a result, these functions may map one+-- input character to two or three output characters. For examples,+-- see the documentation of each function.+--+-- /Note/: In some languages, case conversion is a locale- and+-- context-dependent operation. The case conversion functions in this+-- module are /not/ locale sensitive. Programs that require locale+-- sensitivity should use appropriate versions of the+-- <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 >.++-- | /O(n)/ Convert a string to folded case.  Subject to fusion.+--+-- This function is mainly useful for performing caseless (also known+-- as case insensitive) string comparisons.+--+-- A string @x@ is a caseless match for a string @y@ if and only if:+--+-- @toCaseFold x == toCaseFold y@+--+-- The result string may be longer than the input string, and may+-- differ from applying 'toLower' to the input string.  For instance,+-- the Armenian small ligature \"&#xfb13;\" (men now, U+FB13) is case+-- folded to the sequence \"&#x574;\" (men, U+0574) followed by+-- \"&#x576;\" (now, U+0576), while the Greek \"&#xb5;\" (micro sign,+-- U+00B5) is case folded to \"&#x3bc;\" (small letter mu, U+03BC)+-- instead of itself.+toCaseFold :: Text -> Text+toCaseFold t = unstream (S.toCaseFold (stream t))+{-# INLINE toCaseFold #-}++-- | /O(n)/ Convert a string to lower case, using simple case+-- conversion.  Subject to fusion.+--+-- The result string may be longer than the input string.  For+-- instance, \"&#x130;\" (Latin capital letter I with dot above,+-- U+0130) maps to the sequence \"i\" (Latin small letter i, U+0069)+-- followed by \" &#x307;\" (combining dot above, U+0307).+toLower :: Text -> Text+toLower t = unstream (S.toLower (stream t))+{-# INLINE toLower #-}++-- | /O(n)/ Convert a string to upper case, using simple case+-- conversion.  Subject to fusion.+--+-- The result string may be longer than the input string.  For+-- instance, the German \"&#xdf;\" (eszett, U+00DF) maps to the+-- two-letter sequence \"SS\".+toUpper :: Text -> Text+toUpper t = unstream (S.toUpper (stream t))+{-# INLINE toUpper #-}++-- | /O(n)/ Convert a string to title case, using simple case+-- conversion. Subject to fusion.+--+-- The first letter of the input is converted to title case, as is+-- every subsequent letter that immediately follows a non-letter.+-- Every letter that immediately follows another letter is converted+-- to lower case.+--+-- The result string may be longer than the input string. For example,+-- the Latin small ligature &#xfb02; (U+FB02) is converted to the+-- sequence Latin capital letter F (U+0046) followed by Latin small+-- letter l (U+006C).+--+-- /Note/: this function does not take language or culture specific+-- rules into account. For instance, in English, different style+-- guides disagree on whether the book name \"The Hill of the Red+-- Fox\" is correctly title cased&#x2014;but this function will+-- capitalize /every/ word.+--+-- @since 1.0.0.0+toTitle :: Text -> Text+toTitle t = unstream (S.toTitle (stream t))+{-# INLINE toTitle #-}++-- | /O(n)/ Left-justify a string to the given length, using the+-- specified fill character on the right. Subject to fusion.+-- Performs replacement on invalid scalar values.+--+-- Examples:+--+-- >>> justifyLeft 7 'x' "foo"+-- "fooxxxx"+--+-- >>> justifyLeft 3 'x' "foobar"+-- "foobar"+justifyLeft :: Int -> Char -> Text -> Text+justifyLeft k c t+    | len >= k  = t+    | otherwise = t `append` replicateChar (k-len) c+  where len = length t+{-# INLINE [1] justifyLeft #-}++{-# RULES+"TEXT justifyLeft -> fused" [~1] forall k c t.+    justifyLeft k c t = unstream (S.justifyLeftI k c (stream t))+"TEXT justifyLeft -> unfused" [1] forall k c t.+    unstream (S.justifyLeftI k c (stream t)) = justifyLeft k c t+  #-}++-- | /O(n)/ Right-justify a string to the given length, using the+-- specified fill character on the left.  Performs replacement on+-- invalid scalar values.+--+-- Examples:+--+-- >>> justifyRight 7 'x' "bar"+-- "xxxxbar"+--+-- >>> justifyRight 3 'x' "foobar"+-- "foobar"+justifyRight :: Int -> Char -> Text -> Text+justifyRight k c t+    | len >= k  = t+    | otherwise = replicateChar (k-len) c `append` t+  where len = length t+{-# INLINE justifyRight #-}++-- | /O(n)/ Center a string to the given length, using the specified+-- fill character on either side.  Performs replacement on invalid+-- scalar values.+--+-- Examples:+--+-- >>> center 8 'x' "HS"+-- "xxxHSxxx"+center :: Int -> Char -> Text -> Text+center k c t+    | len >= k  = t+    | otherwise = replicateChar l c `append` t `append` replicateChar r c+  where len = length t+        d   = k - len+        r   = d `quot` 2+        l   = d - r+{-# INLINE center #-}++-- | /O(n)/ The 'transpose' function transposes the rows and columns+-- of its 'Text' argument.  Note that this function uses 'pack',+-- 'unpack', and the list version of transpose, and is thus not very+-- efficient.+--+-- Examples:+--+-- >>> transpose ["green","orange"]+-- ["go","rr","ea","en","ng","e"]+--+-- >>> transpose ["blue","red"]+-- ["br","le","ud","e"]+transpose :: [Text] -> [Text]+transpose ts = P.map pack (L.transpose (P.map unpack ts))++-- -----------------------------------------------------------------------------+-- * Reducing 'Text's (folds)++-- | /O(n)/ 'foldl', applied to a binary operator, a starting value+-- (typically the left-identity of the operator), and a 'Text',+-- reduces the 'Text' using the binary operator, from left to right.+-- Subject to fusion.+foldl :: (a -> Char -> a) -> a -> Text -> a+foldl f z t = S.foldl f z (stream t)+{-# INLINE foldl #-}++-- | /O(n)/ A strict version of 'foldl'.  Subject to fusion.+foldl' :: (a -> Char -> a) -> a -> Text -> a+foldl' f z t = S.foldl' f z (stream t)+{-# INLINE foldl' #-}++-- | /O(n)/ A variant of 'foldl' that has no starting value argument,+-- and thus must be applied to a non-empty 'Text'.  Subject to fusion.+foldl1 :: (Char -> Char -> Char) -> Text -> Char+foldl1 f t = S.foldl1 f (stream t)+{-# INLINE foldl1 #-}++-- | /O(n)/ A strict version of 'foldl1'.  Subject to fusion.+foldl1' :: (Char -> Char -> Char) -> Text -> Char+foldl1' f t = S.foldl1' f (stream t)+{-# INLINE foldl1' #-}++-- | /O(n)/ 'foldr', applied to a binary operator, a starting value+-- (typically the right-identity of the operator), and a 'Text',+-- reduces the 'Text' using the binary operator, from right to left.+-- Subject to fusion.+foldr :: (Char -> a -> a) -> a -> Text -> a+foldr f z t = S.foldr f z (stream t)+{-# INLINE foldr #-}++-- | /O(n)/ A variant of 'foldr' that has no starting value argument,+-- and thus must be applied to a non-empty 'Text'.  Subject to+-- fusion.+foldr1 :: (Char -> Char -> Char) -> Text -> Char+foldr1 f t = S.foldr1 f (stream t)+{-# INLINE foldr1 #-}++-- -----------------------------------------------------------------------------+-- ** Special folds++-- | /O(n)/ Concatenate a list of 'Text's.+concat :: [Text] -> Text+concat ts = case ts' of+              [] -> empty+              [t] -> t+              _ -> Text (A.run go) 0 len+  where+    ts' = L.filter (not . null) ts+    len = sumP "concat" $ L.map lengthWord16 ts'+    go :: ST s (A.MArray s)+    go = do+      arr <- A.new len+      let step i (Text a o l) =+            let !j = i + l in A.copyI arr i a o j >> return j+      foldM step 0 ts' >> return arr++-- | /O(n)/ Map a function over a 'Text' that results in a 'Text', and+-- concatenate the results.+concatMap :: (Char -> Text) -> Text -> Text+concatMap f = concat . foldr ((:) . f) []+{-# INLINE concatMap #-}++-- | /O(n)/ 'any' @p@ @t@ determines whether any character in the+-- 'Text' @t@ satisfies the predicate @p@. Subject to fusion.+any :: (Char -> Bool) -> Text -> Bool+any p t = S.any p (stream t)+{-# INLINE any #-}++-- | /O(n)/ 'all' @p@ @t@ determines whether all characters in the+-- 'Text' @t@ satisfy the predicate @p@. Subject to fusion.+all :: (Char -> Bool) -> Text -> Bool+all p t = S.all p (stream t)+{-# INLINE all #-}++-- | /O(n)/ 'maximum' returns the maximum value from a 'Text', which+-- must be non-empty. Subject to fusion.+maximum :: Text -> Char+maximum t = S.maximum (stream t)+{-# INLINE maximum #-}++-- | /O(n)/ 'minimum' returns the minimum value from a 'Text', which+-- must be non-empty. Subject to fusion.+minimum :: Text -> Char+minimum t = S.minimum (stream t)+{-# INLINE minimum #-}++-- -----------------------------------------------------------------------------+-- * Building 'Text's++-- | /O(n)/ 'scanl' is similar to 'foldl', but returns a list of+-- successive reduced values from the left. Subject to fusion.+-- Performs replacement on invalid scalar values.+--+-- > scanl f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...]+--+-- Note that+--+-- > last (scanl f z xs) == foldl f z xs.+scanl :: (Char -> Char -> Char) -> Char -> Text -> Text+scanl f z t = unstream (S.scanl g z (stream t))+    where g a b = safe (f a b)+{-# INLINE scanl #-}++-- | /O(n)/ 'scanl1' is a variant of 'scanl' that has no starting+-- value argument. Performs replacement on invalid scalar values.+--+-- > scanl1 f [x1, x2, ...] == [x1, x1 `f` x2, ...]+scanl1 :: (Char -> Char -> Char) -> Text -> Text+scanl1 f t | null t    = empty+           | otherwise = scanl f (unsafeHead t) (unsafeTail t)+{-# INLINE scanl1 #-}++-- | /O(n)/ 'scanr' is the right-to-left dual of 'scanl'.  Performs+-- replacement on invalid scalar values.+--+-- > scanr f v == reverse . scanl (flip f) v . reverse+scanr :: (Char -> Char -> Char) -> Char -> Text -> Text+scanr f z = S.reverse . S.reverseScanr g z . reverseStream+    where g a b = safe (f a b)+{-# INLINE scanr #-}++-- | /O(n)/ 'scanr1' is a variant of 'scanr' that has no starting+-- value argument. Performs replacement on invalid scalar values.+scanr1 :: (Char -> Char -> Char) -> Text -> Text+scanr1 f t | null t    = empty+           | otherwise = scanr f (last t) (init t)+{-# INLINE scanr1 #-}++-- | /O(n)/ Like a combination of 'map' and 'foldl''. Applies a+-- function to each element of a 'Text', passing an accumulating+-- parameter from left to right, and returns a final 'Text'.  Performs+-- replacement on invalid scalar values.+mapAccumL :: (a -> Char -> (a,Char)) -> a -> Text -> (a, Text)+mapAccumL f z0 = S.mapAccumL g z0 . stream+    where g a b = second safe (f a b)+{-# INLINE mapAccumL #-}++-- | The 'mapAccumR' function behaves like a combination of 'map' and+-- a strict 'foldr'; it applies a function to each element of a+-- 'Text', passing an accumulating parameter from right to left, and+-- returning a final value of this accumulator together with the new+-- 'Text'.+-- Performs replacement on invalid scalar values.+mapAccumR :: (a -> Char -> (a,Char)) -> a -> Text -> (a, Text)+mapAccumR f z0 = second reverse . S.mapAccumL g z0 . reverseStream+    where g a b = second safe (f a b)+{-# INLINE mapAccumR #-}++-- -----------------------------------------------------------------------------+-- ** Generating and unfolding 'Text's++-- | /O(n*m)/ 'replicate' @n@ @t@ is a 'Text' consisting of the input+-- @t@ repeated @n@ times.+replicate :: Int -> Text -> Text+replicate n t@(Text a o l)+    | n <= 0 || l <= 0       = empty+    | n == 1                 = t+    | isSingleton t          = replicateChar n (unsafeHead t)+    | otherwise              = Text (A.run x) 0 len+  where+    len = l `mul` n -- TODO: detect overflows+    x :: ST s (A.MArray s)+    x = do+      arr <- A.new len+      A.copyI arr 0 a o l+      let loop !l1 =+            let rest = len - l1 in+            if rest <= l1 then A.copyM arr l1 arr 0 rest >> return arr+            else A.copyM arr l1 arr 0 l1 >> loop (l1 `shiftL` 1)+      loop l+{-# INLINE [1] replicate #-}+++{-# RULES+"TEXT replicate/singleton -> replicateChar" [~1] forall n c.+    replicate n (singleton c) = replicateChar n c+  #-}++-- | /O(n)/ 'replicateChar' @n@ @c@ is a 'Text' of length @n@ with @c@ the+-- value of every element. Subject to fusion.+replicateChar :: Int -> Char -> Text+replicateChar n c = unstream (S.replicateCharI n (safe c))+{-# INLINE replicateChar #-}++-- | /O(n)/, where @n@ is the length of the result. The 'unfoldr'+-- function is analogous to the List 'L.unfoldr'. 'unfoldr' builds a+-- 'Text' from a seed value. The function takes the element and+-- returns 'Nothing' if it is done producing the 'Text', otherwise+-- 'Just' @(a,b)@.  In this case, @a@ is the next 'Char' in the+-- string, and @b@ is the seed value for further production. Subject+-- to fusion.  Performs replacement on invalid scalar values.+unfoldr     :: (a -> Maybe (Char,a)) -> a -> Text+unfoldr f s = unstream (S.unfoldr (firstf safe . f) s)+{-# INLINE unfoldr #-}++-- | /O(n)/ Like 'unfoldr', 'unfoldrN' builds a 'Text' from a seed+-- value. However, the length of the result should be limited by the+-- first argument to 'unfoldrN'. This function is more efficient than+-- 'unfoldr' when the maximum length of the result is known and+-- correct, otherwise its performance is similar to 'unfoldr'. Subject+-- to fusion.  Performs replacement on invalid scalar values.+unfoldrN     :: Int -> (a -> Maybe (Char,a)) -> a -> Text+unfoldrN n f s = unstream (S.unfoldrN n (firstf safe . f) s)+{-# INLINE unfoldrN #-}++-- -----------------------------------------------------------------------------+-- * Substrings++-- | /O(n)/ 'take' @n@, applied to a 'Text', returns the prefix of the+-- 'Text' of length @n@, or the 'Text' itself if @n@ is greater than+-- the length of the Text. Subject to fusion.+take :: Int -> Text -> Text+take n t@(Text arr off len)+    | n <= 0    = empty+    | n >= len  = t+    | otherwise = text arr off (iterN n t)+{-# INLINE [1] take #-}++iterN :: Int -> Text -> Int+iterN n t@(Text _arr _off len) = loop 0 0+  where loop !i !cnt+            | i >= len || cnt >= n = i+            | otherwise            = loop (i+d) (cnt+1)+          where d = iter_ t i++{-# RULES+"TEXT take -> fused" [~1] forall n t.+    take n t = unstream (S.take n (stream t))+"TEXT take -> unfused" [1] forall n t.+    unstream (S.take n (stream t)) = take n t+  #-}++-- | /O(n)/ 'takeEnd' @n@ @t@ returns the suffix remaining after+-- taking @n@ characters from the end of @t@.+--+-- Examples:+--+-- >>> takeEnd 3 "foobar"+-- "bar"+--+-- @since 1.1.1.0+takeEnd :: Int -> Text -> Text+takeEnd n t@(Text arr off len)+    | n <= 0    = empty+    | n >= len  = t+    | otherwise = text arr (off+i) (len-i)+  where i = iterNEnd n t++iterNEnd :: Int -> Text -> Int+iterNEnd n t@(Text _arr _off len) = loop (len-1) n+  where loop i !m+          | m <= 0    = i+1+          | i <= 0    = 0+          | otherwise = loop (i+d) (m-1)+          where d = reverseIter_ t i++-- | /O(n)/ 'drop' @n@, applied to a 'Text', returns the suffix of the+-- 'Text' after the first @n@ characters, or the empty 'Text' if @n@+-- is greater than the length of the 'Text'. Subject to fusion.+drop :: Int -> Text -> Text+drop n t@(Text arr off len)+    | n <= 0    = t+    | n >= len  = empty+    | otherwise = text arr (off+i) (len-i)+  where i = iterN n t+{-# INLINE [1] drop #-}++{-# RULES+"TEXT drop -> fused" [~1] forall n t.+    drop n t = unstream (S.drop n (stream t))+"TEXT drop -> unfused" [1] forall n t.+    unstream (S.drop n (stream t)) = drop n t+"TEXT take . drop -> unfused" [1] forall len off t.+    unstream (S.take len (S.drop off (stream t))) = take len (drop off t)+  #-}++-- | /O(n)/ 'dropEnd' @n@ @t@ returns the prefix remaining after+-- dropping @n@ characters from the end of @t@.+--+-- Examples:+--+-- >>> dropEnd 3 "foobar"+-- "foo"+--+-- @since 1.1.1.0+dropEnd :: Int -> Text -> Text+dropEnd n t@(Text arr off len)+    | n <= 0    = t+    | n >= len  = empty+    | otherwise = text arr off (iterNEnd n t)++-- | /O(n)/ 'takeWhile', applied to a predicate @p@ and a 'Text',+-- returns the longest prefix (possibly empty) of elements that+-- satisfy @p@.  Subject to fusion.+takeWhile :: (Char -> Bool) -> Text -> Text+takeWhile p t@(Text arr off len) = loop 0+  where loop !i | i >= len    = t+                | p c         = loop (i+d)+                | otherwise   = text arr off i+            where Iter c d    = iter t i+{-# INLINE [1] takeWhile #-}++{-# RULES+"TEXT takeWhile -> fused" [~1] forall p t.+    takeWhile p t = unstream (S.takeWhile p (stream t))+"TEXT takeWhile -> unfused" [1] forall p t.+    unstream (S.takeWhile p (stream t)) = takeWhile p t+  #-}++-- | /O(n)/ 'takeWhileEnd', applied to a predicate @p@ and a 'Text',+-- returns the longest suffix (possibly empty) of elements that+-- satisfy @p@.+-- Examples:+--+-- >>> takeWhileEnd (=='o') "foo"+-- "oo"+--+-- @since 1.2.2.0+takeWhileEnd :: (Char -> Bool) -> Text -> Text+takeWhileEnd p t@(Text arr off len) = loop (len-1) len+  where loop !i !l | l <= 0    = t+                   | p c       = loop (i+d) (l+d)+                   | otherwise = text arr (off+l) (len-l)+            where (c,d)        = reverseIter t i+{-# INLINE [1] takeWhileEnd #-}++-- | /O(n)/ 'dropWhile' @p@ @t@ returns the suffix remaining after+-- 'takeWhile' @p@ @t@. Subject to fusion.+dropWhile :: (Char -> Bool) -> Text -> Text+dropWhile p t@(Text arr off len) = loop 0 0+  where loop !i !l | l >= len  = empty+                   | p c       = loop (i+d) (l+d)+                   | otherwise = Text arr (off+i) (len-l)+            where Iter c d     = iter t i+{-# INLINE [1] dropWhile #-}++{-# RULES+"TEXT dropWhile -> fused" [~1] forall p t.+    dropWhile p t = unstream (S.dropWhile p (stream t))+"TEXT dropWhile -> unfused" [1] forall p t.+    unstream (S.dropWhile p (stream t)) = dropWhile p t+  #-}++-- | /O(n)/ 'dropWhileEnd' @p@ @t@ returns the prefix remaining after+-- dropping characters that satisfy the predicate @p@ from the end of+-- @t@.+--+-- Examples:+--+-- >>> dropWhileEnd (=='.') "foo..."+-- "foo"+dropWhileEnd :: (Char -> Bool) -> Text -> Text+dropWhileEnd p t@(Text arr off len) = loop (len-1) len+  where loop !i !l | l <= 0    = empty+                   | p c       = loop (i+d) (l+d)+                   | otherwise = Text arr off l+            where (c,d)        = reverseIter t i+{-# INLINE [1] dropWhileEnd #-}++-- | /O(n)/ 'dropAround' @p@ @t@ returns the substring remaining after+-- dropping characters that satisfy the predicate @p@ from both the+-- beginning and end of @t@.  Subject to fusion.+dropAround :: (Char -> Bool) -> Text -> Text+dropAround p = dropWhile p . dropWhileEnd p+{-# INLINE [1] dropAround #-}++-- | /O(n)/ Remove leading white space from a string.  Equivalent to:+--+-- > dropWhile isSpace+stripStart :: Text -> Text+stripStart = dropWhile isSpace+{-# INLINE stripStart #-}++-- | /O(n)/ Remove trailing white space from a string.  Equivalent to:+--+-- > dropWhileEnd isSpace+stripEnd :: Text -> Text+stripEnd = dropWhileEnd isSpace+{-# INLINE [1] stripEnd #-}++-- | /O(n)/ Remove leading and trailing white space from a string.+-- Equivalent to:+--+-- > dropAround isSpace+strip :: Text -> Text+strip = dropAround isSpace+{-# INLINE [1] strip #-}++-- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a+-- prefix of @t@ of length @n@, and whose second is the remainder of+-- the string. It is equivalent to @('take' n t, 'drop' n t)@.+splitAt :: Int -> Text -> (Text, Text)+splitAt n t@(Text arr off len)+    | n <= 0    = (empty, t)+    | n >= len  = (t, empty)+    | otherwise = let k = iterN n t+                  in (text arr off k, text arr (off+k) (len-k))++-- | /O(n)/ 'span', applied to a predicate @p@ and text @t@, returns+-- a pair whose first element is the longest prefix (possibly empty)+-- of @t@ of elements that satisfy @p@, and whose second is the+-- remainder of the list.+--+-- >>> T.span (=='0') "000AB"+-- ("000","AB")+span :: (Char -> Bool) -> Text -> (Text, Text)+span p t = case span_ p t of+             (# hd,tl #) -> (hd,tl)+{-# INLINE span #-}++-- | /O(n)/ 'break' is like 'span', but the prefix returned is+-- over elements that fail the predicate @p@.+--+-- >>> T.break (=='c') "180cm"+-- ("180","cm")+break :: (Char -> Bool) -> Text -> (Text, Text)+break p = span (not . p)+{-# INLINE break #-}++-- | /O(n)/ Group characters in a string according to a predicate.+groupBy :: (Char -> Char -> Bool) -> Text -> [Text]+groupBy p = loop+  where+    loop t@(Text arr off len)+        | null t    = []+        | otherwise = text arr off n : loop (text arr (off+n) (len-n))+        where Iter c d = iter t 0+              n     = d + findAIndexOrEnd (not . p c) (Text arr (off+d) (len-d))++-- | Returns the /array/ index (in units of 'Word16') at which a+-- character may be found.  This is /not/ the same as the logical+-- index returned by e.g. 'findIndex'.+findAIndexOrEnd :: (Char -> Bool) -> Text -> Int+findAIndexOrEnd q t@(Text _arr _off len) = go 0+    where go !i | i >= len || q c       = i+                | otherwise             = go (i+d)+                where Iter c d          = iter t i++-- | /O(n)/ Group characters in a string by equality.+group :: Text -> [Text]+group = groupBy (==)++-- | /O(n)/ Return all initial segments of the given 'Text', shortest+-- first.+inits :: Text -> [Text]+inits t@(Text arr off len) = loop 0+    where loop i | i >= len = [t]+                 | otherwise = Text arr off i : loop (i + iter_ t i)++-- | /O(n)/ Return all final segments of the given 'Text', longest+-- first.+tails :: Text -> [Text]+tails t | null t    = [empty]+        | otherwise = t : tails (unsafeTail t)++-- $split+--+-- Splitting functions in this library do not perform character-wise+-- copies to create substrings; they just construct new 'Text's that+-- are slices of the original.++-- | /O(m+n)/ Break a 'Text' into pieces separated by the first 'Text'+-- argument (which cannot be empty), consuming the delimiter. An empty+-- delimiter is invalid, and will cause an error to be raised.+--+-- Examples:+--+-- >>> splitOn "\r\n" "a\r\nb\r\nd\r\ne"+-- ["a","b","d","e"]+--+-- >>> splitOn "aaa"  "aaaXaaaXaaaXaaa"+-- ["","X","X","X",""]+--+-- >>> splitOn "x"    "x"+-- ["",""]+--+-- and+--+-- > intercalate s . splitOn s         == id+-- > splitOn (singleton c)             == split (==c)+--+-- (Note: the string @s@ to split on above cannot be empty.)+--+-- In (unlikely) bad cases, this function's time complexity degrades+-- towards /O(n*m)/.+splitOn :: Text+        -- ^ String to split on. If this string is empty, an error+        -- will occur.+        -> Text+        -- ^ Input text.+        -> [Text]+splitOn pat@(Text _ _ l) src@(Text arr off len)+    | l <= 0          = emptyError "splitOn"+    | isSingleton pat = split (== unsafeHead pat) src+    | otherwise       = go 0 (indices pat src)+  where+    go !s (x:xs) =  text arr (s+off) (x-s) : go (x+l) xs+    go  s _      = [text arr (s+off) (len-s)]+{-# INLINE [1] splitOn #-}++{-# RULES+"TEXT splitOn/singleton -> split/==" [~1] forall c t.+    splitOn (singleton c) t = split (==c) t+  #-}++-- | /O(n)/ Splits a 'Text' into components delimited by separators,+-- where the predicate returns True for a separator element.  The+-- resulting components do not contain the separators.  Two adjacent+-- separators result in an empty component in the output.  eg.+--+-- >>> split (=='a') "aabbaca"+-- ["","","bb","c",""]+--+-- >>> split (=='a') ""+-- [""]+split :: (Char -> Bool) -> Text -> [Text]+split _ t@(Text _off _arr 0) = [t]+split p t = loop t+    where loop s | null s'   = [l]+                 | otherwise = l : loop (unsafeTail s')+              where (# l, s' #) = span_ (not . p) s+{-# INLINE split #-}++-- | /O(n)/ Splits a 'Text' into components of length @k@.  The last+-- element may be shorter than the other chunks, depending on the+-- length of the input. Examples:+--+-- >>> chunksOf 3 "foobarbaz"+-- ["foo","bar","baz"]+--+-- >>> chunksOf 4 "haskell.org"+-- ["hask","ell.","org"]+chunksOf :: Int -> Text -> [Text]+chunksOf k = go+  where+    go t = case splitAt k t of+             (a,b) | null a    -> []+                   | otherwise -> a : go b+{-# INLINE chunksOf #-}++-- ----------------------------------------------------------------------------+-- * Searching++-------------------------------------------------------------------------------+-- ** Searching with a predicate++-- | /O(n)/ The 'find' function takes a predicate and a 'Text', and+-- returns the first element matching the predicate, or 'Nothing' if+-- there is no such element. Subject to fusion.+find :: (Char -> Bool) -> Text -> Maybe Char+find p t = S.findBy p (stream t)+{-# INLINE find #-}++-- | /O(n)/ The 'partition' function takes a predicate and a 'Text',+-- and returns the pair of 'Text's with elements which do and do not+-- satisfy the predicate, respectively; i.e.+--+-- > partition p t == (filter p t, filter (not . p) t)+partition :: (Char -> Bool) -> Text -> (Text, Text)+partition p t = (filter p t, filter (not . p) t)+{-# INLINE partition #-}++-- | /O(n)/ 'filter', applied to a predicate and a 'Text',+-- returns a 'Text' containing those characters that satisfy the+-- predicate.+filter :: (Char -> Bool) -> Text -> Text+filter p t = unstream (S.filter p (stream t))+{-# INLINE filter #-}++-- | /O(n+m)/ Find the first instance of @needle@ (which must be+-- non-'null') in @haystack@.  The first element of the returned tuple+-- is the prefix of @haystack@ before @needle@ is matched.  The second+-- is the remainder of @haystack@, starting with the match.+--+-- Examples:+--+-- >>> breakOn "::" "a::b::c"+-- ("a","::b::c")+--+-- >>> breakOn "/" "foobar"+-- ("foobar","")+--+-- Laws:+--+-- > append prefix match == haystack+-- >   where (prefix, match) = breakOn needle haystack+--+-- If you need to break a string by a substring repeatedly (e.g. you+-- want to break on every instance of a substring), use 'breakOnAll'+-- instead, as it has lower startup overhead.+--+-- In (unlikely) bad cases, this function's time complexity degrades+-- towards /O(n*m)/.+breakOn :: Text -> Text -> (Text, Text)+breakOn pat src@(Text arr off len)+    | null pat  = emptyError "breakOn"+    | otherwise = case indices pat src of+                    []    -> (src, empty)+                    (x:_) -> (text arr off x, text arr (off+x) (len-x))+{-# INLINE breakOn #-}++-- | /O(n+m)/ Similar to 'breakOn', but searches from the end of the+-- string.+--+-- The first element of the returned tuple is the prefix of @haystack@+-- up to and including the last match of @needle@.  The second is the+-- remainder of @haystack@, following the match.+--+-- >>> breakOnEnd "::" "a::b::c"+-- ("a::b::","c")+breakOnEnd :: Text -> Text -> (Text, Text)+breakOnEnd pat src = (reverse b, reverse a)+    where (a,b) = breakOn (reverse pat) (reverse src)+{-# INLINE breakOnEnd #-}++-- | /O(n+m)/ Find all non-overlapping instances of @needle@ in+-- @haystack@.  Each element of the returned list consists of a pair:+--+-- * The entire string prior to the /k/th match (i.e. the prefix)+--+-- * The /k/th match, followed by the remainder of the string+--+-- Examples:+--+-- >>> breakOnAll "::" ""+-- []+--+-- >>> breakOnAll "/" "a/b/c/"+-- [("a","/b/c/"),("a/b","/c/"),("a/b/c","/")]+--+-- In (unlikely) bad cases, this function's time complexity degrades+-- towards /O(n*m)/.+--+-- The @needle@ parameter may not be empty.+breakOnAll :: Text              -- ^ @needle@ to search for+           -> Text              -- ^ @haystack@ in which to search+           -> [(Text, Text)]+breakOnAll pat src@(Text arr off slen)+    | null pat  = emptyError "breakOnAll"+    | otherwise = L.map step (indices pat src)+  where+    step       x = (chunk 0 x, chunk x (slen-x))+    chunk !n !l  = text arr (n+off) l+{-# INLINE breakOnAll #-}++-------------------------------------------------------------------------------+-- ** Indexing 'Text's++-- $index+--+-- If you think of a 'Text' value as an array of 'Char' values (which+-- it is not), you run the risk of writing inefficient code.+--+-- An idiom that is common in some languages is to find the numeric+-- offset of a character or substring, then use that number to split+-- or trim the searched string.  With a 'Text' value, this approach+-- would require two /O(n)/ operations: one to perform the search, and+-- one to operate from wherever the search ended.+--+-- For example, suppose you have a string that you want to split on+-- the substring @\"::\"@, such as @\"foo::bar::quux\"@. Instead of+-- searching for the index of @\"::\"@ and taking the substrings+-- before and after that index, you would instead use @breakOnAll \"::\"@.++-- | /O(n)/ 'Text' index (subscript) operator, starting from 0. Subject to fusion.+index :: Text -> Int -> Char+index t n = S.index (stream t) n+{-# INLINE index #-}++-- | /O(n)/ The 'findIndex' function takes a predicate and a 'Text'+-- and returns the index of the first element in the 'Text' satisfying+-- the predicate. Subject to fusion.+findIndex :: (Char -> Bool) -> Text -> Maybe Int+findIndex p t = S.findIndex p (stream t)+{-# INLINE findIndex #-}++-- | /O(n+m)/ The 'count' function returns the number of times the+-- query string appears in the given 'Text'. An empty query string is+-- invalid, and will cause an error to be raised.+--+-- In (unlikely) bad cases, this function's time complexity degrades+-- towards /O(n*m)/.+count :: Text -> Text -> Int+count pat src+    | null pat        = emptyError "count"+    | isSingleton pat = countChar (unsafeHead pat) src+    | otherwise       = L.length (indices pat src)+{-# INLINE [1] count #-}++{-# RULES+"TEXT count/singleton -> countChar" [~1] forall c t.+    count (singleton c) t = countChar c t+  #-}++-- | /O(n)/ The 'countChar' function returns the number of times the+-- query element appears in the given 'Text'. Subject to fusion.+countChar :: Char -> Text -> Int+countChar c t = S.countChar c (stream t)+{-# INLINE countChar #-}++-------------------------------------------------------------------------------+-- * Zipping++-- | /O(n)/ 'zip' takes two 'Text's and returns a list of+-- corresponding pairs of bytes. If one input 'Text' is short,+-- excess elements of the longer 'Text' are discarded. This is+-- equivalent to a pair of 'unpack' operations.+zip :: Text -> Text -> [(Char,Char)]+zip a b = S.unstreamList $ S.zipWith (,) (stream a) (stream b)+{-# INLINE zip #-}++-- | /O(n)/ 'zipWith' generalises 'zip' by zipping with the function+-- given as the first argument, instead of a tupling function.+-- Performs replacement on invalid scalar values.+zipWith :: (Char -> Char -> Char) -> Text -> Text -> Text+zipWith f t1 t2 = unstream (S.zipWith g (stream t1) (stream t2))+    where g a b = safe (f a b)+{-# INLINE zipWith #-}++-- | /O(n)/ Breaks a 'Text' up into a list of words, delimited by 'Char's+-- representing white space.+words :: Text -> [Text]+words t@(Text arr off len) = loop 0 0+  where+    loop !start !n+        | n >= len = if start == n+                     then []+                     else [Text arr (start+off) (n-start)]+        | isSpace c =+            if start == n+            then loop (start+1) (start+1)+            else Text arr (start+off) (n-start) : loop (n+d) (n+d)+        | otherwise = loop start (n+d)+        where Iter c d = iter t n+{-# INLINE words #-}++-- | /O(n)/ Breaks a 'Text' up into a list of 'Text's at+-- newline 'Char's. The resulting strings do not contain newlines.+lines :: Text -> [Text]+lines ps | null ps   = []+         | otherwise = h : if null t+                           then []+                           else lines (unsafeTail t)+    where (# h,t #) = span_ (/= '\n') ps+{-# INLINE lines #-}++{-+-- | /O(n)/ Portably breaks a 'Text' up into a list of 'Text's at line+-- boundaries.+--+-- A line boundary is considered to be either a line feed, a carriage+-- return immediately followed by a line feed, or a carriage return.+-- This accounts for both Unix and Windows line ending conventions,+-- and for the old convention used on Mac OS 9 and earlier.+lines' :: Text -> [Text]+lines' ps | null ps   = []+          | otherwise = h : case uncons t of+                              Nothing -> []+                              Just (c,t')+                                  | c == '\n' -> lines t'+                                  | c == '\r' -> case uncons t' of+                                                   Just ('\n',t'') -> lines t''+                                                   _               -> lines t'+    where (h,t)    = span notEOL ps+          notEOL c = c /= '\n' && c /= '\r'+{-# INLINE lines' #-}+-}++-- | /O(n)/ Joins lines, after appending a terminating newline to+-- each.+unlines :: [Text] -> Text+unlines = concat . L.map (`snoc` '\n')+{-# INLINE unlines #-}++-- | /O(n)/ Joins words using single space characters.+unwords :: [Text] -> Text+unwords = intercalate (singleton ' ')+{-# INLINE unwords #-}++-- | /O(n)/ The 'isPrefixOf' function takes two 'Text's and returns+-- 'True' iff the first is a prefix of the second.  Subject to fusion.+isPrefixOf :: Text -> Text -> Bool+isPrefixOf a@(Text _ _ alen) b@(Text _ _ blen) =+    alen <= blen && S.isPrefixOf (stream a) (stream b)+{-# INLINE [1] isPrefixOf #-}++{-# RULES+"TEXT isPrefixOf -> fused" [~1] forall s t.+    isPrefixOf s t = S.isPrefixOf (stream s) (stream t)+  #-}++-- | /O(n)/ The 'isSuffixOf' function takes two 'Text's and returns+-- 'True' iff the first is a suffix of the second.+isSuffixOf :: Text -> Text -> Bool+isSuffixOf a@(Text _aarr _aoff alen) b@(Text barr boff blen) =+    d >= 0 && a == b'+  where d              = blen - alen+        b' | d == 0    = b+           | otherwise = Text barr (boff+d) alen+{-# INLINE isSuffixOf #-}++-- | /O(n+m)/ The 'isInfixOf' function takes two 'Text's and returns+-- 'True' iff the first is contained, wholly and intact, anywhere+-- within the second.+--+-- In (unlikely) bad cases, this function's time complexity degrades+-- towards /O(n*m)/.+isInfixOf :: Text -> Text -> Bool+isInfixOf needle haystack+    | null needle        = True+    | isSingleton needle = S.elem (unsafeHead needle) . S.stream $ haystack+    | otherwise          = not . L.null . indices needle $ haystack+{-# INLINE [1] isInfixOf #-}++{-# RULES+"TEXT isInfixOf/singleton -> S.elem/S.stream" [~1] forall n h.+    isInfixOf (singleton n) h = S.elem n (S.stream h)+  #-}++-------------------------------------------------------------------------------+-- * View patterns++-- | /O(n)/ Return the suffix of the second string if its prefix+-- matches the entire first string.+--+-- Examples:+--+-- >>> stripPrefix "foo" "foobar"+-- Just "bar"+--+-- >>> stripPrefix ""    "baz"+-- Just "baz"+--+-- >>> stripPrefix "foo" "quux"+-- Nothing+--+-- This is particularly useful with the @ViewPatterns@ extension to+-- GHC, as follows:+--+-- > {-# LANGUAGE ViewPatterns #-}+-- > import Data.Text as T+-- >+-- > fnordLength :: Text -> Int+-- > fnordLength (stripPrefix "fnord" -> Just suf) = T.length suf+-- > fnordLength _                                 = -1+stripPrefix :: Text -> Text -> Maybe Text+stripPrefix p@(Text _arr _off plen) t@(Text arr off len)+    | p `isPrefixOf` t = Just $! text arr (off+plen) (len-plen)+    | otherwise        = Nothing++-- | /O(n)/ Find the longest non-empty common prefix of two strings+-- and return it, along with the suffixes of each string at which they+-- no longer match.+--+-- If the strings do not have a common prefix or either one is empty,+-- this function returns 'Nothing'.+--+-- Examples:+--+-- >>> commonPrefixes "foobar" "fooquux"+-- Just ("foo","bar","quux")+--+-- >>> commonPrefixes "veeble" "fetzer"+-- Nothing+--+-- >>> commonPrefixes "" "baz"+-- Nothing+commonPrefixes :: Text -> Text -> Maybe (Text,Text,Text)+commonPrefixes t0@(Text arr0 off0 len0) t1@(Text arr1 off1 len1) = go 0 0+  where+    go !i !j | i < len0 && j < len1 && a == b = go (i+d0) (j+d1)+             | i > 0     = Just (Text arr0 off0 i,+                                 text arr0 (off0+i) (len0-i),+                                 text arr1 (off1+j) (len1-j))+             | otherwise = Nothing+      where Iter a d0 = iter t0 i+            Iter b d1 = iter t1 j++-- | /O(n)/ Return the prefix of the second string if its suffix+-- matches the entire first string.+--+-- Examples:+--+-- >>> stripSuffix "bar" "foobar"+-- Just "foo"+--+-- >>> stripSuffix ""    "baz"+-- Just "baz"+--+-- >>> stripSuffix "foo" "quux"+-- Nothing+--+-- This is particularly useful with the @ViewPatterns@ extension to+-- GHC, as follows:+--+-- > {-# LANGUAGE ViewPatterns #-}+-- > import Data.Text as T+-- >+-- > quuxLength :: Text -> Int+-- > quuxLength (stripSuffix "quux" -> Just pre) = T.length pre+-- > quuxLength _                                = -1+stripSuffix :: Text -> Text -> Maybe Text+stripSuffix p@(Text _arr _off plen) t@(Text arr off len)+    | p `isSuffixOf` t = Just $! text arr off (len-plen)+    | otherwise        = Nothing++-- | Add a list of non-negative numbers.  Errors out on overflow.+sumP :: String -> [Int] -> Int+sumP fun = go 0+  where go !a (x:xs)+            | ax >= 0   = go ax xs+            | otherwise = overflowError fun+          where ax = a + x+        go a  _         = a++emptyError :: String -> a+emptyError fun = P.error $ "Data.Text." ++ fun ++ ": empty input"++overflowError :: String -> a+overflowError fun = P.error $ "Data.Text." ++ fun ++ ": size overflow"++-- | /O(n)/ Make a distinct copy of the given string, sharing no+-- storage with the original string.+--+-- As an example, suppose you read a large string, of which you need+-- only a small portion.  If you do not use 'copy', the entire original+-- array will be kept alive in memory by the smaller string. Making a+-- copy \"breaks the link\" to the original array, allowing it to be+-- garbage collected if there are no other live references to it.+copy :: Text -> Text+copy (Text arr off len) = Text (A.run go) 0 len+  where+    go :: ST s (A.MArray s)+    go = do+      marr <- A.new len+      A.copyI marr 0 arr off len+      return marr+++-------------------------------------------------+-- NOTE: the named chunk below used by doctest;+--       verify the doctests via `doctest -fobject-code Data/Text.hs`++-- $setup+-- >>> :set -XOverloadedStrings+-- >>> import qualified Data.Text as T
+ src/Data/Text/Array.hs view
@@ -0,0 +1,249 @@+{-# LANGUAGE BangPatterns, CPP, MagicHash, Rank2Types,+    RecordWildCards, UnboxedTuples, UnliftedFFITypes #-}+{-# OPTIONS_GHC -fno-warn-unused-matches #-}+-- |+-- Module      : Data.Text.Array+-- Copyright   : (c) 2009, 2010, 2011 Bryan O'Sullivan+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Portability : portable+--+-- Packed, unboxed, heap-resident arrays.  Suitable for performance+-- critical use, both in terms of large data quantities and high+-- speed.+--+-- This module is intended to be imported @qualified@, to avoid name+-- clashes with "Prelude" functions, e.g.+--+-- > import qualified Data.Text.Array as A+--+-- The names in this module resemble those in the 'Data.Array' family+-- of modules, but are shorter due to the assumption of qualified+-- naming.+module Data.Text.Array+    (+    -- * Types+      Array(Array, aBA)+    , MArray(MArray, maBA)++    -- * Functions+    , copyM+    , copyI+    , empty+    , equal+#if defined(ASSERTS)+    , length+#endif+    , run+    , run2+    , toList+    , unsafeFreeze+    , unsafeIndex+    , new+    , unsafeWrite+    ) where++#if defined(ASSERTS)+-- This fugly hack is brought by GHC's apparent reluctance to deal+-- with MagicHash and UnboxedTuples when inferring types. Eek!+# define CHECK_BOUNDS(_func_,_len_,_k_) \+if (_k_) < 0 || (_k_) >= (_len_) then error ("Data.Text.Array." ++ (_func_) ++ ": bounds error, offset " ++ show (_k_) ++ ", length " ++ show (_len_)) else+#else+# define CHECK_BOUNDS(_func_,_len_,_k_)+#endif++#include "MachDeps.h"++#if defined(ASSERTS)+import Control.Exception (assert)+#endif+#if MIN_VERSION_base(4,4,0)+import Control.Monad.ST.Unsafe (unsafeIOToST)+#else+import Control.Monad.ST (unsafeIOToST)+#endif+import Data.Bits ((.&.), xor)+import Data.Text.Internal.Unsafe (inlinePerformIO)+import Data.Text.Internal.Unsafe.Shift (shiftL, shiftR)+#if MIN_VERSION_base(4,5,0)+import Foreign.C.Types (CInt(CInt), CSize(CSize))+#else+import Foreign.C.Types (CInt, CSize)+#endif+import GHC.Base (ByteArray#, MutableByteArray#, Int(..),+                 indexWord16Array#, newByteArray#,+                 unsafeFreezeByteArray#, writeWord16Array#)+import GHC.ST (ST(..), runST)+import GHC.Word (Word16(..))+import Prelude hiding (length, read)++-- | Immutable array type.+--+-- The 'Array' constructor is exposed since @text-1.1.1.3@+data Array = Array {+      aBA :: ByteArray#+#if defined(ASSERTS)+    , aLen :: {-# UNPACK #-} !Int -- length (in units of Word16, not bytes)+#endif+    }++-- | Mutable array type, for use in the ST monad.+--+-- The 'MArray' constructor is exposed since @text-1.1.1.3@+data MArray s = MArray {+      maBA :: MutableByteArray# s+#if defined(ASSERTS)+    , maLen :: {-# UNPACK #-} !Int -- length (in units of Word16, not bytes)+#endif+    }++#if defined(ASSERTS)+-- | Operations supported by all arrays.+class IArray a where+    -- | Return the length of an array.+    length :: a -> Int++instance IArray Array where+    length = aLen+    {-# INLINE length #-}++instance IArray (MArray s) where+    length = maLen+    {-# INLINE length #-}+#endif++-- | Create an uninitialized mutable array.+new :: forall s. Int -> ST s (MArray s)+new n+  | n < 0 || n .&. highBit /= 0 = array_size_error+  | otherwise = ST $ \s1# ->+       case newByteArray# len# s1# of+         (# s2#, marr# #) -> (# s2#, MArray marr#+#if defined(ASSERTS)+                                n+#endif+                                #)+  where !(I# len#) = bytesInArray n+        highBit    = maxBound `xor` (maxBound `shiftR` 1)+{-# INLINE new #-}++array_size_error :: a+array_size_error = error "Data.Text.Array.new: size overflow"++-- | Freeze a mutable array. Do not mutate the 'MArray' afterwards!+unsafeFreeze :: MArray s -> ST s Array+unsafeFreeze MArray{..} = ST $ \s1# ->+    case unsafeFreezeByteArray# maBA s1# of+        (# s2#, ba# #) -> (# s2#, Array ba#+#if defined(ASSERTS)+                             maLen+#endif+                             #)+{-# INLINE unsafeFreeze #-}++-- | Indicate how many bytes would be used for an array of the given+-- size.+bytesInArray :: Int -> Int+bytesInArray n = n `shiftL` 1+{-# INLINE bytesInArray #-}++-- | Unchecked read of an immutable array.  May return garbage or+-- crash on an out-of-bounds access.+unsafeIndex :: Array -> Int -> Word16+unsafeIndex Array{..} i@(I# i#) =+  CHECK_BOUNDS("unsafeIndex",aLen,i)+    case indexWord16Array# aBA i# of r# -> (W16# r#)+{-# INLINE unsafeIndex #-}++-- | Unchecked write of a mutable array.  May return garbage or crash+-- on an out-of-bounds access.+unsafeWrite :: MArray s -> Int -> Word16 -> ST s ()+unsafeWrite MArray{..} i@(I# i#) (W16# e#) = ST $ \s1# ->+  CHECK_BOUNDS("unsafeWrite",maLen,i)+  case writeWord16Array# maBA i# e# s1# of+    s2# -> (# s2#, () #)+{-# INLINE unsafeWrite #-}++-- | Convert an immutable array to a list.+toList :: Array -> Int -> Int -> [Word16]+toList ary off len = loop 0+    where loop i | i < len   = unsafeIndex ary (off+i) : loop (i+1)+                 | otherwise = []++-- | An empty immutable array.+empty :: Array+empty = runST (new 0 >>= unsafeFreeze)++-- | Run an action in the ST monad and return an immutable array of+-- its result.+run :: (forall s. ST s (MArray s)) -> Array+run k = runST (k >>= unsafeFreeze)++-- | Run an action in the ST monad and return an immutable array of+-- its result paired with whatever else the action returns.+run2 :: (forall s. ST s (MArray s, a)) -> (Array, a)+run2 k = runST (do+                 (marr,b) <- k+                 arr <- unsafeFreeze marr+                 return (arr,b))+{-# INLINE run2 #-}++-- | Copy some elements of a mutable array.+copyM :: MArray s               -- ^ Destination+      -> Int                    -- ^ Destination offset+      -> MArray s               -- ^ Source+      -> Int                    -- ^ Source offset+      -> Int                    -- ^ Count+      -> ST s ()+copyM dest didx src sidx count+    | count <= 0 = return ()+    | otherwise =+#if defined(ASSERTS)+    assert (sidx + count <= length src) .+    assert (didx + count <= length dest) .+#endif+    unsafeIOToST $ memcpyM (maBA dest) (fromIntegral didx)+                           (maBA src) (fromIntegral sidx)+                           (fromIntegral count)+{-# INLINE copyM #-}++-- | Copy some elements of an immutable array.+copyI :: MArray s               -- ^ Destination+      -> Int                    -- ^ Destination offset+      -> Array                  -- ^ Source+      -> Int                    -- ^ Source offset+      -> Int                    -- ^ First offset in destination /not/ to+                                -- copy (i.e. /not/ length)+      -> ST s ()+copyI dest i0 src j0 top+    | i0 >= top = return ()+    | otherwise = unsafeIOToST $+                  memcpyI (maBA dest) (fromIntegral i0)+                          (aBA src) (fromIntegral j0)+                          (fromIntegral (top-i0))+{-# INLINE copyI #-}++-- | Compare portions of two arrays for equality.  No bounds checking+-- is performed.+equal :: Array                  -- ^ First+      -> Int                    -- ^ Offset into first+      -> Array                  -- ^ Second+      -> Int                    -- ^ Offset into second+      -> Int                    -- ^ Count+      -> Bool+equal arrA offA arrB offB count = inlinePerformIO $ do+  i <- memcmp (aBA arrA) (fromIntegral offA)+                     (aBA arrB) (fromIntegral offB) (fromIntegral count)+  return $! i == 0+{-# INLINE equal #-}++foreign import ccall unsafe "_hs_text_memcpy" memcpyI+    :: MutableByteArray# s -> CSize -> ByteArray# -> CSize -> CSize -> IO ()++foreign import ccall unsafe "_hs_text_memcmp" memcmp+    :: ByteArray# -> CSize -> ByteArray# -> CSize -> CSize -> IO CInt++foreign import ccall unsafe "_hs_text_memcpy" memcpyM+    :: MutableByteArray# s -> CSize -> MutableByteArray# s -> CSize -> CSize+    -> IO ()
+ src/Data/Text/Encoding.hs view
@@ -0,0 +1,539 @@+{-# LANGUAGE BangPatterns, CPP, GeneralizedNewtypeDeriving, MagicHash,+    UnliftedFFITypes #-}+#if __GLASGOW_HASKELL__ >= 702+{-# LANGUAGE Trustworthy #-}+#endif+-- |+-- Module      : Data.Text.Encoding+-- Copyright   : (c) 2009, 2010, 2011 Bryan O'Sullivan,+--               (c) 2009 Duncan Coutts,+--               (c) 2008, 2009 Tom Harper+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Portability : portable+--+-- Functions for converting 'Text' values to and from 'ByteString',+-- using several standard encodings.+--+-- To gain access to a much larger family of encodings, use the+-- <http://hackage.haskell.org/package/text-icu text-icu package>.++module Data.Text.Encoding+    (+    -- * Decoding ByteStrings to Text+    -- $strict+      decodeASCII+    , decodeLatin1+    , decodeUtf8+    , decodeUtf16LE+    , decodeUtf16BE+    , decodeUtf32LE+    , decodeUtf32BE++    -- ** Catchable failure+    , decodeUtf8'++    -- ** Controllable error handling+    , decodeUtf8With+    , decodeUtf16LEWith+    , decodeUtf16BEWith+    , decodeUtf32LEWith+    , decodeUtf32BEWith++    -- ** Stream oriented decoding+    -- $stream+    , streamDecodeUtf8+    , streamDecodeUtf8With+    , Decoding(..)++    -- * Encoding Text to ByteStrings+    , encodeUtf8+    , encodeUtf16LE+    , encodeUtf16BE+    , encodeUtf32LE+    , encodeUtf32BE++    -- * Encoding Text using ByteString Builders+    , encodeUtf8Builder+    , encodeUtf8BuilderEscaped+    ) where++#if MIN_VERSION_base(4,4,0)+import Control.Monad.ST.Unsafe (unsafeIOToST, unsafeSTToIO)+#else+import Control.Monad.ST (unsafeIOToST, unsafeSTToIO)+#endif++import Control.Exception (evaluate, try, throwIO, ErrorCall(ErrorCall))+import Control.Monad.ST (runST)+import Data.Bits ((.&.))+import Data.ByteString as B+import Data.ByteString.Internal as B hiding (c2w)+import Data.Text.Encoding.Error (OnDecodeError, UnicodeException, strictDecode)+import Data.Text.Internal (Text(..), safe, text)+import Data.Text.Internal.Private (runText)+import Data.Text.Internal.Unsafe.Char (ord, unsafeWrite)+import Data.Text.Internal.Unsafe.Shift (shiftR)+import Data.Text.Show ()+import Data.Text.Unsafe (unsafeDupablePerformIO)+import Data.Word (Word8, Word32)+#if MIN_VERSION_base(4,5,0)+import Foreign.C.Types (CSize(CSize))+#else+import Foreign.C.Types (CSize)+#endif+import Foreign.ForeignPtr (withForeignPtr)+import Foreign.Marshal.Utils (with)+import Foreign.Ptr (Ptr, minusPtr, nullPtr, plusPtr)+import Foreign.Storable (Storable, peek, poke)+import GHC.Base (ByteArray#, MutableByteArray#)+import qualified Data.ByteString.Builder as B+import qualified Data.ByteString.Builder.Internal as B hiding (empty, append)+import qualified Data.ByteString.Builder.Prim as BP+import qualified Data.ByteString.Builder.Prim.Internal as BP+import qualified Data.Text.Array as A+import qualified Data.Text.Internal.Encoding.Fusion as E+import qualified Data.Text.Internal.Encoding.Utf16 as U16+import qualified Data.Text.Internal.Fusion as F+import Data.Text.Internal.ByteStringCompat++#include "text_cbits.h"++-- $strict+--+-- All of the single-parameter functions for decoding bytestrings+-- encoded in one of the Unicode Transformation Formats (UTF) operate+-- in a /strict/ mode: each will throw an exception if given invalid+-- input.+--+-- Each function has a variant, whose name is suffixed with -'With',+-- that gives greater control over the handling of decoding errors.+-- For instance, 'decodeUtf8' will throw an exception, but+-- 'decodeUtf8With' allows the programmer to determine what to do on a+-- decoding error.++-- | /Deprecated/.  Decode a 'ByteString' containing 7-bit ASCII+-- encoded text.+decodeASCII :: ByteString -> Text+decodeASCII = decodeUtf8+{-# DEPRECATED decodeASCII "Use decodeUtf8 instead" #-}++-- | Decode a 'ByteString' containing Latin-1 (aka ISO-8859-1) encoded text.+--+-- 'decodeLatin1' is semantically equivalent to+--  @Data.Text.pack . Data.ByteString.Char8.unpack@+decodeLatin1 :: ByteString -> Text+decodeLatin1 bs = withBS bs aux where+  aux fp len = text a 0 len+   where+    a = A.run (A.new len >>= unsafeIOToST . go)+    go dest = withForeignPtr fp $ \ptr -> do+      c_decode_latin1 (A.maBA dest) ptr (ptr `plusPtr` len)+      return dest++-- | Decode a 'ByteString' containing UTF-8 encoded text.+--+-- __NOTE__: The replacement character returned by 'OnDecodeError'+-- MUST be within the BMP plane; surrogate code points will+-- automatically be remapped to the replacement char @U+FFFD@+-- (/since 0.11.3.0/), whereas code points beyond the BMP will throw an+-- 'error' (/since 1.2.3.1/); For earlier versions of @text@ using+-- those unsupported code points would result in undefined behavior.+decodeUtf8With :: OnDecodeError -> ByteString -> Text+decodeUtf8With onErr bs = withBS bs aux+ where+  aux fp len = runText $ \done -> do+    let go dest = withForeignPtr fp $ \ptr ->+          with (0::CSize) $ \destOffPtr -> do+            let end = ptr `plusPtr` len+                loop curPtr = do+                  curPtr' <- c_decode_utf8 (A.maBA dest) destOffPtr curPtr end+                  if curPtr' == end+                    then do+                      n <- peek destOffPtr+                      unsafeSTToIO (done dest (fromIntegral n))+                    else do+                      x <- peek curPtr'+                      case onErr desc (Just x) of+                        Nothing -> loop $ curPtr' `plusPtr` 1+                        Just c+                          | c > '\xFFFF' -> throwUnsupportedReplChar+                          | otherwise -> do+                              destOff <- peek destOffPtr+                              w <- unsafeSTToIO $+                                   unsafeWrite dest (fromIntegral destOff)+                                               (safe c)+                              poke destOffPtr (destOff + fromIntegral w)+                              loop $ curPtr' `plusPtr` 1+            loop ptr+    (unsafeIOToST . go) =<< A.new len+   where+    desc = "Data.Text.Internal.Encoding.decodeUtf8: Invalid UTF-8 stream"++    throwUnsupportedReplChar = throwIO $+      ErrorCall "decodeUtf8With: non-BMP replacement characters not supported"+  -- TODO: The code currently assumes that the transcoded UTF-16+  -- stream is at most twice as long (in bytes) as the input UTF-8+  -- stream. To justify this assumption one has to assume that the+  -- error handler replacement character also satisfies this+  -- invariant, by emitting at most one UTF16 code unit.+  --+  -- One easy way to support the full range of code-points for+  -- replacement characters in the error handler is to simply change+  -- the (over-)allocation to `A.new (2*len)` and then shrink back the+  -- `ByteArray#` to the real size (recent GHCs have a cheap+  -- `ByteArray#` resize-primop for that which allow the GC to reclaim+  -- the overallocation). However, this would require 4 times as much+  -- (temporary) storage as the original UTF-8 required.+  --+  -- Another strategy would be to optimistically assume that+  -- replacement characters are within the BMP, and if the case of a+  -- non-BMP replacement occurs reallocate the target buffer (or throw+  -- an exception, and fallback to a pessimistic codepath, like e.g.+  -- `decodeUtf8With onErr bs = F.unstream (E.streamUtf8 onErr bs)`)+  --+  -- Alternatively, `OnDecodeError` could become a datastructure which+  -- statically encodes the replacement-character range,+  -- e.g. something isomorphic to+  --+  --   Either (... -> Maybe Word16) (... -> Maybe Char)+  --+  -- And allow to statically switch between the BMP/non-BMP+  -- replacement-character codepaths. There's multiple ways to address+  -- this with different tradeoffs; but ideally we should optimise for+  -- the optimistic/error-free case.+{- INLINE[0] decodeUtf8With #-}++-- $stream+--+-- The 'streamDecodeUtf8' and 'streamDecodeUtf8With' functions accept+-- a 'ByteString' that represents a possibly incomplete input (e.g. a+-- packet from a network stream) that may not end on a UTF-8 boundary.+--+-- 1. The maximal prefix of 'Text' that could be decoded from the+--    given input.+--+-- 2. The suffix of the 'ByteString' that could not be decoded due to+--    insufficient input.+--+-- 3. A function that accepts another 'ByteString'.  That string will+--    be assumed to directly follow the string that was passed as+--    input to the original function, and it will in turn be decoded.+--+-- To help understand the use of these functions, consider the Unicode+-- string @\"hi &#9731;\"@. If encoded as UTF-8, this becomes @\"hi+-- \\xe2\\x98\\x83\"@; the final @\'&#9731;\'@ is encoded as 3 bytes.+--+-- Now suppose that we receive this encoded string as 3 packets that+-- are split up on untidy boundaries: @[\"hi \\xe2\", \"\\x98\",+-- \"\\x83\"]@. We cannot decode the entire Unicode string until we+-- have received all three packets, but we would like to make progress+-- as we receive each one.+--+-- @+-- ghci> let s0\@('Some' _ _ f0) = 'streamDecodeUtf8' \"hi \\xe2\"+-- ghci> s0+-- 'Some' \"hi \" \"\\xe2\" _+-- @+--+-- We use the continuation @f0@ to decode our second packet.+--+-- @+-- ghci> let s1\@('Some' _ _ f1) = f0 \"\\x98\"+-- ghci> s1+-- 'Some' \"\" \"\\xe2\\x98\"+-- @+--+-- We could not give @f0@ enough input to decode anything, so it+-- returned an empty string. Once we feed our second continuation @f1@+-- the last byte of input, it will make progress.+--+-- @+-- ghci> let s2\@('Some' _ _ f2) = f1 \"\\x83\"+-- ghci> s2+-- 'Some' \"\\x2603\" \"\" _+-- @+--+-- If given invalid input, an exception will be thrown by the function+-- or continuation where it is encountered.++-- | A stream oriented decoding result.+--+-- @since 1.0.0.0+data Decoding = Some Text ByteString (ByteString -> Decoding)++instance Show Decoding where+    showsPrec d (Some t bs _) = showParen (d > prec) $+                                showString "Some " . showsPrec prec' t .+                                showChar ' ' . showsPrec prec' bs .+                                showString " _"+      where prec = 10; prec' = prec + 1++newtype CodePoint = CodePoint Word32 deriving (Eq, Show, Num, Storable)+newtype DecoderState = DecoderState Word32 deriving (Eq, Show, Num, Storable)++-- | Decode, in a stream oriented way, a 'ByteString' containing UTF-8+-- encoded text that is known to be valid.+--+-- If the input contains any invalid UTF-8 data, an exception will be+-- thrown (either by this function or a continuation) that cannot be+-- caught in pure code.  For more control over the handling of invalid+-- data, use 'streamDecodeUtf8With'.+--+-- @since 1.0.0.0+streamDecodeUtf8 :: ByteString -> Decoding+streamDecodeUtf8 = streamDecodeUtf8With strictDecode++-- | Decode, in a stream oriented way, a 'ByteString' containing UTF-8+-- encoded text.+--+-- @since 1.0.0.0+streamDecodeUtf8With :: OnDecodeError -> ByteString -> Decoding+streamDecodeUtf8With onErr = decodeChunk B.empty 0 0+ where+  -- We create a slightly larger than necessary buffer to accommodate a+  -- potential surrogate pair started in the last buffer+  decodeChunk :: ByteString -> CodePoint -> DecoderState -> ByteString+              -> Decoding+  decodeChunk undecoded0 codepoint0 state0 bs = withBS bs aux where+    aux fp len = runST $ (unsafeIOToST . decodeChunkToBuffer) =<< A.new (len+1)+       where+        decodeChunkToBuffer :: A.MArray s -> IO Decoding+        decodeChunkToBuffer dest = withForeignPtr fp $ \ptr ->+          with (0::CSize) $ \destOffPtr ->+          with codepoint0 $ \codepointPtr ->+          with state0 $ \statePtr ->+          with nullPtr $ \curPtrPtr ->+            let end = ptr `plusPtr` len+                loop curPtr = do+                  poke curPtrPtr curPtr+                  curPtr' <- c_decode_utf8_with_state (A.maBA dest) destOffPtr+                             curPtrPtr end codepointPtr statePtr+                  state <- peek statePtr+                  case state of+                    UTF8_REJECT -> do+                      -- We encountered an encoding error+                      x <- peek curPtr'+                      poke statePtr 0+                      case onErr desc (Just x) of+                        Nothing -> loop $ curPtr' `plusPtr` 1+                        Just c -> do+                          destOff <- peek destOffPtr+                          w <- unsafeSTToIO $+                               unsafeWrite dest (fromIntegral destOff) (safe c)+                          poke destOffPtr (destOff + fromIntegral w)+                          loop $ curPtr' `plusPtr` 1++                    _ -> do+                      -- We encountered the end of the buffer while decoding+                      n <- peek destOffPtr+                      codepoint <- peek codepointPtr+                      chunkText <- unsafeSTToIO $ do+                          arr <- A.unsafeFreeze dest+                          return $! text arr 0 (fromIntegral n)+                      lastPtr <- peek curPtrPtr+                      let left = lastPtr `minusPtr` curPtr+                          !undecoded = case state of+                            UTF8_ACCEPT -> B.empty+                            _           -> B.append undecoded0 (B.drop left bs)+                      return $ Some chunkText undecoded+                               (decodeChunk undecoded codepoint state)+            in loop ptr+  desc = "Data.Text.Internal.Encoding.streamDecodeUtf8With: Invalid UTF-8 stream"++-- | Decode a 'ByteString' containing UTF-8 encoded text that is known+-- to be valid.+--+-- If the input contains any invalid UTF-8 data, an exception will be+-- thrown that cannot be caught in pure code.  For more control over+-- the handling of invalid data, use 'decodeUtf8'' or+-- 'decodeUtf8With'.+decodeUtf8 :: ByteString -> Text+decodeUtf8 = decodeUtf8With strictDecode+{-# INLINE[0] decodeUtf8 #-}+{-# RULES "STREAM stream/decodeUtf8 fusion" [1]+    forall bs. F.stream (decodeUtf8 bs) = E.streamUtf8 strictDecode bs #-}++-- | Decode a 'ByteString' containing UTF-8 encoded text.+--+-- If the input contains any invalid UTF-8 data, the relevant+-- exception will be returned, otherwise the decoded text.+decodeUtf8' :: ByteString -> Either UnicodeException Text+decodeUtf8' = unsafeDupablePerformIO . try . evaluate . decodeUtf8With strictDecode+{-# INLINE decodeUtf8' #-}++-- | Encode text to a ByteString 'B.Builder' using UTF-8 encoding.+--+-- @since 1.1.0.0+encodeUtf8Builder :: Text -> B.Builder+encodeUtf8Builder = encodeUtf8BuilderEscaped (BP.liftFixedToBounded BP.word8)++-- | Encode text using UTF-8 encoding and escape the ASCII characters using+-- a 'BP.BoundedPrim'.+--+-- Use this function is to implement efficient encoders for text-based formats+-- like JSON or HTML.+--+-- @since 1.1.0.0+{-# INLINE encodeUtf8BuilderEscaped #-}+-- TODO: Extend documentation with references to source code in @blaze-html@+-- or @aeson@ that uses this function.+encodeUtf8BuilderEscaped :: BP.BoundedPrim Word8 -> Text -> B.Builder+encodeUtf8BuilderEscaped be =+    -- manual eta-expansion to ensure inlining works as expected+    \txt -> B.builder (mkBuildstep txt)+  where+    bound = max 4 $ BP.sizeBound be++    mkBuildstep (Text arr off len) !k =+        outerLoop off+      where+        iend = off + len++        outerLoop !i0 !br@(B.BufferRange op0 ope)+          | i0 >= iend       = k br+          | outRemaining > 0 = goPartial (i0 + min outRemaining inpRemaining)+          -- TODO: Use a loop with an integrated bound's check if outRemaining+          -- is smaller than 8, as this will save on divisions.+          | otherwise        = return $ B.bufferFull bound op0 (outerLoop i0)+          where+            outRemaining = (ope `minusPtr` op0) `div` bound+            inpRemaining = iend - i0++            goPartial !iendTmp = go i0 op0+              where+                go !i !op+                  | i < iendTmp = case A.unsafeIndex arr i of+                      w | w <= 0x7F -> do+                            BP.runB be (fromIntegral w) op >>= go (i + 1)+                        | w <= 0x7FF -> do+                            poke8 0 $ (w `shiftR` 6) + 0xC0+                            poke8 1 $ (w .&. 0x3f) + 0x80+                            go (i + 1) (op `plusPtr` 2)+                        | 0xD800 <= w && w <= 0xDBFF -> do+                            let c = ord $ U16.chr2 w (A.unsafeIndex arr (i+1))+                            poke8 0 $ (c `shiftR` 18) + 0xF0+                            poke8 1 $ ((c `shiftR` 12) .&. 0x3F) + 0x80+                            poke8 2 $ ((c `shiftR` 6) .&. 0x3F) + 0x80+                            poke8 3 $ (c .&. 0x3F) + 0x80+                            go (i + 2) (op `plusPtr` 4)+                        | otherwise -> do+                            poke8 0 $ (w `shiftR` 12) + 0xE0+                            poke8 1 $ ((w `shiftR` 6) .&. 0x3F) + 0x80+                            poke8 2 $ (w .&. 0x3F) + 0x80+                            go (i + 1) (op `plusPtr` 3)+                  | otherwise =+                      outerLoop i (B.BufferRange op ope)+                  where+                    poke8 j v = poke (op `plusPtr` j) (fromIntegral v :: Word8)++-- | Encode text using UTF-8 encoding.+encodeUtf8 :: Text -> ByteString+encodeUtf8 (Text arr off len)+  | len == 0  = B.empty+  | otherwise = unsafeDupablePerformIO $ do+  fp <- mallocByteString (len*3) -- see https://github.com/haskell/text/issues/194 for why len*3 is enough+  withForeignPtr fp $ \ptr ->+    with ptr $ \destPtr -> do+      c_encode_utf8 destPtr (A.aBA arr) (fromIntegral off) (fromIntegral len)+      newDest <- peek destPtr+      let utf8len = newDest `minusPtr` ptr+      if utf8len >= len `shiftR` 1+        then return (mkBS fp utf8len)+        else do+          fp' <- mallocByteString utf8len+          withForeignPtr fp' $ \ptr' -> do+            memcpy ptr' ptr (fromIntegral utf8len)+            return (mkBS fp' utf8len)++-- | Decode text from little endian UTF-16 encoding.+decodeUtf16LEWith :: OnDecodeError -> ByteString -> Text+decodeUtf16LEWith onErr bs = F.unstream (E.streamUtf16LE onErr bs)+{-# INLINE decodeUtf16LEWith #-}++-- | Decode text from little endian UTF-16 encoding.+--+-- If the input contains any invalid little endian UTF-16 data, an+-- exception will be thrown.  For more control over the handling of+-- invalid data, use 'decodeUtf16LEWith'.+decodeUtf16LE :: ByteString -> Text+decodeUtf16LE = decodeUtf16LEWith strictDecode+{-# INLINE decodeUtf16LE #-}++-- | Decode text from big endian UTF-16 encoding.+decodeUtf16BEWith :: OnDecodeError -> ByteString -> Text+decodeUtf16BEWith onErr bs = F.unstream (E.streamUtf16BE onErr bs)+{-# INLINE decodeUtf16BEWith #-}++-- | Decode text from big endian UTF-16 encoding.+--+-- If the input contains any invalid big endian UTF-16 data, an+-- exception will be thrown.  For more control over the handling of+-- invalid data, use 'decodeUtf16BEWith'.+decodeUtf16BE :: ByteString -> Text+decodeUtf16BE = decodeUtf16BEWith strictDecode+{-# INLINE decodeUtf16BE #-}++-- | Encode text using little endian UTF-16 encoding.+encodeUtf16LE :: Text -> ByteString+encodeUtf16LE txt = E.unstream (E.restreamUtf16LE (F.stream txt))+{-# INLINE encodeUtf16LE #-}++-- | Encode text using big endian UTF-16 encoding.+encodeUtf16BE :: Text -> ByteString+encodeUtf16BE txt = E.unstream (E.restreamUtf16BE (F.stream txt))+{-# INLINE encodeUtf16BE #-}++-- | Decode text from little endian UTF-32 encoding.+decodeUtf32LEWith :: OnDecodeError -> ByteString -> Text+decodeUtf32LEWith onErr bs = F.unstream (E.streamUtf32LE onErr bs)+{-# INLINE decodeUtf32LEWith #-}++-- | Decode text from little endian UTF-32 encoding.+--+-- If the input contains any invalid little endian UTF-32 data, an+-- exception will be thrown.  For more control over the handling of+-- invalid data, use 'decodeUtf32LEWith'.+decodeUtf32LE :: ByteString -> Text+decodeUtf32LE = decodeUtf32LEWith strictDecode+{-# INLINE decodeUtf32LE #-}++-- | Decode text from big endian UTF-32 encoding.+decodeUtf32BEWith :: OnDecodeError -> ByteString -> Text+decodeUtf32BEWith onErr bs = F.unstream (E.streamUtf32BE onErr bs)+{-# INLINE decodeUtf32BEWith #-}++-- | Decode text from big endian UTF-32 encoding.+--+-- If the input contains any invalid big endian UTF-32 data, an+-- exception will be thrown.  For more control over the handling of+-- invalid data, use 'decodeUtf32BEWith'.+decodeUtf32BE :: ByteString -> Text+decodeUtf32BE = decodeUtf32BEWith strictDecode+{-# INLINE decodeUtf32BE #-}++-- | Encode text using little endian UTF-32 encoding.+encodeUtf32LE :: Text -> ByteString+encodeUtf32LE txt = E.unstream (E.restreamUtf32LE (F.stream txt))+{-# INLINE encodeUtf32LE #-}++-- | Encode text using big endian UTF-32 encoding.+encodeUtf32BE :: Text -> ByteString+encodeUtf32BE txt = E.unstream (E.restreamUtf32BE (F.stream txt))+{-# INLINE encodeUtf32BE #-}++foreign import ccall unsafe "_hs_text_decode_utf8" c_decode_utf8+    :: MutableByteArray# s -> Ptr CSize+    -> Ptr Word8 -> Ptr Word8 -> IO (Ptr Word8)++foreign import ccall unsafe "_hs_text_decode_utf8_state" c_decode_utf8_with_state+    :: MutableByteArray# s -> Ptr CSize+    -> Ptr (Ptr Word8) -> Ptr Word8+    -> Ptr CodePoint -> Ptr DecoderState -> IO (Ptr Word8)++foreign import ccall unsafe "_hs_text_decode_latin1" c_decode_latin1+    :: MutableByteArray# s -> Ptr Word8 -> Ptr Word8 -> IO ()++foreign import ccall unsafe "_hs_text_encode_utf8" c_encode_utf8+    :: Ptr (Ptr Word8) -> ByteArray# -> CSize -> CSize -> IO ()
+ src/Data/Text/Encoding/Error.hs view
@@ -0,0 +1,124 @@+{-# LANGUAGE CPP, DeriveDataTypeable #-}+#if __GLASGOW_HASKELL__ >= 704+{-# LANGUAGE Safe #-}+#elif __GLASGOW_HASKELL__ >= 702+{-# LANGUAGE Trustworthy #-}+#endif+-- |+-- Module      : Data.Text.Encoding.Error+-- Copyright   : (c) Bryan O'Sullivan 2009+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Portability : GHC+--+-- Types and functions for dealing with encoding and decoding errors+-- in Unicode text.+--+-- The standard functions for encoding and decoding text are strict,+-- which is to say that they throw exceptions on invalid input.  This+-- is often unhelpful on real world input, so alternative functions+-- exist that accept custom handlers for dealing with invalid inputs.+-- These 'OnError' handlers are normal Haskell functions.  You can use+-- one of the presupplied functions in this module, or you can write a+-- custom handler of your own.++module Data.Text.Encoding.Error+    (+    -- * Error handling types+      UnicodeException(..)+    , OnError+    , OnDecodeError+    , OnEncodeError+    -- * Useful error handling functions+    , lenientDecode+    , strictDecode+    , strictEncode+    , ignore+    , replace+    ) where++import Control.DeepSeq (NFData (..))+import Control.Exception (Exception, throw)+import Data.Typeable (Typeable)+import Data.Word (Word8)+import Numeric (showHex)++-- | Function type for handling a coding error.  It is supplied with+-- two inputs:+--+-- * A 'String' that describes the error.+--+-- * The input value that caused the error.  If the error arose+--   because the end of input was reached or could not be identified+--   precisely, this value will be 'Nothing'.+--+-- If the handler returns a value wrapped with 'Just', that value will+-- be used in the output as the replacement for the invalid input.  If+-- it returns 'Nothing', no value will be used in the output.+--+-- Should the handler need to abort processing, it should use 'error'+-- or 'throw' an exception (preferably a 'UnicodeException').  It may+-- use the description provided to construct a more helpful error+-- report.+type OnError a b = String -> Maybe a -> Maybe b++-- | A handler for a decoding error.+type OnDecodeError = OnError Word8 Char++-- | A handler for an encoding error.+{-# DEPRECATED OnEncodeError "This exception is never used in practice, and will be removed." #-}+type OnEncodeError = OnError Char Word8++-- | An exception type for representing Unicode encoding errors.+data UnicodeException =+    DecodeError String (Maybe Word8)+    -- ^ Could not decode a byte sequence because it was invalid under+    -- the given encoding, or ran out of input in mid-decode.+  | EncodeError String (Maybe Char)+    -- ^ Tried to encode a character that could not be represented+    -- under the given encoding, or ran out of input in mid-encode.+    deriving (Eq, Typeable)++{-# DEPRECATED EncodeError "This constructor is never used, and will be removed." #-}++showUnicodeException :: UnicodeException -> String+showUnicodeException (DecodeError desc (Just w))+    = "Cannot decode byte '\\x" ++ showHex w ("': " ++ desc)+showUnicodeException (DecodeError desc Nothing)+    = "Cannot decode input: " ++ desc+showUnicodeException (EncodeError desc (Just c))+    = "Cannot encode character '\\x" ++ showHex (fromEnum c) ("': " ++ desc)+showUnicodeException (EncodeError desc Nothing)+    = "Cannot encode input: " ++ desc++instance Show UnicodeException where+    show = showUnicodeException++instance Exception UnicodeException++instance NFData UnicodeException where+    rnf (DecodeError desc w) = rnf desc `seq` rnf w `seq` ()+    rnf (EncodeError desc c) = rnf desc `seq` rnf c `seq` ()++-- | Throw a 'UnicodeException' if decoding fails.+strictDecode :: OnDecodeError+strictDecode desc c = throw (DecodeError desc c)++-- | Replace an invalid input byte with the Unicode replacement+-- character U+FFFD.+lenientDecode :: OnDecodeError+lenientDecode _ _ = Just '\xfffd'++-- | Throw a 'UnicodeException' if encoding fails.+{-# DEPRECATED strictEncode "This function always throws an exception, and will be removed." #-}+strictEncode :: OnEncodeError+strictEncode desc c = throw (EncodeError desc c)++-- | Ignore an invalid input, substituting nothing in the output.+ignore :: OnError a b+ignore _ _ = Nothing++-- | Replace an invalid input with a valid output.+replace :: b -> OnError a b+replace c _ _ = Just c
+ src/Data/Text/Foreign.hs view
@@ -0,0 +1,176 @@+{-# LANGUAGE BangPatterns, CPP, GeneralizedNewtypeDeriving #-}+-- |+-- Module      : Data.Text.Foreign+-- Copyright   : (c) 2009, 2010 Bryan O'Sullivan+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Portability : GHC+--+-- Support for using 'Text' data with native code via the Haskell+-- foreign function interface.++module Data.Text.Foreign+    (+    -- * Interoperability with native code+    -- $interop+      I16+    -- * Safe conversion functions+    , fromPtr+    , useAsPtr+    , asForeignPtr+    -- ** Encoding as UTF-8+    , peekCStringLen+    , withCStringLen+    -- * Unsafe conversion code+    , lengthWord16+    , unsafeCopyToPtr+    -- * Low-level manipulation+    -- $lowlevel+    , dropWord16+    , takeWord16+    ) where++#if defined(ASSERTS)+import Control.Exception (assert)+#endif+#if MIN_VERSION_base(4,4,0)+import Control.Monad.ST.Unsafe (unsafeIOToST)+#else+import Control.Monad.ST (unsafeIOToST)+#endif+import Data.ByteString.Unsafe (unsafePackCStringLen, unsafeUseAsCStringLen)+import Data.Text.Encoding (decodeUtf8, encodeUtf8)+import Data.Text.Internal (Text(..), empty)+import Data.Text.Unsafe (lengthWord16)+import Data.Word (Word16)+import Foreign.C.String (CStringLen)+import Foreign.ForeignPtr (ForeignPtr, mallocForeignPtrArray, withForeignPtr)+import Foreign.Marshal.Alloc (allocaBytes)+import Foreign.Ptr (Ptr, castPtr, plusPtr)+import Foreign.Storable (peek, poke)+import qualified Data.Text.Array as A++-- $interop+--+-- The 'Text' type is implemented using arrays that are not guaranteed+-- to have a fixed address in the Haskell heap. All communication with+-- native code must thus occur by copying data back and forth.+--+-- The 'Text' type's internal representation is UTF-16, using the+-- platform's native endianness.  This makes copied data suitable for+-- use with native libraries that use a similar representation, such+-- as ICU.  To interoperate with native libraries that use different+-- internal representations, such as UTF-8 or UTF-32, consider using+-- the functions in the 'Data.Text.Encoding' module.++-- | A type representing a number of UTF-16 code units.+newtype I16 = I16 Int+    deriving (Bounded, Enum, Eq, Integral, Num, Ord, Read, Real, Show)++-- | /O(n)/ Create a new 'Text' from a 'Ptr' 'Word16' by copying the+-- contents of the array.+fromPtr :: Ptr Word16           -- ^ source array+        -> I16                  -- ^ length of source array (in 'Word16' units)+        -> IO Text+fromPtr _   (I16 0)   = return empty+fromPtr ptr (I16 len) =+#if defined(ASSERTS)+    assert (len > 0) $+#endif+    return $! Text arr 0 len+  where+    arr = A.run (A.new len >>= copy)+    copy marr = loop ptr 0+      where+        loop !p !i | i == len = return marr+                   | otherwise = do+          A.unsafeWrite marr i =<< unsafeIOToST (peek p)+          loop (p `plusPtr` 2) (i + 1)++-- $lowlevel+--+-- Foreign functions that use UTF-16 internally may return indices in+-- units of 'Word16' instead of characters.  These functions may+-- safely be used with such indices, as they will adjust offsets if+-- necessary to preserve the validity of a Unicode string.++-- | /O(1)/ Return the prefix of the 'Text' of @n@ 'Word16' units in+-- length.+--+-- If @n@ would cause the 'Text' to end inside a surrogate pair, the+-- end of the prefix will be advanced by one additional 'Word16' unit+-- to maintain its validity.+takeWord16 :: I16 -> Text -> Text+takeWord16 (I16 n) t@(Text arr off len)+    | n <= 0               = empty+    | n >= len || m >= len = t+    | otherwise            = Text arr off m+  where+    m | w < 0xD800 || w > 0xDBFF = n+      | otherwise                = n+1+    w = A.unsafeIndex arr (off+n-1)++-- | /O(1)/ Return the suffix of the 'Text', with @n@ 'Word16' units+-- dropped from its beginning.+--+-- If @n@ would cause the 'Text' to begin inside a surrogate pair, the+-- beginning of the suffix will be advanced by one additional 'Word16'+-- unit to maintain its validity.+dropWord16 :: I16 -> Text -> Text+dropWord16 (I16 n) t@(Text arr off len)+    | n <= 0               = t+    | n >= len || m >= len = empty+    | otherwise            = Text arr (off+m) (len-m)+  where+    m | w < 0xD800 || w > 0xDBFF = n+      | otherwise                = n+1+    w = A.unsafeIndex arr (off+n-1)++-- | /O(n)/ Copy a 'Text' to an array.  The array is assumed to be big+-- enough to hold the contents of the entire 'Text'.+unsafeCopyToPtr :: Text -> Ptr Word16 -> IO ()+unsafeCopyToPtr (Text arr off len) ptr = loop ptr off+  where+    end = off + len+    loop !p !i | i == end  = return ()+               | otherwise = do+      poke p (A.unsafeIndex arr i)+      loop (p `plusPtr` 2) (i + 1)++-- | /O(n)/ Perform an action on a temporary, mutable copy of a+-- 'Text'.  The copy is freed as soon as the action returns.+useAsPtr :: Text -> (Ptr Word16 -> I16 -> IO a) -> IO a+useAsPtr t@(Text _arr _off len) action =+    allocaBytes (len * 2) $ \buf -> do+      unsafeCopyToPtr t buf+      action (castPtr buf) (fromIntegral len)++-- | /O(n)/ Make a mutable copy of a 'Text'.+asForeignPtr :: Text -> IO (ForeignPtr Word16, I16)+asForeignPtr t@(Text _arr _off len) = do+  fp <- mallocForeignPtrArray len+  withForeignPtr fp $ unsafeCopyToPtr t+  return (fp, I16 len)++-- | /O(n)/ Decode a C string with explicit length, which is assumed+-- to have been encoded as UTF-8. If decoding fails, a+-- 'UnicodeException' is thrown.+--+-- @since 1.0.0.0+peekCStringLen :: CStringLen -> IO Text+peekCStringLen cs = do+  bs <- unsafePackCStringLen cs+  return $! decodeUtf8 bs++-- | Marshal a 'Text' into a C string encoded as UTF-8 in temporary+-- storage, with explicit length information. The encoded string may+-- contain NUL bytes, and is not followed by a trailing NUL byte.+--+-- The temporary storage is freed when the subcomputation terminates+-- (either normally or via an exception), so the pointer to the+-- temporary storage must /not/ be used after this function returns.+--+-- @since 1.0.0.0+withCStringLen :: Text -> (CStringLen -> IO a) -> IO a+withCStringLen t act = unsafeUseAsCStringLen (encodeUtf8 t) act
+ src/Data/Text/IO.hs view
@@ -0,0 +1,350 @@+{-# LANGUAGE BangPatterns, CPP, RecordWildCards, ScopedTypeVariables #-}+#if __GLASGOW_HASKELL__ >= 702+{-# LANGUAGE Trustworthy #-}+#endif+-- |+-- Module      : Data.Text.IO+-- Copyright   : (c) 2009, 2010 Bryan O'Sullivan,+--               (c) 2009 Simon Marlow+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Portability : GHC+--+-- Efficient locale-sensitive support for text I\/O.+--+-- Skip past the synopsis for some important notes on performance and+-- portability across different versions of GHC.++module Data.Text.IO+    (+    -- * Performance+    -- $performance++    -- * Locale support+    -- $locale+    -- * File-at-a-time operations+      readFile+    , writeFile+    , appendFile+    -- * Operations on handles+    , hGetContents+    , hGetChunk+    , hGetLine+    , hPutStr+    , hPutStrLn+    -- * Special cases for standard input and output+    , interact+    , getContents+    , getLine+    , putStr+    , putStrLn+    ) where++import Data.Text (Text)+import Prelude hiding (appendFile, getContents, getLine, interact,+                       putStr, putStrLn, readFile, writeFile)+import System.IO (Handle, IOMode(..), hPutChar, openFile, stdin, stdout,+                  withFile)+import qualified Control.Exception as E+import Control.Monad (liftM2, when)+import Data.IORef (readIORef, writeIORef)+import qualified Data.Text as T+import Data.Text.Internal.Fusion (stream)+import Data.Text.Internal.Fusion.Types (Step(..), Stream(..))+import Data.Text.Internal.IO (hGetLineWith, readChunk)+import GHC.IO.Buffer (Buffer(..), BufferState(..), CharBufElem, CharBuffer,+                      RawCharBuffer, emptyBuffer, isEmptyBuffer, newCharBuffer,+                      writeCharBuf)+import GHC.IO.Exception (IOException(ioe_type), IOErrorType(InappropriateType))+import GHC.IO.Handle.Internals (augmentIOError, hClose_help, wantReadableHandle,+                                wantWritableHandle)+import GHC.IO.Handle.Text (commitBuffer')+import GHC.IO.Handle.Types (BufferList(..), BufferMode(..), Handle__(..),+                            HandleType(..), Newline(..))+import System.IO (hGetBuffering, hFileSize, hSetBuffering, hTell)+import System.IO.Error (isEOFError)++-- $performance+-- #performance#+--+-- The functions in this module obey the runtime system's locale,+-- character set encoding, and line ending conversion settings.+--+-- If you know in advance that you will be working with data that has+-- a specific encoding (e.g. UTF-8), and your application is highly+-- performance sensitive, you may find that it is faster to perform+-- I\/O with bytestrings and to encode and decode yourself than to use+-- the functions in this module.+--+-- Whether this will hold depends on the version of GHC you are using,+-- the platform you are working on, the data you are working with, and+-- the encodings you are using, so be sure to test for yourself.++-- | The 'readFile' function reads a file and returns the contents of+-- the file as a string.  The entire file is read strictly, as with+-- 'getContents'.+readFile :: FilePath -> IO Text+readFile name = openFile name ReadMode >>= hGetContents++-- | Write a string to a file.  The file is truncated to zero length+-- before writing begins.+writeFile :: FilePath -> Text -> IO ()+writeFile p = withFile p WriteMode . flip hPutStr++-- | Write a string the end of a file.+appendFile :: FilePath -> Text -> IO ()+appendFile p = withFile p AppendMode . flip hPutStr++catchError :: String -> Handle -> Handle__ -> IOError -> IO (Text, Bool)+catchError caller h Handle__{..} err+    | isEOFError err = do+        buf <- readIORef haCharBuffer+        return $ if isEmptyBuffer buf+                 then (T.empty, True)+                 else (T.singleton '\r', True)+    | otherwise = E.throwIO (augmentIOError err caller h)++-- | Wrap readChunk and return a value indicating if we're reached the EOF.+-- This is needed because unpack_nl is unable to discern the difference+-- between a buffer with just \r due to EOF or because not enough data was left+-- for decoding. e.g. the final character decoded from the byte buffer was \r.+readChunkEof :: Handle__ -> CharBuffer -> IO (Text, Bool)+readChunkEof hh buf = do t <- readChunk hh buf+                         return (t, False)++-- | /Experimental./ Read a single chunk of strict text from a+-- 'Handle'. The size of the chunk depends on the amount of input+-- currently buffered.+--+-- This function blocks only if there is no data available, and EOF+-- has not yet been reached. Once EOF is reached, this function+-- returns an empty string instead of throwing an exception.+hGetChunk :: Handle -> IO Text+hGetChunk h = wantReadableHandle "hGetChunk" h readSingleChunk+ where+  readSingleChunk hh@Handle__{..} = do+    buf <- readIORef haCharBuffer+    (t, _) <- readChunkEof hh buf `E.catch` catchError "hGetChunk" h hh+    return (hh, t)++-- | Read the remaining contents of a 'Handle' as a string.  The+-- 'Handle' is closed once the contents have been read, or if an+-- exception is thrown.+--+-- Internally, this function reads a chunk at a time from the+-- lower-level buffering abstraction, and concatenates the chunks into+-- a single string once the entire file has been read.+--+-- As a result, it requires approximately twice as much memory as its+-- result to construct its result.  For files more than a half of+-- available RAM in size, this may result in memory exhaustion.+hGetContents :: Handle -> IO Text+hGetContents h = do+  chooseGoodBuffering h+  wantReadableHandle "hGetContents" h readAll+ where+  readAll hh@Handle__{..} = do+    let readChunks = do+          buf <- readIORef haCharBuffer+          (t, eof) <- readChunkEof hh buf+                         `E.catch` catchError "hGetContents" h hh+          if eof+            then return [t]+            else (t:) `fmap` readChunks+    ts <- readChunks+    (hh', _) <- hClose_help hh+    return (hh'{haType=ClosedHandle}, T.concat ts)++-- | Use a more efficient buffer size if we're reading in+-- block-buffered mode with the default buffer size.  When we can+-- determine the size of the handle we're reading, set the buffer size+-- to that, so that we can read the entire file in one chunk.+-- Otherwise, use a buffer size of at least 16KB.+chooseGoodBuffering :: Handle -> IO ()+chooseGoodBuffering h = do+  bufMode <- hGetBuffering h+  case bufMode of+    BlockBuffering Nothing -> do+      d <- E.catch (liftM2 (-) (hFileSize h) (hTell h)) $ \(e::IOException) ->+           if ioe_type e == InappropriateType+           then return 16384 -- faster than the 2KB default+           else E.throwIO e+      when (d > 0) . hSetBuffering h . BlockBuffering . Just . fromIntegral $ d+    _ -> return ()++-- | Read a single line from a handle.+hGetLine :: Handle -> IO Text+hGetLine = hGetLineWith T.concat++-- | Write a string to a handle.+hPutStr :: Handle -> Text -> IO ()+-- This function is lifted almost verbatim from GHC.IO.Handle.Text.+hPutStr h t = do+  (buffer_mode, nl) <-+       wantWritableHandle "hPutStr" h $ \h_ -> do+                     bmode <- getSpareBuffer h_+                     return (bmode, haOutputNL h_)+  let str = stream t+  case buffer_mode of+     (NoBuffering, _)        -> hPutChars h str+     (LineBuffering, buf)    -> writeLines h nl buf str+     (BlockBuffering _, buf)+         | nl == CRLF        -> writeBlocksCRLF h buf str+         | otherwise         -> writeBlocksRaw h buf str++hPutChars :: Handle -> Stream Char -> IO ()+hPutChars h (Stream next0 s0 _len) = loop s0+  where+    loop !s = case next0 s of+                Done       -> return ()+                Skip s'    -> loop s'+                Yield x s' -> hPutChar h x >> loop s'++-- The following functions are largely lifted from GHC.IO.Handle.Text,+-- but adapted to a coinductive stream of data instead of an inductive+-- list.+--+-- We have several variations of more or less the same code for+-- performance reasons.  Splitting the original buffered write+-- function into line- and block-oriented versions gave us a 2.1x+-- performance improvement.  Lifting out the raw/cooked newline+-- handling gave a few more percent on top.++writeLines :: Handle -> Newline -> Buffer CharBufElem -> Stream Char -> IO ()+writeLines h nl buf0 (Stream next0 s0 _len) = outer s0 buf0+ where+  outer s1 Buffer{bufRaw=raw, bufSize=len} = inner s1 (0::Int)+   where+    inner !s !n =+      case next0 s of+        Done -> commit n False{-no flush-} True{-release-} >> return ()+        Skip s' -> inner s' n+        Yield x s'+          | n + 1 >= len -> commit n True{-needs flush-} False >>= outer s+          | x == '\n'    -> do+                   n' <- if nl == CRLF+                         then do n1 <- writeCharBuf raw n '\r'+                                 writeCharBuf raw n1 '\n'+                         else writeCharBuf raw n x+                   commit n' True{-needs flush-} False >>= outer s'+          | otherwise    -> writeCharBuf raw n x >>= inner s'+    commit = commitBuffer h raw len++writeBlocksCRLF :: Handle -> Buffer CharBufElem -> Stream Char -> IO ()+writeBlocksCRLF h buf0 (Stream next0 s0 _len) = outer s0 buf0+ where+  outer s1 Buffer{bufRaw=raw, bufSize=len} = inner s1 (0::Int)+   where+    inner !s !n =+      case next0 s of+        Done -> commit n False{-no flush-} True{-release-} >> return ()+        Skip s' -> inner s' n+        Yield x s'+          | n + 1 >= len -> commit n True{-needs flush-} False >>= outer s+          | x == '\n'    -> do n1 <- writeCharBuf raw n '\r'+                               writeCharBuf raw n1 '\n' >>= inner s'+          | otherwise    -> writeCharBuf raw n x >>= inner s'+    commit = commitBuffer h raw len++writeBlocksRaw :: Handle -> Buffer CharBufElem -> Stream Char -> IO ()+writeBlocksRaw h buf0 (Stream next0 s0 _len) = outer s0 buf0+ where+  outer s1 Buffer{bufRaw=raw, bufSize=len} = inner s1 (0::Int)+   where+    inner !s !n =+      case next0 s of+        Done -> commit n False{-no flush-} True{-release-} >> return ()+        Skip s' -> inner s' n+        Yield x s'+          | n + 1 >= len -> commit n True{-needs flush-} False >>= outer s+          | otherwise    -> writeCharBuf raw n x >>= inner s'+    commit = commitBuffer h raw len++-- This function is completely lifted from GHC.IO.Handle.Text.+getSpareBuffer :: Handle__ -> IO (BufferMode, CharBuffer)+getSpareBuffer Handle__{haCharBuffer=ref,+                        haBuffers=spare_ref,+                        haBufferMode=mode}+ = do+   case mode of+     NoBuffering -> return (mode, error "no buffer!")+     _ -> do+          bufs <- readIORef spare_ref+          buf  <- readIORef ref+          case bufs of+            BufferListCons b rest -> do+                writeIORef spare_ref rest+                return ( mode, emptyBuffer b (bufSize buf) WriteBuffer)+            BufferListNil -> do+                new_buf <- newCharBuffer (bufSize buf) WriteBuffer+                return (mode, new_buf)+++-- This function is completely lifted from GHC.IO.Handle.Text.+commitBuffer :: Handle -> RawCharBuffer -> Int -> Int -> Bool -> Bool+             -> IO CharBuffer+commitBuffer hdl !raw !sz !count flush release =+  wantWritableHandle "commitAndReleaseBuffer" hdl $+     commitBuffer' raw sz count flush release+{-# INLINE commitBuffer #-}++-- | Write a string to a handle, followed by a newline.+hPutStrLn :: Handle -> Text -> IO ()+hPutStrLn h t = hPutStr h t >> hPutChar h '\n'++-- | The 'interact' function takes a function of type @Text -> Text@+-- as its argument. The entire input from the standard input device is+-- passed to this function as its argument, and the resulting string+-- is output on the standard output device.+interact :: (Text -> Text) -> IO ()+interact f = putStr . f =<< getContents++-- | Read all user input on 'stdin' as a single string.+getContents :: IO Text+getContents = hGetContents stdin++-- | Read a single line of user input from 'stdin'.+getLine :: IO Text+getLine = hGetLine stdin++-- | Write a string to 'stdout'.+putStr :: Text -> IO ()+putStr = hPutStr stdout++-- | Write a string to 'stdout', followed by a newline.+putStrLn :: Text -> IO ()+putStrLn = hPutStrLn stdout++-- $locale+--+-- /Note/: The behaviour of functions in this module depends on the+-- version of GHC you are using.+--+-- Beginning with GHC 6.12, text I\/O is performed using the system or+-- handle's current locale and line ending conventions.+--+-- Under GHC 6.10 and earlier, the system I\/O libraries do not+-- support locale-sensitive I\/O or line ending conversion.  On these+-- versions of GHC, functions in this library all use UTF-8.  What+-- does this mean in practice?+--+-- * All data that is read will be decoded as UTF-8.+--+-- * Before data is written, it is first encoded as UTF-8.+--+-- * On both reading and writing, the platform's native newline+--   conversion is performed.+--+-- If you must use a non-UTF-8 locale on an older version of GHC, you+-- will have to perform the transcoding yourself, e.g. as follows:+--+-- > import qualified Data.ByteString as B+-- > import Data.Text (Text)+-- > import Data.Text.Encoding (encodeUtf16)+-- >+-- > putStr_Utf16LE :: Text -> IO ()+-- > putStr_Utf16LE t = B.putStr (encodeUtf16LE t)+--+-- On transcoding errors, an 'IOError' exception is thrown. You can+-- use the API in "Data.Text.Encoding" if you need more control over+-- error handling or transcoding.
+ src/Data/Text/Internal.hs view
@@ -0,0 +1,188 @@+{-# LANGUAGE CPP, DeriveDataTypeable, UnboxedTuples #-}+{-# OPTIONS_HADDOCK not-home #-}++-- |+-- Module      : Data.Text.Internal+-- Copyright   : (c) 2008, 2009 Tom Harper,+--               (c) 2009, 2010 Bryan O'Sullivan,+--               (c) 2009 Duncan Coutts+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- A module containing private 'Text' internals. This exposes the+-- 'Text' representation and low level construction functions.+-- Modules which extend the 'Text' system may need to use this module.+--+-- You should not use this module unless you are determined to monkey+-- with the internals, as the functions here do just about nothing to+-- preserve data invariants.  You have been warned!++#if defined(__GLASGOW_HASKELL__) && !defined(__HADDOCK__)+#include "MachDeps.h"+#endif++module Data.Text.Internal+    (+    -- * Types+    -- $internals+      Text(..)+    -- * Construction+    , text+    , textP+    -- * Safety+    , safe+    -- * Code that must be here for accessibility+    , empty+    , empty_+    -- * Utilities+    , firstf+    -- * Checked multiplication+    , mul+    , mul32+    , mul64+    -- * Debugging+    , showText+    ) where++#if defined(ASSERTS)+import Control.Exception (assert)+#endif+import Data.Bits+import Data.Int (Int32, Int64)+import Data.Text.Internal.Unsafe.Char (ord)+import Data.Typeable (Typeable)+import qualified Data.Text.Array as A++-- | A space efficient, packed, unboxed Unicode text type.+data Text = Text+    {-# UNPACK #-} !A.Array          -- payload (Word16 elements)+    {-# UNPACK #-} !Int              -- offset (units of Word16, not Char)+    {-# UNPACK #-} !Int              -- length (units of Word16, not Char)+    deriving (Typeable)++-- | Smart constructor.+text_ :: A.Array -> Int -> Int -> Text+text_ arr off len =+#if defined(ASSERTS)+  let c    = A.unsafeIndex arr off+      alen = A.length arr+  in assert (len >= 0) .+     assert (off >= 0) .+     assert (alen == 0 || len == 0 || off < alen) .+     assert (len == 0 || c < 0xDC00 || c > 0xDFFF) $+#endif+     Text arr off len+{-# INLINE text_ #-}++-- | /O(1)/ The empty 'Text'.+empty :: Text+empty = Text A.empty 0 0+{-# INLINE [1] empty #-}++-- | A non-inlined version of 'empty'.+empty_ :: Text+empty_ = Text A.empty 0 0+{-# NOINLINE empty_ #-}++-- | Construct a 'Text' without invisibly pinning its byte array in+-- memory if its length has dwindled to zero.+text :: A.Array -> Int -> Int -> Text+text arr off len | len == 0  = empty+                 | otherwise = text_ arr off len+{-# INLINE text #-}++textP :: A.Array -> Int -> Int -> Text+{-# DEPRECATED textP "Use text instead" #-}+textP = text++-- | A useful 'show'-like function for debugging purposes.+showText :: Text -> String+showText (Text arr off len) =+    "Text " ++ show (A.toList arr off len) ++ ' ' :+            show off ++ ' ' : show len++-- | Map a 'Char' to a 'Text'-safe value.+--+-- UTF-16 surrogate code points are not included in the set of Unicode+-- scalar values, but are unfortunately admitted as valid 'Char'+-- values by Haskell.  They cannot be represented in a 'Text'.  This+-- function remaps those code points to the Unicode replacement+-- character (U+FFFD, \'&#xfffd;\'), and leaves other code points+-- unchanged.+safe :: Char -> Char+safe c+    | ord c .&. 0x1ff800 /= 0xd800 = c+    | otherwise                    = '\xfffd'+{-# INLINE [0] safe #-}++-- | Apply a function to the first element of an optional pair.+firstf :: (a -> c) -> Maybe (a,b) -> Maybe (c,b)+firstf f (Just (a, b)) = Just (f a, b)+firstf _  Nothing      = Nothing++-- | Checked multiplication.  Calls 'error' if the result would+-- overflow.+mul :: Int -> Int -> Int+#if WORD_SIZE_IN_BITS == 64+mul a b = fromIntegral $ fromIntegral a `mul64` fromIntegral b+#else+mul a b = fromIntegral $ fromIntegral a `mul32` fromIntegral b+#endif+{-# INLINE mul #-}+infixl 7 `mul`++-- | Checked multiplication.  Calls 'error' if the result would+-- overflow.+mul64 :: Int64 -> Int64 -> Int64+mul64 a b+  | a >= 0 && b >= 0 =  mul64_ a b+  | a >= 0           = -mul64_ a (-b)+  | b >= 0           = -mul64_ (-a) b+  | otherwise        =  mul64_ (-a) (-b)+{-# INLINE mul64 #-}+infixl 7 `mul64`++mul64_ :: Int64 -> Int64 -> Int64+mul64_ a b+  | ahi > 0 && bhi > 0 = error "overflow"+  | top > 0x7fffffff   = error "overflow"+  | total < 0          = error "overflow"+  | otherwise          = total+  where (# ahi, alo #) = (# a `shiftR` 32, a .&. 0xffffffff #)+        (# bhi, blo #) = (# b `shiftR` 32, b .&. 0xffffffff #)+        top            = ahi * blo + alo * bhi+        total          = (top `shiftL` 32) + alo * blo+{-# INLINE mul64_ #-}++-- | Checked multiplication.  Calls 'error' if the result would+-- overflow.+mul32 :: Int32 -> Int32 -> Int32+mul32 a b = case fromIntegral a * fromIntegral b of+              ab | ab < min32 || ab > max32 -> error "overflow"+                 | otherwise                -> fromIntegral ab+  where min32 = -0x80000000 :: Int64+        max32 =  0x7fffffff+{-# INLINE mul32 #-}+infixl 7 `mul32`++-- $internals+--+-- Internally, the 'Text' type is represented as an array of 'Word16'+-- UTF-16 code units. The offset and length fields in the constructor+-- are in these units, /not/ units of 'Char'.+--+-- Invariants that all functions must maintain:+--+-- * Since the 'Text' type uses UTF-16 internally, it cannot represent+--   characters in the reserved surrogate code point range U+D800 to+--   U+DFFF. To maintain this invariant, the 'safe' function maps+--   'Char' values in this range to the replacement character (U+FFFD,+--   \'&#xfffd;\').+--+-- * A leading (or \"high\") surrogate code unit (0xD800–0xDBFF) must+--   always be followed by a trailing (or \"low\") surrogate code unit+--   (0xDC00-0xDFFF). A trailing surrogate code unit must always be+--   preceded by a leading surrogate code unit.
+ src/Data/Text/Internal/Builder.hs view
@@ -0,0 +1,329 @@+{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}+{-# OPTIONS_HADDOCK not-home #-}++-----------------------------------------------------------------------------+-- |+-- Module      : Data.Text.Internal.Builder+-- Copyright   : (c) 2013 Bryan O'Sullivan+--               (c) 2010 Johan Tibell+-- License     : BSD-style (see LICENSE)+--+-- Maintainer  : Johan Tibell <johan.tibell@gmail.com>+-- Stability   : experimental+-- Portability : portable to Hugs and GHC+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- Efficient construction of lazy @Text@ values.  The principal+-- operations on a @Builder@ are @singleton@, @fromText@, and+-- @fromLazyText@, which construct new builders, and 'mappend', which+-- concatenates two builders.+--+-- To get maximum performance when building lazy @Text@ values using a+-- builder, associate @mappend@ calls to the right.  For example,+-- prefer+--+-- > singleton 'a' `mappend` (singleton 'b' `mappend` singleton 'c')+--+-- to+--+-- > singleton 'a' `mappend` singleton 'b' `mappend` singleton 'c'+--+-- as the latter associates @mappend@ to the left.+--+-----------------------------------------------------------------------------++module Data.Text.Internal.Builder+   ( -- * Public API+     -- ** The Builder type+     Builder+   , toLazyText+   , toLazyTextWith++     -- ** Constructing Builders+   , singleton+   , fromText+   , fromLazyText+   , fromString++     -- ** Flushing the buffer state+   , flush++     -- * Internal functions+   , append'+   , ensureFree+   , writeN+   ) where++import Control.Monad.ST (ST, runST)+import Data.Monoid (Monoid(..))+#if !MIN_VERSION_base(4,11,0) && MIN_VERSION_base(4,9,0)+import Data.Semigroup (Semigroup(..))+#endif+import Data.Text.Internal (Text(..))+import Data.Text.Internal.Lazy (smallChunkSize)+import Data.Text.Unsafe (inlineInterleaveST)+import Data.Text.Internal.Unsafe.Char (unsafeWrite)+import Prelude hiding (map, putChar)++import qualified Data.String as String+import qualified Data.Text as S+import qualified Data.Text.Array as A+import qualified Data.Text.Lazy as L++------------------------------------------------------------------------++-- | A @Builder@ is an efficient way to build lazy @Text@ values.+-- There are several functions for constructing builders, but only one+-- to inspect them: to extract any data, you have to turn them into+-- lazy @Text@ values using @toLazyText@.+--+-- Internally, a builder constructs a lazy @Text@ by filling arrays+-- piece by piece.  As each buffer is filled, it is \'popped\' off, to+-- become a new chunk of the resulting lazy @Text@.  All this is+-- hidden from the user of the @Builder@.+newtype Builder = Builder {+     -- Invariant (from Data.Text.Lazy):+     --      The lists include no null Texts.+     runBuilder :: forall s. (Buffer s -> ST s [S.Text])+                -> Buffer s+                -> ST s [S.Text]+   }++#if MIN_VERSION_base(4,9,0)+instance Semigroup Builder where+   (<>) = append+   {-# INLINE (<>) #-}+#endif++instance Monoid Builder where+   mempty  = empty+   {-# INLINE mempty #-}+#if MIN_VERSION_base(4,9,0)+   mappend = (<>) -- future-proof definition+#else+   mappend = append+#endif+   {-# INLINE mappend #-}+   mconcat = foldr mappend Data.Monoid.mempty+   {-# INLINE mconcat #-}++instance String.IsString Builder where+    fromString = fromString+    {-# INLINE fromString #-}++instance Show Builder where+    show = show . toLazyText++instance Eq Builder where+    a == b = toLazyText a == toLazyText b++instance Ord Builder where+    a <= b = toLazyText a <= toLazyText b++------------------------------------------------------------------------++-- | /O(1)./ The empty @Builder@, satisfying+--+--  * @'toLazyText' 'empty' = 'L.empty'@+--+empty :: Builder+empty = Builder (\ k buf -> k buf)+{-# INLINE empty #-}++-- | /O(1)./ A @Builder@ taking a single character, satisfying+--+--  * @'toLazyText' ('singleton' c) = 'L.singleton' c@+--+singleton :: Char -> Builder+singleton c = writeAtMost 2 $ \ marr o -> unsafeWrite marr o c+{-# INLINE singleton #-}++------------------------------------------------------------------------++-- | /O(1)./ The concatenation of two builders, an associative+-- operation with identity 'empty', satisfying+--+--  * @'toLazyText' ('append' x y) = 'L.append' ('toLazyText' x) ('toLazyText' y)@+--+append :: Builder -> Builder -> Builder+append (Builder f) (Builder g) = Builder (f . g)+{-# INLINE [0] append #-}++-- TODO: Experiment to find the right threshold.+copyLimit :: Int+copyLimit = 128++-- This function attempts to merge small @Text@ values instead of+-- treating each value as its own chunk.  We may not always want this.++-- | /O(1)./ A @Builder@ taking a 'S.Text', satisfying+--+--  * @'toLazyText' ('fromText' t) = 'L.fromChunks' [t]@+--+fromText :: S.Text -> Builder+fromText t@(Text arr off l)+    | S.null t       = empty+    | l <= copyLimit = writeN l $ \marr o -> A.copyI marr o arr off (l+o)+    | otherwise      = flush `append` mapBuilder (t :)+{-# INLINE [1] fromText #-}++{-# RULES+"fromText/pack" forall s .+        fromText (S.pack s) = fromString s+ #-}++-- | /O(1)./ A Builder taking a @String@, satisfying+--+--  * @'toLazyText' ('fromString' s) = 'L.fromChunks' [S.pack s]@+--+fromString :: String -> Builder+fromString str = Builder $ \k (Buffer p0 o0 u0 l0) ->+    let loop !marr !o !u !l [] = k (Buffer marr o u l)+        loop marr o u l s@(c:cs)+            | l <= 1 = do+                arr <- A.unsafeFreeze marr+                let !t = Text arr o u+                marr' <- A.new chunkSize+                ts <- inlineInterleaveST (loop marr' 0 0 chunkSize s)+                return $ t : ts+            | otherwise = do+                n <- unsafeWrite marr (o+u) c+                loop marr o (u+n) (l-n) cs+    in loop p0 o0 u0 l0 str+  where+    chunkSize = smallChunkSize+{-# INLINE fromString #-}++-- | /O(1)./ A @Builder@ taking a lazy @Text@, satisfying+--+--  * @'toLazyText' ('fromLazyText' t) = t@+--+fromLazyText :: L.Text -> Builder+fromLazyText ts = flush `append` mapBuilder (L.toChunks ts ++)+{-# INLINE fromLazyText #-}++------------------------------------------------------------------------++-- Our internal buffer type+data Buffer s = Buffer {-# UNPACK #-} !(A.MArray s)+                       {-# UNPACK #-} !Int  -- offset+                       {-# UNPACK #-} !Int  -- used units+                       {-# UNPACK #-} !Int  -- length left++------------------------------------------------------------------------++-- | /O(n)./ Extract a lazy @Text@ from a @Builder@ with a default+-- buffer size.  The construction work takes place if and when the+-- relevant part of the lazy @Text@ is demanded.+toLazyText :: Builder -> L.Text+toLazyText = toLazyTextWith smallChunkSize++-- | /O(n)./ Extract a lazy @Text@ from a @Builder@, using the given+-- size for the initial buffer.  The construction work takes place if+-- and when the relevant part of the lazy @Text@ is demanded.+--+-- If the initial buffer is too small to hold all data, subsequent+-- buffers will be the default buffer size.+toLazyTextWith :: Int -> Builder -> L.Text+toLazyTextWith chunkSize m = L.fromChunks (runST $+  newBuffer chunkSize >>= runBuilder (m `append` flush) (const (return [])))++-- | /O(1)./ Pop the strict @Text@ we have constructed so far, if any,+-- yielding a new chunk in the result lazy @Text@.+flush :: Builder+flush = Builder $ \ k buf@(Buffer p o u l) ->+    if u == 0+    then k buf+    else do arr <- A.unsafeFreeze p+            let !b = Buffer p (o+u) 0 l+                !t = Text arr o u+            ts <- inlineInterleaveST (k b)+            return $! t : ts+{-# INLINE [1] flush #-}+-- defer inlining so that flush/flush rule may fire.++------------------------------------------------------------------------++-- | Sequence an ST operation on the buffer+withBuffer :: (forall s. Buffer s -> ST s (Buffer s)) -> Builder+withBuffer f = Builder $ \k buf -> f buf >>= k+{-# INLINE withBuffer #-}++-- | Get the size of the buffer+withSize :: (Int -> Builder) -> Builder+withSize f = Builder $ \ k buf@(Buffer _ _ _ l) ->+    runBuilder (f l) k buf+{-# INLINE withSize #-}++-- | Map the resulting list of texts.+mapBuilder :: ([S.Text] -> [S.Text]) -> Builder+mapBuilder f = Builder (fmap f .)++------------------------------------------------------------------------++-- | Ensure that there are at least @n@ many elements available.+ensureFree :: Int -> Builder+ensureFree !n = withSize $ \ l ->+    if n <= l+    then empty+    else flush `append'` withBuffer (const (newBuffer (max n smallChunkSize)))+{-# INLINE [0] ensureFree #-}++writeAtMost :: Int -> (forall s. A.MArray s -> Int -> ST s Int) -> Builder+writeAtMost n f = ensureFree n `append'` withBuffer (writeBuffer f)+{-# INLINE [0] writeAtMost #-}++-- | Ensure that @n@ many elements are available, and then use @f@ to+-- write some elements into the memory.+writeN :: Int -> (forall s. A.MArray s -> Int -> ST s ()) -> Builder+writeN n f = writeAtMost n (\ p o -> f p o >> return n)+{-# INLINE writeN #-}++writeBuffer :: (A.MArray s -> Int -> ST s Int) -> Buffer s -> ST s (Buffer s)+writeBuffer f (Buffer p o u l) = do+    n <- f p (o+u)+    return $! Buffer p o (u+n) (l-n)+{-# INLINE writeBuffer #-}++newBuffer :: Int -> ST s (Buffer s)+newBuffer size = do+    arr <- A.new size+    return $! Buffer arr 0 0 size+{-# INLINE newBuffer #-}++------------------------------------------------------------------------+-- Some nice rules for Builder++-- This function makes GHC understand that 'writeN' and 'ensureFree'+-- are *not* recursive in the precense of the rewrite rules below.+-- This is not needed with GHC 7+.+append' :: Builder -> Builder -> Builder+append' (Builder f) (Builder g) = Builder (f . g)+{-# INLINE append' #-}++{-# RULES++"append/writeAtMost" forall a b (f::forall s. A.MArray s -> Int -> ST s Int)+                           (g::forall s. A.MArray s -> Int -> ST s Int) ws.+    append (writeAtMost a f) (append (writeAtMost b g) ws) =+        append (writeAtMost (a+b) (\marr o -> f marr o >>= \ n ->+                                    g marr (o+n) >>= \ m ->+                                    let s = n+m in s `seq` return s)) ws++"writeAtMost/writeAtMost" forall a b (f::forall s. A.MArray s -> Int -> ST s Int)+                           (g::forall s. A.MArray s -> Int -> ST s Int).+    append (writeAtMost a f) (writeAtMost b g) =+        writeAtMost (a+b) (\marr o -> f marr o >>= \ n ->+                            g marr (o+n) >>= \ m ->+                            let s = n+m in s `seq` return s)++"ensureFree/ensureFree" forall a b .+    append (ensureFree a) (ensureFree b) = ensureFree (max a b)++"flush/flush"+    append flush flush = flush++ #-}
+ src/Data/Text/Internal/Builder/Functions.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE MagicHash #-}++-- |+-- Module      : Data.Text.Internal.Builder.Functions+-- Copyright   : (c) 2011 MailRank, Inc.+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- Useful functions and combinators.++module Data.Text.Internal.Builder.Functions+    (+      (<>)+    , i2d+    ) where++import Data.Monoid (mappend)+import Data.Text.Lazy.Builder (Builder)+import GHC.Base (chr#,ord#,(+#),Int(I#),Char(C#))+import Prelude ()++-- | Unsafe conversion for decimal digits.+{-# INLINE i2d #-}+i2d :: Int -> Char+i2d (I# i#) = C# (chr# (ord# '0'# +# i#))++-- | The normal 'mappend' function with right associativity instead of+-- left.+(<>) :: Builder -> Builder -> Builder+(<>) = mappend+{-# INLINE (<>) #-}++infixr 4 <>
+ src/Data/Text/Internal/Builder/Int/Digits.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE OverloadedStrings #-}++-- Module:      Data.Text.Internal.Builder.Int.Digits+-- Copyright:   (c) 2013 Bryan O'Sullivan+-- License:     BSD-style+-- Maintainer:  Bryan O'Sullivan <bos@serpentine.com>+-- Stability:   experimental+-- Portability: portable+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- This module exists because the C preprocessor does things that we+-- shall not speak of when confronted with Haskell multiline strings.++module Data.Text.Internal.Builder.Int.Digits (digits) where++import Data.ByteString.Char8 (ByteString)++digits :: ByteString+digits = "0001020304050607080910111213141516171819\+         \2021222324252627282930313233343536373839\+         \4041424344454647484950515253545556575859\+         \6061626364656667686970717273747576777879\+         \8081828384858687888990919293949596979899"
+ src/Data/Text/Internal/Builder/RealFloat/Functions.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE CPP #-}++-- |+-- Module:    Data.Text.Internal.Builder.RealFloat.Functions+-- Copyright: (c) The University of Glasgow 1994-2002+-- License:   see libraries/base/LICENSE+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!++module Data.Text.Internal.Builder.RealFloat.Functions+    (+      roundTo+    ) where++roundTo :: Int -> [Int] -> (Int,[Int])++#if MIN_VERSION_base(4,6,0)++roundTo d is =+  case f d True is of+    x@(0,_) -> x+    (1,xs)  -> (1, 1:xs)+    _       -> error "roundTo: bad Value"+ where+  b2 = base `quot` 2++  f n _ []     = (0, replicate n 0)+  f 0 e (x:xs) | x == b2 && e && all (== 0) xs = (0, [])   -- Round to even when at exactly half the base+               | otherwise = (if x >= b2 then 1 else 0, [])+  f n _ (i:xs)+     | i' == base = (1,0:ds)+     | otherwise  = (0,i':ds)+      where+       (c,ds) = f (n-1) (even i) xs+       i'     = c + i+  base = 10++#else++roundTo d is =+  case f d is of+    x@(0,_) -> x+    (1,xs)  -> (1, 1:xs)+    _       -> error "roundTo: bad Value"+ where+  f n []     = (0, replicate n 0)+  f 0 (x:_)  = (if x >= 5 then 1 else 0, [])+  f n (i:xs)+     | i' == 10  = (1,0:ds)+     | otherwise = (0,i':ds)+      where+       (c,ds) = f (n-1) xs+       i'     = c + i++#endif
+ src/Data/Text/Internal/ByteStringCompat.hs view
@@ -0,0 +1,55 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE MagicHash #-}+module Data.Text.Internal.ByteStringCompat (mkBS, withBS) where++import Data.ByteString.Internal (ByteString (..))+import Data.Word (Word8)+import Foreign.ForeignPtr (ForeignPtr)++#if !MIN_VERSION_bytestring(0,11,0)+#if MIN_VERSION_base(4,10,0)+import GHC.ForeignPtr (plusForeignPtr)+#else+import GHC.ForeignPtr (ForeignPtr(ForeignPtr))+import GHC.Types (Int (..))+import GHC.Prim (plusAddr#)+#endif+#endif++mkBS :: ForeignPtr Word8 -> Int -> ByteString+#if MIN_VERSION_bytestring(0,11,0)+mkBS dfp n = BS dfp n+#else+mkBS dfp n = PS dfp 0 n+#endif+{-# INLINE mkBS #-}++withBS :: ByteString -> (ForeignPtr Word8 -> Int -> r) -> r+#if MIN_VERSION_bytestring(0,11,0)+withBS (BS !sfp !slen)       kont = kont sfp slen+#else+withBS (PS !sfp !soff !slen) kont = kont (plusForeignPtr sfp soff) slen+#endif+{-# INLINE withBS #-}++#if !MIN_VERSION_bytestring(0,11,0)+#if !MIN_VERSION_base(4,10,0)+-- |Advances the given address by the given offset in bytes.+--+-- The new 'ForeignPtr' shares the finalizer of the original,+-- equivalent from a finalization standpoint to just creating another+-- reference to the original. That is, the finalizer will not be+-- called before the new 'ForeignPtr' is unreachable, nor will it be+-- called an additional time due to this call, and the finalizer will+-- be called with the same address that it would have had this call+-- not happened, *not* the new address.+plusForeignPtr :: ForeignPtr a -> Int -> ForeignPtr b+plusForeignPtr (ForeignPtr addr guts) (I# offset) = ForeignPtr (plusAddr# addr offset) guts+{-# INLINE [0] plusForeignPtr #-}+{-# RULES+"ByteString plusForeignPtr/0" forall fp .+   plusForeignPtr fp 0 = fp+ #-}+#endif+#endif
+ src/Data/Text/Internal/Encoding/Fusion.hs view
@@ -0,0 +1,209 @@+{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}++-- |+-- Module      : Data.Text.Internal.Encoding.Fusion+-- Copyright   : (c) Tom Harper 2008-2009,+--               (c) Bryan O'Sullivan 2009,+--               (c) Duncan Coutts 2009+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : portable+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- Fusible 'Stream'-oriented functions for converting between 'Text'+-- and several common encodings.++module Data.Text.Internal.Encoding.Fusion+    (+    -- * Streaming+      streamASCII+    , streamUtf8+    , streamUtf16LE+    , streamUtf16BE+    , streamUtf32LE+    , streamUtf32BE++    -- * Unstreaming+    , unstream++    , module Data.Text.Internal.Encoding.Fusion.Common+    ) where++#if defined(ASSERTS)+import Control.Exception (assert)+#endif+import Data.ByteString.Internal (ByteString(..), mallocByteString, memcpy)+import Data.Text.Internal.Fusion (Step(..), Stream(..))+import Data.Text.Internal.Fusion.Size+import Data.Text.Encoding.Error+import Data.Text.Internal.Encoding.Fusion.Common+import Data.Text.Internal.Unsafe.Char (unsafeChr, unsafeChr8, unsafeChr32)+import Data.Text.Internal.Unsafe.Shift (shiftL, shiftR)+import Data.Word (Word8, Word16, Word32)+import Foreign.ForeignPtr (withForeignPtr, ForeignPtr)+import Foreign.Storable (pokeByteOff)+import qualified Data.ByteString as B+import qualified Data.ByteString.Unsafe as B+import qualified Data.Text.Internal.Encoding.Utf8 as U8+import qualified Data.Text.Internal.Encoding.Utf16 as U16+import qualified Data.Text.Internal.Encoding.Utf32 as U32+import Data.Text.Unsafe (unsafeDupablePerformIO)+import Data.Text.Internal.ByteStringCompat++streamASCII :: ByteString -> Stream Char+streamASCII bs = Stream next 0 (maxSize l)+    where+      l = B.length bs+      {-# INLINE next #-}+      next i+          | i >= l    = Done+          | otherwise = Yield (unsafeChr8 x1) (i+1)+          where+            x1 = B.unsafeIndex bs i+{-# DEPRECATED streamASCII "Do not use this function" #-}+{-# INLINE [0] streamASCII #-}++-- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using UTF-8+-- encoding.+streamUtf8 :: OnDecodeError -> ByteString -> Stream Char+streamUtf8 onErr bs = Stream next 0 (maxSize l)+    where+      l = B.length bs+      next i+          | i >= l = Done+          | U8.validate1 x1 = Yield (unsafeChr8 x1) (i+1)+          | i+1 < l && U8.validate2 x1 x2 = Yield (U8.chr2 x1 x2) (i+2)+          | i+2 < l && U8.validate3 x1 x2 x3 = Yield (U8.chr3 x1 x2 x3) (i+3)+          | i+3 < l && U8.validate4 x1 x2 x3 x4 = Yield (U8.chr4 x1 x2 x3 x4) (i+4)+          | otherwise = decodeError "streamUtf8" "UTF-8" onErr (Just x1) (i+1)+          where+            x1 = idx i+            x2 = idx (i + 1)+            x3 = idx (i + 2)+            x4 = idx (i + 3)+            idx = B.unsafeIndex bs+{-# INLINE [0] streamUtf8 #-}++-- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using little+-- endian UTF-16 encoding.+streamUtf16LE :: OnDecodeError -> ByteString -> Stream Char+streamUtf16LE onErr bs = Stream next 0 (maxSize (l `shiftR` 1))+    where+      l = B.length bs+      {-# INLINE next #-}+      next i+          | i >= l                         = Done+          | i+1 < l && U16.validate1 x1    = Yield (unsafeChr x1) (i+2)+          | i+3 < l && U16.validate2 x1 x2 = Yield (U16.chr2 x1 x2) (i+4)+          | otherwise = decodeError "streamUtf16LE" "UTF-16LE" onErr Nothing (i+1)+          where+            x1    = idx i       + (idx (i + 1) `shiftL` 8)+            x2    = idx (i + 2) + (idx (i + 3) `shiftL` 8)+            idx = fromIntegral . B.unsafeIndex bs :: Int -> Word16+{-# INLINE [0] streamUtf16LE #-}++-- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using big+-- endian UTF-16 encoding.+streamUtf16BE :: OnDecodeError -> ByteString -> Stream Char+streamUtf16BE onErr bs = Stream next 0 (maxSize (l `shiftR` 1))+    where+      l = B.length bs+      {-# INLINE next #-}+      next i+          | i >= l                         = Done+          | i+1 < l && U16.validate1 x1    = Yield (unsafeChr x1) (i+2)+          | i+3 < l && U16.validate2 x1 x2 = Yield (U16.chr2 x1 x2) (i+4)+          | otherwise = decodeError "streamUtf16BE" "UTF-16BE" onErr Nothing (i+1)+          where+            x1    = (idx i `shiftL` 8)       + idx (i + 1)+            x2    = (idx (i + 2) `shiftL` 8) + idx (i + 3)+            idx = fromIntegral . B.unsafeIndex bs :: Int -> Word16+{-# INLINE [0] streamUtf16BE #-}++-- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using big+-- endian UTF-32 encoding.+streamUtf32BE :: OnDecodeError -> ByteString -> Stream Char+streamUtf32BE onErr bs = Stream next 0 (maxSize (l `shiftR` 2))+    where+      l = B.length bs+      {-# INLINE next #-}+      next i+          | i >= l                    = Done+          | i+3 < l && U32.validate x = Yield (unsafeChr32 x) (i+4)+          | otherwise = decodeError "streamUtf32BE" "UTF-32BE" onErr Nothing (i+1)+          where+            x     = shiftL x1 24 + shiftL x2 16 + shiftL x3 8 + x4+            x1    = idx i+            x2    = idx (i+1)+            x3    = idx (i+2)+            x4    = idx (i+3)+            idx = fromIntegral . B.unsafeIndex bs :: Int -> Word32+{-# INLINE [0] streamUtf32BE #-}++-- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using little+-- endian UTF-32 encoding.+streamUtf32LE :: OnDecodeError -> ByteString -> Stream Char+streamUtf32LE onErr bs = Stream next 0 (maxSize (l `shiftR` 2))+    where+      l = B.length bs+      {-# INLINE next #-}+      next i+          | i >= l                    = Done+          | i+3 < l && U32.validate x = Yield (unsafeChr32 x) (i+4)+          | otherwise = decodeError "streamUtf32LE" "UTF-32LE" onErr Nothing (i+1)+          where+            x     = shiftL x4 24 + shiftL x3 16 + shiftL x2 8 + x1+            x1    = idx i+            x2    = idx $ i+1+            x3    = idx $ i+2+            x4    = idx $ i+3+            idx = fromIntegral . B.unsafeIndex bs :: Int -> Word32+{-# INLINE [0] streamUtf32LE #-}++-- | /O(n)/ Convert a 'Stream' 'Word8' to a 'ByteString'.+unstream :: Stream Word8 -> ByteString+unstream (Stream next s0 len) = unsafeDupablePerformIO $ do+    let mlen = upperBound 4 len+    mallocByteString mlen >>= loop mlen 0 s0+    where+      loop !n !off !s fp = case next s of+          Done -> trimUp fp n off+          Skip s' -> loop n off s' fp+          Yield x s'+              | off == n -> realloc fp n off s' x+              | otherwise -> do+            withForeignPtr fp $ \p -> pokeByteOff p off x+            loop n (off+1) s' fp+      {-# NOINLINE realloc #-}+      realloc fp n off s x = do+        let n' = n+n+        fp' <- copy0 fp n n'+        withForeignPtr fp' $ \p -> pokeByteOff p off x+        loop n' (off+1) s fp'+      {-# NOINLINE trimUp #-}+      trimUp fp _ off = return $! mkBS fp off+      copy0 :: ForeignPtr Word8 -> Int -> Int -> IO (ForeignPtr Word8)+      copy0 !src !srcLen !destLen =+#if defined(ASSERTS)+        assert (srcLen <= destLen) $+#endif+        do+          dest <- mallocByteString destLen+          withForeignPtr src  $ \src'  ->+              withForeignPtr dest $ \dest' ->+                  memcpy dest' src' (fromIntegral srcLen)+          return dest++decodeError :: forall s. String -> String -> OnDecodeError -> Maybe Word8+            -> s -> Step s Char+decodeError func kind onErr mb i =+    case onErr desc mb of+      Nothing -> Skip i+      Just c  -> Yield c i+    where desc = "Data.Text.Internal.Encoding.Fusion." ++ func ++ ": Invalid " +++                 kind ++ " stream"
+ src/Data/Text/Internal/Encoding/Fusion/Common.hs view
@@ -0,0 +1,123 @@+{-# LANGUAGE BangPatterns #-}++-- |+-- Module      : Data.Text.Internal.Encoding.Fusion.Common+-- Copyright   : (c) Tom Harper 2008-2009,+--               (c) Bryan O'Sullivan 2009,+--               (c) Duncan Coutts 2009,+--               (c) Jasper Van der Jeugt 2011+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : portable+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Use at your own risk!+--+-- Fusible 'Stream'-oriented functions for converting between 'Text'+-- and several common encodings.++module Data.Text.Internal.Encoding.Fusion.Common+    (+    -- * Restreaming+    -- Restreaming is the act of converting from one 'Stream'+    -- representation to another.+      restreamUtf16LE+    , restreamUtf16BE+    , restreamUtf32LE+    , restreamUtf32BE+    ) where++import Data.Bits ((.&.))+import Data.Text.Internal.Fusion (Step(..), Stream(..))+import Data.Text.Internal.Fusion.Types (RS(..))+import Data.Text.Internal.Unsafe.Char (ord)+import Data.Text.Internal.Unsafe.Shift (shiftR)+import Data.Word (Word8)++restreamUtf16BE :: Stream Char -> Stream Word8+restreamUtf16BE (Stream next0 s0 len) = Stream next (RS0 s0) (len * 2)+  where+    next (RS0 s) = case next0 s of+        Done -> Done+        Skip s' -> Skip (RS0 s')+        Yield x s'+            | n < 0x10000 -> Yield (fromIntegral $ n `shiftR` 8) $+                             RS1 s' (fromIntegral n)+            | otherwise   -> Yield c1 $ RS3 s' c2 c3 c4+            where+              n  = ord x+              n1 = n - 0x10000+              c1 = fromIntegral (n1 `shiftR` 18 + 0xD8)+              c2 = fromIntegral (n1 `shiftR` 10)+              n2 = n1 .&. 0x3FF+              c3 = fromIntegral (n2 `shiftR` 8 + 0xDC)+              c4 = fromIntegral n2+    next (RS1 s x2)       = Yield x2 (RS0 s)+    next (RS2 s x2 x3)    = Yield x2 (RS1 s x3)+    next (RS3 s x2 x3 x4) = Yield x2 (RS2 s x3 x4)+    {-# INLINE next #-}+{-# INLINE restreamUtf16BE #-}++restreamUtf16LE :: Stream Char -> Stream Word8+restreamUtf16LE (Stream next0 s0 len) = Stream next (RS0 s0) (len * 2)+  where+    next (RS0 s) = case next0 s of+        Done -> Done+        Skip s' -> Skip (RS0 s')+        Yield x s'+            | n < 0x10000 -> Yield (fromIntegral n) $+                             RS1 s' (fromIntegral $ shiftR n 8)+            | otherwise   -> Yield c1 $ RS3 s' c2 c3 c4+          where+            n  = ord x+            n1 = n - 0x10000+            c2 = fromIntegral (shiftR n1 18 + 0xD8)+            c1 = fromIntegral (shiftR n1 10)+            n2 = n1 .&. 0x3FF+            c4 = fromIntegral (shiftR n2 8 + 0xDC)+            c3 = fromIntegral n2+    next (RS1 s x2)       = Yield x2 (RS0 s)+    next (RS2 s x2 x3)    = Yield x2 (RS1 s x3)+    next (RS3 s x2 x3 x4) = Yield x2 (RS2 s x3 x4)+    {-# INLINE next #-}+{-# INLINE restreamUtf16LE #-}++restreamUtf32BE :: Stream Char -> Stream Word8+restreamUtf32BE (Stream next0 s0 len) = Stream next (RS0 s0) (len * 2)+  where+    next (RS0 s) = case next0 s of+        Done       -> Done+        Skip s'    -> Skip (RS0 s')+        Yield x s' -> Yield c1 (RS3 s' c2 c3 c4)+          where+            n  = ord x+            c1 = fromIntegral $ shiftR n 24+            c2 = fromIntegral $ shiftR n 16+            c3 = fromIntegral $ shiftR n 8+            c4 = fromIntegral n+    next (RS1 s x2)       = Yield x2 (RS0 s)+    next (RS2 s x2 x3)    = Yield x2 (RS1 s x3)+    next (RS3 s x2 x3 x4) = Yield x2 (RS2 s x3 x4)+    {-# INLINE next #-}+{-# INLINE restreamUtf32BE #-}++restreamUtf32LE :: Stream Char -> Stream Word8+restreamUtf32LE (Stream next0 s0 len) = Stream next (RS0 s0) (len * 2)+  where+    next (RS0 s) = case next0 s of+        Done       -> Done+        Skip s'    -> Skip (RS0 s')+        Yield x s' -> Yield c1 (RS3 s' c2 c3 c4)+          where+            n  = ord x+            c4 = fromIntegral $ shiftR n 24+            c3 = fromIntegral $ shiftR n 16+            c2 = fromIntegral $ shiftR n 8+            c1 = fromIntegral n+    next (RS1 s x2)       = Yield x2 (RS0 s)+    next (RS2 s x2 x3)    = Yield x2 (RS1 s x3)+    next (RS3 s x2 x3 x4) = Yield x2 (RS2 s x3 x4)+    {-# INLINE next #-}+{-# INLINE restreamUtf32LE #-}
+ src/Data/Text/Internal/Encoding/Utf16.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE MagicHash, BangPatterns #-}++-- |+-- Module      : Data.Text.Internal.Encoding.Utf16+-- Copyright   : (c) 2008, 2009 Tom Harper,+--               (c) 2009 Bryan O'Sullivan,+--               (c) 2009 Duncan Coutts+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- Basic UTF-16 validation and character manipulation.+module Data.Text.Internal.Encoding.Utf16+    (+      chr2+    , validate1+    , validate2+    ) where++import GHC.Exts+import GHC.Word (Word16(..))++chr2 :: Word16 -> Word16 -> Char+chr2 (W16# a#) (W16# b#) = C# (chr# (upper# +# lower# +# 0x10000#))+    where+      !x# = word2Int# a#+      !y# = word2Int# b#+      !upper# = uncheckedIShiftL# (x# -# 0xD800#) 10#+      !lower# = y# -# 0xDC00#+{-# INLINE chr2 #-}++validate1    :: Word16 -> Bool+validate1 x1 = x1 < 0xD800 || x1 > 0xDFFF+{-# INLINE validate1 #-}++validate2       ::  Word16 -> Word16 -> Bool+validate2 x1 x2 = x1 >= 0xD800 && x1 <= 0xDBFF &&+                  x2 >= 0xDC00 && x2 <= 0xDFFF+{-# INLINE validate2 #-}
+ src/Data/Text/Internal/Encoding/Utf32.hs view
@@ -0,0 +1,26 @@+-- |+-- Module      : Data.Text.Internal.Encoding.Utf32+-- Copyright   : (c) 2008, 2009 Tom Harper,+--               (c) 2009, 2010 Bryan O'Sullivan,+--               (c) 2009 Duncan Coutts+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : portable+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- Basic UTF-32 validation.+module Data.Text.Internal.Encoding.Utf32+    (+      validate+    ) where++import Data.Word (Word32)++validate    :: Word32 -> Bool+validate x1 = x1 < 0xD800 || (x1 > 0xDFFF && x1 <= 0x10FFFF)+{-# INLINE validate #-}
+ src/Data/Text/Internal/Encoding/Utf8.hs view
@@ -0,0 +1,168 @@+{-# LANGUAGE CPP, MagicHash, BangPatterns #-}++-- |+-- Module      : Data.Text.Internal.Encoding.Utf8+-- Copyright   : (c) 2008, 2009 Tom Harper,+--               (c) 2009, 2010 Bryan O'Sullivan,+--               (c) 2009 Duncan Coutts+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- Basic UTF-8 validation and character manipulation.+module Data.Text.Internal.Encoding.Utf8+    (+    -- Decomposition+      ord2+    , ord3+    , ord4+    -- Construction+    , chr2+    , chr3+    , chr4+    -- * Validation+    , validate1+    , validate2+    , validate3+    , validate4+    ) where++#if defined(TEST_SUITE)+# undef ASSERTS+#endif++#if defined(ASSERTS)+import Control.Exception (assert)+#endif+import Data.Bits ((.&.))+import Data.Text.Internal.Unsafe.Char (ord)+import Data.Text.Internal.Unsafe.Shift (shiftR)+import GHC.Exts+import GHC.Word (Word8(..))++default(Int)++between :: Word8                -- ^ byte to check+        -> Word8                -- ^ lower bound+        -> Word8                -- ^ upper bound+        -> Bool+between x y z = x >= y && x <= z+{-# INLINE between #-}++ord2 :: Char -> (Word8,Word8)+ord2 c =+#if defined(ASSERTS)+    assert (n >= 0x80 && n <= 0x07ff)+#endif+    (x1,x2)+    where+      n  = ord c+      x1 = fromIntegral $ (n `shiftR` 6) + 0xC0+      x2 = fromIntegral $ (n .&. 0x3F)   + 0x80++ord3 :: Char -> (Word8,Word8,Word8)+ord3 c =+#if defined(ASSERTS)+    assert (n >= 0x0800 && n <= 0xffff)+#endif+    (x1,x2,x3)+    where+      n  = ord c+      x1 = fromIntegral $ (n `shiftR` 12) + 0xE0+      x2 = fromIntegral $ ((n `shiftR` 6) .&. 0x3F) + 0x80+      x3 = fromIntegral $ (n .&. 0x3F) + 0x80++ord4 :: Char -> (Word8,Word8,Word8,Word8)+ord4 c =+#if defined(ASSERTS)+    assert (n >= 0x10000)+#endif+    (x1,x2,x3,x4)+    where+      n  = ord c+      x1 = fromIntegral $ (n `shiftR` 18) + 0xF0+      x2 = fromIntegral $ ((n `shiftR` 12) .&. 0x3F) + 0x80+      x3 = fromIntegral $ ((n `shiftR` 6) .&. 0x3F) + 0x80+      x4 = fromIntegral $ (n .&. 0x3F) + 0x80++chr2 :: Word8 -> Word8 -> Char+chr2 (W8# x1#) (W8# x2#) = C# (chr# (z1# +# z2#))+    where+      !y1# = word2Int# x1#+      !y2# = word2Int# x2#+      !z1# = uncheckedIShiftL# (y1# -# 0xC0#) 6#+      !z2# = y2# -# 0x80#+{-# INLINE chr2 #-}++chr3 :: Word8 -> Word8 -> Word8 -> Char+chr3 (W8# x1#) (W8# x2#) (W8# x3#) = C# (chr# (z1# +# z2# +# z3#))+    where+      !y1# = word2Int# x1#+      !y2# = word2Int# x2#+      !y3# = word2Int# x3#+      !z1# = uncheckedIShiftL# (y1# -# 0xE0#) 12#+      !z2# = uncheckedIShiftL# (y2# -# 0x80#) 6#+      !z3# = y3# -# 0x80#+{-# INLINE chr3 #-}++chr4             :: Word8 -> Word8 -> Word8 -> Word8 -> Char+chr4 (W8# x1#) (W8# x2#) (W8# x3#) (W8# x4#) =+    C# (chr# (z1# +# z2# +# z3# +# z4#))+    where+      !y1# = word2Int# x1#+      !y2# = word2Int# x2#+      !y3# = word2Int# x3#+      !y4# = word2Int# x4#+      !z1# = uncheckedIShiftL# (y1# -# 0xF0#) 18#+      !z2# = uncheckedIShiftL# (y2# -# 0x80#) 12#+      !z3# = uncheckedIShiftL# (y3# -# 0x80#) 6#+      !z4# = y4# -# 0x80#+{-# INLINE chr4 #-}++validate1 :: Word8 -> Bool+validate1 x1 = x1 <= 0x7F+{-# INLINE validate1 #-}++validate2 :: Word8 -> Word8 -> Bool+validate2 x1 x2 = between x1 0xC2 0xDF && between x2 0x80 0xBF+{-# INLINE validate2 #-}++validate3 :: Word8 -> Word8 -> Word8 -> Bool+{-# INLINE validate3 #-}+validate3 x1 x2 x3 = validate3_1 || validate3_2 || validate3_3 || validate3_4+  where+    validate3_1 = (x1 == 0xE0) &&+                  between x2 0xA0 0xBF &&+                  between x3 0x80 0xBF+    validate3_2 = between x1 0xE1 0xEC &&+                  between x2 0x80 0xBF &&+                  between x3 0x80 0xBF+    validate3_3 = x1 == 0xED &&+                  between x2 0x80 0x9F &&+                  between x3 0x80 0xBF+    validate3_4 = between x1 0xEE 0xEF &&+                  between x2 0x80 0xBF &&+                  between x3 0x80 0xBF++validate4 :: Word8 -> Word8 -> Word8 -> Word8 -> Bool+{-# INLINE validate4 #-}+validate4 x1 x2 x3 x4 = validate4_1 || validate4_2 || validate4_3+  where+    validate4_1 = x1 == 0xF0 &&+                  between x2 0x90 0xBF &&+                  between x3 0x80 0xBF &&+                  between x4 0x80 0xBF+    validate4_2 = between x1 0xF1 0xF3 &&+                  between x2 0x80 0xBF &&+                  between x3 0x80 0xBF &&+                  between x4 0x80 0xBF+    validate4_3 = x1 == 0xF4 &&+                  between x2 0x80 0x8F &&+                  between x3 0x80 0xBF &&+                  between x4 0x80 0xBF
+ src/Data/Text/Internal/Functions.hs view
@@ -0,0 +1,29 @@+-- |+-- Module      : Data.Text.Internal.Functions+-- Copyright   : 2010 Bryan O'Sullivan+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- Useful functions.++module Data.Text.Internal.Functions+    (+      intersperse+    ) where++-- | A lazier version of Data.List.intersperse.  The other version+-- causes space leaks!+intersperse :: a -> [a] -> [a]+intersperse _   []     = []+intersperse sep (x:xs) = x : go xs+  where+    go []     = []+    go (y:ys) = sep : y: go ys+{-# INLINE intersperse #-}
+ src/Data/Text/Internal/Fusion.hs view
@@ -0,0 +1,244 @@+{-# LANGUAGE BangPatterns, MagicHash #-}++-- |+-- Module      : Data.Text.Internal.Fusion+-- Copyright   : (c) Tom Harper 2008-2009,+--               (c) Bryan O'Sullivan 2009-2010,+--               (c) Duncan Coutts 2009+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- Text manipulation functions represented as fusible operations over+-- streams.+module Data.Text.Internal.Fusion+    (+    -- * Types+      Stream(..)+    , Step(..)++    -- * Creation and elimination+    , stream+    , unstream+    , reverseStream++    , length++    -- * Transformations+    , reverse++    -- * Construction+    -- ** Scans+    , reverseScanr++    -- ** Accumulating maps+    , mapAccumL++    -- ** Generation and unfolding+    , unfoldrN++    -- * Indexing+    , index+    , findIndex+    , countChar+    ) where++import Prelude (Bool(..), Char, Maybe(..), Monad(..), Int,+                Num(..), Ord(..), ($), (&&),+                fromIntegral, otherwise)+import Data.Bits ((.&.))+import Data.Text.Internal (Text(..))+import Data.Text.Internal.Private (runText)+import Data.Text.Internal.Unsafe.Char (ord, unsafeChr, unsafeWrite)+import Data.Text.Internal.Unsafe.Shift (shiftL, shiftR)+import qualified Data.Text.Array as A+import qualified Data.Text.Internal.Fusion.Common as S+import Data.Text.Internal.Fusion.Types+import Data.Text.Internal.Fusion.Size+import qualified Data.Text.Internal as I+import qualified Data.Text.Internal.Encoding.Utf16 as U16++default(Int)++-- | /O(n)/ Convert a 'Text' into a 'Stream Char'.+stream :: Text -> Stream Char+stream (Text arr off len) = Stream next off (betweenSize (len `shiftR` 1) len)+    where+      !end = off+len+      next !i+          | i >= end                   = Done+          | n >= 0xD800 && n <= 0xDBFF = Yield (U16.chr2 n n2) (i + 2)+          | otherwise                  = Yield (unsafeChr n) (i + 1)+          where+            n  = A.unsafeIndex arr i+            n2 = A.unsafeIndex arr (i + 1)+{-# INLINE [0] stream #-}++-- | /O(n)/ Convert a 'Text' into a 'Stream Char', but iterate+-- backwards.+reverseStream :: Text -> Stream Char+reverseStream (Text arr off len) = Stream next (off+len-1) (betweenSize (len `shiftR` 1) len)+    where+      {-# INLINE next #-}+      next !i+          | i < off                    = Done+          | n >= 0xDC00 && n <= 0xDFFF = Yield (U16.chr2 n2 n) (i - 2)+          | otherwise                  = Yield (unsafeChr n) (i - 1)+          where+            n  = A.unsafeIndex arr i+            n2 = A.unsafeIndex arr (i - 1)+{-# INLINE [0] reverseStream #-}++-- | /O(n)/ Convert a 'Stream Char' into a 'Text'.+unstream :: Stream Char -> Text+unstream (Stream next0 s0 len) = runText $ \done -> do+  -- Before encoding each char we perform a buffer realloc check assuming+  -- worst case encoding size of two 16-bit units for the char. Just add an+  -- extra space to the buffer so that we do not end up reallocating even when+  -- all the chars are encoded as single unit.+  let mlen = upperBound 4 len + 1+  arr0 <- A.new mlen+  let outer !arr !maxi = encode+       where+        -- keep the common case loop as small as possible+        encode !si !di =+            case next0 si of+                Done        -> done arr di+                Skip si'    -> encode si' di+                Yield c si'+                    -- simply check for the worst case+                    | maxi < di + 1 -> realloc si di+                    | otherwise -> do+                            n <- unsafeWrite arr di c+                            encode si' (di + n)++        -- keep uncommon case separate from the common case code+        {-# NOINLINE realloc #-}+        realloc !si !di = do+            let newlen = (maxi + 1) * 2+            arr' <- A.new newlen+            A.copyM arr' 0 arr 0 di+            outer arr' (newlen - 1) si di++  outer arr0 (mlen - 1) s0 0+{-# INLINE [0] unstream #-}+{-# RULES "STREAM stream/unstream fusion" forall s. stream (unstream s) = s #-}+++-- ----------------------------------------------------------------------------+-- * Basic stream functions++length :: Stream Char -> Int+length = S.lengthI+{-# INLINE[0] length #-}++-- | /O(n)/ Reverse the characters of a string.+reverse :: Stream Char -> Text+reverse (Stream next s len0)+    | isEmpty len0 = I.empty+    | otherwise    = I.text arr off' len'+  where+    len0' = upperBound 4 (larger len0 4)+    (arr, (off', len')) = A.run2 (A.new len0' >>= loop s (len0'-1) len0')+    loop !s0 !i !len marr =+        case next s0 of+          Done -> return (marr, (j, len-j))+              where j = i + 1+          Skip s1    -> loop s1 i len marr+          Yield x s1 | i < least -> {-# SCC "reverse/resize" #-} do+                       let newLen = len `shiftL` 1+                       marr' <- A.new newLen+                       A.copyM marr' (newLen-len) marr 0 len+                       write s1 (len+i) newLen marr'+                     | otherwise -> write s1 i len marr+            where n = ord x+                  least | n < 0x10000 = 0+                        | otherwise   = 1+                  m = n - 0x10000+                  lo = fromIntegral $ (m `shiftR` 10) + 0xD800+                  hi = fromIntegral $ (m .&. 0x3FF) + 0xDC00+                  write t j l mar+                      | n < 0x10000 = do+                          A.unsafeWrite mar j (fromIntegral n)+                          loop t (j-1) l mar+                      | otherwise = do+                          A.unsafeWrite mar (j-1) lo+                          A.unsafeWrite mar j hi+                          loop t (j-2) l mar+{-# INLINE [0] reverse #-}++-- | /O(n)/ Perform the equivalent of 'scanr' over a list, only with+-- the input and result reversed.+reverseScanr :: (Char -> Char -> Char) -> Char -> Stream Char -> Stream Char+reverseScanr f z0 (Stream next0 s0 len) = Stream next (Scan1 z0 s0) (len+1) -- HINT maybe too low+  where+    {-# INLINE next #-}+    next (Scan1 z s) = Yield z (Scan2 z s)+    next (Scan2 z s) = case next0 s of+                         Yield x s' -> let !x' = f x z+                                       in Yield x' (Scan2 x' s')+                         Skip s'    -> Skip (Scan2 z s')+                         Done       -> Done+{-# INLINE reverseScanr #-}++-- | /O(n)/ Like 'unfoldr', 'unfoldrN' builds a stream from a seed+-- value. However, the length of the result is limited by the+-- first argument to 'unfoldrN'. This function is more efficient than+-- 'unfoldr' when the length of the result is known.+unfoldrN :: Int -> (a -> Maybe (Char,a)) -> a -> Stream Char+unfoldrN n = S.unfoldrNI n+{-# INLINE [0] unfoldrN #-}++-------------------------------------------------------------------------------+-- ** Indexing streams++-- | /O(n)/ stream index (subscript) operator, starting from 0.+index :: Stream Char -> Int -> Char+index = S.indexI+{-# INLINE [0] index #-}++-- | The 'findIndex' function takes a predicate and a stream and+-- returns the index of the first element in the stream+-- satisfying the predicate.+findIndex :: (Char -> Bool) -> Stream Char -> Maybe Int+findIndex = S.findIndexI+{-# INLINE [0] findIndex #-}++-- | /O(n)/ The 'count' function returns the number of times the query+-- element appears in the given stream.+countChar :: Char -> Stream Char -> Int+countChar = S.countCharI+{-# INLINE [0] countChar #-}++-- | /O(n)/ Like a combination of 'map' and 'foldl''. Applies a+-- function to each element of a 'Text', passing an accumulating+-- parameter from left to right, and returns a final 'Text'.+mapAccumL :: (a -> Char -> (a,Char)) -> a -> Stream Char -> (a, Text)+mapAccumL f z0 (Stream next0 s0 len) = (nz, I.text na 0 nl)+  where+    (na,(nz,nl)) = A.run2 (A.new mlen >>= \arr -> outer arr mlen z0 s0 0)+      where mlen = upperBound 4 len+    outer arr top = loop+      where+        loop !z !s !i =+            case next0 s of+              Done          -> return (arr, (z,i))+              Skip s'       -> loop z s' i+              Yield x s'+                | j >= top  -> {-# SCC "mapAccumL/resize" #-} do+                               let top' = (top + 1) `shiftL` 1+                               arr' <- A.new top'+                               A.copyM arr' 0 arr 0 top+                               outer arr' top' z s i+                | otherwise -> do d <- unsafeWrite arr i c+                                  loop z' s' (i+d)+                where (z',c) = f z x+                      j | ord c < 0x10000 = i+                        | otherwise       = i + 1+{-# INLINE [0] mapAccumL #-}
+ src/Data/Text/Internal/Fusion/CaseMapping.hs view
@@ -0,0 +1,1002 @@+{-# LANGUAGE Rank2Types #-}+-- AUTOMATICALLY GENERATED - DO NOT EDIT+-- Generated by scripts/CaseMapping.hs+-- CaseFolding-9.0.0.txt+-- Date: 2016-03-02, 18:54:54 GMT+-- SpecialCasing-9.0.0.txt+-- Date: 2016-03-02, 18:55:13 GMT++module Data.Text.Internal.Fusion.CaseMapping where+import Data.Char+import Data.Text.Internal.Fusion.Types++upperMapping :: forall s. Char -> s -> Step (CC s) Char+{-# NOINLINE upperMapping #-}+-- LATIN SMALL LETTER SHARP S+upperMapping '\x00df' s = Yield '\x0053' (CC s '\x0053' '\x0000')+-- LATIN SMALL LIGATURE FF+upperMapping '\xfb00' s = Yield '\x0046' (CC s '\x0046' '\x0000')+-- LATIN SMALL LIGATURE FI+upperMapping '\xfb01' s = Yield '\x0046' (CC s '\x0049' '\x0000')+-- LATIN SMALL LIGATURE FL+upperMapping '\xfb02' s = Yield '\x0046' (CC s '\x004c' '\x0000')+-- LATIN SMALL LIGATURE FFI+upperMapping '\xfb03' s = Yield '\x0046' (CC s '\x0046' '\x0049')+-- LATIN SMALL LIGATURE FFL+upperMapping '\xfb04' s = Yield '\x0046' (CC s '\x0046' '\x004c')+-- LATIN SMALL LIGATURE LONG S T+upperMapping '\xfb05' s = Yield '\x0053' (CC s '\x0054' '\x0000')+-- LATIN SMALL LIGATURE ST+upperMapping '\xfb06' s = Yield '\x0053' (CC s '\x0054' '\x0000')+-- ARMENIAN SMALL LIGATURE ECH YIWN+upperMapping '\x0587' s = Yield '\x0535' (CC s '\x0552' '\x0000')+-- ARMENIAN SMALL LIGATURE MEN NOW+upperMapping '\xfb13' s = Yield '\x0544' (CC s '\x0546' '\x0000')+-- ARMENIAN SMALL LIGATURE MEN ECH+upperMapping '\xfb14' s = Yield '\x0544' (CC s '\x0535' '\x0000')+-- ARMENIAN SMALL LIGATURE MEN INI+upperMapping '\xfb15' s = Yield '\x0544' (CC s '\x053b' '\x0000')+-- ARMENIAN SMALL LIGATURE VEW NOW+upperMapping '\xfb16' s = Yield '\x054e' (CC s '\x0546' '\x0000')+-- ARMENIAN SMALL LIGATURE MEN XEH+upperMapping '\xfb17' s = Yield '\x0544' (CC s '\x053d' '\x0000')+-- LATIN SMALL LETTER N PRECEDED BY APOSTROPHE+upperMapping '\x0149' s = Yield '\x02bc' (CC s '\x004e' '\x0000')+-- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS+upperMapping '\x0390' s = Yield '\x0399' (CC s '\x0308' '\x0301')+-- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS+upperMapping '\x03b0' s = Yield '\x03a5' (CC s '\x0308' '\x0301')+-- LATIN SMALL LETTER J WITH CARON+upperMapping '\x01f0' s = Yield '\x004a' (CC s '\x030c' '\x0000')+-- LATIN SMALL LETTER H WITH LINE BELOW+upperMapping '\x1e96' s = Yield '\x0048' (CC s '\x0331' '\x0000')+-- LATIN SMALL LETTER T WITH DIAERESIS+upperMapping '\x1e97' s = Yield '\x0054' (CC s '\x0308' '\x0000')+-- LATIN SMALL LETTER W WITH RING ABOVE+upperMapping '\x1e98' s = Yield '\x0057' (CC s '\x030a' '\x0000')+-- LATIN SMALL LETTER Y WITH RING ABOVE+upperMapping '\x1e99' s = Yield '\x0059' (CC s '\x030a' '\x0000')+-- LATIN SMALL LETTER A WITH RIGHT HALF RING+upperMapping '\x1e9a' s = Yield '\x0041' (CC s '\x02be' '\x0000')+-- GREEK SMALL LETTER UPSILON WITH PSILI+upperMapping '\x1f50' s = Yield '\x03a5' (CC s '\x0313' '\x0000')+-- GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA+upperMapping '\x1f52' s = Yield '\x03a5' (CC s '\x0313' '\x0300')+-- GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA+upperMapping '\x1f54' s = Yield '\x03a5' (CC s '\x0313' '\x0301')+-- GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI+upperMapping '\x1f56' s = Yield '\x03a5' (CC s '\x0313' '\x0342')+-- GREEK SMALL LETTER ALPHA WITH PERISPOMENI+upperMapping '\x1fb6' s = Yield '\x0391' (CC s '\x0342' '\x0000')+-- GREEK SMALL LETTER ETA WITH PERISPOMENI+upperMapping '\x1fc6' s = Yield '\x0397' (CC s '\x0342' '\x0000')+-- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA+upperMapping '\x1fd2' s = Yield '\x0399' (CC s '\x0308' '\x0300')+-- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA+upperMapping '\x1fd3' s = Yield '\x0399' (CC s '\x0308' '\x0301')+-- GREEK SMALL LETTER IOTA WITH PERISPOMENI+upperMapping '\x1fd6' s = Yield '\x0399' (CC s '\x0342' '\x0000')+-- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI+upperMapping '\x1fd7' s = Yield '\x0399' (CC s '\x0308' '\x0342')+-- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA+upperMapping '\x1fe2' s = Yield '\x03a5' (CC s '\x0308' '\x0300')+-- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA+upperMapping '\x1fe3' s = Yield '\x03a5' (CC s '\x0308' '\x0301')+-- GREEK SMALL LETTER RHO WITH PSILI+upperMapping '\x1fe4' s = Yield '\x03a1' (CC s '\x0313' '\x0000')+-- GREEK SMALL LETTER UPSILON WITH PERISPOMENI+upperMapping '\x1fe6' s = Yield '\x03a5' (CC s '\x0342' '\x0000')+-- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI+upperMapping '\x1fe7' s = Yield '\x03a5' (CC s '\x0308' '\x0342')+-- GREEK SMALL LETTER OMEGA WITH PERISPOMENI+upperMapping '\x1ff6' s = Yield '\x03a9' (CC s '\x0342' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI+upperMapping '\x1f80' s = Yield '\x1f08' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI+upperMapping '\x1f81' s = Yield '\x1f09' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI+upperMapping '\x1f82' s = Yield '\x1f0a' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI+upperMapping '\x1f83' s = Yield '\x1f0b' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI+upperMapping '\x1f84' s = Yield '\x1f0c' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI+upperMapping '\x1f85' s = Yield '\x1f0d' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI+upperMapping '\x1f86' s = Yield '\x1f0e' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI+upperMapping '\x1f87' s = Yield '\x1f0f' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI+upperMapping '\x1f88' s = Yield '\x1f08' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI+upperMapping '\x1f89' s = Yield '\x1f09' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI+upperMapping '\x1f8a' s = Yield '\x1f0a' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI+upperMapping '\x1f8b' s = Yield '\x1f0b' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI+upperMapping '\x1f8c' s = Yield '\x1f0c' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI+upperMapping '\x1f8d' s = Yield '\x1f0d' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI+upperMapping '\x1f8e' s = Yield '\x1f0e' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI+upperMapping '\x1f8f' s = Yield '\x1f0f' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI+upperMapping '\x1f90' s = Yield '\x1f28' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI+upperMapping '\x1f91' s = Yield '\x1f29' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI+upperMapping '\x1f92' s = Yield '\x1f2a' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI+upperMapping '\x1f93' s = Yield '\x1f2b' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI+upperMapping '\x1f94' s = Yield '\x1f2c' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI+upperMapping '\x1f95' s = Yield '\x1f2d' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI+upperMapping '\x1f96' s = Yield '\x1f2e' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI+upperMapping '\x1f97' s = Yield '\x1f2f' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI+upperMapping '\x1f98' s = Yield '\x1f28' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI+upperMapping '\x1f99' s = Yield '\x1f29' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI+upperMapping '\x1f9a' s = Yield '\x1f2a' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI+upperMapping '\x1f9b' s = Yield '\x1f2b' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI+upperMapping '\x1f9c' s = Yield '\x1f2c' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI+upperMapping '\x1f9d' s = Yield '\x1f2d' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI+upperMapping '\x1f9e' s = Yield '\x1f2e' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI+upperMapping '\x1f9f' s = Yield '\x1f2f' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI+upperMapping '\x1fa0' s = Yield '\x1f68' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI+upperMapping '\x1fa1' s = Yield '\x1f69' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI+upperMapping '\x1fa2' s = Yield '\x1f6a' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI+upperMapping '\x1fa3' s = Yield '\x1f6b' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI+upperMapping '\x1fa4' s = Yield '\x1f6c' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI+upperMapping '\x1fa5' s = Yield '\x1f6d' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI+upperMapping '\x1fa6' s = Yield '\x1f6e' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI+upperMapping '\x1fa7' s = Yield '\x1f6f' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI+upperMapping '\x1fa8' s = Yield '\x1f68' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI+upperMapping '\x1fa9' s = Yield '\x1f69' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI+upperMapping '\x1faa' s = Yield '\x1f6a' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI+upperMapping '\x1fab' s = Yield '\x1f6b' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI+upperMapping '\x1fac' s = Yield '\x1f6c' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI+upperMapping '\x1fad' s = Yield '\x1f6d' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI+upperMapping '\x1fae' s = Yield '\x1f6e' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI+upperMapping '\x1faf' s = Yield '\x1f6f' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI+upperMapping '\x1fb3' s = Yield '\x0391' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI+upperMapping '\x1fbc' s = Yield '\x0391' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI+upperMapping '\x1fc3' s = Yield '\x0397' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI+upperMapping '\x1fcc' s = Yield '\x0397' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI+upperMapping '\x1ff3' s = Yield '\x03a9' (CC s '\x0399' '\x0000')+-- GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI+upperMapping '\x1ffc' s = Yield '\x03a9' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI+upperMapping '\x1fb2' s = Yield '\x1fba' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI+upperMapping '\x1fb4' s = Yield '\x0386' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI+upperMapping '\x1fc2' s = Yield '\x1fca' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI+upperMapping '\x1fc4' s = Yield '\x0389' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI+upperMapping '\x1ff2' s = Yield '\x1ffa' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI+upperMapping '\x1ff4' s = Yield '\x038f' (CC s '\x0399' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI+upperMapping '\x1fb7' s = Yield '\x0391' (CC s '\x0342' '\x0399')+-- GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI+upperMapping '\x1fc7' s = Yield '\x0397' (CC s '\x0342' '\x0399')+-- GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI+upperMapping '\x1ff7' s = Yield '\x03a9' (CC s '\x0342' '\x0399')+upperMapping c s = Yield (toUpper c) (CC s '\0' '\0')+lowerMapping :: forall s. Char -> s -> Step (CC s) Char+{-# NOINLINE lowerMapping #-}+-- LATIN CAPITAL LETTER I WITH DOT ABOVE+lowerMapping '\x0130' s = Yield '\x0069' (CC s '\x0307' '\x0000')+lowerMapping c s = Yield (toLower c) (CC s '\0' '\0')+titleMapping :: forall s. Char -> s -> Step (CC s) Char+{-# NOINLINE titleMapping #-}+-- LATIN SMALL LETTER SHARP S+titleMapping '\x00df' s = Yield '\x0053' (CC s '\x0073' '\x0000')+-- LATIN SMALL LIGATURE FF+titleMapping '\xfb00' s = Yield '\x0046' (CC s '\x0066' '\x0000')+-- LATIN SMALL LIGATURE FI+titleMapping '\xfb01' s = Yield '\x0046' (CC s '\x0069' '\x0000')+-- LATIN SMALL LIGATURE FL+titleMapping '\xfb02' s = Yield '\x0046' (CC s '\x006c' '\x0000')+-- LATIN SMALL LIGATURE FFI+titleMapping '\xfb03' s = Yield '\x0046' (CC s '\x0066' '\x0069')+-- LATIN SMALL LIGATURE FFL+titleMapping '\xfb04' s = Yield '\x0046' (CC s '\x0066' '\x006c')+-- LATIN SMALL LIGATURE LONG S T+titleMapping '\xfb05' s = Yield '\x0053' (CC s '\x0074' '\x0000')+-- LATIN SMALL LIGATURE ST+titleMapping '\xfb06' s = Yield '\x0053' (CC s '\x0074' '\x0000')+-- ARMENIAN SMALL LIGATURE ECH YIWN+titleMapping '\x0587' s = Yield '\x0535' (CC s '\x0582' '\x0000')+-- ARMENIAN SMALL LIGATURE MEN NOW+titleMapping '\xfb13' s = Yield '\x0544' (CC s '\x0576' '\x0000')+-- ARMENIAN SMALL LIGATURE MEN ECH+titleMapping '\xfb14' s = Yield '\x0544' (CC s '\x0565' '\x0000')+-- ARMENIAN SMALL LIGATURE MEN INI+titleMapping '\xfb15' s = Yield '\x0544' (CC s '\x056b' '\x0000')+-- ARMENIAN SMALL LIGATURE VEW NOW+titleMapping '\xfb16' s = Yield '\x054e' (CC s '\x0576' '\x0000')+-- ARMENIAN SMALL LIGATURE MEN XEH+titleMapping '\xfb17' s = Yield '\x0544' (CC s '\x056d' '\x0000')+-- LATIN SMALL LETTER N PRECEDED BY APOSTROPHE+titleMapping '\x0149' s = Yield '\x02bc' (CC s '\x004e' '\x0000')+-- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS+titleMapping '\x0390' s = Yield '\x0399' (CC s '\x0308' '\x0301')+-- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS+titleMapping '\x03b0' s = Yield '\x03a5' (CC s '\x0308' '\x0301')+-- LATIN SMALL LETTER J WITH CARON+titleMapping '\x01f0' s = Yield '\x004a' (CC s '\x030c' '\x0000')+-- LATIN SMALL LETTER H WITH LINE BELOW+titleMapping '\x1e96' s = Yield '\x0048' (CC s '\x0331' '\x0000')+-- LATIN SMALL LETTER T WITH DIAERESIS+titleMapping '\x1e97' s = Yield '\x0054' (CC s '\x0308' '\x0000')+-- LATIN SMALL LETTER W WITH RING ABOVE+titleMapping '\x1e98' s = Yield '\x0057' (CC s '\x030a' '\x0000')+-- LATIN SMALL LETTER Y WITH RING ABOVE+titleMapping '\x1e99' s = Yield '\x0059' (CC s '\x030a' '\x0000')+-- LATIN SMALL LETTER A WITH RIGHT HALF RING+titleMapping '\x1e9a' s = Yield '\x0041' (CC s '\x02be' '\x0000')+-- GREEK SMALL LETTER UPSILON WITH PSILI+titleMapping '\x1f50' s = Yield '\x03a5' (CC s '\x0313' '\x0000')+-- GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA+titleMapping '\x1f52' s = Yield '\x03a5' (CC s '\x0313' '\x0300')+-- GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA+titleMapping '\x1f54' s = Yield '\x03a5' (CC s '\x0313' '\x0301')+-- GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI+titleMapping '\x1f56' s = Yield '\x03a5' (CC s '\x0313' '\x0342')+-- GREEK SMALL LETTER ALPHA WITH PERISPOMENI+titleMapping '\x1fb6' s = Yield '\x0391' (CC s '\x0342' '\x0000')+-- GREEK SMALL LETTER ETA WITH PERISPOMENI+titleMapping '\x1fc6' s = Yield '\x0397' (CC s '\x0342' '\x0000')+-- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA+titleMapping '\x1fd2' s = Yield '\x0399' (CC s '\x0308' '\x0300')+-- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA+titleMapping '\x1fd3' s = Yield '\x0399' (CC s '\x0308' '\x0301')+-- GREEK SMALL LETTER IOTA WITH PERISPOMENI+titleMapping '\x1fd6' s = Yield '\x0399' (CC s '\x0342' '\x0000')+-- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI+titleMapping '\x1fd7' s = Yield '\x0399' (CC s '\x0308' '\x0342')+-- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA+titleMapping '\x1fe2' s = Yield '\x03a5' (CC s '\x0308' '\x0300')+-- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA+titleMapping '\x1fe3' s = Yield '\x03a5' (CC s '\x0308' '\x0301')+-- GREEK SMALL LETTER RHO WITH PSILI+titleMapping '\x1fe4' s = Yield '\x03a1' (CC s '\x0313' '\x0000')+-- GREEK SMALL LETTER UPSILON WITH PERISPOMENI+titleMapping '\x1fe6' s = Yield '\x03a5' (CC s '\x0342' '\x0000')+-- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI+titleMapping '\x1fe7' s = Yield '\x03a5' (CC s '\x0308' '\x0342')+-- GREEK SMALL LETTER OMEGA WITH PERISPOMENI+titleMapping '\x1ff6' s = Yield '\x03a9' (CC s '\x0342' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI+titleMapping '\x1fb2' s = Yield '\x1fba' (CC s '\x0345' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI+titleMapping '\x1fb4' s = Yield '\x0386' (CC s '\x0345' '\x0000')+-- GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI+titleMapping '\x1fc2' s = Yield '\x1fca' (CC s '\x0345' '\x0000')+-- GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI+titleMapping '\x1fc4' s = Yield '\x0389' (CC s '\x0345' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI+titleMapping '\x1ff2' s = Yield '\x1ffa' (CC s '\x0345' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI+titleMapping '\x1ff4' s = Yield '\x038f' (CC s '\x0345' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI+titleMapping '\x1fb7' s = Yield '\x0391' (CC s '\x0342' '\x0345')+-- GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI+titleMapping '\x1fc7' s = Yield '\x0397' (CC s '\x0342' '\x0345')+-- GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI+titleMapping '\x1ff7' s = Yield '\x03a9' (CC s '\x0342' '\x0345')+titleMapping c s = Yield (toTitle c) (CC s '\0' '\0')+foldMapping :: forall s. Char -> s -> Step (CC s) Char+{-# NOINLINE foldMapping #-}+-- MICRO SIGN+foldMapping '\x00b5' s = Yield '\x03bc' (CC s '\x0000' '\x0000')+-- LATIN SMALL LETTER SHARP S+foldMapping '\x00df' s = Yield '\x0073' (CC s '\x0073' '\x0000')+-- LATIN CAPITAL LETTER I WITH DOT ABOVE+foldMapping '\x0130' s = Yield '\x0069' (CC s '\x0307' '\x0000')+-- LATIN SMALL LETTER N PRECEDED BY APOSTROPHE+foldMapping '\x0149' s = Yield '\x02bc' (CC s '\x006e' '\x0000')+-- LATIN SMALL LETTER LONG S+foldMapping '\x017f' s = Yield '\x0073' (CC s '\x0000' '\x0000')+-- LATIN SMALL LETTER J WITH CARON+foldMapping '\x01f0' s = Yield '\x006a' (CC s '\x030c' '\x0000')+-- COMBINING GREEK YPOGEGRAMMENI+foldMapping '\x0345' s = Yield '\x03b9' (CC s '\x0000' '\x0000')+-- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS+foldMapping '\x0390' s = Yield '\x03b9' (CC s '\x0308' '\x0301')+-- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS+foldMapping '\x03b0' s = Yield '\x03c5' (CC s '\x0308' '\x0301')+-- GREEK SMALL LETTER FINAL SIGMA+foldMapping '\x03c2' s = Yield '\x03c3' (CC s '\x0000' '\x0000')+-- GREEK BETA SYMBOL+foldMapping '\x03d0' s = Yield '\x03b2' (CC s '\x0000' '\x0000')+-- GREEK THETA SYMBOL+foldMapping '\x03d1' s = Yield '\x03b8' (CC s '\x0000' '\x0000')+-- GREEK PHI SYMBOL+foldMapping '\x03d5' s = Yield '\x03c6' (CC s '\x0000' '\x0000')+-- GREEK PI SYMBOL+foldMapping '\x03d6' s = Yield '\x03c0' (CC s '\x0000' '\x0000')+-- GREEK KAPPA SYMBOL+foldMapping '\x03f0' s = Yield '\x03ba' (CC s '\x0000' '\x0000')+-- GREEK RHO SYMBOL+foldMapping '\x03f1' s = Yield '\x03c1' (CC s '\x0000' '\x0000')+-- GREEK LUNATE EPSILON SYMBOL+foldMapping '\x03f5' s = Yield '\x03b5' (CC s '\x0000' '\x0000')+-- ARMENIAN SMALL LIGATURE ECH YIWN+foldMapping '\x0587' s = Yield '\x0565' (CC s '\x0582' '\x0000')+-- CHEROKEE SMALL LETTER YE+foldMapping '\x13f8' s = Yield '\x13f0' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER YI+foldMapping '\x13f9' s = Yield '\x13f1' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER YO+foldMapping '\x13fa' s = Yield '\x13f2' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER YU+foldMapping '\x13fb' s = Yield '\x13f3' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER YV+foldMapping '\x13fc' s = Yield '\x13f4' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER MV+foldMapping '\x13fd' s = Yield '\x13f5' (CC s '\x0000' '\x0000')+-- CYRILLIC SMALL LETTER ROUNDED VE+foldMapping '\x1c80' s = Yield '\x0432' (CC s '\x0000' '\x0000')+-- CYRILLIC SMALL LETTER LONG-LEGGED DE+foldMapping '\x1c81' s = Yield '\x0434' (CC s '\x0000' '\x0000')+-- CYRILLIC SMALL LETTER NARROW O+foldMapping '\x1c82' s = Yield '\x043e' (CC s '\x0000' '\x0000')+-- CYRILLIC SMALL LETTER WIDE ES+foldMapping '\x1c83' s = Yield '\x0441' (CC s '\x0000' '\x0000')+-- CYRILLIC SMALL LETTER TALL TE+foldMapping '\x1c84' s = Yield '\x0442' (CC s '\x0000' '\x0000')+-- CYRILLIC SMALL LETTER THREE-LEGGED TE+foldMapping '\x1c85' s = Yield '\x0442' (CC s '\x0000' '\x0000')+-- CYRILLIC SMALL LETTER TALL HARD SIGN+foldMapping '\x1c86' s = Yield '\x044a' (CC s '\x0000' '\x0000')+-- CYRILLIC SMALL LETTER TALL YAT+foldMapping '\x1c87' s = Yield '\x0463' (CC s '\x0000' '\x0000')+-- CYRILLIC SMALL LETTER UNBLENDED UK+foldMapping '\x1c88' s = Yield '\xa64b' (CC s '\x0000' '\x0000')+-- LATIN SMALL LETTER H WITH LINE BELOW+foldMapping '\x1e96' s = Yield '\x0068' (CC s '\x0331' '\x0000')+-- LATIN SMALL LETTER T WITH DIAERESIS+foldMapping '\x1e97' s = Yield '\x0074' (CC s '\x0308' '\x0000')+-- LATIN SMALL LETTER W WITH RING ABOVE+foldMapping '\x1e98' s = Yield '\x0077' (CC s '\x030a' '\x0000')+-- LATIN SMALL LETTER Y WITH RING ABOVE+foldMapping '\x1e99' s = Yield '\x0079' (CC s '\x030a' '\x0000')+-- LATIN SMALL LETTER A WITH RIGHT HALF RING+foldMapping '\x1e9a' s = Yield '\x0061' (CC s '\x02be' '\x0000')+-- LATIN SMALL LETTER LONG S WITH DOT ABOVE+foldMapping '\x1e9b' s = Yield '\x1e61' (CC s '\x0000' '\x0000')+-- LATIN CAPITAL LETTER SHARP S+foldMapping '\x1e9e' s = Yield '\x0073' (CC s '\x0073' '\x0000')+-- GREEK SMALL LETTER UPSILON WITH PSILI+foldMapping '\x1f50' s = Yield '\x03c5' (CC s '\x0313' '\x0000')+-- GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA+foldMapping '\x1f52' s = Yield '\x03c5' (CC s '\x0313' '\x0300')+-- GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA+foldMapping '\x1f54' s = Yield '\x03c5' (CC s '\x0313' '\x0301')+-- GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI+foldMapping '\x1f56' s = Yield '\x03c5' (CC s '\x0313' '\x0342')+-- GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI+foldMapping '\x1f80' s = Yield '\x1f00' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI+foldMapping '\x1f81' s = Yield '\x1f01' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI+foldMapping '\x1f82' s = Yield '\x1f02' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI+foldMapping '\x1f83' s = Yield '\x1f03' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI+foldMapping '\x1f84' s = Yield '\x1f04' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI+foldMapping '\x1f85' s = Yield '\x1f05' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI+foldMapping '\x1f86' s = Yield '\x1f06' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI+foldMapping '\x1f87' s = Yield '\x1f07' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI+foldMapping '\x1f88' s = Yield '\x1f00' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI+foldMapping '\x1f89' s = Yield '\x1f01' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI+foldMapping '\x1f8a' s = Yield '\x1f02' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI+foldMapping '\x1f8b' s = Yield '\x1f03' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI+foldMapping '\x1f8c' s = Yield '\x1f04' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI+foldMapping '\x1f8d' s = Yield '\x1f05' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI+foldMapping '\x1f8e' s = Yield '\x1f06' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI+foldMapping '\x1f8f' s = Yield '\x1f07' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI+foldMapping '\x1f90' s = Yield '\x1f20' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI+foldMapping '\x1f91' s = Yield '\x1f21' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI+foldMapping '\x1f92' s = Yield '\x1f22' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI+foldMapping '\x1f93' s = Yield '\x1f23' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI+foldMapping '\x1f94' s = Yield '\x1f24' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI+foldMapping '\x1f95' s = Yield '\x1f25' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI+foldMapping '\x1f96' s = Yield '\x1f26' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI+foldMapping '\x1f97' s = Yield '\x1f27' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI+foldMapping '\x1f98' s = Yield '\x1f20' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI+foldMapping '\x1f99' s = Yield '\x1f21' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI+foldMapping '\x1f9a' s = Yield '\x1f22' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI+foldMapping '\x1f9b' s = Yield '\x1f23' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI+foldMapping '\x1f9c' s = Yield '\x1f24' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI+foldMapping '\x1f9d' s = Yield '\x1f25' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI+foldMapping '\x1f9e' s = Yield '\x1f26' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI+foldMapping '\x1f9f' s = Yield '\x1f27' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI+foldMapping '\x1fa0' s = Yield '\x1f60' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI+foldMapping '\x1fa1' s = Yield '\x1f61' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI+foldMapping '\x1fa2' s = Yield '\x1f62' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI+foldMapping '\x1fa3' s = Yield '\x1f63' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI+foldMapping '\x1fa4' s = Yield '\x1f64' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI+foldMapping '\x1fa5' s = Yield '\x1f65' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI+foldMapping '\x1fa6' s = Yield '\x1f66' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI+foldMapping '\x1fa7' s = Yield '\x1f67' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI+foldMapping '\x1fa8' s = Yield '\x1f60' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI+foldMapping '\x1fa9' s = Yield '\x1f61' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI+foldMapping '\x1faa' s = Yield '\x1f62' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI+foldMapping '\x1fab' s = Yield '\x1f63' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI+foldMapping '\x1fac' s = Yield '\x1f64' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI+foldMapping '\x1fad' s = Yield '\x1f65' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI+foldMapping '\x1fae' s = Yield '\x1f66' (CC s '\x03b9' '\x0000')+-- GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI+foldMapping '\x1faf' s = Yield '\x1f67' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI+foldMapping '\x1fb2' s = Yield '\x1f70' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI+foldMapping '\x1fb3' s = Yield '\x03b1' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI+foldMapping '\x1fb4' s = Yield '\x03ac' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH PERISPOMENI+foldMapping '\x1fb6' s = Yield '\x03b1' (CC s '\x0342' '\x0000')+-- GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI+foldMapping '\x1fb7' s = Yield '\x03b1' (CC s '\x0342' '\x03b9')+-- GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI+foldMapping '\x1fbc' s = Yield '\x03b1' (CC s '\x03b9' '\x0000')+-- GREEK PROSGEGRAMMENI+foldMapping '\x1fbe' s = Yield '\x03b9' (CC s '\x0000' '\x0000')+-- GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI+foldMapping '\x1fc2' s = Yield '\x1f74' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI+foldMapping '\x1fc3' s = Yield '\x03b7' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI+foldMapping '\x1fc4' s = Yield '\x03ae' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER ETA WITH PERISPOMENI+foldMapping '\x1fc6' s = Yield '\x03b7' (CC s '\x0342' '\x0000')+-- GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI+foldMapping '\x1fc7' s = Yield '\x03b7' (CC s '\x0342' '\x03b9')+-- GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI+foldMapping '\x1fcc' s = Yield '\x03b7' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA+foldMapping '\x1fd2' s = Yield '\x03b9' (CC s '\x0308' '\x0300')+-- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA+foldMapping '\x1fd3' s = Yield '\x03b9' (CC s '\x0308' '\x0301')+-- GREEK SMALL LETTER IOTA WITH PERISPOMENI+foldMapping '\x1fd6' s = Yield '\x03b9' (CC s '\x0342' '\x0000')+-- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI+foldMapping '\x1fd7' s = Yield '\x03b9' (CC s '\x0308' '\x0342')+-- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA+foldMapping '\x1fe2' s = Yield '\x03c5' (CC s '\x0308' '\x0300')+-- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA+foldMapping '\x1fe3' s = Yield '\x03c5' (CC s '\x0308' '\x0301')+-- GREEK SMALL LETTER RHO WITH PSILI+foldMapping '\x1fe4' s = Yield '\x03c1' (CC s '\x0313' '\x0000')+-- GREEK SMALL LETTER UPSILON WITH PERISPOMENI+foldMapping '\x1fe6' s = Yield '\x03c5' (CC s '\x0342' '\x0000')+-- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI+foldMapping '\x1fe7' s = Yield '\x03c5' (CC s '\x0308' '\x0342')+-- GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI+foldMapping '\x1ff2' s = Yield '\x1f7c' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI+foldMapping '\x1ff3' s = Yield '\x03c9' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI+foldMapping '\x1ff4' s = Yield '\x03ce' (CC s '\x03b9' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH PERISPOMENI+foldMapping '\x1ff6' s = Yield '\x03c9' (CC s '\x0342' '\x0000')+-- GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI+foldMapping '\x1ff7' s = Yield '\x03c9' (CC s '\x0342' '\x03b9')+-- GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI+foldMapping '\x1ffc' s = Yield '\x03c9' (CC s '\x03b9' '\x0000')+-- LATIN CAPITAL LETTER SMALL CAPITAL I+foldMapping '\xa7ae' s = Yield '\x026a' (CC s '\x0000' '\x0000')+-- LATIN CAPITAL LETTER J WITH CROSSED-TAIL+foldMapping '\xa7b2' s = Yield '\x029d' (CC s '\x0000' '\x0000')+-- LATIN CAPITAL LETTER CHI+foldMapping '\xa7b3' s = Yield '\xab53' (CC s '\x0000' '\x0000')+-- LATIN CAPITAL LETTER BETA+foldMapping '\xa7b4' s = Yield '\xa7b5' (CC s '\x0000' '\x0000')+-- LATIN CAPITAL LETTER OMEGA+foldMapping '\xa7b6' s = Yield '\xa7b7' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER A+foldMapping '\xab70' s = Yield '\x13a0' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER E+foldMapping '\xab71' s = Yield '\x13a1' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER I+foldMapping '\xab72' s = Yield '\x13a2' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER O+foldMapping '\xab73' s = Yield '\x13a3' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER U+foldMapping '\xab74' s = Yield '\x13a4' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER V+foldMapping '\xab75' s = Yield '\x13a5' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER GA+foldMapping '\xab76' s = Yield '\x13a6' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER KA+foldMapping '\xab77' s = Yield '\x13a7' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER GE+foldMapping '\xab78' s = Yield '\x13a8' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER GI+foldMapping '\xab79' s = Yield '\x13a9' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER GO+foldMapping '\xab7a' s = Yield '\x13aa' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER GU+foldMapping '\xab7b' s = Yield '\x13ab' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER GV+foldMapping '\xab7c' s = Yield '\x13ac' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER HA+foldMapping '\xab7d' s = Yield '\x13ad' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER HE+foldMapping '\xab7e' s = Yield '\x13ae' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER HI+foldMapping '\xab7f' s = Yield '\x13af' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER HO+foldMapping '\xab80' s = Yield '\x13b0' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER HU+foldMapping '\xab81' s = Yield '\x13b1' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER HV+foldMapping '\xab82' s = Yield '\x13b2' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER LA+foldMapping '\xab83' s = Yield '\x13b3' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER LE+foldMapping '\xab84' s = Yield '\x13b4' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER LI+foldMapping '\xab85' s = Yield '\x13b5' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER LO+foldMapping '\xab86' s = Yield '\x13b6' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER LU+foldMapping '\xab87' s = Yield '\x13b7' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER LV+foldMapping '\xab88' s = Yield '\x13b8' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER MA+foldMapping '\xab89' s = Yield '\x13b9' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER ME+foldMapping '\xab8a' s = Yield '\x13ba' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER MI+foldMapping '\xab8b' s = Yield '\x13bb' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER MO+foldMapping '\xab8c' s = Yield '\x13bc' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER MU+foldMapping '\xab8d' s = Yield '\x13bd' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER NA+foldMapping '\xab8e' s = Yield '\x13be' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER HNA+foldMapping '\xab8f' s = Yield '\x13bf' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER NAH+foldMapping '\xab90' s = Yield '\x13c0' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER NE+foldMapping '\xab91' s = Yield '\x13c1' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER NI+foldMapping '\xab92' s = Yield '\x13c2' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER NO+foldMapping '\xab93' s = Yield '\x13c3' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER NU+foldMapping '\xab94' s = Yield '\x13c4' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER NV+foldMapping '\xab95' s = Yield '\x13c5' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER QUA+foldMapping '\xab96' s = Yield '\x13c6' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER QUE+foldMapping '\xab97' s = Yield '\x13c7' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER QUI+foldMapping '\xab98' s = Yield '\x13c8' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER QUO+foldMapping '\xab99' s = Yield '\x13c9' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER QUU+foldMapping '\xab9a' s = Yield '\x13ca' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER QUV+foldMapping '\xab9b' s = Yield '\x13cb' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER SA+foldMapping '\xab9c' s = Yield '\x13cc' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER S+foldMapping '\xab9d' s = Yield '\x13cd' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER SE+foldMapping '\xab9e' s = Yield '\x13ce' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER SI+foldMapping '\xab9f' s = Yield '\x13cf' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER SO+foldMapping '\xaba0' s = Yield '\x13d0' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER SU+foldMapping '\xaba1' s = Yield '\x13d1' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER SV+foldMapping '\xaba2' s = Yield '\x13d2' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER DA+foldMapping '\xaba3' s = Yield '\x13d3' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER TA+foldMapping '\xaba4' s = Yield '\x13d4' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER DE+foldMapping '\xaba5' s = Yield '\x13d5' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER TE+foldMapping '\xaba6' s = Yield '\x13d6' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER DI+foldMapping '\xaba7' s = Yield '\x13d7' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER TI+foldMapping '\xaba8' s = Yield '\x13d8' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER DO+foldMapping '\xaba9' s = Yield '\x13d9' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER DU+foldMapping '\xabaa' s = Yield '\x13da' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER DV+foldMapping '\xabab' s = Yield '\x13db' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER DLA+foldMapping '\xabac' s = Yield '\x13dc' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER TLA+foldMapping '\xabad' s = Yield '\x13dd' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER TLE+foldMapping '\xabae' s = Yield '\x13de' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER TLI+foldMapping '\xabaf' s = Yield '\x13df' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER TLO+foldMapping '\xabb0' s = Yield '\x13e0' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER TLU+foldMapping '\xabb1' s = Yield '\x13e1' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER TLV+foldMapping '\xabb2' s = Yield '\x13e2' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER TSA+foldMapping '\xabb3' s = Yield '\x13e3' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER TSE+foldMapping '\xabb4' s = Yield '\x13e4' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER TSI+foldMapping '\xabb5' s = Yield '\x13e5' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER TSO+foldMapping '\xabb6' s = Yield '\x13e6' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER TSU+foldMapping '\xabb7' s = Yield '\x13e7' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER TSV+foldMapping '\xabb8' s = Yield '\x13e8' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER WA+foldMapping '\xabb9' s = Yield '\x13e9' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER WE+foldMapping '\xabba' s = Yield '\x13ea' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER WI+foldMapping '\xabbb' s = Yield '\x13eb' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER WO+foldMapping '\xabbc' s = Yield '\x13ec' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER WU+foldMapping '\xabbd' s = Yield '\x13ed' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER WV+foldMapping '\xabbe' s = Yield '\x13ee' (CC s '\x0000' '\x0000')+-- CHEROKEE SMALL LETTER YA+foldMapping '\xabbf' s = Yield '\x13ef' (CC s '\x0000' '\x0000')+-- LATIN SMALL LIGATURE FF+foldMapping '\xfb00' s = Yield '\x0066' (CC s '\x0066' '\x0000')+-- LATIN SMALL LIGATURE FI+foldMapping '\xfb01' s = Yield '\x0066' (CC s '\x0069' '\x0000')+-- LATIN SMALL LIGATURE FL+foldMapping '\xfb02' s = Yield '\x0066' (CC s '\x006c' '\x0000')+-- LATIN SMALL LIGATURE FFI+foldMapping '\xfb03' s = Yield '\x0066' (CC s '\x0066' '\x0069')+-- LATIN SMALL LIGATURE FFL+foldMapping '\xfb04' s = Yield '\x0066' (CC s '\x0066' '\x006c')+-- LATIN SMALL LIGATURE LONG S T+foldMapping '\xfb05' s = Yield '\x0073' (CC s '\x0074' '\x0000')+-- LATIN SMALL LIGATURE ST+foldMapping '\xfb06' s = Yield '\x0073' (CC s '\x0074' '\x0000')+-- ARMENIAN SMALL LIGATURE MEN NOW+foldMapping '\xfb13' s = Yield '\x0574' (CC s '\x0576' '\x0000')+-- ARMENIAN SMALL LIGATURE MEN ECH+foldMapping '\xfb14' s = Yield '\x0574' (CC s '\x0565' '\x0000')+-- ARMENIAN SMALL LIGATURE MEN INI+foldMapping '\xfb15' s = Yield '\x0574' (CC s '\x056b' '\x0000')+-- ARMENIAN SMALL LIGATURE VEW NOW+foldMapping '\xfb16' s = Yield '\x057e' (CC s '\x0576' '\x0000')+-- ARMENIAN SMALL LIGATURE MEN XEH+foldMapping '\xfb17' s = Yield '\x0574' (CC s '\x056d' '\x0000')+-- OSAGE CAPITAL LETTER A+foldMapping '\x104b0' s = Yield '\x104d8' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER AI+foldMapping '\x104b1' s = Yield '\x104d9' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER AIN+foldMapping '\x104b2' s = Yield '\x104da' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER AH+foldMapping '\x104b3' s = Yield '\x104db' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER BRA+foldMapping '\x104b4' s = Yield '\x104dc' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER CHA+foldMapping '\x104b5' s = Yield '\x104dd' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER EHCHA+foldMapping '\x104b6' s = Yield '\x104de' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER E+foldMapping '\x104b7' s = Yield '\x104df' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER EIN+foldMapping '\x104b8' s = Yield '\x104e0' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER HA+foldMapping '\x104b9' s = Yield '\x104e1' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER HYA+foldMapping '\x104ba' s = Yield '\x104e2' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER I+foldMapping '\x104bb' s = Yield '\x104e3' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER KA+foldMapping '\x104bc' s = Yield '\x104e4' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER EHKA+foldMapping '\x104bd' s = Yield '\x104e5' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER KYA+foldMapping '\x104be' s = Yield '\x104e6' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER LA+foldMapping '\x104bf' s = Yield '\x104e7' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER MA+foldMapping '\x104c0' s = Yield '\x104e8' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER NA+foldMapping '\x104c1' s = Yield '\x104e9' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER O+foldMapping '\x104c2' s = Yield '\x104ea' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER OIN+foldMapping '\x104c3' s = Yield '\x104eb' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER PA+foldMapping '\x104c4' s = Yield '\x104ec' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER EHPA+foldMapping '\x104c5' s = Yield '\x104ed' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER SA+foldMapping '\x104c6' s = Yield '\x104ee' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER SHA+foldMapping '\x104c7' s = Yield '\x104ef' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER TA+foldMapping '\x104c8' s = Yield '\x104f0' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER EHTA+foldMapping '\x104c9' s = Yield '\x104f1' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER TSA+foldMapping '\x104ca' s = Yield '\x104f2' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER EHTSA+foldMapping '\x104cb' s = Yield '\x104f3' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER TSHA+foldMapping '\x104cc' s = Yield '\x104f4' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER DHA+foldMapping '\x104cd' s = Yield '\x104f5' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER U+foldMapping '\x104ce' s = Yield '\x104f6' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER WA+foldMapping '\x104cf' s = Yield '\x104f7' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER KHA+foldMapping '\x104d0' s = Yield '\x104f8' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER GHA+foldMapping '\x104d1' s = Yield '\x104f9' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER ZA+foldMapping '\x104d2' s = Yield '\x104fa' (CC s '\x0000' '\x0000')+-- OSAGE CAPITAL LETTER ZHA+foldMapping '\x104d3' s = Yield '\x104fb' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER A+foldMapping '\x10c80' s = Yield '\x10cc0' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER AA+foldMapping '\x10c81' s = Yield '\x10cc1' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER EB+foldMapping '\x10c82' s = Yield '\x10cc2' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER AMB+foldMapping '\x10c83' s = Yield '\x10cc3' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER EC+foldMapping '\x10c84' s = Yield '\x10cc4' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER ENC+foldMapping '\x10c85' s = Yield '\x10cc5' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER ECS+foldMapping '\x10c86' s = Yield '\x10cc6' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER ED+foldMapping '\x10c87' s = Yield '\x10cc7' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER AND+foldMapping '\x10c88' s = Yield '\x10cc8' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER E+foldMapping '\x10c89' s = Yield '\x10cc9' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER CLOSE E+foldMapping '\x10c8a' s = Yield '\x10cca' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER EE+foldMapping '\x10c8b' s = Yield '\x10ccb' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER EF+foldMapping '\x10c8c' s = Yield '\x10ccc' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER EG+foldMapping '\x10c8d' s = Yield '\x10ccd' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER EGY+foldMapping '\x10c8e' s = Yield '\x10cce' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER EH+foldMapping '\x10c8f' s = Yield '\x10ccf' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER I+foldMapping '\x10c90' s = Yield '\x10cd0' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER II+foldMapping '\x10c91' s = Yield '\x10cd1' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER EJ+foldMapping '\x10c92' s = Yield '\x10cd2' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER EK+foldMapping '\x10c93' s = Yield '\x10cd3' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER AK+foldMapping '\x10c94' s = Yield '\x10cd4' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER UNK+foldMapping '\x10c95' s = Yield '\x10cd5' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER EL+foldMapping '\x10c96' s = Yield '\x10cd6' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER ELY+foldMapping '\x10c97' s = Yield '\x10cd7' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER EM+foldMapping '\x10c98' s = Yield '\x10cd8' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER EN+foldMapping '\x10c99' s = Yield '\x10cd9' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER ENY+foldMapping '\x10c9a' s = Yield '\x10cda' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER O+foldMapping '\x10c9b' s = Yield '\x10cdb' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER OO+foldMapping '\x10c9c' s = Yield '\x10cdc' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG OE+foldMapping '\x10c9d' s = Yield '\x10cdd' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER RUDIMENTA OE+foldMapping '\x10c9e' s = Yield '\x10cde' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER OEE+foldMapping '\x10c9f' s = Yield '\x10cdf' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER EP+foldMapping '\x10ca0' s = Yield '\x10ce0' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER EMP+foldMapping '\x10ca1' s = Yield '\x10ce1' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER ER+foldMapping '\x10ca2' s = Yield '\x10ce2' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER SHORT ER+foldMapping '\x10ca3' s = Yield '\x10ce3' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER ES+foldMapping '\x10ca4' s = Yield '\x10ce4' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER ESZ+foldMapping '\x10ca5' s = Yield '\x10ce5' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER ET+foldMapping '\x10ca6' s = Yield '\x10ce6' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER ENT+foldMapping '\x10ca7' s = Yield '\x10ce7' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER ETY+foldMapping '\x10ca8' s = Yield '\x10ce8' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER ECH+foldMapping '\x10ca9' s = Yield '\x10ce9' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER U+foldMapping '\x10caa' s = Yield '\x10cea' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER UU+foldMapping '\x10cab' s = Yield '\x10ceb' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG UE+foldMapping '\x10cac' s = Yield '\x10cec' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER RUDIMENTA UE+foldMapping '\x10cad' s = Yield '\x10ced' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER EV+foldMapping '\x10cae' s = Yield '\x10cee' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER EZ+foldMapping '\x10caf' s = Yield '\x10cef' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER EZS+foldMapping '\x10cb0' s = Yield '\x10cf0' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER ENT-SHAPED SIGN+foldMapping '\x10cb1' s = Yield '\x10cf1' (CC s '\x0000' '\x0000')+-- OLD HUNGARIAN CAPITAL LETTER US+foldMapping '\x10cb2' s = Yield '\x10cf2' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER ALIF+foldMapping '\x1e900' s = Yield '\x1e922' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER DAALI+foldMapping '\x1e901' s = Yield '\x1e923' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER LAAM+foldMapping '\x1e902' s = Yield '\x1e924' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER MIIM+foldMapping '\x1e903' s = Yield '\x1e925' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER BA+foldMapping '\x1e904' s = Yield '\x1e926' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER SINNYIIYHE+foldMapping '\x1e905' s = Yield '\x1e927' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER PE+foldMapping '\x1e906' s = Yield '\x1e928' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER BHE+foldMapping '\x1e907' s = Yield '\x1e929' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER RA+foldMapping '\x1e908' s = Yield '\x1e92a' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER E+foldMapping '\x1e909' s = Yield '\x1e92b' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER FA+foldMapping '\x1e90a' s = Yield '\x1e92c' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER I+foldMapping '\x1e90b' s = Yield '\x1e92d' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER O+foldMapping '\x1e90c' s = Yield '\x1e92e' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER DHA+foldMapping '\x1e90d' s = Yield '\x1e92f' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER YHE+foldMapping '\x1e90e' s = Yield '\x1e930' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER WAW+foldMapping '\x1e90f' s = Yield '\x1e931' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER NUN+foldMapping '\x1e910' s = Yield '\x1e932' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER KAF+foldMapping '\x1e911' s = Yield '\x1e933' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER YA+foldMapping '\x1e912' s = Yield '\x1e934' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER U+foldMapping '\x1e913' s = Yield '\x1e935' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER JIIM+foldMapping '\x1e914' s = Yield '\x1e936' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER CHI+foldMapping '\x1e915' s = Yield '\x1e937' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER HA+foldMapping '\x1e916' s = Yield '\x1e938' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER QAAF+foldMapping '\x1e917' s = Yield '\x1e939' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER GA+foldMapping '\x1e918' s = Yield '\x1e93a' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER NYA+foldMapping '\x1e919' s = Yield '\x1e93b' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER TU+foldMapping '\x1e91a' s = Yield '\x1e93c' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER NHA+foldMapping '\x1e91b' s = Yield '\x1e93d' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER VA+foldMapping '\x1e91c' s = Yield '\x1e93e' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER KHA+foldMapping '\x1e91d' s = Yield '\x1e93f' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER GBE+foldMapping '\x1e91e' s = Yield '\x1e940' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER ZAL+foldMapping '\x1e91f' s = Yield '\x1e941' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER KPO+foldMapping '\x1e920' s = Yield '\x1e942' (CC s '\x0000' '\x0000')+-- ADLAM CAPITAL LETTER SHA+foldMapping '\x1e921' s = Yield '\x1e943' (CC s '\x0000' '\x0000')+foldMapping c s = Yield (toLower c) (CC s '\0' '\0')
+ src/Data/Text/Internal/Fusion/Common.hs view
@@ -0,0 +1,949 @@+{-# LANGUAGE BangPatterns, MagicHash, Rank2Types #-}+-- |+-- Module      : Data.Text.Internal.Fusion.Common+-- Copyright   : (c) Bryan O'Sullivan 2009, 2012+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- Common stream fusion functionality for text.++module Data.Text.Internal.Fusion.Common+    (+    -- * Creation and elimination+      singleton+    , streamList+    , unstreamList+    , streamCString#++    -- * Basic interface+    , cons+    , snoc+    , append+    , head+    , uncons+    , last+    , tail+    , init+    , null+    , lengthI+    , compareLengthI+    , isSingleton++    -- * Transformations+    , map+    , intercalate+    , intersperse++    -- ** Case conversion+    -- $case+    , toCaseFold+    , toLower+    , toTitle+    , toUpper++    -- ** Justification+    , justifyLeftI++    -- * Folds+    , foldl+    , foldl'+    , foldl1+    , foldl1'+    , foldr+    , foldr1++    -- ** Special folds+    , concat+    , concatMap+    , any+    , all+    , maximum+    , minimum++    -- * Construction+    -- ** Scans+    , scanl++    -- ** Generation and unfolding+    , replicateCharI+    , replicateI+    , unfoldr+    , unfoldrNI++    -- * Substrings+    -- ** Breaking strings+    , take+    , drop+    , takeWhile+    , dropWhile++    -- * Predicates+    , isPrefixOf++    -- * Searching+    , elem+    , filter++    -- * Indexing+    , findBy+    , indexI+    , findIndexI+    , countCharI++    -- * Zipping and unzipping+    , zipWith+    ) where++import Prelude (Bool(..), Char, Eq(..), Int, Integral, Maybe(..),+                Ord(..), Ordering(..), String, (.), ($), (+), (-), (*), (++),+                (&&), fromIntegral, otherwise)+import qualified Data.List as L+import qualified Prelude as P+import Data.Bits (shiftL)+import Data.Char (isLetter, isSpace)+import Data.Int (Int64)+import Data.Text.Internal.Fusion.Types+import Data.Text.Internal.Fusion.CaseMapping (foldMapping, lowerMapping, titleMapping,+                                     upperMapping)+import Data.Text.Internal.Fusion.Size+import GHC.Prim (Addr#, chr#, indexCharOffAddr#, ord#)+import GHC.Types (Char(..), Int(..))++singleton :: Char -> Stream Char+singleton c = Stream next False (codePointsSize 1)+    where next False = Yield c True+          next True  = Done+{-# INLINE [0] singleton #-}++streamList :: [a] -> Stream a+{-# INLINE [0] streamList #-}+streamList s  = Stream next s unknownSize+    where next []       = Done+          next (x:xs)   = Yield x xs++unstreamList :: Stream a -> [a]+unstreamList (Stream next s0 _len) = unfold s0+    where unfold !s = case next s of+                        Done       -> []+                        Skip s'    -> unfold s'+                        Yield x s' -> x : unfold s'+{-# INLINE [0] unstreamList #-}++{-# RULES "STREAM streamList/unstreamList fusion" forall s. streamList (unstreamList s) = s #-}++-- | Stream the UTF-8-like packed encoding used by GHC to represent+-- constant strings in generated code.+--+-- This encoding uses the byte sequence "\xc0\x80" to represent NUL,+-- and the string is NUL-terminated.+streamCString# :: Addr# -> Stream Char+streamCString# addr = Stream step 0 unknownSize+  where+    step !i+        | b == 0    = Done+        | b <= 0x7f = Yield (C# b#) (i+1)+        | b <= 0xdf = let !c = chr $ ((b-0xc0) `shiftL` 6) + next 1+                      in Yield c (i+2)+        | b <= 0xef = let !c = chr $ ((b-0xe0) `shiftL` 12) ++                                      (next 1  `shiftL` 6) ++                                       next 2+                      in Yield c (i+3)+        | otherwise = let !c = chr $ ((b-0xf0) `shiftL` 18) ++                                      (next 1  `shiftL` 12) ++                                      (next 2  `shiftL` 6) ++                                       next 3+                      in Yield c (i+4)+      where b      = I# (ord# b#)+            next n = I# (ord# (at# (i+n))) - 0x80+            !b#    = at# i+    at# (I# i#) = indexCharOffAddr# addr i#+    chr (I# i#) = C# (chr# i#)+{-# INLINE [0] streamCString# #-}++-- ----------------------------------------------------------------------------+-- * Basic stream functions++data C s = C0 !s+         | C1 !s++-- | /O(n)/ Adds a character to the front of a Stream Char.+cons :: Char -> Stream Char -> Stream Char+cons !w (Stream next0 s0 len) = Stream next (C1 s0) (len + codePointsSize 1)+    where+      next (C1 s) = Yield w (C0 s)+      next (C0 s) = case next0 s of+                          Done -> Done+                          Skip s' -> Skip (C0 s')+                          Yield x s' -> Yield x (C0 s')+{-# INLINE [0] cons #-}++data Snoc a = N+            | J !a++-- | /O(n)/ Adds a character to the end of a stream.+snoc :: Stream Char -> Char -> Stream Char+snoc (Stream next0 xs0 len) w = Stream next (J xs0) (len + codePointsSize 1)+  where+    next (J xs) = case next0 xs of+      Done        -> Yield w N+      Skip xs'    -> Skip    (J xs')+      Yield x xs' -> Yield x (J xs')+    next N = Done+{-# INLINE [0] snoc #-}++data E l r = L !l+           | R !r++-- | /O(n)/ Appends one Stream to the other.+append :: Stream Char -> Stream Char -> Stream Char+append (Stream next0 s01 len1) (Stream next1 s02 len2) =+    Stream next (L s01) (len1 + len2)+    where+      next (L s1) = case next0 s1 of+                         Done        -> Skip    (R s02)+                         Skip s1'    -> Skip    (L s1')+                         Yield x s1' -> Yield x (L s1')+      next (R s2) = case next1 s2 of+                          Done        -> Done+                          Skip s2'    -> Skip    (R s2')+                          Yield x s2' -> Yield x (R s2')+{-# INLINE [0] append #-}++-- | /O(1)/ Returns the first character of a Text, which must be non-empty.+-- Subject to array fusion.+head :: Stream Char -> Char+head (Stream next s0 _len) = loop_head s0+    where+      loop_head !s = case next s of+                      Yield x _ -> x+                      Skip s'   -> loop_head s'+                      Done      -> head_empty+{-# INLINE [0] head #-}++head_empty :: a+head_empty = streamError "head" "Empty stream"+{-# NOINLINE head_empty #-}++-- | /O(1)/ Returns the first character and remainder of a 'Stream+-- Char', or 'Nothing' if empty.  Subject to array fusion.+uncons :: Stream Char -> Maybe (Char, Stream Char)+uncons (Stream next s0 len) = loop_uncons s0+    where+      loop_uncons !s = case next s of+                         Yield x s1 -> Just (x, Stream next s1 (len - codePointsSize 1))+                         Skip s'    -> loop_uncons s'+                         Done       -> Nothing+{-# INLINE [0] uncons #-}++-- | /O(n)/ Returns the last character of a 'Stream Char', which must+-- be non-empty.+last :: Stream Char -> Char+last (Stream next s0 _len) = loop0_last s0+    where+      loop0_last !s = case next s of+                        Done       -> emptyError "last"+                        Skip s'    -> loop0_last  s'+                        Yield x s' -> loop_last x s'+      loop_last !x !s = case next s of+                         Done        -> x+                         Skip s'     -> loop_last x  s'+                         Yield x' s' -> loop_last x' s'+{-# INLINE[0] last #-}++-- | /O(1)/ Returns all characters after the head of a Stream Char, which must+-- be non-empty.+tail :: Stream Char -> Stream Char+tail (Stream next0 s0 len) = Stream next (C0 s0) (len - codePointsSize 1)+    where+      next (C0 s) = case next0 s of+                      Done       -> emptyError "tail"+                      Skip s'    -> Skip (C0 s')+                      Yield _ s' -> Skip (C1 s')+      next (C1 s) = case next0 s of+                      Done       -> Done+                      Skip s'    -> Skip    (C1 s')+                      Yield x s' -> Yield x (C1 s')+{-# INLINE [0] tail #-}++data Init s = Init0 !s+            | Init1 {-# UNPACK #-} !Char !s++-- | /O(1)/ Returns all but the last character of a Stream Char, which+-- must be non-empty.+init :: Stream Char -> Stream Char+init (Stream next0 s0 len) = Stream next (Init0 s0) (len - codePointsSize 1)+    where+      next (Init0 s) = case next0 s of+                         Done       -> emptyError "init"+                         Skip s'    -> Skip (Init0 s')+                         Yield x s' -> Skip (Init1 x s')+      next (Init1 x s)  = case next0 s of+                            Done        -> Done+                            Skip s'     -> Skip    (Init1 x s')+                            Yield x' s' -> Yield x (Init1 x' s')+{-# INLINE [0] init #-}++-- | /O(1)/ Tests whether a Stream Char is empty or not.+null :: Stream Char -> Bool+null (Stream next s0 _len) = loop_null s0+    where+      loop_null !s = case next s of+                       Done      -> True+                       Yield _ _ -> False+                       Skip s'   -> loop_null s'+{-# INLINE[0] null #-}++-- | /O(n)/ Returns the number of characters in a string.+lengthI :: Integral a => Stream Char -> a+lengthI (Stream next s0 _len) = loop_length 0 s0+    where+      loop_length !z s  = case next s of+                           Done       -> z+                           Skip    s' -> loop_length z s'+                           Yield _ s' -> loop_length (z + 1) s'+{-# INLINE[0] lengthI #-}++-- | /O(n)/ Compares the count of characters in a string to a number.+-- Subject to fusion.+--+-- This function gives the same answer as comparing against the result+-- of 'lengthI', but can short circuit if the count of characters is+-- greater than the number or if the stream can't possibly be as long+-- as the number supplied, and hence be more efficient.+compareLengthI :: Integral a => Stream Char -> a -> Ordering+compareLengthI (Stream next s0 len) n+    -- Note that @len@ tracks code units whereas we want to compare the length+    -- in code points. Specifically, a stream with hint @len@ may consist of+    -- anywhere from @len/2@ to @len@ code points.+  | Just r <- compareSize len n' = r+  | otherwise = loop_cmp 0 s0+    where+      n' = codePointsSize $ fromIntegral n+      loop_cmp !z s  = case next s of+                         Done       -> compare z n+                         Skip    s' -> loop_cmp z s'+                         Yield _ s' | z > n     -> GT+                                    | otherwise -> loop_cmp (z + 1) s'+{-# INLINE[0] compareLengthI #-}++-- | /O(n)/ Indicate whether a string contains exactly one element.+isSingleton :: Stream Char -> Bool+isSingleton (Stream next s0 _len) = loop 0 s0+    where+      loop !z s  = case next s of+                     Done            -> z == (1::Int)+                     Skip    s'      -> loop z s'+                     Yield _ s'+                         | z >= 1    -> False+                         | otherwise -> loop (z+1) s'+{-# INLINE[0] isSingleton #-}++-- ----------------------------------------------------------------------------+-- * Stream transformations++-- | /O(n)/ 'map' @f @xs is the Stream Char obtained by applying @f@+-- to each element of @xs@.+map :: (Char -> Char) -> Stream Char -> Stream Char+map f (Stream next0 s0 len) = Stream next s0 len+    where+      next !s = case next0 s of+                  Done       -> Done+                  Skip s'    -> Skip s'+                  Yield x s' -> Yield (f x) s'+{-# INLINE [0] map #-}++{-#+  RULES "STREAM map/map fusion" forall f g s.+     map f (map g s) = map (\x -> f (g x)) s+ #-}++data I s = I1 !s+         | I2 !s {-# UNPACK #-} !Char+         | I3 !s++-- | /O(n)/ Take a character and place it between each of the+-- characters of a 'Stream Char'.+intersperse :: Char -> Stream Char -> Stream Char+intersperse c (Stream next0 s0 len) = Stream next (I1 s0) (len + unknownSize)+    where+      next (I1 s) = case next0 s of+        Done       -> Done+        Skip s'    -> Skip (I1 s')+        Yield x s' -> Skip (I2 s' x)+      next (I2 s x)  = Yield x (I3 s)+      next (I3 s) = case next0 s of+        Done       -> Done+        Skip s'    -> Skip    (I3 s')+        Yield x s' -> Yield c (I2 s' x)+{-# INLINE [0] intersperse #-}++-- ----------------------------------------------------------------------------+-- ** Case conversions (folds)++-- $case+--+-- With Unicode text, it is incorrect to use combinators like @map+-- toUpper@ to case convert each character of a string individually.+-- Instead, use the whole-string case conversion functions from this+-- module.  For correctness in different writing systems, these+-- functions may map one input character to two or three output+-- characters.++-- | Map a 'Stream' through the given case-mapping function.+caseConvert :: (forall s. Char -> s -> Step (CC s) Char)+            -> Stream Char -> Stream Char+caseConvert remap (Stream next0 s0 len) =+    Stream next (CC s0 '\0' '\0') (len `unionSize` (3*len))+  where+    next (CC s '\0' _) =+        case next0 s of+          Done       -> Done+          Skip s'    -> Skip (CC s' '\0' '\0')+          Yield c s' -> remap c s'+    next (CC s a b)  =  Yield a (CC s b '\0')++-- | /O(n)/ Convert a string to folded case.  This function is mainly+-- useful for performing caseless (or case insensitive) string+-- comparisons.+--+-- A string @x@ is a caseless match for a string @y@ if and only if:+--+-- @toCaseFold x == toCaseFold y@+--+-- The result string may be longer than the input string, and may+-- differ from applying 'toLower' to the input string.  For instance,+-- the Armenian small ligature men now (U+FB13) is case folded to the+-- bigram men now (U+0574 U+0576), while the micro sign (U+00B5) is+-- case folded to the Greek small letter letter mu (U+03BC) instead of+-- itself.+toCaseFold :: Stream Char -> Stream Char+toCaseFold = caseConvert foldMapping+{-# INLINE [0] toCaseFold #-}++-- | /O(n)/ Convert a string to upper case, using simple case+-- conversion.  The result string may be longer than the input string.+-- For instance, the German eszett (U+00DF) maps to the two-letter+-- sequence SS.+toUpper :: Stream Char -> Stream Char+toUpper = caseConvert upperMapping+{-# INLINE [0] toUpper #-}++-- | /O(n)/ Convert a string to lower case, using simple case+-- conversion.  The result string may be longer than the input string.+-- For instance, the Latin capital letter I with dot above (U+0130)+-- maps to the sequence Latin small letter i (U+0069) followed by+-- combining dot above (U+0307).+toLower :: Stream Char -> Stream Char+toLower = caseConvert lowerMapping+{-# INLINE [0] toLower #-}++-- | /O(n)/ Convert a string to title case, using simple case+-- conversion.+--+-- The first letter of the input is converted to title case, as is+-- every subsequent letter that immediately follows a non-letter.+-- Every letter that immediately follows another letter is converted+-- to lower case.+--+-- The result string may be longer than the input string. For example,+-- the Latin small ligature &#xfb02; (U+FB02) is converted to the+-- sequence Latin capital letter F (U+0046) followed by Latin small+-- letter l (U+006C).+--+-- /Note/: this function does not take language or culture specific+-- rules into account. For instance, in English, different style+-- guides disagree on whether the book name \"The Hill of the Red+-- Fox\" is correctly title cased&#x2014;but this function will+-- capitalize /every/ word.+toTitle :: Stream Char -> Stream Char+toTitle (Stream next0 s0 len) = Stream next (CC (False :*: s0) '\0' '\0') (len + unknownSize)+  where+    next (CC (letter :*: s) '\0' _) =+      case next0 s of+        Done            -> Done+        Skip s'         -> Skip (CC (letter :*: s') '\0' '\0')+        Yield c s'+          | nonSpace    -> if letter+                           then lowerMapping c (nonSpace :*: s')+                           else titleMapping c (letter' :*: s')+          | otherwise   -> Yield c (CC (letter' :*: s') '\0' '\0')+          where nonSpace = P.not (isSpace c)+                letter'  = isLetter c+    next (CC s a b)      = Yield a (CC s b '\0')+{-# INLINE [0] toTitle #-}++data Justify i s = Just1 !i !s+                 | Just2 !i !s++justifyLeftI :: Integral a => a -> Char -> Stream Char -> Stream Char+justifyLeftI k c (Stream next0 s0 len) =+    Stream next (Just1 0 s0) (larger (fromIntegral k * charSize c + len) len)+  where+    next (Just1 n s) =+        case next0 s of+          Done       -> next (Just2 n s)+          Skip s'    -> Skip (Just1 n s')+          Yield x s' -> Yield x (Just1 (n+1) s')+    next (Just2 n s)+        | n < k       = Yield c (Just2 (n+1) s)+        | otherwise   = Done+    {-# INLINE next #-}+{-# INLINE [0] justifyLeftI #-}++-- ----------------------------------------------------------------------------+-- * Reducing Streams (folds)++-- | foldl, applied to a binary operator, a starting value (typically the+-- left-identity of the operator), and a Stream, reduces the Stream using the+-- binary operator, from left to right.+foldl :: (b -> Char -> b) -> b -> Stream Char -> b+foldl f z0 (Stream next s0 _len) = loop_foldl z0 s0+    where+      loop_foldl z !s = case next s of+                          Done -> z+                          Skip s' -> loop_foldl z s'+                          Yield x s' -> loop_foldl (f z x) s'+{-# INLINE [0] foldl #-}++-- | A strict version of foldl.+foldl' :: (b -> Char -> b) -> b -> Stream Char -> b+foldl' f z0 (Stream next s0 _len) = loop_foldl' z0 s0+    where+      loop_foldl' !z !s = case next s of+                            Done -> z+                            Skip s' -> loop_foldl' z s'+                            Yield x s' -> loop_foldl' (f z x) s'+{-# INLINE [0] foldl' #-}++-- | foldl1 is a variant of foldl that has no starting value argument,+-- and thus must be applied to non-empty Streams.+foldl1 :: (Char -> Char -> Char) -> Stream Char -> Char+foldl1 f (Stream next s0 _len) = loop0_foldl1 s0+    where+      loop0_foldl1 !s = case next s of+                          Skip s' -> loop0_foldl1 s'+                          Yield x s' -> loop_foldl1 x s'+                          Done -> emptyError "foldl1"+      loop_foldl1 z !s = case next s of+                           Done -> z+                           Skip s' -> loop_foldl1 z s'+                           Yield x s' -> loop_foldl1 (f z x) s'+{-# INLINE [0] foldl1 #-}++-- | A strict version of foldl1.+foldl1' :: (Char -> Char -> Char) -> Stream Char -> Char+foldl1' f (Stream next s0 _len) = loop0_foldl1' s0+    where+      loop0_foldl1' !s = case next s of+                           Skip s' -> loop0_foldl1' s'+                           Yield x s' -> loop_foldl1' x s'+                           Done -> emptyError "foldl1"+      loop_foldl1' !z !s = case next s of+                             Done -> z+                             Skip s' -> loop_foldl1' z s'+                             Yield x s' -> loop_foldl1' (f z x) s'+{-# INLINE [0] foldl1' #-}++-- | 'foldr', applied to a binary operator, a starting value (typically the+-- right-identity of the operator), and a stream, reduces the stream using the+-- binary operator, from right to left.+foldr :: (Char -> b -> b) -> b -> Stream Char -> b+foldr f z (Stream next s0 _len) = loop_foldr s0+    where+      loop_foldr !s = case next s of+                        Done -> z+                        Skip s' -> loop_foldr s'+                        Yield x s' -> f x (loop_foldr s')+{-# INLINE [0] foldr #-}++-- | foldr1 is a variant of 'foldr' that has no starting value argument,+-- and thus must be applied to non-empty streams.+-- Subject to array fusion.+foldr1 :: (Char -> Char -> Char) -> Stream Char -> Char+foldr1 f (Stream next s0 _len) = loop0_foldr1 s0+  where+    loop0_foldr1 !s = case next s of+      Done       -> emptyError "foldr1"+      Skip    s' -> loop0_foldr1  s'+      Yield x s' -> loop_foldr1 x s'++    loop_foldr1 x !s = case next s of+      Done        -> x+      Skip     s' -> loop_foldr1 x s'+      Yield x' s' -> f x (loop_foldr1 x' s')+{-# INLINE [0] foldr1 #-}++intercalate :: Stream Char -> [Stream Char] -> Stream Char+intercalate s = concat . (L.intersperse s)+{-# INLINE [0] intercalate #-}++-- ----------------------------------------------------------------------------+-- ** Special folds++-- | /O(n)/ Concatenate a list of streams. Subject to array fusion.+concat :: [Stream Char] -> Stream Char+concat = L.foldr append empty+{-# INLINE [0] concat #-}++-- | Map a function over a stream that results in a stream and concatenate the+-- results.+concatMap :: (Char -> Stream Char) -> Stream Char -> Stream Char+concatMap f = foldr (append . f) empty+{-# INLINE [0] concatMap #-}++-- | /O(n)/ any @p @xs determines if any character in the stream+-- @xs@ satisfies the predicate @p@.+any :: (Char -> Bool) -> Stream Char -> Bool+any p (Stream next0 s0 _len) = loop_any s0+    where+      loop_any !s = case next0 s of+                      Done                   -> False+                      Skip s'                -> loop_any s'+                      Yield x s' | p x       -> True+                                 | otherwise -> loop_any s'+{-# INLINE [0] any #-}++-- | /O(n)/ all @p @xs determines if all characters in the 'Text'+-- @xs@ satisfy the predicate @p@.+all :: (Char -> Bool) -> Stream Char -> Bool+all p (Stream next0 s0 _len) = loop_all s0+    where+      loop_all !s = case next0 s of+                      Done                   -> True+                      Skip s'                -> loop_all s'+                      Yield x s' | p x       -> loop_all s'+                                 | otherwise -> False+{-# INLINE [0] all #-}++-- | /O(n)/ maximum returns the maximum value from a stream, which must be+-- non-empty.+maximum :: Stream Char -> Char+maximum (Stream next0 s0 _len) = loop0_maximum s0+    where+      loop0_maximum !s   = case next0 s of+                             Done       -> emptyError "maximum"+                             Skip s'    -> loop0_maximum s'+                             Yield x s' -> loop_maximum x s'+      loop_maximum !z !s = case next0 s of+                             Done            -> z+                             Skip s'         -> loop_maximum z s'+                             Yield x s'+                                 | x > z     -> loop_maximum x s'+                                 | otherwise -> loop_maximum z s'+{-# INLINE [0] maximum #-}++-- | /O(n)/ minimum returns the minimum value from a 'Text', which must be+-- non-empty.+minimum :: Stream Char -> Char+minimum (Stream next0 s0 _len) = loop0_minimum s0+    where+      loop0_minimum !s   = case next0 s of+                             Done       -> emptyError "minimum"+                             Skip s'    -> loop0_minimum s'+                             Yield x s' -> loop_minimum x s'+      loop_minimum !z !s = case next0 s of+                             Done            -> z+                             Skip s'         -> loop_minimum z s'+                             Yield x s'+                                 | x < z     -> loop_minimum x s'+                                 | otherwise -> loop_minimum z s'+{-# INLINE [0] minimum #-}++-- -----------------------------------------------------------------------------+-- * Building streams++scanl :: (Char -> Char -> Char) -> Char -> Stream Char -> Stream Char+scanl f z0 (Stream next0 s0 len) = Stream next (Scan1 z0 s0) (len+1) -- HINT maybe too low+  where+    {-# INLINE next #-}+    next (Scan1 z s) = Yield z (Scan2 z s)+    next (Scan2 z s) = case next0 s of+                         Yield x s' -> let !x' = f z x+                                       in Yield x' (Scan2 x' s')+                         Skip s'    -> Skip (Scan2 z s')+                         Done       -> Done+{-# INLINE [0] scanl #-}++-- -----------------------------------------------------------------------------+-- ** Generating and unfolding streams++replicateCharI :: Integral a => a -> Char -> Stream Char+replicateCharI !n !c+    | n < 0     = empty+    | otherwise = Stream next 0 (fromIntegral n) -- HINT maybe too low+  where+    next !i | i >= n    = Done+            | otherwise = Yield c (i + 1)+{-# INLINE [0] replicateCharI #-}++data RI s = RI !s {-# UNPACK #-} !Int64++replicateI :: Int64 -> Stream Char -> Stream Char+replicateI n (Stream next0 s0 len) =+    Stream next (RI s0 0) (fromIntegral (max 0 n) * len)+  where+    next (RI s k)+        | k >= n = Done+        | otherwise = case next0 s of+                        Done       -> Skip    (RI s0 (k+1))+                        Skip s'    -> Skip    (RI s' k)+                        Yield x s' -> Yield x (RI s' k)+{-# INLINE [0] replicateI #-}++-- | /O(n)/, where @n@ is the length of the result. The unfoldr function+-- is analogous to the List 'unfoldr'. unfoldr builds a stream+-- from a seed value. The function takes the element and returns+-- Nothing if it is done producing the stream or returns Just+-- (a,b), in which case, a is the next Char in the string, and b is+-- the seed value for further production.+unfoldr :: (a -> Maybe (Char,a)) -> a -> Stream Char+unfoldr f s0 = Stream next s0 unknownSize+    where+      {-# INLINE next #-}+      next !s = case f s of+                 Nothing      -> Done+                 Just (w, s') -> Yield w s'+{-# INLINE [0] unfoldr #-}++-- | /O(n)/ Like 'unfoldr', 'unfoldrNI' builds a stream from a seed+-- value. However, the length of the result is limited by the+-- first argument to 'unfoldrNI'. This function is more efficient than+-- 'unfoldr' when the length of the result is known.+unfoldrNI :: Integral a => a -> (b -> Maybe (Char,b)) -> b -> Stream Char+unfoldrNI n f s0 | n <  0    = empty+                 | otherwise = Stream next (0 :*: s0) (maxSize $ fromIntegral (n*2))+    where+      {-# INLINE next #-}+      next (z :*: s) = case f s of+          Nothing                  -> Done+          Just (w, s') | z >= n    -> Done+                       | otherwise -> Yield w ((z + 1) :*: s')+{-# INLINE unfoldrNI #-}++-------------------------------------------------------------------------------+--  * Substreams++-- | /O(n)/ @'take' n@, applied to a stream, returns the prefix of the+-- stream of length @n@, or the stream itself if @n@ is greater than the+-- length of the stream.+take :: Integral a => a -> Stream Char -> Stream Char+take n0 (Stream next0 s0 len) =+    Stream next (n0' :*: s0) (smaller len (codePointsSize $ fromIntegral n0'))+    where+      n0' = max n0 0++      {-# INLINE next #-}+      next (n :*: s) | n <= 0    = Done+                     | otherwise = case next0 s of+                                     Done -> Done+                                     Skip s' -> Skip (n :*: s')+                                     Yield x s' -> Yield x ((n-1) :*: s')+{-# INLINE [0] take #-}++data Drop a s = NS !s+              | JS !a !s++-- | /O(n)/ @'drop' n@, applied to a stream, returns the suffix of the+-- stream after the first @n@ characters, or the empty stream if @n@+-- is greater than the length of the stream.+drop :: Integral a => a -> Stream Char -> Stream Char+drop n0 (Stream next0 s0 len) =+    Stream next (JS n0' s0) (len - codePointsSize (fromIntegral n0'))+  where+    n0' = max n0 0++    {-# INLINE next #-}+    next (JS n s)+      | n <= 0    = Skip (NS s)+      | otherwise = case next0 s of+          Done       -> Done+          Skip    s' -> Skip (JS n    s')+          Yield _ s' -> Skip (JS (n-1) s')+    next (NS s) = case next0 s of+      Done       -> Done+      Skip    s' -> Skip    (NS s')+      Yield x s' -> Yield x (NS s')+{-# INLINE [0] drop #-}++-- | 'takeWhile', applied to a predicate @p@ and a stream, returns the+-- longest prefix (possibly empty) of elements that satisfy @p@.+takeWhile :: (Char -> Bool) -> Stream Char -> Stream Char+takeWhile p (Stream next0 s0 len) = Stream next s0 (len - unknownSize)+    where+      {-# INLINE next #-}+      next !s = case next0 s of+                  Done    -> Done+                  Skip s' -> Skip s'+                  Yield x s' | p x       -> Yield x s'+                             | otherwise -> Done+{-# INLINE [0] takeWhile #-}++-- | @'dropWhile' p xs@ returns the suffix remaining after @'takeWhile' p xs@.+dropWhile :: (Char -> Bool) -> Stream Char -> Stream Char+dropWhile p (Stream next0 s0 len) = Stream next (L s0) (len - unknownSize)+    where+    {-# INLINE next #-}+    next (L s)  = case next0 s of+      Done                   -> Done+      Skip    s'             -> Skip    (L s')+      Yield x s' | p x       -> Skip    (L s')+                 | otherwise -> Yield x (R s')+    next (R s) = case next0 s of+      Done       -> Done+      Skip    s' -> Skip    (R s')+      Yield x s' -> Yield x (R s')+{-# INLINE [0] dropWhile #-}++-- | /O(n)/ The 'isPrefixOf' function takes two 'Stream's and returns+-- 'True' iff the first is a prefix of the second.+isPrefixOf :: (Eq a) => Stream a -> Stream a -> Bool+isPrefixOf (Stream next1 s1 _) (Stream next2 s2 _) = loop (next1 s1) (next2 s2)+    where+      loop Done      _ = True+      loop _    Done = False+      loop (Skip s1')     (Skip s2')     = loop (next1 s1') (next2 s2')+      loop (Skip s1')     x2             = loop (next1 s1') x2+      loop x1             (Skip s2')     = loop x1          (next2 s2')+      loop (Yield x1 s1') (Yield x2 s2') = x1 == x2 &&+                                           loop (next1 s1') (next2 s2')+{-# INLINE [0] isPrefixOf #-}++-- ----------------------------------------------------------------------------+-- * Searching++-------------------------------------------------------------------------------+-- ** Searching by equality++-- | /O(n)/ 'elem' is the stream membership predicate.+elem :: Char -> Stream Char -> Bool+elem w (Stream next s0 _len) = loop_elem s0+    where+      loop_elem !s = case next s of+                       Done -> False+                       Skip s' -> loop_elem s'+                       Yield x s' | x == w -> True+                                  | otherwise -> loop_elem s'+{-# INLINE [0] elem #-}++-------------------------------------------------------------------------------+-- ** Searching with a predicate++-- | /O(n)/ The 'findBy' function takes a predicate and a stream,+-- and returns the first element in matching the predicate, or 'Nothing'+-- if there is no such element.++findBy :: (Char -> Bool) -> Stream Char -> Maybe Char+findBy p (Stream next s0 _len) = loop_find s0+    where+      loop_find !s = case next s of+                       Done -> Nothing+                       Skip s' -> loop_find s'+                       Yield x s' | p x -> Just x+                                  | otherwise -> loop_find s'+{-# INLINE [0] findBy #-}++-- | /O(n)/ Stream index (subscript) operator, starting from 0.+indexI :: Integral a => Stream Char -> a -> Char+indexI (Stream next s0 _len) n0+  | n0 < 0    = streamError "index" "Negative index"+  | otherwise = loop_index n0 s0+  where+    loop_index !n !s = case next s of+      Done                   -> streamError "index" "Index too large"+      Skip    s'             -> loop_index  n    s'+      Yield x s' | n == 0    -> x+                 | otherwise -> loop_index (n-1) s'+{-# INLINE [0] indexI #-}++-- | /O(n)/ 'filter', applied to a predicate and a stream,+-- returns a stream containing those characters that satisfy the+-- predicate.+filter :: (Char -> Bool) -> Stream Char -> Stream Char+filter p (Stream next0 s0 len) =+    Stream next s0 (len - unknownSize) -- HINT maybe too high+  where+    next !s = case next0 s of+                Done                   -> Done+                Skip    s'             -> Skip    s'+                Yield x s' | p x       -> Yield x s'+                           | otherwise -> Skip    s'+{-# INLINE [0] filter #-}++{-# RULES+  "STREAM filter/filter fusion" forall p q s.+  filter p (filter q s) = filter (\x -> q x && p x) s+  #-}++-- | The 'findIndexI' function takes a predicate and a stream and+-- returns the index of the first element in the stream satisfying the+-- predicate.+findIndexI :: Integral a => (Char -> Bool) -> Stream Char -> Maybe a+findIndexI p s = case findIndicesI p s of+                  (i:_) -> Just i+                  _     -> Nothing+{-# INLINE [0] findIndexI #-}++-- | The 'findIndicesI' function takes a predicate and a stream and+-- returns all indices of the elements in the stream satisfying the+-- predicate.+findIndicesI :: Integral a => (Char -> Bool) -> Stream Char -> [a]+findIndicesI p (Stream next s0 _len) = loop_findIndex 0 s0+  where+    loop_findIndex !i !s = case next s of+      Done                   -> []+      Skip    s'             -> loop_findIndex i     s' -- hmm. not caught by QC+      Yield x s' | p x       -> i : loop_findIndex (i+1) s'+                 | otherwise -> loop_findIndex (i+1) s'+{-# INLINE [0] findIndicesI #-}++-------------------------------------------------------------------------------+-- * Zipping++-- | Strict triple.+data Zip a b m = Z1 !a !b+               | Z2 !a !b !m++-- | zipWith generalises 'zip' by zipping with the function given as+-- the first argument, instead of a tupling function.+zipWith :: (a -> a -> b) -> Stream a -> Stream a -> Stream b+zipWith f (Stream next0 sa0 len1) (Stream next1 sb0 len2) =+    Stream next (Z1 sa0 sb0) (smaller len1 len2)+    where+      next (Z1 sa sb) = case next0 sa of+                          Done -> Done+                          Skip sa' -> Skip (Z1 sa' sb)+                          Yield a sa' -> Skip (Z2 sa' sb a)++      next (Z2 sa' sb a) = case next1 sb of+                             Done -> Done+                             Skip sb' -> Skip (Z2 sa' sb' a)+                             Yield b sb' -> Yield (f a b) (Z1 sa' sb')+{-# INLINE [0] zipWith #-}++-- | /O(n)/ The 'countCharI' function returns the number of times the+-- query element appears in the given stream.+countCharI :: Integral a => Char -> Stream Char -> a+countCharI a (Stream next s0 _len) = loop 0 s0+  where+    loop !i !s = case next s of+      Done                   -> i+      Skip    s'             -> loop i s'+      Yield x s' | a == x    -> loop (i+1) s'+                 | otherwise -> loop i s'+{-# INLINE [0] countCharI #-}++streamError :: String -> String -> a+streamError func msg = P.error $ "Data.Text.Internal.Fusion.Common." ++ func ++ ": " ++ msg++emptyError :: String -> a+emptyError func = internalError func "Empty input"++internalError :: String -> a+internalError func = streamError func "Internal error"
+ src/Data/Text/Internal/Fusion/Size.hs view
@@ -0,0 +1,187 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-missing-methods #-}+-- |+-- Module      : Data.Text.Internal.Fusion.Internal+-- Copyright   : (c) Roman Leshchinskiy 2008,+--               (c) Bryan O'Sullivan 2009+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : portable+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- Size hints.++module Data.Text.Internal.Fusion.Size+    (+      Size+      -- * Sizes+    , exactSize+    , maxSize+    , betweenSize+    , unknownSize+    , unionSize+    , charSize+    , codePointsSize+      -- * Querying sizes+    , exactly+    , smaller+    , larger+    , upperBound+    , lowerBound+    , compareSize+    , isEmpty+    ) where++import Data.Char (ord)+import Data.Text.Internal (mul)+#if defined(ASSERTS)+import Control.Exception (assert)+#endif++-- | A size in UTF-16 code units.+data Size = Between {-# UNPACK #-} !Int {-# UNPACK #-} !Int -- ^ Lower and upper bounds on size.+          | Unknown                                         -- ^ Unknown size.+            deriving (Eq, Show)++exactly :: Size -> Maybe Int+exactly (Between na nb) | na == nb = Just na+exactly _ = Nothing+{-# INLINE exactly #-}++-- | The 'Size' of the given code point.+charSize :: Char -> Size+charSize c+  | ord c < 0x10000 = exactSize 1+  | otherwise       = exactSize 2++-- | The 'Size' of @n@ code points.+codePointsSize :: Int -> Size+codePointsSize n =+#if defined(ASSERTS)+    assert (n >= 0)+#endif+    Between n (2*n)+{-# INLINE codePointsSize #-}++exactSize :: Int -> Size+exactSize n =+#if defined(ASSERTS)+    assert (n >= 0)+#endif+    Between n n+{-# INLINE exactSize #-}++maxSize :: Int -> Size+maxSize n =+#if defined(ASSERTS)+    assert (n >= 0)+#endif+    Between 0 n+{-# INLINE maxSize #-}++betweenSize :: Int -> Int -> Size+betweenSize m n =+#if defined(ASSERTS)+    assert (m >= 0)+    assert (n >= m)+#endif+    Between m n+{-# INLINE betweenSize #-}++unionSize :: Size -> Size -> Size+unionSize (Between a b) (Between c d) = Between (min a c) (max b d)+unionSize _ _ = Unknown++unknownSize :: Size+unknownSize = Unknown+{-# INLINE unknownSize #-}++instance Num Size where+    (+) = addSize+    (-) = subtractSize+    (*) = mulSize++    fromInteger = f where f = exactSize . fromInteger+                          {-# INLINE f #-}++add :: Int -> Int -> Int+add m n | mn >=   0 = mn+        | otherwise = overflowError+  where mn = m + n+{-# INLINE add #-}++addSize :: Size -> Size -> Size+addSize (Between ma mb) (Between na nb) = Between (add ma na) (add mb nb)+addSize _               _               = Unknown+{-# INLINE addSize #-}++subtractSize :: Size -> Size -> Size+subtractSize (Between ma mb) (Between na nb) = Between (max (ma-nb) 0) (max (mb-na) 0)+subtractSize a@(Between 0 _) Unknown         = a+subtractSize (Between _ mb)  Unknown         = Between 0 mb+subtractSize _               _               = Unknown+{-# INLINE subtractSize #-}++mulSize :: Size -> Size -> Size+mulSize (Between ma mb) (Between na nb) = Between (mul ma na) (mul mb nb)+mulSize _               _               = Unknown+{-# INLINE mulSize #-}++-- | Minimum of two size hints.+smaller :: Size -> Size -> Size+smaller a@(Between ma mb) b@(Between na nb)+    | mb <= na  = a+    | nb <= ma  = b+    | otherwise = Between (ma `min` na) (mb `min` nb)+smaller a@(Between 0 _) Unknown         = a+smaller (Between _ mb)  Unknown         = Between 0 mb+smaller Unknown         b@(Between 0 _) = b+smaller Unknown         (Between _ nb)  = Between 0 nb+smaller Unknown         Unknown         = Unknown+{-# INLINE smaller #-}++-- | Maximum of two size hints.+larger :: Size -> Size -> Size+larger a@(Between ma mb) b@(Between na nb)+    | ma >= nb  = a+    | na >= mb  = b+    | otherwise = Between (ma `max` na) (mb `max` nb)+larger _ _ = Unknown+{-# INLINE larger #-}++-- | Compute the maximum size from a size hint, if possible.+upperBound :: Int -> Size -> Int+upperBound _ (Between _ n) = n+upperBound k _             = k+{-# INLINE upperBound #-}++-- | Compute the maximum size from a size hint, if possible.+lowerBound :: Int -> Size -> Int+lowerBound _ (Between n _) = n+lowerBound k _             = k+{-# INLINE lowerBound #-}++-- | Determine the ordering relationship between two 'Size's, or 'Nothing' in+-- the indeterminate case.+compareSize :: Size -> Size -> Maybe Ordering+compareSize (Between ma mb) (Between na nb)+  | mb < na            = Just LT+  | ma > nb            = Just GT+  | ma == mb+  , ma == na+  , ma == nb           = Just EQ+compareSize _ _        = Nothing+++isEmpty :: Size -> Bool+isEmpty (Between _ n) = n <= 0+isEmpty _             = False+{-# INLINE isEmpty #-}++overflowError :: Int+overflowError = error "Data.Text.Internal.Fusion.Size: size overflow"
+ src/Data/Text/Internal/Fusion/Types.hs view
@@ -0,0 +1,122 @@+{-# LANGUAGE BangPatterns, ExistentialQuantification #-}+-- |+-- Module      : Data.Text.Internal.Fusion.Types+-- Copyright   : (c) Tom Harper 2008-2009,+--               (c) Bryan O'Sullivan 2009,+--               (c) Duncan Coutts 2009,+--               (c) Jasper Van der Jeugt 2011+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- Core stream fusion functionality for text.++module Data.Text.Internal.Fusion.Types+    (+      CC(..)+    , PairS(..)+    , Scan(..)+    , RS(..)+    , Step(..)+    , Stream(..)+    , empty+    ) where++import Data.Text.Internal.Fusion.Size+import Data.Word (Word8)++-- | Specialised tuple for case conversion.+data CC s = CC !s {-# UNPACK #-} !Char {-# UNPACK #-} !Char++-- | Restreaming state.+data RS s+    = RS0 !s+    | RS1 !s {-# UNPACK #-} !Word8+    | RS2 !s {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8+    | RS3 !s {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8++-- | Strict pair.+data PairS a b = !a :*: !b+                 -- deriving (Eq, Ord, Show)+infixl 2 :*:++-- | An intermediate result in a scan.+data Scan s = Scan1 {-# UNPACK #-} !Char !s+            | Scan2 {-# UNPACK #-} !Char !s++-- | Intermediate result in a processing pipeline.+data Step s a = Done+              | Skip !s+              | Yield !a !s++{-+instance (Show a) => Show (Step s a)+    where show Done        = "Done"+          show (Skip _)    = "Skip"+          show (Yield x _) = "Yield " ++ show x+-}++instance (Eq a) => Eq (Stream a) where+    (==) = eq++instance (Ord a) => Ord (Stream a) where+    compare = cmp++-- The length hint in a Stream has two roles.  If its value is zero,+-- we trust it, and treat the stream as empty.  Otherwise, we treat it+-- as a hint: it should usually be accurate, so we use it when+-- unstreaming to decide what size array to allocate.  However, the+-- unstreaming functions must be able to cope with the hint being too+-- small or too large.+--+-- The size hint tries to track the UTF-16 code units in a stream,+-- but often counts the number of code points instead.  It can easily+-- undercount if, for instance, a transformed stream contains astral+-- plane code points (those above 0x10000).++data Stream a =+    forall s. Stream+    (s -> Step s a)             -- stepper function+    !s                          -- current state+    !Size                       -- size hint in code units++-- | /O(n)/ Determines if two streams are equal.+eq :: (Eq a) => Stream a -> Stream a -> Bool+eq (Stream next1 s1 _) (Stream next2 s2 _) = loop (next1 s1) (next2 s2)+    where+      loop Done Done                     = True+      loop (Skip s1')     (Skip s2')     = loop (next1 s1') (next2 s2')+      loop (Skip s1')     x2             = loop (next1 s1') x2+      loop x1             (Skip s2')     = loop x1          (next2 s2')+      loop Done _                        = False+      loop _    Done                     = False+      loop (Yield x1 s1') (Yield x2 s2') = x1 == x2 &&+                                           loop (next1 s1') (next2 s2')+{-# INLINE [0] eq #-}++cmp :: (Ord a) => Stream a -> Stream a -> Ordering+cmp (Stream next1 s1 _) (Stream next2 s2 _) = loop (next1 s1) (next2 s2)+    where+      loop Done Done                     = EQ+      loop (Skip s1')     (Skip s2')     = loop (next1 s1') (next2 s2')+      loop (Skip s1')     x2             = loop (next1 s1') x2+      loop x1             (Skip s2')     = loop x1          (next2 s2')+      loop Done _                        = LT+      loop _    Done                     = GT+      loop (Yield x1 s1') (Yield x2 s2') =+          case compare x1 x2 of+            EQ    -> loop (next1 s1') (next2 s2')+            other -> other+{-# INLINE [0] cmp #-}++-- | The empty stream.+empty :: Stream a+empty = Stream next () 0+    where next _ = Done+{-# INLINE [0] empty #-}
+ src/Data/Text/Internal/IO.hs view
@@ -0,0 +1,166 @@+{-# LANGUAGE BangPatterns, RecordWildCards #-}+-- |+-- Module      : Data.Text.Internal.IO+-- Copyright   : (c) 2009, 2010 Bryan O'Sullivan,+--               (c) 2009 Simon Marlow+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- Low-level support for text I\/O.++module Data.Text.Internal.IO+    (+      hGetLineWith+    , readChunk+    ) where++import qualified Control.Exception as E+import Data.IORef (readIORef, writeIORef)+import Data.Text (Text)+import Data.Text.Internal.Fusion (unstream)+import Data.Text.Internal.Fusion.Types (Step(..), Stream(..))+import Data.Text.Internal.Fusion.Size (exactSize, maxSize)+import Data.Text.Unsafe (inlinePerformIO)+import Foreign.Storable (peekElemOff)+import GHC.IO.Buffer (Buffer(..), CharBuffer, RawCharBuffer, bufferAdjustL,+                      bufferElems, charSize, isEmptyBuffer, readCharBuf,+                      withRawBuffer, writeCharBuf)+import GHC.IO.Handle.Internals (ioe_EOF, readTextDevice, wantReadableHandle_)+import GHC.IO.Handle.Types (Handle__(..), Newline(..))+import System.IO (Handle)+import System.IO.Error (isEOFError)+import qualified Data.Text as T++-- | Read a single line of input from a handle, constructing a list of+-- decoded chunks as we go.  When we're done, transform them into the+-- destination type.+hGetLineWith :: ([Text] -> t) -> Handle -> IO t+hGetLineWith f h = wantReadableHandle_ "hGetLine" h go+  where+    go hh@Handle__{..} = readIORef haCharBuffer >>= fmap f . hGetLineLoop hh []++hGetLineLoop :: Handle__ -> [Text] -> CharBuffer -> IO [Text]+hGetLineLoop hh@Handle__{..} = go where+ go ts buf@Buffer{ bufL=r0, bufR=w, bufRaw=raw0 } = do+  let findEOL raw r | r == w    = return (False, w)+                    | otherwise = do+        (c,r') <- readCharBuf raw r+        if c == '\n'+          then return (True, r)+          else findEOL raw r'+  (eol, off) <- findEOL raw0 r0+  (t,r') <- if haInputNL == CRLF+            then unpack_nl raw0 r0 off+            else do t <- unpack raw0 r0 off+                    return (t,off)+  if eol+    then do writeIORef haCharBuffer (bufferAdjustL (off+1) buf)+            return $ reverse (t:ts)+    else do+      let buf1 = bufferAdjustL r' buf+      maybe_buf <- maybeFillReadBuffer hh buf1+      case maybe_buf of+         -- Nothing indicates we caught an EOF, and we may have a+         -- partial line to return.+         Nothing -> do+              -- we reached EOF.  There might be a lone \r left+              -- in the buffer, so check for that and+              -- append it to the line if necessary.+              let pre | isEmptyBuffer buf1 = T.empty+                      | otherwise          = T.singleton '\r'+              writeIORef haCharBuffer buf1{ bufL=0, bufR=0 }+              let str = reverse . filter (not . T.null) $ pre:t:ts+              if null str+                then ioe_EOF+                else return str+         Just new_buf -> go (t:ts) new_buf++-- This function is lifted almost verbatim from GHC.IO.Handle.Text.+maybeFillReadBuffer :: Handle__ -> CharBuffer -> IO (Maybe CharBuffer)+maybeFillReadBuffer handle_ buf+  = E.catch (Just `fmap` getSomeCharacters handle_ buf) $ \e ->+      if isEOFError e+      then return Nothing+      else ioError e++unpack :: RawCharBuffer -> Int -> Int -> IO Text+unpack !buf !r !w+ | charSize /= 4 = sizeError "unpack"+ | r >= w        = return T.empty+ | otherwise     = withRawBuffer buf go+ where+  go pbuf = return $! unstream (Stream next r (exactSize (w-r)))+   where+    next !i | i >= w    = Done+            | otherwise = Yield (ix i) (i+1)+    ix i = inlinePerformIO $ peekElemOff pbuf i++unpack_nl :: RawCharBuffer -> Int -> Int -> IO (Text, Int)+unpack_nl !buf !r !w+ | charSize /= 4 = sizeError "unpack_nl"+ | r >= w        = return (T.empty, 0)+ | otherwise     = withRawBuffer buf $ go+ where+  go pbuf = do+    let !t = unstream (Stream next r (maxSize (w-r)))+        w' = w - 1+    return $ if ix w' == '\r'+             then (t,w')+             else (t,w)+   where+    next !i | i >= w = Done+            | c == '\r' = let i' = i + 1+                          in if i' < w+                             then if ix i' == '\n'+                                  then Yield '\n' (i+2)+                                  else Yield '\n' i'+                             else Done+            | otherwise = Yield c (i+1)+            where c = ix i+    ix i = inlinePerformIO $ peekElemOff pbuf i++-- This function is completely lifted from GHC.IO.Handle.Text.+getSomeCharacters :: Handle__ -> CharBuffer -> IO CharBuffer+getSomeCharacters handle_@Handle__{..} buf@Buffer{..} =+  case bufferElems buf of+    -- buffer empty: read some more+    0 -> {-# SCC "readTextDevice" #-} readTextDevice handle_ buf++    -- if the buffer has a single '\r' in it and we're doing newline+    -- translation: read some more+    1 | haInputNL == CRLF -> do+      (c,_) <- readCharBuf bufRaw bufL+      if c == '\r'+         then do -- shuffle the '\r' to the beginning.  This is only safe+                 -- if we're about to call readTextDevice, otherwise it+                 -- would mess up flushCharBuffer.+                 -- See [note Buffer Flushing], GHC.IO.Handle.Types+                 _ <- writeCharBuf bufRaw 0 '\r'+                 let buf' = buf{ bufL=0, bufR=1 }+                 readTextDevice handle_ buf'+         else do+                 return buf++    -- buffer has some chars in it already: just return it+    _otherwise -> {-# SCC "otherwise" #-} return buf++-- | Read a single chunk of strict text from a buffer. Used by both+-- the strict and lazy implementations of hGetContents.+readChunk :: Handle__ -> CharBuffer -> IO Text+readChunk hh@Handle__{..} buf = do+  buf'@Buffer{..} <- getSomeCharacters hh buf+  (t,r) <- if haInputNL == CRLF+           then unpack_nl bufRaw bufL bufR+           else do t <- unpack bufRaw bufL bufR+                   return (t,bufR)+  writeIORef haCharBuffer (bufferAdjustL r buf')+  return t++sizeError :: String -> a+sizeError loc = error $ "Data.Text.IO." ++ loc ++ ": bad internal buffer size"
+ src/Data/Text/Internal/Lazy.hs view
@@ -0,0 +1,119 @@+{-# LANGUAGE BangPatterns, DeriveDataTypeable #-}+{-# OPTIONS_HADDOCK not-home #-}++-- |+-- Module      : Data.Text.Internal.Lazy+-- Copyright   : (c) 2009, 2010 Bryan O'Sullivan+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- A module containing private 'Text' internals. This exposes the+-- 'Text' representation and low level construction functions.+-- Modules which extend the 'Text' system may need to use this module.++module Data.Text.Internal.Lazy+    (+      Text(..)+    , chunk+    , empty+    , foldrChunks+    , foldlChunks+    -- * Data type invariant and abstraction functions++    -- $invariant+    , strictInvariant+    , lazyInvariant+    , showStructure++    -- * Chunk allocation sizes+    , defaultChunkSize+    , smallChunkSize+    , chunkOverhead+    ) where++import Data.Text ()+import Data.Text.Internal.Unsafe.Shift (shiftL)+import Data.Typeable (Typeable)+import Foreign.Storable (sizeOf)+import qualified Data.Text.Internal as T++data Text = Empty+          | Chunk {-# UNPACK #-} !T.Text Text+            deriving (Typeable)++-- $invariant+--+-- The data type invariant for lazy 'Text': Every 'Text' is either 'Empty' or+-- consists of non-null 'T.Text's.  All functions must preserve this,+-- and the QC properties must check this.++-- | Check the invariant strictly.+strictInvariant :: Text -> Bool+strictInvariant Empty = True+strictInvariant x@(Chunk (T.Text _ _ len) cs)+    | len > 0   = strictInvariant cs+    | otherwise = error $ "Data.Text.Lazy: invariant violation: "+                  ++ showStructure x++-- | Check the invariant lazily.+lazyInvariant :: Text -> Text+lazyInvariant Empty = Empty+lazyInvariant x@(Chunk c@(T.Text _ _ len) cs)+    | len > 0   = Chunk c (lazyInvariant cs)+    | otherwise = error $ "Data.Text.Lazy: invariant violation: "+                  ++ showStructure x++-- | Display the internal structure of a lazy 'Text'.+showStructure :: Text -> String+showStructure Empty           = "Empty"+showStructure (Chunk t Empty) = "Chunk " ++ show t ++ " Empty"+showStructure (Chunk t ts)    =+    "Chunk " ++ show t ++ " (" ++ showStructure ts ++ ")"++-- | Smart constructor for 'Chunk'. Guarantees the data type invariant.+chunk :: T.Text -> Text -> Text+{-# INLINE chunk #-}+chunk t@(T.Text _ _ len) ts | len == 0 = ts+                            | otherwise = Chunk t ts++-- | Smart constructor for 'Empty'.+empty :: Text+{-# INLINE [0] empty #-}+empty = Empty++-- | Consume the chunks of a lazy 'Text' with a natural right fold.+foldrChunks :: (T.Text -> a -> a) -> a -> Text -> a+foldrChunks f z = go+  where go Empty        = z+        go (Chunk c cs) = f c (go cs)+{-# INLINE foldrChunks #-}++-- | Consume the chunks of a lazy 'Text' with a strict, tail-recursive,+-- accumulating left fold.+foldlChunks :: (a -> T.Text -> a) -> a -> Text -> a+foldlChunks f z = go z+  where go !a Empty        = a+        go !a (Chunk c cs) = go (f a c) cs+{-# INLINE foldlChunks #-}++-- | Currently set to 16 KiB, less the memory management overhead.+defaultChunkSize :: Int+defaultChunkSize = 16384 - chunkOverhead+{-# INLINE defaultChunkSize #-}++-- | Currently set to 128 bytes, less the memory management overhead.+smallChunkSize :: Int+smallChunkSize = 128 - chunkOverhead+{-# INLINE smallChunkSize #-}++-- | The memory management overhead. Currently this is tuned for GHC only.+chunkOverhead :: Int+chunkOverhead = sizeOf (undefined :: Int) `shiftL` 1+{-# INLINE chunkOverhead #-}
+ src/Data/Text/Internal/Lazy/Encoding/Fusion.hs view
@@ -0,0 +1,324 @@+{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}++-- |+-- Module      : Data.Text.Lazy.Encoding.Fusion+-- Copyright   : (c) 2009, 2010 Bryan O'Sullivan+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : portable+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- Fusible 'Stream'-oriented functions for converting between lazy+-- 'Text' and several common encodings.++module Data.Text.Internal.Lazy.Encoding.Fusion+    (+    -- * Streaming+    --  streamASCII+      streamUtf8+    , streamUtf16LE+    , streamUtf16BE+    , streamUtf32LE+    , streamUtf32BE++    -- * Unstreaming+    , unstream++    , module Data.Text.Internal.Encoding.Fusion.Common+    ) where++import Data.ByteString.Lazy.Internal (ByteString(..), defaultChunkSize)+import qualified Data.ByteString as B+import qualified Data.ByteString.Unsafe as B+import Data.Text.Internal.Encoding.Fusion.Common+import Data.Text.Encoding.Error+import Data.Text.Internal.Fusion (Step(..), Stream(..))+import Data.Text.Internal.Fusion.Size+import Data.Text.Internal.Unsafe.Char (unsafeChr, unsafeChr8, unsafeChr32)+import Data.Text.Internal.Unsafe.Shift (shiftL)+import Data.Word (Word8, Word16, Word32)+import qualified Data.Text.Internal.Encoding.Utf8 as U8+import qualified Data.Text.Internal.Encoding.Utf16 as U16+import qualified Data.Text.Internal.Encoding.Utf32 as U32+import Data.Text.Unsafe (unsafeDupablePerformIO)+import Foreign.ForeignPtr (withForeignPtr, ForeignPtr)+import Foreign.Storable (pokeByteOff)+import Data.ByteString.Internal (mallocByteString, memcpy)+#if defined(ASSERTS)+import Control.Exception (assert)+#endif+import Data.Text.Internal.ByteStringCompat++data S = S0+       | S1 {-# UNPACK #-} !Word8+       | S2 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8+       | S3 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8+       | S4 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8 {-# UNPACK #-} !Word8++data T = T !ByteString !S {-# UNPACK #-} !Int++-- | /O(n)/ Convert a lazy 'ByteString' into a 'Stream Char', using+-- UTF-8 encoding.+streamUtf8 :: OnDecodeError -> ByteString -> Stream Char+streamUtf8 onErr bs0 = Stream next (T bs0 S0 0) unknownSize+  where+    next (T bs@(Chunk ps _) S0 i)+      | i < len && U8.validate1 a =+          Yield (unsafeChr8 a)    (T bs S0 (i+1))+      | i + 1 < len && U8.validate2 a b =+          Yield (U8.chr2 a b)     (T bs S0 (i+2))+      | i + 2 < len && U8.validate3 a b c =+          Yield (U8.chr3 a b c)   (T bs S0 (i+3))+      | i + 3 < len && U8.validate4 a b c d =+          Yield (U8.chr4 a b c d) (T bs S0 (i+4))+      where len = B.length ps+            a = B.unsafeIndex ps i+            b = B.unsafeIndex ps (i+1)+            c = B.unsafeIndex ps (i+2)+            d = B.unsafeIndex ps (i+3)+    next st@(T bs s i) =+      case s of+        S1 a       | U8.validate1 a       -> Yield (unsafeChr8 a)    es+        S2 a b     | U8.validate2 a b     -> Yield (U8.chr2 a b)     es+        S3 a b c   | U8.validate3 a b c   -> Yield (U8.chr3 a b c)   es+        S4 a b c d | U8.validate4 a b c d -> Yield (U8.chr4 a b c d) es+        _ -> consume st+       where es = T bs S0 i+    consume (T bs@(Chunk ps rest) s i)+        | i >= B.length ps = consume (T rest s 0)+        | otherwise =+      case s of+        S0         -> next (T bs (S1 x)       (i+1))+        S1 a       -> next (T bs (S2 a x)     (i+1))+        S2 a b     -> next (T bs (S3 a b x)   (i+1))+        S3 a b c   -> next (T bs (S4 a b c x) (i+1))+        S4 a b c d -> decodeError "streamUtf8" "UTF-8" onErr (Just a)+                           (T bs (S3 b c d)   (i+1))+        where x = B.unsafeIndex ps i+    consume (T Empty S0 _) = Done+    consume st             = decodeError "streamUtf8" "UTF-8" onErr Nothing st+{-# INLINE [0] streamUtf8 #-}++-- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using little+-- endian UTF-16 encoding.+streamUtf16LE :: OnDecodeError -> ByteString -> Stream Char+streamUtf16LE onErr bs0 = Stream next (T bs0 S0 0) unknownSize+  where+    next (T bs@(Chunk ps _) S0 i)+      | i + 1 < len && U16.validate1 x1 =+          Yield (unsafeChr x1)         (T bs S0 (i+2))+      | i + 3 < len && U16.validate2 x1 x2 =+          Yield (U16.chr2 x1 x2)       (T bs S0 (i+4))+      where len = B.length ps+            x1   = c (idx  i)      (idx (i + 1))+            x2   = c (idx (i + 2)) (idx (i + 3))+            c w1 w2 = w1 + (w2 `shiftL` 8)+            idx = fromIntegral . B.unsafeIndex ps :: Int -> Word16+    next st@(T bs s i) =+      case s of+        S2 w1 w2       | U16.validate1 (c w1 w2)           ->+          Yield (unsafeChr (c w1 w2))   es+        S4 w1 w2 w3 w4 | U16.validate2 (c w1 w2) (c w3 w4) ->+          Yield (U16.chr2 (c w1 w2) (c w3 w4)) es+        _ -> consume st+       where es = T bs S0 i+             c :: Word8 -> Word8 -> Word16+             c w1 w2 = fromIntegral w1 + (fromIntegral w2 `shiftL` 8)+    consume (T bs@(Chunk ps rest) s i)+        | i >= B.length ps = consume (T rest s 0)+        | otherwise =+      case s of+        S0             -> next (T bs (S1 x)          (i+1))+        S1 w1          -> next (T bs (S2 w1 x)       (i+1))+        S2 w1 w2       -> next (T bs (S3 w1 w2 x)    (i+1))+        S3 w1 w2 w3    -> next (T bs (S4 w1 w2 w3 x) (i+1))+        S4 w1 w2 w3 w4 -> decodeError "streamUtf16LE" "UTF-16LE" onErr (Just w1)+                           (T bs (S3 w2 w3 w4)       (i+1))+        where x = B.unsafeIndex ps i+    consume (T Empty S0 _) = Done+    consume st             = decodeError "streamUtf16LE" "UTF-16LE" onErr Nothing st+{-# INLINE [0] streamUtf16LE #-}++-- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using big+-- endian UTF-16 encoding.+streamUtf16BE :: OnDecodeError -> ByteString -> Stream Char+streamUtf16BE onErr bs0 = Stream next (T bs0 S0 0) unknownSize+  where+    next (T bs@(Chunk ps _) S0 i)+      | i + 1 < len && U16.validate1 x1 =+          Yield (unsafeChr x1)         (T bs S0 (i+2))+      | i + 3 < len && U16.validate2 x1 x2 =+          Yield (U16.chr2 x1 x2)       (T bs S0 (i+4))+      where len = B.length ps+            x1   = c (idx  i)      (idx (i + 1))+            x2   = c (idx (i + 2)) (idx (i + 3))+            c w1 w2 = (w1 `shiftL` 8) + w2+            idx = fromIntegral . B.unsafeIndex ps :: Int -> Word16+    next st@(T bs s i) =+      case s of+        S2 w1 w2       | U16.validate1 (c w1 w2)           ->+          Yield (unsafeChr (c w1 w2))   es+        S4 w1 w2 w3 w4 | U16.validate2 (c w1 w2) (c w3 w4) ->+          Yield (U16.chr2 (c w1 w2) (c w3 w4)) es+        _ -> consume st+       where es = T bs S0 i+             c :: Word8 -> Word8 -> Word16+             c w1 w2 = (fromIntegral w1 `shiftL` 8) + fromIntegral w2+    consume (T bs@(Chunk ps rest) s i)+        | i >= B.length ps = consume (T rest s 0)+        | otherwise =+      case s of+        S0             -> next (T bs (S1 x)          (i+1))+        S1 w1          -> next (T bs (S2 w1 x)       (i+1))+        S2 w1 w2       -> next (T bs (S3 w1 w2 x)    (i+1))+        S3 w1 w2 w3    -> next (T bs (S4 w1 w2 w3 x) (i+1))+        S4 w1 w2 w3 w4 -> decodeError "streamUtf16BE" "UTF-16BE" onErr (Just w1)+                           (T bs (S3 w2 w3 w4)       (i+1))+        where x = B.unsafeIndex ps i+    consume (T Empty S0 _) = Done+    consume st             = decodeError "streamUtf16BE" "UTF-16BE" onErr Nothing st+{-# INLINE [0] streamUtf16BE #-}++-- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using big+-- endian UTF-32 encoding.+streamUtf32BE :: OnDecodeError -> ByteString -> Stream Char+streamUtf32BE onErr bs0 = Stream next (T bs0 S0 0) unknownSize+  where+    next (T bs@(Chunk ps _) S0 i)+      | i + 3 < len && U32.validate x =+          Yield (unsafeChr32 x)       (T bs S0 (i+4))+      where len = B.length ps+            x = shiftL x1 24 + shiftL x2 16 + shiftL x3 8 + x4+            x1    = idx i+            x2    = idx (i+1)+            x3    = idx (i+2)+            x4    = idx (i+3)+            idx = fromIntegral . B.unsafeIndex ps :: Int -> Word32+    next st@(T bs s i) =+      case s of+        S4 w1 w2 w3 w4 | U32.validate (c w1 w2 w3 w4) ->+          Yield (unsafeChr32 (c w1 w2 w3 w4)) es+        _ -> consume st+       where es = T bs S0 i+             c :: Word8 -> Word8 -> Word8 -> Word8 -> Word32+             c w1 w2 w3 w4 = shifted+              where+               shifted = shiftL x1 24 + shiftL x2 16 + shiftL x3 8 + x4+               x1 = fromIntegral w1+               x2 = fromIntegral w2+               x3 = fromIntegral w3+               x4 = fromIntegral w4+    consume (T bs@(Chunk ps rest) s i)+        | i >= B.length ps = consume (T rest s 0)+        | otherwise =+      case s of+        S0             -> next (T bs (S1 x)          (i+1))+        S1 w1          -> next (T bs (S2 w1 x)       (i+1))+        S2 w1 w2       -> next (T bs (S3 w1 w2 x)    (i+1))+        S3 w1 w2 w3    -> next (T bs (S4 w1 w2 w3 x) (i+1))+        S4 w1 w2 w3 w4 -> decodeError "streamUtf32BE" "UTF-32BE" onErr (Just w1)+                           (T bs (S3 w2 w3 w4)       (i+1))+        where x = B.unsafeIndex ps i+    consume (T Empty S0 _) = Done+    consume st             = decodeError "streamUtf32BE" "UTF-32BE" onErr Nothing st+{-# INLINE [0] streamUtf32BE #-}++-- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using little+-- endian UTF-32 encoding.+streamUtf32LE :: OnDecodeError -> ByteString -> Stream Char+streamUtf32LE onErr bs0 = Stream next (T bs0 S0 0) unknownSize+  where+    next (T bs@(Chunk ps _) S0 i)+      | i + 3 < len && U32.validate x =+          Yield (unsafeChr32 x)       (T bs S0 (i+4))+      where len = B.length ps+            x = shiftL x4 24 + shiftL x3 16 + shiftL x2 8 + x1+            x1    = idx i+            x2    = idx (i+1)+            x3    = idx (i+2)+            x4    = idx (i+3)+            idx = fromIntegral . B.unsafeIndex ps :: Int -> Word32+    next st@(T bs s i) =+      case s of+        S4 w1 w2 w3 w4 | U32.validate (c w1 w2 w3 w4) ->+          Yield (unsafeChr32 (c w1 w2 w3 w4)) es+        _ -> consume st+       where es = T bs S0 i+             c :: Word8 -> Word8 -> Word8 -> Word8 -> Word32+             c w1 w2 w3 w4 = shifted+              where+               shifted = shiftL x4 24 + shiftL x3 16 + shiftL x2 8 + x1+               x1 = fromIntegral w1+               x2 = fromIntegral w2+               x3 = fromIntegral w3+               x4 = fromIntegral w4+    consume (T bs@(Chunk ps rest) s i)+        | i >= B.length ps = consume (T rest s 0)+        | otherwise =+      case s of+        S0             -> next (T bs (S1 x)          (i+1))+        S1 w1          -> next (T bs (S2 w1 x)       (i+1))+        S2 w1 w2       -> next (T bs (S3 w1 w2 x)    (i+1))+        S3 w1 w2 w3    -> next (T bs (S4 w1 w2 w3 x) (i+1))+        S4 w1 w2 w3 w4 -> decodeError "streamUtf32LE" "UTF-32LE" onErr (Just w1)+                           (T bs (S3 w2 w3 w4)       (i+1))+        where x = B.unsafeIndex ps i+    consume (T Empty S0 _) = Done+    consume st             = decodeError "streamUtf32LE" "UTF-32LE" onErr Nothing st+{-# INLINE [0] streamUtf32LE #-}++-- | /O(n)/ Convert a 'Stream' 'Word8' to a lazy 'ByteString'.+unstreamChunks :: Int -> Stream Word8 -> ByteString+unstreamChunks chunkSize (Stream next s0 len0) = chunk s0 (upperBound 4 len0)+  where chunk s1 len1 = unsafeDupablePerformIO $ do+          let len = max 4 (min len1 chunkSize)+          mallocByteString len >>= loop len 0 s1+          where+            loop !n !off !s fp = case next s of+                Done | off == 0 -> return Empty+                     | otherwise -> return $! Chunk (trimUp fp off) Empty+                Skip s' -> loop n off s' fp+                Yield x s'+                    | off == chunkSize -> do+                      let !newLen = n - off+                      return $! Chunk (trimUp fp off) (chunk s newLen)+                    | off == n -> realloc fp n off s' x+                    | otherwise -> do+                      withForeignPtr fp $ \p -> pokeByteOff p off x+                      loop n (off+1) s' fp+            {-# NOINLINE realloc #-}+            realloc fp n off s x = do+              let n' = min (n+n) chunkSize+              fp' <- copy0 fp n n'+              withForeignPtr fp' $ \p -> pokeByteOff p off x+              loop n' (off+1) s fp'+            trimUp fp off = mkBS fp off+            copy0 :: ForeignPtr Word8 -> Int -> Int -> IO (ForeignPtr Word8)+            copy0 !src !srcLen !destLen =+#if defined(ASSERTS)+              assert (srcLen <= destLen) $+#endif+              do+                dest <- mallocByteString destLen+                withForeignPtr src  $ \src'  ->+                    withForeignPtr dest $ \dest' ->+                        memcpy dest' src' (fromIntegral srcLen)+                return dest++-- | /O(n)/ Convert a 'Stream' 'Word8' to a lazy 'ByteString'.+unstream :: Stream Word8 -> ByteString+unstream = unstreamChunks defaultChunkSize++decodeError :: forall s. String -> String -> OnDecodeError -> Maybe Word8+            -> s -> Step s Char+decodeError func kind onErr mb i =+    case onErr desc mb of+      Nothing -> Skip i+      Just c  -> Yield c i+    where desc = "Data.Text.Lazy.Encoding.Fusion." ++ func ++ ": Invalid " +++                 kind ++ " stream"
+ src/Data/Text/Internal/Lazy/Fusion.hs view
@@ -0,0 +1,120 @@+{-# LANGUAGE BangPatterns #-}+-- |+-- Module      : Data.Text.Lazy.Fusion+-- Copyright   : (c) 2009, 2010 Bryan O'Sullivan+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- Core stream fusion functionality for text.++module Data.Text.Internal.Lazy.Fusion+    (+      stream+    , unstream+    , unstreamChunks+    , length+    , unfoldrN+    , index+    , countChar+    ) where++import Prelude hiding (length)+import qualified Data.Text.Internal.Fusion.Common as S+import Control.Monad.ST (runST)+import Data.Text.Internal.Fusion.Types+import Data.Text.Internal.Fusion.Size (isEmpty, unknownSize)+import Data.Text.Internal.Lazy+import qualified Data.Text.Internal as I+import qualified Data.Text.Array as A+import Data.Text.Internal.Unsafe.Char (unsafeWrite)+import Data.Text.Internal.Unsafe.Shift (shiftL)+import Data.Text.Unsafe (Iter(..), iter)+import Data.Int (Int64)++default(Int64)++-- | /O(n)/ Convert a 'Text' into a 'Stream Char'.+stream :: Text -> Stream Char+stream text = Stream next (text :*: 0) unknownSize+  where+    next (Empty :*: _) = Done+    next (txt@(Chunk t@(I.Text _ _ len) ts) :*: i)+        | i >= len  = next (ts :*: 0)+        | otherwise = Yield c (txt :*: i+d)+        where Iter c d = iter t i+{-# INLINE [0] stream #-}++-- | /O(n)/ Convert a 'Stream Char' into a 'Text', using the given+-- chunk size.+unstreamChunks :: Int -> Stream Char -> Text+unstreamChunks !chunkSize (Stream next s0 len0)+  | isEmpty len0 = Empty+  | otherwise    = outer s0+  where+    outer so = {-# SCC "unstreamChunks/outer" #-}+              case next so of+                Done       -> Empty+                Skip s'    -> outer s'+                Yield x s' -> runST $ do+                                a <- A.new unknownLength+                                unsafeWrite a 0 x >>= inner a unknownLength s'+                    where unknownLength = 4+      where+        inner marr !len s !i+            | i + 1 >= chunkSize = finish marr i s+            | i + 1 >= len       = {-# SCC "unstreamChunks/resize" #-} do+                let newLen = min (len `shiftL` 1) chunkSize+                marr' <- A.new newLen+                A.copyM marr' 0 marr 0 len+                inner marr' newLen s i+            | otherwise =+                {-# SCC "unstreamChunks/inner" #-}+                case next s of+                  Done        -> finish marr i s+                  Skip s'     -> inner marr len s' i+                  Yield x s'  -> do d <- unsafeWrite marr i x+                                    inner marr len s' (i+d)+        finish marr len s' = do+          arr <- A.unsafeFreeze marr+          return (I.Text arr 0 len `Chunk` outer s')+{-# INLINE [0] unstreamChunks #-}++-- | /O(n)/ Convert a 'Stream Char' into a 'Text', using+-- 'defaultChunkSize'.+unstream :: Stream Char -> Text+unstream = unstreamChunks defaultChunkSize+{-# INLINE [0] unstream #-}++-- | /O(n)/ Returns the number of characters in a text.+length :: Stream Char -> Int64+length = S.lengthI+{-# INLINE[0] length #-}++{-# RULES "LAZY STREAM stream/unstream fusion" forall s.+    stream (unstream s) = s #-}++-- | /O(n)/ Like 'unfoldr', 'unfoldrN' builds a stream from a seed+-- value. However, the length of the result is limited by the+-- first argument to 'unfoldrN'. This function is more efficient than+-- 'unfoldr' when the length of the result is known.+unfoldrN :: Int64 -> (a -> Maybe (Char,a)) -> a -> Stream Char+unfoldrN n = S.unfoldrNI n+{-# INLINE [0] unfoldrN #-}++-- | /O(n)/ stream index (subscript) operator, starting from 0.+index :: Stream Char -> Int64 -> Char+index = S.indexI+{-# INLINE [0] index #-}++-- | /O(n)/ The 'count' function returns the number of times the query+-- element appears in the given stream.+countChar :: Char -> Stream Char -> Int64+countChar = S.countCharI+{-# INLINE [0] countChar #-}
+ src/Data/Text/Internal/Lazy/Search.hs view
@@ -0,0 +1,134 @@+{-# LANGUAGE BangPatterns, ScopedTypeVariables #-}++-- |+-- Module      : Data.Text.Lazy.Search+-- Copyright   : (c) 2009, 2010 Bryan O'Sullivan+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- Fast substring search for lazy 'Text', based on work by Boyer,+-- Moore, Horspool, Sunday, and Lundh.  Adapted from the strict+-- implementation.++module Data.Text.Internal.Lazy.Search+    (+      indices+    ) where++import qualified Data.Text.Array as A+import Data.Int (Int64)+import Data.Word (Word16, Word64)+import qualified Data.Text.Internal as T+import Data.Text.Internal.Fusion.Types (PairS(..))+import Data.Text.Internal.Lazy (Text(..), foldlChunks)+import Data.Bits ((.|.), (.&.))+import Data.Text.Internal.Unsafe.Shift (shiftL)++-- | /O(n+m)/ Find the offsets of all non-overlapping indices of+-- @needle@ within @haystack@.+--+-- This function is strict in @needle@, and lazy (as far as possible)+-- in the chunks of @haystack@.+--+-- In (unlikely) bad cases, this algorithm's complexity degrades+-- towards /O(n*m)/.+indices :: Text              -- ^ Substring to search for (@needle@)+        -> Text              -- ^ Text to search in (@haystack@)+        -> [Int64]+indices needle@(Chunk n ns) _haystack@(Chunk k ks)+    | nlen <= 0  = []+    | nlen == 1  = indicesOne (nindex 0) 0 k ks+    | otherwise  = advance k ks 0 0+  where+    advance x@(T.Text _ _ l) xs = scan+     where+      scan !g !i+         | i >= m = case xs of+                      Empty           -> []+                      Chunk y ys      -> advance y ys g (i-m)+         | lackingHay (i + nlen) x xs  = []+         | c == z && candidateMatch 0  = g : scan (g+nlen) (i+nlen)+         | otherwise                   = scan (g+delta) (i+delta)+       where+         m = fromIntegral l+         c = hindex (i + nlast)+         delta | nextInPattern = nlen + 1+               | c == z        = skip + 1+               | otherwise     = 1+         nextInPattern         = mask .&. swizzle (hindex (i+nlen)) == 0+         candidateMatch !j+             | j >= nlast               = True+             | hindex (i+j) /= nindex j = False+             | otherwise                = candidateMatch (j+1)+         hindex                         = index x xs+    nlen      = wordLength needle+    nlast     = nlen - 1+    nindex    = index n ns+    z         = foldlChunks fin 0 needle+        where fin _ (T.Text farr foff flen) = A.unsafeIndex farr (foff+flen-1)+    (mask :: Word64) :*: skip = buildTable n ns 0 0 0 (nlen-2)+    swizzle w = 1 `shiftL` (fromIntegral w .&. 0x3f)+    buildTable (T.Text xarr xoff xlen) xs = go+      where+        go !(g::Int64) !i !msk !skp+            | i >= xlast = case xs of+                             Empty      -> (msk .|. swizzle z) :*: skp+                             Chunk y ys -> buildTable y ys g 0 msk' skp'+            | otherwise = go (g+1) (i+1) msk' skp'+            where c                = A.unsafeIndex xarr (xoff+i)+                  msk'             = msk .|. swizzle c+                  skp' | c == z    = nlen - g - 2+                       | otherwise = skp+                  xlast = xlen - 1+    -- | Check whether an attempt to index into the haystack at the+    -- given offset would fail.+    lackingHay q = go 0+      where+        go p (T.Text _ _ l) ps = p' < q && case ps of+                                             Empty      -> True+                                             Chunk r rs -> go p' r rs+            where p' = p + fromIntegral l+indices _ _ = []++-- | Fast index into a partly unpacked 'Text'.  We take into account+-- the possibility that the caller might try to access one element+-- past the end.+index :: T.Text -> Text -> Int64 -> Word16+index (T.Text arr off len) xs !i+    | j < len   = A.unsafeIndex arr (off+j)+    | otherwise = case xs of+                    Empty+                        -- out of bounds, but legal+                        | j == len  -> 0+                        -- should never happen, due to lackingHay above+                        | otherwise -> emptyError "index"+                    Chunk c cs -> index c cs (i-fromIntegral len)+    where j = fromIntegral i++-- | A variant of 'indices' that scans linearly for a single 'Word16'.+indicesOne :: Word16 -> Int64 -> T.Text -> Text -> [Int64]+indicesOne c = chunk+  where+    chunk !i (T.Text oarr ooff olen) os = go 0+      where+        go h | h >= olen = case os of+                             Empty      -> []+                             Chunk y ys -> chunk (i+fromIntegral olen) y ys+             | on == c = i + fromIntegral h : go (h+1)+             | otherwise = go (h+1)+             where on = A.unsafeIndex oarr (ooff+h)++-- | The number of 'Word16' values in a 'Text'.+wordLength :: Text -> Int64+wordLength = foldlChunks sumLength 0+    where sumLength i (T.Text _ _ l) = i + fromIntegral l++emptyError :: String -> a+emptyError fun = error ("Data.Text.Lazy.Search." ++ fun ++ ": empty input")
+ src/Data/Text/Internal/Private.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE BangPatterns, Rank2Types, UnboxedTuples #-}++-- |+-- Module      : Data.Text.Internal.Private+-- Copyright   : (c) 2011 Bryan O'Sullivan+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC++module Data.Text.Internal.Private+    (+      runText+    , span_+    ) where++import Control.Monad.ST (ST, runST)+import Data.Text.Internal (Text(..), text)+import Data.Text.Unsafe (Iter(..), iter)+import qualified Data.Text.Array as A++span_ :: (Char -> Bool) -> Text -> (# Text, Text #)+span_ p t@(Text arr off len) = (# hd,tl #)+  where hd = text arr off k+        tl = text arr (off+k) (len-k)+        !k = loop 0+        loop !i | i < len && p c = loop (i+d)+                | otherwise      = i+            where Iter c d       = iter t i+{-# INLINE span_ #-}++runText :: (forall s. (A.MArray s -> Int -> ST s Text) -> ST s Text) -> Text+runText act = runST (act $ \ !marr !len -> do+                             arr <- A.unsafeFreeze marr+                             return $! text arr 0 len)+{-# INLINE runText #-}
+ src/Data/Text/Internal/Read.hs view
@@ -0,0 +1,69 @@+-- |+-- Module      : Data.Text.Internal.Read+-- Copyright   : (c) 2014 Bryan O'Sullivan+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- Common internal functions for reading textual data.+module Data.Text.Internal.Read+    (+      IReader+    , IParser(..)+    , T(..)+    , digitToInt+    , hexDigitToInt+    , perhaps+    ) where++import Control.Applicative as App (Applicative(..))+import Control.Arrow (first)+import Control.Monad (ap)+import Data.Char (ord)++type IReader t a = t -> Either String (a,t)++newtype IParser t a = P {+      runP :: IReader t a+    }++instance Functor (IParser t) where+    fmap f m = P $ fmap (first f) . runP m++instance Applicative (IParser t) where+    pure a = P $ \t -> Right (a,t)+    {-# INLINE pure #-}+    (<*>) = ap++instance Monad (IParser t) where+    return = App.pure+    m >>= k  = P $ \t -> case runP m t of+                           Left err     -> Left err+                           Right (a,t') -> runP (k a) t'+    {-# INLINE (>>=) #-}++-- If we ever need a `MonadFail` instance the definition below can be used+--+-- > instance MonadFail (IParser t) where+-- >   fail msg = P $ \_ -> Left msg+--+-- But given the code compiles fine with a post-MFP GHC 8.6+ we don't need+-- one just yet.++data T = T !Integer !Int++perhaps :: a -> IParser t a -> IParser t a+perhaps def m = P $ \t -> case runP m t of+                            Left _      -> Right (def,t)+                            r@(Right _) -> r++hexDigitToInt :: Char -> Int+hexDigitToInt c+    | c >= '0' && c <= '9' = ord c - ord '0'+    | c >= 'a' && c <= 'f' = ord c - (ord 'a' - 10)+    | otherwise            = ord c - (ord 'A' - 10)++digitToInt :: Char -> Int+digitToInt c = ord c - ord '0'
+ src/Data/Text/Internal/Search.hs view
@@ -0,0 +1,89 @@+{-# LANGUAGE BangPatterns, ScopedTypeVariables #-}++-- |+-- Module      : Data.Text.Internal.Search+-- Copyright   : (c) Bryan O'Sullivan 2009+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- Fast substring search for 'Text', based on work by Boyer, Moore,+-- Horspool, Sunday, and Lundh.+--+-- References:+--+-- * R. S. Boyer, J. S. Moore: A Fast String Searching Algorithm.+--   Communications of the ACM, 20, 10, 762-772 (1977)+--+-- * R. N. Horspool: Practical Fast Searching in Strings.  Software -+--   Practice and Experience 10, 501-506 (1980)+--+-- * D. M. Sunday: A Very Fast Substring Search Algorithm.+--   Communications of the ACM, 33, 8, 132-142 (1990)+--+-- * F. Lundh: The Fast Search Algorithm.+--   <http://effbot.org/zone/stringlib.htm> (2006)++module Data.Text.Internal.Search+    (+      indices+    ) where++import qualified Data.Text.Array as A+import Data.Word (Word64)+import Data.Text.Internal (Text(..))+import Data.Bits ((.|.), (.&.))+import Data.Text.Internal.Unsafe.Shift (shiftL)++data T = {-# UNPACK #-} !Word64 :* {-# UNPACK #-} !Int++-- | /O(n+m)/ Find the offsets of all non-overlapping indices of+-- @needle@ within @haystack@.  The offsets returned represent+-- uncorrected indices in the low-level \"needle\" array, to which its+-- offset must be added.+--+-- In (unlikely) bad cases, this algorithm's complexity degrades+-- towards /O(n*m)/.+indices :: Text                -- ^ Substring to search for (@needle@)+        -> Text                -- ^ Text to search in (@haystack@)+        -> [Int]+indices _needle@(Text narr noff nlen) _haystack@(Text harr hoff hlen)+    | nlen == 1              = scanOne (nindex 0)+    | nlen <= 0 || ldiff < 0 = []+    | otherwise              = scan 0+  where+    ldiff    = hlen - nlen+    nlast    = nlen - 1+    z        = nindex nlast+    nindex k = A.unsafeIndex narr (noff+k)+    hindex k = A.unsafeIndex harr (hoff+k)+    hindex' k | k == hlen  = 0+              | otherwise = A.unsafeIndex harr (hoff+k)+    buildTable !i !msk !skp+        | i >= nlast           = (msk .|. swizzle z) :* skp+        | otherwise            = buildTable (i+1) (msk .|. swizzle c) skp'+        where c                = nindex i+              skp' | c == z    = nlen - i - 2+                   | otherwise = skp+    swizzle k = 1 `shiftL` (fromIntegral k .&. 0x3f)+    scan !i+        | i > ldiff                  = []+        | c == z && candidateMatch 0 = i : scan (i + nlen)+        | otherwise                  = scan (i + delta)+        where c = hindex (i + nlast)+              candidateMatch !j+                    | j >= nlast               = True+                    | hindex (i+j) /= nindex j = False+                    | otherwise                = candidateMatch (j+1)+              delta | nextInPattern = nlen + 1+                    | c == z        = skip + 1+                    | otherwise     = 1+                where nextInPattern = mask .&. swizzle (hindex' (i+nlen)) == 0+              !(mask :* skip)       = buildTable 0 0 (nlen-2)+    scanOne c = loop 0+        where loop !i | i >= hlen     = []+                      | hindex i == c = i : loop (i+1)+                      | otherwise     = loop (i+1)+{-# INLINE indices #-}
+ src/Data/Text/Internal/Unsafe.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE CPP, MagicHash, UnboxedTuples #-}+{-# OPTIONS_HADDOCK not-home #-}++-- |+-- Module      : Data.Text.Internal.Unsafe+-- Copyright   : (c) 2009, 2010, 2011 Bryan O'Sullivan+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : portable+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- A module containing /unsafe/ operations, for /very very careful/ use+-- in /heavily tested/ code.+module Data.Text.Internal.Unsafe+    (+      inlineInterleaveST+    , inlinePerformIO+    ) where++import GHC.ST (ST(..))+#if defined(__GLASGOW_HASKELL__)+import GHC.IO (IO(IO))+import GHC.Base (realWorld#)+#endif+++-- | Just like unsafePerformIO, but we inline it. Big performance gains as+-- it exposes lots of things to further inlining. /Very unsafe/. In+-- particular, you should do no memory allocation inside an+-- 'inlinePerformIO' block. On Hugs this is just @unsafePerformIO@.+--+{-# INLINE inlinePerformIO #-}+inlinePerformIO :: IO a -> a+#if defined(__GLASGOW_HASKELL__)+inlinePerformIO (IO m) = case m realWorld# of (# _, r #) -> r+#else+inlinePerformIO = unsafePerformIO+#endif++-- | Allow an 'ST' computation to be deferred lazily. When passed an+-- action of type 'ST' @s@ @a@, the action will only be performed when+-- the value of @a@ is demanded.+--+-- This function is identical to the normal unsafeInterleaveST, but is+-- inlined and hence faster.+--+-- /Note/: This operation is highly unsafe, as it can introduce+-- externally visible non-determinism into an 'ST' action.+inlineInterleaveST :: ST s a -> ST s a+inlineInterleaveST (ST m) = ST $ \ s ->+    let r = case m s of (# _, res #) -> res in (# s, r #)+{-# INLINE inlineInterleaveST #-}
+ src/Data/Text/Internal/Unsafe/Char.hs view
@@ -0,0 +1,95 @@+{-# LANGUAGE CPP, MagicHash #-}++-- |+-- Module      : Data.Text.Internal.Unsafe.Char+-- Copyright   : (c) 2008, 2009 Tom Harper,+--               (c) 2009, 2010 Bryan O'Sullivan,+--               (c) 2009 Duncan Coutts+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- Fast character manipulation functions.+module Data.Text.Internal.Unsafe.Char+    (+      ord+    , unsafeChr+    , unsafeChr8+    , unsafeChr32+    , unsafeWrite+    -- , unsafeWriteRev+    ) where++#ifdef ASSERTS+import Control.Exception (assert)+#endif+import Control.Monad.ST (ST)+import Data.Bits ((.&.))+import Data.Text.Internal.Unsafe.Shift (shiftR)+import GHC.Exts (Char(..), Int(..), chr#, ord#, word2Int#)+import GHC.Word (Word8(..), Word16(..), Word32(..))+import qualified Data.Text.Array as A++ord :: Char -> Int+ord (C# c#) = I# (ord# c#)+{-# INLINE ord #-}++unsafeChr :: Word16 -> Char+unsafeChr (W16# w#) = C# (chr# (word2Int# w#))+{-# INLINE unsafeChr #-}++unsafeChr8 :: Word8 -> Char+unsafeChr8 (W8# w#) = C# (chr# (word2Int# w#))+{-# INLINE unsafeChr8 #-}++unsafeChr32 :: Word32 -> Char+unsafeChr32 (W32# w#) = C# (chr# (word2Int# w#))+{-# INLINE unsafeChr32 #-}++-- | Write a character into the array at the given offset.  Returns+-- the number of 'Word16's written.+unsafeWrite :: A.MArray s -> Int -> Char -> ST s Int+unsafeWrite marr i c+    | n < 0x10000 = do+#if defined(ASSERTS)+        assert (i >= 0) . assert (i < A.length marr) $ return ()+#endif+        A.unsafeWrite marr i (fromIntegral n)+        return 1+    | otherwise = do+#if defined(ASSERTS)+        assert (i >= 0) . assert (i < A.length marr - 1) $ return ()+#endif+        A.unsafeWrite marr i lo+        A.unsafeWrite marr (i+1) hi+        return 2+    where n = ord c+          m = n - 0x10000+          lo = fromIntegral $ (m `shiftR` 10) + 0xD800+          hi = fromIntegral $ (m .&. 0x3FF) + 0xDC00+{-# INLINE unsafeWrite #-}++{-+unsafeWriteRev :: A.MArray s Word16 -> Int -> Char -> ST s Int+unsafeWriteRev marr i c+    | n < 0x10000 = do+        assert (i >= 0) . assert (i < A.length marr) $+          A.unsafeWrite marr i (fromIntegral n)+        return (i-1)+    | otherwise = do+        assert (i >= 1) . assert (i < A.length marr) $+          A.unsafeWrite marr (i-1) lo+        A.unsafeWrite marr i hi+        return (i-2)+    where n = ord c+          m = n - 0x10000+          lo = fromIntegral $ (m `shiftR` 10) + 0xD800+          hi = fromIntegral $ (m .&. 0x3FF) + 0xDC00+{-# INLINE unsafeWriteRev #-}+-}
+ src/Data/Text/Internal/Unsafe/Shift.hs view
@@ -0,0 +1,72 @@+{-# LANGUAGE MagicHash #-}++-- |+-- Module      : Data.Text.Internal.Unsafe.Shift+-- Copyright   : (c) Bryan O'Sullivan 2009+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- /Warning/: this is an internal module, and does not have a stable+-- API or name. Functions in this module may not check or enforce+-- preconditions expected by public modules. Use at your own risk!+--+-- Fast, unchecked bit shifting functions.++module Data.Text.Internal.Unsafe.Shift+    (+      UnsafeShift(..)+    ) where++-- import qualified Data.Bits as Bits+import GHC.Base+import GHC.Word++-- | This is a workaround for poor optimisation in GHC 6.8.2.  It+-- fails to notice constant-width shifts, and adds a test and branch+-- to every shift.  This imposes about a 10% performance hit.+--+-- These functions are undefined when the amount being shifted by is+-- greater than the size in bits of a machine Int#.+class UnsafeShift a where+    shiftL :: a -> Int -> a+    shiftR :: a -> Int -> a++instance UnsafeShift Word16 where+    {-# INLINE shiftL #-}+    shiftL (W16# x#) (I# i#) = W16# (narrow16Word# (x# `uncheckedShiftL#` i#))++    {-# INLINE shiftR #-}+    shiftR (W16# x#) (I# i#) = W16# (x# `uncheckedShiftRL#` i#)++instance UnsafeShift Word32 where+    {-# INLINE shiftL #-}+    shiftL (W32# x#) (I# i#) = W32# (narrow32Word# (x# `uncheckedShiftL#` i#))++    {-# INLINE shiftR #-}+    shiftR (W32# x#) (I# i#) = W32# (x# `uncheckedShiftRL#` i#)++instance UnsafeShift Word64 where+    {-# INLINE shiftL #-}+    shiftL (W64# x#) (I# i#) = W64# (x# `uncheckedShiftL64#` i#)++    {-# INLINE shiftR #-}+    shiftR (W64# x#) (I# i#) = W64# (x# `uncheckedShiftRL64#` i#)++instance UnsafeShift Int where+    {-# INLINE shiftL #-}+    shiftL (I# x#) (I# i#) = I# (x# `iShiftL#` i#)++    {-# INLINE shiftR #-}+    shiftR (I# x#) (I# i#) = I# (x# `iShiftRA#` i#)++{-+instance UnsafeShift Integer where+    {-# INLINE shiftL #-}+    shiftL = Bits.shiftL++    {-# INLINE shiftR #-}+    shiftR = Bits.shiftR+-}
+ src/Data/Text/Lazy.hs view
@@ -0,0 +1,1762 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-# LANGUAGE BangPatterns, MagicHash, CPP, TypeFamilies #-}+#if __GLASGOW_HASKELL__ >= 702+{-# LANGUAGE Trustworthy #-}+#endif+-- Using TemplateHaskell in text unconditionally is unacceptable, as+-- it's a GHC boot library. TemplateHaskellQuotes was added in 8.0, so+-- this would seem to be a problem. However, GHC's policy of only+-- needing to be able to compile itself from the last few releases+-- allows us to use full-fat TH on older versions, while using THQ for+-- GHC versions that may be used for bootstrapping.+#if __GLASGOW_HASKELL__ >= 800+{-# LANGUAGE TemplateHaskellQuotes #-}+#else+{-# LANGUAGE TemplateHaskell #-}+#endif++-- |+-- Module      : Data.Text.Lazy+-- Copyright   : (c) 2009, 2010, 2012 Bryan O'Sullivan+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Portability : GHC+--+-- A time and space-efficient implementation of Unicode text using+-- lists of packed arrays.+--+-- /Note/: Read below the synopsis for important notes on the use of+-- this module.+--+-- The representation used by this module is suitable for high+-- performance use and for streaming large quantities of data.  It+-- provides a means to manipulate a large body of text without+-- requiring that the entire content be resident in memory.+--+-- Some operations, such as 'concat', 'append', 'reverse' and 'cons',+-- have better time complexity than their "Data.Text" equivalents, due+-- to the underlying representation being a list of chunks. For other+-- operations, lazy 'Text's are usually within a few percent of strict+-- ones, but often with better heap usage if used in a streaming+-- fashion. For data larger than available memory, or if you have+-- tight memory constraints, this module will be the only option.+--+-- This module is intended to be imported @qualified@, to avoid name+-- clashes with "Prelude" functions.  eg.+--+-- > import qualified Data.Text.Lazy as L++module Data.Text.Lazy+    (+    -- * Fusion+    -- $fusion++    -- * Acceptable data+    -- $replacement++    -- * Types+      Text++    -- * Creation and elimination+    , pack+    , unpack+    , singleton+    , empty+    , fromChunks+    , toChunks+    , toStrict+    , fromStrict+    , foldrChunks+    , foldlChunks++    -- * Basic interface+    , cons+    , snoc+    , append+    , uncons+    , unsnoc+    , head+    , last+    , tail+    , init+    , null+    , length+    , compareLength++    -- * Transformations+    , map+    , intercalate+    , intersperse+    , transpose+    , reverse+    , replace++    -- ** Case conversion+    -- $case+    , toCaseFold+    , toLower+    , toUpper+    , toTitle++    -- ** Justification+    , justifyLeft+    , justifyRight+    , center++    -- * Folds+    , foldl+    , foldl'+    , foldl1+    , foldl1'+    , foldr+    , foldr1++    -- ** Special folds+    , concat+    , concatMap+    , any+    , all+    , maximum+    , minimum++    -- * Construction++    -- ** Scans+    , scanl+    , scanl1+    , scanr+    , scanr1++    -- ** Accumulating maps+    , mapAccumL+    , mapAccumR++    -- ** Generation and unfolding+    , repeat+    , replicate+    , cycle+    , iterate+    , unfoldr+    , unfoldrN++    -- * Substrings++    -- ** Breaking strings+    , take+    , takeEnd+    , drop+    , dropEnd+    , takeWhile+    , takeWhileEnd+    , dropWhile+    , dropWhileEnd+    , dropAround+    , strip+    , stripStart+    , stripEnd+    , splitAt+    , span+    , breakOn+    , breakOnEnd+    , break+    , group+    , groupBy+    , inits+    , tails++    -- ** Breaking into many substrings+    -- $split+    , splitOn+    , split+    , chunksOf+    -- , breakSubstring++    -- ** Breaking into lines and words+    , lines+    , words+    , unlines+    , unwords++    -- * Predicates+    , isPrefixOf+    , isSuffixOf+    , isInfixOf++    -- ** View patterns+    , stripPrefix+    , stripSuffix+    , commonPrefixes++    -- * Searching+    , filter+    , find+    , breakOnAll+    , partition++    -- , findSubstring++    -- * Indexing+    , index+    , count++    -- * Zipping and unzipping+    , zip+    , zipWith++    -- -* Ordered text+    -- , sort+    ) where++import Prelude (Char, Bool(..), Maybe(..), String,+                Eq(..), Ord(..), Ordering(..), Read(..), Show(..),+                (&&), (||), (+), (-), (.), ($), (++),+                error, flip, fmap, fromIntegral, not, otherwise, quot)+import qualified Prelude as P+import Control.DeepSeq (NFData(..))+import Data.Int (Int64)+import qualified Data.List as L+import Data.Char (isSpace)+import Data.Data (Data(gfoldl, toConstr, gunfold, dataTypeOf), constrIndex,+                  Constr, mkConstr, DataType, mkDataType, Fixity(Prefix))+import Data.Binary (Binary(get, put))+import Data.Monoid (Monoid(..))+#if MIN_VERSION_base(4,9,0)+import Data.Semigroup (Semigroup(..))+#endif+import Data.String (IsString(..))+import qualified Data.Text as T+import qualified Data.Text.Internal as T+import qualified Data.Text.Internal.Fusion.Common as S+import qualified Data.Text.Unsafe as T+import qualified Data.Text.Internal.Lazy.Fusion as S+import Data.Text.Internal.Fusion.Types (PairS(..))+import Data.Text.Internal.Lazy.Fusion (stream, unstream)+import Data.Text.Internal.Lazy (Text(..), chunk, empty, foldlChunks,+                                foldrChunks, smallChunkSize)+import Data.Text.Internal (firstf, safe, text)+import Data.Text.Lazy.Encoding (decodeUtf8', encodeUtf8)+import qualified Data.Text.Internal.Functions as F+import Data.Text.Internal.Lazy.Search (indices)+#if __GLASGOW_HASKELL__ >= 702+import qualified GHC.CString as GHC+#else+import qualified GHC.Base as GHC+#endif+#if MIN_VERSION_base(4,7,0)+import qualified GHC.Exts as Exts+#endif+import GHC.Prim (Addr#)+import qualified Language.Haskell.TH.Lib as TH+import qualified Language.Haskell.TH.Syntax as TH+#if MIN_VERSION_base(4,7,0)+import Text.Printf (PrintfArg, formatArg, formatString)+#endif++-- $fusion+--+-- Most of the functions in this module are subject to /fusion/,+-- meaning that a pipeline of such functions will usually allocate at+-- most one 'Text' value.+--+-- As an example, consider the following pipeline:+--+-- > import Data.Text.Lazy as T+-- > import Data.Text.Lazy.Encoding as E+-- > import Data.ByteString.Lazy (ByteString)+-- >+-- > countChars :: ByteString -> Int+-- > countChars = T.length . T.toUpper . E.decodeUtf8+--+-- From the type signatures involved, this looks like it should+-- allocate one 'ByteString' value, and two 'Text' values. However,+-- when a module is compiled with optimisation enabled under GHC, the+-- two intermediate 'Text' values will be optimised away, and the+-- function will be compiled down to a single loop over the source+-- 'ByteString'.+--+-- Functions that can be fused by the compiler are documented with the+-- phrase \"Subject to fusion\".++-- $replacement+--+-- A 'Text' value is a sequence of Unicode scalar values, as defined+-- in+-- <http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#page=35 §3.9, definition D76 of the Unicode 5.2 standard >.+-- As such, a 'Text' cannot contain values in the range U+D800 to+-- U+DFFF inclusive. Haskell implementations admit all Unicode code+-- points+-- (<http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#page=13 §3.4, definition D10 >)+-- as 'Char' values, including code points from this invalid range.+-- This means that there are some 'Char' values that are not valid+-- Unicode scalar values, and the functions in this module must handle+-- those cases.+--+-- Within this module, many functions construct a 'Text' from one or+-- more 'Char' values. Those functions will substitute 'Char' values+-- that are not valid Unicode scalar values with the replacement+-- character \"&#xfffd;\" (U+FFFD).  Functions that perform this+-- inspection and replacement are documented with the phrase+-- \"Performs replacement on invalid scalar values\".+--+-- (One reason for this policy of replacement is that internally, a+-- 'Text' value is represented as packed UTF-16 data. Values in the+-- range U+D800 through U+DFFF are used by UTF-16 to denote surrogate+-- code points, and so cannot be represented. The functions replace+-- invalid scalar values, instead of dropping them, as a security+-- measure. For details, see+-- <http://unicode.org/reports/tr36/#Deletion_of_Noncharacters Unicode Technical Report 36, §3.5 >.)++-- $setup+-- >>> import Data.Text+-- >>> import qualified Data.Text as T+-- >>> :seti -XOverloadedStrings++equal :: Text -> Text -> Bool+equal Empty Empty = True+equal Empty _     = False+equal _ Empty     = False+equal (Chunk a as) (Chunk b bs) =+    case compare lenA lenB of+      LT -> a == (T.takeWord16 lenA b) &&+            as `equal` Chunk (T.dropWord16 lenA b) bs+      EQ -> a == b && as `equal` bs+      GT -> T.takeWord16 lenB a == b &&+            Chunk (T.dropWord16 lenB a) as `equal` bs+  where lenA = T.lengthWord16 a+        lenB = T.lengthWord16 b++instance Eq Text where+    (==) = equal+    {-# INLINE (==) #-}++instance Ord Text where+    compare = compareText++compareText :: Text -> Text -> Ordering+compareText Empty Empty = EQ+compareText Empty _     = LT+compareText _     Empty = GT+compareText (Chunk a0 as) (Chunk b0 bs) = outer a0 b0+ where+  outer ta@(T.Text arrA offA lenA) tb@(T.Text arrB offB lenB) = go 0 0+   where+    go !i !j+      | i >= lenA = compareText as (chunk (T.Text arrB (offB+j) (lenB-j)) bs)+      | j >= lenB = compareText (chunk (T.Text arrA (offA+i) (lenA-i)) as) bs+      | a < b     = LT+      | a > b     = GT+      | otherwise = go (i+di) (j+dj)+      where T.Iter a di = T.iter ta i+            T.Iter b dj = T.iter tb j++instance Show Text where+    showsPrec p ps r = showsPrec p (unpack ps) r++instance Read Text where+    readsPrec p str = [(pack x,y) | (x,y) <- readsPrec p str]++#if MIN_VERSION_base(4,9,0)+-- | Non-orphan 'Semigroup' instance only defined for+-- @base-4.9.0.0@ and later; orphan instances for older GHCs are+-- provided by+-- the [semigroups](http://hackage.haskell.org/package/semigroups)+-- package+--+-- @since 1.2.2.0+instance Semigroup Text where+    (<>) = append+#endif++instance Monoid Text where+    mempty  = empty+#if MIN_VERSION_base(4,9,0)+    mappend = (<>) -- future-proof definition+#else+    mappend = append+#endif+    mconcat = concat++instance IsString Text where+    fromString = pack++#if MIN_VERSION_base(4,7,0)+-- | @since 1.2.0.0+instance Exts.IsList Text where+    type Item Text = Char+    fromList       = pack+    toList         = unpack+#endif++instance NFData Text where+    rnf Empty        = ()+    rnf (Chunk _ ts) = rnf ts++-- | @since 1.2.1.0+instance Binary Text where+    put t = put (encodeUtf8 t)+    get   = do+      bs <- get+      case decodeUtf8' bs of+        P.Left exn -> P.fail (P.show exn)+        P.Right a -> P.return a++-- | This instance preserves data abstraction at the cost of inefficiency.+-- We omit reflection services for the sake of data abstraction.+--+-- This instance was created by copying the updated behavior of+-- @"Data.Text".@'Data.Text.Text'+instance Data Text where+  gfoldl f z txt = z pack `f` (unpack txt)+  toConstr _     = packConstr+  gunfold k z c  = case constrIndex c of+    1 -> k (z pack)+    _ -> error "Data.Text.Lazy.Text.gunfold"+  dataTypeOf _   = textDataType++-- | This instance has similar considerations to the 'Data' instance:+-- it preserves abstraction at the cost of inefficiency.+--+-- @since 1.2.4.0+instance TH.Lift Text where+  lift = TH.appE (TH.varE 'pack) . TH.stringE . unpack+#if MIN_VERSION_template_haskell(2,17,0)+  liftTyped = TH.unsafeCodeCoerce . TH.lift+#elif MIN_VERSION_template_haskell(2,16,0)+  liftTyped = TH.unsafeTExpCoerce . TH.lift+#endif++#if MIN_VERSION_base(4,7,0)+-- | Only defined for @base-4.7.0.0@ and later+--+-- @since 1.2.2.0+instance PrintfArg Text where+  formatArg txt = formatString $ unpack txt+#endif++packConstr :: Constr+packConstr = mkConstr textDataType "pack" [] Prefix++textDataType :: DataType+textDataType = mkDataType "Data.Text.Lazy.Text" [packConstr]++-- | /O(n)/ Convert a 'String' into a 'Text'.+--+-- Subject to fusion.  Performs replacement on invalid scalar values.+pack :: String -> Text+pack = unstream . S.streamList . L.map safe+{-# INLINE [1] pack #-}++-- | /O(n)/ Convert a 'Text' into a 'String'.+-- Subject to fusion.+unpack :: Text -> String+unpack t = S.unstreamList (stream t)+{-# INLINE [1] unpack #-}++-- | /O(n)/ Convert a literal string into a Text.+unpackCString# :: Addr# -> Text+unpackCString# addr# = unstream (S.streamCString# addr#)+{-# NOINLINE unpackCString# #-}++{-# RULES "TEXT literal" forall a.+    unstream (S.streamList (L.map safe (GHC.unpackCString# a)))+      = unpackCString# a #-}++{-# RULES "TEXT literal UTF8" forall a.+    unstream (S.streamList (L.map safe (GHC.unpackCStringUtf8# a)))+      = unpackCString# a #-}++{-# RULES "LAZY TEXT empty literal"+    unstream (S.streamList (L.map safe []))+      = Empty #-}++{-# RULES "LAZY TEXT empty literal" forall a.+    unstream (S.streamList (L.map safe [a]))+      = Chunk (T.singleton a) Empty #-}++-- | /O(1)/ Convert a character into a Text.  Subject to fusion.+-- Performs replacement on invalid scalar values.+singleton :: Char -> Text+singleton c = Chunk (T.singleton c) Empty+{-# INLINE [1] singleton #-}++{-# RULES+"LAZY TEXT singleton -> fused" [~1] forall c.+    singleton c = unstream (S.singleton c)+"LAZY TEXT singleton -> unfused" [1] forall c.+    unstream (S.singleton c) = singleton c+  #-}++-- | /O(c)/ Convert a list of strict 'T.Text's into a lazy 'Text'.+fromChunks :: [T.Text] -> Text+fromChunks cs = L.foldr chunk Empty cs++-- | /O(n)/ Convert a lazy 'Text' into a list of strict 'T.Text's.+toChunks :: Text -> [T.Text]+toChunks cs = foldrChunks (:) [] cs++-- | /O(n)/ Convert a lazy 'Text' into a strict 'T.Text'.+toStrict :: Text -> T.Text+toStrict t = T.concat (toChunks t)+{-# INLINE [1] toStrict #-}++-- | /O(c)/ Convert a strict 'T.Text' into a lazy 'Text'.+fromStrict :: T.Text -> Text+fromStrict t = chunk t Empty+{-# INLINE [1] fromStrict #-}++-- -----------------------------------------------------------------------------+-- * Basic functions++-- | /O(1)/ Adds a character to the front of a 'Text'.  Subject to fusion.+cons :: Char -> Text -> Text+cons c t = Chunk (T.singleton c) t+{-# INLINE [1] cons #-}++infixr 5 `cons`++{-# RULES+"LAZY TEXT cons -> fused" [~1] forall c t.+    cons c t = unstream (S.cons c (stream t))+"LAZY TEXT cons -> unfused" [1] forall c t.+    unstream (S.cons c (stream t)) = cons c t+ #-}++-- | /O(n)/ Adds a character to the end of a 'Text'.  This copies the+-- entire array in the process, unless fused.  Subject to fusion.+snoc :: Text -> Char -> Text+snoc t c = foldrChunks Chunk (singleton c) t+{-# INLINE [1] snoc #-}++{-# RULES+"LAZY TEXT snoc -> fused" [~1] forall t c.+    snoc t c = unstream (S.snoc (stream t) c)+"LAZY TEXT snoc -> unfused" [1] forall t c.+    unstream (S.snoc (stream t) c) = snoc t c+ #-}++-- | /O(n\/c)/ Appends one 'Text' to another.  Subject to fusion.+append :: Text -> Text -> Text+append xs ys = foldrChunks Chunk ys xs+{-# INLINE [1] append #-}++{-# RULES+"LAZY TEXT append -> fused" [~1] forall t1 t2.+    append t1 t2 = unstream (S.append (stream t1) (stream t2))+"LAZY TEXT append -> unfused" [1] forall t1 t2.+    unstream (S.append (stream t1) (stream t2)) = append t1 t2+ #-}++-- | /O(1)/ Returns the first character and rest of a 'Text', or+-- 'Nothing' if empty. Subject to fusion.+uncons :: Text -> Maybe (Char, Text)+uncons Empty        = Nothing+uncons (Chunk t ts) = Just (T.unsafeHead t, ts')+  where ts' | T.compareLength t 1 == EQ = ts+            | otherwise                 = Chunk (T.unsafeTail t) ts+{-# INLINE uncons #-}++-- | /O(1)/ Returns the first character of a 'Text', which must be+-- non-empty.  Subject to fusion.+head :: Text -> Char+head t = S.head (stream t)+{-# INLINE head #-}++-- | /O(1)/ Returns all characters after the head of a 'Text', which+-- must be non-empty.  Subject to fusion.+tail :: Text -> Text+tail (Chunk t ts) = chunk (T.tail t) ts+tail Empty        = emptyError "tail"+{-# INLINE [1] tail #-}++{-# RULES+"LAZY TEXT tail -> fused" [~1] forall t.+    tail t = unstream (S.tail (stream t))+"LAZY TEXT tail -> unfused" [1] forall t.+    unstream (S.tail (stream t)) = tail t+ #-}++-- | /O(n\/c)/ Returns all but the last character of a 'Text', which must+-- be non-empty.  Subject to fusion.+init :: Text -> Text+init (Chunk t0 ts0) = go t0 ts0+    where go t (Chunk t' ts) = Chunk t (go t' ts)+          go t Empty         = chunk (T.init t) Empty+init Empty = emptyError "init"+{-# INLINE [1] init #-}++{-# RULES+"LAZY TEXT init -> fused" [~1] forall t.+    init t = unstream (S.init (stream t))+"LAZY TEXT init -> unfused" [1] forall t.+    unstream (S.init (stream t)) = init t+ #-}++-- | /O(n\/c)/ Returns the 'init' and 'last' of a 'Text', or 'Nothing' if+-- empty.+--+-- * It is no faster than using 'init' and 'last'.+--+-- @since 1.2.3.0+unsnoc :: Text -> Maybe (Text, Char)+unsnoc Empty          = Nothing+unsnoc ts@(Chunk _ _) = Just (init ts, last ts)+{-# INLINE unsnoc #-}++-- | /O(1)/ Tests whether a 'Text' is empty or not.  Subject to+-- fusion.+null :: Text -> Bool+null Empty = True+null _     = False+{-# INLINE [1] null #-}++{-# RULES+"LAZY TEXT null -> fused" [~1] forall t.+    null t = S.null (stream t)+"LAZY TEXT null -> unfused" [1] forall t.+    S.null (stream t) = null t+ #-}++-- | /O(1)/ Tests whether a 'Text' contains exactly one character.+-- Subject to fusion.+isSingleton :: Text -> Bool+isSingleton = S.isSingleton . stream+{-# INLINE isSingleton #-}++-- | /O(n\/c)/ Returns the last character of a 'Text', which must be+-- non-empty.  Subject to fusion.+last :: Text -> Char+last Empty        = emptyError "last"+last (Chunk t ts) = go t ts+    where go _ (Chunk t' ts') = go t' ts'+          go t' Empty         = T.last t'+{-# INLINE [1] last #-}++{-# RULES+"LAZY TEXT last -> fused" [~1] forall t.+    last t = S.last (stream t)+"LAZY TEXT last -> unfused" [1] forall t.+    S.last (stream t) = last t+  #-}++-- | /O(n)/ Returns the number of characters in a 'Text'.+-- Subject to fusion.+length :: Text -> Int64+length = foldlChunks go 0+    where go l t = l + fromIntegral (T.length t)+{-# INLINE [1] length #-}++{-# RULES+"LAZY TEXT length -> fused" [~1] forall t.+    length t = S.length (stream t)+"LAZY TEXT length -> unfused" [1] forall t.+    S.length (stream t) = length t+ #-}++-- | /O(n)/ Compare the count of characters in a 'Text' to a number.+-- Subject to fusion.+--+-- This function gives the same answer as comparing against the result+-- of 'length', but can short circuit if the count of characters is+-- greater than the number, and hence be more efficient.+compareLength :: Text -> Int64 -> Ordering+compareLength t n = S.compareLengthI (stream t) n+{-# INLINE [1] compareLength #-}++-- We don't apply those otherwise appealing length-to-compareLength+-- rewrite rules here, because they can change the strictness+-- properties of code.++-- | /O(n)/ 'map' @f@ @t@ is the 'Text' obtained by applying @f@ to+-- each element of @t@.  Subject to fusion.  Performs replacement on+-- invalid scalar values.+map :: (Char -> Char) -> Text -> Text+map f t = unstream (S.map (safe . f) (stream t))+{-# INLINE [1] map #-}++-- | /O(n)/ The 'intercalate' function takes a 'Text' and a list of+-- 'Text's and concatenates the list after interspersing the first+-- argument between each element of the list.+intercalate :: Text -> [Text] -> Text+intercalate t = concat . (F.intersperse t)+{-# INLINE intercalate #-}++-- | /O(n)/ The 'intersperse' function takes a character and places it+-- between the characters of a 'Text'.  Subject to fusion.  Performs+-- replacement on invalid scalar values.+intersperse :: Char -> Text -> Text+intersperse c t = unstream (S.intersperse (safe c) (stream t))+{-# INLINE intersperse #-}++-- | /O(n)/ Left-justify a string to the given length, using the+-- specified fill character on the right. Subject to fusion.  Performs+-- replacement on invalid scalar values.+--+-- Examples:+--+-- > justifyLeft 7 'x' "foo"    == "fooxxxx"+-- > justifyLeft 3 'x' "foobar" == "foobar"+justifyLeft :: Int64 -> Char -> Text -> Text+justifyLeft k c t+    | len >= k  = t+    | otherwise = t `append` replicateChar (k-len) c+  where len = length t+{-# INLINE [1] justifyLeft #-}++{-# RULES+"LAZY TEXT justifyLeft -> fused" [~1] forall k c t.+    justifyLeft k c t = unstream (S.justifyLeftI k c (stream t))+"LAZY TEXT justifyLeft -> unfused" [1] forall k c t.+    unstream (S.justifyLeftI k c (stream t)) = justifyLeft k c t+  #-}++-- | /O(n)/ Right-justify a string to the given length, using the+-- specified fill character on the left.  Performs replacement on+-- invalid scalar values.+--+-- Examples:+--+-- > justifyRight 7 'x' "bar"    == "xxxxbar"+-- > justifyRight 3 'x' "foobar" == "foobar"+justifyRight :: Int64 -> Char -> Text -> Text+justifyRight k c t+    | len >= k  = t+    | otherwise = replicateChar (k-len) c `append` t+  where len = length t+{-# INLINE justifyRight #-}++-- | /O(n)/ Center a string to the given length, using the specified+-- fill character on either side.  Performs replacement on invalid+-- scalar values.+--+-- Examples:+--+-- > center 8 'x' "HS" = "xxxHSxxx"+center :: Int64 -> Char -> Text -> Text+center k c t+    | len >= k  = t+    | otherwise = replicateChar l c `append` t `append` replicateChar r c+  where len = length t+        d   = k - len+        r   = d `quot` 2+        l   = d - r+{-# INLINE center #-}++-- | /O(n)/ The 'transpose' function transposes the rows and columns+-- of its 'Text' argument.  Note that this function uses 'pack',+-- 'unpack', and the list version of transpose, and is thus not very+-- efficient.+transpose :: [Text] -> [Text]+transpose ts = L.map (\ss -> Chunk (T.pack ss) Empty)+                     (L.transpose (L.map unpack ts))+-- TODO: make this fast++-- | /O(n)/ 'reverse' @t@ returns the elements of @t@ in reverse order.+reverse :: Text -> Text+reverse = rev Empty+  where rev a Empty        = a+        rev a (Chunk t ts) = rev (Chunk (T.reverse t) a) ts++-- | /O(m+n)/ Replace every non-overlapping occurrence of @needle@ in+-- @haystack@ with @replacement@.+--+-- This function behaves as though it was defined as follows:+--+-- @+-- replace needle replacement haystack =+--   'intercalate' replacement ('splitOn' needle haystack)+-- @+--+-- As this suggests, each occurrence is replaced exactly once.  So if+-- @needle@ occurs in @replacement@, that occurrence will /not/ itself+-- be replaced recursively:+--+-- > replace "oo" "foo" "oo" == "foo"+--+-- In cases where several instances of @needle@ overlap, only the+-- first one will be replaced:+--+-- > replace "ofo" "bar" "ofofo" == "barfo"+--+-- In (unlikely) bad cases, this function's time complexity degrades+-- towards /O(n*m)/.+replace :: Text+        -- ^ @needle@ to search for.  If this string is empty, an+        -- error will occur.+        -> Text+        -- ^ @replacement@ to replace @needle@ with.+        -> Text+        -- ^ @haystack@ in which to search.+        -> Text+replace s d = intercalate d . splitOn s+{-# INLINE replace #-}++-- ----------------------------------------------------------------------------+-- ** Case conversions (folds)++-- $case+--+-- With Unicode text, it is incorrect to use combinators like @map+-- toUpper@ to case convert each character of a string individually.+-- Instead, use the whole-string case conversion functions from this+-- module.  For correctness in different writing systems, these+-- functions may map one input character to two or three output+-- characters.++-- | /O(n)/ Convert a string to folded case.  Subject to fusion.+--+-- This function is mainly useful for performing caseless (or case+-- insensitive) string comparisons.+--+-- A string @x@ is a caseless match for a string @y@ if and only if:+--+-- @toCaseFold x == toCaseFold y@+--+-- The result string may be longer than the input string, and may+-- differ from applying 'toLower' to the input string.  For instance,+-- the Armenian small ligature men now (U+FB13) is case folded to the+-- bigram men now (U+0574 U+0576), while the micro sign (U+00B5) is+-- case folded to the Greek small letter letter mu (U+03BC) instead of+-- itself.+toCaseFold :: Text -> Text+toCaseFold t = unstream (S.toCaseFold (stream t))+{-# INLINE toCaseFold #-}++-- | /O(n)/ Convert a string to lower case, using simple case+-- conversion.  Subject to fusion.+--+-- The result string may be longer than the input string.  For+-- instance, the Latin capital letter I with dot above (U+0130) maps+-- to the sequence Latin small letter i (U+0069) followed by combining+-- dot above (U+0307).+toLower :: Text -> Text+toLower t = unstream (S.toLower (stream t))+{-# INLINE toLower #-}++-- | /O(n)/ Convert a string to upper case, using simple case+-- conversion.  Subject to fusion.+--+-- The result string may be longer than the input string.  For+-- instance, the German eszett (U+00DF) maps to the two-letter+-- sequence SS.+toUpper :: Text -> Text+toUpper t = unstream (S.toUpper (stream t))+{-# INLINE toUpper #-}+++-- | /O(n)/ Convert a string to title case, using simple case+-- conversion.  Subject to fusion.+--+-- The first letter of the input is converted to title case, as is+-- every subsequent letter that immediately follows a non-letter.+-- Every letter that immediately follows another letter is converted+-- to lower case.+--+-- The result string may be longer than the input string. For example,+-- the Latin small ligature &#xfb02; (U+FB02) is converted to the+-- sequence Latin capital letter F (U+0046) followed by Latin small+-- letter l (U+006C).+--+-- /Note/: this function does not take language or culture specific+-- rules into account. For instance, in English, different style+-- guides disagree on whether the book name \"The Hill of the Red+-- Fox\" is correctly title cased&#x2014;but this function will+-- capitalize /every/ word.+--+-- @since 1.0.0.0+toTitle :: Text -> Text+toTitle t = unstream (S.toTitle (stream t))+{-# INLINE toTitle #-}++-- | /O(n)/ 'foldl', applied to a binary operator, a starting value+-- (typically the left-identity of the operator), and a 'Text',+-- reduces the 'Text' using the binary operator, from left to right.+-- Subject to fusion.+foldl :: (a -> Char -> a) -> a -> Text -> a+foldl f z t = S.foldl f z (stream t)+{-# INLINE foldl #-}++-- | /O(n)/ A strict version of 'foldl'.+-- Subject to fusion.+foldl' :: (a -> Char -> a) -> a -> Text -> a+foldl' f z t = S.foldl' f z (stream t)+{-# INLINE foldl' #-}++-- | /O(n)/ A variant of 'foldl' that has no starting value argument,+-- and thus must be applied to a non-empty 'Text'.  Subject to fusion.+foldl1 :: (Char -> Char -> Char) -> Text -> Char+foldl1 f t = S.foldl1 f (stream t)+{-# INLINE foldl1 #-}++-- | /O(n)/ A strict version of 'foldl1'.  Subject to fusion.+foldl1' :: (Char -> Char -> Char) -> Text -> Char+foldl1' f t = S.foldl1' f (stream t)+{-# INLINE foldl1' #-}++-- | /O(n)/ 'foldr', applied to a binary operator, a starting value+-- (typically the right-identity of the operator), and a 'Text',+-- reduces the 'Text' using the binary operator, from right to left.+-- Subject to fusion.+foldr :: (Char -> a -> a) -> a -> Text -> a+foldr f z t = S.foldr f z (stream t)+{-# INLINE foldr #-}++-- | /O(n)/ A variant of 'foldr' that has no starting value argument,+-- and thus must be applied to a non-empty 'Text'.  Subject to+-- fusion.+foldr1 :: (Char -> Char -> Char) -> Text -> Char+foldr1 f t = S.foldr1 f (stream t)+{-# INLINE foldr1 #-}++-- | /O(n)/ Concatenate a list of 'Text's.+concat :: [Text] -> Text+concat = to+  where+    go Empty        css = to css+    go (Chunk c cs) css = Chunk c (go cs css)+    to []               = Empty+    to (cs:css)         = go cs css+{-# INLINE concat #-}++-- | /O(n)/ Map a function over a 'Text' that results in a 'Text', and+-- concatenate the results.+concatMap :: (Char -> Text) -> Text -> Text+concatMap f = concat . foldr ((:) . f) []+{-# INLINE concatMap #-}++-- | /O(n)/ 'any' @p@ @t@ determines whether any character in the+-- 'Text' @t@ satisfies the predicate @p@. Subject to fusion.+any :: (Char -> Bool) -> Text -> Bool+any p t = S.any p (stream t)+{-# INLINE any #-}++-- | /O(n)/ 'all' @p@ @t@ determines whether all characters in the+-- 'Text' @t@ satisfy the predicate @p@. Subject to fusion.+all :: (Char -> Bool) -> Text -> Bool+all p t = S.all p (stream t)+{-# INLINE all #-}++-- | /O(n)/ 'maximum' returns the maximum value from a 'Text', which+-- must be non-empty. Subject to fusion.+maximum :: Text -> Char+maximum t = S.maximum (stream t)+{-# INLINE maximum #-}++-- | /O(n)/ 'minimum' returns the minimum value from a 'Text', which+-- must be non-empty. Subject to fusion.+minimum :: Text -> Char+minimum t = S.minimum (stream t)+{-# INLINE minimum #-}++-- | /O(n)/ 'scanl' is similar to 'foldl', but returns a list of+-- successive reduced values from the left. Subject to fusion.+-- Performs replacement on invalid scalar values.+--+-- > scanl f z [x1, x2, ...] == [z, z `f` x1, (z `f` x1) `f` x2, ...]+--+-- Note that+--+-- > last (scanl f z xs) == foldl f z xs.+scanl :: (Char -> Char -> Char) -> Char -> Text -> Text+scanl f z t = unstream (S.scanl g z (stream t))+    where g a b = safe (f a b)+{-# INLINE scanl #-}++-- | /O(n)/ 'scanl1' is a variant of 'scanl' that has no starting+-- value argument.  Performs replacement on invalid scalar values.+--+-- > scanl1 f [x1, x2, ...] == [x1, x1 `f` x2, ...]+scanl1 :: (Char -> Char -> Char) -> Text -> Text+scanl1 f t0 = case uncons t0 of+                Nothing -> empty+                Just (t,ts) -> scanl f t ts+{-# INLINE scanl1 #-}++-- | /O(n)/ 'scanr' is the right-to-left dual of 'scanl'.  Performs+-- replacement on invalid scalar values.+--+-- > scanr f v == reverse . scanl (flip f) v . reverse+scanr :: (Char -> Char -> Char) -> Char -> Text -> Text+scanr f v = reverse . scanl g v . reverse+    where g a b = safe (f b a)++-- | /O(n)/ 'scanr1' is a variant of 'scanr' that has no starting+-- value argument.  Performs replacement on invalid scalar values.+scanr1 :: (Char -> Char -> Char) -> Text -> Text+scanr1 f t | null t    = empty+           | otherwise = scanr f (last t) (init t)++-- | /O(n)/ Like a combination of 'map' and 'foldl''. Applies a+-- function to each element of a 'Text', passing an accumulating+-- parameter from left to right, and returns a final 'Text'.  Performs+-- replacement on invalid scalar values.+mapAccumL :: (a -> Char -> (a,Char)) -> a -> Text -> (a, Text)+mapAccumL f = go+  where+    go z (Chunk c cs)    = (z'', Chunk c' cs')+        where (z',  c')  = T.mapAccumL f z c+              (z'', cs') = go z' cs+    go z Empty           = (z, Empty)+{-# INLINE mapAccumL #-}++-- | The 'mapAccumR' function behaves like a combination of 'map' and+-- a strict 'foldr'; it applies a function to each element of a+-- 'Text', passing an accumulating parameter from right to left, and+-- returning a final value of this accumulator together with the new+-- 'Text'.  Performs replacement on invalid scalar values.+mapAccumR :: (a -> Char -> (a,Char)) -> a -> Text -> (a, Text)+mapAccumR f = go+  where+    go z (Chunk c cs)   = (z'', Chunk c' cs')+        where (z'', c') = T.mapAccumR f z' c+              (z', cs') = go z cs+    go z Empty          = (z, Empty)+{-# INLINE mapAccumR #-}++-- | @'repeat' x@ is an infinite 'Text', with @x@ the value of every+-- element.+--+-- @since 1.2.0.5+repeat :: Char -> Text+repeat c = let t = Chunk (T.replicate smallChunkSize (T.singleton c)) t+            in t++-- | /O(n*m)/ 'replicate' @n@ @t@ is a 'Text' consisting of the input+-- @t@ repeated @n@ times.+replicate :: Int64 -> Text -> Text+replicate n t+    | null t || n <= 0 = empty+    | isSingleton t    = replicateChar n (head t)+    | otherwise        = concat (rep 0)+    where rep !i | i >= n    = []+                 | otherwise = t : rep (i+1)+{-# INLINE [1] replicate #-}++-- | 'cycle' ties a finite, non-empty 'Text' into a circular one, or+-- equivalently, the infinite repetition of the original 'Text'.+--+-- @since 1.2.0.5+cycle :: Text -> Text+cycle Empty = emptyError "cycle"+cycle t     = let t' = foldrChunks Chunk t' t+               in t'++-- | @'iterate' f x@ returns an infinite 'Text' of repeated applications+-- of @f@ to @x@:+--+-- > iterate f x == [x, f x, f (f x), ...]+--+-- @since 1.2.0.5+iterate :: (Char -> Char) -> Char -> Text+iterate f c = let t c' = Chunk (T.singleton c') (t (f c'))+               in t c++-- | /O(n)/ 'replicateChar' @n@ @c@ is a 'Text' of length @n@ with @c@ the+-- value of every element. Subject to fusion.+replicateChar :: Int64 -> Char -> Text+replicateChar n c = unstream (S.replicateCharI n (safe c))+{-# INLINE replicateChar #-}++{-# RULES+"LAZY TEXT replicate/singleton -> replicateChar" [~1] forall n c.+    replicate n (singleton c) = replicateChar n c+"LAZY TEXT replicate/unstream/singleton -> replicateChar" [~1] forall n c.+    replicate n (unstream (S.singleton c)) = replicateChar n c+  #-}++-- | /O(n)/, where @n@ is the length of the result. The 'unfoldr'+-- function is analogous to the List 'L.unfoldr'. 'unfoldr' builds a+-- 'Text' from a seed value. The function takes the element and+-- returns 'Nothing' if it is done producing the 'Text', otherwise+-- 'Just' @(a,b)@.  In this case, @a@ is the next 'Char' in the+-- string, and @b@ is the seed value for further production.+-- Subject to fusion.+-- Performs replacement on invalid scalar values.+unfoldr :: (a -> Maybe (Char,a)) -> a -> Text+unfoldr f s = unstream (S.unfoldr (firstf safe . f) s)+{-# INLINE unfoldr #-}++-- | /O(n)/ Like 'unfoldr', 'unfoldrN' builds a 'Text' from a seed+-- value. However, the length of the result should be limited by the+-- first argument to 'unfoldrN'. This function is more efficient than+-- 'unfoldr' when the maximum length of the result is known and+-- correct, otherwise its performance is similar to 'unfoldr'.+-- Subject to fusion.+-- Performs replacement on invalid scalar values.+unfoldrN :: Int64 -> (a -> Maybe (Char,a)) -> a -> Text+unfoldrN n f s = unstream (S.unfoldrN n (firstf safe . f) s)+{-# INLINE unfoldrN #-}++-- | /O(n)/ 'take' @n@, applied to a 'Text', returns the prefix of the+-- 'Text' of length @n@, or the 'Text' itself if @n@ is greater than+-- the length of the Text. Subject to fusion.+take :: Int64 -> Text -> Text+take i _ | i <= 0 = Empty+take i t0         = take' i t0+  where take' 0 _            = Empty+        take' _ Empty        = Empty+        take' n (Chunk t ts)+            | n < len   = Chunk (T.take (fromIntegral n) t) Empty+            | otherwise = Chunk t (take' (n - len) ts)+            where len = fromIntegral (T.length t)+{-# INLINE [1] take #-}++{-# RULES+"LAZY TEXT take -> fused" [~1] forall n t.+    take n t = unstream (S.take n (stream t))+"LAZY TEXT take -> unfused" [1] forall n t.+    unstream (S.take n (stream t)) = take n t+  #-}++-- | /O(n)/ 'takeEnd' @n@ @t@ returns the suffix remaining after+-- taking @n@ characters from the end of @t@.+--+-- Examples:+--+-- > takeEnd 3 "foobar" == "bar"+--+-- @since 1.1.1.0+takeEnd :: Int64 -> Text -> Text+takeEnd n t0+    | n <= 0    = empty+    | otherwise = takeChunk n empty . L.reverse . toChunks $ t0+  where takeChunk _ acc [] = acc+        takeChunk i acc (t:ts)+          | i <= l    = chunk (T.takeEnd (fromIntegral i) t) acc+          | otherwise = takeChunk (i-l) (Chunk t acc) ts+          where l = fromIntegral (T.length t)++-- | /O(n)/ 'drop' @n@, applied to a 'Text', returns the suffix of the+-- 'Text' after the first @n@ characters, or the empty 'Text' if @n@+-- is greater than the length of the 'Text'. Subject to fusion.+drop :: Int64 -> Text -> Text+drop i t0+    | i <= 0    = t0+    | otherwise = drop' i t0+  where drop' 0 ts           = ts+        drop' _ Empty        = Empty+        drop' n (Chunk t ts)+            | n < len   = Chunk (T.drop (fromIntegral n) t) ts+            | otherwise = drop' (n - len) ts+            where len   = fromIntegral (T.length t)+{-# INLINE [1] drop #-}++{-# RULES+"LAZY TEXT drop -> fused" [~1] forall n t.+    drop n t = unstream (S.drop n (stream t))+"LAZY TEXT drop -> unfused" [1] forall n t.+    unstream (S.drop n (stream t)) = drop n t+  #-}++-- | /O(n)/ 'dropEnd' @n@ @t@ returns the prefix remaining after+-- dropping @n@ characters from the end of @t@.+--+-- Examples:+--+-- > dropEnd 3 "foobar" == "foo"+--+-- @since 1.1.1.0+dropEnd :: Int64 -> Text -> Text+dropEnd n t0+    | n <= 0    = t0+    | otherwise = dropChunk n . L.reverse . toChunks $ t0+  where dropChunk _ [] = empty+        dropChunk m (t:ts)+          | m >= l    = dropChunk (m-l) ts+          | otherwise = fromChunks . L.reverse $+                        T.dropEnd (fromIntegral m) t : ts+          where l = fromIntegral (T.length t)++-- | /O(n)/ 'dropWords' @n@ returns the suffix with @n@ 'Word16'+-- values dropped, or the empty 'Text' if @n@ is greater than the+-- number of 'Word16' values present.+dropWords :: Int64 -> Text -> Text+dropWords i t0+    | i <= 0    = t0+    | otherwise = drop' i t0+  where drop' 0 ts           = ts+        drop' _ Empty        = Empty+        drop' n (Chunk (T.Text arr off len) ts)+            | n < len'  = chunk (text arr (off+n') (len-n')) ts+            | otherwise = drop' (n - len') ts+            where len'  = fromIntegral len+                  n'    = fromIntegral n++-- | /O(n)/ 'takeWhile', applied to a predicate @p@ and a 'Text',+-- returns the longest prefix (possibly empty) of elements that+-- satisfy @p@.  Subject to fusion.+takeWhile :: (Char -> Bool) -> Text -> Text+takeWhile p t0 = takeWhile' t0+  where takeWhile' Empty        = Empty+        takeWhile' (Chunk t ts) =+          case T.findIndex (not . p) t of+            Just n | n > 0     -> Chunk (T.take n t) Empty+                   | otherwise -> Empty+            Nothing            -> Chunk t (takeWhile' ts)+{-# INLINE [1] takeWhile #-}++{-# RULES+"LAZY TEXT takeWhile -> fused" [~1] forall p t.+    takeWhile p t = unstream (S.takeWhile p (stream t))+"LAZY TEXT takeWhile -> unfused" [1] forall p t.+    unstream (S.takeWhile p (stream t)) = takeWhile p t+  #-}+-- | /O(n)/ 'takeWhileEnd', applied to a predicate @p@ and a 'Text',+-- returns the longest suffix (possibly empty) of elements that+-- satisfy @p@.+-- Examples:+--+-- > takeWhileEnd (=='o') "foo" == "oo"+--+-- @since 1.2.2.0+takeWhileEnd :: (Char -> Bool) -> Text -> Text+takeWhileEnd p = takeChunk empty . L.reverse . toChunks+  where takeChunk acc []     = acc+        takeChunk acc (t:ts)+          | T.lengthWord16 t' < T.lengthWord16 t+                             = chunk t' acc+          | otherwise        = takeChunk (Chunk t' acc) ts+          where t' = T.takeWhileEnd p t+{-# INLINE takeWhileEnd #-}++-- | /O(n)/ 'dropWhile' @p@ @t@ returns the suffix remaining after+-- 'takeWhile' @p@ @t@.  Subject to fusion.+dropWhile :: (Char -> Bool) -> Text -> Text+dropWhile p t0 = dropWhile' t0+  where dropWhile' Empty        = Empty+        dropWhile' (Chunk t ts) =+          case T.findIndex (not . p) t of+            Just n  -> Chunk (T.drop n t) ts+            Nothing -> dropWhile' ts+{-# INLINE [1] dropWhile #-}++{-# RULES+"LAZY TEXT dropWhile -> fused" [~1] forall p t.+    dropWhile p t = unstream (S.dropWhile p (stream t))+"LAZY TEXT dropWhile -> unfused" [1] forall p t.+    unstream (S.dropWhile p (stream t)) = dropWhile p t+  #-}++-- | /O(n)/ 'dropWhileEnd' @p@ @t@ returns the prefix remaining after+-- dropping characters that satisfy the predicate @p@ from the end of+-- @t@.+--+-- Examples:+--+-- > dropWhileEnd (=='.') "foo..." == "foo"+dropWhileEnd :: (Char -> Bool) -> Text -> Text+dropWhileEnd p = go+  where go Empty = Empty+        go (Chunk t Empty) = if T.null t'+                             then Empty+                             else Chunk t' Empty+            where t' = T.dropWhileEnd p t+        go (Chunk t ts) = case go ts of+                            Empty -> go (Chunk t Empty)+                            ts' -> Chunk t ts'+{-# INLINE dropWhileEnd #-}++-- | /O(n)/ 'dropAround' @p@ @t@ returns the substring remaining after+-- dropping characters that satisfy the predicate @p@ from both the+-- beginning and end of @t@.+dropAround :: (Char -> Bool) -> Text -> Text+dropAround p = dropWhile p . dropWhileEnd p+{-# INLINE [1] dropAround #-}++-- | /O(n)/ Remove leading white space from a string.  Equivalent to:+--+-- > dropWhile isSpace+stripStart :: Text -> Text+stripStart = dropWhile isSpace+{-# INLINE stripStart #-}++-- | /O(n)/ Remove trailing white space from a string.  Equivalent to:+--+-- > dropWhileEnd isSpace+stripEnd :: Text -> Text+stripEnd = dropWhileEnd isSpace+{-# INLINE [1] stripEnd #-}++-- | /O(n)/ Remove leading and trailing white space from a string.+-- Equivalent to:+--+-- > dropAround isSpace+strip :: Text -> Text+strip = dropAround isSpace+{-# INLINE [1] strip #-}++-- | /O(n)/ 'splitAt' @n t@ returns a pair whose first element is a+-- prefix of @t@ of length @n@, and whose second is the remainder of+-- the string. It is equivalent to @('take' n t, 'drop' n t)@.+splitAt :: Int64 -> Text -> (Text, Text)+splitAt = loop+  where loop _ Empty      = (empty, empty)+        loop n t | n <= 0 = (empty, t)+        loop n (Chunk t ts)+             | n < len   = let (t',t'') = T.splitAt (fromIntegral n) t+                           in (Chunk t' Empty, Chunk t'' ts)+             | otherwise = let (ts',ts'') = loop (n - len) ts+                           in (Chunk t ts', ts'')+             where len = fromIntegral (T.length t)++-- | /O(n)/ 'splitAtWord' @n t@ returns a strict pair whose first+-- element is a prefix of @t@ whose chunks contain @n@ 'Word16'+-- values, and whose second is the remainder of the string.+splitAtWord :: Int64 -> Text -> PairS Text Text+splitAtWord _ Empty = empty :*: empty+splitAtWord x (Chunk c@(T.Text arr off len) cs)+    | y >= len  = let h :*: t = splitAtWord (x-fromIntegral len) cs+                  in  Chunk c h :*: t+    | otherwise = chunk (text arr off y) empty :*:+                  chunk (text arr (off+y) (len-y)) cs+    where y = fromIntegral x++-- | /O(n+m)/ Find the first instance of @needle@ (which must be+-- non-'null') in @haystack@.  The first element of the returned tuple+-- is the prefix of @haystack@ before @needle@ is matched.  The second+-- is the remainder of @haystack@, starting with the match.+--+-- Examples:+--+-- > breakOn "::" "a::b::c" ==> ("a", "::b::c")+-- > breakOn "/" "foobar"   ==> ("foobar", "")+--+-- Laws:+--+-- > append prefix match == haystack+-- >   where (prefix, match) = breakOn needle haystack+--+-- If you need to break a string by a substring repeatedly (e.g. you+-- want to break on every instance of a substring), use 'breakOnAll'+-- instead, as it has lower startup overhead.+--+-- This function is strict in its first argument, and lazy in its+-- second.+--+-- In (unlikely) bad cases, this function's time complexity degrades+-- towards /O(n*m)/.+breakOn :: Text -> Text -> (Text, Text)+breakOn pat src+    | null pat  = emptyError "breakOn"+    | otherwise = case indices pat src of+                    []    -> (src, empty)+                    (x:_) -> let h :*: t = splitAtWord x src+                             in  (h, t)++-- | /O(n+m)/ Similar to 'breakOn', but searches from the end of the string.+--+-- The first element of the returned tuple is the prefix of @haystack@+-- up to and including the last match of @needle@.  The second is the+-- remainder of @haystack@, following the match.+--+-- > breakOnEnd "::" "a::b::c" ==> ("a::b::", "c")+breakOnEnd :: Text -> Text -> (Text, Text)+breakOnEnd pat src = let (a,b) = breakOn (reverse pat) (reverse src)+                   in  (reverse b, reverse a)+{-# INLINE breakOnEnd #-}++-- | /O(n+m)/ Find all non-overlapping instances of @needle@ in+-- @haystack@.  Each element of the returned list consists of a pair:+--+-- * The entire string prior to the /k/th match (i.e. the prefix)+--+-- * The /k/th match, followed by the remainder of the string+--+-- Examples:+--+-- > breakOnAll "::" ""+-- > ==> []+-- > breakOnAll "/" "a/b/c/"+-- > ==> [("a", "/b/c/"), ("a/b", "/c/"), ("a/b/c", "/")]+--+-- This function is strict in its first argument, and lazy in its+-- second.+--+-- In (unlikely) bad cases, this function's time complexity degrades+-- towards /O(n*m)/.+--+-- The @needle@ parameter may not be empty.+breakOnAll :: Text              -- ^ @needle@ to search for+           -> Text              -- ^ @haystack@ in which to search+           -> [(Text, Text)]+breakOnAll pat src+    | null pat  = emptyError "breakOnAll"+    | otherwise = go 0 empty src (indices pat src)+  where+    go !n p s (x:xs) = let h :*: t = splitAtWord (x-n) s+                           h'      = append p h+                       in (h',t) : go x h' t xs+    go _  _ _ _      = []++-- | /O(n)/ 'break' is like 'span', but the prefix returned is over+-- elements that fail the predicate @p@.+--+-- >>> T.break (=='c') "180cm"+-- ("180","cm")+break :: (Char -> Bool) -> Text -> (Text, Text)+break p t0 = break' t0+  where break' Empty          = (empty, empty)+        break' c@(Chunk t ts) =+          case T.findIndex p t of+            Nothing      -> let (ts', ts'') = break' ts+                            in (Chunk t ts', ts'')+            Just n | n == 0    -> (Empty, c)+                   | otherwise -> let (a,b) = T.splitAt n t+                                  in (Chunk a Empty, Chunk b ts)++-- | /O(n)/ 'span', applied to a predicate @p@ and text @t@, returns+-- a pair whose first element is the longest prefix (possibly empty)+-- of @t@ of elements that satisfy @p@, and whose second is the+-- remainder of the list.+--+-- >>> T.span (=='0') "000AB"+-- ("000","AB")+span :: (Char -> Bool) -> Text -> (Text, Text)+span p = break (not . p)+{-# INLINE span #-}++-- | The 'group' function takes a 'Text' and returns a list of 'Text's+-- such that the concatenation of the result is equal to the argument.+-- Moreover, each sublist in the result contains only equal elements.+-- For example,+--+-- > group "Mississippi" = ["M","i","ss","i","ss","i","pp","i"]+--+-- It is a special case of 'groupBy', which allows the programmer to+-- supply their own equality test.+group :: Text -> [Text]+group =  groupBy (==)+{-# INLINE group #-}++-- | The 'groupBy' function is the non-overloaded version of 'group'.+groupBy :: (Char -> Char -> Bool) -> Text -> [Text]+groupBy _  Empty        = []+groupBy eq (Chunk t ts) = cons x ys : groupBy eq zs+                          where (ys,zs) = span (eq x) xs+                                x  = T.unsafeHead t+                                xs = chunk (T.unsafeTail t) ts++-- | /O(n)/ Return all initial segments of the given 'Text',+-- shortest first.+inits :: Text -> [Text]+inits = (Empty :) . inits'+  where inits' Empty        = []+        inits' (Chunk t ts) = L.map (\t' -> Chunk t' Empty) (L.tail (T.inits t))+                           ++ L.map (Chunk t) (inits' ts)++-- | /O(n)/ Return all final segments of the given 'Text', longest+-- first.+tails :: Text -> [Text]+tails Empty         = Empty : []+tails ts@(Chunk t ts')+  | T.length t == 1 = ts : tails ts'+  | otherwise       = ts : tails (Chunk (T.unsafeTail t) ts')++-- $split+--+-- Splitting functions in this library do not perform character-wise+-- copies to create substrings; they just construct new 'Text's that+-- are slices of the original.++-- | /O(m+n)/ Break a 'Text' into pieces separated by the first 'Text'+-- argument (which cannot be an empty string), consuming the+-- delimiter. An empty delimiter is invalid, and will cause an error+-- to be raised.+--+-- Examples:+--+-- > splitOn "\r\n" "a\r\nb\r\nd\r\ne" == ["a","b","d","e"]+-- > splitOn "aaa"  "aaaXaaaXaaaXaaa"  == ["","X","X","X",""]+-- > splitOn "x"    "x"                == ["",""]+--+-- and+--+-- > intercalate s . splitOn s         == id+-- > splitOn (singleton c)             == split (==c)+--+-- (Note: the string @s@ to split on above cannot be empty.)+--+-- This function is strict in its first argument, and lazy in its+-- second.+--+-- In (unlikely) bad cases, this function's time complexity degrades+-- towards /O(n*m)/.+splitOn :: Text+        -- ^ String to split on. If this string is empty, an error+        -- will occur.+        -> Text+        -- ^ Input text.+        -> [Text]+splitOn pat src+    | null pat        = emptyError "splitOn"+    | isSingleton pat = split (== head pat) src+    | otherwise       = go 0 (indices pat src) src+  where+    go  _ []     cs = [cs]+    go !i (x:xs) cs = let h :*: t = splitAtWord (x-i) cs+                      in  h : go (x+l) xs (dropWords l t)+    l = foldlChunks (\a (T.Text _ _ b) -> a + fromIntegral b) 0 pat+{-# INLINE [1] splitOn #-}++{-# RULES+"LAZY TEXT splitOn/singleton -> split/==" [~1] forall c t.+    splitOn (singleton c) t = split (==c) t+  #-}++-- | /O(n)/ Splits a 'Text' into components delimited by separators,+-- where the predicate returns True for a separator element.  The+-- resulting components do not contain the separators.  Two adjacent+-- separators result in an empty component in the output.  eg.+--+-- > split (=='a') "aabbaca" == ["","","bb","c",""]+-- > split (=='a') []        == [""]+split :: (Char -> Bool) -> Text -> [Text]+split _ Empty = [Empty]+split p (Chunk t0 ts0) = comb [] (T.split p t0) ts0+  where comb acc (s:[]) Empty        = revChunks (s:acc) : []+        comb acc (s:[]) (Chunk t ts) = comb (s:acc) (T.split p t) ts+        comb acc (s:ss) ts           = revChunks (s:acc) : comb [] ss ts+        comb _   []     _            = impossibleError "split"+{-# INLINE split #-}++-- | /O(n)/ Splits a 'Text' into components of length @k@.  The last+-- element may be shorter than the other chunks, depending on the+-- length of the input. Examples:+--+-- > chunksOf 3 "foobarbaz"   == ["foo","bar","baz"]+-- > chunksOf 4 "haskell.org" == ["hask","ell.","org"]+chunksOf :: Int64 -> Text -> [Text]+chunksOf k = go+  where+    go t = case splitAt k t of+             (a,b) | null a    -> []+                   | otherwise -> a : go b+{-# INLINE chunksOf #-}++-- | /O(n)/ Breaks a 'Text' up into a list of 'Text's at+-- newline 'Char's. The resulting strings do not contain newlines.+lines :: Text -> [Text]+lines Empty = []+lines t = let (l,t') = break ((==) '\n') t+          in l : if null t' then []+                 else lines (tail t')++-- | /O(n)/ Breaks a 'Text' up into a list of words, delimited by 'Char's+-- representing white space.+words :: Text -> [Text]+words = L.filter (not . null) . split isSpace+{-# INLINE words #-}++-- | /O(n)/ Joins lines, after appending a terminating newline to+-- each.+unlines :: [Text] -> Text+unlines = concat . L.map (`snoc` '\n')+{-# INLINE unlines #-}++-- | /O(n)/ Joins words using single space characters.+unwords :: [Text] -> Text+unwords = intercalate (singleton ' ')+{-# INLINE unwords #-}++-- | /O(n)/ The 'isPrefixOf' function takes two 'Text's and returns+-- 'True' iff the first is a prefix of the second.  Subject to fusion.+isPrefixOf :: Text -> Text -> Bool+isPrefixOf Empty _  = True+isPrefixOf _ Empty  = False+isPrefixOf (Chunk x xs) (Chunk y ys)+    | lx == ly  = x == y  && isPrefixOf xs ys+    | lx <  ly  = x == yh && isPrefixOf xs (Chunk yt ys)+    | otherwise = xh == y && isPrefixOf (Chunk xt xs) ys+  where (xh,xt) = T.splitAt ly x+        (yh,yt) = T.splitAt lx y+        lx = T.length x+        ly = T.length y+{-# INLINE [1] isPrefixOf #-}++{-# RULES+"LAZY TEXT isPrefixOf -> fused" [~1] forall s t.+    isPrefixOf s t = S.isPrefixOf (stream s) (stream t)+"LAZY TEXT isPrefixOf -> unfused" [1] forall s t.+    S.isPrefixOf (stream s) (stream t) = isPrefixOf s t+  #-}++-- | /O(n)/ The 'isSuffixOf' function takes two 'Text's and returns+-- 'True' iff the first is a suffix of the second.+isSuffixOf :: Text -> Text -> Bool+isSuffixOf x y = reverse x `isPrefixOf` reverse y+{-# INLINE isSuffixOf #-}+-- TODO: a better implementation++-- | /O(n+m)/ The 'isInfixOf' function takes two 'Text's and returns+-- 'True' iff the first is contained, wholly and intact, anywhere+-- within the second.+--+-- This function is strict in its first argument, and lazy in its+-- second.+--+-- In (unlikely) bad cases, this function's time complexity degrades+-- towards /O(n*m)/.+isInfixOf :: Text -> Text -> Bool+isInfixOf needle haystack+    | null needle        = True+    | isSingleton needle = S.elem (head needle) . S.stream $ haystack+    | otherwise          = not . L.null . indices needle $ haystack+{-# INLINE [1] isInfixOf #-}++{-# RULES+"LAZY TEXT isInfixOf/singleton -> S.elem/S.stream" [~1] forall n h.+    isInfixOf (singleton n) h = S.elem n (S.stream h)+  #-}++-------------------------------------------------------------------------------+-- * View patterns++-- | /O(n)/ Return the suffix of the second string if its prefix+-- matches the entire first string.+--+-- Examples:+--+-- > stripPrefix "foo" "foobar" == Just "bar"+-- > stripPrefix ""    "baz"    == Just "baz"+-- > stripPrefix "foo" "quux"   == Nothing+--+-- This is particularly useful with the @ViewPatterns@ extension to+-- GHC, as follows:+--+-- > {-# LANGUAGE ViewPatterns #-}+-- > import Data.Text.Lazy as T+-- >+-- > fnordLength :: Text -> Int+-- > fnordLength (stripPrefix "fnord" -> Just suf) = T.length suf+-- > fnordLength _                                 = -1+stripPrefix :: Text -> Text -> Maybe Text+stripPrefix p t+    | null p    = Just t+    | otherwise = case commonPrefixes p t of+                    Just (_,c,r) | null c -> Just r+                    _                     -> Nothing++-- | /O(n)/ Find the longest non-empty common prefix of two strings+-- and return it, along with the suffixes of each string at which they+-- no longer match.+--+-- If the strings do not have a common prefix or either one is empty,+-- this function returns 'Nothing'.+--+-- Examples:+--+-- > commonPrefixes "foobar" "fooquux" == Just ("foo","bar","quux")+-- > commonPrefixes "veeble" "fetzer"  == Nothing+-- > commonPrefixes "" "baz"           == Nothing+commonPrefixes :: Text -> Text -> Maybe (Text,Text,Text)+commonPrefixes Empty _ = Nothing+commonPrefixes _ Empty = Nothing+commonPrefixes a0 b0   = Just (go a0 b0 [])+  where+    go t0@(Chunk x xs) t1@(Chunk y ys) ps+        = case T.commonPrefixes x y of+            Just (p,a,b)+              | T.null a  -> go xs (chunk b ys) (p:ps)+              | T.null b  -> go (chunk a xs) ys (p:ps)+              | otherwise -> (fromChunks (L.reverse (p:ps)),chunk a xs, chunk b ys)+            Nothing       -> (fromChunks (L.reverse ps),t0,t1)+    go t0 t1 ps = (fromChunks (L.reverse ps),t0,t1)++-- | /O(n)/ Return the prefix of the second string if its suffix+-- matches the entire first string.+--+-- Examples:+--+-- > stripSuffix "bar" "foobar" == Just "foo"+-- > stripSuffix ""    "baz"    == Just "baz"+-- > stripSuffix "foo" "quux"   == Nothing+--+-- This is particularly useful with the @ViewPatterns@ extension to+-- GHC, as follows:+--+-- > {-# LANGUAGE ViewPatterns #-}+-- > import Data.Text.Lazy as T+-- >+-- > quuxLength :: Text -> Int+-- > quuxLength (stripSuffix "quux" -> Just pre) = T.length pre+-- > quuxLength _                                = -1+stripSuffix :: Text -> Text -> Maybe Text+stripSuffix p t = reverse `fmap` stripPrefix (reverse p) (reverse t)++-- | /O(n)/ 'filter', applied to a predicate and a 'Text',+-- returns a 'Text' containing those characters that satisfy the+-- predicate.+filter :: (Char -> Bool) -> Text -> Text+filter p t = unstream (S.filter p (stream t))+{-# INLINE filter #-}++-- | /O(n)/ The 'find' function takes a predicate and a 'Text', and+-- returns the first element in matching the predicate, or 'Nothing'+-- if there is no such element. Subject to fusion.+find :: (Char -> Bool) -> Text -> Maybe Char+find p t = S.findBy p (stream t)+{-# INLINE find #-}++-- | /O(n)/ The 'partition' function takes a predicate and a 'Text',+-- and returns the pair of 'Text's with elements which do and do not+-- satisfy the predicate, respectively; i.e.+--+-- > partition p t == (filter p t, filter (not . p) t)+partition :: (Char -> Bool) -> Text -> (Text, Text)+partition p t = (filter p t, filter (not . p) t)+{-# INLINE partition #-}++-- | /O(n)/ 'Text' index (subscript) operator, starting from 0.+-- Subject to fusion.+index :: Text -> Int64 -> Char+index t n = S.index (stream t) n+{-# INLINE index #-}++-- | /O(n+m)/ The 'count' function returns the number of times the+-- query string appears in the given 'Text'. An empty query string is+-- invalid, and will cause an error to be raised.+--+-- In (unlikely) bad cases, this function's time complexity degrades+-- towards /O(n*m)/.+count :: Text -> Text -> Int64+count pat src+    | null pat        = emptyError "count"+    | otherwise       = go 0 (indices pat src)+  where go !n []     = n+        go !n (_:xs) = go (n+1) xs+{-# INLINE [1] count #-}++{-# RULES+"LAZY TEXT count/singleton -> countChar" [~1] forall c t.+    count (singleton c) t = countChar c t+  #-}++-- | /O(n)/ The 'countChar' function returns the number of times the+-- query element appears in the given 'Text'.  Subject to fusion.+countChar :: Char -> Text -> Int64+countChar c t = S.countChar c (stream t)++-- | /O(n)/ 'zip' takes two 'Text's and returns a list of+-- corresponding pairs of bytes. If one input 'Text' is short,+-- excess elements of the longer 'Text' are discarded. This is+-- equivalent to a pair of 'unpack' operations.+zip :: Text -> Text -> [(Char,Char)]+zip a b = S.unstreamList $ S.zipWith (,) (stream a) (stream b)+{-# INLINE [0] zip #-}++-- | /O(n)/ 'zipWith' generalises 'zip' by zipping with the function+-- given as the first argument, instead of a tupling function.+-- Performs replacement on invalid scalar values.+zipWith :: (Char -> Char -> Char) -> Text -> Text -> Text+zipWith f t1 t2 = unstream (S.zipWith g (stream t1) (stream t2))+    where g a b = safe (f a b)+{-# INLINE [0] zipWith #-}++revChunks :: [T.Text] -> Text+revChunks = L.foldl' (flip chunk) Empty++emptyError :: String -> a+emptyError fun = P.error ("Data.Text.Lazy." ++ fun ++ ": empty input")++impossibleError :: String -> a+impossibleError fun = P.error ("Data.Text.Lazy." ++ fun ++ ": impossible case")
+ src/Data/Text/Lazy/Builder.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}+#if __GLASGOW_HASKELL__ >= 702+{-# LANGUAGE Trustworthy #-}+#endif++-----------------------------------------------------------------------------+-- |+-- Module      : Data.Text.Lazy.Builder+-- Copyright   : (c) 2013 Bryan O'Sullivan+--               (c) 2010 Johan Tibell+-- License     : BSD-style (see LICENSE)+--+-- Maintainer  : Johan Tibell <johan.tibell@gmail.com>+-- Portability : portable to Hugs and GHC+--+-- Efficient construction of lazy @Text@ values.  The principal+-- operations on a @Builder@ are @singleton@, @fromText@, and+-- @fromLazyText@, which construct new builders, and 'mappend', which+-- concatenates two builders.+--+-- To get maximum performance when building lazy @Text@ values using a+-- builder, associate @mappend@ calls to the right.  For example,+-- prefer+--+-- > singleton 'a' `mappend` (singleton 'b' `mappend` singleton 'c')+--+-- to+--+-- > singleton 'a' `mappend` singleton 'b' `mappend` singleton 'c'+--+-- as the latter associates @mappend@ to the left. Or, equivalently,+-- prefer+--+--  > singleton 'a' <> singleton 'b' <> singleton 'c'+--+-- since the '<>' from recent versions of 'Data.Monoid' associates+-- to the right.++-----------------------------------------------------------------------------++module Data.Text.Lazy.Builder+   ( -- * The Builder type+     Builder+   , toLazyText+   , toLazyTextWith++     -- * Constructing Builders+   , singleton+   , fromText+   , fromLazyText+   , fromString++     -- * Flushing the buffer state+   , flush+   ) where++import Data.Text.Internal.Builder
+ src/Data/Text/Lazy/Builder/Int.hs view
@@ -0,0 +1,272 @@+{-# LANGUAGE BangPatterns, CPP, MagicHash, RankNTypes, ScopedTypeVariables,+    UnboxedTuples #-}+#if __GLASGOW_HASKELL__ >= 702+{-# LANGUAGE Trustworthy #-}+#endif++-- Module:      Data.Text.Lazy.Builder.Int+-- Copyright:   (c) 2013 Bryan O'Sullivan+--              (c) 2011 MailRank, Inc.+-- License:     BSD-style+-- Maintainer:  Bryan O'Sullivan <bos@serpentine.com>+-- Portability: portable+--+-- Efficiently write an integral value to a 'Builder'.++module Data.Text.Lazy.Builder.Int+    (+      decimal+    , hexadecimal+    ) where++import Data.Int (Int8, Int16, Int32, Int64)+import Data.Monoid (mempty)+import qualified Data.ByteString.Unsafe as B+import Data.Text.Internal.Builder.Functions ((<>), i2d)+import Data.Text.Internal.Builder+import Data.Text.Internal.Builder.Int.Digits (digits)+import Data.Text.Array+import Data.Word (Word, Word8, Word16, Word32, Word64)+import GHC.Base (quotInt, remInt)+import GHC.Types (Int(..))+import Control.Monad.ST+#if MIN_VERSION_base(4,11,0)+import Prelude hiding ((<>))+#endif++#ifdef  __GLASGOW_HASKELL__++#if __GLASGOW_HASKELL__ >= 811++import GHC.Num.Integer+#define HAS_INTEGER_CONSTR 1+#define quotRemInteger integerQuotRem#++#else++import GHC.Num (quotRemInteger)++# if defined(INTEGER_GMP)+import GHC.Integer.GMP.Internals (Integer(S#))+#define IS S#+#define HAS_INTEGER_CONSTR 1+# elif defined(INTEGER_SIMPLE)+import GHC.Integer ()+# else+# error "You need to use either GMP or integer-simple."+# endif+#endif++#endif++decimal :: Integral a => a -> Builder+{-# RULES "decimal/Int8" decimal = boundedDecimal :: Int8 -> Builder #-}+{-# RULES "decimal/Int" decimal = boundedDecimal :: Int -> Builder #-}+{-# RULES "decimal/Int16" decimal = boundedDecimal :: Int16 -> Builder #-}+{-# RULES "decimal/Int32" decimal = boundedDecimal :: Int32 -> Builder #-}+{-# RULES "decimal/Int64" decimal = boundedDecimal :: Int64 -> Builder #-}+{-# RULES "decimal/Word" decimal = positive :: Data.Word.Word -> Builder #-}+{-# RULES "decimal/Word8" decimal = positive :: Word8 -> Builder #-}+{-# RULES "decimal/Word16" decimal = positive :: Word16 -> Builder #-}+{-# RULES "decimal/Word32" decimal = positive :: Word32 -> Builder #-}+{-# RULES "decimal/Word64" decimal = positive :: Word64 -> Builder #-}+{-# RULES "decimal/Integer" decimal = integer 10 :: Integer -> Builder #-}+decimal i = decimal' (<= -128) i+{-# NOINLINE decimal #-}++boundedDecimal :: (Integral a, Bounded a) => a -> Builder+{-# SPECIALIZE boundedDecimal :: Int -> Builder #-}+{-# SPECIALIZE boundedDecimal :: Int8 -> Builder #-}+{-# SPECIALIZE boundedDecimal :: Int16 -> Builder #-}+{-# SPECIALIZE boundedDecimal :: Int32 -> Builder #-}+{-# SPECIALIZE boundedDecimal :: Int64 -> Builder #-}+boundedDecimal i = decimal' (== minBound) i++decimal' :: (Integral a) => (a -> Bool) -> a -> Builder+{-# INLINE decimal' #-}+decimal' p i+    | i < 0 = if p i+              then let (q, r) = i `quotRem` 10+                       qq = -q+                       !n = countDigits qq+                   in writeN (n + 2) $ \marr off -> do+                       unsafeWrite marr off minus+                       posDecimal marr (off+1) n qq+                       unsafeWrite marr (off+n+1) (i2w (-r))+              else let j = -i+                       !n = countDigits j+                   in writeN (n + 1) $ \marr off ->+                       unsafeWrite marr off minus >> posDecimal marr (off+1) n j+    | otherwise = positive i++positive :: (Integral a) => a -> Builder+{-# SPECIALIZE positive :: Int -> Builder #-}+{-# SPECIALIZE positive :: Int8 -> Builder #-}+{-# SPECIALIZE positive :: Int16 -> Builder #-}+{-# SPECIALIZE positive :: Int32 -> Builder #-}+{-# SPECIALIZE positive :: Int64 -> Builder #-}+{-# SPECIALIZE positive :: Word -> Builder #-}+{-# SPECIALIZE positive :: Word8 -> Builder #-}+{-# SPECIALIZE positive :: Word16 -> Builder #-}+{-# SPECIALIZE positive :: Word32 -> Builder #-}+{-# SPECIALIZE positive :: Word64 -> Builder #-}+positive i+    | i < 10    = writeN 1 $ \marr off -> unsafeWrite marr off (i2w i)+    | otherwise = let !n = countDigits i+                  in writeN n $ \marr off -> posDecimal marr off n i++posDecimal :: (Integral a) =>+              forall s. MArray s -> Int -> Int -> a -> ST s ()+{-# INLINE posDecimal #-}+posDecimal marr off0 ds v0 = go (off0 + ds - 1) v0+  where go off v+           | v >= 100 = do+               let (q, r) = v `quotRem` 100+               write2 off r+               go (off - 2) q+           | v < 10    = unsafeWrite marr off (i2w v)+           | otherwise = write2 off v+        write2 off i0 = do+          let i = fromIntegral i0; j = i + i+          unsafeWrite marr off $ get (j + 1)+          unsafeWrite marr (off - 1) $ get j+        get = fromIntegral . B.unsafeIndex digits++minus, zero :: Word16+{-# INLINE minus #-}+{-# INLINE zero #-}+minus = 45+zero = 48++i2w :: (Integral a) => a -> Word16+{-# INLINE i2w #-}+i2w v = zero + fromIntegral v++countDigits :: (Integral a) => a -> Int+{-# INLINE countDigits #-}+countDigits v0+  | fromIntegral v64 == v0 = go 1 v64+  | otherwise              = goBig 1 (fromIntegral v0)+  where v64 = fromIntegral v0+        goBig !k (v :: Integer)+           | v > big   = goBig (k + 19) (v `quot` big)+           | otherwise = go k (fromIntegral v)+        big = 10000000000000000000+        go !k (v :: Word64)+           | v < 10    = k+           | v < 100   = k + 1+           | v < 1000  = k + 2+           | v < 1000000000000 =+               k + if v < 100000000+                   then if v < 1000000+                        then if v < 10000+                             then 3+                             else 4 + fin v 100000+                        else 6 + fin v 10000000+                   else if v < 10000000000+                        then 8 + fin v 1000000000+                        else 10 + fin v 100000000000+           | otherwise = go (k + 12) (v `quot` 1000000000000)+        fin v n = if v >= n then 1 else 0++hexadecimal :: Integral a => a -> Builder+{-# SPECIALIZE hexadecimal :: Int -> Builder #-}+{-# SPECIALIZE hexadecimal :: Int8 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Int16 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Int32 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Int64 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Word -> Builder #-}+{-# SPECIALIZE hexadecimal :: Word8 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Word16 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Word32 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Word64 -> Builder #-}+{-# RULES "hexadecimal/Integer"+    hexadecimal = hexInteger :: Integer -> Builder #-}+hexadecimal i+    | i < 0     = error hexErrMsg+    | otherwise = go i+  where+    go n | n < 16    = hexDigit n+         | otherwise = go (n `quot` 16) <> hexDigit (n `rem` 16)+{-# NOINLINE[0] hexadecimal #-}++hexInteger :: Integer -> Builder+hexInteger i+    | i < 0     = error hexErrMsg+    | otherwise = integer 16 i++hexErrMsg :: String+hexErrMsg = "Data.Text.Lazy.Builder.Int.hexadecimal: applied to negative number"++hexDigit :: Integral a => a -> Builder+hexDigit n+    | n <= 9    = singleton $! i2d (fromIntegral n)+    | otherwise = singleton $! toEnum (fromIntegral n + 87)+{-# INLINE hexDigit #-}++data T = T !Integer !Int++integer :: Int -> Integer -> Builder+#ifdef HAS_INTEGER_CONSTR+integer 10 (IS i#) = decimal (I# i#)+integer 16 (IS i#) = hexadecimal (I# i#)+#endif+integer base i+    | i < 0     = singleton '-' <> go (-i)+    | otherwise = go i+  where+    go n | n < maxInt = int (fromInteger n)+         | otherwise  = putH (splitf (maxInt * maxInt) n)++    splitf p n+      | p > n       = [n]+      | otherwise   = splith p (splitf (p*p) n)++    splith p (n:ns) = case n `quotRemInteger` p of+                        (# q,r #) | q > 0     -> q : r : splitb p ns+                                  | otherwise -> r : splitb p ns+    splith _ _      = error "splith: the impossible happened."++    splitb p (n:ns) = case n `quotRemInteger` p of+                        (# q,r #) -> q : r : splitb p ns+    splitb _ _      = []++    T maxInt10 maxDigits10 =+        until ((>mi) . (*10) . fstT) (\(T n d) -> T (n*10) (d+1)) (T 10 1)+      where mi = fromIntegral (maxBound :: Int)+    T maxInt16 maxDigits16 =+        until ((>mi) . (*16) . fstT) (\(T n d) -> T (n*16) (d+1)) (T 16 1)+      where mi = fromIntegral (maxBound :: Int)++    fstT (T a _) = a++    maxInt | base == 10 = maxInt10+           | otherwise  = maxInt16+    maxDigits | base == 10 = maxDigits10+              | otherwise  = maxDigits16++    putH (n:ns) = case n `quotRemInteger` maxInt of+                    (# x,y #)+                        | q > 0     -> int q <> pblock r <> putB ns+                        | otherwise -> int r <> putB ns+                        where q = fromInteger x+                              r = fromInteger y+    putH _ = error "putH: the impossible happened"++    putB (n:ns) = case n `quotRemInteger` maxInt of+                    (# x,y #) -> pblock q <> pblock r <> putB ns+                        where q = fromInteger x+                              r = fromInteger y+    putB _ = Data.Monoid.mempty++    int :: Int -> Builder+    int x | base == 10 = decimal x+          | otherwise  = hexadecimal x++    pblock = loop maxDigits+      where+        loop !d !n+            | d == 1    = hexDigit n+            | otherwise = loop (d-1) q <> hexDigit r+            where q = n `quotInt` base+                  r = n `remInt` base
+ src/Data/Text/Lazy/Builder/RealFloat.hs view
@@ -0,0 +1,253 @@+{-# LANGUAGE CPP, OverloadedStrings #-}+#if __GLASGOW_HASKELL__ >= 702+{-# LANGUAGE Trustworthy #-}+#endif++-- |+-- Module:    Data.Text.Lazy.Builder.RealFloat+-- Copyright: (c) The University of Glasgow 1994-2002+-- License:   see libraries/base/LICENSE+--+-- Write a floating point value to a 'Builder'.++module Data.Text.Lazy.Builder.RealFloat+    (+      FPFormat(..)+    , realFloat+    , formatRealFloat+    ) where++import Data.Array.Base (unsafeAt)+import Data.Array.IArray+import Data.Text.Internal.Builder.Functions ((<>), i2d)+import Data.Text.Lazy.Builder.Int (decimal)+import Data.Text.Internal.Builder.RealFloat.Functions (roundTo)+import Data.Text.Lazy.Builder+import qualified Data.Text as T+#if MIN_VERSION_base(4,11,0)+import Prelude hiding ((<>))+#endif++-- | Control the rendering of floating point numbers.+data FPFormat = Exponent+              -- ^ Scientific notation (e.g. @2.3e123@).+              | Fixed+              -- ^ Standard decimal notation.+              | Generic+              -- ^ Use decimal notation for values between @0.1@ and+              -- @9,999,999@, and scientific notation otherwise.+                deriving (Enum, Read, Show)++-- | Show a signed 'RealFloat' value to full precision,+-- using standard decimal notation for arguments whose absolute value lies+-- between @0.1@ and @9,999,999@, and scientific notation otherwise.+realFloat :: (RealFloat a) => a -> Builder+{-# SPECIALIZE realFloat :: Float -> Builder #-}+{-# SPECIALIZE realFloat :: Double -> Builder #-}+realFloat x = formatRealFloat Generic Nothing x++-- | Encode a signed 'RealFloat' according to 'FPFormat' and optionally requested precision.+--+-- This corresponds to the @show{E,F,G}Float@ operations provided by @base@'s "Numeric" module.+--+-- __NOTE__: The functions in @base-4.12@ changed the serialisation in+-- case of a @Just 0@ precision; this version of @text@ still provides+-- the serialisation as implemented in @base-4.11@. The next major+-- version of @text@ will switch to the more correct @base-4.12@ serialisation.+formatRealFloat :: (RealFloat a) =>+                   FPFormat+                -> Maybe Int  -- ^ Number of decimal places to render.+                -> a+                -> Builder+{-# SPECIALIZE formatRealFloat :: FPFormat -> Maybe Int -> Float -> Builder #-}+{-# SPECIALIZE formatRealFloat :: FPFormat -> Maybe Int -> Double -> Builder #-}+formatRealFloat fmt decs x+   | isNaN x                   = "NaN"+   | isInfinite x              = if x < 0 then "-Infinity" else "Infinity"+   | x < 0 || isNegativeZero x = singleton '-' <> doFmt fmt (floatToDigits (-x))+   | otherwise                 = doFmt fmt (floatToDigits x)+ where+  doFmt format (is, e) =+    let ds = map i2d is in+    case format of+     Generic ->+      doFmt (if e < 0 || e > 7 then Exponent else Fixed)+            (is,e)+     Exponent ->+      case decs of+       Nothing ->+        let show_e' = decimal (e-1) in+        case ds of+          "0"     -> "0.0e0"+          [d]     -> singleton d <> ".0e" <> show_e'+          (d:ds') -> singleton d <> singleton '.' <> fromString ds' <> singleton 'e' <> show_e'+          []      -> error "formatRealFloat/doFmt/Exponent/Nothing: []"+       Just dec ->+        let dec' = max dec 1 in+        case is of+         [0] -> "0." <> fromText (T.replicate dec' "0") <> "e0"+         _ ->+          let (ei,is') = roundTo (dec'+1) is+              is'' = map i2d (if ei > 0 then init is' else is')+          in case is'' of+               [] -> error "formatRealFloat/doFmt/Exponent/Just: []"+               (d:ds') -> singleton d <> singleton '.' <> fromString ds' <> singleton 'e' <> decimal (e-1+ei)+     Fixed ->+      let+       mk0 ls = case ls of { "" -> "0" ; _ -> fromString ls}+      in+      case decs of+       Nothing+          | e <= 0    -> "0." <> fromText (T.replicate (-e) "0") <> fromString ds+          | otherwise ->+             let+                f 0 s    rs  = mk0 (reverse s) <> singleton '.' <> mk0 rs+                f n s    ""  = f (n-1) ('0':s) ""+                f n s (r:rs) = f (n-1) (r:s) rs+             in+                f e "" ds+       Just dec ->+        let dec' = max dec 0 in+        if e >= 0 then+         let+          (ei,is') = roundTo (dec' + e) is+          (ls,rs)  = splitAt (e+ei) (map i2d is')+         in+         mk0 ls <> (if null rs then "" else singleton '.' <> fromString rs)+        else+         let (ei,is') = roundTo dec' (replicate (-e) 0 ++ is)+             is'' = map i2d (if ei > 0 then is' else 0:is')+         in case is'' of+              [] -> error "formatRealFloat/doFmt/Fixed: []"+              (d:ds') -> singleton d <> (if null ds' then "" else singleton '.' <> fromString ds')+++-- Based on "Printing Floating-Point Numbers Quickly and Accurately"+-- by R.G. Burger and R.K. Dybvig in PLDI 96.+-- This version uses a much slower logarithm estimator. It should be improved.++-- | 'floatToDigits' takes a base and a non-negative 'RealFloat' number,+-- and returns a list of digits and an exponent.+-- In particular, if @x>=0@, and+--+-- > floatToDigits base x = ([d1,d2,...,dn], e)+--+-- then+--+--      (1) @n >= 1@+--+--      (2) @x = 0.d1d2...dn * (base**e)@+--+--      (3) @0 <= di <= base-1@++floatToDigits :: (RealFloat a) => a -> ([Int], Int)+{-# SPECIALIZE floatToDigits :: Float -> ([Int], Int) #-}+{-# SPECIALIZE floatToDigits :: Double -> ([Int], Int) #-}+floatToDigits 0 = ([0], 0)+floatToDigits x =+ let+  (f0, e0) = decodeFloat x+  (minExp0, _) = floatRange x+  p = floatDigits x+  b = floatRadix x+  minExp = minExp0 - p -- the real minimum exponent+  -- Haskell requires that f be adjusted so denormalized numbers+  -- will have an impossibly low exponent.  Adjust for this.+  (f, e) =+   let n = minExp - e0 in+   if n > 0 then (f0 `quot` (expt b n), e0+n) else (f0, e0)+  (r, s, mUp, mDn) =+   if e >= 0 then+    let be = expt b e in+    if f == expt b (p-1) then+      (f*be*b*2, 2*b, be*b, be)     -- according to Burger and Dybvig+    else+      (f*be*2, 2, be, be)+   else+    if e > minExp && f == expt b (p-1) then+      (f*b*2, expt b (-e+1)*2, b, 1)+    else+      (f*2, expt b (-e)*2, 1, 1)+  k :: Int+  k =+   let+    k0 :: Int+    k0 =+     if b == 2 then+        -- logBase 10 2 is very slightly larger than 8651/28738+        -- (about 5.3558e-10), so if log x >= 0, the approximation+        -- k1 is too small, hence we add one and need one fixup step less.+        -- If log x < 0, the approximation errs rather on the high side.+        -- That is usually more than compensated for by ignoring the+        -- fractional part of logBase 2 x, but when x is a power of 1/2+        -- or slightly larger and the exponent is a multiple of the+        -- denominator of the rational approximation to logBase 10 2,+        -- k1 is larger than logBase 10 x. If k1 > 1 + logBase 10 x,+        -- we get a leading zero-digit we don't want.+        -- With the approximation 3/10, this happened for+        -- 0.5^1030, 0.5^1040, ..., 0.5^1070 and values close above.+        -- The approximation 8651/28738 guarantees k1 < 1 + logBase 10 x+        -- for IEEE-ish floating point types with exponent fields+        -- <= 17 bits and mantissae of several thousand bits, earlier+        -- convergents to logBase 10 2 would fail for long double.+        -- Using quot instead of div is a little faster and requires+        -- fewer fixup steps for negative lx.+        let lx = p - 1 + e0+            k1 = (lx * 8651) `quot` 28738+        in if lx >= 0 then k1 + 1 else k1+     else+        -- f :: Integer, log :: Float -> Float,+        --               ceiling :: Float -> Int+        ceiling ((log (fromInteger (f+1) :: Float) ++                 fromIntegral e * log (fromInteger b)) /+                   log 10)+--WAS:            fromInt e * log (fromInteger b))++    fixup n =+      if n >= 0 then+        if r + mUp <= expt 10 n * s then n else fixup (n+1)+      else+        if expt 10 (-n) * (r + mUp) <= s then n else fixup (n+1)+   in+   fixup k0++  gen ds rn sN mUpN mDnN =+   let+    (dn, rn') = (rn * 10) `quotRem` sN+    mUpN' = mUpN * 10+    mDnN' = mDnN * 10+   in+   case (rn' < mDnN', rn' + mUpN' > sN) of+    (True,  False) -> dn : ds+    (False, True)  -> dn+1 : ds+    (True,  True)  -> if rn' * 2 < sN then dn : ds else dn+1 : ds+    (False, False) -> gen (dn:ds) rn' sN mUpN' mDnN'++  rds =+   if k >= 0 then+      gen [] r (s * expt 10 k) mUp mDn+   else+     let bk = expt 10 (-k) in+     gen [] (r * bk) s (mUp * bk) (mDn * bk)+ in+ (map fromIntegral (reverse rds), k)++-- Exponentiation with a cache for the most common numbers.+minExpt, maxExpt :: Int+minExpt = 0+maxExpt = 1100++expt :: Integer -> Int -> Integer+expt base n+    | base == 2 && n >= minExpt && n <= maxExpt = expts `unsafeAt` n+    | base == 10 && n <= maxExpt10              = expts10 `unsafeAt` n+    | otherwise                                 = base^n++expts :: Array Int Integer+expts = array (minExpt,maxExpt) [(n,2^n) | n <- [minExpt .. maxExpt]]++maxExpt10 :: Int+maxExpt10 = 324++expts10 :: Array Int Integer+expts10 = array (minExpt,maxExpt10) [(n,10^n) | n <- [minExpt .. maxExpt10]]
+ src/Data/Text/Lazy/Encoding.hs view
@@ -0,0 +1,250 @@+{-# LANGUAGE BangPatterns,CPP #-}+#if __GLASGOW_HASKELL__ >= 702+{-# LANGUAGE Trustworthy #-}+#endif+-- |+-- Module      : Data.Text.Lazy.Encoding+-- Copyright   : (c) 2009, 2010 Bryan O'Sullivan+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Portability : portable+--+-- Functions for converting lazy 'Text' values to and from lazy+-- 'ByteString', using several standard encodings.+--+-- To gain access to a much larger family of encodings, use the+-- <http://hackage.haskell.org/package/text-icu text-icu package>.++module Data.Text.Lazy.Encoding+    (+    -- * Decoding ByteStrings to Text+    -- $strict+      decodeASCII+    , decodeLatin1+    , decodeUtf8+    , decodeUtf16LE+    , decodeUtf16BE+    , decodeUtf32LE+    , decodeUtf32BE++    -- ** Catchable failure+    , decodeUtf8'++    -- ** Controllable error handling+    , decodeUtf8With+    , decodeUtf16LEWith+    , decodeUtf16BEWith+    , decodeUtf32LEWith+    , decodeUtf32BEWith++    -- * Encoding Text to ByteStrings+    , encodeUtf8+    , encodeUtf16LE+    , encodeUtf16BE+    , encodeUtf32LE+    , encodeUtf32BE++    -- * Encoding Text using ByteString Builders+    , encodeUtf8Builder+    , encodeUtf8BuilderEscaped+    ) where++import Control.Exception (evaluate, try)+import Data.Monoid (Monoid(..))+import Data.Text.Encoding.Error (OnDecodeError, UnicodeException, strictDecode)+import Data.Text.Internal.Lazy (Text(..), chunk, empty, foldrChunks)+import Data.Word (Word8)+import qualified Data.ByteString as S+import qualified Data.ByteString.Builder as B+import qualified Data.ByteString.Builder.Extra as B (safeStrategy, toLazyByteStringWith)+import qualified Data.ByteString.Builder.Prim as BP+import qualified Data.ByteString.Lazy as B+import qualified Data.ByteString.Lazy.Internal as B+import qualified Data.ByteString.Unsafe as B+import qualified Data.Text as T+import qualified Data.Text.Encoding as TE+import qualified Data.Text.Internal.Lazy.Encoding.Fusion as E+import qualified Data.Text.Internal.Lazy.Fusion as F+import Data.Text.Unsafe (unsafeDupablePerformIO)++-- $strict+--+-- All of the single-parameter functions for decoding bytestrings+-- encoded in one of the Unicode Transformation Formats (UTF) operate+-- in a /strict/ mode: each will throw an exception if given invalid+-- input.+--+-- Each function has a variant, whose name is suffixed with -'With',+-- that gives greater control over the handling of decoding errors.+-- For instance, 'decodeUtf8' will throw an exception, but+-- 'decodeUtf8With' allows the programmer to determine what to do on a+-- decoding error.++-- | /Deprecated/.  Decode a 'ByteString' containing 7-bit ASCII+-- encoded text.+decodeASCII :: B.ByteString -> Text+decodeASCII = decodeUtf8+{-# DEPRECATED decodeASCII "Use decodeUtf8 instead" #-}++-- | Decode a 'ByteString' containing Latin-1 (aka ISO-8859-1) encoded text.+decodeLatin1 :: B.ByteString -> Text+decodeLatin1 = foldr (chunk . TE.decodeLatin1) empty . B.toChunks++-- | Decode a 'ByteString' containing UTF-8 encoded text.+decodeUtf8With :: OnDecodeError -> B.ByteString -> Text+decodeUtf8With onErr (B.Chunk b0 bs0) =+    case TE.streamDecodeUtf8With onErr b0 of+      TE.Some t l f -> chunk t (go f l bs0)+  where+    go f0 _ (B.Chunk b bs) =+      case f0 b of+        TE.Some t l f -> chunk t (go f l bs)+    go _ l _+      | S.null l  = empty+      | otherwise = case onErr desc (Just (B.unsafeHead l)) of+                      Nothing -> empty+                      Just c  -> Chunk (T.singleton c) Empty+    desc = "Data.Text.Lazy.Encoding.decodeUtf8With: Invalid UTF-8 stream"+decodeUtf8With _ _ = empty++-- | Decode a 'ByteString' containing UTF-8 encoded text that is known+-- to be valid.+--+-- If the input contains any invalid UTF-8 data, an exception will be+-- thrown that cannot be caught in pure code.  For more control over+-- the handling of invalid data, use 'decodeUtf8'' or+-- 'decodeUtf8With'.+decodeUtf8 :: B.ByteString -> Text+decodeUtf8 = decodeUtf8With strictDecode+{-# INLINE[0] decodeUtf8 #-}++-- This rule seems to cause performance loss.+{- RULES "LAZY STREAM stream/decodeUtf8' fusion" [1]+   forall bs. F.stream (decodeUtf8' bs) = E.streamUtf8 strictDecode bs #-}++-- | Decode a 'ByteString' containing UTF-8 encoded text..+--+-- If the input contains any invalid UTF-8 data, the relevant+-- exception will be returned, otherwise the decoded text.+--+-- /Note/: this function is /not/ lazy, as it must decode its entire+-- input before it can return a result.  If you need lazy (streaming)+-- decoding, use 'decodeUtf8With' in lenient mode.+decodeUtf8' :: B.ByteString -> Either UnicodeException Text+decodeUtf8' bs = unsafeDupablePerformIO $ do+                   let t = decodeUtf8 bs+                   try (evaluate (rnf t `seq` t))+  where+    rnf Empty        = ()+    rnf (Chunk _ ts) = rnf ts+{-# INLINE decodeUtf8' #-}++-- | Encode text using UTF-8 encoding.+encodeUtf8 :: Text -> B.ByteString+encodeUtf8    Empty       = B.empty+encodeUtf8 lt@(Chunk t _) =+    B.toLazyByteStringWith strategy B.empty $ encodeUtf8Builder lt+  where+    -- To improve our small string performance, we use a strategy that+    -- allocates a buffer that is guaranteed to be large enough for the+    -- encoding of the first chunk, but not larger than the default+    -- B.smallChunkSize. We clamp the firstChunkSize to ensure that we don't+    -- generate too large buffers which hamper streaming.+    firstChunkSize  = min B.smallChunkSize (4 * (T.length t + 1))+    strategy        = B.safeStrategy firstChunkSize B.defaultChunkSize++-- | Encode text to a ByteString 'B.Builder' using UTF-8 encoding.+--+-- @since 1.1.0.0+encodeUtf8Builder :: Text -> B.Builder+encodeUtf8Builder =+    foldrChunks (\c b -> TE.encodeUtf8Builder c `mappend` b) Data.Monoid.mempty++-- | Encode text using UTF-8 encoding and escape the ASCII characters using+-- a 'BP.BoundedPrim'.+--+-- Use this function is to implement efficient encoders for text-based formats+-- like JSON or HTML.+--+-- @since 1.1.0.0+{-# INLINE encodeUtf8BuilderEscaped #-}+encodeUtf8BuilderEscaped :: BP.BoundedPrim Word8 -> Text -> B.Builder+encodeUtf8BuilderEscaped prim =+    foldrChunks (\c b -> TE.encodeUtf8BuilderEscaped prim c `mappend` b) mempty++-- | Decode text from little endian UTF-16 encoding.+decodeUtf16LEWith :: OnDecodeError -> B.ByteString -> Text+decodeUtf16LEWith onErr bs = F.unstream (E.streamUtf16LE onErr bs)+{-# INLINE decodeUtf16LEWith #-}++-- | Decode text from little endian UTF-16 encoding.+--+-- If the input contains any invalid little endian UTF-16 data, an+-- exception will be thrown.  For more control over the handling of+-- invalid data, use 'decodeUtf16LEWith'.+decodeUtf16LE :: B.ByteString -> Text+decodeUtf16LE = decodeUtf16LEWith strictDecode+{-# INLINE decodeUtf16LE #-}++-- | Decode text from big endian UTF-16 encoding.+decodeUtf16BEWith :: OnDecodeError -> B.ByteString -> Text+decodeUtf16BEWith onErr bs = F.unstream (E.streamUtf16BE onErr bs)+{-# INLINE decodeUtf16BEWith #-}++-- | Decode text from big endian UTF-16 encoding.+--+-- If the input contains any invalid big endian UTF-16 data, an+-- exception will be thrown.  For more control over the handling of+-- invalid data, use 'decodeUtf16BEWith'.+decodeUtf16BE :: B.ByteString -> Text+decodeUtf16BE = decodeUtf16BEWith strictDecode+{-# INLINE decodeUtf16BE #-}++-- | Encode text using little endian UTF-16 encoding.+encodeUtf16LE :: Text -> B.ByteString+encodeUtf16LE txt = B.fromChunks (foldrChunks ((:) . TE.encodeUtf16LE) [] txt)+{-# INLINE encodeUtf16LE #-}++-- | Encode text using big endian UTF-16 encoding.+encodeUtf16BE :: Text -> B.ByteString+encodeUtf16BE txt = B.fromChunks (foldrChunks ((:) . TE.encodeUtf16BE) [] txt)+{-# INLINE encodeUtf16BE #-}++-- | Decode text from little endian UTF-32 encoding.+decodeUtf32LEWith :: OnDecodeError -> B.ByteString -> Text+decodeUtf32LEWith onErr bs = F.unstream (E.streamUtf32LE onErr bs)+{-# INLINE decodeUtf32LEWith #-}++-- | Decode text from little endian UTF-32 encoding.+--+-- If the input contains any invalid little endian UTF-32 data, an+-- exception will be thrown.  For more control over the handling of+-- invalid data, use 'decodeUtf32LEWith'.+decodeUtf32LE :: B.ByteString -> Text+decodeUtf32LE = decodeUtf32LEWith strictDecode+{-# INLINE decodeUtf32LE #-}++-- | Decode text from big endian UTF-32 encoding.+decodeUtf32BEWith :: OnDecodeError -> B.ByteString -> Text+decodeUtf32BEWith onErr bs = F.unstream (E.streamUtf32BE onErr bs)+{-# INLINE decodeUtf32BEWith #-}++-- | Decode text from big endian UTF-32 encoding.+--+-- If the input contains any invalid big endian UTF-32 data, an+-- exception will be thrown.  For more control over the handling of+-- invalid data, use 'decodeUtf32BEWith'.+decodeUtf32BE :: B.ByteString -> Text+decodeUtf32BE = decodeUtf32BEWith strictDecode+{-# INLINE decodeUtf32BE #-}++-- | Encode text using little endian UTF-32 encoding.+encodeUtf32LE :: Text -> B.ByteString+encodeUtf32LE txt = B.fromChunks (foldrChunks ((:) . TE.encodeUtf32LE) [] txt)+{-# INLINE encodeUtf32LE #-}++-- | Encode text using big endian UTF-32 encoding.+encodeUtf32BE :: Text -> B.ByteString+encodeUtf32BE txt = B.fromChunks (foldrChunks ((:) . TE.encodeUtf32BE) [] txt)+{-# INLINE encodeUtf32BE #-}
+ src/Data/Text/Lazy/IO.hs view
@@ -0,0 +1,195 @@+{-# LANGUAGE BangPatterns, CPP, RecordWildCards #-}+#if __GLASGOW_HASKELL__ >= 702+{-# LANGUAGE Trustworthy #-}+#endif+-- |+-- Module      : Data.Text.Lazy.IO+-- Copyright   : (c) 2009, 2010 Bryan O'Sullivan,+--               (c) 2009 Simon Marlow+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Portability : GHC+--+-- Efficient locale-sensitive support for lazy text I\/O.+--+-- Skip past the synopsis for some important notes on performance and+-- portability across different versions of GHC.++module Data.Text.Lazy.IO+    (+    -- * Performance+    -- $performance++    -- * Locale support+    -- $locale+    -- * File-at-a-time operations+      readFile+    , writeFile+    , appendFile+    -- * Operations on handles+    , hGetContents+    , hGetLine+    , hPutStr+    , hPutStrLn+    -- * Special cases for standard input and output+    , interact+    , getContents+    , getLine+    , putStr+    , putStrLn+    ) where++import Data.Text.Lazy (Text)+import Prelude hiding (appendFile, getContents, getLine, interact,+                       putStr, putStrLn, readFile, writeFile)+import System.IO (Handle, IOMode(..), hPutChar, openFile, stdin, stdout,+                  withFile)+import qualified Data.Text.IO as T+import qualified Data.Text.Lazy as L+import qualified Control.Exception as E+import Control.Monad (when)+import Data.IORef (readIORef)+import Data.Text.Internal.IO (hGetLineWith, readChunk)+import Data.Text.Internal.Lazy (chunk, empty)+import GHC.IO.Buffer (isEmptyBuffer)+import GHC.IO.Exception (IOException(..), IOErrorType(..), ioException)+import GHC.IO.Handle.Internals (augmentIOError, hClose_help,+                                wantReadableHandle, withHandle)+import GHC.IO.Handle.Types (Handle__(..), HandleType(..))+import System.IO (BufferMode(..), hGetBuffering, hSetBuffering)+import System.IO.Error (isEOFError)+import System.IO.Unsafe (unsafeInterleaveIO)++-- $performance+--+-- The functions in this module obey the runtime system's locale,+-- character set encoding, and line ending conversion settings.+--+-- If you know in advance that you will be working with data that has+-- a specific encoding (e.g. UTF-8), and your application is highly+-- performance sensitive, you may find that it is faster to perform+-- I\/O with bytestrings and to encode and decode yourself than to use+-- the functions in this module.+--+-- Whether this will hold depends on the version of GHC you are using,+-- the platform you are working on, the data you are working with, and+-- the encodings you are using, so be sure to test for yourself.++-- | Read a file and return its contents as a string.  The file is+-- read lazily, as with 'getContents'.+readFile :: FilePath -> IO Text+readFile name = openFile name ReadMode >>= hGetContents++-- | Write a string to a file.  The file is truncated to zero length+-- before writing begins.+writeFile :: FilePath -> Text -> IO ()+writeFile p = withFile p WriteMode . flip hPutStr++-- | Write a string the end of a file.+appendFile :: FilePath -> Text -> IO ()+appendFile p = withFile p AppendMode . flip hPutStr++-- | Lazily read the remaining contents of a 'Handle'.  The 'Handle'+-- will be closed after the read completes, or on error.+hGetContents :: Handle -> IO Text+hGetContents h = do+  chooseGoodBuffering h+  wantReadableHandle "hGetContents" h $ \hh -> do+    ts <- lazyRead h+    return (hh{haType=SemiClosedHandle}, ts)++-- | Use a more efficient buffer size if we're reading in+-- block-buffered mode with the default buffer size.+chooseGoodBuffering :: Handle -> IO ()+chooseGoodBuffering h = do+  bufMode <- hGetBuffering h+  when (bufMode == BlockBuffering Nothing) $+    hSetBuffering h (BlockBuffering (Just 16384))++lazyRead :: Handle -> IO Text+lazyRead h = unsafeInterleaveIO $+  withHandle "hGetContents" h $ \hh -> do+    case haType hh of+      ClosedHandle     -> return (hh, L.empty)+      SemiClosedHandle -> lazyReadBuffered h hh+      _                -> ioException+                          (IOError (Just h) IllegalOperation "hGetContents"+                           "illegal handle type" Nothing Nothing)++lazyReadBuffered :: Handle -> Handle__ -> IO (Handle__, Text)+lazyReadBuffered h hh@Handle__{..} = do+   buf <- readIORef haCharBuffer+   (do t <- readChunk hh buf+       ts <- lazyRead h+       return (hh, chunk t ts)) `E.catch` \e -> do+         (hh', _) <- hClose_help hh+         if isEOFError e+           then return $ if isEmptyBuffer buf+                         then (hh', empty)+                         else (hh', L.singleton '\r')+           else E.throwIO (augmentIOError e "hGetContents" h)++-- | Read a single line from a handle.+hGetLine :: Handle -> IO Text+hGetLine = hGetLineWith L.fromChunks++-- | Write a string to a handle.+hPutStr :: Handle -> Text -> IO ()+hPutStr h = mapM_ (T.hPutStr h) . L.toChunks++-- | Write a string to a handle, followed by a newline.+hPutStrLn :: Handle -> Text -> IO ()+hPutStrLn h t = hPutStr h t >> hPutChar h '\n'++-- | The 'interact' function takes a function of type @Text -> Text@+-- as its argument. The entire input from the standard input device is+-- passed (lazily) to this function as its argument, and the resulting+-- string is output on the standard output device.+interact :: (Text -> Text) -> IO ()+interact f = putStr . f =<< getContents++-- | Lazily read all user input on 'stdin' as a single string.+getContents :: IO Text+getContents = hGetContents stdin++-- | Read a single line of user input from 'stdin'.+getLine :: IO Text+getLine = hGetLine stdin++-- | Write a string to 'stdout'.+putStr :: Text -> IO ()+putStr = hPutStr stdout++-- | Write a string to 'stdout', followed by a newline.+putStrLn :: Text -> IO ()+putStrLn = hPutStrLn stdout++-- $locale+--+-- /Note/: The behaviour of functions in this module depends on the+-- version of GHC you are using.+--+-- Beginning with GHC 6.12, text I\/O is performed using the system or+-- handle's current locale and line ending conventions.+--+-- Under GHC 6.10 and earlier, the system I\/O libraries /do not+-- support/ locale-sensitive I\/O or line ending conversion.  On these+-- versions of GHC, functions in this library all use UTF-8.  What+-- does this mean in practice?+--+-- * All data that is read will be decoded as UTF-8.+--+-- * Before data is written, it is first encoded as UTF-8.+--+-- * On both reading and writing, the platform's native newline+--   conversion is performed.+--+-- If you must use a non-UTF-8 locale on an older version of GHC, you+-- will have to perform the transcoding yourself, e.g. as follows:+--+-- > import qualified Data.ByteString.Lazy as B+-- > import Data.Text.Lazy (Text)+-- > import Data.Text.Lazy.Encoding (encodeUtf16)+-- >+-- > putStr_Utf16LE :: Text -> IO ()+-- > putStr_Utf16LE t = B.putStr (encodeUtf16LE t)
+ src/Data/Text/Lazy/Internal.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE BangPatterns, DeriveDataTypeable #-}+-- |+-- Module      : Data.Text.Lazy.Internal+-- Copyright   : (c) 2013 Bryan O'Sullivan+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- This module has been renamed to 'Data.Text.Internal.Lazy'. This+-- name for the module will be removed in the next major release.++module Data.Text.Lazy.Internal+    {-# DEPRECATED "Use Data.Text.Internal.Lazy instead" #-}+    (+      module Data.Text.Internal.Lazy+    ) where++import Data.Text.Internal.Lazy
+ src/Data/Text/Lazy/Read.hs view
@@ -0,0 +1,192 @@+{-# LANGUAGE OverloadedStrings, CPP #-}+#if __GLASGOW_HASKELL__ >= 704+{-# LANGUAGE Safe #-}+#elif __GLASGOW_HASKELL__ >= 702+{-# LANGUAGE Trustworthy #-}+#endif++-- |+-- Module      : Data.Text.Lazy.Read+-- Copyright   : (c) 2010, 2011 Bryan O'Sullivan+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Portability : GHC+--+-- Functions used frequently when reading textual data.+module Data.Text.Lazy.Read+    (+      Reader+    , decimal+    , hexadecimal+    , signed+    , rational+    , double+    ) where++import Control.Monad (liftM)+import Data.Char (isDigit, isHexDigit)+import Data.Int (Int8, Int16, Int32, Int64)+import Data.Ratio ((%))+import Data.Text.Internal.Read+import Data.Text.Lazy as T+import Data.Word (Word, Word8, Word16, Word32, Word64)++-- | Read some text.  If the read succeeds, return its value and the+-- remaining text, otherwise an error message.+type Reader a = IReader Text a+type Parser = IParser Text++-- | Read a decimal integer.  The input must begin with at least one+-- decimal digit, and is consumed until a non-digit or end of string+-- is reached.+--+-- This function does not handle leading sign characters.  If you need+-- to handle signed input, use @'signed' 'decimal'@.+--+-- /Note/: For fixed-width integer types, this function does not+-- attempt to detect overflow, so a sufficiently long input may give+-- incorrect results.  If you are worried about overflow, use+-- 'Integer' for your result type.+decimal :: Integral a => Reader a+{-# SPECIALIZE decimal :: Reader Int #-}+{-# SPECIALIZE decimal :: Reader Int8 #-}+{-# SPECIALIZE decimal :: Reader Int16 #-}+{-# SPECIALIZE decimal :: Reader Int32 #-}+{-# SPECIALIZE decimal :: Reader Int64 #-}+{-# SPECIALIZE decimal :: Reader Integer #-}+{-# SPECIALIZE decimal :: Reader Data.Word.Word #-}+{-# SPECIALIZE decimal :: Reader Word8 #-}+{-# SPECIALIZE decimal :: Reader Word16 #-}+{-# SPECIALIZE decimal :: Reader Word32 #-}+{-# SPECIALIZE decimal :: Reader Word64 #-}+decimal txt+    | T.null h  = Left "input does not start with a digit"+    | otherwise = Right (T.foldl' go 0 h, t)+  where (h,t)  = T.span isDigit txt+        go n d = (n * 10 + fromIntegral (digitToInt d))++-- | Read a hexadecimal integer, consisting of an optional leading+-- @\"0x\"@ followed by at least one hexadecimal digit. Input is+-- consumed until a non-hex-digit or end of string is reached.+-- This function is case insensitive.+--+-- This function does not handle leading sign characters.  If you need+-- to handle signed input, use @'signed' 'hexadecimal'@.+--+-- /Note/: For fixed-width integer types, this function does not+-- attempt to detect overflow, so a sufficiently long input may give+-- incorrect results.  If you are worried about overflow, use+-- 'Integer' for your result type.+hexadecimal :: Integral a => Reader a+{-# SPECIALIZE hexadecimal :: Reader Int #-}+{-# SPECIALIZE hexadecimal :: Reader Integer #-}+hexadecimal txt+    | h == "0x" || h == "0X" = hex t+    | otherwise              = hex txt+ where (h,t) = T.splitAt 2 txt++hex :: Integral a => Reader a+{-# SPECIALIZE hexadecimal :: Reader Int #-}+{-# SPECIALIZE hexadecimal :: Reader Int8 #-}+{-# SPECIALIZE hexadecimal :: Reader Int16 #-}+{-# SPECIALIZE hexadecimal :: Reader Int32 #-}+{-# SPECIALIZE hexadecimal :: Reader Int64 #-}+{-# SPECIALIZE hexadecimal :: Reader Integer #-}+{-# SPECIALIZE hexadecimal :: Reader Word #-}+{-# SPECIALIZE hexadecimal :: Reader Word8 #-}+{-# SPECIALIZE hexadecimal :: Reader Word16 #-}+{-# SPECIALIZE hexadecimal :: Reader Word32 #-}+{-# SPECIALIZE hexadecimal :: Reader Word64 #-}+hex txt+    | T.null h  = Left "input does not start with a hexadecimal digit"+    | otherwise = Right (T.foldl' go 0 h, t)+  where (h,t)  = T.span isHexDigit txt+        go n d = (n * 16 + fromIntegral (hexDigitToInt d))++-- | Read an optional leading sign character (@\'-\'@ or @\'+\'@) and+-- apply it to the result of applying the given reader.+signed :: Num a => Reader a -> Reader a+{-# INLINE signed #-}+signed f = runP (signa (P f))++-- | Read a rational number.+--+-- This function accepts an optional leading sign character, followed+-- by at least one decimal digit.  The syntax similar to that accepted+-- by the 'read' function, with the exception that a trailing @\'.\'@+-- or @\'e\'@ /not/ followed by a number is not consumed.+--+-- Examples:+--+-- >rational "3"     == Right (3.0, "")+-- >rational "3.1"   == Right (3.1, "")+-- >rational "3e4"   == Right (30000.0, "")+-- >rational "3.1e4" == Right (31000.0, "")+-- >rational ".3"    == Left "input does not start with a digit"+-- >rational "e3"    == Left "input does not start with a digit"+--+-- Examples of differences from 'read':+--+-- >rational "3.foo" == Right (3.0, ".foo")+-- >rational "3e"    == Right (3.0, "e")+rational :: Fractional a => Reader a+{-# SPECIALIZE rational :: Reader Double #-}+rational = floaty $ \real frac fracDenom -> fromRational $+                     real % 1 + frac % fracDenom++-- | Read a rational number.+--+-- The syntax accepted by this function is the same as for 'rational'.+--+-- /Note/: This function is almost ten times faster than 'rational',+-- but is slightly less accurate.+--+-- The 'Double' type supports about 16 decimal places of accuracy.+-- For 94.2% of numbers, this function and 'rational' give identical+-- results, but for the remaining 5.8%, this function loses precision+-- around the 15th decimal place.  For 0.001% of numbers, this+-- function will lose precision at the 13th or 14th decimal place.+double :: Reader Double+double = floaty $ \real frac fracDenom ->+                   fromIntegral real ++                   fromIntegral frac / fromIntegral fracDenom++signa :: Num a => Parser a -> Parser a+{-# SPECIALIZE signa :: Parser Int -> Parser Int #-}+{-# SPECIALIZE signa :: Parser Int8 -> Parser Int8 #-}+{-# SPECIALIZE signa :: Parser Int16 -> Parser Int16 #-}+{-# SPECIALIZE signa :: Parser Int32 -> Parser Int32 #-}+{-# SPECIALIZE signa :: Parser Int64 -> Parser Int64 #-}+{-# SPECIALIZE signa :: Parser Integer -> Parser Integer #-}+signa p = do+  sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')+  if sign == '+' then p else negate `liftM` p++char :: (Char -> Bool) -> Parser Char+char p = P $ \t -> case T.uncons t of+                     Just (c,t') | p c -> Right (c,t')+                     _                 -> Left "character does not match"++floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Reader a+{-# INLINE floaty #-}+floaty f = runP $ do+  sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')+  real <- P decimal+  T fraction fracDigits <- perhaps (T 0 0) $ do+    _ <- char (=='.')+    digits <- P $ \t -> Right (fromIntegral . T.length $ T.takeWhile isDigit t, t)+    n <- P decimal+    return $ T n digits+  let e c = c == 'e' || c == 'E'+  power <- perhaps 0 (char e >> signa (P decimal) :: Parser Int)+  let n = if fracDigits == 0+          then if power == 0+               then fromIntegral real+               else fromIntegral real * (10 ^^ power)+          else if power == 0+               then f real fraction (10 ^ fracDigits)+               else f real fraction (10 ^ fracDigits) * (10 ^^ power)+  return $! if sign == '+'+            then n+            else -n
+ src/Data/Text/Read.hs view
@@ -0,0 +1,200 @@+{-# LANGUAGE OverloadedStrings, UnboxedTuples, CPP #-}+#if __GLASGOW_HASKELL__ >= 702+{-# LANGUAGE Trustworthy #-}+#endif++-- |+-- Module      : Data.Text.Read+-- Copyright   : (c) 2010, 2011 Bryan O'Sullivan+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Portability : GHC+--+-- Functions used frequently when reading textual data.+module Data.Text.Read+    (+      Reader+    , decimal+    , hexadecimal+    , signed+    , rational+    , double+    ) where++import Control.Monad (liftM)+import Data.Char (isDigit, isHexDigit)+import Data.Int (Int8, Int16, Int32, Int64)+import Data.Ratio ((%))+import Data.Text as T+import Data.Text.Internal.Private (span_)+import Data.Text.Internal.Read+import Data.Word (Word, Word8, Word16, Word32, Word64)++-- | Read some text.  If the read succeeds, return its value and the+-- remaining text, otherwise an error message.+type Reader a = IReader Text a+type Parser a = IParser Text a++-- | Read a decimal integer.  The input must begin with at least one+-- decimal digit, and is consumed until a non-digit or end of string+-- is reached.+--+-- This function does not handle leading sign characters.  If you need+-- to handle signed input, use @'signed' 'decimal'@.+--+-- /Note/: For fixed-width integer types, this function does not+-- attempt to detect overflow, so a sufficiently long input may give+-- incorrect results.  If you are worried about overflow, use+-- 'Integer' for your result type.+decimal :: Integral a => Reader a+{-# SPECIALIZE decimal :: Reader Int #-}+{-# SPECIALIZE decimal :: Reader Int8 #-}+{-# SPECIALIZE decimal :: Reader Int16 #-}+{-# SPECIALIZE decimal :: Reader Int32 #-}+{-# SPECIALIZE decimal :: Reader Int64 #-}+{-# SPECIALIZE decimal :: Reader Integer #-}+{-# SPECIALIZE decimal :: Reader Data.Word.Word #-}+{-# SPECIALIZE decimal :: Reader Word8 #-}+{-# SPECIALIZE decimal :: Reader Word16 #-}+{-# SPECIALIZE decimal :: Reader Word32 #-}+{-# SPECIALIZE decimal :: Reader Word64 #-}+decimal txt+    | T.null h  = Left "input does not start with a digit"+    | otherwise = Right (T.foldl' go 0 h, t)+  where (# h,t #)  = span_ isDigit txt+        go n d = (n * 10 + fromIntegral (digitToInt d))++-- | Read a hexadecimal integer, consisting of an optional leading+-- @\"0x\"@ followed by at least one hexadecimal digit. Input is+-- consumed until a non-hex-digit or end of string is reached.+-- This function is case insensitive.+--+-- This function does not handle leading sign characters.  If you need+-- to handle signed input, use @'signed' 'hexadecimal'@.+--+-- /Note/: For fixed-width integer types, this function does not+-- attempt to detect overflow, so a sufficiently long input may give+-- incorrect results.  If you are worried about overflow, use+-- 'Integer' for your result type.+hexadecimal :: Integral a => Reader a+{-# SPECIALIZE hexadecimal :: Reader Int #-}+{-# SPECIALIZE hexadecimal :: Reader Int8 #-}+{-# SPECIALIZE hexadecimal :: Reader Int16 #-}+{-# SPECIALIZE hexadecimal :: Reader Int32 #-}+{-# SPECIALIZE hexadecimal :: Reader Int64 #-}+{-# SPECIALIZE hexadecimal :: Reader Integer #-}+{-# SPECIALIZE hexadecimal :: Reader Word #-}+{-# SPECIALIZE hexadecimal :: Reader Word8 #-}+{-# SPECIALIZE hexadecimal :: Reader Word16 #-}+{-# SPECIALIZE hexadecimal :: Reader Word32 #-}+{-# SPECIALIZE hexadecimal :: Reader Word64 #-}+hexadecimal txt+    | h == "0x" || h == "0X" = hex t+    | otherwise              = hex txt+ where (h,t) = T.splitAt 2 txt++hex :: Integral a => Reader a+{-# SPECIALIZE hex :: Reader Int #-}+{-# SPECIALIZE hex :: Reader Int8 #-}+{-# SPECIALIZE hex :: Reader Int16 #-}+{-# SPECIALIZE hex :: Reader Int32 #-}+{-# SPECIALIZE hex :: Reader Int64 #-}+{-# SPECIALIZE hex :: Reader Integer #-}+{-# SPECIALIZE hex :: Reader Word #-}+{-# SPECIALIZE hex :: Reader Word8 #-}+{-# SPECIALIZE hex :: Reader Word16 #-}+{-# SPECIALIZE hex :: Reader Word32 #-}+{-# SPECIALIZE hex :: Reader Word64 #-}+hex txt+    | T.null h  = Left "input does not start with a hexadecimal digit"+    | otherwise = Right (T.foldl' go 0 h, t)+  where (# h,t #)  = span_ isHexDigit txt+        go n d = (n * 16 + fromIntegral (hexDigitToInt d))++-- | Read an optional leading sign character (@\'-\'@ or @\'+\'@) and+-- apply it to the result of applying the given reader.+signed :: Num a => Reader a -> Reader a+{-# INLINE signed #-}+signed f = runP (signa (P f))++-- | Read a rational number.+--+-- This function accepts an optional leading sign character, followed+-- by at least one decimal digit.  The syntax similar to that accepted+-- by the 'read' function, with the exception that a trailing @\'.\'@+-- or @\'e\'@ /not/ followed by a number is not consumed.+--+-- Examples (with behaviour identical to 'read'):+--+-- >rational "3"     == Right (3.0, "")+-- >rational "3.1"   == Right (3.1, "")+-- >rational "3e4"   == Right (30000.0, "")+-- >rational "3.1e4" == Right (31000.0, "")+-- >rational ".3"    == Left "input does not start with a digit"+-- >rational "e3"    == Left "input does not start with a digit"+--+-- Examples of differences from 'read':+--+-- >rational "3.foo" == Right (3.0, ".foo")+-- >rational "3e"    == Right (3.0, "e")+rational :: Fractional a => Reader a+{-# SPECIALIZE rational :: Reader Double #-}+rational = floaty $ \real frac fracDenom -> fromRational $+                     real % 1 + frac % fracDenom++-- | Read a rational number.+--+-- The syntax accepted by this function is the same as for 'rational'.+--+-- /Note/: This function is almost ten times faster than 'rational',+-- but is slightly less accurate.+--+-- The 'Double' type supports about 16 decimal places of accuracy.+-- For 94.2% of numbers, this function and 'rational' give identical+-- results, but for the remaining 5.8%, this function loses precision+-- around the 15th decimal place.  For 0.001% of numbers, this+-- function will lose precision at the 13th or 14th decimal place.+double :: Reader Double+double = floaty $ \real frac fracDenom ->+                   fromIntegral real ++                   fromIntegral frac / fromIntegral fracDenom++signa :: Num a => Parser a -> Parser a+{-# SPECIALIZE signa :: Parser Int -> Parser Int #-}+{-# SPECIALIZE signa :: Parser Int8 -> Parser Int8 #-}+{-# SPECIALIZE signa :: Parser Int16 -> Parser Int16 #-}+{-# SPECIALIZE signa :: Parser Int32 -> Parser Int32 #-}+{-# SPECIALIZE signa :: Parser Int64 -> Parser Int64 #-}+{-# SPECIALIZE signa :: Parser Integer -> Parser Integer #-}+signa p = do+  sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')+  if sign == '+' then p else negate `liftM` p++char :: (Char -> Bool) -> Parser Char+char p = P $ \t -> case T.uncons t of+                     Just (c,t') | p c -> Right (c,t')+                     _                 -> Left "character does not match"++floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Reader a+{-# INLINE floaty #-}+floaty f = runP $ do+  sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')+  real <- P decimal+  T fraction fracDigits <- perhaps (T 0 0) $ do+    _ <- char (=='.')+    digits <- P $ \t -> Right (T.length $ T.takeWhile isDigit t, t)+    n <- P decimal+    return $ T n digits+  let e c = c == 'e' || c == 'E'+  power <- perhaps 0 (char e >> signa (P decimal) :: Parser Int)+  let n = if fracDigits == 0+          then if power == 0+               then fromIntegral real+               else fromIntegral real * (10 ^^ power)+          else if power == 0+               then f real fraction (10 ^ fracDigits)+               else f real fraction (10 ^ fracDigits) * (10 ^^ power)+  return $! if sign == '+'+            then n+            else -n
+ src/Data/Text/Show.hs view
@@ -0,0 +1,90 @@+{-# LANGUAGE CPP, MagicHash #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+#if __GLASGOW_HASKELL__ >= 702+{-# LANGUAGE Trustworthy #-}+#endif++-- |+-- Module      : Data.Text.Show+-- Copyright   : (c) 2009-2015 Bryan O'Sullivan+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC++module Data.Text.Show+    (+      singleton+    , unpack+    , unpackCString#+    ) where++import Control.Monad.ST (ST)+import Data.Text.Internal (Text(..), empty_, safe)+import Data.Text.Internal.Fusion (stream, unstream)+import Data.Text.Internal.Unsafe.Char (unsafeWrite)+import GHC.Prim (Addr#)+import qualified Data.Text.Array as A+import qualified Data.Text.Internal.Fusion.Common as S++#if __GLASGOW_HASKELL__ >= 702+import qualified GHC.CString as GHC+#else+import qualified GHC.Base as GHC+#endif++instance Show Text where+    showsPrec p ps r = showsPrec p (unpack ps) r++-- | /O(n)/ Convert a 'Text' into a 'String'.  Subject to fusion.+unpack :: Text -> String+unpack = S.unstreamList . stream+{-# INLINE [1] unpack #-}++-- | /O(n)/ Convert a literal string into a 'Text'.+--+-- This is exposed solely for people writing GHC rewrite rules.+--+-- @since 1.2.1.1+unpackCString# :: Addr# -> Text+unpackCString# addr# = unstream (S.streamCString# addr#)+{-# NOINLINE unpackCString# #-}++{-# RULES "TEXT literal" [1] forall a.+    unstream (S.map safe (S.streamList (GHC.unpackCString# a)))+      = unpackCString# a #-}++{-# RULES "TEXT literal UTF8" [1] forall a.+    unstream (S.map safe (S.streamList (GHC.unpackCStringUtf8# a)))+      = unpackCString# a #-}++{-# RULES "TEXT empty literal" [1]+    unstream (S.map safe (S.streamList []))+      = empty_ #-}++{-# RULES "TEXT singleton literal" [1] forall a.+    unstream (S.map safe (S.streamList [a]))+      = singleton_ a #-}++-- | /O(1)/ Convert a character into a Text.  Subject to fusion.+-- Performs replacement on invalid scalar values.+singleton :: Char -> Text+singleton = unstream . S.singleton . safe+{-# INLINE [1] singleton #-}++{-# RULES "TEXT singleton" forall a.+    unstream (S.singleton (safe a))+      = singleton_ a #-}++-- This is intended to reduce inlining bloat.+singleton_ :: Char -> Text+singleton_ c = Text (A.run x) 0 len+  where x :: ST s (A.MArray s)+        x = do arr <- A.new len+               _ <- unsafeWrite arr 0 d+               return arr+        len | d < '\x10000' = 1+            | otherwise     = 2+        d = safe c+{-# NOINLINE singleton_ #-}
+ src/Data/Text/Unsafe.hs view
@@ -0,0 +1,124 @@+{-# LANGUAGE CPP, MagicHash, UnboxedTuples #-}+-- |+-- Module      : Data.Text.Unsafe+-- Copyright   : (c) 2009, 2010, 2011 Bryan O'Sullivan+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Portability : portable+--+-- A module containing unsafe 'Text' operations, for very very careful+-- use in heavily tested code.+module Data.Text.Unsafe+    (+      inlineInterleaveST+    , inlinePerformIO+    , unsafeDupablePerformIO+    , Iter(..)+    , iter+    , iter_+    , reverseIter+    , reverseIter_+    , unsafeHead+    , unsafeTail+    , lengthWord16+    , takeWord16+    , dropWord16+    ) where++#if defined(ASSERTS)+import Control.Exception (assert)+#endif+import Data.Text.Internal.Encoding.Utf16 (chr2)+import Data.Text.Internal (Text(..))+import Data.Text.Internal.Unsafe (inlineInterleaveST, inlinePerformIO)+import Data.Text.Internal.Unsafe.Char (unsafeChr)+import qualified Data.Text.Array as A+import GHC.IO (unsafeDupablePerformIO)++-- | /O(1)/ A variant of 'head' for non-empty 'Text'. 'unsafeHead'+-- omits the check for the empty case, so there is an obligation on+-- the programmer to provide a proof that the 'Text' is non-empty.+unsafeHead :: Text -> Char+unsafeHead (Text arr off _len)+    | m < 0xD800 || m > 0xDBFF = unsafeChr m+    | otherwise                = chr2 m n+    where m = A.unsafeIndex arr off+          n = A.unsafeIndex arr (off+1)+{-# INLINE unsafeHead #-}++-- | /O(1)/ A variant of 'tail' for non-empty 'Text'. 'unsafeTail'+-- omits the check for the empty case, so there is an obligation on+-- the programmer to provide a proof that the 'Text' is non-empty.+unsafeTail :: Text -> Text+unsafeTail t@(Text arr off len) =+#if defined(ASSERTS)+    assert (d <= len) $+#endif+    Text arr (off+d) (len-d)+  where d = iter_ t 0+{-# INLINE unsafeTail #-}++data Iter = Iter {-# UNPACK #-} !Char {-# UNPACK #-} !Int++-- | /O(1)/ Iterate (unsafely) one step forwards through a UTF-16+-- array, returning the current character and the delta to add to give+-- the next offset to iterate at.+iter :: Text -> Int -> Iter+iter (Text arr off _len) i+    | m < 0xD800 || m > 0xDBFF = Iter (unsafeChr m) 1+    | otherwise                = Iter (chr2 m n) 2+  where m = A.unsafeIndex arr j+        n = A.unsafeIndex arr k+        j = off + i+        k = j + 1+{-# INLINE iter #-}++-- | /O(1)/ Iterate one step through a UTF-16 array, returning the+-- delta to add to give the next offset to iterate at.+iter_ :: Text -> Int -> Int+iter_ (Text arr off _len) i | m < 0xD800 || m > 0xDBFF = 1+                            | otherwise                = 2+  where m = A.unsafeIndex arr (off+i)+{-# INLINE iter_ #-}++-- | /O(1)/ Iterate one step backwards through a UTF-16 array,+-- returning the current character and the delta to add (i.e. a+-- negative number) to give the next offset to iterate at.+reverseIter :: Text -> Int -> (Char,Int)+reverseIter (Text arr off _len) i+    | m < 0xDC00 || m > 0xDFFF = (unsafeChr m, -1)+    | otherwise                = (chr2 n m,    -2)+  where m = A.unsafeIndex arr j+        n = A.unsafeIndex arr k+        j = off + i+        k = j - 1+{-# INLINE reverseIter #-}++-- | /O(1)/ Iterate one step backwards through a UTF-16 array,+-- returning the delta to add (i.e. a negative number) to give the+-- next offset to iterate at.+--+-- @since 1.1.1.0+reverseIter_ :: Text -> Int -> Int+reverseIter_ (Text arr off _len) i+    | m < 0xDC00 || m > 0xDFFF = -1+    | otherwise                = -2+  where m = A.unsafeIndex arr (off+i)+{-# INLINE reverseIter_ #-}++-- | /O(1)/ Return the length of a 'Text' in units of 'Word16'.  This+-- is useful for sizing a target array appropriately before using+-- 'unsafeCopyToPtr'.+lengthWord16 :: Text -> Int+lengthWord16 (Text _arr _off len) = len+{-# INLINE lengthWord16 #-}++-- | /O(1)/ Unchecked take of 'k' 'Word16's from the front of a 'Text'.+takeWord16 :: Int -> Text -> Text+takeWord16 k (Text arr off _len) = Text arr off k+{-# INLINE takeWord16 #-}++-- | /O(1)/ Unchecked drop of 'k' 'Word16's from the front of a 'Text'.+dropWord16 :: Int -> Text -> Text+dropWord16 k (Text arr off len) = Text arr (off+k) (len-k)+{-# INLINE dropWord16 #-}
tests/Tests/Regressions.hs view
@@ -14,7 +14,9 @@ import Data.ByteString.Char8 () import qualified Data.ByteString.Lazy as LB import qualified Data.Text as T+import qualified Data.Text.Array as TA import qualified Data.Text.Encoding as TE+import qualified Data.Text.Internal as T import qualified Data.Text.IO as T import qualified Data.Text.Lazy as LT import qualified Data.Text.Lazy.Encoding as LE@@ -95,6 +97,24 @@                 (T.length $ T.filter isLetter $ T.take (-3) "Hello! How are you doing today?")                 0 +-- See GitHub issue #301+-- This tests whether the "TEXT take . drop -> unfused" rule is applied to the+-- slice function. When the slice function is fused, a new array will be+-- constructed that is shorter than the original array. Without fusion the+-- array remains unmodified.+t301 :: IO ()+t301 = do+    assertEqual "The length of the array remains the same despite slicing"+                (TA.length originalArr)+                (TA.length newArr)++    assertEqual "The new array still contains the original value"+                (T.Text newArr originalOff originalLen)+                original+  where+    original@(T.Text originalArr originalOff originalLen) = T.pack "1234567890"+    T.Text newArr _off _len = T.take 1 $ T.drop 1 original+ tests :: F.Test tests = F.testGroup "Regressions"     [ F.testCase "hGetContents_crash" hGetContents_crash@@ -105,4 +125,5 @@     , F.testCase "t197" t197     , F.testCase "t221" t221     , F.testCase "t227" t227+    , F.testCase "t301" t301     ]
tests/text-tests.cabal view
@@ -1,33 +1,96 @@-name:          text-tests-version:       0.0.0.0-synopsis:      Functional tests for the text package-description:   Functional tests for the text package-homepage:      https://github.com/bos/text-license:       BSD2-license-file:  ../LICENSE-author:        Jasper Van der Jeugt <jaspervdj@gmail.com>,-               Bryan O'Sullivan <bos@serpentine.com>,-               Tom Harper <rtomharper@googlemail.com>,-               Duncan Coutts <duncan@haskell.org>-maintainer:    Bryan O'Sullivan <bos@serpentine.com>-category:      Text-build-type:    Simple+cabal-version:  >= 1.10+name:           text-tests+version:        1.2.4.1 -cabal-version: >=1.8+homepage:       https://github.com/haskell/text+bug-reports:    https://github.com/haskell/text/issues+synopsis:       An efficient packed Unicode text type.+description:+    .+    An efficient packed, immutable Unicode text type (both strict and+    lazy), with a powerful loop fusion optimization framework.+    .+    The 'Text' type represents Unicode character strings, in a time and+    space-efficient manner. This package provides text processing+    capabilities that are optimized for performance critical use, both+    in terms of large data quantities and high speed.+    .+    The 'Text' type provides character-encoding, type-safe case+    conversion via whole-string case conversion functions (see "Data.Text").+    It also provides a range of functions for converting 'Text' values to+    and from 'ByteStrings', using several standard encodings+    (see "Data.Text.Encoding").+    .+    Efficient locale-sensitive support for text IO is also supported+    (see "Data.Text.IO").+    .+    These modules are intended to be imported qualified, to avoid name+    clashes with Prelude functions, e.g.+    .+    > import qualified Data.Text as T+    .+    == ICU Support+    .+    To use an extended and very rich family of functions for working+    with Unicode text (including normalization, regular expressions,+    non-standard encodings, text breaking, and locales), see+    the [text-icu package](https://hackage.haskell.org/package/text-icu)+    based on the well-respected and liberally+    licensed [ICU library](http://site.icu-project.org/).+    .+    == Internal Representation: UTF-16 vs. UTF-8+    .+    Currently the @text@ library uses UTF-16 as its internal representation+    which is [neither a fixed-width nor always the most dense representation](http://utf8everywhere.org/)+    for Unicode text. We're currently investigating the feasibility+    of [changing Text's internal representation to UTF-8](https://github.com/text-utf8)+    and if you need such a 'Text' type right now you might be interested in using the spin-off+    packages <https://hackage.haskell.org/package/text-utf8 text-utf8> and+    <https://hackage.haskell.org/package/text-short text-short>. -flag hpc-  description: Enable HPC to generate coverage reports-  default:     False-  manual:      True +license:        BSD2+license-file:   LICENSE+author:         Bryan O'Sullivan <bos@serpentine.com>+maintainer:     Bryan O'Sullivan <bos@serpentine.com>, Herbert Valerio Riedel <hvr@gnu.org>+copyright:      2009-2011 Bryan O'Sullivan, 2008-2009 Tom Harper+category:       Data, Text+build-type:     Simple+tested-with:    GHC==8.10.2, GHC==8.8.4, GHC==8.6.5, GHC==8.4.4,+                GHC==8.2.2, GHC==8.0.2, GHC==7.10.3, GHC==7.8.4,+                GHC==7.6.3, GHC==7.4.2, GHC==7.2.2, GHC==7.0.4+extra-source-files:+    include/*.h+ flag bytestring-builder-  description: Depend on the bytestring-builder package for backwards compatibility.+  description:+    Depend on the [bytestring-builder](https://hackage.haskell.org/package/bytestring-builder)+    package for backwards compatibility.   default: False   manual: False -executable text-tests-  main-is: Tests.hs+flag integer-simple+  description:+    Use the [simple integer library](http://hackage.haskell.org/package/integer-simple)+    instead of [integer-gmp](http://hackage.haskell.org/package/integer-gmp)+  default: False+  manual: False +test-suite tests+  type:           exitcode-stdio-1.0+  c-sources:      cbits/cbits.c+  include-dirs:   include+  hs-source-dirs: src++  ghc-options:+    -Wall -threaded -rtsopts++  cpp-options:+    -DASSERTS -DTEST_SUITE++  -- modules specific to test-suite+  hs-source-dirs: .+  main-is:        Tests.hs   other-modules:     Tests.Properties     Tests.Properties.Mul@@ -36,121 +99,103 @@     Tests.SlowFunctions     Tests.Utils -  ghc-options:-    -Wall -threaded -O0 -rtsopts--  if flag(hpc)-    ghc-options:-      -fhpc--  cpp-options:-    -DTEST_SUITE-    -DASSERTS--  build-depends:-    HUnit >= 1.2,-    QuickCheck >= 2.7,-    base == 4.*,-    deepseq,-    directory,-    quickcheck-unicode >= 1.0.1.0,-    random,-    test-framework >= 0.4,-    test-framework-hunit >= 0.2,-    test-framework-quickcheck2 >= 0.2,-    text-tests--  if flag(bytestring-builder)-    build-depends: bytestring         >= 0.9    && < 0.10.4,-                   bytestring-builder >= 0.10.4-  else-    build-depends: bytestring         >= 0.10.4--executable text-tests-stdio-  main-is:        Tests/IO.hs--  ghc-options:-    -Wall -threaded -rtsopts--  -- Optional HPC support-  if flag(hpc)-    ghc-options:-      -fhpc--  build-depends:-    text-tests,-    base >= 4 && < 5--library-  hs-source-dirs: ..-  c-sources: ../cbits/cbits.c-  include-dirs: ../include-  ghc-options: -Wall-  exposed-modules:+  -- This can be merged back to `text` package, when cabal+  -- will support per-component solving. Otherwise we have loops.+  --+  -- Same as in `library` stanza; this is needed by cabal for accurate+  -- file-monitoring as well as to avoid `-Wmissing-home-modules`+  -- warnings We can't use an inter-package library dependency because+  -- of different `ghc-options`/`cpp-options` (as a side-benefitt,+  -- this enables per-component build parallelism in `cabal+  -- new-build`!); We could, however, use cabal-version:2.2's `common`+  -- blocks at some point in the future to reduce the duplication.+  other-modules:     Data.Text     Data.Text.Array     Data.Text.Encoding     Data.Text.Encoding.Error+    Data.Text.Foreign+    Data.Text.IO+    Data.Text.Internal+    Data.Text.Internal.Builder+    Data.Text.Internal.Builder.Functions+    Data.Text.Internal.Builder.Int.Digits+    Data.Text.Internal.Builder.RealFloat.Functions+    Data.Text.Internal.ByteStringCompat     Data.Text.Internal.Encoding.Fusion     Data.Text.Internal.Encoding.Fusion.Common     Data.Text.Internal.Encoding.Utf16     Data.Text.Internal.Encoding.Utf32     Data.Text.Internal.Encoding.Utf8-    Data.Text.Foreign+    Data.Text.Internal.Functions     Data.Text.Internal.Fusion     Data.Text.Internal.Fusion.CaseMapping     Data.Text.Internal.Fusion.Common     Data.Text.Internal.Fusion.Size     Data.Text.Internal.Fusion.Types-    Data.Text.IO     Data.Text.Internal.IO-    Data.Text.Internal-    Data.Text.Lazy-    Data.Text.Lazy.Builder-    Data.Text.Internal.Builder.Functions-    Data.Text.Lazy.Builder.Int-    Data.Text.Internal.Builder.Int.Digits-    Data.Text.Internal.Builder-    Data.Text.Lazy.Builder.RealFloat-    Data.Text.Internal.Builder.RealFloat.Functions-    Data.Text.Lazy.Encoding+    Data.Text.Internal.Lazy     Data.Text.Internal.Lazy.Encoding.Fusion     Data.Text.Internal.Lazy.Fusion-    Data.Text.Lazy.IO-    Data.Text.Internal.Lazy-    Data.Text.Lazy.Read     Data.Text.Internal.Lazy.Search     Data.Text.Internal.Private-    Data.Text.Read-    Data.Text.Show     Data.Text.Internal.Read     Data.Text.Internal.Search-    Data.Text.Unsafe     Data.Text.Internal.Unsafe     Data.Text.Internal.Unsafe.Char     Data.Text.Internal.Unsafe.Shift-    Data.Text.Internal.Functions--  if flag(hpc)-    ghc-options:-      -fhpc--  cpp-options:-    -DTEST_SUITE-    -DASSERTS-    -DINTEGER_GMP+    Data.Text.Lazy+    Data.Text.Lazy.Builder+    Data.Text.Lazy.Builder.Int+    Data.Text.Lazy.Builder.RealFloat+    Data.Text.Lazy.Encoding+    Data.Text.Lazy.IO+    Data.Text.Lazy.Internal+    Data.Text.Lazy.Read+    Data.Text.Read+    Data.Text.Unsafe+    Data.Text.Show    build-depends:+    HUnit >= 1.2,+    QuickCheck >= 2.14.1 && < 2.15,     array,-    base == 4.*,+    base <5,     binary,     deepseq,+    directory,     ghc-prim,-    integer-gmp,-    template-haskell+    quickcheck-unicode >= 1.0.1.0,+    random,+    template-haskell,+    test-framework >= 0.4,+    test-framework-hunit >= 0.2,+    test-framework-quickcheck2 >= 0.2    if flag(bytestring-builder)     build-depends: bytestring         >= 0.9    && < 0.10.4,                    bytestring-builder >= 0.10.4   else     build-depends: bytestring         >= 0.10.4++  if impl(ghc >= 8.11)+    build-depends: ghc-bignum++  if impl(ghc < 8.11)+    if flag(integer-simple)+      cpp-options: -DINTEGER_SIMPLE+      build-depends: integer-simple >= 0.1 && < 0.5+    else+      cpp-options: -DINTEGER_GMP+      build-depends: integer-gmp >= 0.2++  default-language: Haskell2010+  default-extensions: NondecreasingIndentation++source-repository head+  type:     git+  location: https://github.com/haskell/text++source-repository head+  type:     mercurial+  location: https://bitbucket.org/bos/text
text.cabal view
@@ -1,6 +1,6 @@ cabal-version:  >= 1.10 name:           text-version:        1.2.4.0+version:        1.2.4.1  homepage:       https://github.com/haskell/text bug-reports:    https://github.com/haskell/text/issues@@ -56,7 +56,7 @@ copyright:      2009-2011 Bryan O'Sullivan, 2008-2009 Tom Harper category:       Data, Text build-type:     Simple-tested-with:    GHC==8.6.5, GHC==8.4.4,+tested-with:    GHC==8.10.2, GHC==8.8.4, GHC==8.6.5, GHC==8.4.4,                 GHC==8.2.2, GHC==8.0.2, GHC==7.10.3, GHC==7.8.4,                 GHC==7.6.3, GHC==7.4.2, GHC==7.2.2, GHC==7.0.4 extra-source-files:@@ -64,7 +64,7 @@     -- scripts/SpecialCasing.txt     README.markdown     benchmarks/Setup.hs-    benchmarks/cbits/*.c+    benchmarks/cbits-bench/*.c     benchmarks/haskell/*.hs     benchmarks/haskell/Benchmarks/*.hs     benchmarks/haskell/Benchmarks/Programs/*.hs@@ -106,6 +106,7 @@ library   c-sources:    cbits/cbits.c   include-dirs: include+  hs-source-dirs: src    exposed-modules:     Data.Text@@ -119,6 +120,7 @@     Data.Text.Internal.Builder.Functions     Data.Text.Internal.Builder.Int.Digits     Data.Text.Internal.Builder.RealFloat.Functions+    Data.Text.Internal.ByteStringCompat     Data.Text.Internal.Encoding.Fusion     Data.Text.Internal.Encoding.Fusion.Common     Data.Text.Internal.Encoding.Utf16@@ -157,17 +159,17 @@    build-depends:     array            >= 0.3 && < 0.6,-    base             >= 4.3 && < 5,+    base             >= 4.3 && < 4.16,     binary           >= 0.5 && < 0.9,     deepseq          >= 1.1 && < 1.5,-    ghc-prim         >= 0.2 && < 0.6,-    template-haskell >= 2.5 && < 2.16+    ghc-prim         >= 0.2 && < 0.8,+    template-haskell >= 2.5 && < 2.18    if flag(bytestring-builder)     build-depends: bytestring         >= 0.9    && < 0.10.4,                    bytestring-builder >= 0.10.4.0.2 && < 0.11   else-    build-depends: bytestring         >= 0.10.4 && < 0.11+    build-depends: bytestring         >= 0.10.4 && < 0.12    ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2   if flag(developer)@@ -175,12 +177,16 @@     ghc-options: -Werror     cpp-options: -DASSERTS -  if flag(integer-simple)-    cpp-options: -DINTEGER_SIMPLE-    build-depends: integer-simple >= 0.1 && < 0.5+  if impl(ghc >= 9.0)+    build-depends: ghc-bignum >= 1.0 && < 1.1+   else-    cpp-options: -DINTEGER_GMP-    build-depends: integer-gmp >= 0.2 && < 1.1+    if flag(integer-simple)+      cpp-options: -DINTEGER_SIMPLE+      build-depends: integer-simple >= 0.1 && < 0.5+    else+      cpp-options: -DINTEGER_GMP+      build-depends: integer-gmp >= 0.2 && < 1.1    -- compiler specification   default-language: Haskell2010@@ -211,114 +217,6 @@     other-extensions: TemplateHaskellQuotes   else     other-extensions: TemplateHaskell--test-suite tests-  type:           exitcode-stdio-1.0-  c-sources:      cbits/cbits.c-  include-dirs:   include--  ghc-options:-    -Wall -threaded -rtsopts--  cpp-options:-    -DASSERTS -DTEST_SUITE--  -- modules specific to test-suite-  hs-source-dirs: tests-  main-is:        Tests.hs-  other-modules:-    Tests.Properties-    Tests.Properties.Mul-    Tests.QuickCheckUtils-    Tests.Regressions-    Tests.SlowFunctions-    Tests.Utils--  -- Same as in `library` stanza; this is needed by cabal for accurate-  -- file-monitoring as well as to avoid `-Wmissing-home-modules`-  -- warnings We can't use an inter-package library dependency because-  -- of different `ghc-options`/`cpp-options` (as a side-benefitt,-  -- this enables per-component build parallelism in `cabal-  -- new-build`!); We could, however, use cabal-version:2.2's `common`-  -- blocks at some point in the future to reduce the duplication.-  hs-source-dirs: .-  other-modules:-    Data.Text-    Data.Text.Array-    Data.Text.Encoding-    Data.Text.Encoding.Error-    Data.Text.Foreign-    Data.Text.IO-    Data.Text.Internal-    Data.Text.Internal.Builder-    Data.Text.Internal.Builder.Functions-    Data.Text.Internal.Builder.Int.Digits-    Data.Text.Internal.Builder.RealFloat.Functions-    Data.Text.Internal.Encoding.Fusion-    Data.Text.Internal.Encoding.Fusion.Common-    Data.Text.Internal.Encoding.Utf16-    Data.Text.Internal.Encoding.Utf32-    Data.Text.Internal.Encoding.Utf8-    Data.Text.Internal.Functions-    Data.Text.Internal.Fusion-    Data.Text.Internal.Fusion.CaseMapping-    Data.Text.Internal.Fusion.Common-    Data.Text.Internal.Fusion.Size-    Data.Text.Internal.Fusion.Types-    Data.Text.Internal.IO-    Data.Text.Internal.Lazy-    Data.Text.Internal.Lazy.Encoding.Fusion-    Data.Text.Internal.Lazy.Fusion-    Data.Text.Internal.Lazy.Search-    Data.Text.Internal.Private-    Data.Text.Internal.Read-    Data.Text.Internal.Search-    Data.Text.Internal.Unsafe-    Data.Text.Internal.Unsafe.Char-    Data.Text.Internal.Unsafe.Shift-    Data.Text.Lazy-    Data.Text.Lazy.Builder-    Data.Text.Lazy.Builder.Int-    Data.Text.Lazy.Builder.RealFloat-    Data.Text.Lazy.Encoding-    Data.Text.Lazy.IO-    Data.Text.Lazy.Internal-    Data.Text.Lazy.Read-    Data.Text.Read-    Data.Text.Unsafe-    Data.Text.Show--  build-depends:-    HUnit >= 1.2,-    QuickCheck >= 2.7 && < 2.11,-    array,-    base,-    binary,-    deepseq,-    directory,-    ghc-prim,-    quickcheck-unicode >= 1.0.1.0,-    random,-    template-haskell,-    test-framework >= 0.4,-    test-framework-hunit >= 0.2,-    test-framework-quickcheck2 >= 0.2--  if flag(bytestring-builder)-    build-depends: bytestring         >= 0.9    && < 0.10.4,-                   bytestring-builder >= 0.10.4-  else-    build-depends: bytestring         >= 0.10.4--  if flag(integer-simple)-    cpp-options: -DINTEGER_SIMPLE-    build-depends: integer-simple >= 0.1 && < 0.5-  else-    cpp-options: -DINTEGER_GMP-    build-depends: integer-gmp >= 0.2--  default-language: Haskell2010-  default-extensions: NondecreasingIndentation  source-repository head   type:     git