text 0.4 → 0.5
raw patch · 28 files changed
+3902/−805 lines, 28 files
Files
- Data/Text.hs +144/−160
- Data/Text/Encoding/Fusion.hs +10/−8
- Data/Text/Fusion.hs +19/−55
- Data/Text/Fusion/CaseMapping.hs +223/−223
- Data/Text/Fusion/Common.hs +114/−126
- Data/Text/Fusion/Internal.hs +6/−6
- Data/Text/Fusion/Size.hs +129/−0
- Data/Text/Lazy.hs +192/−164
- Data/Text/Lazy/Encoding/Fusion.hs +19/−21
- Data/Text/Lazy/Fusion.hs +8/−38
- Data/Text/Lazy/Internal.hs +1/−0
- Data/Text/Lazy/Search.hs +124/−0
- Data/Text/Search.hs +85/−0
- Data/Text/UnsafeShift.hs +0/−2
- README +6/−0
- TODO +6/−0
- scripts/ApiCompare.hs +24/−0
- scripts/Arsec.hs +49/−0
- scripts/CaseFolding.hs +42/−0
- scripts/CaseFolding.txt +1196/−0
- scripts/CaseMapping.hs +32/−0
- scripts/SpecialCasing.hs +50/−0
- scripts/SpecialCasing.txt +274/−0
- tests/Makefile +69/−0
- tests/Properties.hs +888/−0
- tests/QuickCheckUtils.hs +128/−0
- tests/SlowFunctions.hs +40/−0
- text.cabal +24/−2
Data/Text.hs view
@@ -97,7 +97,6 @@ -- ** Generation and unfolding , replicate- , replicateChar , unfoldr , unfoldrN @@ -114,8 +113,9 @@ , stripStart , stripEnd , splitAt- , span+ , spanBy , break+ , breakBy , group , groupBy , inits@@ -124,9 +124,7 @@ -- ** Breaking into many substrings -- $split , split- , splitTimes- , splitTimesEnd- , splitWith+ , splitBy , chunksOf -- ** Breaking into lines and words@@ -142,10 +140,10 @@ , isInfixOf -- * Searching- , elem , filter , find- , partition+ , findBy+ , partitionBy -- , findSubstring @@ -153,9 +151,6 @@ -- $index , index , findIndex- , findIndices- , elemIndex- , elemIndices , count -- * Zipping and unzipping@@ -179,16 +174,15 @@ import Data.Monoid (Monoid(..)) import Data.Word (Word16) import Data.String (IsString(..))- import qualified Data.Text.Fusion as S import qualified Data.Text.Fusion.Common as S import Data.Text.Fusion (stream, reverseStream, unstream)- import Data.Text.Internal (Text(..), empty, text, textP) import qualified Prelude as P import Data.Text.Unsafe (iter, iter_, reverseIter, unsafeHead, unsafeTail) import Data.Text.UnsafeChar (unsafeChr) import qualified Data.Text.Encoding.Utf16 as U16+import Data.Text.Search (indices) -- $fusion --@@ -368,6 +362,12 @@ 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@@ -400,7 +400,7 @@ reverse t = S.reverse (stream t) {-# INLINE reverse #-} --- | /O(m)*O(n)/ Replace every occurrence of one substring with another.+-- | /O(m*n)/ Replace every occurrence of one substring with another. replace :: Text -- ^ Text to search for -> Text -- ^ Replacement text -> Text -- ^ Input text@@ -658,7 +658,9 @@ -- | /O(n*m)/ 'replicate' @n@ @t@ is a 'Text' consisting of the input -- @t@ repeated @n@ times. Subject to fusion. replicate :: Int -> Text -> Text-replicate n t = unstream (S.replicateI (fromIntegral n) (S.stream t))+replicate n t+ | isSingleton t = replicateChar n (unsafeHead t)+ | otherwise = unstream (S.replicateI (fromIntegral n) (S.stream t)) {-# INLINE [1] replicate #-} {-# RULES@@ -670,6 +672,7 @@ -- value of every element. Subject to fusion. replicateChar :: Int -> Char -> Text replicateChar n c = unstream (S.replicateCharI n 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@@ -838,23 +841,23 @@ where d = iter_ t i {-# INLINE splitAt #-} --- | /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@(Text arr off len) = (textP arr off k, textP arr (off+k) (len-k))+-- | /O(n)/ 'spanBy', 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.+spanBy :: (Char -> Bool) -> Text -> (Text, Text)+spanBy p t@(Text arr off len) = (textP arr off k, textP arr (off+k) (len-k)) where k = loop 0 loop !i | i >= len || not (p c) = i | otherwise = loop (i+d) where (c,d) = iter t i-{-# INLINE span #-}+{-# INLINE spanBy #-} --- | /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)/ 'breakBy' is like 'spanBy', but the prefix returned is+-- over elements that fail the predicate @p@.+breakBy :: (Char -> Bool) -> Text -> (Text, Text)+breakBy p = spanBy (not . p)+{-# INLINE breakBy #-} -- | /O(n)/ Group characters in a string according to a predicate. groupBy :: (Char -> Char -> Bool) -> Text -> [Text]@@ -898,7 +901,7 @@ -- copies to create substrings; they just construct new 'Text's that -- are slices of the original. --- | /O(m)*O(n)/ Break a 'Text' into pieces separated by the first+-- | /O(m+n)/ Break a 'Text' into pieces separated by the first -- 'Text' argument, consuming the delimiter. An empty delimiter is -- invalid, and will cause an error to be raised. --@@ -911,94 +914,39 @@ -- and -- -- > intercalate s . split s == id--- > split (singleton c) == splitWith (==c)-split :: Text -- ^ Text to split on- -> Text -- ^ Input text- -> [Text]-split pat src0- | l == 0 = emptyError "split"- | l == 1 = splitWith (== (unsafeHead pat)) src0- | otherwise = go src0+-- > split (singleton c) == splitBy (==c)+--+-- In (unlikely) bad cases, this function's time complexity degrades+-- towards /O(n*m)/.+split :: Text -> Text -> [Text]+split pat@(Text _ _ l) src@(Text arr off len)+ | l <= 0 = emptyError "split"+ | isSingleton pat = splitBy (== unsafeHead pat) src+ | otherwise = go 0 (indices pat src) where- l = length pat- go src = search 0 src- where- search !n !s- | null s = [src] -- not found- | pat `isPrefixOf` s = take n src : go (drop l s)- | otherwise = search (n+1) (unsafeTail s)+ go !s (x:xs) = textP arr (s+off) (x-s) : go (x+l) xs+ go s _ = [textP arr (s+off) (len-s)] {-# INLINE [1] split #-} {-# RULES-"TEXT split/singleton -> splitWith/==" [~1] forall c t.- split (singleton c) t = splitWith (==c) t+"TEXT split/singleton -> splitBy/==" [~1] forall c t.+ split (singleton c) t = splitBy (==c) t #-} --- | /O(m)*O(n)/ Break a 'Text' into pieces at most @k@ times,--- treating the first 'Text' argument as the delimiter to break on,--- and consuming the delimiter. The last element of the list contains--- the remaining text after the number of times to split has been--- reached. A value of zero or less for @k@ causes no splitting to--- occur. An empty delimiter is invalid, and will cause an error to be--- raised.------ Examples:------ > splitTimes 0 "//" "a//b//c" == ["a//b//c"]--- > splitTimes 2 ":" "a:b:c:d:e" == ["a","b","c:d:e"]--- > splitTimes 100 "???" "a????b" == ["a","?b"]------ and------ > intercalate s . splitTimes k s == id-splitTimes :: Int -- ^ Maximum number of times to split- -> Text -- ^ Text to split on- -> Text -- ^ Input text- -> [Text]-splitTimes k pat src0- | k <= 0 = [src0]- | l == 0 = emptyError "splitTimes"- | otherwise = go k src0- where- l = length pat- go !i src = search 0 src- where- search !n !s- | i == 0 || null s = [src] -- not found or limit reached- | pat `isPrefixOf` s = take n src : go (i-1) (drop l s)- | otherwise = search (n+1) (unsafeTail s)-{-# INLINE splitTimes #-}---- | /O(m)*O(n)/ Break a 'Text' into pieces at most @k@ times, like--- 'splitTimes', but start from the end of the input and work towards--- the start.------ Examples:------ > splitTimes 2 "::" "a::b::c::d::e" == ["a","b","c::d::e"]--- > splitTimesEnd 2 "::" "a::b::c::d::e" == ["a::b::c","d","e"]-splitTimesEnd :: Int -- ^ Maximum number of times to split- -> Text -- ^ Text to split on- -> Text -- ^ Input text- -> [Text]-splitTimesEnd k pat src =- L.reverse . L.map reverse $ splitTimes k (reverse pat) (reverse src)-{-# INLINE splitTimesEnd #-}- -- | /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. ----- > splitWith (=='a') "aabbaca" == ["","","bb","c",""]--- > splitWith (=='a') "" == [""]-splitWith :: (Char -> Bool) -> Text -> [Text]-splitWith _ t@(Text _off _arr 0) = [t]-splitWith p t = loop t+-- > splitBy (=='a') "aabbaca" == ["","","bb","c",""]+-- > splitBy (=='a') "" == [""]+splitBy :: (Char -> Bool) -> Text -> [Text]+splitBy _ t@(Text _off _arr 0) = [t]+splitBy p t = loop t where loop s | null s' = [l] | otherwise = l : loop (unsafeTail s')- where (l, s') = break p s-{-# INLINE splitWith #-}+ where (l, s') = breakBy p s+{-# INLINE splitBy #-} -- | /O(n)/ Splits a 'Text' into components of length @k@. The last -- element may be shorter than the other chunks, depending on the@@ -1018,31 +966,23 @@ -- * Searching ---------------------------------------------------------------------------------- ** Searching by equality---- | /O(n)/ 'elem' is the 'Text' membership predicate.-elem :: Char -> Text -> Bool-elem c t = S.elem c (stream t)-{-# INLINE elem #-}--------------------------------------------------------------------------------- -- ** Searching with a predicate --- | /O(n)/ The 'find' function takes a predicate and a 'Text',--- and returns the first element in matching the predicate, or 'Nothing'+-- | /O(n)/ The 'findBy' function takes a predicate and a 'Text', and+-- returns the first element in matching the predicate, or 'Nothing' -- if there is no such element.-find :: (Char -> Bool) -> Text -> Maybe Char-find p t = S.find p (stream t)-{-# INLINE find #-}+findBy :: (Char -> Bool) -> Text -> Maybe Char+findBy p t = S.findBy p (stream t)+{-# INLINE findBy #-} --- | /O(n)/ The 'partition' function takes a predicate and a 'Text',+-- | /O(n)/ The 'partitionBy' 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 #-}+-- > partitionBy p t == (filter p t, filter (not . p) t)+partitionBy :: (Char -> Bool) -> Text -> (Text, Text)+partitionBy p t = (filter p t, filter (not . p) t)+{-# INLINE partitionBy #-} -- | /O(n)/ 'filter', applied to a predicate and a 'Text', -- returns a 'Text' containing those characters that satisfy the@@ -1051,7 +991,67 @@ 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:+--+-- > break "::" "a::b::c" ==> ("a", "::b::c")+-- > break "/" "foobar" ==> ("foobar", "")+--+-- Laws:+--+-- > append prefix match == haystack+-- > where (prefix, match) = break 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 'find'+-- instead, as it has lower startup overhead.+--+-- In (unlikely) bad cases, this function's time complexity degrades+-- towards /O(n*m)/.+break :: Text -> Text -> (Text, Text)+break pat src@(Text arr off len)+ | null pat = emptyError "break"+ | otherwise = case indices pat src of+ [] -> (src, empty)+ (x:_) -> (textP arr off x, textP arr (off+x) (len-x))+{-# INLINE break #-} +-- | /O(n+m)/ Find all non-overlapping instances of @needle@ in+-- @haystack@. The first element of the returned pair is the prefix+-- of @haystack@ prior to any matches of @needle@. The second is a+-- list of pairs.+--+-- The first element of each pair in the list is a span from the+-- beginning of a match to the beginning of the next match, while the+-- second is a span from the beginning of the match to the end of the+-- input.+--+-- Examples:+--+-- > find "::" ""+-- > ==> ("", [])+-- > find "/" "a/b/c/d"+-- > ==> ("a", [("/b","/b/c/d"), ("/c","/c/d"), ("/d","/d")])+--+-- In (unlikely) bad cases, this function's time complexity degrades+-- towards /O(n*m)/.+find :: Text -> Text -> (Text, [(Text, Text)])+find pat src@(Text arr off len)+ | null pat = emptyError "find"+ | otherwise = case indices pat src of+ [] -> (src, [])+ (x:xs) -> (chunk 0 x, go x xs)+ where+ go !s (x:xs) = (chunk s (x-s), chunk s (len-s)) : go x xs+ go s _ = let c = chunk s (len-s)+ in [(c,c)]+ chunk !n !l = textP arr (n+off) l+{-# INLINE find #-}+ ------------------------------------------------------------------------------- -- ** Indexing 'Text's @@ -1069,8 +1069,7 @@ -- 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 @splitTimes 1--- "::"@.+-- before and after that index, you would instead use @find "::"@. -- | /O(n)/ 'Text' index (subscript) operator, starting from 0. index :: Text -> Int -> Char@@ -1084,42 +1083,17 @@ findIndex p t = S.findIndex p (stream t) {-# INLINE findIndex #-} --- | The 'findIndices' function extends 'findIndex', by returning the--- indices of all elements satisfying the predicate, in ascending--- order. Subject to fusion.-findIndices :: (Char -> Bool) -> Text -> [Int]-findIndices p t = S.findIndices p (stream t)-{-# INLINE findIndices #-}---- | /O(n)/ The 'elemIndex' function returns the index of the first--- element in the given 'Text' which is equal to the query element, or--- 'Nothing' if there is no such element. Subject to fusion.-elemIndex :: Char -> Text -> Maybe Int-elemIndex c t = S.elemIndex c (stream t)-{-# INLINE elemIndex #-}---- | /O(n)/ The 'elemIndices' function returns the index of every--- element in the given 'Text' which is equal to the query--- element. Subject to fusion.-elemIndices :: Char -> Text -> [Int]-elemIndices c t = S.elemIndices c (stream t)-{-# INLINE elemIndices #-}---- | /O(n*m)/ The 'count' function returns the number of times the+-- | /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 src0- | l == 0 = emptyError "count"- | l == 1 = countChar (unsafeHead pat) src0- | otherwise = go 0 src0- where- l = length pat- go !n src = search src- where- search s | null s = n- | pat `isPrefixOf` s = go (n+1) (drop l s)- | otherwise = search (unsafeTail s)+count pat src+ | null pat = emptyError "count"+ | isSingleton pat = countChar (unsafeHead pat) src+ | otherwise = L.length (indices pat src) {-# INLINE [1] count #-} {-# RULES@@ -1174,7 +1148,7 @@ | otherwise = h : if null t then [] else lines (unsafeTail t)- where (h,t) = span (/= '\n') ps+ where (h,t) = spanBy (/= '\n') ps {-# INLINE lines #-} -- | /O(n)/ Portably breaks a 'Text' up into a list of 'Text's at line@@ -1235,13 +1209,23 @@ | otherwise = Text barr (boff+d) alen {-# INLINE isSuffixOf #-} --- | /O(n)/ The 'isInfixOf' function takes two 'Text's and returns+-- | /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 = L.any (isPrefixOf needle) (tails haystack)-{-# INLINE isInfixOf #-}--- TODO: a better implementation+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)+ #-} emptyError :: String -> a emptyError fun = P.error ("Data.Text." ++ fun ++ ": empty input")
Data/Text/Encoding/Fusion.hs view
@@ -35,10 +35,11 @@ import Data.ByteString as B import Data.ByteString.Internal (ByteString(..), mallocByteString, memcpy) import Data.Text.Fusion (Step(..), Stream(..))+import Data.Text.Fusion.Size import Data.Text.Encoding.Error import Data.Text.Encoding.Fusion.Common import Data.Text.UnsafeChar (unsafeChr, unsafeChr8, unsafeChr32)-import Data.Text.UnsafeShift (shiftL)+import Data.Text.UnsafeShift (shiftL, shiftR) import Data.Word (Word8, Word16, Word32) import Foreign.ForeignPtr (withForeignPtr, ForeignPtr) import Foreign.Storable (pokeByteOff)@@ -50,7 +51,7 @@ import qualified Data.Text.Encoding.Utf32 as U32 streamASCII :: ByteString -> Stream Char-streamASCII bs = Stream next 0 l+streamASCII bs = Stream next 0 (maxSize l) where l = B.length bs {-# INLINE next #-}@@ -64,7 +65,7 @@ -- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using UTF-8 -- encoding. streamUtf8 :: OnDecodeError -> ByteString -> Stream Char-streamUtf8 onErr bs = Stream next 0 l+streamUtf8 onErr bs = Stream next 0 (maxSize l) where l = B.length bs {-# INLINE next #-}@@ -87,7 +88,7 @@ -- | /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 l+streamUtf16LE onErr bs = Stream next 0 (maxSize (l `shiftR` 1)) where l = B.length bs {-# INLINE next #-}@@ -105,7 +106,7 @@ -- | /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 l+streamUtf16BE onErr bs = Stream next 0 (maxSize (l `shiftR` 1)) where l = B.length bs {-# INLINE next #-}@@ -123,7 +124,7 @@ -- | /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 l+streamUtf32BE onErr bs = Stream next 0 (maxSize (l `shiftR` 2)) where l = B.length bs {-# INLINE next #-}@@ -143,7 +144,7 @@ -- | /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 l+streamUtf32LE onErr bs = Stream next 0 (maxSize (l `shiftR` 2)) where l = B.length bs {-# INLINE next #-}@@ -163,7 +164,8 @@ -- | /O(n)/ Convert a 'Stream' 'Word8' to a 'ByteString'. unstream :: Stream Word8 -> ByteString unstream (Stream next s0 len) = unsafePerformIO $ do- mallocByteString len >>= loop len 0 s0+ 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
Data/Text/Fusion.hs view
@@ -40,24 +40,21 @@ -- * Indexing , index , findIndex- , findIndices- , findIndexOrEnd- , elemIndex- , elemIndices , countChar ) where -import Prelude (Bool(..), Char, Eq(..), Maybe(..), Monad(..), Int,+import Prelude (Bool(..), Char, Maybe(..), Monad(..), Int, Num(..), Ord(..), ($), (&&), fromIntegral, otherwise) import Data.Bits ((.&.)) import Data.Char (ord) import Data.Text.Internal (Text(..)) import Data.Text.UnsafeChar (unsafeChr, unsafeWrite)-import Data.Text.UnsafeShift (shiftR)+import Data.Text.UnsafeShift (shiftL, shiftR) import qualified Data.Text.Array as A import qualified Data.Text.Fusion.Common as S import Data.Text.Fusion.Internal+import Data.Text.Fusion.Size import qualified Data.Text.Internal as I import qualified Data.Text.Encoding.Utf16 as U16 import qualified Prelude as P@@ -66,7 +63,7 @@ -- | /O(n)/ Convert a 'Text' into a 'Stream Char'. stream :: Text -> Stream Char-stream (Text arr off len) = Stream next off len+stream (Text arr off len) = Stream next off (maxSize len) where end = off+len {-# INLINE next #-}@@ -82,7 +79,7 @@ -- | /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) len+reverseStream (Text arr off len) = Stream next (off+len-1) (maxSize len) where {-# INLINE next #-} next !i@@ -96,17 +93,17 @@ -- | /O(n)/ Convert a 'Stream Char' into a 'Text'. unstream :: Stream Char -> Text-unstream (Stream next0 s0 len)- | len == 0 = I.empty- | otherwise = I.textP (P.fst a) 0 (P.snd a)+unstream (Stream next0 s0 len) = I.textP (P.fst a) 0 (P.snd a) where- a = A.run2 (A.unsafeNew len >>= (\arr -> loop arr len s0 0))+ mlen = upperBound 4 len+ a = A.run2 (A.unsafeNew mlen >>= (\arr -> loop arr mlen s0 0)) loop arr !top !s !i | i + 1 >= top = case next0 s of Done -> return (arr, i) _ -> do- arr' <- A.unsafeNew (top*2)- A.copy arr arr' >> loop arr' (top*2) s i+ let top' = (top `shiftL` 1) + 1+ arr' <- A.unsafeNew top'+ A.copy arr arr' >> loop arr' top' s i | otherwise = case next0 s of Done -> return (arr, i) Skip s' -> loop arr top s' i@@ -125,10 +122,10 @@ -- | /O(n)/ Reverse the characters of a string. reverse :: Stream Char -> Text reverse (Stream next s len0)- | len0 == 0 = I.empty- | otherwise = I.textP arr off' len'+ | isEmpty len0 = I.empty+ | otherwise = I.textP arr off' len' where- len0' = max len0 4+ len0' = upperBound 4 (larger len0 4) (arr, (off', len')) = A.run2 (A.unsafeNew len0' >>= loop s (len0'-1) len0') loop !s0 !i !len marr = case next s0 of@@ -160,14 +157,14 @@ -- | /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 (S1 :!: z0 :!: s0) (len+1) -- HINT maybe too low+reverseScanr f z0 (Stream next0 s0 len) = Stream next (S1 :*: z0 :*: s0) (len+1) -- HINT maybe too low where {-# INLINE next #-}- next (S1 :!: z :!: s) = Yield z (S2 :!: z :!: s)- next (S2 :!: z :!: s) = case next0 s of+ next (S1 :*: z :*: s) = Yield z (S2 :*: z :*: s)+ next (S2 :*: z :*: s) = case next0 s of Yield x s' -> let !x' = f x z- in Yield x' (S2 :!: x' :!: s')- Skip s' -> Skip (S2 :!: z :!: s')+ in Yield x' (S2 :*: x' :*: s')+ Skip s' -> Skip (S2 :*: z :*: s') Done -> Done {-# INLINE reverseScanr #-} @@ -193,39 +190,6 @@ findIndex :: (Char -> Bool) -> Stream Char -> Maybe Int findIndex = S.findIndexI {-# INLINE [0] findIndex #-}---- | The 'findIndices' function takes a predicate and a stream and--- returns all indices of the elements in the stream--- satisfying the predicate.-findIndices :: (Char -> Bool) -> Stream Char -> [Int]-findIndices = S.findIndicesI-{-# INLINE [0] findIndices #-}---- | The 'findIndexOrEnd' function takes a predicate and a stream and--- returns the index of the first element in the stream--- satisfying the predicate.-findIndexOrEnd :: (Char -> Bool) -> Stream Char -> Int-findIndexOrEnd p (Stream next s0 _len) = loop_findIndex 0 s0- where- loop_findIndex !i !s = case next s of- Done -> i- Skip s' -> loop_findIndex i s' -- hmm. not caught by QC- Yield x s' | p x -> i- | otherwise -> loop_findIndex (i+1) s'-{-# INLINE [0] findIndexOrEnd #-}---- | /O(n)/ The 'elemIndex' function returns the index of the first--- element in the given stream which is equal to the query--- element, or 'Nothing' if there is no such element.-elemIndex :: Char -> Stream Char -> Maybe Int-elemIndex = S.elemIndexI-{-# INLINE [0] elemIndex #-}---- | /O(n)/ The 'elemIndices' function returns the index of every--- element in the given stream which is equal to the query element.-elemIndices :: Char -> Stream Char -> [Int]-elemIndices = S.elemIndicesI-{-# INLINE [0] elemIndices #-} -- | /O(n)/ The 'count' function returns the number of times the query -- element appears in the given stream.
Data/Text/Fusion/CaseMapping.hs view
@@ -8,449 +8,449 @@ upperMapping :: forall s. Char -> s -> Step (PairS (PairS s Char) Char) Char {-# INLINE upperMapping #-} -- LATIN SMALL LETTER SHARP S-upperMapping '\x00df' s = Yield '\x0053' (s :!: '\x0053' :!: '\x0000')+upperMapping '\x00df' s = Yield '\x0053' (s :*: '\x0053' :*: '\x0000') -- LATIN SMALL LIGATURE FF-upperMapping '\xfb00' s = Yield '\x0046' (s :!: '\x0046' :!: '\x0000')+upperMapping '\xfb00' s = Yield '\x0046' (s :*: '\x0046' :*: '\x0000') -- LATIN SMALL LIGATURE FI-upperMapping '\xfb01' s = Yield '\x0046' (s :!: '\x0049' :!: '\x0000')+upperMapping '\xfb01' s = Yield '\x0046' (s :*: '\x0049' :*: '\x0000') -- LATIN SMALL LIGATURE FL-upperMapping '\xfb02' s = Yield '\x0046' (s :!: '\x004c' :!: '\x0000')+upperMapping '\xfb02' s = Yield '\x0046' (s :*: '\x004c' :*: '\x0000') -- LATIN SMALL LIGATURE FFI-upperMapping '\xfb03' s = Yield '\x0046' (s :!: '\x0046' :!: '\x0049')+upperMapping '\xfb03' s = Yield '\x0046' (s :*: '\x0046' :*: '\x0049') -- LATIN SMALL LIGATURE FFL-upperMapping '\xfb04' s = Yield '\x0046' (s :!: '\x0046' :!: '\x004c')+upperMapping '\xfb04' s = Yield '\x0046' (s :*: '\x0046' :*: '\x004c') -- LATIN SMALL LIGATURE LONG S T-upperMapping '\xfb05' s = Yield '\x0053' (s :!: '\x0054' :!: '\x0000')+upperMapping '\xfb05' s = Yield '\x0053' (s :*: '\x0054' :*: '\x0000') -- LATIN SMALL LIGATURE ST-upperMapping '\xfb06' s = Yield '\x0053' (s :!: '\x0054' :!: '\x0000')+upperMapping '\xfb06' s = Yield '\x0053' (s :*: '\x0054' :*: '\x0000') -- ARMENIAN SMALL LIGATURE ECH YIWN-upperMapping '\x0587' s = Yield '\x0535' (s :!: '\x0552' :!: '\x0000')+upperMapping '\x0587' s = Yield '\x0535' (s :*: '\x0552' :*: '\x0000') -- ARMENIAN SMALL LIGATURE MEN NOW-upperMapping '\xfb13' s = Yield '\x0544' (s :!: '\x0546' :!: '\x0000')+upperMapping '\xfb13' s = Yield '\x0544' (s :*: '\x0546' :*: '\x0000') -- ARMENIAN SMALL LIGATURE MEN ECH-upperMapping '\xfb14' s = Yield '\x0544' (s :!: '\x0535' :!: '\x0000')+upperMapping '\xfb14' s = Yield '\x0544' (s :*: '\x0535' :*: '\x0000') -- ARMENIAN SMALL LIGATURE MEN INI-upperMapping '\xfb15' s = Yield '\x0544' (s :!: '\x053b' :!: '\x0000')+upperMapping '\xfb15' s = Yield '\x0544' (s :*: '\x053b' :*: '\x0000') -- ARMENIAN SMALL LIGATURE VEW NOW-upperMapping '\xfb16' s = Yield '\x054e' (s :!: '\x0546' :!: '\x0000')+upperMapping '\xfb16' s = Yield '\x054e' (s :*: '\x0546' :*: '\x0000') -- ARMENIAN SMALL LIGATURE MEN XEH-upperMapping '\xfb17' s = Yield '\x0544' (s :!: '\x053d' :!: '\x0000')+upperMapping '\xfb17' s = Yield '\x0544' (s :*: '\x053d' :*: '\x0000') -- LATIN SMALL LETTER N PRECEDED BY APOSTROPHE-upperMapping '\x0149' s = Yield '\x02bc' (s :!: '\x004e' :!: '\x0000')+upperMapping '\x0149' s = Yield '\x02bc' (s :*: '\x004e' :*: '\x0000') -- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS-upperMapping '\x0390' s = Yield '\x0399' (s :!: '\x0308' :!: '\x0301')+upperMapping '\x0390' s = Yield '\x0399' (s :*: '\x0308' :*: '\x0301') -- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS-upperMapping '\x03b0' s = Yield '\x03a5' (s :!: '\x0308' :!: '\x0301')+upperMapping '\x03b0' s = Yield '\x03a5' (s :*: '\x0308' :*: '\x0301') -- LATIN SMALL LETTER J WITH CARON-upperMapping '\x01f0' s = Yield '\x004a' (s :!: '\x030c' :!: '\x0000')+upperMapping '\x01f0' s = Yield '\x004a' (s :*: '\x030c' :*: '\x0000') -- LATIN SMALL LETTER H WITH LINE BELOW-upperMapping '\x1e96' s = Yield '\x0048' (s :!: '\x0331' :!: '\x0000')+upperMapping '\x1e96' s = Yield '\x0048' (s :*: '\x0331' :*: '\x0000') -- LATIN SMALL LETTER T WITH DIAERESIS-upperMapping '\x1e97' s = Yield '\x0054' (s :!: '\x0308' :!: '\x0000')+upperMapping '\x1e97' s = Yield '\x0054' (s :*: '\x0308' :*: '\x0000') -- LATIN SMALL LETTER W WITH RING ABOVE-upperMapping '\x1e98' s = Yield '\x0057' (s :!: '\x030a' :!: '\x0000')+upperMapping '\x1e98' s = Yield '\x0057' (s :*: '\x030a' :*: '\x0000') -- LATIN SMALL LETTER Y WITH RING ABOVE-upperMapping '\x1e99' s = Yield '\x0059' (s :!: '\x030a' :!: '\x0000')+upperMapping '\x1e99' s = Yield '\x0059' (s :*: '\x030a' :*: '\x0000') -- LATIN SMALL LETTER A WITH RIGHT HALF RING-upperMapping '\x1e9a' s = Yield '\x0041' (s :!: '\x02be' :!: '\x0000')+upperMapping '\x1e9a' s = Yield '\x0041' (s :*: '\x02be' :*: '\x0000') -- GREEK SMALL LETTER UPSILON WITH PSILI-upperMapping '\x1f50' s = Yield '\x03a5' (s :!: '\x0313' :!: '\x0000')+upperMapping '\x1f50' s = Yield '\x03a5' (s :*: '\x0313' :*: '\x0000') -- GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA-upperMapping '\x1f52' s = Yield '\x03a5' (s :!: '\x0313' :!: '\x0300')+upperMapping '\x1f52' s = Yield '\x03a5' (s :*: '\x0313' :*: '\x0300') -- GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA-upperMapping '\x1f54' s = Yield '\x03a5' (s :!: '\x0313' :!: '\x0301')+upperMapping '\x1f54' s = Yield '\x03a5' (s :*: '\x0313' :*: '\x0301') -- GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI-upperMapping '\x1f56' s = Yield '\x03a5' (s :!: '\x0313' :!: '\x0342')+upperMapping '\x1f56' s = Yield '\x03a5' (s :*: '\x0313' :*: '\x0342') -- GREEK SMALL LETTER ALPHA WITH PERISPOMENI-upperMapping '\x1fb6' s = Yield '\x0391' (s :!: '\x0342' :!: '\x0000')+upperMapping '\x1fb6' s = Yield '\x0391' (s :*: '\x0342' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH PERISPOMENI-upperMapping '\x1fc6' s = Yield '\x0397' (s :!: '\x0342' :!: '\x0000')+upperMapping '\x1fc6' s = Yield '\x0397' (s :*: '\x0342' :*: '\x0000') -- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA-upperMapping '\x1fd2' s = Yield '\x0399' (s :!: '\x0308' :!: '\x0300')+upperMapping '\x1fd2' s = Yield '\x0399' (s :*: '\x0308' :*: '\x0300') -- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA-upperMapping '\x1fd3' s = Yield '\x0399' (s :!: '\x0308' :!: '\x0301')+upperMapping '\x1fd3' s = Yield '\x0399' (s :*: '\x0308' :*: '\x0301') -- GREEK SMALL LETTER IOTA WITH PERISPOMENI-upperMapping '\x1fd6' s = Yield '\x0399' (s :!: '\x0342' :!: '\x0000')+upperMapping '\x1fd6' s = Yield '\x0399' (s :*: '\x0342' :*: '\x0000') -- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI-upperMapping '\x1fd7' s = Yield '\x0399' (s :!: '\x0308' :!: '\x0342')+upperMapping '\x1fd7' s = Yield '\x0399' (s :*: '\x0308' :*: '\x0342') -- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA-upperMapping '\x1fe2' s = Yield '\x03a5' (s :!: '\x0308' :!: '\x0300')+upperMapping '\x1fe2' s = Yield '\x03a5' (s :*: '\x0308' :*: '\x0300') -- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA-upperMapping '\x1fe3' s = Yield '\x03a5' (s :!: '\x0308' :!: '\x0301')+upperMapping '\x1fe3' s = Yield '\x03a5' (s :*: '\x0308' :*: '\x0301') -- GREEK SMALL LETTER RHO WITH PSILI-upperMapping '\x1fe4' s = Yield '\x03a1' (s :!: '\x0313' :!: '\x0000')+upperMapping '\x1fe4' s = Yield '\x03a1' (s :*: '\x0313' :*: '\x0000') -- GREEK SMALL LETTER UPSILON WITH PERISPOMENI-upperMapping '\x1fe6' s = Yield '\x03a5' (s :!: '\x0342' :!: '\x0000')+upperMapping '\x1fe6' s = Yield '\x03a5' (s :*: '\x0342' :*: '\x0000') -- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI-upperMapping '\x1fe7' s = Yield '\x03a5' (s :!: '\x0308' :!: '\x0342')+upperMapping '\x1fe7' s = Yield '\x03a5' (s :*: '\x0308' :*: '\x0342') -- GREEK SMALL LETTER OMEGA WITH PERISPOMENI-upperMapping '\x1ff6' s = Yield '\x03a9' (s :!: '\x0342' :!: '\x0000')+upperMapping '\x1ff6' s = Yield '\x03a9' (s :*: '\x0342' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI-upperMapping '\x1f80' s = Yield '\x1f08' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f80' s = Yield '\x1f08' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI-upperMapping '\x1f81' s = Yield '\x1f09' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f81' s = Yield '\x1f09' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI-upperMapping '\x1f82' s = Yield '\x1f0a' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f82' s = Yield '\x1f0a' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI-upperMapping '\x1f83' s = Yield '\x1f0b' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f83' s = Yield '\x1f0b' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI-upperMapping '\x1f84' s = Yield '\x1f0c' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f84' s = Yield '\x1f0c' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI-upperMapping '\x1f85' s = Yield '\x1f0d' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f85' s = Yield '\x1f0d' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI-upperMapping '\x1f86' s = Yield '\x1f0e' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f86' s = Yield '\x1f0e' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI-upperMapping '\x1f87' s = Yield '\x1f0f' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f87' s = Yield '\x1f0f' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI-upperMapping '\x1f88' s = Yield '\x1f08' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f88' s = Yield '\x1f08' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI-upperMapping '\x1f89' s = Yield '\x1f09' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f89' s = Yield '\x1f09' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI-upperMapping '\x1f8a' s = Yield '\x1f0a' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f8a' s = Yield '\x1f0a' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI-upperMapping '\x1f8b' s = Yield '\x1f0b' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f8b' s = Yield '\x1f0b' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI-upperMapping '\x1f8c' s = Yield '\x1f0c' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f8c' s = Yield '\x1f0c' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI-upperMapping '\x1f8d' s = Yield '\x1f0d' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f8d' s = Yield '\x1f0d' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI-upperMapping '\x1f8e' s = Yield '\x1f0e' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f8e' s = Yield '\x1f0e' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI-upperMapping '\x1f8f' s = Yield '\x1f0f' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f8f' s = Yield '\x1f0f' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI-upperMapping '\x1f90' s = Yield '\x1f28' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f90' s = Yield '\x1f28' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI-upperMapping '\x1f91' s = Yield '\x1f29' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f91' s = Yield '\x1f29' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI-upperMapping '\x1f92' s = Yield '\x1f2a' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f92' s = Yield '\x1f2a' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI-upperMapping '\x1f93' s = Yield '\x1f2b' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f93' s = Yield '\x1f2b' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI-upperMapping '\x1f94' s = Yield '\x1f2c' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f94' s = Yield '\x1f2c' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI-upperMapping '\x1f95' s = Yield '\x1f2d' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f95' s = Yield '\x1f2d' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI-upperMapping '\x1f96' s = Yield '\x1f2e' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f96' s = Yield '\x1f2e' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI-upperMapping '\x1f97' s = Yield '\x1f2f' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f97' s = Yield '\x1f2f' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI-upperMapping '\x1f98' s = Yield '\x1f28' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f98' s = Yield '\x1f28' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI-upperMapping '\x1f99' s = Yield '\x1f29' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f99' s = Yield '\x1f29' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI-upperMapping '\x1f9a' s = Yield '\x1f2a' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f9a' s = Yield '\x1f2a' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI-upperMapping '\x1f9b' s = Yield '\x1f2b' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f9b' s = Yield '\x1f2b' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI-upperMapping '\x1f9c' s = Yield '\x1f2c' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f9c' s = Yield '\x1f2c' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI-upperMapping '\x1f9d' s = Yield '\x1f2d' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f9d' s = Yield '\x1f2d' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI-upperMapping '\x1f9e' s = Yield '\x1f2e' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f9e' s = Yield '\x1f2e' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI-upperMapping '\x1f9f' s = Yield '\x1f2f' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1f9f' s = Yield '\x1f2f' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI-upperMapping '\x1fa0' s = Yield '\x1f68' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fa0' s = Yield '\x1f68' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI-upperMapping '\x1fa1' s = Yield '\x1f69' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fa1' s = Yield '\x1f69' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI-upperMapping '\x1fa2' s = Yield '\x1f6a' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fa2' s = Yield '\x1f6a' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI-upperMapping '\x1fa3' s = Yield '\x1f6b' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fa3' s = Yield '\x1f6b' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI-upperMapping '\x1fa4' s = Yield '\x1f6c' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fa4' s = Yield '\x1f6c' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI-upperMapping '\x1fa5' s = Yield '\x1f6d' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fa5' s = Yield '\x1f6d' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI-upperMapping '\x1fa6' s = Yield '\x1f6e' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fa6' s = Yield '\x1f6e' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI-upperMapping '\x1fa7' s = Yield '\x1f6f' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fa7' s = Yield '\x1f6f' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI-upperMapping '\x1fa8' s = Yield '\x1f68' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fa8' s = Yield '\x1f68' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI-upperMapping '\x1fa9' s = Yield '\x1f69' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fa9' s = Yield '\x1f69' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI-upperMapping '\x1faa' s = Yield '\x1f6a' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1faa' s = Yield '\x1f6a' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI-upperMapping '\x1fab' s = Yield '\x1f6b' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fab' s = Yield '\x1f6b' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI-upperMapping '\x1fac' s = Yield '\x1f6c' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fac' s = Yield '\x1f6c' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI-upperMapping '\x1fad' s = Yield '\x1f6d' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fad' s = Yield '\x1f6d' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI-upperMapping '\x1fae' s = Yield '\x1f6e' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fae' s = Yield '\x1f6e' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI-upperMapping '\x1faf' s = Yield '\x1f6f' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1faf' s = Yield '\x1f6f' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI-upperMapping '\x1fb3' s = Yield '\x0391' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fb3' s = Yield '\x0391' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI-upperMapping '\x1fbc' s = Yield '\x0391' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fbc' s = Yield '\x0391' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI-upperMapping '\x1fc3' s = Yield '\x0397' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fc3' s = Yield '\x0397' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI-upperMapping '\x1fcc' s = Yield '\x0397' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fcc' s = Yield '\x0397' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI-upperMapping '\x1ff3' s = Yield '\x03a9' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1ff3' s = Yield '\x03a9' (s :*: '\x0399' :*: '\x0000') -- GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI-upperMapping '\x1ffc' s = Yield '\x03a9' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1ffc' s = Yield '\x03a9' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI-upperMapping '\x1fb2' s = Yield '\x1fba' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fb2' s = Yield '\x1fba' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI-upperMapping '\x1fb4' s = Yield '\x0386' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fb4' s = Yield '\x0386' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI-upperMapping '\x1fc2' s = Yield '\x1fca' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fc2' s = Yield '\x1fca' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI-upperMapping '\x1fc4' s = Yield '\x0389' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1fc4' s = Yield '\x0389' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI-upperMapping '\x1ff2' s = Yield '\x1ffa' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1ff2' s = Yield '\x1ffa' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI-upperMapping '\x1ff4' s = Yield '\x038f' (s :!: '\x0399' :!: '\x0000')+upperMapping '\x1ff4' s = Yield '\x038f' (s :*: '\x0399' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI-upperMapping '\x1fb7' s = Yield '\x0391' (s :!: '\x0342' :!: '\x0399')+upperMapping '\x1fb7' s = Yield '\x0391' (s :*: '\x0342' :*: '\x0399') -- GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI-upperMapping '\x1fc7' s = Yield '\x0397' (s :!: '\x0342' :!: '\x0399')+upperMapping '\x1fc7' s = Yield '\x0397' (s :*: '\x0342' :*: '\x0399') -- GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI-upperMapping '\x1ff7' s = Yield '\x03a9' (s :!: '\x0342' :!: '\x0399')-upperMapping c s = Yield (toUpper c) (s :!: '\0' :!: '\0')+upperMapping '\x1ff7' s = Yield '\x03a9' (s :*: '\x0342' :*: '\x0399')+upperMapping c s = Yield (toUpper c) (s :*: '\0' :*: '\0') lowerMapping :: forall s. Char -> s -> Step (PairS (PairS s Char) Char) Char {-# INLINE lowerMapping #-} -- LATIN CAPITAL LETTER I WITH DOT ABOVE-lowerMapping '\x0130' s = Yield '\x0069' (s :!: '\x0307' :!: '\x0000')-lowerMapping c s = Yield (toLower c) (s :!: '\0' :!: '\0')+lowerMapping '\x0130' s = Yield '\x0069' (s :*: '\x0307' :*: '\x0000')+lowerMapping c s = Yield (toLower c) (s :*: '\0' :*: '\0') foldMapping :: forall s. Char -> s -> Step (PairS (PairS s Char) Char) Char {-# INLINE foldMapping #-} -- MICRO SIGN-foldMapping '\x00b5' s = Yield '\x03bc' (s :!: '\x0000' :!: '\x0000')+foldMapping '\x00b5' s = Yield '\x03bc' (s :*: '\x0000' :*: '\x0000') -- LATIN SMALL LETTER SHARP S-foldMapping '\x00df' s = Yield '\x0073' (s :!: '\x0073' :!: '\x0000')+foldMapping '\x00df' s = Yield '\x0073' (s :*: '\x0073' :*: '\x0000') -- LATIN CAPITAL LETTER I WITH DOT ABOVE-foldMapping '\x0130' s = Yield '\x0069' (s :!: '\x0307' :!: '\x0000')+foldMapping '\x0130' s = Yield '\x0069' (s :*: '\x0307' :*: '\x0000') -- LATIN SMALL LETTER N PRECEDED BY APOSTROPHE-foldMapping '\x0149' s = Yield '\x02bc' (s :!: '\x006e' :!: '\x0000')+foldMapping '\x0149' s = Yield '\x02bc' (s :*: '\x006e' :*: '\x0000') -- LATIN SMALL LETTER LONG S-foldMapping '\x017f' s = Yield '\x0073' (s :!: '\x0000' :!: '\x0000')+foldMapping '\x017f' s = Yield '\x0073' (s :*: '\x0000' :*: '\x0000') -- LATIN SMALL LETTER J WITH CARON-foldMapping '\x01f0' s = Yield '\x006a' (s :!: '\x030c' :!: '\x0000')+foldMapping '\x01f0' s = Yield '\x006a' (s :*: '\x030c' :*: '\x0000') -- COMBINING GREEK YPOGEGRAMMENI-foldMapping '\x0345' s = Yield '\x03b9' (s :!: '\x0000' :!: '\x0000')+foldMapping '\x0345' s = Yield '\x03b9' (s :*: '\x0000' :*: '\x0000') -- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS-foldMapping '\x0390' s = Yield '\x03b9' (s :!: '\x0308' :!: '\x0301')+foldMapping '\x0390' s = Yield '\x03b9' (s :*: '\x0308' :*: '\x0301') -- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS-foldMapping '\x03b0' s = Yield '\x03c5' (s :!: '\x0308' :!: '\x0301')+foldMapping '\x03b0' s = Yield '\x03c5' (s :*: '\x0308' :*: '\x0301') -- GREEK SMALL LETTER FINAL SIGMA-foldMapping '\x03c2' s = Yield '\x03c3' (s :!: '\x0000' :!: '\x0000')+foldMapping '\x03c2' s = Yield '\x03c3' (s :*: '\x0000' :*: '\x0000') -- GREEK BETA SYMBOL-foldMapping '\x03d0' s = Yield '\x03b2' (s :!: '\x0000' :!: '\x0000')+foldMapping '\x03d0' s = Yield '\x03b2' (s :*: '\x0000' :*: '\x0000') -- GREEK THETA SYMBOL-foldMapping '\x03d1' s = Yield '\x03b8' (s :!: '\x0000' :!: '\x0000')+foldMapping '\x03d1' s = Yield '\x03b8' (s :*: '\x0000' :*: '\x0000') -- GREEK PHI SYMBOL-foldMapping '\x03d5' s = Yield '\x03c6' (s :!: '\x0000' :!: '\x0000')+foldMapping '\x03d5' s = Yield '\x03c6' (s :*: '\x0000' :*: '\x0000') -- GREEK PI SYMBOL-foldMapping '\x03d6' s = Yield '\x03c0' (s :!: '\x0000' :!: '\x0000')+foldMapping '\x03d6' s = Yield '\x03c0' (s :*: '\x0000' :*: '\x0000') -- GREEK KAPPA SYMBOL-foldMapping '\x03f0' s = Yield '\x03ba' (s :!: '\x0000' :!: '\x0000')+foldMapping '\x03f0' s = Yield '\x03ba' (s :*: '\x0000' :*: '\x0000') -- GREEK RHO SYMBOL-foldMapping '\x03f1' s = Yield '\x03c1' (s :!: '\x0000' :!: '\x0000')+foldMapping '\x03f1' s = Yield '\x03c1' (s :*: '\x0000' :*: '\x0000') -- GREEK LUNATE EPSILON SYMBOL-foldMapping '\x03f5' s = Yield '\x03b5' (s :!: '\x0000' :!: '\x0000')+foldMapping '\x03f5' s = Yield '\x03b5' (s :*: '\x0000' :*: '\x0000') -- ARMENIAN SMALL LIGATURE ECH YIWN-foldMapping '\x0587' s = Yield '\x0565' (s :!: '\x0582' :!: '\x0000')+foldMapping '\x0587' s = Yield '\x0565' (s :*: '\x0582' :*: '\x0000') -- LATIN SMALL LETTER H WITH LINE BELOW-foldMapping '\x1e96' s = Yield '\x0068' (s :!: '\x0331' :!: '\x0000')+foldMapping '\x1e96' s = Yield '\x0068' (s :*: '\x0331' :*: '\x0000') -- LATIN SMALL LETTER T WITH DIAERESIS-foldMapping '\x1e97' s = Yield '\x0074' (s :!: '\x0308' :!: '\x0000')+foldMapping '\x1e97' s = Yield '\x0074' (s :*: '\x0308' :*: '\x0000') -- LATIN SMALL LETTER W WITH RING ABOVE-foldMapping '\x1e98' s = Yield '\x0077' (s :!: '\x030a' :!: '\x0000')+foldMapping '\x1e98' s = Yield '\x0077' (s :*: '\x030a' :*: '\x0000') -- LATIN SMALL LETTER Y WITH RING ABOVE-foldMapping '\x1e99' s = Yield '\x0079' (s :!: '\x030a' :!: '\x0000')+foldMapping '\x1e99' s = Yield '\x0079' (s :*: '\x030a' :*: '\x0000') -- LATIN SMALL LETTER A WITH RIGHT HALF RING-foldMapping '\x1e9a' s = Yield '\x0061' (s :!: '\x02be' :!: '\x0000')+foldMapping '\x1e9a' s = Yield '\x0061' (s :*: '\x02be' :*: '\x0000') -- LATIN SMALL LETTER LONG S WITH DOT ABOVE-foldMapping '\x1e9b' s = Yield '\x1e61' (s :!: '\x0000' :!: '\x0000')+foldMapping '\x1e9b' s = Yield '\x1e61' (s :*: '\x0000' :*: '\x0000') -- LATIN CAPITAL LETTER SHARP S-foldMapping '\x1e9e' s = Yield '\x0073' (s :!: '\x0073' :!: '\x0000')+foldMapping '\x1e9e' s = Yield '\x0073' (s :*: '\x0073' :*: '\x0000') -- GREEK SMALL LETTER UPSILON WITH PSILI-foldMapping '\x1f50' s = Yield '\x03c5' (s :!: '\x0313' :!: '\x0000')+foldMapping '\x1f50' s = Yield '\x03c5' (s :*: '\x0313' :*: '\x0000') -- GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA-foldMapping '\x1f52' s = Yield '\x03c5' (s :!: '\x0313' :!: '\x0300')+foldMapping '\x1f52' s = Yield '\x03c5' (s :*: '\x0313' :*: '\x0300') -- GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA-foldMapping '\x1f54' s = Yield '\x03c5' (s :!: '\x0313' :!: '\x0301')+foldMapping '\x1f54' s = Yield '\x03c5' (s :*: '\x0313' :*: '\x0301') -- GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI-foldMapping '\x1f56' s = Yield '\x03c5' (s :!: '\x0313' :!: '\x0342')+foldMapping '\x1f56' s = Yield '\x03c5' (s :*: '\x0313' :*: '\x0342') -- GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI-foldMapping '\x1f80' s = Yield '\x1f00' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f80' s = Yield '\x1f00' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI-foldMapping '\x1f81' s = Yield '\x1f01' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f81' s = Yield '\x1f01' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI-foldMapping '\x1f82' s = Yield '\x1f02' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f82' s = Yield '\x1f02' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI-foldMapping '\x1f83' s = Yield '\x1f03' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f83' s = Yield '\x1f03' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI-foldMapping '\x1f84' s = Yield '\x1f04' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f84' s = Yield '\x1f04' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI-foldMapping '\x1f85' s = Yield '\x1f05' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f85' s = Yield '\x1f05' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI-foldMapping '\x1f86' s = Yield '\x1f06' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f86' s = Yield '\x1f06' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI-foldMapping '\x1f87' s = Yield '\x1f07' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f87' s = Yield '\x1f07' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI-foldMapping '\x1f88' s = Yield '\x1f00' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f88' s = Yield '\x1f00' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI-foldMapping '\x1f89' s = Yield '\x1f01' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f89' s = Yield '\x1f01' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI-foldMapping '\x1f8a' s = Yield '\x1f02' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f8a' s = Yield '\x1f02' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI-foldMapping '\x1f8b' s = Yield '\x1f03' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f8b' s = Yield '\x1f03' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI-foldMapping '\x1f8c' s = Yield '\x1f04' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f8c' s = Yield '\x1f04' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI-foldMapping '\x1f8d' s = Yield '\x1f05' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f8d' s = Yield '\x1f05' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI-foldMapping '\x1f8e' s = Yield '\x1f06' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f8e' s = Yield '\x1f06' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI-foldMapping '\x1f8f' s = Yield '\x1f07' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f8f' s = Yield '\x1f07' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI-foldMapping '\x1f90' s = Yield '\x1f20' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f90' s = Yield '\x1f20' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI-foldMapping '\x1f91' s = Yield '\x1f21' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f91' s = Yield '\x1f21' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI-foldMapping '\x1f92' s = Yield '\x1f22' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f92' s = Yield '\x1f22' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI-foldMapping '\x1f93' s = Yield '\x1f23' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f93' s = Yield '\x1f23' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI-foldMapping '\x1f94' s = Yield '\x1f24' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f94' s = Yield '\x1f24' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI-foldMapping '\x1f95' s = Yield '\x1f25' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f95' s = Yield '\x1f25' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI-foldMapping '\x1f96' s = Yield '\x1f26' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f96' s = Yield '\x1f26' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI-foldMapping '\x1f97' s = Yield '\x1f27' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f97' s = Yield '\x1f27' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI-foldMapping '\x1f98' s = Yield '\x1f20' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f98' s = Yield '\x1f20' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI-foldMapping '\x1f99' s = Yield '\x1f21' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f99' s = Yield '\x1f21' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI-foldMapping '\x1f9a' s = Yield '\x1f22' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f9a' s = Yield '\x1f22' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI-foldMapping '\x1f9b' s = Yield '\x1f23' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f9b' s = Yield '\x1f23' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI-foldMapping '\x1f9c' s = Yield '\x1f24' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f9c' s = Yield '\x1f24' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI-foldMapping '\x1f9d' s = Yield '\x1f25' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f9d' s = Yield '\x1f25' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI-foldMapping '\x1f9e' s = Yield '\x1f26' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f9e' s = Yield '\x1f26' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI-foldMapping '\x1f9f' s = Yield '\x1f27' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1f9f' s = Yield '\x1f27' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI-foldMapping '\x1fa0' s = Yield '\x1f60' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fa0' s = Yield '\x1f60' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI-foldMapping '\x1fa1' s = Yield '\x1f61' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fa1' s = Yield '\x1f61' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI-foldMapping '\x1fa2' s = Yield '\x1f62' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fa2' s = Yield '\x1f62' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI-foldMapping '\x1fa3' s = Yield '\x1f63' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fa3' s = Yield '\x1f63' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI-foldMapping '\x1fa4' s = Yield '\x1f64' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fa4' s = Yield '\x1f64' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI-foldMapping '\x1fa5' s = Yield '\x1f65' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fa5' s = Yield '\x1f65' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI-foldMapping '\x1fa6' s = Yield '\x1f66' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fa6' s = Yield '\x1f66' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI-foldMapping '\x1fa7' s = Yield '\x1f67' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fa7' s = Yield '\x1f67' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI-foldMapping '\x1fa8' s = Yield '\x1f60' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fa8' s = Yield '\x1f60' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI-foldMapping '\x1fa9' s = Yield '\x1f61' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fa9' s = Yield '\x1f61' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI-foldMapping '\x1faa' s = Yield '\x1f62' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1faa' s = Yield '\x1f62' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI-foldMapping '\x1fab' s = Yield '\x1f63' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fab' s = Yield '\x1f63' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI-foldMapping '\x1fac' s = Yield '\x1f64' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fac' s = Yield '\x1f64' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI-foldMapping '\x1fad' s = Yield '\x1f65' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fad' s = Yield '\x1f65' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI-foldMapping '\x1fae' s = Yield '\x1f66' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fae' s = Yield '\x1f66' (s :*: '\x03b9' :*: '\x0000') -- GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI-foldMapping '\x1faf' s = Yield '\x1f67' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1faf' s = Yield '\x1f67' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI-foldMapping '\x1fb2' s = Yield '\x1f70' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fb2' s = Yield '\x1f70' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI-foldMapping '\x1fb3' s = Yield '\x03b1' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fb3' s = Yield '\x03b1' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI-foldMapping '\x1fb4' s = Yield '\x03ac' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fb4' s = Yield '\x03ac' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH PERISPOMENI-foldMapping '\x1fb6' s = Yield '\x03b1' (s :!: '\x0342' :!: '\x0000')+foldMapping '\x1fb6' s = Yield '\x03b1' (s :*: '\x0342' :*: '\x0000') -- GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI-foldMapping '\x1fb7' s = Yield '\x03b1' (s :!: '\x0342' :!: '\x03b9')+foldMapping '\x1fb7' s = Yield '\x03b1' (s :*: '\x0342' :*: '\x03b9') -- GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI-foldMapping '\x1fbc' s = Yield '\x03b1' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fbc' s = Yield '\x03b1' (s :*: '\x03b9' :*: '\x0000') -- GREEK PROSGEGRAMMENI-foldMapping '\x1fbe' s = Yield '\x03b9' (s :!: '\x0000' :!: '\x0000')+foldMapping '\x1fbe' s = Yield '\x03b9' (s :*: '\x0000' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI-foldMapping '\x1fc2' s = Yield '\x1f74' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fc2' s = Yield '\x1f74' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI-foldMapping '\x1fc3' s = Yield '\x03b7' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fc3' s = Yield '\x03b7' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI-foldMapping '\x1fc4' s = Yield '\x03ae' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fc4' s = Yield '\x03ae' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH PERISPOMENI-foldMapping '\x1fc6' s = Yield '\x03b7' (s :!: '\x0342' :!: '\x0000')+foldMapping '\x1fc6' s = Yield '\x03b7' (s :*: '\x0342' :*: '\x0000') -- GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI-foldMapping '\x1fc7' s = Yield '\x03b7' (s :!: '\x0342' :!: '\x03b9')+foldMapping '\x1fc7' s = Yield '\x03b7' (s :*: '\x0342' :*: '\x03b9') -- GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI-foldMapping '\x1fcc' s = Yield '\x03b7' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1fcc' s = Yield '\x03b7' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA-foldMapping '\x1fd2' s = Yield '\x03b9' (s :!: '\x0308' :!: '\x0300')+foldMapping '\x1fd2' s = Yield '\x03b9' (s :*: '\x0308' :*: '\x0300') -- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA-foldMapping '\x1fd3' s = Yield '\x03b9' (s :!: '\x0308' :!: '\x0301')+foldMapping '\x1fd3' s = Yield '\x03b9' (s :*: '\x0308' :*: '\x0301') -- GREEK SMALL LETTER IOTA WITH PERISPOMENI-foldMapping '\x1fd6' s = Yield '\x03b9' (s :!: '\x0342' :!: '\x0000')+foldMapping '\x1fd6' s = Yield '\x03b9' (s :*: '\x0342' :*: '\x0000') -- GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI-foldMapping '\x1fd7' s = Yield '\x03b9' (s :!: '\x0308' :!: '\x0342')+foldMapping '\x1fd7' s = Yield '\x03b9' (s :*: '\x0308' :*: '\x0342') -- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA-foldMapping '\x1fe2' s = Yield '\x03c5' (s :!: '\x0308' :!: '\x0300')+foldMapping '\x1fe2' s = Yield '\x03c5' (s :*: '\x0308' :*: '\x0300') -- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA-foldMapping '\x1fe3' s = Yield '\x03c5' (s :!: '\x0308' :!: '\x0301')+foldMapping '\x1fe3' s = Yield '\x03c5' (s :*: '\x0308' :*: '\x0301') -- GREEK SMALL LETTER RHO WITH PSILI-foldMapping '\x1fe4' s = Yield '\x03c1' (s :!: '\x0313' :!: '\x0000')+foldMapping '\x1fe4' s = Yield '\x03c1' (s :*: '\x0313' :*: '\x0000') -- GREEK SMALL LETTER UPSILON WITH PERISPOMENI-foldMapping '\x1fe6' s = Yield '\x03c5' (s :!: '\x0342' :!: '\x0000')+foldMapping '\x1fe6' s = Yield '\x03c5' (s :*: '\x0342' :*: '\x0000') -- GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI-foldMapping '\x1fe7' s = Yield '\x03c5' (s :!: '\x0308' :!: '\x0342')+foldMapping '\x1fe7' s = Yield '\x03c5' (s :*: '\x0308' :*: '\x0342') -- GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI-foldMapping '\x1ff2' s = Yield '\x1f7c' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1ff2' s = Yield '\x1f7c' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI-foldMapping '\x1ff3' s = Yield '\x03c9' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1ff3' s = Yield '\x03c9' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI-foldMapping '\x1ff4' s = Yield '\x03ce' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1ff4' s = Yield '\x03ce' (s :*: '\x03b9' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH PERISPOMENI-foldMapping '\x1ff6' s = Yield '\x03c9' (s :!: '\x0342' :!: '\x0000')+foldMapping '\x1ff6' s = Yield '\x03c9' (s :*: '\x0342' :*: '\x0000') -- GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI-foldMapping '\x1ff7' s = Yield '\x03c9' (s :!: '\x0342' :!: '\x03b9')+foldMapping '\x1ff7' s = Yield '\x03c9' (s :*: '\x0342' :*: '\x03b9') -- GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI-foldMapping '\x1ffc' s = Yield '\x03c9' (s :!: '\x03b9' :!: '\x0000')+foldMapping '\x1ffc' s = Yield '\x03c9' (s :*: '\x03b9' :*: '\x0000') -- LATIN SMALL LIGATURE FF-foldMapping '\xfb00' s = Yield '\x0066' (s :!: '\x0066' :!: '\x0000')+foldMapping '\xfb00' s = Yield '\x0066' (s :*: '\x0066' :*: '\x0000') -- LATIN SMALL LIGATURE FI-foldMapping '\xfb01' s = Yield '\x0066' (s :!: '\x0069' :!: '\x0000')+foldMapping '\xfb01' s = Yield '\x0066' (s :*: '\x0069' :*: '\x0000') -- LATIN SMALL LIGATURE FL-foldMapping '\xfb02' s = Yield '\x0066' (s :!: '\x006c' :!: '\x0000')+foldMapping '\xfb02' s = Yield '\x0066' (s :*: '\x006c' :*: '\x0000') -- LATIN SMALL LIGATURE FFI-foldMapping '\xfb03' s = Yield '\x0066' (s :!: '\x0066' :!: '\x0069')+foldMapping '\xfb03' s = Yield '\x0066' (s :*: '\x0066' :*: '\x0069') -- LATIN SMALL LIGATURE FFL-foldMapping '\xfb04' s = Yield '\x0066' (s :!: '\x0066' :!: '\x006c')+foldMapping '\xfb04' s = Yield '\x0066' (s :*: '\x0066' :*: '\x006c') -- LATIN SMALL LIGATURE LONG S T-foldMapping '\xfb05' s = Yield '\x0073' (s :!: '\x0074' :!: '\x0000')+foldMapping '\xfb05' s = Yield '\x0073' (s :*: '\x0074' :*: '\x0000') -- LATIN SMALL LIGATURE ST-foldMapping '\xfb06' s = Yield '\x0073' (s :!: '\x0074' :!: '\x0000')+foldMapping '\xfb06' s = Yield '\x0073' (s :*: '\x0074' :*: '\x0000') -- ARMENIAN SMALL LIGATURE MEN NOW-foldMapping '\xfb13' s = Yield '\x0574' (s :!: '\x0576' :!: '\x0000')+foldMapping '\xfb13' s = Yield '\x0574' (s :*: '\x0576' :*: '\x0000') -- ARMENIAN SMALL LIGATURE MEN ECH-foldMapping '\xfb14' s = Yield '\x0574' (s :!: '\x0565' :!: '\x0000')+foldMapping '\xfb14' s = Yield '\x0574' (s :*: '\x0565' :*: '\x0000') -- ARMENIAN SMALL LIGATURE MEN INI-foldMapping '\xfb15' s = Yield '\x0574' (s :!: '\x056b' :!: '\x0000')+foldMapping '\xfb15' s = Yield '\x0574' (s :*: '\x056b' :*: '\x0000') -- ARMENIAN SMALL LIGATURE VEW NOW-foldMapping '\xfb16' s = Yield '\x057e' (s :!: '\x0576' :!: '\x0000')+foldMapping '\xfb16' s = Yield '\x057e' (s :*: '\x0576' :*: '\x0000') -- ARMENIAN SMALL LIGATURE MEN XEH-foldMapping '\xfb17' s = Yield '\x0574' (s :!: '\x056d' :!: '\x0000')-foldMapping c s = Yield (toLower c) (s :!: '\0' :!: '\0')+foldMapping '\xfb17' s = Yield '\x0574' (s :*: '\x056d' :*: '\x0000')+foldMapping c s = Yield (toLower c) (s :*: '\0' :*: '\0')
Data/Text/Fusion/Common.hs view
@@ -29,6 +29,7 @@ , init , null , lengthI+ , isSingleton -- * Transformations , map@@ -88,12 +89,9 @@ , filter -- * Indexing- , find+ , findBy , indexI , findIndexI- , findIndicesI- , elemIndexI- , elemIndicesI , countCharI -- * Zipping and unzipping@@ -108,20 +106,19 @@ import Data.Int (Int64) import Data.Text.Fusion.Internal import Data.Text.Fusion.CaseMapping (foldMapping, lowerMapping, upperMapping)+import Data.Text.Fusion.Size singleton :: Char -> Stream Char-singleton c = Stream next False 1 -- HINT maybe too low+singleton c = Stream next False 1 where next False = Yield c True next True = Done {-# INLINE singleton #-} streamList :: [a] -> Stream a {-# INLINE [0] streamList #-}-streamList [] = empty-streamList s = Stream next s unknownLength+streamList s = Stream next s unknownSize where next [] = Done next (x:xs) = Yield x xs- unknownLength = 8 -- random HINT unstreamList :: Stream a -> [a] {-# INLINE [0] unstreamList #-}@@ -138,19 +135,19 @@ -- | /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 (S2 :!: s0) (len+2) -- HINT maybe too high+cons w (Stream next0 s0 len) = Stream next (S2 :*: s0) (len+1) where {-# INLINE next #-}- next (S2 :!: s) = Yield w (S1 :!: s)- next (S1 :!: s) = case next0 s of+ next (S2 :*: s) = Yield w (S1 :*: s)+ next (S1 :*: s) = case next0 s of Done -> Done- Skip s' -> Skip (S1 :!: s')- Yield x s' -> Yield x (S1 :!: s')+ Skip s' -> Skip (S1 :*: s')+ Yield x s' -> Yield x (S1 :*: s') {-# INLINE [0] cons #-} -- | /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+2) -- HINT maybe too high+snoc (Stream next0 xs0 len) w = Stream next (J xs0) (len+1) where {-# INLINE next #-} next (J xs) = case next0 xs of@@ -193,7 +190,7 @@ 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-1)) -- HINT maybe too high+ Yield x s1 -> Just (x, Stream next s1 (len-1)) Skip s' -> loop_uncons s' Done -> Nothing {-# INLINE [0] uncons #-}@@ -216,34 +213,34 @@ -- | /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 (False :!: s0) (len-1) -- HINT maybe too high+tail (Stream next0 s0 len) = Stream next (False :*: s0) (len-1) where {-# INLINE next #-}- next (False :!: s) = case next0 s of- Done -> emptyError "tail"- Skip s' -> Skip (False :!: s')- Yield _ s' -> Skip (True :!: s')- next (True :!: s) = case next0 s of- Done -> Done- Skip s' -> Skip (True :!: s')- Yield x s' -> Yield x (True :!: s')+ next (False :*: s) = case next0 s of+ Done -> emptyError "tail"+ Skip s' -> Skip (False :*: s')+ Yield _ s' -> Skip (True :*: s')+ next (True :*: s) = case next0 s of+ Done -> Done+ Skip s' -> Skip (True :*: s')+ Yield x s' -> Yield x (True :*: s') {-# INLINE [0] tail #-} -- | /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 (N :!: s0) (len-1) -- HINT maybe too high+init (Stream next0 s0 len) = Stream next (N :*: s0) (len-1) where {-# INLINE next #-}- next (N :!: s) = case next0 s of+ next (N :*: s) = case next0 s of Done -> emptyError "init"- Skip s' -> Skip (N :!: s')- Yield x s' -> Skip (J x :!: s')- next (J x :!: s) = case next0 s of+ Skip s' -> Skip (N :*: s')+ Yield x s' -> Skip (J x :*: s')+ next (J x :*: s) = case next0 s of Done -> Done- Skip s' -> Skip (J x :!: s')- Yield x' s' -> Yield x (J x' :!: s')+ Skip s' -> Skip (J x :*: s')+ Yield x' s' -> Yield x (J x' :*: s') {-# INLINE [0] init #-} -- | /O(1)/ Tests whether a Stream Char is empty or not.@@ -256,7 +253,7 @@ Skip s' -> loop_null s' {-# INLINE[0] null #-} --- | /O(n)/ Returns the number of characters in a text.+-- | /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@@ -266,13 +263,25 @@ Yield _ s' -> loop_length (z + 1) s' {-# INLINE[0] lengthI #-} +-- | /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@.+-- | /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 -- HINT depends on f+map f (Stream next0 s0 len) = Stream next s0 len where {-# INLINE next #-} next !s = case next0 s of@@ -289,18 +298,18 @@ -- | /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 (s0 :!: N :!: S1) len -- HINT maybe too low+intersperse c (Stream next0 s0 len) = Stream next (s0 :*: N :*: S1) len where {-# INLINE next #-}- next (s :!: N :!: S1) = case next0 s of+ next (s :*: N :*: S1) = case next0 s of Done -> Done- Skip s' -> Skip (s' :!: N :!: S1)- Yield x s' -> Skip (s' :!: J x :!: S1)- next (s :!: J x :!: S1) = Yield x (s :!: N :!: S2)- next (s :!: N :!: S2) = case next0 s of+ Skip s' -> Skip (s' :*: N :*: S1)+ Yield x s' -> Skip (s' :*: J x :*: S1)+ next (s :*: J x :*: S1) = Yield x (s :*: N :*: S2)+ next (s :*: N :*: S2) = case next0 s of Done -> Done- Skip s' -> Skip (s' :!: N :!: S2)- Yield x s' -> Yield c (s' :!: J x :!: S1)+ Skip s' -> Skip (s' :*: N :*: S2)+ Yield x s' -> Yield c (s' :*: J x :*: S1) next _ = internalError "intersperse" {-# INLINE [0] intersperse #-} @@ -318,15 +327,15 @@ caseConvert :: (forall s. Char -> s -> Step (PairS (PairS s Char) Char) Char) -> Stream Char -> Stream Char-caseConvert remap (Stream next0 s0 len) = Stream next (s0 :!: '\0' :!: '\0') len+caseConvert remap (Stream next0 s0 len) = Stream next (s0 :*: '\0' :*: '\0') len where {-# INLINE next #-}- next (s :!: '\0' :!: _) =+ next (s :*: '\0' :*: _) = case next0 s of Done -> Done- Skip s' -> Skip (s' :!: '\0' :!: '\0')+ Skip s' -> Skip (s' :*: '\0' :*: '\0') Yield c s' -> remap c s'- next (s :!: a :!: b) = Yield a (s :!: b :!: '\0')+ next (s :*: a :*: b) = Yield a (s :*: b :*: '\0') -- | /O(n)/ Convert a string to folded case. This function is mainly -- useful for performing caseless (or case insensitive) string@@ -364,18 +373,16 @@ {-# INLINE [0] toLower #-} justifyLeftI :: Integral a => a -> Char -> Stream Char -> Stream Char-justifyLeftI k c (Stream next0 s0 len) = Stream next (s0 :!: S1 :!: 0) newLen+justifyLeftI k c (Stream next0 s0 len) =+ Stream next (s0 :*: S1 :*: 0) (larger (fromIntegral k) len) where- j = fromIntegral k- newLen | j > len = j- | otherwise = len- next (s :!: S1 :!: n) =+ next (s :*: S1 :*: n) = case next0 s of- Done -> next (s :!: S2 :!: n)- Skip s' -> Skip (s' :!: S1 :!: n)- Yield x s' -> Yield x (s' :!: S1 :!: n+1)- next (s :!: S2 :!: n)- | n < k = Yield c (s :!: S2 :!: n+1)+ Done -> next (s :*: S2 :*: n)+ Skip s' -> Skip (s' :*: S1 :*: n)+ Yield x s' -> Yield x (s' :*: S1 :*: n+1)+ next (s :*: S2 :*: n)+ | n < k = Yield c (s :*: S2 :*: n+1) | otherwise = Done {-# INLINE next #-} {-# INLINE [0] justifyLeftI #-}@@ -541,14 +548,14 @@ -- * Building streams scanl :: (Char -> Char -> Char) -> Char -> Stream Char -> Stream Char-scanl f z0 (Stream next0 s0 len) = Stream next (S1 :!: z0 :!: s0) (len+1) -- HINT maybe too low+scanl f z0 (Stream next0 s0 len) = Stream next (S1 :*: z0 :*: s0) (len+1) -- HINT maybe too low where {-# INLINE next #-}- next (S1 :!: z :!: s) = Yield z (S2 :!: z :!: s)- next (S2 :!: z :!: s) = case next0 s of+ next (S1 :*: z :*: s) = Yield z (S2 :*: z :*: s)+ next (S2 :*: z :*: s) = case next0 s of Yield x s' -> let !x' = f z x- in Yield x' (S2 :!: x' :!: s')- Skip s' -> Skip (S2 :!: z :!: s')+ in Yield x' (S2 :*: x' :*: s')+ Skip s' -> Skip (S2 :*: z :*: s') Done -> Done {-# INLINE [0] scanl #-} @@ -564,13 +571,13 @@ -- return a final value for the accumulator, because the nature of -- streams precludes it. mapAccumL :: (a -> b -> (a,b)) -> a -> Stream b -> Stream b-mapAccumL f z0 (Stream next0 s0 len) = Stream next (s0 :!: z0) len -- HINT depends on f+mapAccumL f z0 (Stream next0 s0 len) = Stream next (s0 :*: z0) len -- HINT depends on f where {-# INLINE next #-}- next (s :!: z) = case next0 s of+ next (s :*: z) = case next0 s of Yield x s' -> let (z',y) = f z x- in Yield y (s' :!: z')- Skip s' -> Skip (s' :!: z)+ in Yield y (s' :*: z')+ Skip s' -> Skip (s' :*: z) Done -> Done {-# INLINE [0] mapAccumL #-} -}@@ -590,14 +597,14 @@ replicateI :: Int64 -> Stream Char -> Stream Char replicateI n (Stream next0 s0 len) =- Stream next (0 :!: s0) (max 0 (fromIntegral n * len))+ Stream next (0 :*: s0) (fromIntegral (max 0 n) * len) where- next (k :!: s)+ next (k :*: s) | k >= n = Done | otherwise = case next0 s of- Done -> Skip (k+1 :!: s0)- Skip s' -> Skip (k :!: s')- Yield x s' -> Yield x (k :!: s')+ Done -> Skip (k+1 :*: s0)+ Skip s' -> Skip (k :*: s')+ Yield x s' -> Yield x (k :*: s') {-# INLINE [0] replicateI #-} -- | /O(n)/, where @n@ is the length of the result. The unfoldr function@@ -621,13 +628,13 @@ -- '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) (fromIntegral (n*2)) -- HINT maybe too high+ | otherwise = Stream next (0 :*: s0) (fromIntegral (n*2)) -- HINT maybe too high where {-# INLINE next #-}- next (z :!: s) = case f s of+ next (z :*: s) = case f s of Nothing -> Done Just (w, s') | z >= n -> Done- | otherwise -> Yield w ((z + 1) :!: s')+ | otherwise -> Yield w ((z + 1) :*: s') {-# INLINE unfoldrNI #-} -------------------------------------------------------------------------------@@ -637,14 +644,15 @@ -- 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) (min 0 (len - fromIntegral n0)) -- HINT maybe too high+take n0 (Stream next0 s0 len) =+ Stream next (n0 :*: s0) (smaller len (fromIntegral (max 0 n0))) where {-# INLINE next #-}- next (n :!: s) | n <= 0 = Done+ 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')+ Skip s' -> Skip (n :*: s')+ Yield x s' -> Yield x ((n-1) :*: s') {-# INLINE [0] take #-} -- | /O(n)/ drop n, applied to a stream, returns the suffix of the@@ -652,19 +660,19 @@ -- length of the stream. drop :: Integral a => a -> Stream Char -> Stream Char drop n0 (Stream next0 s0 len) =- Stream next (J (max 0 n0) :!: s0) (len - fromIntegral n0) -- HINT maybe too high+ Stream next (J n0 :*: s0) (len - fromIntegral (max 0 n0)) where {-# INLINE next #-}- next (J n :!: s)- | n == 0 = Skip (N :!: s)+ next (J n :*: s)+ | n <= 0 = Skip (N :*: s) | otherwise = case next0 s of Done -> Done- Skip s' -> Skip (J n :!: s')- Yield _ s' -> Skip (J (n-1) :!: s')- next (N :!: s) = case next0 s of+ Skip s' -> Skip (J n :*: s')+ Yield _ s' -> Skip (J (n-1) :*: s')+ next (N :*: s) = case next0 s of Done -> Done- Skip s' -> Skip (N :!: s')- Yield x s' -> Yield x (N :!: s')+ Skip s' -> Skip (N :*: s')+ Yield x s' -> Yield x (N :*: s') {-# INLINE [0] drop #-} -- | takeWhile, applied to a predicate @p@ and a stream, returns the@@ -682,18 +690,18 @@ -- | 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 (S1 :!: s0) len -- HINT maybe too high+dropWhile p (Stream next0 s0 len) = Stream next (S1 :*: s0) len -- HINT maybe too high where {-# INLINE next #-}- next (S1 :!: s) = case next0 s of+ next (S1 :*: s) = case next0 s of Done -> Done- Skip s' -> Skip (S1 :!: s')- Yield x s' | p x -> Skip (S1 :!: s')- | otherwise -> Yield x (S2 :!: s')- next (S2 :!: s) = case next0 s of+ Skip s' -> Skip (S1 :*: s')+ Yield x s' | p x -> Skip (S1 :*: s')+ | otherwise -> Yield x (S2 :*: s')+ next (S2 :*: s) = case next0 s of Done -> Done- Skip s' -> Skip (S2 :!: s')- Yield x s' -> Yield x (S2 :!: s')+ Skip s' -> Skip (S2 :*: s')+ Yield x s' -> Yield x (S2 :*: s') {-# INLINE [0] dropWhile #-} -- | /O(n)/ The 'isPrefixOf' function takes two 'Stream's and returns@@ -731,19 +739,19 @@ ------------------------------------------------------------------------------- -- ** Searching with a predicate --- | /O(n)/ The 'find' function takes a predicate and a stream,+-- | /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. -find :: (Char -> Bool) -> Stream Char -> Maybe Char-find p (Stream next s0 _len) = loop_find s0+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] find #-}+{-# INLINE [0] findBy #-} -- | /O(n)/ Stream index (subscript) operator, starting from 0. indexI :: Integral a => Stream Char -> a -> Char@@ -805,40 +813,20 @@ -- | 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 (sa0 :!: sb0 :!: N) (min len1 len2)+zipWith f (Stream next0 sa0 len1) (Stream next1 sb0 len2) =+ Stream next (sa0 :*: sb0 :*: N) (smaller len1 len2) where {-# INLINE next #-}- next (sa :!: sb :!: N) = case next0 sa of+ next (sa :*: sb :*: N) = case next0 sa of Done -> Done- Skip sa' -> Skip (sa' :!: sb :!: N)- Yield a sa' -> Skip (sa' :!: sb :!: J a)+ Skip sa' -> Skip (sa' :*: sb :*: N)+ Yield a sa' -> Skip (sa' :*: sb :*: J a) - next (sa' :!: sb :!: J a) = case next1 sb of+ next (sa' :*: sb :*: J a) = case next1 sb of Done -> Done- Skip sb' -> Skip (sa' :!: sb' :!: J a)- Yield b sb' -> Yield (f a b) (sa' :!: sb' :!: N)+ Skip sb' -> Skip (sa' :*: sb' :*: J a)+ Yield b sb' -> Yield (f a b) (sa' :*: sb' :*: N) {-# INLINE [0] zipWith #-}---- | /O(n)/ The 'elemIndexI' function returns the index of the first--- element in the given stream which is equal to the query--- element, or 'Nothing' if there is no such element.-elemIndexI :: Integral a => Char -> Stream Char -> Maybe a-elemIndexI a s = case elemIndicesI a s of- (i:_) -> Just i- _ -> Nothing-{-# INLINE [0] elemIndexI #-}---- | /O(n)/ The 'elemIndicesI' function returns the index of every--- element in the given stream which is equal to the query element.-elemIndicesI :: Integral a => Char -> Stream Char -> [a]-elemIndicesI a (Stream next s0 _len) = loop 0 s0- where- loop !i !s = case next s of- Done -> []- Skip s' -> loop i s'- Yield x s' | a == x -> i : loop (i+1) s'- | otherwise -> loop (i+1) s'-{-# INLINE [0] elemIndicesI #-} -- | /O(n)/ The 'countCharI' function returns the number of times the -- query element appears in the given stream.
Data/Text/Fusion/Internal.hs view
@@ -25,6 +25,7 @@ , empty ) where +import Data.Text.Fusion.Size import Data.Word (Word8) -- | Specialised, strict Maybe-like type.@@ -37,8 +38,9 @@ data S s = S {-# UNPACK #-} !s {-# UNPACK #-} !M8 {-# UNPACK #-} !M8 {-# UNPACK #-} !M8 -infixl 2 :!:-data PairS a b = !a :!: !b+infixl 2 :*:+data PairS a b = {-# UNPACK #-} !a :*: {-# UNPACK #-} !b+ deriving (Eq, Ord, Show) -- | Allow a function over a stream to switch between two states. data Switch = S1 | S2@@ -47,12 +49,10 @@ | Skip !s | Yield !a !s -{--instance Show a => Show (Step s a)+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@@ -76,7 +76,7 @@ forall s. Stream (s -> Step s a) -- stepper function !s -- current state- {-# UNPACK #-}!Int -- length hint+ {-# UNPACK #-} !Size -- size hint -- | /O(n)/ Determines if two streams are equal. eq :: (Eq a) => Stream a -> Stream a -> Bool
+ Data/Text/Fusion/Size.hs view
@@ -0,0 +1,129 @@+{-# OPTIONS_GHC -fno-warn-missing-methods #-}+-- |+-- Module : Data.Text.Fusion.Internal+-- Copyright : (c) Roman Leshchinskiy 2008,+-- (c) Bryan O'Sullivan 2009+--+-- License : BSD-style+-- Maintainer : bos@serpentine.com, rtharper@aftereternity.co.uk,+-- duncan@haskell.org+-- Stability : experimental+-- Portability : portable+--+-- Size hints.++module Data.Text.Fusion.Size+ (+ Size+ , exactSize+ , maxSize+ , unknownSize+ , smaller+ , larger+ , toMax+ , upperBound+ , lowerBound+ , isEmpty+ ) where++import Control.Exception (assert)++data Size = Exact {-# UNPACK #-} !Int -- ^ Exact size.+ | Max {-# UNPACK #-} !Int -- ^ Upper bound on size.+ | Unknown -- ^ Unknown size.+ deriving (Eq, Show)++exactSize :: Int -> Size+exactSize n = assert (n >= 0) Exact n+{-# INLINE exactSize #-}++maxSize :: Int -> Size+maxSize n = assert (n >= 0) Max n+{-# INLINE maxSize #-}++unknownSize :: Size+unknownSize = Unknown+{-# INLINE unknownSize #-}++instance Num Size where+ (+) = addSize+ (-) = subtractSize+ (*) = mulSize++ fromInteger = f where f = Exact . fromInteger+ {-# INLINE f #-}++addSize :: Size -> Size -> Size+addSize (Exact m) (Exact n) = Exact (m+n)+addSize (Exact m) (Max n) = Max (m+n)+addSize (Max m) (Exact n) = Max (m+n)+addSize (Max m) (Max n) = Max (m+n)+addSize _ _ = Unknown+{-# INLINE addSize #-}++subtractSize :: Size -> Size -> Size+subtractSize (Exact m) (Exact n) = Exact (max (m-n) 0)+subtractSize (Exact m) (Max _) = Max m+subtractSize (Max m) (Exact n) = Max (max (m-n) 0)+subtractSize a@(Max _) (Max _) = a+subtractSize a@(Max _) Unknown = a+subtractSize _ _ = Unknown+{-# INLINE subtractSize #-}++mulSize :: Size -> Size -> Size+mulSize (Exact m) (Exact n) = Exact (m*n)+mulSize (Exact m) (Max n) = Max (m*n)+mulSize (Max m) (Exact n) = Max (m*n)+mulSize (Max m) (Max n) = Max (m*n)+mulSize _ _ = Unknown+{-# INLINE mulSize #-}++-- | Minimum of two size hints.+smaller :: Size -> Size -> Size+smaller (Exact m) (Exact n) = Exact (m `min` n)+smaller (Exact m) (Max n) = Max (m `min` n)+smaller (Exact m) Unknown = Max m+smaller (Max m) (Exact n) = Max (m `min` n)+smaller (Max m) (Max n) = Max (m `min` n)+smaller a@(Max _) Unknown = a+smaller Unknown (Exact n) = Max n+smaller Unknown (Max n) = Max n+smaller Unknown Unknown = Unknown+{-# INLINE smaller #-}++-- | Maximum of two size hints.+larger :: Size -> Size -> Size+larger (Exact m) (Exact n) = Exact (m `max` n)+larger a@(Exact m) b@(Max n) | m >= n = a+ | otherwise = b+larger a@(Max m) b@(Exact n) | n >= m = b+ | otherwise = a+larger (Max m) (Max n) = Max (m `max` n)+larger _ _ = Unknown+{-# INLINE larger #-}++-- | Convert a size hint to an upper bound.+toMax :: Size -> Size+toMax (Exact n) = Max n+toMax a@(Max _) = a+toMax Unknown = Unknown+{-# INLINE toMax #-}++-- | Compute the minimum size from a size hint.+lowerBound :: Size -> Int+lowerBound (Exact n) = n+lowerBound _ = 0+{-# INLINE lowerBound #-}++-- | Compute the maximum size from a size hint, if possible.+upperBound :: Int -> Size -> Int+upperBound _ (Exact n) = n+upperBound _ (Max n) = n+upperBound k _ = k+{-# INLINE upperBound #-}++isEmpty :: Size -> Bool+isEmpty (Exact n) = n <= 0+isEmpty (Max n) = n <= 0+isEmpty _ = False+{-# INLINE isEmpty #-}
Data/Text/Lazy.hs view
@@ -101,7 +101,6 @@ -- ** Generation and unfolding , replicate- , replicateChar , unfoldr , unfoldrN @@ -118,8 +117,9 @@ , stripStart , stripEnd , splitAt- , span+ , spanBy , break+ , breakBy , group , groupBy , inits@@ -128,9 +128,7 @@ -- ** Breaking into many substrings -- $split , split- , splitTimes- , splitTimesEnd- , splitWith+ , splitBy , chunksOf -- , breakSubstring @@ -146,19 +144,15 @@ , isInfixOf -- * Searching- , elem , filter , find- , partition+ , findBy+ , partitionBy -- , findSubstring -- * Indexing , index- , findIndex- , findIndices- , elemIndex- , elemIndices , count -- * Zipping and unzipping@@ -171,7 +165,7 @@ import Prelude (Char, Bool(..), Int, Maybe(..), String, Eq(..), Ord(..), Read(..), Show(..),- (&&), (||), (+), (-), (.), ($), (++),+ (&&), (+), (-), (.), ($), (++), div, flip, fromIntegral, not, otherwise) import qualified Prelude as P import Data.Int (Int64)@@ -180,11 +174,15 @@ import Data.Monoid (Monoid(..)) import Data.String (IsString(..)) import qualified Data.Text as T+import qualified Data.Text.Internal as T import qualified Data.Text.Fusion.Common as S import qualified Data.Text.Unsafe as T import qualified Data.Text.Lazy.Fusion as S+import Data.Text.Fusion.Internal (PairS(..)) import Data.Text.Lazy.Fusion (stream, unstream)-import Data.Text.Lazy.Internal+import Data.Text.Lazy.Internal (Text(..), chunk, empty, foldlChunks, foldrChunks)+import Data.Text.Internal (textP)+import Data.Text.Lazy.Search (indices) instance Eq Text where t1 == t2 = stream t1 == stream t2@@ -334,6 +332,12 @@ 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(1)/ Returns the last character of a 'Text', which must be -- non-empty. Subject to array fusion. last :: Text -> Char@@ -635,13 +639,16 @@ -- | /O(n*m)/ 'replicate' @n@ @t@ is a 'Text' consisting of the input -- @t@ repeated @n@ times. Subject to fusion. replicate :: Int64 -> Text -> Text-replicate n t = unstream (S.replicateI n (S.stream t))+replicate n t+ | isSingleton t = replicateChar n (head t)+ | otherwise = unstream (S.replicateI n (S.stream t)) {-# INLINE replicate #-} -- | /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 c)+{-# INLINE replicateChar #-} {-# RULES "LAZY TEXT replicate/singleton -> replicateChar" [~1] forall n c.@@ -693,14 +700,14 @@ -- length of the 'Text'. Subject to fusion. drop :: Int64 -> Text -> Text drop i t0- | i <= 0 = 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+ | n < len = Chunk (T.drop (fromIntegral n) t) ts | otherwise = drop' (n - len) ts- where len = fromIntegral (T.length t)+ where len = fromIntegral (T.length t) {-# INLINE [1] drop #-} {-# RULES@@ -710,6 +717,21 @@ unstream (S.drop n (stream t)) = drop n 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 (textP 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@. -- This function is subject to array fusion.@@ -808,10 +830,88 @@ in (Chunk t ts', ts'') where len = fromIntegral (T.length t) --- | /O(n)/ 'break' is like 'span', but the prefix returned is over+-- | /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 (textP arr off y) empty :*:+ chunk (textP 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:+--+-- > break "::" "a::b::c" ==> ("a", "::b::c")+-- > break "/" "foobar" ==> ("foobar", "")+--+-- Laws:+--+-- > append prefix match == haystack+-- > where (prefix, match) = break 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 'find'+-- 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)/.+break :: Text -> Text -> (Text, Text)+break pat src+ | null pat = emptyError "break"+ | otherwise = case indices pat src of+ [] -> (src, empty)+ (x:_) -> let h :*: t = splitAtWord x src+ in (h, t)++-- | /O(n+m)/ Find all non-overlapping instances of @needle@ in+-- @haystack@. The first element of the returned pair is the prefix+-- of @haystack@ prior to any matches of @needle@. The second is a+-- list of pairs.+--+-- The first element of each pair in the list is a span from the+-- beginning of a match to the beginning of the next match, while the+-- second is a span from the beginning of the match to the end of the+-- input.+--+-- Examples:+--+-- > find "::" ""+-- > ==> ("", [])+-- > find "/" "a/b/c/d"+-- > ==> ("a", [("/b","/b/c/d"), ("/c","/c/d"), ("/d","/d")])+--+-- 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)/.+find :: Text -> Text -> (Text, [(Text, Text)])+find pat src+ | null pat = emptyError "find"+ | otherwise = case indices pat src of+ [] -> (src, [])+ (x:xs) -> let h :*: t = splitAtWord x src+ in (h, go x xs t)+ where+ go !i (x:xs) cs = let h :*: t = splitAtWord (x-i) cs+ in (h, cs) : go x xs t+ go _ _ cs = [(cs,cs)]++-- | /O(n)/ 'breakBy' is like 'spanBy', but the prefix returned is over -- elements that fail the predicate @p@.-break :: (Char -> Bool) -> Text -> (Text, Text)-break p t0 = break' t0+breakBy :: (Char -> Bool) -> Text -> (Text, Text)+breakBy p t0 = break' t0 where break' Empty = (empty, empty) break' c@(Chunk t ts) = case T.findIndex p t of@@ -821,13 +921,13 @@ | 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 #-}+-- | /O(n)/ 'spanBy', 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.+spanBy :: (Char -> Bool) -> Text -> (Text, Text)+spanBy p = breakBy (not . p)+{-# INLINE spanBy #-} -- | 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.@@ -846,7 +946,7 @@ 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+ where (ys,zs) = spanBy (eq x) xs x = T.unsafeHead t xs = chunk (T.unsafeTail t) ts @@ -872,8 +972,8 @@ -- copies to create substrings; they just construct new 'Text's that -- are slices of the original. --- | /O(m)*O(n)/ Break a 'Text' into pieces separated by the first--- 'Text' argument, consuming the delimiter. An empty delimiter is+-- | /O(m+n)/ Break a 'Text' into pieces separated by the first+-- 'Text' argument, consuming the delimiter. An empty delimiter is -- invalid, and will cause an error to be raised. -- -- Examples:@@ -885,95 +985,47 @@ -- and -- -- > intercalate s . split s == id--- > split (singleton c) == splitWith (==c)+-- > split (singleton c) == splitBy (==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)/. split :: Text -- ^ Text to split on -> Text -- ^ Input text -> [Text]-split pat src0- | l == 0 = emptyError "split"- | l == 1 = splitWith (== (head pat)) src0- | otherwise = go src0+split pat src+ | null pat = emptyError "split"+ | isSingleton pat = splitBy (== head pat) src+ | otherwise = go 0 (indices pat src) src where- l = length pat- go src = search 0 src- where- search !n !s- | null s = [src] -- not found- | pat `isPrefixOf` s = take n src : go (drop l s)- | otherwise = search (n+1) (tail s)+ 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] split #-} {-# RULES-"LAZY TEXT split/singleton -> splitWith/==" [~1] forall c t.- split (singleton c) t = splitWith (==c) t+"LAZY TEXT split/singleton -> splitBy/==" [~1] forall c t.+ split (singleton c) t = splitBy (==c) t #-} --- | /O(m)*O(n)/ Break a 'Text' into pieces at most @k@ times,--- treating the first 'Text' argument as the delimiter to break on,--- and consuming the delimiter. The last element of the list contains--- the remaining text after the number of times to split has been--- reached. A value of zero or less for @k@ causes no splitting to--- occur. An empty delimiter is invalid, and will cause an error to--- be raised.------ Examples:------ > splitTimes 0 "//" "a//b//c" == ["a//b//c"]--- > splitTimes 2 ":" "a:b:c:d:e" == ["a","b","c:d:e"]--- > splitTimes 100 "???" "a????b" == ["a","?b"]------ and------ > intercalate s . splitTimes k s == id-splitTimes :: Int64 -- ^ Maximum number of times to split- -> Text -- ^ Text to split on- -> Text -- ^ Input text- -> [Text]-splitTimes k pat src0- | k <= 0 = [src0]- | l == 0 = emptyError "splitTimes"- | otherwise = go k src0- where- l = length pat- go !i src = search 0 src- where- search !n !s- | i == 0 || null s = [src] -- not found or limit reached- | pat `isPrefixOf` s = take n src : go (i-1) (drop l s)- | otherwise = search (n+1) (tail s)-{-# INLINE splitTimes #-}---- | /O(m)*O(n)/ Break a 'Text' into pieces at most @k@ times, like--- 'splitTimes', but start from the end of the input and work towards--- the start.------ Examples:------ > splitTimes 2 "::" "a::b::c::d::e" == ["a","b","c::d::e"]--- > splitTimesEnd 2 "::" "a::b::c::d::e" == ["a::b::c","d","e"]-splitTimesEnd :: Int64 -- ^ Maximum number of times to split- -> Text -- ^ Text to split on- -> Text -- ^ Input text- -> [Text]-splitTimesEnd k pat src =- L.reverse . L.map reverse $ splitTimes k (reverse pat) (reverse src)-{-# INLINE splitTimesEnd #-}- -- | /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. ----- > splitWith (=='a') "aabbaca" == ["","","bb","c",""]--- > splitWith (=='a') [] == [""]-splitWith :: (Char -> Bool) -> Text -> [Text]-splitWith _ Empty = [Empty]-splitWith p (Chunk t0 ts0) = comb [] (T.splitWith p t0) ts0+-- > splitBy (=='a') "aabbaca" == ["","","bb","c",""]+-- > splitBy (=='a') [] == [""]+splitBy :: (Char -> Bool) -> Text -> [Text]+splitBy _ Empty = [Empty]+splitBy p (Chunk t0 ts0) = comb [] (T.splitBy p t0) ts0 where comb acc (s:[]) Empty = revChunks (s:acc) : []- comb acc (s:[]) (Chunk t ts) = comb (s:acc) (T.splitWith p t) ts+ comb acc (s:[]) (Chunk t ts) = comb (s:acc) (T.splitBy p t) ts comb acc (s:ss) ts = revChunks (s:acc) : comb [] ss ts- comb _ [] _ = impossibleError "splitWith"-{-# INLINE splitWith #-}+ comb _ [] _ = impossibleError "splitBy"+{-# INLINE splitBy #-} -- | /O(n)/ Splits a 'Text' into components of length @k@. The last -- element may be shorter than the other chunks, depending on the@@ -993,14 +1045,14 @@ -- newline 'Char's. The resulting strings do not contain newlines. lines :: Text -> [Text] lines Empty = []-lines t = let (l,t') = break ((==) '\n') t+lines t = let (l,t') = breakBy ((==) '\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) . splitWith isSpace+words = L.filter (not . null) . splitBy isSpace {-# INLINE words #-} -- | /O(n)/ Joins lines, after appending a terminating newline to@@ -1044,18 +1096,26 @@ {-# INLINE isSuffixOf #-} -- TODO: a better implementation --- | /O(n)/ The 'isInfixOf' function takes two 'Text's and returns+-- | /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 = L.any (isPrefixOf needle) (tails haystack)-{-# INLINE isInfixOf #-}--- TODO: a better implementation+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 #-} --- | /O(n)/ 'elem' is the 'Text' membership predicate.-elem :: Char -> Text -> Bool-elem c t = S.elem c (stream t)-{-# INLINE elem #-}+{-# RULES+"LAZY TEXT isInfixOf/singleton -> S.elem/S.stream" [~1] forall n h.+ isInfixOf (singleton n) h = S.elem n (S.stream h)+ #-} -- | /O(n)/ 'filter', applied to a predicate and a 'Text', -- returns a 'Text' containing those characters that satisfy the@@ -1064,71 +1124,39 @@ 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'+-- | /O(n)/ The 'findBy' function takes a predicate and a 'Text', and+-- returns the first element in matching the predicate, or 'Nothing' -- if there is no such element.-find :: (Char -> Bool) -> Text -> Maybe Char-find p t = S.find p (stream t)-{-# INLINE find #-}+findBy :: (Char -> Bool) -> Text -> Maybe Char+findBy p t = S.findBy p (stream t)+{-# INLINE findBy #-} --- | /O(n)/ The 'partition' function takes a predicate and a 'Text',+-- | /O(n)/ The 'partitionBy' 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 #-}+-- > partitionBy p t == (filter p t, filter (not . p) t)+partitionBy :: (Char -> Bool) -> Text -> (Text, Text)+partitionBy p t = (filter p t, filter (not . p) t)+{-# INLINE partitionBy #-} -- | /O(n)/ 'Text' index (subscript) operator, starting from 0. index :: Text -> Int64 -> 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. This function is subject to fusion.-findIndex :: (Char -> Bool) -> Text -> Maybe Int64-findIndex p t = S.findIndex p (stream t)-{-# INLINE findIndex #-}---- | The 'findIndices' function extends 'findIndex', by returning the--- indices of all elements satisfying the predicate, in ascending--- order. This function is subject to fusion.-findIndices :: (Char -> Bool) -> Text -> [Int64]-findIndices p t = S.findIndices p (stream t)-{-# INLINE findIndices #-}---- | /O(n)/ The 'elemIndex' function returns the index of the first--- element in the given 'Text' which is equal to the query element, or--- 'Nothing' if there is no such element. This function is subject to--- fusion.-elemIndex :: Char -> Text -> Maybe Int64-elemIndex c t = S.elemIndex c (stream t)-{-# INLINE elemIndex #-}---- | /O(n)/ The 'elemIndices' function returns the index of every--- element in the given 'Text' which is equal to the query--- element. This function is subject to fusion.-elemIndices :: Char -> Text -> [Int64]-elemIndices c t = S.elemIndices c (stream t)-{-# INLINE elemIndices #-}---- | /O(n*m)/ The 'count' function returns the number of times the+-- | /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 src0- | l == 0 = emptyError "count"- | l == 1 = countChar (head pat) src0- | otherwise = go 0 src0- where- l = length pat- go !n src = search src- where- search s | null s = n- | pat `isPrefixOf` s = go (n+1) (drop l s)- | otherwise = search (tail s)+count pat src+ | null pat = emptyError "count"+ | otherwise = len (indices pat src)+ where len [] = 0+ len (_:xs) = 1 + len xs {-# INLINE [1] count #-} {-# RULES
Data/Text/Lazy/Encoding/Fusion.hs view
@@ -36,6 +36,7 @@ import Data.Text.Encoding.Error import Data.Text.Fusion (Step(..), Stream(..)) import Data.Text.Fusion.Internal (M(..), PairS(..), S(..))+import Data.Text.Fusion.Size import Data.Text.UnsafeChar (unsafeChr8) import Data.Word (Word8) import qualified Data.Text.Encoding.Utf8 as U8@@ -46,31 +47,28 @@ import Control.Exception (assert) import qualified Data.ByteString.Internal as B -unknownLength :: Int-unknownLength = 4- -- | /O(n)/ Convert a lazy 'ByteString' into a 'Stream Char', using -- UTF-8 encoding. streamUtf8 :: OnDecodeError -> ByteString -> Stream Char-streamUtf8 onErr bs0 = Stream next (bs0 :!: empty :!: 0) unknownLength+streamUtf8 onErr bs0 = Stream next (bs0 :*: empty :*: 0) unknownSize where empty = S N N N N {-# INLINE next #-}- next (bs@(Chunk ps _) :!: S N _ _ _ :!: i)+ next (bs@(Chunk ps _) :*: S N _ _ _ :*: i) | i < len && U8.validate1 a =- Yield (unsafeChr8 a) (bs :!: empty :!: i+1)+ Yield (unsafeChr8 a) (bs :*: empty :*: i+1) | i + 1 < len && U8.validate2 a b =- Yield (U8.chr2 a b) (bs :!: empty :!: i+2)+ Yield (U8.chr2 a b) (bs :*: empty :*: i+2) | i + 2 < len && U8.validate3 a b c =- Yield (U8.chr3 a b c) (bs :!: empty :!: i+3)+ Yield (U8.chr3 a b c) (bs :*: empty :*: i+3) | i + 4 < len && U8.validate4 a b c d =- Yield (U8.chr4 a b c d) (bs :!: empty :!: i+4)+ Yield (U8.chr4 a b c d) (bs :*: empty :*: 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@(bs :!: s :!: i) =+ next st@(bs :*: s :*: i) = case s of S (J a) N _ _ | U8.validate1 a -> Yield (unsafeChr8 a) es@@ -81,28 +79,28 @@ S (J a) (J b) (J c) (J d) | U8.validate4 a b c d -> Yield (U8.chr4 a b c d) es _ -> consume st- where es = bs :!: empty :!: i+ where es = bs :*: empty :*: i {-# INLINE consume #-}- consume (bs@(Chunk ps rest) :!: s :!: i)- | i >= B.length ps = consume (rest :!: s :!: 0)+ consume (bs@(Chunk ps rest) :*: s :*: i)+ | i >= B.length ps = consume (rest :*: s :*: 0) | otherwise = case s of- S N _ _ _ -> next (bs :!: S x N N N :!: i+1)- S a N _ _ -> next (bs :!: S a x N N :!: i+1)- S a b N _ -> next (bs :!: S a b x N :!: i+1)- S a b c N -> next (bs :!: S a b c x :!: i+1)+ S N _ _ _ -> next (bs :*: S x N N N :*: i+1)+ S a N _ _ -> next (bs :*: S a x N N :*: i+1)+ S a b N _ -> next (bs :*: S a b x N :*: i+1)+ S a b c N -> next (bs :*: S a b c x :*: i+1) S (J a) b c d -> decodeError "streamUtf8" "UTF-8" onErr (Just a)- (bs :!: S b c d N :!: i+1)+ (bs :*: S b c d N :*: i+1) where x = J (B.unsafeIndex ps i)- consume (Empty :!: S N _ _ _ :!: _) = Done+ consume (Empty :*: S N _ _ _ :*: _) = Done consume st = decodeError "streamUtf8" "UTF-8" onErr Nothing st {-# INLINE [0] streamUtf8 #-} -- | /O(n)/ Convert a 'Stream' 'Word8' to a lazy 'ByteString'. unstreamChunks :: Int -> Stream Word8 -> ByteString-unstreamChunks chunkSize (Stream next s0 len0) = chunk s0 len0+unstreamChunks chunkSize (Stream next s0 len0) = chunk s0 (upperBound 4 len0) where chunk s1 len1 = unsafePerformIO $ do- let len = min (max len1 unknownLength) chunkSize+ let len = min len1 chunkSize mallocByteString len >>= loop len 0 s1 where loop !n !off !s fp = case next s of
Data/Text/Lazy/Fusion.hs view
@@ -18,16 +18,13 @@ , length , unfoldrN , index- , findIndex- , findIndices- , elemIndex- , elemIndices , countChar ) where import Prelude hiding (length) import qualified Data.Text.Fusion.Common as S import Data.Text.Fusion.Internal+import Data.Text.Fusion.Size (isEmpty) import Data.Text.Lazy.Internal import qualified Data.Text.Internal as I import qualified Data.Text.Array as A@@ -39,12 +36,12 @@ -- | /O(n)/ Convert a 'Text' into a 'Stream Char'. stream :: Text -> Stream Char-stream text = Stream next (text :!: 0) 4 -- random HINT+stream text = Stream next (text :*: 0) 4 -- random HINT where- next (Empty :!: _) = Done- next (txt@(Chunk t@(I.Text _ _ len) ts) :!: i)- | i >= len = next (ts :!: 0)- | otherwise = Yield c (txt :!: i+d)+ next (Empty :*: _) = Done+ next (txt@(Chunk t@(I.Text _ _ len) ts) :*: i)+ | i >= len = next (ts :*: 0)+ | otherwise = Yield c (txt :*: i+d) where (c,d) = iter t i {-# INLINE [0] stream #-} @@ -52,8 +49,8 @@ -- chunk size. unstreamChunks :: Int -> Stream Char -> Text unstreamChunks chunkSize (Stream next s0 len0)- | len0 == 0 = Empty- | otherwise = outer s0+ | isEmpty len0 = Empty+ | otherwise = outer s0 where outer s = case next s of Done -> Empty@@ -104,33 +101,6 @@ index :: Stream Char -> Int64 -> 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 Int64-findIndex = S.findIndexI-{-# INLINE [0] findIndex #-}---- | The 'findIndices' function takes a predicate and a stream and--- returns all indices of the elements in the stream--- satisfying the predicate.-findIndices :: (Char -> Bool) -> Stream Char -> [Int64]-findIndices = S.findIndicesI-{-# INLINE [0] findIndices #-}---- | /O(n)/ The 'elemIndex' function returns the index of the first--- element in the given stream which is equal to the query--- element, or 'Nothing' if there is no such element.-elemIndex :: Char -> Stream Char -> Maybe Int64-elemIndex = S.elemIndexI-{-# INLINE [0] elemIndex #-}---- | /O(n)/ The 'elemIndices' function returns the index of every--- element in the given stream which is equal to the query element.-elemIndices :: Char -> Stream Char -> [Int64]-elemIndices = S.elemIndicesI-{-# INLINE [0] elemIndices #-} -- | /O(n)/ The 'count' function returns the number of times the query -- element appears in the given stream.
Data/Text/Lazy/Internal.hs view
@@ -91,6 +91,7 @@ defaultChunkSize :: Int defaultChunkSize = 32 * k - chunkOverhead where k = 1024 `div` sizeOf (undefined :: Word16)+{-# INLINE defaultChunkSize #-} -- | Currently set to 4k, less the memory management overhead. smallChunkSize :: Int
+ Data/Text/Lazy/Search.hs view
@@ -0,0 +1,124 @@+{-# LANGUAGE BangPatterns, ScopedTypeVariables #-}++-- |+-- Module : Data.Text.Lazy.Search+-- Copyright : (c) Bryan O'Sullivan 2009+--+-- License : BSD-style+-- Maintainer : bos@serpentine.com, rtharper@aftereternity.co.uk,+-- duncan@haskell.org+-- Stability : experimental+-- Portability : GHC+--+-- Fast substring search for lazy 'Text', based on work by Boyer,+-- Moore, Horspool, Sunday, and Lundh. Adapted from the strict+-- implementation.++module Data.Text.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 qualified Data.Text as T+import Data.Text.Fusion.Internal (PairS(..))+import Data.Text.Lazy.Internal (Text(..), foldlChunks)+import Data.Bits ((.|.), (.&.))+import Data.Text.UnsafeShift (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 = scanOne (nindex 0) 0 k ks+ | otherwise = scan 0 0 k ks+ where+ scan !g !i x@(T.Text _ _ l) xs+ | i >= m = case xs of+ Empty -> []+ Chunk y ys -> scan g (i-m) y ys+ | lackingHay (i + nlen) x xs = []+ | c == z && candidateMatch 0 = g : scan (g+nlen) (i+nlen) x xs+ | otherwise = scan (g+delta) (i+delta) x xs+ 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 .|. swizzle c) skp'+ where c = A.unsafeIndex xarr (xoff+i)+ skp' | c == z = nlen - fromIntegral g - 2+ | otherwise = skp+ xlast = xlen - 1+ scanOne c i (T.Text oarr ooff olen) os = go 0+ where+ go h | h >= olen = case os of+ Empty -> []+ Chunk y ys -> scanOne c (i+fromIntegral olen) y ys+ | on == c = i + fromIntegral h : go (h+1)+ | otherwise = go (h+1)+ where on = A.unsafeIndex oarr (ooff+h)+ -- | 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++-- | 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/Search.hs view
@@ -0,0 +1,85 @@+{-# LANGUAGE BangPatterns, ScopedTypeVariables #-}++-- |+-- Module : Data.Text.Search+-- Copyright : (c) Bryan O'Sullivan 2009+--+-- License : BSD-style+-- Maintainer : bos@serpentine.com, rtharper@aftereternity.co.uk,+-- duncan@haskell.org+-- 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.Search+ (+ indices+ ) where++import qualified Data.Text.Array as A+import Data.Word (Word64)+import Data.Text.Internal (Text(..))+import Data.Text.Fusion.Internal (PairS(..))+import Data.Bits ((.|.), (.&.))+import Data.Text.UnsafeShift (shiftL)++-- | /O(n+m)/ Find the offsets of all non-overlapping indices of+-- @needle@ within @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@)+ -> [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)+ (mask :: Word64) :*: skip = buildTable 0 0 (nlen-2)+ 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+ nextInPattern = mask .&. swizzle (hindex (i+nlen)) == 0+ scanOne c = loop 0+ where loop !i | i >= hlen = []+ | hindex i == c = i : loop (i+1)+ | otherwise = loop (i+1)+{-# INLINE indices #-}
Data/Text/UnsafeShift.hs view
@@ -45,14 +45,12 @@ {-# 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 #-}
README view
@@ -26,6 +26,12 @@ darcs get http://code.haskell.org/text +Reporting bugs, asking for enhancements+---------------------------------------++http://trac.haskell.org/text/++ Authors -------
+ TODO view
@@ -0,0 +1,6 @@+Normalization.++Collation.++Case conversion lacks locale sensitivity, so cannot handle a few+Turkic and Azeri code points completely correctly.
+ scripts/ApiCompare.hs view
@@ -0,0 +1,24 @@+-- This script compares the strict and lazy Text APIs to ensure that+-- they're reasonably in sync.++{-# LANGUAGE OverloadedStrings #-}++import qualified Data.Set as S+import qualified Data.Text as T+import System.Process++main = do+ let tidy pkg = (S.fromList . filter (T.isInfixOf "::") . T.lines .+ T.replace "GHC.Int.Int64" "Int" .+ T.replace "\n " "" .+ T.replace (T.append (T.pack pkg) ".") "" . T.pack) `fmap`+ readProcess "ghci" [] (":browse " ++ pkg)+ let diff a b = mapM_ (putStrLn . (" "++) . T.unpack) . S.toList $+ S.difference a b+ text <- tidy "Data.Text"+ lazy <- tidy "Data.Text.Lazy"+ putStrLn "In Data.Text:"+ diff text lazy+ putStrLn ""+ putStrLn "In Data.Text.Lazy:"+ diff lazy text
+ scripts/Arsec.hs view
@@ -0,0 +1,49 @@+module Arsec+ (+ comment+ , semi+ , showC+ , unichar+ , unichars+ , module Control.Applicative+ , module Control.Monad+ , module Data.Char+ , module Text.ParserCombinators.Parsec.Char+ , module Text.ParserCombinators.Parsec.Combinator+ , module Text.ParserCombinators.Parsec.Error+ , module Text.ParserCombinators.Parsec.Prim+ ) where++import Control.Monad+import Control.Applicative+import Data.Char+import Numeric+import Text.ParserCombinators.Parsec.Char hiding (lower, upper)+import Text.ParserCombinators.Parsec.Combinator hiding (optional)+import Text.ParserCombinators.Parsec.Error+import Text.ParserCombinators.Parsec.Prim hiding ((<|>), many)++instance Applicative (GenParser s a) where+ pure = return+ (<*>) = ap+ +instance Alternative (GenParser s a) where+ empty = mzero+ (<|>) = mplus++unichar :: Parser Char+unichar = chr . fst . head . readHex <$> many1 hexDigit++unichars :: Parser [Char]+unichars = manyTill (unichar <* spaces) semi++semi :: Parser ()+semi = char ';' *> spaces *> pure ()++comment :: Parser String+comment = (char '#' *> manyTill anyToken (char '\n')) <|> string "\n"++showC :: Char -> String+showC c = "'\\x" ++ d ++ "'"+ where h = showHex (ord c) ""+ d = replicate (4 - length h) '0' ++ h
+ scripts/CaseFolding.hs view
@@ -0,0 +1,42 @@+-- This script processes the following source file:+--+-- http://unicode.org/Public/UNIDATA/CaseFolding.txt++module CaseFolding+ (+ Fold(..)+ , parseCF+ , mapCF+ ) where++import Arsec++data Fold = Fold {+ code :: Char+ , status :: Char+ , mapping :: [Char]+ , name :: String+ } deriving (Eq, Ord, Show)++entries :: Parser [Fold]+entries = many comment *> many (entry <* many comment)+ where+ entry = Fold <$> unichar <* semi+ <*> oneOf "CFST" <* semi+ <*> unichars+ <*> (string "# " *> manyTill anyToken (char '\n'))++parseCF :: FilePath -> IO (Either ParseError [Fold])+parseCF name = parse entries name <$> readFile name++mapCF :: [Fold] -> [String]+mapCF ms = typ ++ (map nice . filter p $ ms) ++ [last]+ where+ typ = ["foldMapping :: forall s. Char -> s -> Step (PairS (PairS s Char) Char) Char"+ ,"{-# INLINE foldMapping #-}"]+ last = "foldMapping c s = Yield (toLower c) (s :!: '\\0' :!: '\\0')"+ nice c = "-- " ++ name c ++ "\n" +++ "foldMapping " ++ showC (code c) ++ " s = Yield " ++ x ++ " (s :!: " ++ y ++ " :!: " ++ z ++ ")"+ where [x,y,z] = (map showC . take 3) (mapping c ++ repeat '\0')+ p f = status f `elem` "CF" &&+ mapping f /= [toLower (code f)]
+ scripts/CaseFolding.txt view
@@ -0,0 +1,1196 @@+# CaseFolding-5.1.0.txt+# Date: 2008-03-03, 21:57:14 GMT [MD]+#+# Unicode Character Database+# Copyright (c) 1991-2008 Unicode, Inc.+# For terms of use, see http://www.unicode.org/terms_of_use.html+# For documentation, see UCD.html+#+# Case Folding Properties+#+# This file is a supplement to the UnicodeData file.+# It provides a case folding mapping generated from the Unicode Character Database.+# If all characters are mapped according to the full mapping below, then+# case differences (according to UnicodeData.txt and SpecialCasing.txt)+# are eliminated.+#+# The data supports both implementations that require simple case foldings+# (where string lengths don't change), and implementations that allow full case folding+# (where string lengths may grow). Note that where they can be supported, the+# full case foldings are superior: for example, they allow "MASSE" and "Maße" to match.+#+# All code points not listed in this file map to themselves.+#+# NOTE: case folding does not preserve normalization formats!+#+# For information on case folding, including how to have case folding +# preserve normalization formats, see Section 3.13 Default Case Algorithms in+# The Unicode Standard, Version 5.0.+#+# ================================================================================+# Format+# ================================================================================+# The entries in this file are in the following machine-readable format:+#+# <code>; <status>; <mapping>; # <name>+#+# The status field is:+# C: common case folding, common mappings shared by both simple and full mappings.+# F: full case folding, mappings that cause strings to grow in length. Multiple characters are separated by spaces.+# S: simple case folding, mappings to single characters where different from F.+# T: special case for uppercase I and dotted uppercase I+# - For non-Turkic languages, this mapping is normally not used.+# - For Turkic languages (tr, az), this mapping can be used instead of the normal mapping for these characters.+# Note that the Turkic mappings do not maintain canonical equivalence without additional processing.+# See the discussions of case mapping in the Unicode Standard for more information.+#+# Usage:+# A. To do a simple case folding, use the mappings with status C + S.+# B. To do a full case folding, use the mappings with status C + F.+#+# The mappings with status T can be used or omitted depending on the desired case-folding+# behavior. (The default option is to exclude them.)+#+# =================================================================+# @missing 0000..10FFFF; <codepoint>+0041; C; 0061; # LATIN CAPITAL LETTER A+0042; C; 0062; # LATIN CAPITAL LETTER B+0043; C; 0063; # LATIN CAPITAL LETTER C+0044; C; 0064; # LATIN CAPITAL LETTER D+0045; C; 0065; # LATIN CAPITAL LETTER E+0046; C; 0066; # LATIN CAPITAL LETTER F+0047; C; 0067; # LATIN CAPITAL LETTER G+0048; C; 0068; # LATIN CAPITAL LETTER H+0049; C; 0069; # LATIN CAPITAL LETTER I+0049; T; 0131; # LATIN CAPITAL LETTER I+004A; C; 006A; # LATIN CAPITAL LETTER J+004B; C; 006B; # LATIN CAPITAL LETTER K+004C; C; 006C; # LATIN CAPITAL LETTER L+004D; C; 006D; # LATIN CAPITAL LETTER M+004E; C; 006E; # LATIN CAPITAL LETTER N+004F; C; 006F; # LATIN CAPITAL LETTER O+0050; C; 0070; # LATIN CAPITAL LETTER P+0051; C; 0071; # LATIN CAPITAL LETTER Q+0052; C; 0072; # LATIN CAPITAL LETTER R+0053; C; 0073; # LATIN CAPITAL LETTER S+0054; C; 0074; # LATIN CAPITAL LETTER T+0055; C; 0075; # LATIN CAPITAL LETTER U+0056; C; 0076; # LATIN CAPITAL LETTER V+0057; C; 0077; # LATIN CAPITAL LETTER W+0058; C; 0078; # LATIN CAPITAL LETTER X+0059; C; 0079; # LATIN CAPITAL LETTER Y+005A; C; 007A; # LATIN CAPITAL LETTER Z+00B5; C; 03BC; # MICRO SIGN+00C0; C; 00E0; # LATIN CAPITAL LETTER A WITH GRAVE+00C1; C; 00E1; # LATIN CAPITAL LETTER A WITH ACUTE+00C2; C; 00E2; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX+00C3; C; 00E3; # LATIN CAPITAL LETTER A WITH TILDE+00C4; C; 00E4; # LATIN CAPITAL LETTER A WITH DIAERESIS+00C5; C; 00E5; # LATIN CAPITAL LETTER A WITH RING ABOVE+00C6; C; 00E6; # LATIN CAPITAL LETTER AE+00C7; C; 00E7; # LATIN CAPITAL LETTER C WITH CEDILLA+00C8; C; 00E8; # LATIN CAPITAL LETTER E WITH GRAVE+00C9; C; 00E9; # LATIN CAPITAL LETTER E WITH ACUTE+00CA; C; 00EA; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX+00CB; C; 00EB; # LATIN CAPITAL LETTER E WITH DIAERESIS+00CC; C; 00EC; # LATIN CAPITAL LETTER I WITH GRAVE+00CD; C; 00ED; # LATIN CAPITAL LETTER I WITH ACUTE+00CE; C; 00EE; # LATIN CAPITAL LETTER I WITH CIRCUMFLEX+00CF; C; 00EF; # LATIN CAPITAL LETTER I WITH DIAERESIS+00D0; C; 00F0; # LATIN CAPITAL LETTER ETH+00D1; C; 00F1; # LATIN CAPITAL LETTER N WITH TILDE+00D2; C; 00F2; # LATIN CAPITAL LETTER O WITH GRAVE+00D3; C; 00F3; # LATIN CAPITAL LETTER O WITH ACUTE+00D4; C; 00F4; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX+00D5; C; 00F5; # LATIN CAPITAL LETTER O WITH TILDE+00D6; C; 00F6; # LATIN CAPITAL LETTER O WITH DIAERESIS+00D8; C; 00F8; # LATIN CAPITAL LETTER O WITH STROKE+00D9; C; 00F9; # LATIN CAPITAL LETTER U WITH GRAVE+00DA; C; 00FA; # LATIN CAPITAL LETTER U WITH ACUTE+00DB; C; 00FB; # LATIN CAPITAL LETTER U WITH CIRCUMFLEX+00DC; C; 00FC; # LATIN CAPITAL LETTER U WITH DIAERESIS+00DD; C; 00FD; # LATIN CAPITAL LETTER Y WITH ACUTE+00DE; C; 00FE; # LATIN CAPITAL LETTER THORN+00DF; F; 0073 0073; # LATIN SMALL LETTER SHARP S+0100; C; 0101; # LATIN CAPITAL LETTER A WITH MACRON+0102; C; 0103; # LATIN CAPITAL LETTER A WITH BREVE+0104; C; 0105; # LATIN CAPITAL LETTER A WITH OGONEK+0106; C; 0107; # LATIN CAPITAL LETTER C WITH ACUTE+0108; C; 0109; # LATIN CAPITAL LETTER C WITH CIRCUMFLEX+010A; C; 010B; # LATIN CAPITAL LETTER C WITH DOT ABOVE+010C; C; 010D; # LATIN CAPITAL LETTER C WITH CARON+010E; C; 010F; # LATIN CAPITAL LETTER D WITH CARON+0110; C; 0111; # LATIN CAPITAL LETTER D WITH STROKE+0112; C; 0113; # LATIN CAPITAL LETTER E WITH MACRON+0114; C; 0115; # LATIN CAPITAL LETTER E WITH BREVE+0116; C; 0117; # LATIN CAPITAL LETTER E WITH DOT ABOVE+0118; C; 0119; # LATIN CAPITAL LETTER E WITH OGONEK+011A; C; 011B; # LATIN CAPITAL LETTER E WITH CARON+011C; C; 011D; # LATIN CAPITAL LETTER G WITH CIRCUMFLEX+011E; C; 011F; # LATIN CAPITAL LETTER G WITH BREVE+0120; C; 0121; # LATIN CAPITAL LETTER G WITH DOT ABOVE+0122; C; 0123; # LATIN CAPITAL LETTER G WITH CEDILLA+0124; C; 0125; # LATIN CAPITAL LETTER H WITH CIRCUMFLEX+0126; C; 0127; # LATIN CAPITAL LETTER H WITH STROKE+0128; C; 0129; # LATIN CAPITAL LETTER I WITH TILDE+012A; C; 012B; # LATIN CAPITAL LETTER I WITH MACRON+012C; C; 012D; # LATIN CAPITAL LETTER I WITH BREVE+012E; C; 012F; # LATIN CAPITAL LETTER I WITH OGONEK+0130; F; 0069 0307; # LATIN CAPITAL LETTER I WITH DOT ABOVE+0130; T; 0069; # LATIN CAPITAL LETTER I WITH DOT ABOVE+0132; C; 0133; # LATIN CAPITAL LIGATURE IJ+0134; C; 0135; # LATIN CAPITAL LETTER J WITH CIRCUMFLEX+0136; C; 0137; # LATIN CAPITAL LETTER K WITH CEDILLA+0139; C; 013A; # LATIN CAPITAL LETTER L WITH ACUTE+013B; C; 013C; # LATIN CAPITAL LETTER L WITH CEDILLA+013D; C; 013E; # LATIN CAPITAL LETTER L WITH CARON+013F; C; 0140; # LATIN CAPITAL LETTER L WITH MIDDLE DOT+0141; C; 0142; # LATIN CAPITAL LETTER L WITH STROKE+0143; C; 0144; # LATIN CAPITAL LETTER N WITH ACUTE+0145; C; 0146; # LATIN CAPITAL LETTER N WITH CEDILLA+0147; C; 0148; # LATIN CAPITAL LETTER N WITH CARON+0149; F; 02BC 006E; # LATIN SMALL LETTER N PRECEDED BY APOSTROPHE+014A; C; 014B; # LATIN CAPITAL LETTER ENG+014C; C; 014D; # LATIN CAPITAL LETTER O WITH MACRON+014E; C; 014F; # LATIN CAPITAL LETTER O WITH BREVE+0150; C; 0151; # LATIN CAPITAL LETTER O WITH DOUBLE ACUTE+0152; C; 0153; # LATIN CAPITAL LIGATURE OE+0154; C; 0155; # LATIN CAPITAL LETTER R WITH ACUTE+0156; C; 0157; # LATIN CAPITAL LETTER R WITH CEDILLA+0158; C; 0159; # LATIN CAPITAL LETTER R WITH CARON+015A; C; 015B; # LATIN CAPITAL LETTER S WITH ACUTE+015C; C; 015D; # LATIN CAPITAL LETTER S WITH CIRCUMFLEX+015E; C; 015F; # LATIN CAPITAL LETTER S WITH CEDILLA+0160; C; 0161; # LATIN CAPITAL LETTER S WITH CARON+0162; C; 0163; # LATIN CAPITAL LETTER T WITH CEDILLA+0164; C; 0165; # LATIN CAPITAL LETTER T WITH CARON+0166; C; 0167; # LATIN CAPITAL LETTER T WITH STROKE+0168; C; 0169; # LATIN CAPITAL LETTER U WITH TILDE+016A; C; 016B; # LATIN CAPITAL LETTER U WITH MACRON+016C; C; 016D; # LATIN CAPITAL LETTER U WITH BREVE+016E; C; 016F; # LATIN CAPITAL LETTER U WITH RING ABOVE+0170; C; 0171; # LATIN CAPITAL LETTER U WITH DOUBLE ACUTE+0172; C; 0173; # LATIN CAPITAL LETTER U WITH OGONEK+0174; C; 0175; # LATIN CAPITAL LETTER W WITH CIRCUMFLEX+0176; C; 0177; # LATIN CAPITAL LETTER Y WITH CIRCUMFLEX+0178; C; 00FF; # LATIN CAPITAL LETTER Y WITH DIAERESIS+0179; C; 017A; # LATIN CAPITAL LETTER Z WITH ACUTE+017B; C; 017C; # LATIN CAPITAL LETTER Z WITH DOT ABOVE+017D; C; 017E; # LATIN CAPITAL LETTER Z WITH CARON+017F; C; 0073; # LATIN SMALL LETTER LONG S+0181; C; 0253; # LATIN CAPITAL LETTER B WITH HOOK+0182; C; 0183; # LATIN CAPITAL LETTER B WITH TOPBAR+0184; C; 0185; # LATIN CAPITAL LETTER TONE SIX+0186; C; 0254; # LATIN CAPITAL LETTER OPEN O+0187; C; 0188; # LATIN CAPITAL LETTER C WITH HOOK+0189; C; 0256; # LATIN CAPITAL LETTER AFRICAN D+018A; C; 0257; # LATIN CAPITAL LETTER D WITH HOOK+018B; C; 018C; # LATIN CAPITAL LETTER D WITH TOPBAR+018E; C; 01DD; # LATIN CAPITAL LETTER REVERSED E+018F; C; 0259; # LATIN CAPITAL LETTER SCHWA+0190; C; 025B; # LATIN CAPITAL LETTER OPEN E+0191; C; 0192; # LATIN CAPITAL LETTER F WITH HOOK+0193; C; 0260; # LATIN CAPITAL LETTER G WITH HOOK+0194; C; 0263; # LATIN CAPITAL LETTER GAMMA+0196; C; 0269; # LATIN CAPITAL LETTER IOTA+0197; C; 0268; # LATIN CAPITAL LETTER I WITH STROKE+0198; C; 0199; # LATIN CAPITAL LETTER K WITH HOOK+019C; C; 026F; # LATIN CAPITAL LETTER TURNED M+019D; C; 0272; # LATIN CAPITAL LETTER N WITH LEFT HOOK+019F; C; 0275; # LATIN CAPITAL LETTER O WITH MIDDLE TILDE+01A0; C; 01A1; # LATIN CAPITAL LETTER O WITH HORN+01A2; C; 01A3; # LATIN CAPITAL LETTER OI+01A4; C; 01A5; # LATIN CAPITAL LETTER P WITH HOOK+01A6; C; 0280; # LATIN LETTER YR+01A7; C; 01A8; # LATIN CAPITAL LETTER TONE TWO+01A9; C; 0283; # LATIN CAPITAL LETTER ESH+01AC; C; 01AD; # LATIN CAPITAL LETTER T WITH HOOK+01AE; C; 0288; # LATIN CAPITAL LETTER T WITH RETROFLEX HOOK+01AF; C; 01B0; # LATIN CAPITAL LETTER U WITH HORN+01B1; C; 028A; # LATIN CAPITAL LETTER UPSILON+01B2; C; 028B; # LATIN CAPITAL LETTER V WITH HOOK+01B3; C; 01B4; # LATIN CAPITAL LETTER Y WITH HOOK+01B5; C; 01B6; # LATIN CAPITAL LETTER Z WITH STROKE+01B7; C; 0292; # LATIN CAPITAL LETTER EZH+01B8; C; 01B9; # LATIN CAPITAL LETTER EZH REVERSED+01BC; C; 01BD; # LATIN CAPITAL LETTER TONE FIVE+01C4; C; 01C6; # LATIN CAPITAL LETTER DZ WITH CARON+01C5; C; 01C6; # LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON+01C7; C; 01C9; # LATIN CAPITAL LETTER LJ+01C8; C; 01C9; # LATIN CAPITAL LETTER L WITH SMALL LETTER J+01CA; C; 01CC; # LATIN CAPITAL LETTER NJ+01CB; C; 01CC; # LATIN CAPITAL LETTER N WITH SMALL LETTER J+01CD; C; 01CE; # LATIN CAPITAL LETTER A WITH CARON+01CF; C; 01D0; # LATIN CAPITAL LETTER I WITH CARON+01D1; C; 01D2; # LATIN CAPITAL LETTER O WITH CARON+01D3; C; 01D4; # LATIN CAPITAL LETTER U WITH CARON+01D5; C; 01D6; # LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON+01D7; C; 01D8; # LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE+01D9; C; 01DA; # LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON+01DB; C; 01DC; # LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE+01DE; C; 01DF; # LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON+01E0; C; 01E1; # LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON+01E2; C; 01E3; # LATIN CAPITAL LETTER AE WITH MACRON+01E4; C; 01E5; # LATIN CAPITAL LETTER G WITH STROKE+01E6; C; 01E7; # LATIN CAPITAL LETTER G WITH CARON+01E8; C; 01E9; # LATIN CAPITAL LETTER K WITH CARON+01EA; C; 01EB; # LATIN CAPITAL LETTER O WITH OGONEK+01EC; C; 01ED; # LATIN CAPITAL LETTER O WITH OGONEK AND MACRON+01EE; C; 01EF; # LATIN CAPITAL LETTER EZH WITH CARON+01F0; F; 006A 030C; # LATIN SMALL LETTER J WITH CARON+01F1; C; 01F3; # LATIN CAPITAL LETTER DZ+01F2; C; 01F3; # LATIN CAPITAL LETTER D WITH SMALL LETTER Z+01F4; C; 01F5; # LATIN CAPITAL LETTER G WITH ACUTE+01F6; C; 0195; # LATIN CAPITAL LETTER HWAIR+01F7; C; 01BF; # LATIN CAPITAL LETTER WYNN+01F8; C; 01F9; # LATIN CAPITAL LETTER N WITH GRAVE+01FA; C; 01FB; # LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE+01FC; C; 01FD; # LATIN CAPITAL LETTER AE WITH ACUTE+01FE; C; 01FF; # LATIN CAPITAL LETTER O WITH STROKE AND ACUTE+0200; C; 0201; # LATIN CAPITAL LETTER A WITH DOUBLE GRAVE+0202; C; 0203; # LATIN CAPITAL LETTER A WITH INVERTED BREVE+0204; C; 0205; # LATIN CAPITAL LETTER E WITH DOUBLE GRAVE+0206; C; 0207; # LATIN CAPITAL LETTER E WITH INVERTED BREVE+0208; C; 0209; # LATIN CAPITAL LETTER I WITH DOUBLE GRAVE+020A; C; 020B; # LATIN CAPITAL LETTER I WITH INVERTED BREVE+020C; C; 020D; # LATIN CAPITAL LETTER O WITH DOUBLE GRAVE+020E; C; 020F; # LATIN CAPITAL LETTER O WITH INVERTED BREVE+0210; C; 0211; # LATIN CAPITAL LETTER R WITH DOUBLE GRAVE+0212; C; 0213; # LATIN CAPITAL LETTER R WITH INVERTED BREVE+0214; C; 0215; # LATIN CAPITAL LETTER U WITH DOUBLE GRAVE+0216; C; 0217; # LATIN CAPITAL LETTER U WITH INVERTED BREVE+0218; C; 0219; # LATIN CAPITAL LETTER S WITH COMMA BELOW+021A; C; 021B; # LATIN CAPITAL LETTER T WITH COMMA BELOW+021C; C; 021D; # LATIN CAPITAL LETTER YOGH+021E; C; 021F; # LATIN CAPITAL LETTER H WITH CARON+0220; C; 019E; # LATIN CAPITAL LETTER N WITH LONG RIGHT LEG+0222; C; 0223; # LATIN CAPITAL LETTER OU+0224; C; 0225; # LATIN CAPITAL LETTER Z WITH HOOK+0226; C; 0227; # LATIN CAPITAL LETTER A WITH DOT ABOVE+0228; C; 0229; # LATIN CAPITAL LETTER E WITH CEDILLA+022A; C; 022B; # LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON+022C; C; 022D; # LATIN CAPITAL LETTER O WITH TILDE AND MACRON+022E; C; 022F; # LATIN CAPITAL LETTER O WITH DOT ABOVE+0230; C; 0231; # LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON+0232; C; 0233; # LATIN CAPITAL LETTER Y WITH MACRON+023A; C; 2C65; # LATIN CAPITAL LETTER A WITH STROKE+023B; C; 023C; # LATIN CAPITAL LETTER C WITH STROKE+023D; C; 019A; # LATIN CAPITAL LETTER L WITH BAR+023E; C; 2C66; # LATIN CAPITAL LETTER T WITH DIAGONAL STROKE+0241; C; 0242; # LATIN CAPITAL LETTER GLOTTAL STOP+0243; C; 0180; # LATIN CAPITAL LETTER B WITH STROKE+0244; C; 0289; # LATIN CAPITAL LETTER U BAR+0245; C; 028C; # LATIN CAPITAL LETTER TURNED V+0246; C; 0247; # LATIN CAPITAL LETTER E WITH STROKE+0248; C; 0249; # LATIN CAPITAL LETTER J WITH STROKE+024A; C; 024B; # LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL+024C; C; 024D; # LATIN CAPITAL LETTER R WITH STROKE+024E; C; 024F; # LATIN CAPITAL LETTER Y WITH STROKE+0345; C; 03B9; # COMBINING GREEK YPOGEGRAMMENI+0370; C; 0371; # GREEK CAPITAL LETTER HETA+0372; C; 0373; # GREEK CAPITAL LETTER ARCHAIC SAMPI+0376; C; 0377; # GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA+0386; C; 03AC; # GREEK CAPITAL LETTER ALPHA WITH TONOS+0388; C; 03AD; # GREEK CAPITAL LETTER EPSILON WITH TONOS+0389; C; 03AE; # GREEK CAPITAL LETTER ETA WITH TONOS+038A; C; 03AF; # GREEK CAPITAL LETTER IOTA WITH TONOS+038C; C; 03CC; # GREEK CAPITAL LETTER OMICRON WITH TONOS+038E; C; 03CD; # GREEK CAPITAL LETTER UPSILON WITH TONOS+038F; C; 03CE; # GREEK CAPITAL LETTER OMEGA WITH TONOS+0390; F; 03B9 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS+0391; C; 03B1; # GREEK CAPITAL LETTER ALPHA+0392; C; 03B2; # GREEK CAPITAL LETTER BETA+0393; C; 03B3; # GREEK CAPITAL LETTER GAMMA+0394; C; 03B4; # GREEK CAPITAL LETTER DELTA+0395; C; 03B5; # GREEK CAPITAL LETTER EPSILON+0396; C; 03B6; # GREEK CAPITAL LETTER ZETA+0397; C; 03B7; # GREEK CAPITAL LETTER ETA+0398; C; 03B8; # GREEK CAPITAL LETTER THETA+0399; C; 03B9; # GREEK CAPITAL LETTER IOTA+039A; C; 03BA; # GREEK CAPITAL LETTER KAPPA+039B; C; 03BB; # GREEK CAPITAL LETTER LAMDA+039C; C; 03BC; # GREEK CAPITAL LETTER MU+039D; C; 03BD; # GREEK CAPITAL LETTER NU+039E; C; 03BE; # GREEK CAPITAL LETTER XI+039F; C; 03BF; # GREEK CAPITAL LETTER OMICRON+03A0; C; 03C0; # GREEK CAPITAL LETTER PI+03A1; C; 03C1; # GREEK CAPITAL LETTER RHO+03A3; C; 03C3; # GREEK CAPITAL LETTER SIGMA+03A4; C; 03C4; # GREEK CAPITAL LETTER TAU+03A5; C; 03C5; # GREEK CAPITAL LETTER UPSILON+03A6; C; 03C6; # GREEK CAPITAL LETTER PHI+03A7; C; 03C7; # GREEK CAPITAL LETTER CHI+03A8; C; 03C8; # GREEK CAPITAL LETTER PSI+03A9; C; 03C9; # GREEK CAPITAL LETTER OMEGA+03AA; C; 03CA; # GREEK CAPITAL LETTER IOTA WITH DIALYTIKA+03AB; C; 03CB; # GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA+03B0; F; 03C5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS+03C2; C; 03C3; # GREEK SMALL LETTER FINAL SIGMA+03CF; C; 03D7; # GREEK CAPITAL KAI SYMBOL+03D0; C; 03B2; # GREEK BETA SYMBOL+03D1; C; 03B8; # GREEK THETA SYMBOL+03D5; C; 03C6; # GREEK PHI SYMBOL+03D6; C; 03C0; # GREEK PI SYMBOL+03D8; C; 03D9; # GREEK LETTER ARCHAIC KOPPA+03DA; C; 03DB; # GREEK LETTER STIGMA+03DC; C; 03DD; # GREEK LETTER DIGAMMA+03DE; C; 03DF; # GREEK LETTER KOPPA+03E0; C; 03E1; # GREEK LETTER SAMPI+03E2; C; 03E3; # COPTIC CAPITAL LETTER SHEI+03E4; C; 03E5; # COPTIC CAPITAL LETTER FEI+03E6; C; 03E7; # COPTIC CAPITAL LETTER KHEI+03E8; C; 03E9; # COPTIC CAPITAL LETTER HORI+03EA; C; 03EB; # COPTIC CAPITAL LETTER GANGIA+03EC; C; 03ED; # COPTIC CAPITAL LETTER SHIMA+03EE; C; 03EF; # COPTIC CAPITAL LETTER DEI+03F0; C; 03BA; # GREEK KAPPA SYMBOL+03F1; C; 03C1; # GREEK RHO SYMBOL+03F4; C; 03B8; # GREEK CAPITAL THETA SYMBOL+03F5; C; 03B5; # GREEK LUNATE EPSILON SYMBOL+03F7; C; 03F8; # GREEK CAPITAL LETTER SHO+03F9; C; 03F2; # GREEK CAPITAL LUNATE SIGMA SYMBOL+03FA; C; 03FB; # GREEK CAPITAL LETTER SAN+03FD; C; 037B; # GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL+03FE; C; 037C; # GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL+03FF; C; 037D; # GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL+0400; C; 0450; # CYRILLIC CAPITAL LETTER IE WITH GRAVE+0401; C; 0451; # CYRILLIC CAPITAL LETTER IO+0402; C; 0452; # CYRILLIC CAPITAL LETTER DJE+0403; C; 0453; # CYRILLIC CAPITAL LETTER GJE+0404; C; 0454; # CYRILLIC CAPITAL LETTER UKRAINIAN IE+0405; C; 0455; # CYRILLIC CAPITAL LETTER DZE+0406; C; 0456; # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I+0407; C; 0457; # CYRILLIC CAPITAL LETTER YI+0408; C; 0458; # CYRILLIC CAPITAL LETTER JE+0409; C; 0459; # CYRILLIC CAPITAL LETTER LJE+040A; C; 045A; # CYRILLIC CAPITAL LETTER NJE+040B; C; 045B; # CYRILLIC CAPITAL LETTER TSHE+040C; C; 045C; # CYRILLIC CAPITAL LETTER KJE+040D; C; 045D; # CYRILLIC CAPITAL LETTER I WITH GRAVE+040E; C; 045E; # CYRILLIC CAPITAL LETTER SHORT U+040F; C; 045F; # CYRILLIC CAPITAL LETTER DZHE+0410; C; 0430; # CYRILLIC CAPITAL LETTER A+0411; C; 0431; # CYRILLIC CAPITAL LETTER BE+0412; C; 0432; # CYRILLIC CAPITAL LETTER VE+0413; C; 0433; # CYRILLIC CAPITAL LETTER GHE+0414; C; 0434; # CYRILLIC CAPITAL LETTER DE+0415; C; 0435; # CYRILLIC CAPITAL LETTER IE+0416; C; 0436; # CYRILLIC CAPITAL LETTER ZHE+0417; C; 0437; # CYRILLIC CAPITAL LETTER ZE+0418; C; 0438; # CYRILLIC CAPITAL LETTER I+0419; C; 0439; # CYRILLIC CAPITAL LETTER SHORT I+041A; C; 043A; # CYRILLIC CAPITAL LETTER KA+041B; C; 043B; # CYRILLIC CAPITAL LETTER EL+041C; C; 043C; # CYRILLIC CAPITAL LETTER EM+041D; C; 043D; # CYRILLIC CAPITAL LETTER EN+041E; C; 043E; # CYRILLIC CAPITAL LETTER O+041F; C; 043F; # CYRILLIC CAPITAL LETTER PE+0420; C; 0440; # CYRILLIC CAPITAL LETTER ER+0421; C; 0441; # CYRILLIC CAPITAL LETTER ES+0422; C; 0442; # CYRILLIC CAPITAL LETTER TE+0423; C; 0443; # CYRILLIC CAPITAL LETTER U+0424; C; 0444; # CYRILLIC CAPITAL LETTER EF+0425; C; 0445; # CYRILLIC CAPITAL LETTER HA+0426; C; 0446; # CYRILLIC CAPITAL LETTER TSE+0427; C; 0447; # CYRILLIC CAPITAL LETTER CHE+0428; C; 0448; # CYRILLIC CAPITAL LETTER SHA+0429; C; 0449; # CYRILLIC CAPITAL LETTER SHCHA+042A; C; 044A; # CYRILLIC CAPITAL LETTER HARD SIGN+042B; C; 044B; # CYRILLIC CAPITAL LETTER YERU+042C; C; 044C; # CYRILLIC CAPITAL LETTER SOFT SIGN+042D; C; 044D; # CYRILLIC CAPITAL LETTER E+042E; C; 044E; # CYRILLIC CAPITAL LETTER YU+042F; C; 044F; # CYRILLIC CAPITAL LETTER YA+0460; C; 0461; # CYRILLIC CAPITAL LETTER OMEGA+0462; C; 0463; # CYRILLIC CAPITAL LETTER YAT+0464; C; 0465; # CYRILLIC CAPITAL LETTER IOTIFIED E+0466; C; 0467; # CYRILLIC CAPITAL LETTER LITTLE YUS+0468; C; 0469; # CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS+046A; C; 046B; # CYRILLIC CAPITAL LETTER BIG YUS+046C; C; 046D; # CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS+046E; C; 046F; # CYRILLIC CAPITAL LETTER KSI+0470; C; 0471; # CYRILLIC CAPITAL LETTER PSI+0472; C; 0473; # CYRILLIC CAPITAL LETTER FITA+0474; C; 0475; # CYRILLIC CAPITAL LETTER IZHITSA+0476; C; 0477; # CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT+0478; C; 0479; # CYRILLIC CAPITAL LETTER UK+047A; C; 047B; # CYRILLIC CAPITAL LETTER ROUND OMEGA+047C; C; 047D; # CYRILLIC CAPITAL LETTER OMEGA WITH TITLO+047E; C; 047F; # CYRILLIC CAPITAL LETTER OT+0480; C; 0481; # CYRILLIC CAPITAL LETTER KOPPA+048A; C; 048B; # CYRILLIC CAPITAL LETTER SHORT I WITH TAIL+048C; C; 048D; # CYRILLIC CAPITAL LETTER SEMISOFT SIGN+048E; C; 048F; # CYRILLIC CAPITAL LETTER ER WITH TICK+0490; C; 0491; # CYRILLIC CAPITAL LETTER GHE WITH UPTURN+0492; C; 0493; # CYRILLIC CAPITAL LETTER GHE WITH STROKE+0494; C; 0495; # CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK+0496; C; 0497; # CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER+0498; C; 0499; # CYRILLIC CAPITAL LETTER ZE WITH DESCENDER+049A; C; 049B; # CYRILLIC CAPITAL LETTER KA WITH DESCENDER+049C; C; 049D; # CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE+049E; C; 049F; # CYRILLIC CAPITAL LETTER KA WITH STROKE+04A0; C; 04A1; # CYRILLIC CAPITAL LETTER BASHKIR KA+04A2; C; 04A3; # CYRILLIC CAPITAL LETTER EN WITH DESCENDER+04A4; C; 04A5; # CYRILLIC CAPITAL LIGATURE EN GHE+04A6; C; 04A7; # CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK+04A8; C; 04A9; # CYRILLIC CAPITAL LETTER ABKHASIAN HA+04AA; C; 04AB; # CYRILLIC CAPITAL LETTER ES WITH DESCENDER+04AC; C; 04AD; # CYRILLIC CAPITAL LETTER TE WITH DESCENDER+04AE; C; 04AF; # CYRILLIC CAPITAL LETTER STRAIGHT U+04B0; C; 04B1; # CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE+04B2; C; 04B3; # CYRILLIC CAPITAL LETTER HA WITH DESCENDER+04B4; C; 04B5; # CYRILLIC CAPITAL LIGATURE TE TSE+04B6; C; 04B7; # CYRILLIC CAPITAL LETTER CHE WITH DESCENDER+04B8; C; 04B9; # CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE+04BA; C; 04BB; # CYRILLIC CAPITAL LETTER SHHA+04BC; C; 04BD; # CYRILLIC CAPITAL LETTER ABKHASIAN CHE+04BE; C; 04BF; # CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER+04C0; C; 04CF; # CYRILLIC LETTER PALOCHKA+04C1; C; 04C2; # CYRILLIC CAPITAL LETTER ZHE WITH BREVE+04C3; C; 04C4; # CYRILLIC CAPITAL LETTER KA WITH HOOK+04C5; C; 04C6; # CYRILLIC CAPITAL LETTER EL WITH TAIL+04C7; C; 04C8; # CYRILLIC CAPITAL LETTER EN WITH HOOK+04C9; C; 04CA; # CYRILLIC CAPITAL LETTER EN WITH TAIL+04CB; C; 04CC; # CYRILLIC CAPITAL LETTER KHAKASSIAN CHE+04CD; C; 04CE; # CYRILLIC CAPITAL LETTER EM WITH TAIL+04D0; C; 04D1; # CYRILLIC CAPITAL LETTER A WITH BREVE+04D2; C; 04D3; # CYRILLIC CAPITAL LETTER A WITH DIAERESIS+04D4; C; 04D5; # CYRILLIC CAPITAL LIGATURE A IE+04D6; C; 04D7; # CYRILLIC CAPITAL LETTER IE WITH BREVE+04D8; C; 04D9; # CYRILLIC CAPITAL LETTER SCHWA+04DA; C; 04DB; # CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS+04DC; C; 04DD; # CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS+04DE; C; 04DF; # CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS+04E0; C; 04E1; # CYRILLIC CAPITAL LETTER ABKHASIAN DZE+04E2; C; 04E3; # CYRILLIC CAPITAL LETTER I WITH MACRON+04E4; C; 04E5; # CYRILLIC CAPITAL LETTER I WITH DIAERESIS+04E6; C; 04E7; # CYRILLIC CAPITAL LETTER O WITH DIAERESIS+04E8; C; 04E9; # CYRILLIC CAPITAL LETTER BARRED O+04EA; C; 04EB; # CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS+04EC; C; 04ED; # CYRILLIC CAPITAL LETTER E WITH DIAERESIS+04EE; C; 04EF; # CYRILLIC CAPITAL LETTER U WITH MACRON+04F0; C; 04F1; # CYRILLIC CAPITAL LETTER U WITH DIAERESIS+04F2; C; 04F3; # CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE+04F4; C; 04F5; # CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS+04F6; C; 04F7; # CYRILLIC CAPITAL LETTER GHE WITH DESCENDER+04F8; C; 04F9; # CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS+04FA; C; 04FB; # CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK+04FC; C; 04FD; # CYRILLIC CAPITAL LETTER HA WITH HOOK+04FE; C; 04FF; # CYRILLIC CAPITAL LETTER HA WITH STROKE+0500; C; 0501; # CYRILLIC CAPITAL LETTER KOMI DE+0502; C; 0503; # CYRILLIC CAPITAL LETTER KOMI DJE+0504; C; 0505; # CYRILLIC CAPITAL LETTER KOMI ZJE+0506; C; 0507; # CYRILLIC CAPITAL LETTER KOMI DZJE+0508; C; 0509; # CYRILLIC CAPITAL LETTER KOMI LJE+050A; C; 050B; # CYRILLIC CAPITAL LETTER KOMI NJE+050C; C; 050D; # CYRILLIC CAPITAL LETTER KOMI SJE+050E; C; 050F; # CYRILLIC CAPITAL LETTER KOMI TJE+0510; C; 0511; # CYRILLIC CAPITAL LETTER REVERSED ZE+0512; C; 0513; # CYRILLIC CAPITAL LETTER EL WITH HOOK+0514; C; 0515; # CYRILLIC CAPITAL LETTER LHA+0516; C; 0517; # CYRILLIC CAPITAL LETTER RHA+0518; C; 0519; # CYRILLIC CAPITAL LETTER YAE+051A; C; 051B; # CYRILLIC CAPITAL LETTER QA+051C; C; 051D; # CYRILLIC CAPITAL LETTER WE+051E; C; 051F; # CYRILLIC CAPITAL LETTER ALEUT KA+0520; C; 0521; # CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK+0522; C; 0523; # CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK+0531; C; 0561; # ARMENIAN CAPITAL LETTER AYB+0532; C; 0562; # ARMENIAN CAPITAL LETTER BEN+0533; C; 0563; # ARMENIAN CAPITAL LETTER GIM+0534; C; 0564; # ARMENIAN CAPITAL LETTER DA+0535; C; 0565; # ARMENIAN CAPITAL LETTER ECH+0536; C; 0566; # ARMENIAN CAPITAL LETTER ZA+0537; C; 0567; # ARMENIAN CAPITAL LETTER EH+0538; C; 0568; # ARMENIAN CAPITAL LETTER ET+0539; C; 0569; # ARMENIAN CAPITAL LETTER TO+053A; C; 056A; # ARMENIAN CAPITAL LETTER ZHE+053B; C; 056B; # ARMENIAN CAPITAL LETTER INI+053C; C; 056C; # ARMENIAN CAPITAL LETTER LIWN+053D; C; 056D; # ARMENIAN CAPITAL LETTER XEH+053E; C; 056E; # ARMENIAN CAPITAL LETTER CA+053F; C; 056F; # ARMENIAN CAPITAL LETTER KEN+0540; C; 0570; # ARMENIAN CAPITAL LETTER HO+0541; C; 0571; # ARMENIAN CAPITAL LETTER JA+0542; C; 0572; # ARMENIAN CAPITAL LETTER GHAD+0543; C; 0573; # ARMENIAN CAPITAL LETTER CHEH+0544; C; 0574; # ARMENIAN CAPITAL LETTER MEN+0545; C; 0575; # ARMENIAN CAPITAL LETTER YI+0546; C; 0576; # ARMENIAN CAPITAL LETTER NOW+0547; C; 0577; # ARMENIAN CAPITAL LETTER SHA+0548; C; 0578; # ARMENIAN CAPITAL LETTER VO+0549; C; 0579; # ARMENIAN CAPITAL LETTER CHA+054A; C; 057A; # ARMENIAN CAPITAL LETTER PEH+054B; C; 057B; # ARMENIAN CAPITAL LETTER JHEH+054C; C; 057C; # ARMENIAN CAPITAL LETTER RA+054D; C; 057D; # ARMENIAN CAPITAL LETTER SEH+054E; C; 057E; # ARMENIAN CAPITAL LETTER VEW+054F; C; 057F; # ARMENIAN CAPITAL LETTER TIWN+0550; C; 0580; # ARMENIAN CAPITAL LETTER REH+0551; C; 0581; # ARMENIAN CAPITAL LETTER CO+0552; C; 0582; # ARMENIAN CAPITAL LETTER YIWN+0553; C; 0583; # ARMENIAN CAPITAL LETTER PIWR+0554; C; 0584; # ARMENIAN CAPITAL LETTER KEH+0555; C; 0585; # ARMENIAN CAPITAL LETTER OH+0556; C; 0586; # ARMENIAN CAPITAL LETTER FEH+0587; F; 0565 0582; # ARMENIAN SMALL LIGATURE ECH YIWN+10A0; C; 2D00; # GEORGIAN CAPITAL LETTER AN+10A1; C; 2D01; # GEORGIAN CAPITAL LETTER BAN+10A2; C; 2D02; # GEORGIAN CAPITAL LETTER GAN+10A3; C; 2D03; # GEORGIAN CAPITAL LETTER DON+10A4; C; 2D04; # GEORGIAN CAPITAL LETTER EN+10A5; C; 2D05; # GEORGIAN CAPITAL LETTER VIN+10A6; C; 2D06; # GEORGIAN CAPITAL LETTER ZEN+10A7; C; 2D07; # GEORGIAN CAPITAL LETTER TAN+10A8; C; 2D08; # GEORGIAN CAPITAL LETTER IN+10A9; C; 2D09; # GEORGIAN CAPITAL LETTER KAN+10AA; C; 2D0A; # GEORGIAN CAPITAL LETTER LAS+10AB; C; 2D0B; # GEORGIAN CAPITAL LETTER MAN+10AC; C; 2D0C; # GEORGIAN CAPITAL LETTER NAR+10AD; C; 2D0D; # GEORGIAN CAPITAL LETTER ON+10AE; C; 2D0E; # GEORGIAN CAPITAL LETTER PAR+10AF; C; 2D0F; # GEORGIAN CAPITAL LETTER ZHAR+10B0; C; 2D10; # GEORGIAN CAPITAL LETTER RAE+10B1; C; 2D11; # GEORGIAN CAPITAL LETTER SAN+10B2; C; 2D12; # GEORGIAN CAPITAL LETTER TAR+10B3; C; 2D13; # GEORGIAN CAPITAL LETTER UN+10B4; C; 2D14; # GEORGIAN CAPITAL LETTER PHAR+10B5; C; 2D15; # GEORGIAN CAPITAL LETTER KHAR+10B6; C; 2D16; # GEORGIAN CAPITAL LETTER GHAN+10B7; C; 2D17; # GEORGIAN CAPITAL LETTER QAR+10B8; C; 2D18; # GEORGIAN CAPITAL LETTER SHIN+10B9; C; 2D19; # GEORGIAN CAPITAL LETTER CHIN+10BA; C; 2D1A; # GEORGIAN CAPITAL LETTER CAN+10BB; C; 2D1B; # GEORGIAN CAPITAL LETTER JIL+10BC; C; 2D1C; # GEORGIAN CAPITAL LETTER CIL+10BD; C; 2D1D; # GEORGIAN CAPITAL LETTER CHAR+10BE; C; 2D1E; # GEORGIAN CAPITAL LETTER XAN+10BF; C; 2D1F; # GEORGIAN CAPITAL LETTER JHAN+10C0; C; 2D20; # GEORGIAN CAPITAL LETTER HAE+10C1; C; 2D21; # GEORGIAN CAPITAL LETTER HE+10C2; C; 2D22; # GEORGIAN CAPITAL LETTER HIE+10C3; C; 2D23; # GEORGIAN CAPITAL LETTER WE+10C4; C; 2D24; # GEORGIAN CAPITAL LETTER HAR+10C5; C; 2D25; # GEORGIAN CAPITAL LETTER HOE+1E00; C; 1E01; # LATIN CAPITAL LETTER A WITH RING BELOW+1E02; C; 1E03; # LATIN CAPITAL LETTER B WITH DOT ABOVE+1E04; C; 1E05; # LATIN CAPITAL LETTER B WITH DOT BELOW+1E06; C; 1E07; # LATIN CAPITAL LETTER B WITH LINE BELOW+1E08; C; 1E09; # LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE+1E0A; C; 1E0B; # LATIN CAPITAL LETTER D WITH DOT ABOVE+1E0C; C; 1E0D; # LATIN CAPITAL LETTER D WITH DOT BELOW+1E0E; C; 1E0F; # LATIN CAPITAL LETTER D WITH LINE BELOW+1E10; C; 1E11; # LATIN CAPITAL LETTER D WITH CEDILLA+1E12; C; 1E13; # LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW+1E14; C; 1E15; # LATIN CAPITAL LETTER E WITH MACRON AND GRAVE+1E16; C; 1E17; # LATIN CAPITAL LETTER E WITH MACRON AND ACUTE+1E18; C; 1E19; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW+1E1A; C; 1E1B; # LATIN CAPITAL LETTER E WITH TILDE BELOW+1E1C; C; 1E1D; # LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE+1E1E; C; 1E1F; # LATIN CAPITAL LETTER F WITH DOT ABOVE+1E20; C; 1E21; # LATIN CAPITAL LETTER G WITH MACRON+1E22; C; 1E23; # LATIN CAPITAL LETTER H WITH DOT ABOVE+1E24; C; 1E25; # LATIN CAPITAL LETTER H WITH DOT BELOW+1E26; C; 1E27; # LATIN CAPITAL LETTER H WITH DIAERESIS+1E28; C; 1E29; # LATIN CAPITAL LETTER H WITH CEDILLA+1E2A; C; 1E2B; # LATIN CAPITAL LETTER H WITH BREVE BELOW+1E2C; C; 1E2D; # LATIN CAPITAL LETTER I WITH TILDE BELOW+1E2E; C; 1E2F; # LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE+1E30; C; 1E31; # LATIN CAPITAL LETTER K WITH ACUTE+1E32; C; 1E33; # LATIN CAPITAL LETTER K WITH DOT BELOW+1E34; C; 1E35; # LATIN CAPITAL LETTER K WITH LINE BELOW+1E36; C; 1E37; # LATIN CAPITAL LETTER L WITH DOT BELOW+1E38; C; 1E39; # LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON+1E3A; C; 1E3B; # LATIN CAPITAL LETTER L WITH LINE BELOW+1E3C; C; 1E3D; # LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW+1E3E; C; 1E3F; # LATIN CAPITAL LETTER M WITH ACUTE+1E40; C; 1E41; # LATIN CAPITAL LETTER M WITH DOT ABOVE+1E42; C; 1E43; # LATIN CAPITAL LETTER M WITH DOT BELOW+1E44; C; 1E45; # LATIN CAPITAL LETTER N WITH DOT ABOVE+1E46; C; 1E47; # LATIN CAPITAL LETTER N WITH DOT BELOW+1E48; C; 1E49; # LATIN CAPITAL LETTER N WITH LINE BELOW+1E4A; C; 1E4B; # LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW+1E4C; C; 1E4D; # LATIN CAPITAL LETTER O WITH TILDE AND ACUTE+1E4E; C; 1E4F; # LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS+1E50; C; 1E51; # LATIN CAPITAL LETTER O WITH MACRON AND GRAVE+1E52; C; 1E53; # LATIN CAPITAL LETTER O WITH MACRON AND ACUTE+1E54; C; 1E55; # LATIN CAPITAL LETTER P WITH ACUTE+1E56; C; 1E57; # LATIN CAPITAL LETTER P WITH DOT ABOVE+1E58; C; 1E59; # LATIN CAPITAL LETTER R WITH DOT ABOVE+1E5A; C; 1E5B; # LATIN CAPITAL LETTER R WITH DOT BELOW+1E5C; C; 1E5D; # LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON+1E5E; C; 1E5F; # LATIN CAPITAL LETTER R WITH LINE BELOW+1E60; C; 1E61; # LATIN CAPITAL LETTER S WITH DOT ABOVE+1E62; C; 1E63; # LATIN CAPITAL LETTER S WITH DOT BELOW+1E64; C; 1E65; # LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE+1E66; C; 1E67; # LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE+1E68; C; 1E69; # LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE+1E6A; C; 1E6B; # LATIN CAPITAL LETTER T WITH DOT ABOVE+1E6C; C; 1E6D; # LATIN CAPITAL LETTER T WITH DOT BELOW+1E6E; C; 1E6F; # LATIN CAPITAL LETTER T WITH LINE BELOW+1E70; C; 1E71; # LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW+1E72; C; 1E73; # LATIN CAPITAL LETTER U WITH DIAERESIS BELOW+1E74; C; 1E75; # LATIN CAPITAL LETTER U WITH TILDE BELOW+1E76; C; 1E77; # LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW+1E78; C; 1E79; # LATIN CAPITAL LETTER U WITH TILDE AND ACUTE+1E7A; C; 1E7B; # LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS+1E7C; C; 1E7D; # LATIN CAPITAL LETTER V WITH TILDE+1E7E; C; 1E7F; # LATIN CAPITAL LETTER V WITH DOT BELOW+1E80; C; 1E81; # LATIN CAPITAL LETTER W WITH GRAVE+1E82; C; 1E83; # LATIN CAPITAL LETTER W WITH ACUTE+1E84; C; 1E85; # LATIN CAPITAL LETTER W WITH DIAERESIS+1E86; C; 1E87; # LATIN CAPITAL LETTER W WITH DOT ABOVE+1E88; C; 1E89; # LATIN CAPITAL LETTER W WITH DOT BELOW+1E8A; C; 1E8B; # LATIN CAPITAL LETTER X WITH DOT ABOVE+1E8C; C; 1E8D; # LATIN CAPITAL LETTER X WITH DIAERESIS+1E8E; C; 1E8F; # LATIN CAPITAL LETTER Y WITH DOT ABOVE+1E90; C; 1E91; # LATIN CAPITAL LETTER Z WITH CIRCUMFLEX+1E92; C; 1E93; # LATIN CAPITAL LETTER Z WITH DOT BELOW+1E94; C; 1E95; # LATIN CAPITAL LETTER Z WITH LINE BELOW+1E96; F; 0068 0331; # LATIN SMALL LETTER H WITH LINE BELOW+1E97; F; 0074 0308; # LATIN SMALL LETTER T WITH DIAERESIS+1E98; F; 0077 030A; # LATIN SMALL LETTER W WITH RING ABOVE+1E99; F; 0079 030A; # LATIN SMALL LETTER Y WITH RING ABOVE+1E9A; F; 0061 02BE; # LATIN SMALL LETTER A WITH RIGHT HALF RING+1E9B; C; 1E61; # LATIN SMALL LETTER LONG S WITH DOT ABOVE+1E9E; F; 0073 0073; # LATIN CAPITAL LETTER SHARP S+1E9E; S; 00DF; # LATIN CAPITAL LETTER SHARP S+1EA0; C; 1EA1; # LATIN CAPITAL LETTER A WITH DOT BELOW+1EA2; C; 1EA3; # LATIN CAPITAL LETTER A WITH HOOK ABOVE+1EA4; C; 1EA5; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE+1EA6; C; 1EA7; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE+1EA8; C; 1EA9; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE+1EAA; C; 1EAB; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE+1EAC; C; 1EAD; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW+1EAE; C; 1EAF; # LATIN CAPITAL LETTER A WITH BREVE AND ACUTE+1EB0; C; 1EB1; # LATIN CAPITAL LETTER A WITH BREVE AND GRAVE+1EB2; C; 1EB3; # LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE+1EB4; C; 1EB5; # LATIN CAPITAL LETTER A WITH BREVE AND TILDE+1EB6; C; 1EB7; # LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW+1EB8; C; 1EB9; # LATIN CAPITAL LETTER E WITH DOT BELOW+1EBA; C; 1EBB; # LATIN CAPITAL LETTER E WITH HOOK ABOVE+1EBC; C; 1EBD; # LATIN CAPITAL LETTER E WITH TILDE+1EBE; C; 1EBF; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE+1EC0; C; 1EC1; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE+1EC2; C; 1EC3; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE+1EC4; C; 1EC5; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE+1EC6; C; 1EC7; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW+1EC8; C; 1EC9; # LATIN CAPITAL LETTER I WITH HOOK ABOVE+1ECA; C; 1ECB; # LATIN CAPITAL LETTER I WITH DOT BELOW+1ECC; C; 1ECD; # LATIN CAPITAL LETTER O WITH DOT BELOW+1ECE; C; 1ECF; # LATIN CAPITAL LETTER O WITH HOOK ABOVE+1ED0; C; 1ED1; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE+1ED2; C; 1ED3; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE+1ED4; C; 1ED5; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE+1ED6; C; 1ED7; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE+1ED8; C; 1ED9; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW+1EDA; C; 1EDB; # LATIN CAPITAL LETTER O WITH HORN AND ACUTE+1EDC; C; 1EDD; # LATIN CAPITAL LETTER O WITH HORN AND GRAVE+1EDE; C; 1EDF; # LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE+1EE0; C; 1EE1; # LATIN CAPITAL LETTER O WITH HORN AND TILDE+1EE2; C; 1EE3; # LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW+1EE4; C; 1EE5; # LATIN CAPITAL LETTER U WITH DOT BELOW+1EE6; C; 1EE7; # LATIN CAPITAL LETTER U WITH HOOK ABOVE+1EE8; C; 1EE9; # LATIN CAPITAL LETTER U WITH HORN AND ACUTE+1EEA; C; 1EEB; # LATIN CAPITAL LETTER U WITH HORN AND GRAVE+1EEC; C; 1EED; # LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE+1EEE; C; 1EEF; # LATIN CAPITAL LETTER U WITH HORN AND TILDE+1EF0; C; 1EF1; # LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW+1EF2; C; 1EF3; # LATIN CAPITAL LETTER Y WITH GRAVE+1EF4; C; 1EF5; # LATIN CAPITAL LETTER Y WITH DOT BELOW+1EF6; C; 1EF7; # LATIN CAPITAL LETTER Y WITH HOOK ABOVE+1EF8; C; 1EF9; # LATIN CAPITAL LETTER Y WITH TILDE+1EFA; C; 1EFB; # LATIN CAPITAL LETTER MIDDLE-WELSH LL+1EFC; C; 1EFD; # LATIN CAPITAL LETTER MIDDLE-WELSH V+1EFE; C; 1EFF; # LATIN CAPITAL LETTER Y WITH LOOP+1F08; C; 1F00; # GREEK CAPITAL LETTER ALPHA WITH PSILI+1F09; C; 1F01; # GREEK CAPITAL LETTER ALPHA WITH DASIA+1F0A; C; 1F02; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA+1F0B; C; 1F03; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA+1F0C; C; 1F04; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA+1F0D; C; 1F05; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA+1F0E; C; 1F06; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI+1F0F; C; 1F07; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI+1F18; C; 1F10; # GREEK CAPITAL LETTER EPSILON WITH PSILI+1F19; C; 1F11; # GREEK CAPITAL LETTER EPSILON WITH DASIA+1F1A; C; 1F12; # GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA+1F1B; C; 1F13; # GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA+1F1C; C; 1F14; # GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA+1F1D; C; 1F15; # GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA+1F28; C; 1F20; # GREEK CAPITAL LETTER ETA WITH PSILI+1F29; C; 1F21; # GREEK CAPITAL LETTER ETA WITH DASIA+1F2A; C; 1F22; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA+1F2B; C; 1F23; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA+1F2C; C; 1F24; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA+1F2D; C; 1F25; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA+1F2E; C; 1F26; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI+1F2F; C; 1F27; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI+1F38; C; 1F30; # GREEK CAPITAL LETTER IOTA WITH PSILI+1F39; C; 1F31; # GREEK CAPITAL LETTER IOTA WITH DASIA+1F3A; C; 1F32; # GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA+1F3B; C; 1F33; # GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA+1F3C; C; 1F34; # GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA+1F3D; C; 1F35; # GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA+1F3E; C; 1F36; # GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI+1F3F; C; 1F37; # GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI+1F48; C; 1F40; # GREEK CAPITAL LETTER OMICRON WITH PSILI+1F49; C; 1F41; # GREEK CAPITAL LETTER OMICRON WITH DASIA+1F4A; C; 1F42; # GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA+1F4B; C; 1F43; # GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA+1F4C; C; 1F44; # GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA+1F4D; C; 1F45; # GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA+1F50; F; 03C5 0313; # GREEK SMALL LETTER UPSILON WITH PSILI+1F52; F; 03C5 0313 0300; # GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA+1F54; F; 03C5 0313 0301; # GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA+1F56; F; 03C5 0313 0342; # GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI+1F59; C; 1F51; # GREEK CAPITAL LETTER UPSILON WITH DASIA+1F5B; C; 1F53; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA+1F5D; C; 1F55; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA+1F5F; C; 1F57; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI+1F68; C; 1F60; # GREEK CAPITAL LETTER OMEGA WITH PSILI+1F69; C; 1F61; # GREEK CAPITAL LETTER OMEGA WITH DASIA+1F6A; C; 1F62; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA+1F6B; C; 1F63; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA+1F6C; C; 1F64; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA+1F6D; C; 1F65; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA+1F6E; C; 1F66; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI+1F6F; C; 1F67; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI+1F80; F; 1F00 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI+1F81; F; 1F01 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI+1F82; F; 1F02 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI+1F83; F; 1F03 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI+1F84; F; 1F04 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI+1F85; F; 1F05 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI+1F86; F; 1F06 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI+1F87; F; 1F07 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI+1F88; F; 1F00 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI+1F88; S; 1F80; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI+1F89; F; 1F01 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI+1F89; S; 1F81; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI+1F8A; F; 1F02 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI+1F8A; S; 1F82; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI+1F8B; F; 1F03 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI+1F8B; S; 1F83; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI+1F8C; F; 1F04 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI+1F8C; S; 1F84; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI+1F8D; F; 1F05 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI+1F8D; S; 1F85; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI+1F8E; F; 1F06 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI+1F8E; S; 1F86; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI+1F8F; F; 1F07 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI+1F8F; S; 1F87; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI+1F90; F; 1F20 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI+1F91; F; 1F21 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI+1F92; F; 1F22 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI+1F93; F; 1F23 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI+1F94; F; 1F24 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI+1F95; F; 1F25 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI+1F96; F; 1F26 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI+1F97; F; 1F27 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI+1F98; F; 1F20 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI+1F98; S; 1F90; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI+1F99; F; 1F21 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI+1F99; S; 1F91; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI+1F9A; F; 1F22 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI+1F9A; S; 1F92; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI+1F9B; F; 1F23 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI+1F9B; S; 1F93; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI+1F9C; F; 1F24 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI+1F9C; S; 1F94; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI+1F9D; F; 1F25 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI+1F9D; S; 1F95; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI+1F9E; F; 1F26 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI+1F9E; S; 1F96; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI+1F9F; F; 1F27 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI+1F9F; S; 1F97; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI+1FA0; F; 1F60 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI+1FA1; F; 1F61 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI+1FA2; F; 1F62 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI+1FA3; F; 1F63 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI+1FA4; F; 1F64 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI+1FA5; F; 1F65 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI+1FA6; F; 1F66 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI+1FA7; F; 1F67 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI+1FA8; F; 1F60 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI+1FA8; S; 1FA0; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI+1FA9; F; 1F61 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI+1FA9; S; 1FA1; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI+1FAA; F; 1F62 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI+1FAA; S; 1FA2; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI+1FAB; F; 1F63 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI+1FAB; S; 1FA3; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI+1FAC; F; 1F64 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI+1FAC; S; 1FA4; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI+1FAD; F; 1F65 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI+1FAD; S; 1FA5; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI+1FAE; F; 1F66 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI+1FAE; S; 1FA6; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI+1FAF; F; 1F67 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI+1FAF; S; 1FA7; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI+1FB2; F; 1F70 03B9; # GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI+1FB3; F; 03B1 03B9; # GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI+1FB4; F; 03AC 03B9; # GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI+1FB6; F; 03B1 0342; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI+1FB7; F; 03B1 0342 03B9; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI+1FB8; C; 1FB0; # GREEK CAPITAL LETTER ALPHA WITH VRACHY+1FB9; C; 1FB1; # GREEK CAPITAL LETTER ALPHA WITH MACRON+1FBA; C; 1F70; # GREEK CAPITAL LETTER ALPHA WITH VARIA+1FBB; C; 1F71; # GREEK CAPITAL LETTER ALPHA WITH OXIA+1FBC; F; 03B1 03B9; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI+1FBC; S; 1FB3; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI+1FBE; C; 03B9; # GREEK PROSGEGRAMMENI+1FC2; F; 1F74 03B9; # GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI+1FC3; F; 03B7 03B9; # GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI+1FC4; F; 03AE 03B9; # GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI+1FC6; F; 03B7 0342; # GREEK SMALL LETTER ETA WITH PERISPOMENI+1FC7; F; 03B7 0342 03B9; # GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI+1FC8; C; 1F72; # GREEK CAPITAL LETTER EPSILON WITH VARIA+1FC9; C; 1F73; # GREEK CAPITAL LETTER EPSILON WITH OXIA+1FCA; C; 1F74; # GREEK CAPITAL LETTER ETA WITH VARIA+1FCB; C; 1F75; # GREEK CAPITAL LETTER ETA WITH OXIA+1FCC; F; 03B7 03B9; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI+1FCC; S; 1FC3; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI+1FD2; F; 03B9 0308 0300; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA+1FD3; F; 03B9 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA+1FD6; F; 03B9 0342; # GREEK SMALL LETTER IOTA WITH PERISPOMENI+1FD7; F; 03B9 0308 0342; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI+1FD8; C; 1FD0; # GREEK CAPITAL LETTER IOTA WITH VRACHY+1FD9; C; 1FD1; # GREEK CAPITAL LETTER IOTA WITH MACRON+1FDA; C; 1F76; # GREEK CAPITAL LETTER IOTA WITH VARIA+1FDB; C; 1F77; # GREEK CAPITAL LETTER IOTA WITH OXIA+1FE2; F; 03C5 0308 0300; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA+1FE3; F; 03C5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA+1FE4; F; 03C1 0313; # GREEK SMALL LETTER RHO WITH PSILI+1FE6; F; 03C5 0342; # GREEK SMALL LETTER UPSILON WITH PERISPOMENI+1FE7; F; 03C5 0308 0342; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI+1FE8; C; 1FE0; # GREEK CAPITAL LETTER UPSILON WITH VRACHY+1FE9; C; 1FE1; # GREEK CAPITAL LETTER UPSILON WITH MACRON+1FEA; C; 1F7A; # GREEK CAPITAL LETTER UPSILON WITH VARIA+1FEB; C; 1F7B; # GREEK CAPITAL LETTER UPSILON WITH OXIA+1FEC; C; 1FE5; # GREEK CAPITAL LETTER RHO WITH DASIA+1FF2; F; 1F7C 03B9; # GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI+1FF3; F; 03C9 03B9; # GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI+1FF4; F; 03CE 03B9; # GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI+1FF6; F; 03C9 0342; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI+1FF7; F; 03C9 0342 03B9; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI+1FF8; C; 1F78; # GREEK CAPITAL LETTER OMICRON WITH VARIA+1FF9; C; 1F79; # GREEK CAPITAL LETTER OMICRON WITH OXIA+1FFA; C; 1F7C; # GREEK CAPITAL LETTER OMEGA WITH VARIA+1FFB; C; 1F7D; # GREEK CAPITAL LETTER OMEGA WITH OXIA+1FFC; F; 03C9 03B9; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI+1FFC; S; 1FF3; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI+2126; C; 03C9; # OHM SIGN+212A; C; 006B; # KELVIN SIGN+212B; C; 00E5; # ANGSTROM SIGN+2132; C; 214E; # TURNED CAPITAL F+2160; C; 2170; # ROMAN NUMERAL ONE+2161; C; 2171; # ROMAN NUMERAL TWO+2162; C; 2172; # ROMAN NUMERAL THREE+2163; C; 2173; # ROMAN NUMERAL FOUR+2164; C; 2174; # ROMAN NUMERAL FIVE+2165; C; 2175; # ROMAN NUMERAL SIX+2166; C; 2176; # ROMAN NUMERAL SEVEN+2167; C; 2177; # ROMAN NUMERAL EIGHT+2168; C; 2178; # ROMAN NUMERAL NINE+2169; C; 2179; # ROMAN NUMERAL TEN+216A; C; 217A; # ROMAN NUMERAL ELEVEN+216B; C; 217B; # ROMAN NUMERAL TWELVE+216C; C; 217C; # ROMAN NUMERAL FIFTY+216D; C; 217D; # ROMAN NUMERAL ONE HUNDRED+216E; C; 217E; # ROMAN NUMERAL FIVE HUNDRED+216F; C; 217F; # ROMAN NUMERAL ONE THOUSAND+2183; C; 2184; # ROMAN NUMERAL REVERSED ONE HUNDRED+24B6; C; 24D0; # CIRCLED LATIN CAPITAL LETTER A+24B7; C; 24D1; # CIRCLED LATIN CAPITAL LETTER B+24B8; C; 24D2; # CIRCLED LATIN CAPITAL LETTER C+24B9; C; 24D3; # CIRCLED LATIN CAPITAL LETTER D+24BA; C; 24D4; # CIRCLED LATIN CAPITAL LETTER E+24BB; C; 24D5; # CIRCLED LATIN CAPITAL LETTER F+24BC; C; 24D6; # CIRCLED LATIN CAPITAL LETTER G+24BD; C; 24D7; # CIRCLED LATIN CAPITAL LETTER H+24BE; C; 24D8; # CIRCLED LATIN CAPITAL LETTER I+24BF; C; 24D9; # CIRCLED LATIN CAPITAL LETTER J+24C0; C; 24DA; # CIRCLED LATIN CAPITAL LETTER K+24C1; C; 24DB; # CIRCLED LATIN CAPITAL LETTER L+24C2; C; 24DC; # CIRCLED LATIN CAPITAL LETTER M+24C3; C; 24DD; # CIRCLED LATIN CAPITAL LETTER N+24C4; C; 24DE; # CIRCLED LATIN CAPITAL LETTER O+24C5; C; 24DF; # CIRCLED LATIN CAPITAL LETTER P+24C6; C; 24E0; # CIRCLED LATIN CAPITAL LETTER Q+24C7; C; 24E1; # CIRCLED LATIN CAPITAL LETTER R+24C8; C; 24E2; # CIRCLED LATIN CAPITAL LETTER S+24C9; C; 24E3; # CIRCLED LATIN CAPITAL LETTER T+24CA; C; 24E4; # CIRCLED LATIN CAPITAL LETTER U+24CB; C; 24E5; # CIRCLED LATIN CAPITAL LETTER V+24CC; C; 24E6; # CIRCLED LATIN CAPITAL LETTER W+24CD; C; 24E7; # CIRCLED LATIN CAPITAL LETTER X+24CE; C; 24E8; # CIRCLED LATIN CAPITAL LETTER Y+24CF; C; 24E9; # CIRCLED LATIN CAPITAL LETTER Z+2C00; C; 2C30; # GLAGOLITIC CAPITAL LETTER AZU+2C01; C; 2C31; # GLAGOLITIC CAPITAL LETTER BUKY+2C02; C; 2C32; # GLAGOLITIC CAPITAL LETTER VEDE+2C03; C; 2C33; # GLAGOLITIC CAPITAL LETTER GLAGOLI+2C04; C; 2C34; # GLAGOLITIC CAPITAL LETTER DOBRO+2C05; C; 2C35; # GLAGOLITIC CAPITAL LETTER YESTU+2C06; C; 2C36; # GLAGOLITIC CAPITAL LETTER ZHIVETE+2C07; C; 2C37; # GLAGOLITIC CAPITAL LETTER DZELO+2C08; C; 2C38; # GLAGOLITIC CAPITAL LETTER ZEMLJA+2C09; C; 2C39; # GLAGOLITIC CAPITAL LETTER IZHE+2C0A; C; 2C3A; # GLAGOLITIC CAPITAL LETTER INITIAL IZHE+2C0B; C; 2C3B; # GLAGOLITIC CAPITAL LETTER I+2C0C; C; 2C3C; # GLAGOLITIC CAPITAL LETTER DJERVI+2C0D; C; 2C3D; # GLAGOLITIC CAPITAL LETTER KAKO+2C0E; C; 2C3E; # GLAGOLITIC CAPITAL LETTER LJUDIJE+2C0F; C; 2C3F; # GLAGOLITIC CAPITAL LETTER MYSLITE+2C10; C; 2C40; # GLAGOLITIC CAPITAL LETTER NASHI+2C11; C; 2C41; # GLAGOLITIC CAPITAL LETTER ONU+2C12; C; 2C42; # GLAGOLITIC CAPITAL LETTER POKOJI+2C13; C; 2C43; # GLAGOLITIC CAPITAL LETTER RITSI+2C14; C; 2C44; # GLAGOLITIC CAPITAL LETTER SLOVO+2C15; C; 2C45; # GLAGOLITIC CAPITAL LETTER TVRIDO+2C16; C; 2C46; # GLAGOLITIC CAPITAL LETTER UKU+2C17; C; 2C47; # GLAGOLITIC CAPITAL LETTER FRITU+2C18; C; 2C48; # GLAGOLITIC CAPITAL LETTER HERU+2C19; C; 2C49; # GLAGOLITIC CAPITAL LETTER OTU+2C1A; C; 2C4A; # GLAGOLITIC CAPITAL LETTER PE+2C1B; C; 2C4B; # GLAGOLITIC CAPITAL LETTER SHTA+2C1C; C; 2C4C; # GLAGOLITIC CAPITAL LETTER TSI+2C1D; C; 2C4D; # GLAGOLITIC CAPITAL LETTER CHRIVI+2C1E; C; 2C4E; # GLAGOLITIC CAPITAL LETTER SHA+2C1F; C; 2C4F; # GLAGOLITIC CAPITAL LETTER YERU+2C20; C; 2C50; # GLAGOLITIC CAPITAL LETTER YERI+2C21; C; 2C51; # GLAGOLITIC CAPITAL LETTER YATI+2C22; C; 2C52; # GLAGOLITIC CAPITAL LETTER SPIDERY HA+2C23; C; 2C53; # GLAGOLITIC CAPITAL LETTER YU+2C24; C; 2C54; # GLAGOLITIC CAPITAL LETTER SMALL YUS+2C25; C; 2C55; # GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL+2C26; C; 2C56; # GLAGOLITIC CAPITAL LETTER YO+2C27; C; 2C57; # GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS+2C28; C; 2C58; # GLAGOLITIC CAPITAL LETTER BIG YUS+2C29; C; 2C59; # GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS+2C2A; C; 2C5A; # GLAGOLITIC CAPITAL LETTER FITA+2C2B; C; 2C5B; # GLAGOLITIC CAPITAL LETTER IZHITSA+2C2C; C; 2C5C; # GLAGOLITIC CAPITAL LETTER SHTAPIC+2C2D; C; 2C5D; # GLAGOLITIC CAPITAL LETTER TROKUTASTI A+2C2E; C; 2C5E; # GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE+2C60; C; 2C61; # LATIN CAPITAL LETTER L WITH DOUBLE BAR+2C62; C; 026B; # LATIN CAPITAL LETTER L WITH MIDDLE TILDE+2C63; C; 1D7D; # LATIN CAPITAL LETTER P WITH STROKE+2C64; C; 027D; # LATIN CAPITAL LETTER R WITH TAIL+2C67; C; 2C68; # LATIN CAPITAL LETTER H WITH DESCENDER+2C69; C; 2C6A; # LATIN CAPITAL LETTER K WITH DESCENDER+2C6B; C; 2C6C; # LATIN CAPITAL LETTER Z WITH DESCENDER+2C6D; C; 0251; # LATIN CAPITAL LETTER ALPHA+2C6E; C; 0271; # LATIN CAPITAL LETTER M WITH HOOK+2C6F; C; 0250; # LATIN CAPITAL LETTER TURNED A+2C72; C; 2C73; # LATIN CAPITAL LETTER W WITH HOOK+2C75; C; 2C76; # LATIN CAPITAL LETTER HALF H+2C80; C; 2C81; # COPTIC CAPITAL LETTER ALFA+2C82; C; 2C83; # COPTIC CAPITAL LETTER VIDA+2C84; C; 2C85; # COPTIC CAPITAL LETTER GAMMA+2C86; C; 2C87; # COPTIC CAPITAL LETTER DALDA+2C88; C; 2C89; # COPTIC CAPITAL LETTER EIE+2C8A; C; 2C8B; # COPTIC CAPITAL LETTER SOU+2C8C; C; 2C8D; # COPTIC CAPITAL LETTER ZATA+2C8E; C; 2C8F; # COPTIC CAPITAL LETTER HATE+2C90; C; 2C91; # COPTIC CAPITAL LETTER THETHE+2C92; C; 2C93; # COPTIC CAPITAL LETTER IAUDA+2C94; C; 2C95; # COPTIC CAPITAL LETTER KAPA+2C96; C; 2C97; # COPTIC CAPITAL LETTER LAULA+2C98; C; 2C99; # COPTIC CAPITAL LETTER MI+2C9A; C; 2C9B; # COPTIC CAPITAL LETTER NI+2C9C; C; 2C9D; # COPTIC CAPITAL LETTER KSI+2C9E; C; 2C9F; # COPTIC CAPITAL LETTER O+2CA0; C; 2CA1; # COPTIC CAPITAL LETTER PI+2CA2; C; 2CA3; # COPTIC CAPITAL LETTER RO+2CA4; C; 2CA5; # COPTIC CAPITAL LETTER SIMA+2CA6; C; 2CA7; # COPTIC CAPITAL LETTER TAU+2CA8; C; 2CA9; # COPTIC CAPITAL LETTER UA+2CAA; C; 2CAB; # COPTIC CAPITAL LETTER FI+2CAC; C; 2CAD; # COPTIC CAPITAL LETTER KHI+2CAE; C; 2CAF; # COPTIC CAPITAL LETTER PSI+2CB0; C; 2CB1; # COPTIC CAPITAL LETTER OOU+2CB2; C; 2CB3; # COPTIC CAPITAL LETTER DIALECT-P ALEF+2CB4; C; 2CB5; # COPTIC CAPITAL LETTER OLD COPTIC AIN+2CB6; C; 2CB7; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE+2CB8; C; 2CB9; # COPTIC CAPITAL LETTER DIALECT-P KAPA+2CBA; C; 2CBB; # COPTIC CAPITAL LETTER DIALECT-P NI+2CBC; C; 2CBD; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI+2CBE; C; 2CBF; # COPTIC CAPITAL LETTER OLD COPTIC OOU+2CC0; C; 2CC1; # COPTIC CAPITAL LETTER SAMPI+2CC2; C; 2CC3; # COPTIC CAPITAL LETTER CROSSED SHEI+2CC4; C; 2CC5; # COPTIC CAPITAL LETTER OLD COPTIC SHEI+2CC6; C; 2CC7; # COPTIC CAPITAL LETTER OLD COPTIC ESH+2CC8; C; 2CC9; # COPTIC CAPITAL LETTER AKHMIMIC KHEI+2CCA; C; 2CCB; # COPTIC CAPITAL LETTER DIALECT-P HORI+2CCC; C; 2CCD; # COPTIC CAPITAL LETTER OLD COPTIC HORI+2CCE; C; 2CCF; # COPTIC CAPITAL LETTER OLD COPTIC HA+2CD0; C; 2CD1; # COPTIC CAPITAL LETTER L-SHAPED HA+2CD2; C; 2CD3; # COPTIC CAPITAL LETTER OLD COPTIC HEI+2CD4; C; 2CD5; # COPTIC CAPITAL LETTER OLD COPTIC HAT+2CD6; C; 2CD7; # COPTIC CAPITAL LETTER OLD COPTIC GANGIA+2CD8; C; 2CD9; # COPTIC CAPITAL LETTER OLD COPTIC DJA+2CDA; C; 2CDB; # COPTIC CAPITAL LETTER OLD COPTIC SHIMA+2CDC; C; 2CDD; # COPTIC CAPITAL LETTER OLD NUBIAN SHIMA+2CDE; C; 2CDF; # COPTIC CAPITAL LETTER OLD NUBIAN NGI+2CE0; C; 2CE1; # COPTIC CAPITAL LETTER OLD NUBIAN NYI+2CE2; C; 2CE3; # COPTIC CAPITAL LETTER OLD NUBIAN WAU+A640; C; A641; # CYRILLIC CAPITAL LETTER ZEMLYA+A642; C; A643; # CYRILLIC CAPITAL LETTER DZELO+A644; C; A645; # CYRILLIC CAPITAL LETTER REVERSED DZE+A646; C; A647; # CYRILLIC CAPITAL LETTER IOTA+A648; C; A649; # CYRILLIC CAPITAL LETTER DJERV+A64A; C; A64B; # CYRILLIC CAPITAL LETTER MONOGRAPH UK+A64C; C; A64D; # CYRILLIC CAPITAL LETTER BROAD OMEGA+A64E; C; A64F; # CYRILLIC CAPITAL LETTER NEUTRAL YER+A650; C; A651; # CYRILLIC CAPITAL LETTER YERU WITH BACK YER+A652; C; A653; # CYRILLIC CAPITAL LETTER IOTIFIED YAT+A654; C; A655; # CYRILLIC CAPITAL LETTER REVERSED YU+A656; C; A657; # CYRILLIC CAPITAL LETTER IOTIFIED A+A658; C; A659; # CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS+A65A; C; A65B; # CYRILLIC CAPITAL LETTER BLENDED YUS+A65C; C; A65D; # CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS+A65E; C; A65F; # CYRILLIC CAPITAL LETTER YN+A662; C; A663; # CYRILLIC CAPITAL LETTER SOFT DE+A664; C; A665; # CYRILLIC CAPITAL LETTER SOFT EL+A666; C; A667; # CYRILLIC CAPITAL LETTER SOFT EM+A668; C; A669; # CYRILLIC CAPITAL LETTER MONOCULAR O+A66A; C; A66B; # CYRILLIC CAPITAL LETTER BINOCULAR O+A66C; C; A66D; # CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O+A680; C; A681; # CYRILLIC CAPITAL LETTER DWE+A682; C; A683; # CYRILLIC CAPITAL LETTER DZWE+A684; C; A685; # CYRILLIC CAPITAL LETTER ZHWE+A686; C; A687; # CYRILLIC CAPITAL LETTER CCHE+A688; C; A689; # CYRILLIC CAPITAL LETTER DZZE+A68A; C; A68B; # CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK+A68C; C; A68D; # CYRILLIC CAPITAL LETTER TWE+A68E; C; A68F; # CYRILLIC CAPITAL LETTER TSWE+A690; C; A691; # CYRILLIC CAPITAL LETTER TSSE+A692; C; A693; # CYRILLIC CAPITAL LETTER TCHE+A694; C; A695; # CYRILLIC CAPITAL LETTER HWE+A696; C; A697; # CYRILLIC CAPITAL LETTER SHWE+A722; C; A723; # LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF+A724; C; A725; # LATIN CAPITAL LETTER EGYPTOLOGICAL AIN+A726; C; A727; # LATIN CAPITAL LETTER HENG+A728; C; A729; # LATIN CAPITAL LETTER TZ+A72A; C; A72B; # LATIN CAPITAL LETTER TRESILLO+A72C; C; A72D; # LATIN CAPITAL LETTER CUATRILLO+A72E; C; A72F; # LATIN CAPITAL LETTER CUATRILLO WITH COMMA+A732; C; A733; # LATIN CAPITAL LETTER AA+A734; C; A735; # LATIN CAPITAL LETTER AO+A736; C; A737; # LATIN CAPITAL LETTER AU+A738; C; A739; # LATIN CAPITAL LETTER AV+A73A; C; A73B; # LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR+A73C; C; A73D; # LATIN CAPITAL LETTER AY+A73E; C; A73F; # LATIN CAPITAL LETTER REVERSED C WITH DOT+A740; C; A741; # LATIN CAPITAL LETTER K WITH STROKE+A742; C; A743; # LATIN CAPITAL LETTER K WITH DIAGONAL STROKE+A744; C; A745; # LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE+A746; C; A747; # LATIN CAPITAL LETTER BROKEN L+A748; C; A749; # LATIN CAPITAL LETTER L WITH HIGH STROKE+A74A; C; A74B; # LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY+A74C; C; A74D; # LATIN CAPITAL LETTER O WITH LOOP+A74E; C; A74F; # LATIN CAPITAL LETTER OO+A750; C; A751; # LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER+A752; C; A753; # LATIN CAPITAL LETTER P WITH FLOURISH+A754; C; A755; # LATIN CAPITAL LETTER P WITH SQUIRREL TAIL+A756; C; A757; # LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER+A758; C; A759; # LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE+A75A; C; A75B; # LATIN CAPITAL LETTER R ROTUNDA+A75C; C; A75D; # LATIN CAPITAL LETTER RUM ROTUNDA+A75E; C; A75F; # LATIN CAPITAL LETTER V WITH DIAGONAL STROKE+A760; C; A761; # LATIN CAPITAL LETTER VY+A762; C; A763; # LATIN CAPITAL LETTER VISIGOTHIC Z+A764; C; A765; # LATIN CAPITAL LETTER THORN WITH STROKE+A766; C; A767; # LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER+A768; C; A769; # LATIN CAPITAL LETTER VEND+A76A; C; A76B; # LATIN CAPITAL LETTER ET+A76C; C; A76D; # LATIN CAPITAL LETTER IS+A76E; C; A76F; # LATIN CAPITAL LETTER CON+A779; C; A77A; # LATIN CAPITAL LETTER INSULAR D+A77B; C; A77C; # LATIN CAPITAL LETTER INSULAR F+A77D; C; 1D79; # LATIN CAPITAL LETTER INSULAR G+A77E; C; A77F; # LATIN CAPITAL LETTER TURNED INSULAR G+A780; C; A781; # LATIN CAPITAL LETTER TURNED L+A782; C; A783; # LATIN CAPITAL LETTER INSULAR R+A784; C; A785; # LATIN CAPITAL LETTER INSULAR S+A786; C; A787; # LATIN CAPITAL LETTER INSULAR T+A78B; C; A78C; # LATIN CAPITAL LETTER SALTILLO+FB00; F; 0066 0066; # LATIN SMALL LIGATURE FF+FB01; F; 0066 0069; # LATIN SMALL LIGATURE FI+FB02; F; 0066 006C; # LATIN SMALL LIGATURE FL+FB03; F; 0066 0066 0069; # LATIN SMALL LIGATURE FFI+FB04; F; 0066 0066 006C; # LATIN SMALL LIGATURE FFL+FB05; F; 0073 0074; # LATIN SMALL LIGATURE LONG S T+FB06; F; 0073 0074; # LATIN SMALL LIGATURE ST+FB13; F; 0574 0576; # ARMENIAN SMALL LIGATURE MEN NOW+FB14; F; 0574 0565; # ARMENIAN SMALL LIGATURE MEN ECH+FB15; F; 0574 056B; # ARMENIAN SMALL LIGATURE MEN INI+FB16; F; 057E 0576; # ARMENIAN SMALL LIGATURE VEW NOW+FB17; F; 0574 056D; # ARMENIAN SMALL LIGATURE MEN XEH+FF21; C; FF41; # FULLWIDTH LATIN CAPITAL LETTER A+FF22; C; FF42; # FULLWIDTH LATIN CAPITAL LETTER B+FF23; C; FF43; # FULLWIDTH LATIN CAPITAL LETTER C+FF24; C; FF44; # FULLWIDTH LATIN CAPITAL LETTER D+FF25; C; FF45; # FULLWIDTH LATIN CAPITAL LETTER E+FF26; C; FF46; # FULLWIDTH LATIN CAPITAL LETTER F+FF27; C; FF47; # FULLWIDTH LATIN CAPITAL LETTER G+FF28; C; FF48; # FULLWIDTH LATIN CAPITAL LETTER H+FF29; C; FF49; # FULLWIDTH LATIN CAPITAL LETTER I+FF2A; C; FF4A; # FULLWIDTH LATIN CAPITAL LETTER J+FF2B; C; FF4B; # FULLWIDTH LATIN CAPITAL LETTER K+FF2C; C; FF4C; # FULLWIDTH LATIN CAPITAL LETTER L+FF2D; C; FF4D; # FULLWIDTH LATIN CAPITAL LETTER M+FF2E; C; FF4E; # FULLWIDTH LATIN CAPITAL LETTER N+FF2F; C; FF4F; # FULLWIDTH LATIN CAPITAL LETTER O+FF30; C; FF50; # FULLWIDTH LATIN CAPITAL LETTER P+FF31; C; FF51; # FULLWIDTH LATIN CAPITAL LETTER Q+FF32; C; FF52; # FULLWIDTH LATIN CAPITAL LETTER R+FF33; C; FF53; # FULLWIDTH LATIN CAPITAL LETTER S+FF34; C; FF54; # FULLWIDTH LATIN CAPITAL LETTER T+FF35; C; FF55; # FULLWIDTH LATIN CAPITAL LETTER U+FF36; C; FF56; # FULLWIDTH LATIN CAPITAL LETTER V+FF37; C; FF57; # FULLWIDTH LATIN CAPITAL LETTER W+FF38; C; FF58; # FULLWIDTH LATIN CAPITAL LETTER X+FF39; C; FF59; # FULLWIDTH LATIN CAPITAL LETTER Y+FF3A; C; FF5A; # FULLWIDTH LATIN CAPITAL LETTER Z+10400; C; 10428; # DESERET CAPITAL LETTER LONG I+10401; C; 10429; # DESERET CAPITAL LETTER LONG E+10402; C; 1042A; # DESERET CAPITAL LETTER LONG A+10403; C; 1042B; # DESERET CAPITAL LETTER LONG AH+10404; C; 1042C; # DESERET CAPITAL LETTER LONG O+10405; C; 1042D; # DESERET CAPITAL LETTER LONG OO+10406; C; 1042E; # DESERET CAPITAL LETTER SHORT I+10407; C; 1042F; # DESERET CAPITAL LETTER SHORT E+10408; C; 10430; # DESERET CAPITAL LETTER SHORT A+10409; C; 10431; # DESERET CAPITAL LETTER SHORT AH+1040A; C; 10432; # DESERET CAPITAL LETTER SHORT O+1040B; C; 10433; # DESERET CAPITAL LETTER SHORT OO+1040C; C; 10434; # DESERET CAPITAL LETTER AY+1040D; C; 10435; # DESERET CAPITAL LETTER OW+1040E; C; 10436; # DESERET CAPITAL LETTER WU+1040F; C; 10437; # DESERET CAPITAL LETTER YEE+10410; C; 10438; # DESERET CAPITAL LETTER H+10411; C; 10439; # DESERET CAPITAL LETTER PEE+10412; C; 1043A; # DESERET CAPITAL LETTER BEE+10413; C; 1043B; # DESERET CAPITAL LETTER TEE+10414; C; 1043C; # DESERET CAPITAL LETTER DEE+10415; C; 1043D; # DESERET CAPITAL LETTER CHEE+10416; C; 1043E; # DESERET CAPITAL LETTER JEE+10417; C; 1043F; # DESERET CAPITAL LETTER KAY+10418; C; 10440; # DESERET CAPITAL LETTER GAY+10419; C; 10441; # DESERET CAPITAL LETTER EF+1041A; C; 10442; # DESERET CAPITAL LETTER VEE+1041B; C; 10443; # DESERET CAPITAL LETTER ETH+1041C; C; 10444; # DESERET CAPITAL LETTER THEE+1041D; C; 10445; # DESERET CAPITAL LETTER ES+1041E; C; 10446; # DESERET CAPITAL LETTER ZEE+1041F; C; 10447; # DESERET CAPITAL LETTER ESH+10420; C; 10448; # DESERET CAPITAL LETTER ZHEE+10421; C; 10449; # DESERET CAPITAL LETTER ER+10422; C; 1044A; # DESERET CAPITAL LETTER EL+10423; C; 1044B; # DESERET CAPITAL LETTER EM+10424; C; 1044C; # DESERET CAPITAL LETTER EN+10425; C; 1044D; # DESERET CAPITAL LETTER ENG+10426; C; 1044E; # DESERET CAPITAL LETTER OI+10427; C; 1044F; # DESERET CAPITAL LETTER EW
+ scripts/CaseMapping.hs view
@@ -0,0 +1,32 @@+import System.Environment+import System.IO++import Arsec+import CaseFolding+import SpecialCasing++main = do+ args <- getArgs+ let oname = case args of+ [] -> "../Data/Text/Fusion/CaseMapping.hs"+ [o] -> o+ psc <- parseSC "SpecialCasing.txt"+ pcf <- parseCF "CaseFolding.txt"+ scs <- case psc of+ Left err -> print err >> return undefined+ Right ms -> return ms+ cfs <- case pcf of+ Left err -> print err >> return undefined+ Right ms -> return ms+ h <- openFile oname WriteMode+ mapM_ (hPutStrLn h) ["{-# LANGUAGE Rank2Types #-}"+ ,"-- AUTOMATICALLY GENERATED - DO NOT EDIT"+ ,"-- Generated by scripts/SpecialCasing.hs"+ ,"module Data.Text.Fusion.CaseMapping where"+ ,"import Data.Char"+ ,"import Data.Text.Fusion.Internal"+ ,""]+ mapM_ (hPutStrLn h) (mapSC "upper" upper toUpper scs)+ mapM_ (hPutStrLn h) (mapSC "lower" lower toLower scs)+ mapM_ (hPutStrLn h) (mapCF cfs)+ hClose h
+ scripts/SpecialCasing.hs view
@@ -0,0 +1,50 @@+-- This script processes the following source file:+--+-- http://unicode.org/Public/UNIDATA/SpecialCasing.txt++module SpecialCasing+ (+ Case(..)+ , parseSC+ , mapSC+ ) where++import Arsec++data Case = Case {+ code :: Char+ , lower :: [Char]+ , title :: [Char]+ , upper :: [Char]+ , conditions :: String+ , name :: String+ } deriving (Eq, Ord, Show)++entries :: Parser [Case]+entries = many comment *> many (entry <* many comment)+ where+ entry = Case <$> unichar <* semi+ <*> unichars+ <*> unichars+ <*> unichars+ <*> manyTill anyToken (string "# ")+ <*> manyTill anyToken (char '\n')++parseSC :: FilePath -> IO (Either ParseError [Case])+parseSC name = parse entries name <$> readFile name++mapSC :: String -> (Case -> String) -> (Char -> Char) -> [Case] -> [String]+mapSC which access twiddle ms = typ ++ (map nice . filter p $ ms) ++ [last]+ where+ typ = [which ++ "Mapping :: forall s. Char -> s -> Step (PairS (PairS s Char) Char) Char"+ ,"{-# INLINE " ++ which ++ "Mapping #-}"]+ last = which ++ "Mapping c s = Yield (to" ++ ucFirst which ++ " c) (s :!: '\\0' :!: '\\0')"+ nice c = "-- " ++ name c ++ "\n" +++ which ++ "Mapping " ++ showC (code c) ++ " s = Yield " ++ x ++ " (s :!: " ++ y ++ " :!: " ++ z ++ ")"+ where [x,y,z] = (map showC . take 3) (access c ++ repeat '\0')+ p c = [k] /= a && a /= [twiddle k] && null (conditions c)+ where a = access c+ k = code c++ucFirst (c:cs) = toUpper c : cs+ucFirst [] = []
+ scripts/SpecialCasing.txt view
@@ -0,0 +1,274 @@+# SpecialCasing-5.1.0.txt+# Date: 2008-03-03, 21:58:10 GMT [MD]+#+# Unicode Character Database+# Copyright (c) 1991-2008 Unicode, Inc.+# For terms of use, see http://www.unicode.org/terms_of_use.html+# For documentation, see UCD.html+#+# Special Casing Properties+#+# This file is a supplement to the UnicodeData file.+# It contains additional information about the casing of Unicode characters.+# (For compatibility, the UnicodeData.txt file only contains case mappings for+# characters where they are 1-1, and independent of context and language.+# For more information, see the discussion of Case Mappings in the Unicode Standard.+#+# All code points not listed in this file that do not have a simple case mappings+# in UnicodeData.txt map to themselves.+# ================================================================================+# Format+# ================================================================================+# The entries in this file are in the following machine-readable format:+#+# <code>; <lower> ; <title> ; <upper> ; (<condition_list> ;)? # <comment>+#+# <code>, <lower>, <title>, and <upper> provide character values in hex. If there is more+# than one character, they are separated by spaces. Other than as used to separate +# elements, spaces are to be ignored.+#+# The <condition_list> is optional. Where present, it consists of one or more language IDs+# or contexts, separated by spaces. In these conditions:+# - A condition list overrides the normal behavior if all of the listed conditions are true.+# - The context is always the context of the characters in the original string,+# NOT in the resulting string.+# - Case distinctions in the condition list are not significant.+# - Conditions preceded by "Not_" represent the negation of the condition.+# The condition list is not represented in the UCD as a formal property.+#+# A language ID is defined by BCP 47, with '-' and '_' treated equivalently.+#+# A context for a character C is defined by Section 3.13 Default Case +# Operations, of The Unicode Standard, Version 5.0.+# (This is identical to the context defined by Unicode 4.1.0,+# as specified in http://www.unicode.org/versions/Unicode4.1.0/)+#+# Parsers of this file must be prepared to deal with future additions to this format:+# * Additional contexts+# * Additional fields+# ================================================================================+# @missing 0000..10FFFF; <slc>; <stc>; <suc>+# ================================================================================+# Unconditional mappings+# ================================================================================++# The German es-zed is special--the normal mapping is to SS.+# Note: the titlecase should never occur in practice. It is equal to titlecase(uppercase(<es-zed>))++00DF; 00DF; 0053 0073; 0053 0053; # LATIN SMALL LETTER SHARP S++# Preserve canonical equivalence for I with dot. Turkic is handled below.++0130; 0069 0307; 0130; 0130; # LATIN CAPITAL LETTER I WITH DOT ABOVE++# Ligatures++FB00; FB00; 0046 0066; 0046 0046; # LATIN SMALL LIGATURE FF+FB01; FB01; 0046 0069; 0046 0049; # LATIN SMALL LIGATURE FI+FB02; FB02; 0046 006C; 0046 004C; # LATIN SMALL LIGATURE FL+FB03; FB03; 0046 0066 0069; 0046 0046 0049; # LATIN SMALL LIGATURE FFI+FB04; FB04; 0046 0066 006C; 0046 0046 004C; # LATIN SMALL LIGATURE FFL+FB05; FB05; 0053 0074; 0053 0054; # LATIN SMALL LIGATURE LONG S T+FB06; FB06; 0053 0074; 0053 0054; # LATIN SMALL LIGATURE ST++0587; 0587; 0535 0582; 0535 0552; # ARMENIAN SMALL LIGATURE ECH YIWN+FB13; FB13; 0544 0576; 0544 0546; # ARMENIAN SMALL LIGATURE MEN NOW+FB14; FB14; 0544 0565; 0544 0535; # ARMENIAN SMALL LIGATURE MEN ECH+FB15; FB15; 0544 056B; 0544 053B; # ARMENIAN SMALL LIGATURE MEN INI+FB16; FB16; 054E 0576; 054E 0546; # ARMENIAN SMALL LIGATURE VEW NOW+FB17; FB17; 0544 056D; 0544 053D; # ARMENIAN SMALL LIGATURE MEN XEH++# No corresponding uppercase precomposed character++0149; 0149; 02BC 004E; 02BC 004E; # LATIN SMALL LETTER N PRECEDED BY APOSTROPHE+0390; 0390; 0399 0308 0301; 0399 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS+03B0; 03B0; 03A5 0308 0301; 03A5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS+01F0; 01F0; 004A 030C; 004A 030C; # LATIN SMALL LETTER J WITH CARON+1E96; 1E96; 0048 0331; 0048 0331; # LATIN SMALL LETTER H WITH LINE BELOW+1E97; 1E97; 0054 0308; 0054 0308; # LATIN SMALL LETTER T WITH DIAERESIS+1E98; 1E98; 0057 030A; 0057 030A; # LATIN SMALL LETTER W WITH RING ABOVE+1E99; 1E99; 0059 030A; 0059 030A; # LATIN SMALL LETTER Y WITH RING ABOVE+1E9A; 1E9A; 0041 02BE; 0041 02BE; # LATIN SMALL LETTER A WITH RIGHT HALF RING+1F50; 1F50; 03A5 0313; 03A5 0313; # GREEK SMALL LETTER UPSILON WITH PSILI+1F52; 1F52; 03A5 0313 0300; 03A5 0313 0300; # GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA+1F54; 1F54; 03A5 0313 0301; 03A5 0313 0301; # GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA+1F56; 1F56; 03A5 0313 0342; 03A5 0313 0342; # GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI+1FB6; 1FB6; 0391 0342; 0391 0342; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI+1FC6; 1FC6; 0397 0342; 0397 0342; # GREEK SMALL LETTER ETA WITH PERISPOMENI+1FD2; 1FD2; 0399 0308 0300; 0399 0308 0300; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA+1FD3; 1FD3; 0399 0308 0301; 0399 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA+1FD6; 1FD6; 0399 0342; 0399 0342; # GREEK SMALL LETTER IOTA WITH PERISPOMENI+1FD7; 1FD7; 0399 0308 0342; 0399 0308 0342; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI+1FE2; 1FE2; 03A5 0308 0300; 03A5 0308 0300; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA+1FE3; 1FE3; 03A5 0308 0301; 03A5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA+1FE4; 1FE4; 03A1 0313; 03A1 0313; # GREEK SMALL LETTER RHO WITH PSILI+1FE6; 1FE6; 03A5 0342; 03A5 0342; # GREEK SMALL LETTER UPSILON WITH PERISPOMENI+1FE7; 1FE7; 03A5 0308 0342; 03A5 0308 0342; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI+1FF6; 1FF6; 03A9 0342; 03A9 0342; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI++# IMPORTANT-when capitalizing iota-subscript (0345)+# It MUST be in normalized form--moved to the end of any sequence of combining marks.+# This is because logically it represents a following base character!+# E.g. <iota_subscript> (<Mn> | <Mc> | <Me>)+ => (<Mn> | <Mc> | <Me>)+ <iota_subscript>+# It should never be the first character in a word, so in titlecasing it can be left as is.++# The following cases are already in the UnicodeData file, so are only commented here.++# 0345; 0345; 0345; 0399; # COMBINING GREEK YPOGEGRAMMENI++# All letters with YPOGEGRAMMENI (iota-subscript) or PROSGEGRAMMENI (iota adscript)+# have special uppercases.+# Note: characters with PROSGEGRAMMENI are actually titlecase, not uppercase!++1F80; 1F80; 1F88; 1F08 0399; # GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI+1F81; 1F81; 1F89; 1F09 0399; # GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI+1F82; 1F82; 1F8A; 1F0A 0399; # GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI+1F83; 1F83; 1F8B; 1F0B 0399; # GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI+1F84; 1F84; 1F8C; 1F0C 0399; # GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI+1F85; 1F85; 1F8D; 1F0D 0399; # GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI+1F86; 1F86; 1F8E; 1F0E 0399; # GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI+1F87; 1F87; 1F8F; 1F0F 0399; # GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI+1F88; 1F80; 1F88; 1F08 0399; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI+1F89; 1F81; 1F89; 1F09 0399; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI+1F8A; 1F82; 1F8A; 1F0A 0399; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI+1F8B; 1F83; 1F8B; 1F0B 0399; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI+1F8C; 1F84; 1F8C; 1F0C 0399; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI+1F8D; 1F85; 1F8D; 1F0D 0399; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI+1F8E; 1F86; 1F8E; 1F0E 0399; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI+1F8F; 1F87; 1F8F; 1F0F 0399; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI+1F90; 1F90; 1F98; 1F28 0399; # GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI+1F91; 1F91; 1F99; 1F29 0399; # GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI+1F92; 1F92; 1F9A; 1F2A 0399; # GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI+1F93; 1F93; 1F9B; 1F2B 0399; # GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI+1F94; 1F94; 1F9C; 1F2C 0399; # GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI+1F95; 1F95; 1F9D; 1F2D 0399; # GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI+1F96; 1F96; 1F9E; 1F2E 0399; # GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI+1F97; 1F97; 1F9F; 1F2F 0399; # GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI+1F98; 1F90; 1F98; 1F28 0399; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI+1F99; 1F91; 1F99; 1F29 0399; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI+1F9A; 1F92; 1F9A; 1F2A 0399; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI+1F9B; 1F93; 1F9B; 1F2B 0399; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI+1F9C; 1F94; 1F9C; 1F2C 0399; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI+1F9D; 1F95; 1F9D; 1F2D 0399; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI+1F9E; 1F96; 1F9E; 1F2E 0399; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI+1F9F; 1F97; 1F9F; 1F2F 0399; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI+1FA0; 1FA0; 1FA8; 1F68 0399; # GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI+1FA1; 1FA1; 1FA9; 1F69 0399; # GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI+1FA2; 1FA2; 1FAA; 1F6A 0399; # GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI+1FA3; 1FA3; 1FAB; 1F6B 0399; # GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI+1FA4; 1FA4; 1FAC; 1F6C 0399; # GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI+1FA5; 1FA5; 1FAD; 1F6D 0399; # GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI+1FA6; 1FA6; 1FAE; 1F6E 0399; # GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI+1FA7; 1FA7; 1FAF; 1F6F 0399; # GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI+1FA8; 1FA0; 1FA8; 1F68 0399; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI+1FA9; 1FA1; 1FA9; 1F69 0399; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI+1FAA; 1FA2; 1FAA; 1F6A 0399; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI+1FAB; 1FA3; 1FAB; 1F6B 0399; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI+1FAC; 1FA4; 1FAC; 1F6C 0399; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI+1FAD; 1FA5; 1FAD; 1F6D 0399; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI+1FAE; 1FA6; 1FAE; 1F6E 0399; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI+1FAF; 1FA7; 1FAF; 1F6F 0399; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI+1FB3; 1FB3; 1FBC; 0391 0399; # GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI+1FBC; 1FB3; 1FBC; 0391 0399; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI+1FC3; 1FC3; 1FCC; 0397 0399; # GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI+1FCC; 1FC3; 1FCC; 0397 0399; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI+1FF3; 1FF3; 1FFC; 03A9 0399; # GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI+1FFC; 1FF3; 1FFC; 03A9 0399; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI++# Some characters with YPOGEGRAMMENI also have no corresponding titlecases++1FB2; 1FB2; 1FBA 0345; 1FBA 0399; # GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI+1FB4; 1FB4; 0386 0345; 0386 0399; # GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI+1FC2; 1FC2; 1FCA 0345; 1FCA 0399; # GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI+1FC4; 1FC4; 0389 0345; 0389 0399; # GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI+1FF2; 1FF2; 1FFA 0345; 1FFA 0399; # GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI+1FF4; 1FF4; 038F 0345; 038F 0399; # GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI++1FB7; 1FB7; 0391 0342 0345; 0391 0342 0399; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI+1FC7; 1FC7; 0397 0342 0345; 0397 0342 0399; # GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI+1FF7; 1FF7; 03A9 0342 0345; 03A9 0342 0399; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI++# ================================================================================+# Conditional Mappings+# The remainder of this file provides conditional casing data used to produce +# full case mappings.+# ================================================================================+# Language-Insensitive Mappings+# These are characters whose full case mappings do not depend on language, but do+# depend on context (which characters come before or after). For more information+# see the header of this file and the Unicode Standard.+# ================================================================================++# Special case for final form of sigma++03A3; 03C2; 03A3; 03A3; Final_Sigma; # GREEK CAPITAL LETTER SIGMA++# Note: the following cases for non-final are already in the UnicodeData file.++# 03A3; 03C3; 03A3; 03A3; # GREEK CAPITAL LETTER SIGMA+# 03C3; 03C3; 03A3; 03A3; # GREEK SMALL LETTER SIGMA+# 03C2; 03C2; 03A3; 03A3; # GREEK SMALL LETTER FINAL SIGMA++# Note: the following cases are not included, since they would case-fold in lowercasing++# 03C3; 03C2; 03A3; 03A3; Final_Sigma; # GREEK SMALL LETTER SIGMA+# 03C2; 03C3; 03A3; 03A3; Not_Final_Sigma; # GREEK SMALL LETTER FINAL SIGMA++# ================================================================================+# Language-Sensitive Mappings+# These are characters whose full case mappings depend on language and perhaps also+# context (which characters come before or after). For more information+# see the header of this file and the Unicode Standard.+# ================================================================================++# Lithuanian++# Lithuanian retains the dot in a lowercase i when followed by accents.++# Remove DOT ABOVE after "i" with upper or titlecase++0307; 0307; ; ; lt After_Soft_Dotted; # COMBINING DOT ABOVE++# Introduce an explicit dot above when lowercasing capital I's and J's+# whenever there are more accents above.+# (of the accents used in Lithuanian: grave, acute, tilde above, and ogonek)++0049; 0069 0307; 0049; 0049; lt More_Above; # LATIN CAPITAL LETTER I+004A; 006A 0307; 004A; 004A; lt More_Above; # LATIN CAPITAL LETTER J+012E; 012F 0307; 012E; 012E; lt More_Above; # LATIN CAPITAL LETTER I WITH OGONEK+00CC; 0069 0307 0300; 00CC; 00CC; lt; # LATIN CAPITAL LETTER I WITH GRAVE+00CD; 0069 0307 0301; 00CD; 00CD; lt; # LATIN CAPITAL LETTER I WITH ACUTE+0128; 0069 0307 0303; 0128; 0128; lt; # LATIN CAPITAL LETTER I WITH TILDE++# ================================================================================++# Turkish and Azeri++# I and i-dotless; I-dot and i are case pairs in Turkish and Azeri+# The following rules handle those cases.++0130; 0069; 0130; 0130; tr; # LATIN CAPITAL LETTER I WITH DOT ABOVE+0130; 0069; 0130; 0130; az; # LATIN CAPITAL LETTER I WITH DOT ABOVE++# When lowercasing, remove dot_above in the sequence I + dot_above, which will turn into i.+# This matches the behavior of the canonically equivalent I-dot_above++0307; ; 0307; 0307; tr After_I; # COMBINING DOT ABOVE+0307; ; 0307; 0307; az After_I; # COMBINING DOT ABOVE++# When lowercasing, unless an I is before a dot_above, it turns into a dotless i.++0049; 0131; 0049; 0049; tr Not_Before_Dot; # LATIN CAPITAL LETTER I+0049; 0131; 0049; 0049; az Not_Before_Dot; # LATIN CAPITAL LETTER I++# When uppercasing, i turns into a dotted capital I++0069; 0069; 0130; 0130; tr; # LATIN SMALL LETTER I+0069; 0069; 0130; 0130; az; # LATIN SMALL LETTER I++# Note: the following case is already in the UnicodeData file.++# 0131; 0131; 0049; 0049; tr; # LATIN SMALL LETTER DOTLESS I++# EOF+
+ tests/Makefile view
@@ -0,0 +1,69 @@+version := $(shell awk '/^version:/{print $$2}' ../text.cabal)+ghc := ghc+ghc-opt-flags = -O0+ghc-base-flags := -funbox-strict-fields -package criterion \+ -package bytestring -package QuickCheck -package test-framework \+ -package test-framework-quickcheck -ignore-package text \+ -fno-ignore-asserts+ghc-base-flags += -Wall -fno-warn-orphans -fno-warn-missing-signatures+ghc-flags := $(ghc-base-flags) -i../dist/build -package-name text-$(version)+ghc-hpc-flags := $(ghc-base-flags) -fhpc -fno-ignore-asserts -odir hpcdir \+ -hidir hpcdir -i..+lib := ../dist/build/libHStext-$(version).a+lib-srcs := $(shell grep '^ *Data' ../text.cabal | \+ sed -e 's,\.,/,g' -e 's,$$,.hs,')++cabal := $(shell which cabal 2>/dev/null)++all: qc coverage++lib: $(lib)++$(lib): $(lib-srcs:%=../%)+ifeq ($(cabal),)+ cd .. && runghc Setup configure --user --prefix=$(HOME)+ cd .. && runghc Setup build+else+ cd .. && cabal configure+ cd .. && cabal build+endif++Properties.o: QuickCheckUtils.o SlowFunctions.o++QuickCheckUtils.o: $(lib)++qc: Properties.o QuickCheckUtils.o SlowFunctions.o+ $(ghc) $(ghc-flags) -threaded -o $@ $^ $(lib)++sb: SearchBench.o+ $(ghc) $(ghc-flags) -threaded -o $@ $^ $(lib)++qc-hpc: Properties.hs QuickCheckUtils.hs $(lib-srcs:%=../%)+ -mkdir -p hpcdir+ @rm -f $@.tix+ $(ghc) $(ghc-hpc-flags) $(ghc-opt-flags) -ihpcdir \+ --make -threaded -o $@ $<++coverage: qc-hpc-html/hpc_index.html++qc-hpc-html/hpc_index.html: qc-hpc+ ./qc-hpc -a 100 +RTS -N2+ hpc markup qc-hpc --exclude=Main --exclude=Properties \+ --exclude=Data.Text.Fusion.CaseMapping \+ --exclude=QuickCheckUtils --srcdir=.. --srcdir=. --destdir=$(dir $@)++SearchBench.o: ghc-opt-flags = -O+%.o: %.hs+ $(ghc) $(ghc-flags) $(ghc-opt-flags) -c -o $@ $<++hpcdir/%.o: %.hs+ $(ghc) $(ghc-hpc-flags) $(ghc-opt-flags) --make -c -o $@ $<++.PHONY: testdata+testdata: text-testdata.tar.bz2++text-testdata.tar.bz2:+ curl -O http://projects.haskell.org/text/text-testdata.tar.bz2++clean:+ -rm -rf *.o *.hi *.tix qc qc-hpc hpcdir .hpc qc-hpc-html
+ tests/Properties.hs view
@@ -0,0 +1,888 @@+{-# LANGUAGE BangPatterns, FlexibleInstances, OverloadedStrings,+ ScopedTypeVariables, TypeSynonymInstances #-}+{-# OPTIONS_GHC -fno-enable-rewrite-rules #-}++import Test.QuickCheck hiding (evaluate)+import Text.Show.Functions ()++import qualified Data.Bits as Bits (shiftL, shiftR)+import Data.Char (chr, isLower, isSpace, isUpper, ord)+import Data.Monoid (Monoid(..))+import Data.String (fromString)+import Debug.Trace (trace)+import Control.Arrow ((***), second)+import Data.Word (Word8, Word16, Word32)+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Encoding as E+import Control.Exception (SomeException, evaluate, try)+import qualified Data.Text.Fusion as S+import qualified Data.Text.Fusion.Common as S+import Data.Text.Fusion.Size+import qualified Data.Text.Lazy.Encoding as EL+import qualified Data.Text.Lazy.Fusion as SL+import qualified Data.Text.UnsafeShift as U+import qualified Data.List as L+import Prelude hiding (replicate)+import System.IO.Unsafe (unsafePerformIO)+import Test.Framework (defaultMain, testGroup)+import Test.Framework.Providers.QuickCheck (testProperty)+import Data.Text.Search (indices)+import qualified Data.Text.Lazy.Search as S (indices)+import qualified SlowFunctions as Slow++import QuickCheckUtils (NotEmpty(..), small)++-- Ensure that two potentially bottom values (in the sense of crashing+-- for some inputs, not looping infinitely) either both crash, or both+-- give comparable results for some input.+(=^=) :: (Eq a, Show a) => a -> a -> Bool+{-# NOINLINE (=^=) #-}+i =^= j = unsafePerformIO $ do+ x <- try (evaluate i)+ y <- try (evaluate j)+ case (x,y) of+ (Left (_ :: SomeException), Left (_ :: SomeException))+ -> return True+ (Right a, Right b) -> return (a == b)+ e -> trace ("*** Divergence: " ++ show e) return False+infix 4 =^=++t_pack_unpack = (T.unpack . T.pack) `eq` id+tl_pack_unpack = (TL.unpack . TL.pack) `eq` id+t_stream_unstream = (S.unstream . S.stream) `eq` id+tl_stream_unstream = (SL.unstream . SL.stream) `eq` id+t_reverse_stream t = (S.reverse . S.reverseStream) t == t+t_singleton c = [c] == (T.unpack . T.singleton) c+tl_singleton c = [c] == (TL.unpack . TL.singleton) c+tl_unstreamChunks x = f 11 x == f 1000 x+ where f n = SL.unstreamChunks n . S.streamList+tl_chunk_unchunk = (TL.fromChunks . TL.toChunks) `eq` id++t_ascii t = E.decodeASCII (E.encodeUtf8 a) == a+ where a = T.map (\c -> chr (ord c `mod` 128)) t+t_utf8 = (E.decodeUtf8 . E.encodeUtf8) `eq` id+tl_utf8 = (EL.decodeUtf8 . EL.encodeUtf8) `eq` id+t_utf16LE = (E.decodeUtf16LE . E.encodeUtf16LE) `eq` id+t_utf16BE = (E.decodeUtf16BE . E.encodeUtf16BE) `eq` id+t_utf32LE = (E.decodeUtf32LE . E.encodeUtf32LE) `eq` id+t_utf32BE = (E.decodeUtf32BE . E.encodeUtf32BE) `eq` id++class Stringy s where+ packS :: String -> s+ unpackS :: s -> String+ splitAtS :: Int -> s -> (s,s)+ packSChunkSize :: Int -> String -> s+ packSChunkSize _ = packS++instance Stringy String where+ packS = id+ unpackS = id+ splitAtS = splitAt++instance Stringy (S.Stream Char) where+ packS = S.streamList+ unpackS = S.unstreamList+ splitAtS n s = (S.take n s, S.drop n s)++instance Stringy T.Text where+ packS = T.pack+ unpackS = T.unpack+ splitAtS = T.splitAt++instance Stringy TL.Text where+ packSChunkSize k = SL.unstreamChunks k . S.streamList+ packS = TL.pack+ unpackS = TL.unpack+ splitAtS = TL.splitAt . fromIntegral++-- Do two functions give the same answer?+eq :: (Eq a, Show a) => (t -> a) -> (t -> a) -> t -> Bool+eq a b s = a s =^= b s++-- What about with the RHS packed?+eqP :: (Eq a, Show a, Stringy s) =>+ (String -> a) -> (s -> a) -> String -> Word8 -> Bool+eqP f g s w = eql "orig" (f s) (g t) &&+ eql "mini" (f s) (g mini) &&+ eql "head" (f sa) (g ta) &&+ eql "tail" (f sb) (g tb)+ where t = packS s+ mini = packSChunkSize 10 s+ (sa,sb) = splitAt m s+ (ta,tb) = splitAtS m t+ l = length s+ m | l == 0 = n+ | otherwise = n `mod` l+ n = fromIntegral w+ eql d a b | a =^= b = True+ | otherwise = trace (d ++ ": " ++ show a ++ " /= " ++ show b) False++-- For tests that have O(n^2) running times or input sizes, resize+-- their inputs to the square root of the originals.+unsquare :: (Arbitrary a, Show a, Testable b) => (a -> b) -> Property+unsquare = forAll . sized $ \n -> resize (smallish n) arbitrary+ where smallish = round . (sqrt :: Double -> Double) . fromIntegral++s_Eq s = (s==) `eq` ((S.streamList s==) . S.streamList)+ where _types = s :: String+sf_Eq p s =+ ((L.filter p s==) . L.filter p) `eq`+ (((S.filter p $ S.streamList s)==) . S.filter p . S.streamList)+t_Eq s = (s==) `eq` ((T.pack s==) . T.pack)+tl_Eq s = (s==) `eq` ((TL.pack s==) . TL.pack)+s_Ord s = (compare s) `eq` (compare (S.streamList s) . S.streamList)+ where _types = s :: String+sf_Ord p s =+ ((compare $ L.filter p s) . L.filter p) `eq`+ (compare (S.filter p $ S.streamList s) . S.filter p . S.streamList)+t_Ord s = (compare s) `eq` (compare (T.pack s) . T.pack)+tl_Ord s = (compare s) `eq` (compare (TL.pack s) . TL.pack)+t_Read = id `eq` (T.unpack . read . show)+tl_Read = id `eq` (TL.unpack . read . show)+t_Show = show `eq` (show . T.pack)+tl_Show = show `eq` (show . TL.pack)+t_mappend s = mappend s`eqP` (unpackS . mappend (T.pack s))+tl_mappend s = mappend s`eqP` (unpackS . mappend (TL.pack s))+t_mconcat = unsquare (mconcat `eq` (unpackS . mconcat . L.map T.pack))+tl_mconcat = unsquare (mconcat `eq` (unpackS . mconcat . L.map TL.pack))+t_IsString = fromString `eqP` (T.unpack . fromString)+tl_IsString = fromString `eqP` (TL.unpack . fromString)++s_cons x = (x:) `eqP` (unpackS . S.cons x)+s_cons_s x = (x:) `eqP` (unpackS . S.unstream . S.cons x)+sf_cons p x = ((x:) . L.filter p) `eqP` (unpackS . S.cons x . S.filter p)+t_cons x = (x:) `eqP` (unpackS . T.cons x)+tl_cons x = (x:) `eqP` (unpackS . TL.cons x)+s_snoc x = (++ [x]) `eqP` (unpackS . (flip S.snoc) x)+t_snoc x = (++ [x]) `eqP` (unpackS . (flip T.snoc) x)+tl_snoc x = (++ [x]) `eqP` (unpackS . (flip TL.snoc) x)+s_append s = (s++) `eqP` (unpackS . S.append (S.streamList s))+s_append_s s = (s++) `eqP` (unpackS . S.unstream . S.append (S.streamList s))+sf_append p s = (L.filter p s++) `eqP` (unpackS . S.append (S.filter p $ S.streamList s))+t_append s = (s++) `eqP` (unpackS . T.append (packS s))++uncons (x:xs) = Just (x,xs)+uncons _ = Nothing++s_uncons = uncons `eqP` (fmap (second unpackS) . S.uncons)+sf_uncons p = (uncons . L.filter p) `eqP` (fmap (second unpackS) . S.uncons . S.filter p)+t_uncons = uncons `eqP` (fmap (second unpackS) . T.uncons)+tl_uncons = uncons `eqP` (fmap (second unpackS) . TL.uncons)+s_head = head `eqP` S.head+sf_head p = (head . L.filter p) `eqP` (S.head . S.filter p)+t_head = head `eqP` T.head+tl_head = head `eqP` TL.head+s_last = last `eqP` S.last+sf_last p = (last . L.filter p) `eqP` (S.last . S.filter p)+t_last = last `eqP` T.last+tl_last = last `eqP` TL.last+s_tail = tail `eqP` (unpackS . S.tail)+s_tail_s = tail `eqP` (unpackS . S.unstream . S.tail)+sf_tail p = (tail . L.filter p) `eqP` (unpackS . S.tail . S.filter p)+t_tail = tail `eqP` (unpackS . T.tail)+tl_tail = tail `eqP` (unpackS . TL.tail)+s_init = init `eqP` (unpackS . S.init)+s_init_s = init `eqP` (unpackS . S.unstream . S.init)+sf_init p = (init . L.filter p) `eqP` (unpackS . S.init . S.filter p)+t_init = init `eqP` (unpackS . T.init)+tl_init = init `eqP` (unpackS . TL.init)+s_null = null `eqP` S.null+sf_null p = (null . L.filter p) `eqP` (S.null . S.filter p)+t_null = null `eqP` T.null+tl_null = null `eqP` TL.null+s_length = length `eqP` S.length+sf_length p = (length . L.filter p) `eqP` (S.length . S.filter p)+t_length = length `eqP` T.length+tl_length = length `eqP` (fromIntegral . TL.length)++s_map f = map f `eqP` (unpackS . S.map f)+s_map_s f = map f `eqP` (unpackS . S.unstream . S.map f)+sf_map p f = (map f . L.filter p) `eqP` (unpackS . S.map f . S.filter p)+t_map f = map f `eqP` (unpackS . T.map f)+tl_map f = map f `eqP` (unpackS . TL.map f)+t_intercalate c = unsquare (L.intercalate c `eq` (unpackS . T.intercalate (packS c) . map packS))+tl_intercalate c = unsquare (L.intercalate c `eq` (unpackS . TL.intercalate (TL.pack c) . map TL.pack))+s_intersperse c = L.intersperse c `eqP` (unpackS . S.intersperse c)+s_intersperse_s c = L.intersperse c `eqP` (unpackS . S.unstream . S.intersperse c)+sf_intersperse p c= (L.intersperse c . L.filter p) `eqP` (unpackS . S.intersperse c . S.filter p)+t_intersperse c = L.intersperse c `eqP` (unpackS . T.intersperse c)+tl_intersperse c = L.intersperse c `eqP` (unpackS . TL.intersperse c)+t_transpose = unsquare (L.transpose `eq` (map unpackS . T.transpose . map packS))+tl_transpose = unsquare (L.transpose `eq` (map unpackS . TL.transpose . map TL.pack))+t_reverse = L.reverse `eqP` (unpackS . T.reverse)+tl_reverse = L.reverse `eqP` (unpackS . TL.reverse)+t_reverse_short n = L.reverse `eqP` (unpackS . S.reverse . shorten n . S.stream)++t_replace s d = (L.intercalate d . split s) `eqP` (unpackS . T.replace (T.pack s) (T.pack d))+tl_replace s d = (L.intercalate d . split s) `eqP` (unpackS . TL.replace (TL.pack s) (TL.pack d))++split :: (Eq a) => [a] -> [a] -> [[a]]+split pat src0+ | l == 0 = error "empty"+ | otherwise = go src0+ where+ l = length pat+ go src = search 0 src+ where+ search _ [] = [src]+ search !n s@(_:s')+ | pat `L.isPrefixOf` s = take n src : go (drop l s)+ | otherwise = search (n+1) s'++s_toCaseFold_length xs = S.length (S.toCaseFold s) >= length xs+ where s = S.streamList xs+sf_toCaseFold_length p xs =+ (S.length . S.toCaseFold . S.filter p $ s) >= (length . L.filter p $ xs)+ where s = S.streamList xs+t_toCaseFold_length t = T.length (T.toCaseFold t) >= T.length t+tl_toCaseFold_length t = TL.length (TL.toCaseFold t) >= TL.length t+t_toLower_length t = T.length (T.toLower t) >= T.length t+t_toLower_lower t = p (T.toLower t) >= p t+ where p = T.length . T.filter isLower+tl_toLower_lower t = p (TL.toLower t) >= p t+ where p = TL.length . TL.filter isLower+t_toUpper_length t = T.length (T.toUpper t) >= T.length t+t_toUpper_upper t = p (T.toUpper t) >= p t+ where p = T.length . T.filter isUpper+tl_toUpper_upper t = p (TL.toUpper t) >= p t+ where p = TL.length . TL.filter isUpper++justifyLeft k c s = s ++ L.replicate (k - length s) c+justifyRight m n s = L.replicate (m - length s) n ++ s++s_justifyLeft k c = justifyLeft k c `eqP` (unpackS . S.justifyLeftI k c)+s_justifyLeft_s k c = justifyLeft k c `eqP` (unpackS . S.unstream . S.justifyLeftI k c)+sf_justifyLeft p k c =+ (justifyLeft k c . L.filter p) `eqP` (unpackS . S.justifyLeftI k c . S.filter p)+t_justifyLeft k c = justifyLeft k c `eqP` (unpackS . T.justifyLeft k c)+tl_justifyLeft k c = justifyLeft k c `eqP` (unpackS . TL.justifyLeft (fromIntegral k) c)+t_justifyRight k c = justifyRight k c `eqP` (unpackS . T.justifyRight k c)+tl_justifyRight k c = justifyRight k c `eqP` (unpackS . TL.justifyRight (fromIntegral k) c)++sf_foldl p f z = (L.foldl f z . L.filter p) `eqP` (S.foldl f z . S.filter p)+ where _types = f :: Char -> Char -> Char+t_foldl f z = L.foldl f z `eqP` (T.foldl f z)+ where _types = f :: Char -> Char -> Char+tl_foldl f z = L.foldl f z `eqP` (TL.foldl f z)+ where _types = f :: Char -> Char -> Char+sf_foldl' p f z = (L.foldl' f z . L.filter p) `eqP` (S.foldl' f z . S.filter p)+ where _types = f :: Char -> Char -> Char+t_foldl' f z = L.foldl' f z `eqP` T.foldl' f z+ where _types = f :: Char -> Char -> Char+tl_foldl' f z = L.foldl' f z `eqP` TL.foldl' f z+ where _types = f :: Char -> Char -> Char+sf_foldl1 p f = (L.foldl1 f . L.filter p) `eqP` (S.foldl1 f . S.filter p)+t_foldl1 f = L.foldl1 f `eqP` T.foldl1 f+tl_foldl1 f = L.foldl1 f `eqP` TL.foldl1 f+sf_foldl1' p f = (L.foldl1' f . L.filter p) `eqP` (S.foldl1' f . S.filter p)+t_foldl1' f = L.foldl1' f `eqP` T.foldl1' f+tl_foldl1' f = L.foldl1' f `eqP` TL.foldl1' f+sf_foldr p f z = (L.foldr f z . L.filter p) `eqP` (S.foldr f z . S.filter p)+ where _types = f :: Char -> Char -> Char+t_foldr f z = L.foldr f z `eqP` T.foldr f z+ where _types = f :: Char -> Char -> Char+tl_foldr f z = L.foldr f z `eqP` TL.foldr f z+ where _types = f :: Char -> Char -> Char+sf_foldr1 p f = (L.foldr1 f . L.filter p) `eqP` (S.foldr1 f . S.filter p)+t_foldr1 f = L.foldr1 f `eqP` T.foldr1 f+tl_foldr1 f = L.foldr1 f `eqP` TL.foldr1 f++s_concat_s = unsquare (L.concat `eq` (unpackS . S.unstream . S.concat . map packS))+sf_concat p = unsquare ((L.concat . map (L.filter p)) `eq` (unpackS . S.concat . map (S.filter p . packS)))+t_concat = unsquare (L.concat `eq` (unpackS . T.concat . map packS))+tl_concat = unsquare (L.concat `eq` (unpackS . TL.concat . map TL.pack))+sf_concatMap p f = unsquare ((L.concatMap f . L.filter p) `eqP` (unpackS . S.concatMap (packS . f) . S.filter p))+t_concatMap f = unsquare (L.concatMap f `eqP` (unpackS . T.concatMap (packS . f)))+tl_concatMap f = unsquare (L.concatMap f `eqP` (unpackS . TL.concatMap (TL.pack . f)))+sf_any q p = (L.any p . L.filter q) `eqP` (S.any p . S.filter q)+t_any p = L.any p `eqP` T.any p+tl_any p = L.any p `eqP` TL.any p+sf_all q p = (L.all p . L.filter q) `eqP` (S.all p . S.filter q)+t_all p = L.all p `eqP` T.all p+tl_all p = L.all p `eqP` TL.all p+sf_maximum p = (L.maximum . L.filter p) `eqP` (S.maximum . S.filter p)+t_maximum = L.maximum `eqP` T.maximum+tl_maximum = L.maximum `eqP` TL.maximum+sf_minimum p = (L.minimum . L.filter p) `eqP` (S.minimum . S.filter p)+t_minimum = L.minimum `eqP` T.minimum+tl_minimum = L.minimum `eqP` TL.minimum++sf_scanl p f z = (L.scanl f z . L.filter p) `eqP` (unpackS . S.scanl f z . S.filter p)+t_scanl f z = L.scanl f z `eqP` (unpackS . T.scanl f z)+tl_scanl f z = L.scanl f z `eqP` (unpackS . TL.scanl f z)+t_scanl1 f = L.scanl1 f `eqP` (unpackS . T.scanl1 f)+tl_scanl1 f = L.scanl1 f `eqP` (unpackS . TL.scanl1 f)+t_scanr f z = L.scanr f z `eqP` (unpackS . T.scanr f z)+tl_scanr f z = L.scanr f z `eqP` (unpackS . TL.scanr f z)+t_scanr1 f = L.scanr1 f `eqP` (unpackS . T.scanr1 f)+tl_scanr1 f = L.scanr1 f `eqP` (unpackS . TL.scanr1 f)++t_mapAccumL f z = unsquare (L.mapAccumL f z `eqP` (second unpackS . T.mapAccumL f z))+ where _types = f :: Int -> Char -> (Int,Char)+tl_mapAccumL f z = unsquare (L.mapAccumL f z `eqP` (second unpackS . TL.mapAccumL f z))+ where _types = f :: Int -> Char -> (Int,Char)+t_mapAccumR f z = unsquare (L.mapAccumR f z `eqP` (second unpackS . T.mapAccumR f z))+ where _types = f :: Int -> Char -> (Int,Char)+tl_mapAccumR f z = unsquare (L.mapAccumR f z `eqP` (second unpackS . TL.mapAccumR f z))+ where _types = f :: Int -> Char -> (Int,Char)++replicate n l = concat (L.replicate n l)++t_replicate n = replicate n `eq` (unpackS . T.replicate n . packS)+tl_replicate n = replicate n `eq` (unpackS . TL.replicate (fromIntegral n) . packS)++unf :: Int -> Char -> Maybe (Char, Char)+unf n c | fromEnum c * 100 > n = Nothing+ | otherwise = Just (c, succ c)++t_unfoldr n = L.unfoldr (unf n) `eq` (unpackS . T.unfoldr (unf n))+tl_unfoldr n = L.unfoldr (unf n) `eq` (unpackS . TL.unfoldr (unf n))+t_unfoldrN n m = (L.take n . L.unfoldr (unf m)) `eq`+ (unpackS . T.unfoldrN n (unf m))+tl_unfoldrN n m = (L.take n . L.unfoldr (unf m)) `eq`+ (unpackS . TL.unfoldrN (fromIntegral n) (unf m))++unpack2 :: (Stringy s) => (s,s) -> (String,String)+unpack2 = unpackS *** unpackS++s_take n = L.take n `eqP` (unpackS . S.take n)+s_take_s m = L.take n `eqP` (unpackS . S.unstream . S.take n)+ where n = small m+sf_take p n = (L.take n . L.filter p) `eqP` (unpackS . S.take n . S.filter p)+t_take n = L.take n `eqP` (unpackS . T.take n)+tl_take n = L.take n `eqP` (unpackS . TL.take (fromIntegral n))+s_drop n = L.drop n `eqP` (unpackS . S.drop n)+s_drop_s m = L.drop n `eqP` (unpackS . S.unstream . S.drop n)+ where n = small m+sf_drop p n = (L.drop n . L.filter p) `eqP` (unpackS . S.drop n . S.filter p)+t_drop n = L.drop n `eqP` (unpackS . T.drop n)+tl_drop n = L.drop n `eqP` (unpackS . TL.drop (fromIntegral n))+s_take_drop m = (L.take n . L.drop n) `eqP` (unpackS . S.take n . S.drop n)+ where n = small m+s_take_drop_s m = (L.take n . L.drop n) `eqP` (unpackS . S.unstream . S.take n . S.drop n)+ where n = small m+s_takeWhile p = L.takeWhile p `eqP` (unpackS . S.takeWhile p)+s_takeWhile_s p = L.takeWhile p `eqP` (unpackS . S.unstream . S.takeWhile p)+sf_takeWhile q p = (L.takeWhile p . L.filter q) `eqP` (unpackS . S.takeWhile p . S.filter q)+t_takeWhile p = L.takeWhile p `eqP` (unpackS . T.takeWhile p)+tl_takeWhile p = L.takeWhile p `eqP` (unpackS . TL.takeWhile p)+s_dropWhile p = L.dropWhile p `eqP` (unpackS . S.dropWhile p)+s_dropWhile_s p = L.dropWhile p `eqP` (unpackS . S.unstream . S.dropWhile p)+sf_dropWhile q p = (L.dropWhile p . L.filter q) `eqP` (unpackS . S.dropWhile p . S.filter q)+t_dropWhile p = L.dropWhile p `eqP` (unpackS . T.dropWhile p)+tl_dropWhile p = L.dropWhile p `eqP` (unpackS . S.dropWhile p)+t_dropWhileEnd p = (L.reverse . L.dropWhile p . L.reverse) `eqP` (unpackS . T.dropWhileEnd p)+tl_dropWhileEnd p = (L.reverse . L.dropWhile p . L.reverse) `eqP` (unpackS . TL.dropWhileEnd p)+t_dropAround p = (L.dropWhile p . L.reverse . L.dropWhile p . L.reverse) `eqP` (unpackS . T.dropAround p)+tl_dropAround p = (L.dropWhile p . L.reverse . L.dropWhile p . L.reverse) `eqP` (unpackS . TL.dropAround p)+t_stripStart = T.dropWhile isSpace `eq` T.stripStart+tl_stripStart = TL.dropWhile isSpace `eq` TL.stripStart+t_stripEnd = T.dropWhileEnd isSpace `eq` T.stripEnd+tl_stripEnd = TL.dropWhileEnd isSpace `eq` TL.stripEnd+t_strip = T.dropAround isSpace `eq` T.strip+tl_strip = TL.dropAround isSpace `eq` TL.strip+t_splitAt n = L.splitAt n `eqP` (unpack2 . T.splitAt n)+tl_splitAt n = L.splitAt n `eqP` (unpack2 . TL.splitAt (fromIntegral n))+t_spanBy p = L.span p `eqP` (unpack2 . T.spanBy p)+tl_spanBy p = L.span p `eqP` (unpack2 . TL.spanBy p)++t_break_id s = squid `eq` (uncurry T.append . T.break s)+ where squid t | T.null s = error "empty"+ | otherwise = t+tl_break_id s = squid `eq` (uncurry TL.append . TL.break s)+ where squid t | TL.null s = error "empty"+ | otherwise = t+t_break_start (NotEmpty s) t = let (_,m) = T.break s t+ in T.null m || s `T.isPrefixOf` m+tl_break_start (NotEmpty s) t = let (_,m) = TL.break s t+ in TL.null m || s `TL.isPrefixOf` m+t_breakBy p = L.break p `eqP` (unpack2 . T.breakBy p)+tl_breakBy p = L.break p `eqP` (unpack2 . TL.breakBy p)+t_group = L.group `eqP` (map unpackS . T.group)+tl_group = L.group `eqP` (map unpackS . TL.group)+t_groupBy p = L.groupBy p `eqP` (map unpackS . T.groupBy p)+tl_groupBy p = L.groupBy p `eqP` (map unpackS . TL.groupBy p)+t_inits = L.inits `eqP` (map unpackS . T.inits)+tl_inits = L.inits `eqP` (map unpackS . TL.inits)+t_tails = L.tails `eqP` (map unpackS . T.tails)+tl_tails = L.tails `eqP` (map unpackS . TL.tails)++t_findSplit s t = (T.split s `eq` splitty) u+ where splitty v = case T.find s v of+ (x,xs) -> x : L.map (T.drop (T.length s) . fst) xs+ u = T.concat [t,s,t]+tl_findSplit s t = (TL.split s `eq` splitty) u+ where splitty v = case TL.find s v of+ (x,xs) -> x : L.map (TL.drop (TL.length s) . fst) xs+ u = TL.concat [t,s,t]+t_split_split s = unsquare ((T.split s `eq` Slow.split s) .+ T.intercalate s)+tl_split_split s = unsquare (((TL.split (chunkify s) . chunkify) `eq`+ (map chunkify . T.split s)) .+ T.intercalate s)+t_split_i (NotEmpty t) = id `eq` (T.intercalate t . T.split t)+tl_split_i (NotEmpty t) = id `eq` (TL.intercalate t . TL.split t)++t_splitBy p = splitBy p `eqP` (map unpackS . T.splitBy p)+t_splitBy_count c = (L.length . T.splitBy (==c)) `eq` ((1+) . T.count (T.singleton c))+t_splitBy_split c = T.splitBy (==c) `eq` T.split (T.singleton c)+tl_splitBy p = splitBy p `eqP` (map unpackS . TL.splitBy p)++splitBy :: (a -> Bool) -> [a] -> [[a]]+splitBy _ [] = [[]]+splitBy p xs = loop xs+ where loop s | null s' = [l]+ | otherwise = l : loop (tail s')+ where (l, s') = break p s++t_chunksOf_same_lengths k = all ((==k) . T.length) . ini . T.chunksOf k+ where ini [] = []+ ini xs = init xs++t_chunksOf_length k t = len == T.length t || (k <= 0 && len == 0)+ where len = L.sum . L.map T.length $ T.chunksOf k t++chunkify = TL.fromChunks . (:[])++tl_chunksOf k = T.chunksOf k `eq` (map (T.concat . TL.toChunks) . TL.chunksOf (fromIntegral k) . chunkify)++t_lines = L.lines `eqP` (map unpackS . T.lines)+tl_lines = L.lines `eqP` (map unpackS . TL.lines)+{-+t_lines' = lines' `eqP` (map unpackS . T.lines')+ where lines' "" = []+ lines' s = let (l, s') = break eol s+ in l : case s' of+ [] -> []+ ('\r':'\n':s'') -> lines' s''+ (_:s'') -> lines' s''+ eol c = c == '\r' || c == '\n'+-}+t_words = L.words `eqP` (map unpackS . T.words)++tl_words = L.words `eqP` (map unpackS . TL.words)+t_unlines = unsquare (L.unlines `eq` (unpackS . T.unlines . map packS))+tl_unlines = unsquare (L.unlines `eq` (unpackS . TL.unlines . map packS))+t_unwords = unsquare (L.unwords `eq` (unpackS . T.unwords . map packS))+tl_unwords = unsquare (L.unwords `eq` (unpackS . TL.unwords . map packS))++s_isPrefixOf s = L.isPrefixOf s `eqP` (S.isPrefixOf (S.stream $ packS s) . S.stream)+sf_isPrefixOf p s = (L.isPrefixOf s . L.filter p) `eqP` (S.isPrefixOf (S.stream $ packS s) . S.filter p . S.stream)+t_isPrefixOf s = L.isPrefixOf s`eqP` T.isPrefixOf (packS s)+tl_isPrefixOf s = L.isPrefixOf s`eqP` TL.isPrefixOf (packS s)+t_isSuffixOf s = L.isSuffixOf s`eqP` T.isSuffixOf (packS s)+tl_isSuffixOf s = L.isSuffixOf s`eqP` TL.isSuffixOf (packS s)+t_isInfixOf s = L.isInfixOf s `eqP` T.isInfixOf (packS s)+tl_isInfixOf s = L.isInfixOf s `eqP` TL.isInfixOf (packS s)++sf_elem p c = (L.elem c . L.filter p) `eqP` (S.elem c . S.filter p)+sf_filter q p = (L.filter p . L.filter q) `eqP` (unpackS . S.filter p . S.filter q)+t_filter p = L.filter p `eqP` (unpackS . T.filter p)+tl_filter p = L.filter p `eqP` (unpackS . TL.filter p)+sf_findBy q p = (L.find p . L.filter q) `eqP` (S.findBy p . S.filter q)+t_findBy p = L.find p `eqP` T.findBy p+tl_findBy p = L.find p `eqP` TL.findBy p+t_partition p = L.partition p `eqP` (unpack2 . T.partitionBy p)+tl_partition p = L.partition p `eqP` (unpack2 . TL.partitionBy p)++sf_index p s = forAll (choose (-l,l*2)) ((L.filter p s L.!!) `eq` S.index (S.filter p $ packS s))+ where l = L.length s+t_index s = forAll (choose (-l,l*2)) ((s L.!!) `eq` T.index (packS s))+ where l = L.length s++tl_index s = forAll (choose (-l,l*2)) ((s L.!!) `eq` (TL.index (packS s) . fromIntegral))+ where l = L.length s++t_findIndex p = L.findIndex p `eqP` T.findIndex p+t_count t = (subtract 1 . L.length . T.split t) `eq` T.count t+tl_count t = (subtract 1 . L.genericLength . TL.split t) `eq` TL.count t+t_zip s = L.zip s `eqP` T.zip (packS s)+tl_zip s = L.zip s `eqP` TL.zip (packS s)+sf_zipWith p c s = (L.zipWith c (L.filter p s) . L.filter p) `eqP` (unpackS . S.zipWith c (S.filter p $ packS s) . S.filter p)+t_zipWith c s = L.zipWith c s `eqP` (unpackS . T.zipWith c (packS s))+tl_zipWith c s = L.zipWith c s `eqP` (unpackS . TL.zipWith c (packS s))++t_indices = unsquare (\s -> Slow.indices s `eq` indices s)+tl_indices = unsquare (\s -> lazyIndices s `eq` S.indices s)+ where lazyIndices s t = map fromIntegral $ Slow.indices (conc s) (conc t)+ conc = T.concat . TL.toChunks+t_indices_occurs t = unsquare (\ts -> let s = T.intercalate t ts+ in Slow.indices t s == indices t s)++-- Bit shifts.+shiftL w = forAll (choose (0,width-1)) $ \k -> Bits.shiftL w k == U.shiftL w k+ where width = round (log (fromIntegral m) / log 2 :: Double)+ (m,_) = (maxBound, m == w)+shiftR w = forAll (choose (0,width-1)) $ \k -> Bits.shiftR w k == U.shiftR w k+ where width = round (log (fromIntegral m) / log 2 :: Double)+ (m,_) = (maxBound, m == w)++shiftL_Int = shiftL :: Int -> Property+shiftL_Word16 = shiftL :: Word16 -> Property+shiftL_Word32 = shiftL :: Word32 -> Property+shiftR_Int = shiftR :: Int -> Property+shiftR_Word16 = shiftR :: Word16 -> Property+shiftR_Word32 = shiftR :: Word32 -> Property++-- Regression tests.+s_filter_eq s = S.filter p t == S.streamList (filter p s)+ where p = (/= S.last t)+ t = S.streamList s++-- Make a stream appear shorter than it really is, to ensure that+-- functions that consume inaccurately sized streams behave+-- themselves.+shorten :: Int -> S.Stream a -> S.Stream a+shorten n t@(S.Stream arr off len)+ | n > 0 = S.Stream arr off (smaller (exactSize n) len) + | otherwise = t++main = defaultMain tests++tests = [+ testGroup "creation/elimination" [+ testProperty "t_pack_unpack" t_pack_unpack,+ testProperty "tl_pack_unpack" tl_pack_unpack,+ testProperty "t_stream_unstream" t_stream_unstream,+ testProperty "tl_stream_unstream" tl_stream_unstream,+ testProperty "t_reverse_stream" t_reverse_stream,+ testProperty "t_singleton" t_singleton,+ testProperty "tl_singleton" tl_singleton,+ testProperty "tl_unstreamChunks" tl_unstreamChunks,+ testProperty "tl_chunk_unchunk" tl_chunk_unchunk+ ],++ testGroup "transcoding" [+ testProperty "t_ascii" t_ascii,+ testProperty "t_utf8" t_utf8,+ testProperty "tl_utf8" tl_utf8,+ testProperty "t_utf16LE" t_utf16LE,+ testProperty "t_utf16BE" t_utf16BE,+ testProperty "t_utf32LE" t_utf32LE,+ testProperty "t_utf32BE" t_utf32BE+ ],++ testGroup "instances" [+ testProperty "s_Eq" s_Eq,+ testProperty "sf_Eq" sf_Eq,+ testProperty "t_Eq" t_Eq,+ testProperty "tl_Eq" tl_Eq,+ testProperty "s_Ord" s_Ord,+ testProperty "sf_Ord" sf_Ord,+ testProperty "t_Ord" t_Ord,+ testProperty "tl_Ord" tl_Ord,+ testProperty "t_Read" t_Read,+ testProperty "tl_Read" tl_Read,+ testProperty "t_Show" t_Show,+ testProperty "tl_Show" tl_Show,+ testProperty "t_mappend" t_mappend,+ testProperty "tl_mappend" tl_mappend,+ testProperty "t_mconcat" t_mconcat,+ testProperty "tl_mconcat" tl_mconcat,+ testProperty "t_IsString" t_IsString,+ testProperty "tl_IsString" tl_IsString+ ],++ testGroup "basics" [+ testProperty "s_cons" s_cons,+ testProperty "s_cons_s" s_cons_s,+ testProperty "sf_cons" sf_cons,+ testProperty "t_cons" t_cons,+ testProperty "tl_cons" tl_cons,+ testProperty "s_snoc" s_snoc,+ testProperty "t_snoc" t_snoc,+ testProperty "tl_snoc" tl_snoc,+ testProperty "s_append" s_append,+ testProperty "s_append_s" s_append_s,+ testProperty "sf_append" sf_append,+ testProperty "t_append" t_append,+ testProperty "s_uncons" s_uncons,+ testProperty "sf_uncons" sf_uncons,+ testProperty "t_uncons" t_uncons,+ testProperty "tl_uncons" tl_uncons,+ testProperty "s_head" s_head,+ testProperty "sf_head" sf_head,+ testProperty "t_head" t_head,+ testProperty "tl_head" tl_head,+ testProperty "s_last" s_last,+ testProperty "sf_last" sf_last,+ testProperty "t_last" t_last,+ testProperty "tl_last" tl_last,+ testProperty "s_tail" s_tail,+ testProperty "s_tail_s" s_tail_s,+ testProperty "sf_tail" sf_tail,+ testProperty "t_tail" t_tail,+ testProperty "tl_tail" tl_tail,+ testProperty "s_init" s_init,+ testProperty "s_init_s" s_init_s,+ testProperty "sf_init" sf_init,+ testProperty "t_init" t_init,+ testProperty "tl_init" tl_init,+ testProperty "s_null" s_null,+ testProperty "sf_null" sf_null,+ testProperty "t_null" t_null,+ testProperty "tl_null" tl_null,+ testProperty "s_length" s_length,+ testProperty "sf_length" sf_length,+ testProperty "t_length" t_length,+ testProperty "tl_length" tl_length+ ],++ testGroup "transformations" [+ testProperty "s_map" s_map,+ testProperty "s_map_s" s_map_s,+ testProperty "sf_map" sf_map,+ testProperty "t_map" t_map,+ testProperty "tl_map" tl_map,+ testProperty "t_intercalate" t_intercalate,+ testProperty "tl_intercalate" tl_intercalate,+ testProperty "s_intersperse" s_intersperse,+ testProperty "s_intersperse_s" s_intersperse_s,+ testProperty "sf_intersperse" sf_intersperse,+ testProperty "t_intersperse" t_intersperse,+ testProperty "tl_intersperse" tl_intersperse,+ testProperty "t_transpose" t_transpose,+ testProperty "tl_transpose" tl_transpose,+ testProperty "t_reverse" t_reverse,+ testProperty "tl_reverse" tl_reverse,+ testProperty "t_reverse_short" t_reverse_short,+ testProperty "t_replace" t_replace,+ testProperty "tl_replace" tl_replace,++ testGroup "case conversion" [+ testProperty "s_toCaseFold_length" s_toCaseFold_length,+ testProperty "sf_toCaseFold_length" sf_toCaseFold_length,+ testProperty "t_toCaseFold_length" t_toCaseFold_length,+ testProperty "tl_toCaseFold_length" tl_toCaseFold_length,+ testProperty "t_toLower_length" t_toLower_length,+ testProperty "t_toLower_lower" t_toLower_lower,+ testProperty "tl_toLower_lower" tl_toLower_lower,+ testProperty "t_toUpper_length" t_toUpper_length,+ testProperty "t_toUpper_upper" t_toUpper_upper,+ testProperty "tl_toUpper_upper" tl_toUpper_upper+ ],++ testGroup "justification" [+ testProperty "s_justifyLeft" s_justifyLeft,+ testProperty "s_justifyLeft_s" s_justifyLeft_s,+ testProperty "sf_justifyLeft" sf_justifyLeft,+ testProperty "t_justifyLeft" t_justifyLeft,+ testProperty "tl_justifyLeft" tl_justifyLeft,+ testProperty "t_justifyRight" t_justifyRight,+ testProperty "tl_justifyRight" tl_justifyRight+ ]+ ],++ testGroup "folds" [+ testProperty "sf_foldl" sf_foldl,+ testProperty "t_foldl" t_foldl,+ testProperty "tl_foldl" tl_foldl,+ testProperty "sf_foldl'" sf_foldl',+ testProperty "t_foldl'" t_foldl',+ testProperty "tl_foldl'" tl_foldl',+ testProperty "sf_foldl1" sf_foldl1,+ testProperty "t_foldl1" t_foldl1,+ testProperty "tl_foldl1" tl_foldl1,+ testProperty "t_foldl1'" t_foldl1',+ testProperty "sf_foldl1'" sf_foldl1',+ testProperty "tl_foldl1'" tl_foldl1',+ testProperty "sf_foldr" sf_foldr,+ testProperty "t_foldr" t_foldr,+ testProperty "tl_foldr" tl_foldr,+ testProperty "sf_foldr1" sf_foldr1,+ testProperty "t_foldr1" t_foldr1,+ testProperty "tl_foldr1" tl_foldr1,++ testGroup "special" [+ testProperty "s_concat_s" s_concat_s,+ testProperty "sf_concat" sf_concat,+ testProperty "t_concat" t_concat,+ testProperty "tl_concat" tl_concat,+ testProperty "sf_concatMap" sf_concatMap,+ testProperty "t_concatMap" t_concatMap,+ testProperty "tl_concatMap" tl_concatMap,+ testProperty "sf_any" sf_any,+ testProperty "t_any" t_any,+ testProperty "tl_any" tl_any,+ testProperty "sf_all" sf_all,+ testProperty "t_all" t_all,+ testProperty "tl_all" tl_all,+ testProperty "sf_maximum" sf_maximum,+ testProperty "t_maximum" t_maximum,+ testProperty "tl_maximum" tl_maximum,+ testProperty "sf_minimum" sf_minimum,+ testProperty "t_minimum" t_minimum,+ testProperty "tl_minimum" tl_minimum+ ]+ ],++ testGroup "construction" [+ testGroup "scans" [+ testProperty "sf_scanl" sf_scanl,+ testProperty "t_scanl" t_scanl,+ testProperty "tl_scanl" tl_scanl,+ testProperty "t_scanl1" t_scanl1,+ testProperty "tl_scanl1" tl_scanl1,+ testProperty "t_scanr" t_scanr,+ testProperty "tl_scanr" tl_scanr,+ testProperty "t_scanr1" t_scanr1,+ testProperty "tl_scanr1" tl_scanr1+ ],++ testGroup "mapAccum" [+ testProperty "t_mapAccumL" t_mapAccumL,+ testProperty "tl_mapAccumL" tl_mapAccumL,+ testProperty "t_mapAccumR" t_mapAccumR,+ testProperty "tl_mapAccumR" tl_mapAccumR+ ],++ testGroup "unfolds" [+ testProperty "t_replicate" t_replicate,+ testProperty "tl_replicate" tl_replicate,+ testProperty "t_unfoldr" t_unfoldr,+ testProperty "tl_unfoldr" tl_unfoldr,+ testProperty "t_unfoldrN" t_unfoldrN,+ testProperty "tl_unfoldrN" tl_unfoldrN+ ]+ ],++ testGroup "substrings" [+ testGroup "breaking" [+ testProperty "s_take" s_take,+ testProperty "s_take_s" s_take_s,+ testProperty "sf_take" sf_take,+ testProperty "t_take" t_take,+ testProperty "tl_take" tl_take,+ testProperty "s_drop" s_drop,+ testProperty "s_drop_s" s_drop_s,+ testProperty "sf_drop" sf_drop,+ testProperty "t_drop" t_drop,+ testProperty "tl_drop" tl_drop,+ testProperty "s_take_drop" s_take_drop,+ testProperty "s_take_drop_s" s_take_drop_s,+ testProperty "s_takeWhile" s_takeWhile,+ testProperty "s_takeWhile_s" s_takeWhile_s,+ testProperty "sf_takeWhile" sf_takeWhile,+ testProperty "t_takeWhile" t_takeWhile,+ testProperty "tl_takeWhile" tl_takeWhile,+ testProperty "sf_dropWhile" sf_dropWhile,+ testProperty "s_dropWhile" s_dropWhile,+ testProperty "s_dropWhile_s" s_dropWhile_s,+ testProperty "t_dropWhile" t_dropWhile,+ testProperty "tl_dropWhile" tl_dropWhile,+ testProperty "t_dropWhileEnd" t_dropWhileEnd,+ testProperty "tl_dropWhileEnd" tl_dropWhileEnd,+ testProperty "t_dropAround" t_dropAround,+ testProperty "tl_dropAround" tl_dropAround,+ testProperty "t_stripStart" t_stripStart,+ testProperty "tl_stripStart" tl_stripStart,+ testProperty "t_stripEnd" t_stripEnd,+ testProperty "tl_stripEnd" tl_stripEnd,+ testProperty "t_strip" t_strip,+ testProperty "tl_strip" tl_strip,+ testProperty "t_splitAt" t_splitAt,+ testProperty "tl_splitAt" tl_splitAt,+ testProperty "t_spanBy" t_spanBy,+ testProperty "tl_spanBy" tl_spanBy,+ testProperty "t_break_id" t_break_id,+ testProperty "tl_break_id" tl_break_id,+ testProperty "t_break_start" t_break_start,+ testProperty "tl_break_start" tl_break_start,+ testProperty "t_breakBy" t_breakBy,+ testProperty "tl_breakBy" tl_breakBy,+ testProperty "t_group" t_group,+ testProperty "tl_group" tl_group,+ testProperty "t_groupBy" t_groupBy,+ testProperty "tl_groupBy" tl_groupBy,+ testProperty "t_inits" t_inits,+ testProperty "tl_inits" tl_inits,+ testProperty "t_tails" t_tails,+ testProperty "tl_tails" tl_tails+ ],++ testGroup "breaking many" [+ testProperty "t_findSplit" t_findSplit,+ testProperty "tl_findSplit" tl_findSplit,+ testProperty "t_split_split" t_split_split,+ testProperty "tl_split_split" tl_split_split,+ testProperty "t_split_i" t_split_i,+ testProperty "tl_split_i" tl_split_i,+ testProperty "t_splitBy" t_splitBy,+ testProperty "t_splitBy_count" t_splitBy_count,+ testProperty "t_splitBy_split" t_splitBy_split,+ testProperty "tl_splitBy" tl_splitBy,+ testProperty "t_chunksOf_same_lengths" t_chunksOf_same_lengths,+ testProperty "t_chunksOf_length" t_chunksOf_length,+ testProperty "tl_chunksOf" tl_chunksOf+ ],++ testGroup "lines and words" [+ testProperty "t_lines" t_lines,+ testProperty "tl_lines" tl_lines,+ --testProperty "t_lines'" t_lines',+ testProperty "t_words" t_words,+ testProperty "tl_words" tl_words,+ testProperty "t_unlines" t_unlines,+ testProperty "tl_unlines" tl_unlines,+ testProperty "t_unwords" t_unwords,+ testProperty "tl_unwords" tl_unwords+ ]+ ],++ testGroup "predicates" [+ testProperty "s_isPrefixOf" s_isPrefixOf,+ testProperty "sf_isPrefixOf" sf_isPrefixOf,+ testProperty "t_isPrefixOf" t_isPrefixOf,+ testProperty "tl_isPrefixOf" tl_isPrefixOf,+ testProperty "t_isSuffixOf" t_isSuffixOf,+ testProperty "tl_isSuffixOf" tl_isSuffixOf,+ testProperty "t_isInfixOf" t_isInfixOf,+ testProperty "tl_isInfixOf" tl_isInfixOf+ ],++ testGroup "searching" [+ testProperty "sf_elem" sf_elem,+ testProperty "sf_filter" sf_filter,+ testProperty "t_filter" t_filter,+ testProperty "tl_filter" tl_filter,+ testProperty "sf_findBy" sf_findBy,+ testProperty "t_findBy" t_findBy,+ testProperty "tl_findBy" tl_findBy,+ testProperty "t_partition" t_partition,+ testProperty "tl_partition" tl_partition+ ],++ testGroup "indexing" [+ testProperty "sf_index" sf_index,+ testProperty "t_index" t_index,+ testProperty "tl_index" tl_index,+ testProperty "t_findIndex" t_findIndex,+ testProperty "t_count" t_count,+ testProperty "tl_count" tl_count,+ testProperty "t_indices" t_indices,+ testProperty "tl_indices" tl_indices,+ testProperty "t_indices_occurs" t_indices_occurs+ ],++ testGroup "zips" [+ testProperty "t_zip" t_zip,+ testProperty "tl_zip" tl_zip,+ testProperty "sf_zipWith" sf_zipWith,+ testProperty "t_zipWith" t_zipWith,+ testProperty "tl_zipWith" tl_zipWith+ ],++ testGroup "regressions" [+ testProperty "s_filter_eq" s_filter_eq+ ],++ testGroup "shifts" [+ testProperty "shiftL_Int" shiftL_Int,+ testProperty "shiftL_Word16" shiftL_Word16,+ testProperty "shiftL_Word32" shiftL_Word32,+ testProperty "shiftR_Int" shiftR_Int,+ testProperty "shiftR_Word16" shiftR_Word16,+ testProperty "shiftR_Word32" shiftR_Word32+ ]+ ]
+ tests/QuickCheckUtils.hs view
@@ -0,0 +1,128 @@+{-# LANGUAGE FlexibleInstances #-}++module QuickCheckUtils where++import Control.Arrow (first)+import Data.Int (Int64)+import Data.Word (Word8, Word16, Word32)+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import System.Random (Random(..), RandomGen)+import Test.QuickCheck (Arbitrary(..), choose, oneof, sized, variant, vector)+import qualified Data.ByteString as B++instance Random Int64 where+ randomR = integralRandomR+ random = randomR (minBound,maxBound)++instance Arbitrary Int64 where+ arbitrary = choose (minBound,maxBound)+ coarbitrary c = variant (fromEnum c `rem` 4)++instance Random Word8 where+ randomR = integralRandomR+ random = randomR (minBound,maxBound)++instance Arbitrary Word8 where+ arbitrary = choose (minBound,maxBound)+ coarbitrary c = variant (fromEnum c `rem` 4)++instance Arbitrary B.ByteString where+ arbitrary = B.pack `fmap` arbitrary+ coarbitrary s = coarbitrary (B.unpack s)++instance Random Word16 where+ randomR = integralRandomR+ random = randomR (minBound,maxBound)++instance Arbitrary Word16 where+ arbitrary = choose (minBound,maxBound)+ coarbitrary c = variant (fromEnum c `rem` 4)++instance Random Word32 where+ randomR = integralRandomR+ random = randomR (minBound,maxBound)++instance Arbitrary Word32 where+ arbitrary = choose (minBound,maxBound)+ coarbitrary c = variant (fromEnum c `rem` 4)++instance Arbitrary Char where+ arbitrary = oneof [choose ('\0','\55295'), choose ('\57344','\1114111')]+ coarbitrary c = variant (fromEnum c `rem` 4)++instance Arbitrary T.Text where+ arbitrary = T.pack `fmap` arbitrary+ coarbitrary s = coarbitrary (T.unpack s)++instance Arbitrary TL.Text where+ arbitrary = TL.pack `fmap` arbitrary+ coarbitrary s = coarbitrary (TL.unpack s)++newtype NotEmpty a = NotEmpty { notEmpty :: a }+ deriving (Eq, Ord, Show)++instance Functor NotEmpty where+ fmap f (NotEmpty a) = NotEmpty (f a)++instance Arbitrary a => Arbitrary (NotEmpty [a]) where+ arbitrary = sized (\n -> NotEmpty `fmap` (choose (1,n+1) >>= vector))+ coarbitrary = coarbitrary . notEmpty++instance Arbitrary (NotEmpty T.Text) where+ arbitrary = (fmap T.pack) `fmap` arbitrary+ coarbitrary = coarbitrary . notEmpty++instance Arbitrary (NotEmpty TL.Text) where+ arbitrary = (fmap TL.pack) `fmap` arbitrary+ coarbitrary = coarbitrary . notEmpty++instance Arbitrary (NotEmpty B.ByteString) where+ arbitrary = (fmap B.pack) `fmap` arbitrary+ coarbitrary = coarbitrary . notEmpty++data Small = S0 | S1 | S2 | S3 | S4 | S5 | S6 | S7+ | S8 | S9 | S10 | S11 | S12 | S13 | S14 | S15+ | S16 | S17 | S18 | S19 | S20 | S21 | S22 | S23+ | S24 | S25 | S26 | S27 | S28 | S29 | S30 | S31+ deriving (Eq, Ord, Enum, Bounded)++small :: Small -> Int+small = fromEnum++intf f a b = toEnum ((fromEnum a `f` fromEnum b) `mod` 32)++instance Show Small where+ show = show . fromEnum++instance Read Small where+ readsPrec n = map (first toEnum) . readsPrec n++instance Num Small where+ fromInteger = toEnum . fromIntegral+ signum _ = 1+ abs = id+ (+) = intf (+)+ (-) = intf (-)+ (*) = intf (*)++instance Real Small where+ toRational = toRational . fromEnum++instance Integral Small where+ toInteger = toInteger . fromEnum+ quotRem a b = (toEnum x, toEnum y)+ where (x, y) = fromEnum a `quotRem` fromEnum b++instance Random Small where+ randomR = integralRandomR+ random = randomR (minBound,maxBound)++instance Arbitrary Small where+ arbitrary = choose (minBound,maxBound)+ coarbitrary c = variant (fromEnum c `rem` 4)++integralRandomR :: (Integral a, RandomGen g) => (a,a) -> g -> (a,g)+integralRandomR (a,b) g = case randomR (fromIntegral a :: Integer,+ fromIntegral b :: Integer) g of+ (x,h) -> (fromIntegral x, h)
+ tests/SlowFunctions.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE BangPatterns #-}++module SlowFunctions+ (+ indices+ , split+ ) where++import qualified Data.Text as T+import Data.Text.Internal (Text(..))+import Data.Text.Unsafe (iter_, unsafeHead, unsafeTail)++indices :: T.Text -- ^ Substring to search for (@needle@)+ -> T.Text -- ^ Text to search in (@haystack@)+ -> [Int]+indices needle@(Text _narr _noff nlen) haystack@(Text harr hoff hlen)+ | T.null needle = []+ | otherwise = scan 0+ where+ scan i | i >= hlen = []+ | needle `T.isPrefixOf` t = i : scan (i+nlen)+ | otherwise = scan (i+d)+ where t = Text harr (hoff+i) (hlen-i)+ d = iter_ haystack i++split :: T.Text -- ^ Text to split on+ -> T.Text -- ^ Input text+ -> [T.Text]+split pat src0+ | T.null pat = error "split: empty"+ | l == 1 = T.splitBy (== (unsafeHead pat)) src0+ | otherwise = go src0+ where+ l = T.length pat+ go src = search 0 src+ where+ search !n !s+ | T.null s = [src] -- not found+ | pat `T.isPrefixOf` s = T.take n src : go (T.drop l s)+ | otherwise = search (n+1) (unsafeTail s)
text.cabal view
@@ -1,5 +1,5 @@ name: text-version: 0.4+version: 0.5 synopsis: An efficient packed Unicode text type description: An efficient packed Unicode text type. license: BSD3@@ -12,8 +12,25 @@ category: Data, Text build-type: Simple cabal-version: >= 1.2-extra-source-files: README+extra-source-files:+ README+ TODO+ scripts/ApiCompare.hs+ scripts/Arsec.hs+ scripts/CaseFolding.hs+ scripts/CaseFolding.txt+ scripts/CaseMapping.hs+ scripts/SpecialCasing.hs+ scripts/SpecialCasing.txt+ tests/Makefile+ tests/Properties.hs+ tests/QuickCheckUtils.hs+ tests/SlowFunctions.hs +flag developer+ description: operate in developer mode+ default: False+ library exposed-modules: Data.Text@@ -33,10 +50,13 @@ Data.Text.Fusion.CaseMapping Data.Text.Fusion.Common Data.Text.Fusion.Internal+ Data.Text.Fusion.Size Data.Text.Internal Data.Text.Lazy.Encoding.Fusion Data.Text.Lazy.Fusion Data.Text.Lazy.Internal+ Data.Text.Lazy.Search+ Data.Text.Search Data.Text.Unsafe Data.Text.UnsafeChar Data.Text.UnsafeShift@@ -54,3 +74,5 @@ ghc-options: -Wall -funbox-strict-fields -O2 if impl(ghc >= 6.8) ghc-options: -fwarn-tabs+ if flag(developer)+ ghc-options: -Werror