on c976329 help sign in
.hgtags+1
since splitsnapshots
unifiedsplit
@@ -64,3 +64,4 @@ f8a60279237c1c28e094868740d9188dd94fcc9e 1.2.0.0
64631fd055e27fa10983e17e9ad36d1b285b85c661 1.2.1.3
64631fd055e27fa10983e17e9ad36d1b285b85c661 1.2.1.3
658221a68ed5ec37028357df9c6c25f52320e54ad9 1.2.2.0
658221a68ed5ec37028357df9c6c25f52320e54ad9 1.2.2.0
66ce1c5ac65eb9f5580114b4e380092b05a485e95d 1.2.2.1
66ce1c5ac65eb9f5580114b4e380092b05a485e95d 1.2.2.1
67+d72c634a91ffe27ec5cd03921dd53efc8129d8f6 1.2.2.2
Data/Text.hs+13−1
@@ -60,6 +60,7 @@ module Data.Text
60 , snoc
60 , snoc
61 , append
61 , append
62 , uncons
62 , uncons
63+ , unsnoc
63 , head
64 , head
64 , last
65 , last
65 , tail
66 , tail
@@ -545,6 +546,17 @@ init (Text arr off len) | len <= 0 = emptyError "init"
545 unstream (S.init (stream t)) = init t
546 unstream (S.init (stream t)) = init t
546 #-}
547 #-}
547
548
549+-- | /O(1)/ Returns all but the last character and the last character of a
550+-- 'Text', or 'Nothing' if empty.
551+unsnoc :: Text -> Maybe (Text, Char)
552+unsnoc (Text arr off len)
553+ | len <= 0 = Nothing
554+ | n < 0xDC00 || n > 0xDFFF = Just (text arr off (len-1), unsafeChr n)
555+ | otherwise = Just (text arr off (len-2), U16.chr2 n0 n)
556+ where n = A.unsafeIndex arr (off+len-1)
557+ n0 = A.unsafeIndex arr (off+len-2)
558+{-# INLINE [1] unsnoc #-}
559+
548-- | /O(1)/ Tests whether a 'Text' is empty or not. Subject to
560-- | /O(1)/ Tests whether a 'Text' is empty or not. Subject to
549-- fusion.
561-- fusion.
550null :: Text -> Bool
562null :: Text -> Bool
@@ -1099,8 +1111,8 @@ takeEnd n t@(Text arr off len)
1099iterNEnd :: Int -> Text -> Int
1111iterNEnd :: Int -> Text -> Int
1100iterNEnd n t@(Text _arr _off len) = loop (len-1) n
1112iterNEnd n t@(Text _arr _off len) = loop (len-1) n
1101 where loop i !m
1113 where loop i !m
1114+ | m <= 0 = i+1
1102 | i <= 0 = 0
1115 | i <= 0 = 0
1103− | m <= 1 = i
1104 | otherwise = loop (i+d) (m-1)
1116 | otherwise = loop (i+d) (m-1)
1105 where d = reverseIter_ t i
1117 where d = reverseIter_ t i
1106
1118
Data/Text/Foreign.hs+1−1
@@ -108,7 +108,7 @@ takeWord16 (I16 n) t@(Text arr off len)
108 | n >= len || m >= len = t
108 | n >= len || m >= len = t
109 | otherwise = Text arr off m
109 | otherwise = Text arr off m
110 where
110 where
111− m | w < 0xDB00 || w > 0xD8FF = n
111+ m | w < 0xD800 || w > 0xDBFF = n
112 | otherwise = n+1
112 | otherwise = n+1
113 w = A.unsafeIndex arr (off+n-1)
113 w = A.unsafeIndex arr (off+n-1)
114
114
Data/Text/Internal/Fusion/CaseMapping.hs+164−4
@@ -1,10 +1,10 @@
1{-# LANGUAGE Rank2Types #-}
1{-# LANGUAGE Rank2Types #-}
2-- AUTOMATICALLY GENERATED - DO NOT EDIT
2-- AUTOMATICALLY GENERATED - DO NOT EDIT
3-- Generated by scripts/CaseMapping.hs
3-- Generated by scripts/CaseMapping.hs
4−-- CaseFolding-8.0.0.txt
4+-- CaseFolding-9.0.0.txt
5−-- Date: 2015-01-13, 18:16:36 GMT [MD]
5+-- Date: 2016-03-02, 18:54:54 GMT
6−-- SpecialCasing-8.0.0.txt
6+-- SpecialCasing-9.0.0.txt
7−-- Date: 2014-12-16, 23:08:04 GMT [MD]
7+-- Date: 2016-03-02, 18:55:13 GMT
8
8
9module Data.Text.Internal.Fusion.CaseMapping where
9module Data.Text.Internal.Fusion.CaseMapping where
10import Data.Char
10import Data.Char
@@ -371,6 +371,24 @@ foldMapping '\x13fb' s = Yield '\x13f3' (CC s '\x0000' '\x0000')
371foldMapping '\x13fc' s = Yield '\x13f4' (CC s '\x0000' '\x0000')
371foldMapping '\x13fc' s = Yield '\x13f4' (CC s '\x0000' '\x0000')
372-- CHEROKEE SMALL LETTER MV
372-- CHEROKEE SMALL LETTER MV
373foldMapping '\x13fd' s = Yield '\x13f5' (CC s '\x0000' '\x0000')
373foldMapping '\x13fd' s = Yield '\x13f5' (CC s '\x0000' '\x0000')
374+-- CYRILLIC SMALL LETTER ROUNDED VE
375+foldMapping '\x1c80' s = Yield '\x0432' (CC s '\x0000' '\x0000')
376+-- CYRILLIC SMALL LETTER LONG-LEGGED DE
377+foldMapping '\x1c81' s = Yield '\x0434' (CC s '\x0000' '\x0000')
378+-- CYRILLIC SMALL LETTER NARROW O
379+foldMapping '\x1c82' s = Yield '\x043e' (CC s '\x0000' '\x0000')
380+-- CYRILLIC SMALL LETTER WIDE ES
381+foldMapping '\x1c83' s = Yield '\x0441' (CC s '\x0000' '\x0000')
382+-- CYRILLIC SMALL LETTER TALL TE
383+foldMapping '\x1c84' s = Yield '\x0442' (CC s '\x0000' '\x0000')
384+-- CYRILLIC SMALL LETTER THREE-LEGGED TE
385+foldMapping '\x1c85' s = Yield '\x0442' (CC s '\x0000' '\x0000')
386+-- CYRILLIC SMALL LETTER TALL HARD SIGN
387+foldMapping '\x1c86' s = Yield '\x044a' (CC s '\x0000' '\x0000')
388+-- CYRILLIC SMALL LETTER TALL YAT
389+foldMapping '\x1c87' s = Yield '\x0463' (CC s '\x0000' '\x0000')
390+-- CYRILLIC SMALL LETTER UNBLENDED UK
391+foldMapping '\x1c88' s = Yield '\xa64b' (CC s '\x0000' '\x0000')
374-- LATIN SMALL LETTER H WITH LINE BELOW
392-- LATIN SMALL LETTER H WITH LINE BELOW
375foldMapping '\x1e96' s = Yield '\x0068' (CC s '\x0331' '\x0000')
393foldMapping '\x1e96' s = Yield '\x0068' (CC s '\x0331' '\x0000')
376-- LATIN SMALL LETTER T WITH DIAERESIS
394-- LATIN SMALL LETTER T WITH DIAERESIS
@@ -545,6 +563,8 @@ foldMapping '\x1ff6' s = Yield '\x03c9' (CC s '\x0342' '\x0000')
545foldMapping '\x1ff7' s = Yield '\x03c9' (CC s '\x0342' '\x03b9')
563foldMapping '\x1ff7' s = Yield '\x03c9' (CC s '\x0342' '\x03b9')
546-- GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
564-- GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
547foldMapping '\x1ffc' s = Yield '\x03c9' (CC s '\x03b9' '\x0000')
565foldMapping '\x1ffc' s = Yield '\x03c9' (CC s '\x03b9' '\x0000')
566+-- LATIN CAPITAL LETTER SMALL CAPITAL I
567+foldMapping '\xa7ae' s = Yield '\x026a' (CC s '\x0000' '\x0000')
548-- LATIN CAPITAL LETTER J WITH CROSSED-TAIL
568-- LATIN CAPITAL LETTER J WITH CROSSED-TAIL
549foldMapping '\xa7b2' s = Yield '\x029d' (CC s '\x0000' '\x0000')
569foldMapping '\xa7b2' s = Yield '\x029d' (CC s '\x0000' '\x0000')
550-- LATIN CAPITAL LETTER CHI
570-- LATIN CAPITAL LETTER CHI
@@ -737,6 +757,78 @@ foldMapping '\xfb15' s = Yield '\x0574' (CC s '\x056b' '\x0000')
737foldMapping '\xfb16' s = Yield '\x057e' (CC s '\x0576' '\x0000')
757foldMapping '\xfb16' s = Yield '\x057e' (CC s '\x0576' '\x0000')
738-- ARMENIAN SMALL LIGATURE MEN XEH
758-- ARMENIAN SMALL LIGATURE MEN XEH
739foldMapping '\xfb17' s = Yield '\x0574' (CC s '\x056d' '\x0000')
759foldMapping '\xfb17' s = Yield '\x0574' (CC s '\x056d' '\x0000')
760+-- OSAGE CAPITAL LETTER A
761+foldMapping '\x104b0' s = Yield '\x104d8' (CC s '\x0000' '\x0000')
762+-- OSAGE CAPITAL LETTER AI
763+foldMapping '\x104b1' s = Yield '\x104d9' (CC s '\x0000' '\x0000')
764+-- OSAGE CAPITAL LETTER AIN
765+foldMapping '\x104b2' s = Yield '\x104da' (CC s '\x0000' '\x0000')
766+-- OSAGE CAPITAL LETTER AH
767+foldMapping '\x104b3' s = Yield '\x104db' (CC s '\x0000' '\x0000')
768+-- OSAGE CAPITAL LETTER BRA
769+foldMapping '\x104b4' s = Yield '\x104dc' (CC s '\x0000' '\x0000')
770+-- OSAGE CAPITAL LETTER CHA
771+foldMapping '\x104b5' s = Yield '\x104dd' (CC s '\x0000' '\x0000')
772+-- OSAGE CAPITAL LETTER EHCHA
773+foldMapping '\x104b6' s = Yield '\x104de' (CC s '\x0000' '\x0000')
774+-- OSAGE CAPITAL LETTER E
775+foldMapping '\x104b7' s = Yield '\x104df' (CC s '\x0000' '\x0000')
776+-- OSAGE CAPITAL LETTER EIN
777+foldMapping '\x104b8' s = Yield '\x104e0' (CC s '\x0000' '\x0000')
778+-- OSAGE CAPITAL LETTER HA
779+foldMapping '\x104b9' s = Yield '\x104e1' (CC s '\x0000' '\x0000')
780+-- OSAGE CAPITAL LETTER HYA
781+foldMapping '\x104ba' s = Yield '\x104e2' (CC s '\x0000' '\x0000')
782+-- OSAGE CAPITAL LETTER I
783+foldMapping '\x104bb' s = Yield '\x104e3' (CC s '\x0000' '\x0000')
784+-- OSAGE CAPITAL LETTER KA
785+foldMapping '\x104bc' s = Yield '\x104e4' (CC s '\x0000' '\x0000')
786+-- OSAGE CAPITAL LETTER EHKA
787+foldMapping '\x104bd' s = Yield '\x104e5' (CC s '\x0000' '\x0000')
788+-- OSAGE CAPITAL LETTER KYA
789+foldMapping '\x104be' s = Yield '\x104e6' (CC s '\x0000' '\x0000')
790+-- OSAGE CAPITAL LETTER LA
791+foldMapping '\x104bf' s = Yield '\x104e7' (CC s '\x0000' '\x0000')
792+-- OSAGE CAPITAL LETTER MA
793+foldMapping '\x104c0' s = Yield '\x104e8' (CC s '\x0000' '\x0000')
794+-- OSAGE CAPITAL LETTER NA
795+foldMapping '\x104c1' s = Yield '\x104e9' (CC s '\x0000' '\x0000')
796+-- OSAGE CAPITAL LETTER O
797+foldMapping '\x104c2' s = Yield '\x104ea' (CC s '\x0000' '\x0000')
798+-- OSAGE CAPITAL LETTER OIN
799+foldMapping '\x104c3' s = Yield '\x104eb' (CC s '\x0000' '\x0000')
800+-- OSAGE CAPITAL LETTER PA
801+foldMapping '\x104c4' s = Yield '\x104ec' (CC s '\x0000' '\x0000')
802+-- OSAGE CAPITAL LETTER EHPA
803+foldMapping '\x104c5' s = Yield '\x104ed' (CC s '\x0000' '\x0000')
804+-- OSAGE CAPITAL LETTER SA
805+foldMapping '\x104c6' s = Yield '\x104ee' (CC s '\x0000' '\x0000')
806+-- OSAGE CAPITAL LETTER SHA
807+foldMapping '\x104c7' s = Yield '\x104ef' (CC s '\x0000' '\x0000')
808+-- OSAGE CAPITAL LETTER TA
809+foldMapping '\x104c8' s = Yield '\x104f0' (CC s '\x0000' '\x0000')
810+-- OSAGE CAPITAL LETTER EHTA
811+foldMapping '\x104c9' s = Yield '\x104f1' (CC s '\x0000' '\x0000')
812+-- OSAGE CAPITAL LETTER TSA
813+foldMapping '\x104ca' s = Yield '\x104f2' (CC s '\x0000' '\x0000')
814+-- OSAGE CAPITAL LETTER EHTSA
815+foldMapping '\x104cb' s = Yield '\x104f3' (CC s '\x0000' '\x0000')
816+-- OSAGE CAPITAL LETTER TSHA
817+foldMapping '\x104cc' s = Yield '\x104f4' (CC s '\x0000' '\x0000')
818+-- OSAGE CAPITAL LETTER DHA
819+foldMapping '\x104cd' s = Yield '\x104f5' (CC s '\x0000' '\x0000')
820+-- OSAGE CAPITAL LETTER U
821+foldMapping '\x104ce' s = Yield '\x104f6' (CC s '\x0000' '\x0000')
822+-- OSAGE CAPITAL LETTER WA
823+foldMapping '\x104cf' s = Yield '\x104f7' (CC s '\x0000' '\x0000')
824+-- OSAGE CAPITAL LETTER KHA
825+foldMapping '\x104d0' s = Yield '\x104f8' (CC s '\x0000' '\x0000')
826+-- OSAGE CAPITAL LETTER GHA
827+foldMapping '\x104d1' s = Yield '\x104f9' (CC s '\x0000' '\x0000')
828+-- OSAGE CAPITAL LETTER ZA
829+foldMapping '\x104d2' s = Yield '\x104fa' (CC s '\x0000' '\x0000')
830+-- OSAGE CAPITAL LETTER ZHA
831+foldMapping '\x104d3' s = Yield '\x104fb' (CC s '\x0000' '\x0000')
740-- OLD HUNGARIAN CAPITAL LETTER A
832-- OLD HUNGARIAN CAPITAL LETTER A
741foldMapping '\x10c80' s = Yield '\x10cc0' (CC s '\x0000' '\x0000')
833foldMapping '\x10c80' s = Yield '\x10cc0' (CC s '\x0000' '\x0000')
742-- OLD HUNGARIAN CAPITAL LETTER AA
834-- OLD HUNGARIAN CAPITAL LETTER AA
@@ -839,4 +931,72 @@ foldMapping '\x10cb0' s = Yield '\x10cf0' (CC s '\x0000' '\x0000')
839foldMapping '\x10cb1' s = Yield '\x10cf1' (CC s '\x0000' '\x0000')
931foldMapping '\x10cb1' s = Yield '\x10cf1' (CC s '\x0000' '\x0000')
840-- OLD HUNGARIAN CAPITAL LETTER US
932-- OLD HUNGARIAN CAPITAL LETTER US
841foldMapping '\x10cb2' s = Yield '\x10cf2' (CC s '\x0000' '\x0000')
933foldMapping '\x10cb2' s = Yield '\x10cf2' (CC s '\x0000' '\x0000')
934+-- ADLAM CAPITAL LETTER ALIF
935+foldMapping '\x1e900' s = Yield '\x1e922' (CC s '\x0000' '\x0000')
936+-- ADLAM CAPITAL LETTER DAALI
937+foldMapping '\x1e901' s = Yield '\x1e923' (CC s '\x0000' '\x0000')
938+-- ADLAM CAPITAL LETTER LAAM
939+foldMapping '\x1e902' s = Yield '\x1e924' (CC s '\x0000' '\x0000')
940+-- ADLAM CAPITAL LETTER MIIM
941+foldMapping '\x1e903' s = Yield '\x1e925' (CC s '\x0000' '\x0000')
942+-- ADLAM CAPITAL LETTER BA
943+foldMapping '\x1e904' s = Yield '\x1e926' (CC s '\x0000' '\x0000')
944+-- ADLAM CAPITAL LETTER SINNYIIYHE
945+foldMapping '\x1e905' s = Yield '\x1e927' (CC s '\x0000' '\x0000')
946+-- ADLAM CAPITAL LETTER PE
947+foldMapping '\x1e906' s = Yield '\x1e928' (CC s '\x0000' '\x0000')
948+-- ADLAM CAPITAL LETTER BHE
949+foldMapping '\x1e907' s = Yield '\x1e929' (CC s '\x0000' '\x0000')
950+-- ADLAM CAPITAL LETTER RA
951+foldMapping '\x1e908' s = Yield '\x1e92a' (CC s '\x0000' '\x0000')
952+-- ADLAM CAPITAL LETTER E
953+foldMapping '\x1e909' s = Yield '\x1e92b' (CC s '\x0000' '\x0000')
954+-- ADLAM CAPITAL LETTER FA
955+foldMapping '\x1e90a' s = Yield '\x1e92c' (CC s '\x0000' '\x0000')
956+-- ADLAM CAPITAL LETTER I
957+foldMapping '\x1e90b' s = Yield '\x1e92d' (CC s '\x0000' '\x0000')
958+-- ADLAM CAPITAL LETTER O
959+foldMapping '\x1e90c' s = Yield '\x1e92e' (CC s '\x0000' '\x0000')
960+-- ADLAM CAPITAL LETTER DHA
961+foldMapping '\x1e90d' s = Yield '\x1e92f' (CC s '\x0000' '\x0000')
962+-- ADLAM CAPITAL LETTER YHE
963+foldMapping '\x1e90e' s = Yield '\x1e930' (CC s '\x0000' '\x0000')
964+-- ADLAM CAPITAL LETTER WAW
965+foldMapping '\x1e90f' s = Yield '\x1e931' (CC s '\x0000' '\x0000')
966+-- ADLAM CAPITAL LETTER NUN
967+foldMapping '\x1e910' s = Yield '\x1e932' (CC s '\x0000' '\x0000')
968+-- ADLAM CAPITAL LETTER KAF
969+foldMapping '\x1e911' s = Yield '\x1e933' (CC s '\x0000' '\x0000')
970+-- ADLAM CAPITAL LETTER YA
971+foldMapping '\x1e912' s = Yield '\x1e934' (CC s '\x0000' '\x0000')
972+-- ADLAM CAPITAL LETTER U
973+foldMapping '\x1e913' s = Yield '\x1e935' (CC s '\x0000' '\x0000')
974+-- ADLAM CAPITAL LETTER JIIM
975+foldMapping '\x1e914' s = Yield '\x1e936' (CC s '\x0000' '\x0000')
976+-- ADLAM CAPITAL LETTER CHI
977+foldMapping '\x1e915' s = Yield '\x1e937' (CC s '\x0000' '\x0000')
978+-- ADLAM CAPITAL LETTER HA
979+foldMapping '\x1e916' s = Yield '\x1e938' (CC s '\x0000' '\x0000')
980+-- ADLAM CAPITAL LETTER QAAF
981+foldMapping '\x1e917' s = Yield '\x1e939' (CC s '\x0000' '\x0000')
982+-- ADLAM CAPITAL LETTER GA
983+foldMapping '\x1e918' s = Yield '\x1e93a' (CC s '\x0000' '\x0000')
984+-- ADLAM CAPITAL LETTER NYA
985+foldMapping '\x1e919' s = Yield '\x1e93b' (CC s '\x0000' '\x0000')
986+-- ADLAM CAPITAL LETTER TU
987+foldMapping '\x1e91a' s = Yield '\x1e93c' (CC s '\x0000' '\x0000')
988+-- ADLAM CAPITAL LETTER NHA
989+foldMapping '\x1e91b' s = Yield '\x1e93d' (CC s '\x0000' '\x0000')
990+-- ADLAM CAPITAL LETTER VA
991+foldMapping '\x1e91c' s = Yield '\x1e93e' (CC s '\x0000' '\x0000')
992+-- ADLAM CAPITAL LETTER KHA
993+foldMapping '\x1e91d' s = Yield '\x1e93f' (CC s '\x0000' '\x0000')
994+-- ADLAM CAPITAL LETTER GBE
995+foldMapping '\x1e91e' s = Yield '\x1e940' (CC s '\x0000' '\x0000')
996+-- ADLAM CAPITAL LETTER ZAL
997+foldMapping '\x1e91f' s = Yield '\x1e941' (CC s '\x0000' '\x0000')
998+-- ADLAM CAPITAL LETTER KPO
999+foldMapping '\x1e920' s = Yield '\x1e942' (CC s '\x0000' '\x0000')
1000+-- ADLAM CAPITAL LETTER SHA
1001+foldMapping '\x1e921' s = Yield '\x1e943' (CC s '\x0000' '\x0000')
842foldMapping c s = Yield (toLower c) (CC s '\0' '\0')
1002foldMapping c s = Yield (toLower c) (CC s '\0' '\0')
Data/Text/Internal/Fusion/Common.hs+10−9
@@ -107,7 +107,7 @@ import Prelude (Bool(..), Char, Eq(..), Int, Integral, Maybe(..),
107import qualified Data.List as L
107import qualified Data.List as L
108import qualified Prelude as P
108import qualified Prelude as P
109import Data.Bits (shiftL)
109import Data.Bits (shiftL)
110−import Data.Char (isLetter)
110+import Data.Char (isLetter, isSpace)
111import Data.Int (Int64)
111import Data.Int (Int64)
112import Data.Text.Internal.Fusion.Types
112import Data.Text.Internal.Fusion.Types
113import Data.Text.Internal.Fusion.CaseMapping (foldMapping, lowerMapping, titleMapping,
113import Data.Text.Internal.Fusion.CaseMapping (foldMapping, lowerMapping, titleMapping,
@@ -462,15 +462,16 @@ toTitle (Stream next0 s0 len) = Stream next (CC (False :*: s0) '\0' '\0') len
462 where
462 where
463 next (CC (letter :*: s) '\0' _) =
463 next (CC (letter :*: s) '\0' _) =
464 case next0 s of
464 case next0 s of
465− Done -> Done
465+ Done -> Done
466− Skip s' -> Skip (CC (letter :*: s') '\0' '\0')
466+ Skip s' -> Skip (CC (letter :*: s') '\0' '\0')
467 Yield c s'
467 Yield c s'
468− | letter' -> if letter
468+ | nonSpace -> if letter
469− then lowerMapping c (letter' :*: s')
469+ then lowerMapping c (nonSpace :*: s')
470− else titleMapping c (letter' :*: s')
470+ else titleMapping c (letter' :*: s')
471− | otherwise -> Yield c (CC (letter' :*: s') '\0' '\0')
471+ | otherwise -> Yield c (CC (letter' :*: s') '\0' '\0')
472+ where nonSpace = P.not (isSpace c)
472− where letter' = isLetter c
473+ letter' = isLetter c
473− next (CC s a b) = Yield a (CC s b '\0')
474+ next (CC s a b) = Yield a (CC s b '\0')
474{-# INLINE [0] toTitle #-}
475{-# INLINE [0] toTitle #-}
475
476
476data Justify i s = Just1 !i !s
477data Justify i s = Just1 !i !s
Data/Text/Lazy.hs+15−6
@@ -68,6 +68,7 @@ module Data.Text.Lazy
68 , snoc
68 , snoc
69 , append
69 , append
70 , uncons
70 , uncons
71+ , unsnoc
71 , head
72 , head
72 , last
73 , last
73 , tail
74 , tail
@@ -475,9 +476,7 @@ fromStrict t = chunk t Empty
475-- -----------------------------------------------------------------------------
476-- -----------------------------------------------------------------------------
476-- * Basic functions
477-- * Basic functions
477
478
478−-- | /O(n)/ Adds a character to the front of a 'Text'. This function
479+-- | /O(1)/ Adds a character to the front of a 'Text'. Subject to fusion.
479−-- is more costly than its 'List' counterpart because it requires
480−-- copying a new array. Subject to fusion.
481cons :: Char -> Text -> Text
480cons :: Char -> Text -> Text
482cons c t = Chunk (T.singleton c) t
481cons c t = Chunk (T.singleton c) t
483{-# INLINE [1] cons #-}
482{-# INLINE [1] cons #-}
@@ -561,6 +560,15 @@ init Empty = emptyError "init"
561 unstream (S.init (stream t)) = init t
560 unstream (S.init (stream t)) = init t
562 #-}
561 #-}
563
562
563+-- | /O(n\/c)/ Returns the 'init' and 'last' of a 'Text', or 'Nothing' if
564+-- empty.
565+--
566+-- * It is no faster than using 'init' and 'last'.
567+unsnoc :: Text -> Maybe (Text, Char)
568+unsnoc Empty = Nothing
569+unsnoc ts@(Chunk _ _) = Just (init ts, last ts)
570+{-# INLINE unsnoc #-}
571+
564-- | /O(1)/ Tests whether a 'Text' is empty or not. Subject to
572-- | /O(1)/ Tests whether a 'Text' is empty or not. Subject to
565-- fusion.
573-- fusion.
566null :: Text -> Bool
574null :: Text -> Bool
@@ -1153,9 +1161,10 @@ takeWhile p t0 = takeWhile' t0
1153takeWhileEnd :: (Char -> Bool) -> Text -> Text
1161takeWhileEnd :: (Char -> Bool) -> Text -> Text
1154takeWhileEnd p = takeChunk empty . L.reverse . toChunks
1162takeWhileEnd p = takeChunk empty . L.reverse . toChunks
1155 where takeChunk acc [] = acc
1163 where takeChunk acc [] = acc
1156− takeChunk acc (t:ts) = if T.length t' < T.length t
1164+ takeChunk acc (t:ts)
1157− then (Chunk t' acc)
1165+ | T.lengthWord16 t' < T.lengthWord16 t
1166+ = chunk t' acc
1158− else takeChunk (Chunk t' acc) ts
1167+ | otherwise = takeChunk (Chunk t' acc) ts
1159 where t' = T.takeWhileEnd p t
1168 where t' = T.takeWhileEnd p t
1160{-# INLINE takeWhileEnd #-}
1169{-# INLINE takeWhileEnd #-}
1161
1170
Data/Text/Lazy/Read.hs+3−3
@@ -68,9 +68,9 @@ decimal txt
68 go n d = (n * 10 + fromIntegral (digitToInt d))
68 go n d = (n * 10 + fromIntegral (digitToInt d))
69
69
70-- | Read a hexadecimal integer, consisting of an optional leading
70-- | Read a hexadecimal integer, consisting of an optional leading
71−-- @\"0x\"@ followed by at least one decimal digit. Input is consumed
71+-- @\"0x\"@ followed by at least one hexadecimal digit. Input is
72−-- until a non-hex-digit or end of string is reached. This function
72+-- consumed until a non-hex-digit or end of string is reached.
73−-- is case insensitive.
73+-- This function is case insensitive.
74--
74--
75-- This function does not handle leading sign characters. If you need
75-- This function does not handle leading sign characters. If you need
76-- to handle signed input, use @'signed' 'hexadecimal'@.
76-- to handle signed input, use @'signed' 'hexadecimal'@.
Data/Text/Read.hs+3−3
@@ -67,9 +67,9 @@ decimal txt
67 go n d = (n * 10 + fromIntegral (digitToInt d))
67 go n d = (n * 10 + fromIntegral (digitToInt d))
68
68
69-- | Read a hexadecimal integer, consisting of an optional leading
69-- | Read a hexadecimal integer, consisting of an optional leading
70−-- @\"0x\"@ followed by at least one decimal digit. Input is consumed
70+-- @\"0x\"@ followed by at least one hexadecimal digit. Input is
71−-- until a non-hex-digit or end of string is reached. This function
71+-- consumed until a non-hex-digit or end of string is reached.
72−-- is case insensitive.
72+-- This function is case insensitive.
73--
73--
74-- This function does not handle leading sign characters. If you need
74-- This function does not handle leading sign characters. If you need
75-- to handle signed input, use @'signed' 'hexadecimal'@.
75-- to handle signed input, use @'signed' 'hexadecimal'@.
cbits/cbits.c+5−10
@@ -207,10 +207,8 @@ _hs_text_decode_utf8_state(uint16_t *const dest, size_t *destoff,
207 uint32_t *codepoint0, uint32_t *state0)
207 uint32_t *codepoint0, uint32_t *state0)
208{
208{
209 uint8_t const *ret = _hs_text_decode_utf8_int(dest, destoff, src, srcend,
209 uint8_t const *ret = _hs_text_decode_utf8_int(dest, destoff, src, srcend,
210− codepoint0, state0);
210+ codepoint0, state0);
211− if (*state0 == UTF8_REJECT)
211+ return *src;
212− ret -=1;
213− return ret;
214}
212}
215
213
216/*
214/*
@@ -222,12 +220,9 @@ _hs_text_decode_utf8(uint16_t *const dest, size_t *destoff,
222{
220{
223 uint32_t codepoint;
221 uint32_t codepoint;
224 uint32_t state = UTF8_ACCEPT;
222 uint32_t state = UTF8_ACCEPT;
225− uint8_t const *ret = _hs_text_decode_utf8_int(dest, destoff, &src, srcend,
223+ _hs_text_decode_utf8_int(dest, destoff, &src, srcend,
226− &codepoint, &state);
224+ &codepoint, &state);
227− /* Back up if we have an incomplete or invalid encoding */
228− if (state != UTF8_ACCEPT)
229− ret -= 1;
230− return ret;
225+ return src;
231}
226}
232
227
233void
228void
changelog.md+27−1
@@ -1,10 +1,36 @@
1+1.2.3.0
2+
3+* Bug fix: the lazy `takeWhileEnd` function violated the
4+ [lazy text invariant](https://github.com/bos/text/blob/1.2.3.0/Data/Text/Internal/Lazy.hs#L51).
5+
6+* Spec compliance: `toCaseFold` now follows the Unicode 9.0 spec
7+ (updated from 8.0)
8+
9+
10+1.2.2.2
11+
12+* The `toTitle` function now correctly handles letters that
13+ immediately follow punctuation. Before, `"there's"` would turn into
14+ `"There'S"`. Now, it becomes `"There's"`.
15+
16+* The implementation of unstreaming is faster, resulting in operations
17+ such as `map` and `intersperse` speeding up by up to 30%, with
18+ smaller code generated.
19+
20+* The optimised length comparison function is now more likely to be
21+ used after some rewrite rule tweaking.
22+
23+* Bug fix: an off-by-one bug in `takeEnd` is fixed.
24+
25+* Bug fix: a logic error in `takeWord16` is fixed.
26+
11.2.2.1
271.2.2.1
2
28
3* The switch to `integer-pure` in 1.2.2.0 was apparently mistaken.
29* The switch to `integer-pure` in 1.2.2.0 was apparently mistaken.
4 The build flag has been renamed accordingly. Your army of diligent
30 The build flag has been renamed accordingly. Your army of diligent
5 maintainers apologizes for the churn.
31 maintainers apologizes for the churn.
6
32
7−* Spec compliance: toCaseFold now follows the Unicode 8.0 spec
33+* Spec compliance: `toCaseFold` now follows the Unicode 8.0 spec
8 (updated from 7.0)
34 (updated from 7.0)
9
35
10* An STG lint error has been fixed
36* An STG lint error has been fixed
tests/Tests/Properties.hs+89−21
@@ -9,9 +9,9 @@ module Tests.Properties
9 ) where
9 ) where
10
10
11import Control.Applicative ((<$>), (<*>))
11import Control.Applicative ((<$>), (<*>))
12−import Control.Arrow ((***), second)
12+import Control.Arrow ((***), first, second)
13import Data.Bits ((.&.))
13import Data.Bits ((.&.))
14−import Data.Char (chr, isDigit, isHexDigit, isLower, isSpace, isUpper, ord)
14+import Data.Char (chr, isDigit, isHexDigit, isLower, isSpace, isLetter, isUpper, ord)
15import Data.Int (Int8, Int16, Int32, Int64)
15import Data.Int (Int8, Int16, Int32, Int64)
16import Data.Monoid (Monoid(..))
16import Data.Monoid (Monoid(..))
17import Data.String (IsString(fromString))
17import Data.String (IsString(fromString))
@@ -23,6 +23,7 @@ import Data.Text.Internal.Search (indices)
23import Data.Text.Lazy.Read as TL
23import Data.Text.Lazy.Read as TL
24import Data.Text.Read as T
24import Data.Text.Read as T
25import Data.Word (Word, Word8, Word16, Word32, Word64)
25import Data.Word (Word, Word8, Word16, Word32, Word64)
26+import Data.Maybe (mapMaybe)
26import Numeric (showEFloat, showFFloat, showGFloat, showHex)
27import Numeric (showEFloat, showFFloat, showGFloat, showHex)
27import Prelude hiding (replicate)
28import Prelude hiding (replicate)
28import Test.Framework (Test, testGroup)
29import Test.Framework (Test, testGroup)
@@ -30,6 +31,7 @@ import Test.Framework.Providers.QuickCheck2 (testProperty)
30import Test.QuickCheck hiding ((.&.))
31import Test.QuickCheck hiding ((.&.))
31import Test.QuickCheck.Monadic
32import Test.QuickCheck.Monadic
32import Test.QuickCheck.Property (Property(..))
33import Test.QuickCheck.Property (Property(..))
34+import Test.QuickCheck.Unicode (char)
33import Tests.QuickCheckUtils
35import Tests.QuickCheckUtils
34import Tests.Utils
36import Tests.Utils
35import Text.Show.Functions ()
37import Text.Show.Functions ()
@@ -37,6 +39,7 @@ import qualified Control.Exception as Exception
37import qualified Data.Bits as Bits (shiftL, shiftR)
39import qualified Data.Bits as Bits (shiftL, shiftR)
38import qualified Data.ByteString as B
40import qualified Data.ByteString as B
39import qualified Data.ByteString.Lazy as BL
41import qualified Data.ByteString.Lazy as BL
42+import qualified Data.Char as C
40import qualified Data.List as L
43import qualified Data.List as L
41import qualified Data.Text as T
44import qualified Data.Text as T
42import qualified Data.Text.Encoding as E
45import qualified Data.Text.Encoding as E
@@ -60,10 +63,10 @@ t_pack_unpack = (T.unpack . T.pack) `eq` id
60tl_pack_unpack = (TL.unpack . TL.pack) `eq` id
63tl_pack_unpack = (TL.unpack . TL.pack) `eq` id
61t_stream_unstream = (S.unstream . S.stream) `eq` id
64t_stream_unstream = (S.unstream . S.stream) `eq` id
62tl_stream_unstream = (SL.unstream . SL.stream) `eq` id
65tl_stream_unstream = (SL.unstream . SL.stream) `eq` id
63−t_reverse_stream t = (S.reverse . S.reverseStream) t == t
66+t_reverse_stream t = (S.reverse . S.reverseStream) t === t
64−t_singleton c = [c] == (T.unpack . T.singleton) c
67+t_singleton c = [c] === (T.unpack . T.singleton) c
65−tl_singleton c = [c] == (TL.unpack . TL.singleton) c
68+tl_singleton c = [c] === (TL.unpack . TL.singleton) c
66−tl_unstreamChunks x = f 11 x == f 1000 x
69+tl_unstreamChunks x = f 11 x === f 1000 x
67 where f n = SL.unstreamChunks n . S.streamList
70 where f n = SL.unstreamChunks n . S.streamList
68tl_chunk_unchunk = (TL.fromChunks . TL.toChunks) `eq` id
71tl_chunk_unchunk = (TL.fromChunks . TL.toChunks) `eq` id
69tl_from_to_strict = (TL.fromStrict . TL.toStrict) `eq` id
72tl_from_to_strict = (TL.fromStrict . TL.toStrict) `eq` id
@@ -74,13 +77,13 @@ encodeL1 = B.pack . map (fromIntegral . fromEnum) . T.unpack
74encodeLazyL1 :: TL.Text -> BL.ByteString
77encodeLazyL1 :: TL.Text -> BL.ByteString
75encodeLazyL1 = BL.fromChunks . map encodeL1 . TL.toChunks
78encodeLazyL1 = BL.fromChunks . map encodeL1 . TL.toChunks
76
79
77−t_ascii t = E.decodeASCII (E.encodeUtf8 a) == a
80+t_ascii t = E.decodeASCII (E.encodeUtf8 a) === a
78 where a = T.map (\c -> chr (ord c `mod` 128)) t
81 where a = T.map (\c -> chr (ord c `mod` 128)) t
79−tl_ascii t = EL.decodeASCII (EL.encodeUtf8 a) == a
82+tl_ascii t = EL.decodeASCII (EL.encodeUtf8 a) === a
80 where a = TL.map (\c -> chr (ord c `mod` 128)) t
83 where a = TL.map (\c -> chr (ord c `mod` 128)) t
81−t_latin1 t = E.decodeLatin1 (encodeL1 a) == a
84+t_latin1 t = E.decodeLatin1 (encodeL1 a) === a
82 where a = T.map (\c -> chr (ord c `mod` 256)) t
85 where a = T.map (\c -> chr (ord c `mod` 256)) t
83−tl_latin1 t = EL.decodeLatin1 (encodeLazyL1 a) == a
86+tl_latin1 t = EL.decodeLatin1 (encodeLazyL1 a) === a
84 where a = TL.map (\c -> chr (ord c `mod` 256)) t
87 where a = TL.map (\c -> chr (ord c `mod` 256)) t
85t_utf8 = forAll genUnicode $ (E.decodeUtf8 . E.encodeUtf8) `eq` id
88t_utf8 = forAll genUnicode $ (E.decodeUtf8 . E.encodeUtf8) `eq` id
86t_utf8' = forAll genUnicode $ (E.decodeUtf8' . E.encodeUtf8) `eq` (id . Right)
89t_utf8' = forAll genUnicode $ (E.decodeUtf8' . E.encodeUtf8) `eq` (id . Right)
@@ -111,7 +114,7 @@ t_utf8_undecoded = forAll genUnicode $ \t ->
111 let b = E.encodeUtf8 t
114 let b = E.encodeUtf8 t
112 ls = concatMap (leftover . E.encodeUtf8 . T.singleton) . T.unpack $ t
115 ls = concatMap (leftover . E.encodeUtf8 . T.singleton) . T.unpack $ t
113 leftover = (++ [B.empty]) . init . tail . B.inits
116 leftover = (++ [B.empty]) . init . tail . B.inits
114− in (map snd . feedChunksOf 1 E.streamDecodeUtf8) b == ls
117+ in (map snd . feedChunksOf 1 E.streamDecodeUtf8) b === ls
115
118
116data Badness = Solo | Leading | Trailing
119data Badness = Solo | Leading | Trailing
117 deriving (Eq, Show)
120 deriving (Eq, Show)
@@ -177,6 +180,29 @@ genInvalidUTF8 = B.pack <$> oneof [
177 k <- choose (0,n)
180 k <- choose (0,n)
178 vectorOf k gen
181 vectorOf k gen
179
182
183+-- See http://unicode.org/faq/utf_bom.html#gen8
184+-- A sequence such as <110xxxxx2 0xxxxxxx2> is illegal ...
185+-- When faced with this illegal byte sequence ... a UTF-8 conformant process
186+-- must treat the first byte 110xxxxx2 as an illegal termination error
187+-- (e.g. filter it out or replace by 0xFFFD) ...
188+-- ... and continue processing at the second byte 0xxxxxxx2
189+t_decode_with_error2 =
190+ E.decodeUtf8With (\_ _ -> Just 'x') (B.pack [0xC2, 97]) === "xa"
191+t_decode_with_error3 =
192+ E.decodeUtf8With (\_ _ -> Just 'x') (B.pack [0xE0, 97, 97]) === "xaa"
193+t_decode_with_error4 =
194+ E.decodeUtf8With (\_ _ -> Just 'x') (B.pack [0xF0, 97, 97, 97]) === "xaaa"
195+
196+t_decode_with_error2' =
197+ case E.streamDecodeUtf8With (\_ _ -> Just 'x') (B.pack [0xC2, 97]) of
198+ E.Some x _ _ -> x === "xa"
199+t_decode_with_error3' =
200+ case E.streamDecodeUtf8With (\_ _ -> Just 'x') (B.pack [0xC2, 97, 97]) of
201+ E.Some x _ _ -> x === "xaa"
202+t_decode_with_error4' =
203+ case E.streamDecodeUtf8With (\_ _ -> Just 'x') (B.pack [0xC2, 97, 97, 97]) of
204+ E.Some x _ _ -> x === "xaaa"
205+
180s_Eq s = (s==) `eq` ((S.streamList s==) . S.streamList)
206s_Eq s = (s==) `eq` ((S.streamList s==) . S.streamList)
181 where _types = s :: String
207 where _types = s :: String
182sf_Eq p s =
208sf_Eq p s =
@@ -201,8 +227,8 @@ t_mconcat = unsquare $
201 mconcat `eq` (unpackS . mconcat . L.map T.pack)
227 mconcat `eq` (unpackS . mconcat . L.map T.pack)
202tl_mconcat = unsquare $
228tl_mconcat = unsquare $
203 mconcat `eq` (unpackS . mconcat . L.map TL.pack)
229 mconcat `eq` (unpackS . mconcat . L.map TL.pack)
204−t_mempty = mempty == (unpackS (mempty :: T.Text))
230+t_mempty = mempty === (unpackS (mempty :: T.Text))
205−tl_mempty = mempty == (unpackS (mempty :: TL.Text))
231+tl_mempty = mempty === (unpackS (mempty :: TL.Text))
206t_IsString = fromString `eqP` (T.unpack . fromString)
232t_IsString = fromString `eqP` (T.unpack . fromString)
207tl_IsString = fromString `eqP` (TL.unpack . fromString)
233tl_IsString = fromString `eqP` (TL.unpack . fromString)
208
234
@@ -229,6 +255,13 @@ sf_uncons p = (uncons . L.filter p) `eqP`
229 (fmap (second unpackS) . S.uncons . S.filter p)
255 (fmap (second unpackS) . S.uncons . S.filter p)
230t_uncons = uncons `eqP` (fmap (second unpackS) . T.uncons)
256t_uncons = uncons `eqP` (fmap (second unpackS) . T.uncons)
231tl_uncons = uncons `eqP` (fmap (second unpackS) . TL.uncons)
257tl_uncons = uncons `eqP` (fmap (second unpackS) . TL.uncons)
258+
259+unsnoc xs@(_:_) = Just (init xs, last xs)
260+unsnoc [] = Nothing
261+
262+t_unsnoc = unsnoc `eqP` (fmap (first unpackS) . T.unsnoc)
263+tl_unsnoc = unsnoc `eqP` (fmap (first unpackS) . TL.unsnoc)
264+
232s_head = head `eqP` S.head
265s_head = head `eqP` S.head
233sf_head p = (head . L.filter p) `eqP` (S.head . S.filter p)
266sf_head p = (head . L.filter p) `eqP` (S.head . S.filter p)
234t_head = head `eqP` T.head
267t_head = head `eqP` T.head
@@ -326,6 +359,19 @@ t_toUpper_upper t = p (T.toUpper t) >= p t
326 where p = T.length . T.filter isUpper
359 where p = T.length . T.filter isUpper
327tl_toUpper_upper t = p (TL.toUpper t) >= p t
360tl_toUpper_upper t = p (TL.toUpper t) >= p t
328 where p = TL.length . TL.filter isUpper
361 where p = TL.length . TL.filter isUpper
362+t_toTitle_title t = all (<= 1) (caps w)
363+ where caps = fmap (T.length . T.filter isUpper) . T.words . T.toTitle
364+ -- TIL: there exist uppercase-only letters
365+ w = T.filter (\c -> if C.isUpper c then C.toLower c /= c else True) t
366+t_toTitle_1stNotLower = and . notLow . T.toTitle . T.filter stable
367+ where notLow = mapMaybe (fmap (not . isLower) . (T.find isLetter)) . T.words
368+ -- Surprise! The Spanish/Portuguese ordinal indicators changed
369+ -- from category Ll (letter, lowercase) to Lo (letter, other)
370+ -- in Unicode 7.0
371+ -- Oh, and there exist lowercase-only letters (see previous test)
372+ stable c = if isLower c
373+ then C.toUpper c /= c
374+ else c /= '\170' && c /= '\186'
329
375
330justifyLeft k c xs = xs ++ L.replicate (k - length xs) c
376justifyLeft k c xs = xs ++ L.replicate (k - length xs) c
331justifyRight m n xs = L.replicate (m - length xs) n ++ xs
377justifyRight m n xs = L.replicate (m - length xs) n ++ xs
@@ -514,12 +560,20 @@ s_takeWhile p = L.takeWhile p `eqP` (unpackS . S.takeWhile p)
514s_takeWhile_s p = L.takeWhile p `eqP` (unpackS . S.unstream . S.takeWhile p)
560s_takeWhile_s p = L.takeWhile p `eqP` (unpackS . S.unstream . S.takeWhile p)
515sf_takeWhile q p = (L.takeWhile p . L.filter q) `eqP`
561sf_takeWhile q p = (L.takeWhile p . L.filter q) `eqP`
516 (unpackS . S.takeWhile p . S.filter q)
562 (unpackS . S.takeWhile p . S.filter q)
563+noMatch = do
564+ c <- char
565+ d <- suchThat char (/= c)
566+ return (c,d)
517t_takeWhile p = L.takeWhile p `eqP` (unpackS . T.takeWhile p)
567t_takeWhile p = L.takeWhile p `eqP` (unpackS . T.takeWhile p)
518tl_takeWhile p = L.takeWhile p `eqP` (unpackS . TL.takeWhile p)
568tl_takeWhile p = L.takeWhile p `eqP` (unpackS . TL.takeWhile p)
519t_takeWhileEnd p = (L.reverse . L.takeWhile p . L.reverse) `eqP`
569t_takeWhileEnd p = (L.reverse . L.takeWhile p . L.reverse) `eqP`
520 (unpackS . T.takeWhileEnd p)
570 (unpackS . T.takeWhileEnd p)
571+t_takeWhileEnd_null t = forAll noMatch $ \(c,d) -> T.null $
572+ T.takeWhileEnd (==d) (T.snoc t c)
521tl_takeWhileEnd p = (L.reverse . L.takeWhile p . L.reverse) `eqP`
573tl_takeWhileEnd p = (L.reverse . L.takeWhile p . L.reverse) `eqP`
522 (unpackS . TL.takeWhileEnd p)
574 (unpackS . TL.takeWhileEnd p)
575+tl_takeWhileEnd_null t = forAll noMatch $ \(c,d) -> TL.null $
576+ TL.takeWhileEnd (==d) (TL.snoc t c)
523s_dropWhile p = L.dropWhile p `eqP` (unpackS . S.dropWhile p)
577s_dropWhile p = L.dropWhile p `eqP` (unpackS . S.dropWhile p)
524s_dropWhile_s p = L.dropWhile p `eqP` (unpackS . S.unstream . S.dropWhile p)
578s_dropWhile_s p = L.dropWhile p `eqP` (unpackS . S.unstream . S.dropWhile p)
525sf_dropWhile q p = (L.dropWhile p . L.filter q) `eqP`
579sf_dropWhile q p = (L.dropWhile p . L.filter q) `eqP`
@@ -720,7 +774,7 @@ tl_indices (NotEmpty s) = lazyIndices s `eq` S.indices s
720 conc = T.concat . TL.toChunks
774 conc = T.concat . TL.toChunks
721t_indices_occurs = unsquare $ \(NotEmpty t) ts ->
775t_indices_occurs = unsquare $ \(NotEmpty t) ts ->
722 let s = T.intercalate t ts
776 let s = T.intercalate t ts
723− in Slow.indices t s == indices t s
777+ in Slow.indices t s === indices t s
724
778
725-- Bit shifts.
779-- Bit shifts.
726shiftL w = forAll (choose (0,width-1)) $ \k -> Bits.shiftL w k == U.shiftL w k
780shiftL w = forAll (choose (0,width-1)) $ \k -> Bits.shiftL w k == U.shiftL w k
@@ -812,18 +866,18 @@ tb_formatRealFloat_double (a::Double) = tb_formatRealFloat a
812-- Reading.
866-- Reading.
813
867
814t_decimal (n::Int) s =
868t_decimal (n::Int) s =
815− T.signed T.decimal (T.pack (show n) `T.append` t) == Right (n,t)
869+ T.signed T.decimal (T.pack (show n) `T.append` t) === Right (n,t)
816 where t = T.dropWhile isDigit s
870 where t = T.dropWhile isDigit s
817tl_decimal (n::Int) s =
871tl_decimal (n::Int) s =
818− TL.signed TL.decimal (TL.pack (show n) `TL.append` t) == Right (n,t)
872+ TL.signed TL.decimal (TL.pack (show n) `TL.append` t) === Right (n,t)
819 where t = TL.dropWhile isDigit s
873 where t = TL.dropWhile isDigit s
820t_hexadecimal m s ox =
874t_hexadecimal m s ox =
821− T.hexadecimal (T.concat [p, T.pack (showHex n ""), t]) == Right (n,t)
875+ T.hexadecimal (T.concat [p, T.pack (showHex n ""), t]) === Right (n,t)
822 where t = T.dropWhile isHexDigit s
876 where t = T.dropWhile isHexDigit s
823 p = if ox then "0x" else ""
877 p = if ox then "0x" else ""
824 n = getPositive m :: Int
878 n = getPositive m :: Int
825tl_hexadecimal m s ox =
879tl_hexadecimal m s ox =
826− TL.hexadecimal (TL.concat [p, TL.pack (showHex n ""), t]) == Right (n,t)
880+ TL.hexadecimal (TL.concat [p, TL.pack (showHex n ""), t]) === Right (n,t)
827 where t = TL.dropWhile isHexDigit s
881 where t = TL.dropWhile isHexDigit s
828 p = if ox then "0x" else ""
882 p = if ox then "0x" else ""
829 n = getPositive m :: Int
883 n = getPositive m :: Int
@@ -867,11 +921,11 @@ tl_write_read_line e m b t = write_read head TL.filter TL.hPutStrLn
867
921
868t_dropWord16 m t = dropWord16 m t `T.isSuffixOf` t
922t_dropWord16 m t = dropWord16 m t `T.isSuffixOf` t
869t_takeWord16 m t = takeWord16 m t `T.isPrefixOf` t
923t_takeWord16 m t = takeWord16 m t `T.isPrefixOf` t
870−t_take_drop_16 m t = T.append (takeWord16 n t) (dropWord16 n t) == t
924+t_take_drop_16 m t = T.append (takeWord16 n t) (dropWord16 n t) === t
871 where n = small m
925 where n = small m
872t_use_from t = monadicIO $ assert . (==t) =<< run (useAsPtr t fromPtr)
926t_use_from t = monadicIO $ assert . (==t) =<< run (useAsPtr t fromPtr)
873
927
874−t_copy t = T.copy t == t
928+t_copy t = T.copy t === t
875
929
876-- Regression tests.
930-- Regression tests.
877s_filter_eq s = S.filter p t == S.streamList (filter p s)
931s_filter_eq s = S.filter p t == S.streamList (filter p s)
@@ -924,6 +978,14 @@ tests =
924 testGroup "errors" [
978 testGroup "errors" [
925 testProperty "t_utf8_err" t_utf8_err,
979 testProperty "t_utf8_err" t_utf8_err,
926 testProperty "t_utf8_err'" t_utf8_err'
980 testProperty "t_utf8_err'" t_utf8_err'
981+ ],
982+ testGroup "error recovery" [
983+ testProperty "t_decode_with_error2" t_decode_with_error2,
984+ testProperty "t_decode_with_error3" t_decode_with_error3,
985+ testProperty "t_decode_with_error4" t_decode_with_error4,
986+ testProperty "t_decode_with_error2'" t_decode_with_error2',
987+ testProperty "t_decode_with_error3'" t_decode_with_error3',
988+ testProperty "t_decode_with_error4'" t_decode_with_error4'
927 ]
989 ]
928 ],
990 ],
929
991
@@ -967,6 +1029,8 @@ tests =
967 testProperty "sf_uncons" sf_uncons,
1029 testProperty "sf_uncons" sf_uncons,
968 testProperty "t_uncons" t_uncons,
1030 testProperty "t_uncons" t_uncons,
969 testProperty "tl_uncons" tl_uncons,
1031 testProperty "tl_uncons" tl_uncons,
1032+ testProperty "t_unsnoc" t_unsnoc,
1033+ testProperty "tl_unsnoc" tl_unsnoc,
970 testProperty "s_head" s_head,
1034 testProperty "s_head" s_head,
971 testProperty "sf_head" sf_head,
1035 testProperty "sf_head" sf_head,
972 testProperty "t_head" t_head,
1036 testProperty "t_head" t_head,
@@ -1030,7 +1094,9 @@ tests =
1030 testProperty "tl_toLower_lower" tl_toLower_lower,
1094 testProperty "tl_toLower_lower" tl_toLower_lower,
1031 testProperty "t_toUpper_length" t_toUpper_length,
1095 testProperty "t_toUpper_length" t_toUpper_length,
1032 testProperty "t_toUpper_upper" t_toUpper_upper,
1096 testProperty "t_toUpper_upper" t_toUpper_upper,
1033− testProperty "tl_toUpper_upper" tl_toUpper_upper
1097+ testProperty "tl_toUpper_upper" tl_toUpper_upper,
1098+ testProperty "t_toTitle_title" t_toTitle_title,
1099+ testProperty "t_toTitle_1stNotLower" t_toTitle_1stNotLower
1034 ],
1100 ],
1035
1101
1036 testGroup "justification" [
1102 testGroup "justification" [
@@ -1147,7 +1213,9 @@ tests =
1147 testProperty "t_takeWhile" t_takeWhile,
1213 testProperty "t_takeWhile" t_takeWhile,
1148 testProperty "tl_takeWhile" tl_takeWhile,
1214 testProperty "tl_takeWhile" tl_takeWhile,
1149 testProperty "t_takeWhileEnd" t_takeWhileEnd,
1215 testProperty "t_takeWhileEnd" t_takeWhileEnd,
1216+ testProperty "t_takeWhileEnd_null" t_takeWhileEnd_null,
1150 testProperty "tl_takeWhileEnd" tl_takeWhileEnd,
1217 testProperty "tl_takeWhileEnd" tl_takeWhileEnd,
1218+ testProperty "tl_takeWhileEnd_null" tl_takeWhileEnd_null,
1151 testProperty "sf_dropWhile" sf_dropWhile,
1219 testProperty "sf_dropWhile" sf_dropWhile,
1152 testProperty "s_dropWhile" s_dropWhile,
1220 testProperty "s_dropWhile" s_dropWhile,
1153 testProperty "s_dropWhile_s" s_dropWhile_s,
1221 testProperty "s_dropWhile_s" s_dropWhile_s,
tests/Tests/QuickCheckUtils.hs+1−1
@@ -106,7 +106,7 @@ smallArbitrary = sized $ \n -> resize (smallish n) arbitrary
106 where smallish = round . (sqrt :: Double -> Double) . fromIntegral . abs
106 where smallish = round . (sqrt :: Double -> Double) . fromIntegral . abs
107
107
108instance Arbitrary T.Text where
108instance Arbitrary T.Text where
109− arbitrary = T.pack `fmap` arbitrary
109+ arbitrary = T.pack `fmap` string
110 shrink = map T.pack . shrink . T.unpack
110 shrink = map T.pack . shrink . T.unpack
111
111
112instance Arbitrary TL.Text where
112instance Arbitrary TL.Text where
tests/text-tests.cabal+18−3
@@ -20,6 +20,11 @@ flag hpc
20 default: False
20 default: False
21 manual: True
21 manual: True
22
22
23+flag bytestring-builder
24+ description: Depend on the bytestring-builder package for backwards compatibility.
25+ default: False
26+ manual: False
27+
23executable text-tests
28executable text-tests
24 main-is: Tests.hs
29 main-is: Tests.hs
25
30
@@ -48,16 +53,21 @@ executable text-tests
48 HUnit >= 1.2,
53 HUnit >= 1.2,
49 QuickCheck >= 2.7,
54 QuickCheck >= 2.7,
50 base == 4.*,
55 base == 4.*,
51− bytestring,
52 deepseq,
56 deepseq,
53 directory,
57 directory,
54− quickcheck-unicode,
58+ quickcheck-unicode >= 1.0.1.0,
55 random,
59 random,
56 test-framework >= 0.4,
60 test-framework >= 0.4,
57 test-framework-hunit >= 0.2,
61 test-framework-hunit >= 0.2,
58 test-framework-quickcheck2 >= 0.2,
62 test-framework-quickcheck2 >= 0.2,
59 text-tests
63 text-tests
60
64
65+ if flag(bytestring-builder)
66+ build-depends: bytestring >= 0.9 && < 0.10.4,
67+ bytestring-builder >= 0.10.4
68+ else
69+ build-depends: bytestring >= 0.10.4
70+
61executable text-tests-stdio
71executable text-tests-stdio
62 main-is: Tests/IO.hs
72 main-is: Tests/IO.hs
63
73
@@ -137,7 +147,12 @@ library
137 array,
147 array,
138 base == 4.*,
148 base == 4.*,
139 binary,
149 binary,
140− bytestring,
141 deepseq,
150 deepseq,
142 ghc-prim,
151 ghc-prim,
143 integer-gmp
152 integer-gmp
153+
154+ if flag(bytestring-builder)
155+ build-depends: bytestring >= 0.9 && < 0.10.4,
156+ bytestring-builder >= 0.10.4
157+ else
158+ build-depends: bytestring >= 0.10.4
text.cabal+2−2
@@ -1,5 +1,5 @@
1name: text
1name: text
2−version: 1.2.2.1
2+version: 1.2.3.0
3homepage: https://github.com/bos/text
3homepage: https://github.com/bos/text
4bug-reports: https://github.com/bos/text/issues
4bug-reports: https://github.com/bos/text/issues
5synopsis: An efficient packed Unicode text type.
5synopsis: An efficient packed Unicode text type.
@@ -180,7 +180,7 @@ test-suite tests
180 deepseq,
180 deepseq,
181 directory,
181 directory,
182 ghc-prim,
182 ghc-prim,
183− quickcheck-unicode,
183+ quickcheck-unicode >= 1.0.1.0,
184 random,
184 random,
185 test-framework >= 0.4,
185 test-framework >= 0.4,
186 test-framework-hunit >= 0.2,
186 test-framework-hunit >= 0.2,