on master help sign in
Improve the type of replicate. Get rid of the Compat module.
da51d3aBryan O'Sullivan
Data/Text.hs+19−8
@@ -97,6 +97,7 @@ module Data.Text
97
97
98 -- ** Generation and unfolding
98 -- ** Generation and unfolding
99 , replicate
99 , replicate
100+ , replicateChar
100 , unfoldr
101 , unfoldr
101 , unfoldrN
102 , unfoldrN
102
103
@@ -169,7 +170,7 @@ import Prelude (Char, Bool(..), Functor(..), Int, Maybe(..), String,
169 Eq(..), Ord(..), (++),
170 Eq(..), Ord(..), (++),
170 Read(..), Show(..),
171 Read(..), Show(..),
171 (&&), (||), (+), (-), (.), ($),
172 (&&), (||), (+), (-), (.), ($),
172− div, not, return, otherwise)
173+ fromIntegral, div, not, return, otherwise)
173import Control.Exception (assert)
174import Control.Exception (assert)
174import Data.Char (isSpace)
175import Data.Char (isSpace)
175import Control.Monad.ST (ST)
176import Control.Monad.ST (ST)
@@ -465,7 +466,7 @@ toUpper t = unstream (S.toUpper (stream t))
465justifyLeft :: Int -> Char -> Text -> Text
466justifyLeft :: Int -> Char -> Text -> Text
466justifyLeft k c t
467justifyLeft k c t
467 | len >= k = t
468 | len >= k = t
468− | otherwise = t `append` replicate (k-len) c
469+ | otherwise = t `append` replicateChar (k-len) c
469 where len = length t
470 where len = length t
470{-# INLINE [1] justifyLeft #-}
471{-# INLINE [1] justifyLeft #-}
471
472
@@ -484,7 +485,7 @@ justifyLeft k c t
484justifyRight :: Int -> Char -> Text -> Text
485justifyRight :: Int -> Char -> Text -> Text
485justifyRight k c t
486justifyRight k c t
486 | len >= k = t
487 | len >= k = t
487− | otherwise = replicate (k-len) c `append` t
488+ | otherwise = replicateChar (k-len) c `append` t
488 where len = length t
489 where len = length t
489{-# INLINE justifyRight #-}
490{-# INLINE justifyRight #-}
490
491
@@ -495,7 +496,7 @@ justifyRight k c t
495center :: Int -> Char -> Text -> Text
496center :: Int -> Char -> Text -> Text
496center k c t
497center k c t
497 | len >= k = t
498 | len >= k = t
498− | otherwise = replicate l c `append` t `append` replicate r c
499+ | otherwise = replicateChar l c `append` t `append` replicateChar r c
499 where len = length t
500 where len = length t
500 d = k - len
501 d = k - len
501 r = d `div` 2
502 r = d `div` 2
@@ -654,11 +655,21 @@ mapAccumR f s t = case uncons t of
654-- -----------------------------------------------------------------------------
655-- -----------------------------------------------------------------------------
655-- ** Generating and unfolding 'Text's
656-- ** Generating and unfolding 'Text's
656
657
658+-- | /O(n*m)/ 'replicate' @n@ @t@ is a 'Text' consisting of the input
659+-- @t@ repeated @n@ times. Subject to fusion.
660+replicate :: Int -> Text -> Text
661+replicate n t = unstream (S.replicateI (fromIntegral n) (S.stream t))
662+{-# INLINE [1] replicate #-}
663+
664+{-# RULES
665+"TEXT replicate/singleton -> replicateChar" [~1] forall n c.
666+ replicate n (singleton c) = replicateChar n c
667+ #-}
668+
657−-- | /O(n)/ 'replicate' @n@ @c@ is a 'Text' of length @n@ with @c@ the
669+-- | /O(n)/ 'replicateChar' @n@ @c@ is a 'Text' of length @n@ with @c@ the
658-- value of every element. Subject to fusion.
670-- value of every element. Subject to fusion.
659−replicate :: Int -> Char -> Text
671+replicateChar :: Int -> Char -> Text
660−replicate n c = unstream (S.replicateI n c)
672+replicateChar n c = unstream (S.replicateCharI n c)
661−{-# INLINE replicate #-}
662
673
663-- | /O(n)/, where @n@ is the length of the result. The 'unfoldr'
674-- | /O(n)/, where @n@ is the length of the result. The 'unfoldr'
664-- function is analogous to the List 'L.unfoldr'. 'unfoldr' builds a
675-- function is analogous to the List 'L.unfoldr'. 'unfoldr' builds a
Data/Text/Compat.hsdeleted−186
@@ -1,186 +0,0 @@
1−{-# LANGUAGE BangPatterns #-}
2−{-# OPTIONS_GHC -fno-warn-unused-imports #-}
3−-- |
4−-- Module : Data.Text.Compat
5−-- Copyright : (c) Bryan O'Sullivan 2009
6−--
7−-- License : BSD-style
8−-- Maintainer : bos@serpentine.com, rtharper@aftereternity.co.uk,
9−-- duncan@haskell.org
10−-- Stability : experimental
11−-- Portability : GHC
12−--
13−-- A text API for which function names closely resemble those of the
14−-- list and 'ByteString' types.
15−--
16−-- This module is intended to be imported @qualified@, to avoid name
17−-- clashes with "Prelude" functions, e.g.
18−--
19−-- > import qualified Data.Text.Compat as T
20−
21−module Data.Text.Compat
22− (
23− -- * Types
24− Text
25−
26− -- * Creation and elimination
27− , pack
28− , unpack
29− , singleton
30− , empty
31−
32− -- * Basic interface
33− , cons
34− , snoc
35− , append
36− , uncons
37− , head
38− , last
39− , tail
40− , init
41− , null
42− , length
43−
44− -- * Transformations
45− , map
46− , intercalate
47− , intersperse
48− , transpose
49− , reverse
50−
51− -- * Case conversion
52− -- $case
53− , toCaseFold
54− , toLower
55− , toUpper
56−
57− -- * Folds
58− , foldl
59− , foldl'
60− , foldl1
61− , foldl1'
62− , foldr
63− , foldr1
64−
65− -- ** Special folds
66− , concat
67− , concatMap
68− , any
69− , all
70− , maximum
71− , minimum
72−
73− -- * Construction
74−
75− -- ** Scans
76− , scanl
77− , scanl1
78− , scanr
79− , scanr1
80−
81− -- ** Accumulating maps
82− , mapAccumL
83− , mapAccumR
84−
85− -- ** Generation and unfolding
86− , replicate
87− , unfoldr
88− , unfoldrN
89−
90− -- * Substrings
91−
92− -- ** Breaking strings
93− , take
94− , drop
95− , takeWhile
96− , dropWhile
97− , splitAt
98− , span
99− , break
100− , group
101− , groupBy
102− , inits
103− , tails
104−
105− -- ** Breaking into many substrings
106− , split
107− , splitWith
108− , breakSubstring
109−
110− -- ** Breaking into lines and words
111− , lines
112− --, lines'
113− , words
114− , unlines
115− , unwords
116−
117− -- * Predicates
118− , isPrefixOf
119− , isSuffixOf
120− , isInfixOf
121−
122− -- * Searching
123− , elem
124− , filter
125− , find
126− , partition
127−
128− -- , findSubstring
129−
130− -- * Indexing
131− , index
132− , findIndex
133− , findIndices
134− , elemIndex
135− , elemIndices
136− , count
137−
138− -- * Zipping and unzipping
139− , zip
140− , zipWith
141−
142− -- -* Ordered text
143− -- , sort
144− ) where
145−
146−import Data.ByteString (ByteString)
147−import Data.Text hiding (split)
148−import qualified Data.Text as T
149−import Data.Text.Unsafe (unsafeTail)
150−import Prelude (Char, (+), otherwise)
151−
152−split :: Char -> Text -> [Text]
153−split c = T.split (singleton c)
154−{-# INLINE split #-}
155−
156−-- | /O(n)/ Break a string on a substring, returning a pair of the
157−-- part of the string prior to the match, and the rest of the string.
158−--
159−-- The following relationship holds:
160−--
161−-- > break (==c) l == breakSubstring (singleton c) l
162−--
163−-- For example, to tokenise a string, dropping delimiters:
164−--
165−-- > tokenise x y = h : if null t then [] else tokenise x (drop (length x) t)
166−-- > where (h,t) = breakSubstring x y
167−--
168−-- To skip to the first occurence of a string:
169−--
170−-- > snd (breakSubstring x y)
171−--
172−-- To take the parts of a string before a delimiter:
173−--
174−-- > fst (breakSubstring x y)
175−--
176−breakSubstring :: Text -- ^ String to search for
177− -> Text -- ^ String to search in
178− -> (Text,Text) -- ^ Head and tail of string broken at substring
179−
180−breakSubstring pat src = search 0 src
181− where
182− search !n !s
183− | null s = (src,empty) -- not found
184− | pat `isPrefixOf` s = (take n src,s)
185− | otherwise = search (n+1) (unsafeTail s)
186−{-# INLINE breakSubstring #-}
Data/Text/Fusion/Common.hs+16−2
@@ -68,6 +68,7 @@ module Data.Text.Fusion.Common
68 -- , mapAccumL
68 -- , mapAccumL
69
69
70 -- ** Generation and unfolding
70 -- ** Generation and unfolding
71+ , replicateCharI
71 , replicateI
72 , replicateI
72 , unfoldr
73 , unfoldr
73 , unfoldrNI
74 , unfoldrNI
@@ -104,6 +105,7 @@ import Prelude (Bool(..), Char, Either(..), Eq(..), Int, Integral, Maybe(..),
104 fromIntegral, otherwise)
105 fromIntegral, otherwise)
105import qualified Data.List as L
106import qualified Data.List as L
106import qualified Prelude as P
107import qualified Prelude as P
108+import Data.Int (Int64)
107import Data.Text.Fusion.Internal
109import Data.Text.Fusion.Internal
108import Data.Text.Fusion.CaseMapping (foldMapping, lowerMapping, upperMapping)
110import Data.Text.Fusion.CaseMapping (foldMapping, lowerMapping, upperMapping)
109
111
@@ -576,14 +578,26 @@ mapAccumL f z0 (Stream next0 s0 len) = Stream next (s0 :!: z0) len -- HINT depen
576-- -----------------------------------------------------------------------------
578-- -----------------------------------------------------------------------------
577-- ** Generating and unfolding streams
579-- ** Generating and unfolding streams
578
580
579−replicateI :: Integral a => a -> Char -> Stream Char
581+replicateCharI :: Integral a => a -> Char -> Stream Char
580−replicateI n c
582+replicateCharI n c
581 | n < 0 = empty
583 | n < 0 = empty
582 | otherwise = Stream next 0 (fromIntegral n) -- HINT maybe too low
584 | otherwise = Stream next 0 (fromIntegral n) -- HINT maybe too low
583 where
585 where
584 {-# INLINE next #-}
586 {-# INLINE next #-}
585 next i | i >= n = Done
587 next i | i >= n = Done
586 | otherwise = Yield c (i + 1)
588 | otherwise = Yield c (i + 1)
589+{-# INLINE [0] replicateCharI #-}
590+
591+replicateI :: Int64 -> Stream Char -> Stream Char
592+replicateI n (Stream next0 s0 len) =
593+ Stream next (0 :!: s0) (max 0 (fromIntegral n * len))
594+ where
595+ next (k :!: s)
596+ | k >= n = Done
597+ | otherwise = case next0 s of
598+ Done -> Skip (k+1 :!: s0)
599+ Skip s' -> Skip (k :!: s')
600+ Yield x s' -> Yield x (k :!: s')
587{-# INLINE [0] replicateI #-}
601{-# INLINE [0] replicateI #-}
588
602
589-- | /O(n)/, where @n@ is the length of the result. The unfoldr function
603-- | /O(n)/, where @n@ is the length of the result. The unfoldr function
Data/Text/Lazy.hs+18−7
@@ -101,6 +101,7 @@ module Data.Text.Lazy
101
101
102 -- ** Generation and unfolding
102 -- ** Generation and unfolding
103 , replicate
103 , replicate
104+ , replicateChar
104 , unfoldr
105 , unfoldr
105 , unfoldrN
106 , unfoldrN
106
107
@@ -388,7 +389,7 @@ intersperse c t = unstream (S.intersperse c (stream t))
388justifyLeft :: Int64 -> Char -> Text -> Text
389justifyLeft :: Int64 -> Char -> Text -> Text
389justifyLeft k c t
390justifyLeft k c t
390 | len >= k = t
391 | len >= k = t
391− | otherwise = t `append` replicate (k-len) c
392+ | otherwise = t `append` replicateChar (k-len) c
392 where len = length t
393 where len = length t
393{-# INLINE [1] justifyLeft #-}
394{-# INLINE [1] justifyLeft #-}
394
395
@@ -407,7 +408,7 @@ justifyLeft k c t
407justifyRight :: Int64 -> Char -> Text -> Text
408justifyRight :: Int64 -> Char -> Text -> Text
408justifyRight k c t
409justifyRight k c t
409 | len >= k = t
410 | len >= k = t
410− | otherwise = replicate (k-len) c `append` t
411+ | otherwise = replicateChar (k-len) c `append` t
411 where len = length t
412 where len = length t
412{-# INLINE justifyRight #-}
413{-# INLINE justifyRight #-}
413
414
@@ -418,7 +419,7 @@ justifyRight k c t
418center :: Int64 -> Char -> Text -> Text
419center :: Int64 -> Char -> Text -> Text
419center k c t
420center k c t
420 | len >= k = t
421 | len >= k = t
421− | otherwise = replicate l c `append` t `append` replicate r c
422+ | otherwise = replicateChar l c `append` t `append` replicateChar r c
422 where len = length t
423 where len = length t
423 d = k - len
424 d = k - len
424 r = d `div` 2
425 r = d `div` 2
@@ -631,12 +632,22 @@ mapAccumR f s t = case uncons t of
631 where (s'',y ) = f s' x
632 where (s'',y ) = f s' x
632 (s', ys) = mapAccumR f s xs
633 (s', ys) = mapAccumR f s xs
633
634
634−-- | /O(n)/ 'replicate' @n@ @c@ is a 'Text' of length @n@ with @c@ the
635+-- | /O(n*m)/ 'replicate' @n@ @t@ is a 'Text' consisting of the input
635−-- value of every element.
636+-- @t@ repeated @n@ times. Subject to fusion.
636−replicate :: Int64 -> Char -> Text
637+replicate :: Int64 -> Text -> Text
637−replicate n c = unstream (S.replicateI n c)
638+replicate n t = unstream (S.replicateI (fromIntegral n) (S.stream t))
638{-# INLINE replicate #-}
639{-# INLINE replicate #-}
639
640
641+-- | /O(n)/ 'replicateChar' @n@ @c@ is a 'Text' of length @n@ with @c@ the
642+-- value of every element. Subject to fusion.
643+replicateChar :: Int64 -> Char -> Text
644+replicateChar n c = unstream (S.replicateCharI n c)
645+
646+{-# RULES
647+"LAZY TEXT replicate/singleton -> replicateChar" [~1] forall n c.
648+ replicate n (singleton c) = replicateChar n c
649+ #-}
650+
640-- | /O(n)/, where @n@ is the length of the result. The 'unfoldr'
651-- | /O(n)/, where @n@ is the length of the result. The 'unfoldr'
641-- function is analogous to the List 'L.unfoldr'. 'unfoldr' builds a
652-- function is analogous to the List 'L.unfoldr'. 'unfoldr' builds a
642-- 'Text' from a seed value. The function takes the element and
653-- 'Text' from a seed value. The function takes the element and
Data/Text/UnsafeShift.hs+1−1
@@ -17,7 +17,7 @@ module Data.Text.UnsafeShift
17 UnsafeShift(..)
17 UnsafeShift(..)
18 ) where
18 ) where
19
19
20−import qualified Data.Bits as Bits
20+-- import qualified Data.Bits as Bits
21import GHC.Base
21import GHC.Base
22import GHC.Word
22import GHC.Word
23
23
tests/Properties.hs+12−17
@@ -13,7 +13,6 @@ import Debug.Trace (trace)
13import Control.Arrow ((***), second)
13import Control.Arrow ((***), second)
14import Data.Word (Word8, Word16, Word32)
14import Data.Word (Word8, Word16, Word32)
15import qualified Data.Text as T
15import qualified Data.Text as T
16−import qualified Data.Text.Compat as C
17import qualified Data.Text.Lazy as TL
16import qualified Data.Text.Lazy as TL
18import qualified Data.Text.Encoding as E
17import qualified Data.Text.Encoding as E
19import Control.Exception (SomeException, try)
18import Control.Exception (SomeException, try)
@@ -23,6 +22,7 @@ import qualified Data.Text.Lazy.Encoding as EL
23import qualified Data.Text.Lazy.Fusion as SL
22import qualified Data.Text.Lazy.Fusion as SL
24import qualified Data.Text.UnsafeShift as U
23import qualified Data.Text.UnsafeShift as U
25import qualified Data.List as L
24import qualified Data.List as L
25+import Prelude hiding (replicate)
26import System.IO.Unsafe (unsafePerformIO)
26import System.IO.Unsafe (unsafePerformIO)
27import Test.Framework (defaultMain, testGroup)
27import Test.Framework (defaultMain, testGroup)
28import Test.Framework.Providers.QuickCheck (testProperty)
28import Test.Framework.Providers.QuickCheck (testProperty)
@@ -238,8 +238,8 @@ t_toUpper_upper t = p (T.toUpper t) >= p t
238tl_toUpper_upper t = p (TL.toUpper t) >= p t
238tl_toUpper_upper t = p (TL.toUpper t) >= p t
239 where p = TL.length . TL.filter isUpper
239 where p = TL.length . TL.filter isUpper
240
240
241−justifyLeft k c s = s ++ replicate (k - length s) c
241+justifyLeft k c s = s ++ L.replicate (k - length s) c
242−justifyRight m n s = replicate (m - length s) n ++ s
242+justifyRight m n s = L.replicate (m - length s) n ++ s
243
243
244s_justifyLeft k c = justifyLeft k c `eqP` (unpackS . S.justifyLeftI k c)
244s_justifyLeft k c = justifyLeft k c `eqP` (unpackS . S.justifyLeftI k c)
245sf_justifyLeft p k c =
245sf_justifyLeft p k c =
@@ -315,8 +315,12 @@ t_mapAccumR f z = unsquare (L.mapAccumR f z `eqP` (second unpackS . T.mapAccum
315tl_mapAccumR f z = unsquare (L.mapAccumR f z `eqP` (second unpackS . TL.mapAccumR f z))
315tl_mapAccumR f z = unsquare (L.mapAccumR f z `eqP` (second unpackS . TL.mapAccumR f z))
316 where _types = f :: Int -> Char -> (Int,Char)
316 where _types = f :: Int -> Char -> (Int,Char)
317
317
318+replicate n l = concat (L.replicate n l)
319+
318−t_replicate n = L.replicate n `eq` (unpackS . T.replicate n)
320+t_replicate n = replicate n `eq` (unpackS . T.replicate n . packS)
319−tl_replicate n = L.replicate n `eq` (unpackS . TL.replicate (fromIntegral n))
321+tl_replicate n = replicate n `eq` (unpackS . TL.replicate (fromIntegral n) . packS)
322+t_replicateChar n = L.replicate n `eq` (unpackS . T.replicateChar n)
323+tl_replicateChar n= L.replicate n `eq` (unpackS . TL.replicateChar (fromIntegral n))
320
324
321unf :: Int -> Char -> Maybe (Char, Char)
325unf :: Int -> Char -> Maybe (Char, Char)
322unf n c | fromEnum c * 100 > n = Nothing
326unf n c | fromEnum c * 100 > n = Nothing
@@ -393,7 +397,6 @@ tl_split_i t = id `eq` (TL.intercalate t . TL.split t)
393t_splitWith p = splitWith p `eqP` (map unpackS . T.splitWith p)
397t_splitWith p = splitWith p `eqP` (map unpackS . T.splitWith p)
394t_splitWith_count c = (L.length . T.splitWith (==c)) `eq` ((1+) . T.count c)
398t_splitWith_count c = (L.length . T.splitWith (==c)) `eq` ((1+) . T.count c)
395t_splitWith_split c = T.splitWith (==c) `eq` T.split (T.singleton c)
399t_splitWith_split c = T.splitWith (==c) `eq` T.split (T.singleton c)
396−t_splitWith_Csplit c = T.splitWith (==c) `eq` C.split c
397tl_splitWith p = splitWith p `eqP` (map unpackS . TL.splitWith p)
400tl_splitWith p = splitWith p `eqP` (map unpackS . TL.splitWith p)
398
401
399splitWith :: (a -> Bool) -> [a] -> [[a]]
402splitWith :: (a -> Bool) -> [a] -> [[a]]
@@ -412,13 +415,6 @@ t_chunksOf_length k t = len == T.length t || (k <= 0 && len == 0)
412
415
413tl_chunksOf k = T.chunksOf k `eq` (map (T.concat . TL.toChunks) . TL.chunksOf (fromIntegral k) . TL.fromChunks . (:[]))
416tl_chunksOf k = T.chunksOf k `eq` (map (T.concat . TL.toChunks) . TL.chunksOf (fromIntegral k) . TL.fromChunks . (:[]))
414
417
415−t_breakSubstring_isInfixOf s l
416− = T.isInfixOf s l ==
417− T.null s || (not . T.null . snd $ C.breakSubstring s l)
418−t_breakSubstringC c
419− = L.break (==c) `eqP`
420− (unpack2 . C.breakSubstring (T.singleton c))
421−
422t_lines = L.lines `eqP` (map unpackS . T.lines)
418t_lines = L.lines `eqP` (map unpackS . T.lines)
423tl_lines = L.lines `eqP` (map unpackS . TL.lines)
419tl_lines = L.lines `eqP` (map unpackS . TL.lines)
424{-
420{-
@@ -711,6 +707,8 @@ tests = [
711 testGroup "unfolds" [
707 testGroup "unfolds" [
712 testProperty "t_replicate" t_replicate,
708 testProperty "t_replicate" t_replicate,
713 testProperty "tl_replicate" tl_replicate,
709 testProperty "tl_replicate" tl_replicate,
710+ testProperty "t_replicateChar" t_replicateChar,
711+ testProperty "tl_replicateChar" tl_replicateChar,
714 testProperty "t_unfoldr" t_unfoldr,
712 testProperty "t_unfoldr" t_unfoldr,
715 testProperty "tl_unfoldr" tl_unfoldr,
713 testProperty "tl_unfoldr" tl_unfoldr,
716 testProperty "t_unfoldrN" t_unfoldrN,
714 testProperty "t_unfoldrN" t_unfoldrN,
@@ -776,13 +774,10 @@ tests = [
776 testProperty "t_splitWith" t_splitWith,
774 testProperty "t_splitWith" t_splitWith,
777 testProperty "t_splitWith_count" t_splitWith_count,
775 testProperty "t_splitWith_count" t_splitWith_count,
778 testProperty "t_splitWith_split" t_splitWith_split,
776 testProperty "t_splitWith_split" t_splitWith_split,
779− testProperty "t_splitWith_Csplit" t_splitWith_Csplit,
780 testProperty "tl_splitWith" tl_splitWith,
777 testProperty "tl_splitWith" tl_splitWith,
781 testProperty "t_chunksOf_same_lengths" t_chunksOf_same_lengths,
778 testProperty "t_chunksOf_same_lengths" t_chunksOf_same_lengths,
782 testProperty "t_chunksOf_length" t_chunksOf_length,
779 testProperty "t_chunksOf_length" t_chunksOf_length,
783− testProperty "tl_chunksOf" tl_chunksOf,
780+ testProperty "tl_chunksOf" tl_chunksOf
784− testProperty "t_breakSubstringC" t_breakSubstringC,
785− testProperty "t_breakSubstring_isInfixOf" t_breakSubstring_isInfixOf
786 ],
781 ],
787
782
788 testGroup "lines and words" [
783 testGroup "lines and words" [
text.cabal−1
@@ -17,7 +17,6 @@ extra-source-files: README
17library
17library
18 exposed-modules:
18 exposed-modules:
19 Data.Text
19 Data.Text
20− Data.Text.Compat
21 Data.Text.Encoding
20 Data.Text.Encoding
22 Data.Text.Encoding.Error
21 Data.Text.Encoding.Error
23 Data.Text.Foreign
22 Data.Text.Foreign