packages feed

text 0.11.0.8 → 0.11.1.0

raw patch · 57 files changed

+2311/−1212 lines, 57 filesdep +arraydep +integerdep +integer-gmpdep ~basedep ~bytestring

Dependencies added: array, integer, integer-gmp

Dependency ranges changed: base, bytestring

Files

Data/Text/IO.hs view
@@ -46,7 +46,7 @@ import qualified Data.ByteString.Char8 as B import Data.Text.Encoding (decodeUtf8, encodeUtf8) #else-import Control.Exception (catch, throw)+import Control.Exception (catch, throwIO) import Control.Monad (liftM2, when) import Data.IORef (readIORef, writeIORef) import qualified Data.Text as T@@ -123,7 +123,7 @@               return $ if isEmptyBuffer buf                        then T.empty                        else T.singleton '\r'-          | otherwise = throw (augmentIOError e "hGetContents" h)+          | otherwise = throwIO (augmentIOError e "hGetContents" h)         readChunks = do           buf <- readIORef haCharBuffer           t <- readChunk hh buf `catch` catchError@@ -147,7 +147,7 @@       d <- catch (liftM2 (-) (hFileSize h) (hTell h)) $ \(e::IOException) ->            if ioe_type e == InappropriateType            then return 16384 -- faster than the 2KB default-           else throw e+           else throwIO e       when (d > 0) . hSetBuffering h . BlockBuffering . Just . fromIntegral $ d     _ -> return () #endif
Data/Text/Lazy/Builder.hs view
@@ -82,14 +82,22 @@    {-# INLINE mempty #-}    mappend = append    {-# INLINE mappend #-}+   mconcat = foldr mappend mempty+   {-# INLINE mconcat #-}  instance String.IsString Builder where     fromString = fromString     {-# INLINE fromString #-}  instance Show Builder where-    show = L.unpack . toLazyText+    show = show . toLazyText +instance Eq Builder where+    a == b = toLazyText a == toLazyText b++instance Ord Builder where+    a <= b = toLazyText a <= toLazyText b+ ------------------------------------------------------------------------  -- | /O(1)./ The empty @Builder@, satisfying@@ -97,7 +105,7 @@ --  * @'toLazyText' 'empty' = 'L.empty'@ -- empty :: Builder-empty = Builder id+empty = Builder (\ k buf -> k buf) {-# INLINE empty #-}  -- | /O(1)./ A @Builder@ taking a single character, satisfying@@ -105,7 +113,17 @@ --  * @'toLazyText' ('singleton' c) = 'L.singleton' c@ -- singleton :: Char -> Builder-singleton c = putChar c+singleton c = writeAtMost 2 $ \ marr o ->+    if n < 0x10000+    then A.unsafeWrite marr o (fromIntegral n) >> return 1+    else do+        A.unsafeWrite marr o lo+        A.unsafeWrite marr (o+1) hi+        return 2+  where n = ord c+        m = n - 0x10000+        lo = fromIntegral $ (m `shiftR` 10) + 0xD800+        hi = fromIntegral $ (m .&. 0x3FF) + 0xDC00 {-# INLINE singleton #-}  ------------------------------------------------------------------------@@ -229,20 +247,6 @@  ------------------------------------------------------------------------ -putChar :: Char -> Builder-putChar c-    | n < 0x10000 = writeN 1 $ \marr o -> A.unsafeWrite marr o (fromIntegral n)-    | otherwise   = writeN 2 $ \marr o -> do-          A.unsafeWrite marr o lo-          A.unsafeWrite marr (o+1) hi-  where n = ord c-        m = n - 0x10000-        lo = fromIntegral $ (m `shiftR` 10) + 0xD800-        hi = fromIntegral $ (m .&. 0x3FF) + 0xDC00-{-# INLINE putChar #-}--------------------------------------------------------------------------- -- | Ensure that there are at least @n@ many elements available. ensureFree :: Int -> Builder ensureFree !n = withSize $ \ l ->@@ -251,18 +255,21 @@     else flush `append'` withBuffer (const (newBuffer (max n smallChunkSize))) {-# INLINE [0] ensureFree #-} +writeAtMost :: Int -> (forall s. A.MArray s -> Int -> ST s Int) -> Builder+writeAtMost n f = ensureFree n `append'` withBuffer (writeBuffer f)+{-# INLINE [0] writeAtMost #-}+ -- | Ensure that @n@ many elements are available, and then use @f@ to -- write some elements into the memory. writeN :: Int -> (forall s. A.MArray s -> Int -> ST s ()) -> Builder-writeN n f = ensureFree n `append'` withBuffer (writeNBuffer n f)-{-# INLINE [0] writeN #-}+writeN n f = writeAtMost n (\ p o -> f p o >> return n)+{-# INLINE writeN #-} -writeNBuffer :: Int -> (A.MArray s -> Int -> ST s ()) -> (Buffer s)-             -> ST s (Buffer s)-writeNBuffer n f (Buffer p o u l) = do-    f p (o+u)+writeBuffer :: (A.MArray s -> Int -> ST s Int) -> Buffer s -> ST s (Buffer s)+writeBuffer f (Buffer p o u l) = do+    n <- f p (o+u)     return $! Buffer p o (u+n) (l-n)-{-# INLINE writeNBuffer #-}+{-# INLINE writeBuffer #-}  newBuffer :: Int -> ST s (Buffer s) newBuffer size = do@@ -275,27 +282,31 @@  -- This function makes GHC understand that 'writeN' and 'ensureFree' -- are *not* recursive in the precense of the rewrite rules below.--- This is not needed with GHC 6.14+.+-- This is not needed with GHC 7+. append' :: Builder -> Builder -> Builder append' (Builder f) (Builder g) = Builder (f . g) {-# INLINE append' #-}  {-# RULES -"append/writeN" forall a b (f::forall s. A.MArray s -> Int -> ST s ())-                           (g::forall s. A.MArray s -> Int -> ST s ()) ws.-        append (writeN a f) (append (writeN b g) ws) =-            append (writeN (a+b) (\marr o -> f marr o >> g marr (o+a))) ws+"append/writeAtMost" forall a b (f::forall s. A.MArray s -> Int -> ST s Int)+                           (g::forall s. A.MArray s -> Int -> ST s Int) ws.+    append (writeAtMost a f) (append (writeAtMost b g) ws) =+        append (writeAtMost (a+b) (\marr o -> f marr o >>= \ n -> +                                    g marr (o+n) >>= \ m ->+                                    let s = n+m in s `seq` return s)) ws -"writeN/writeN" forall a b (f::forall s. A.MArray s -> Int -> ST s ())-                           (g::forall s. A.MArray s -> Int -> ST s ()).-        append (writeN a f) (writeN b g) =-            writeN (a+b) (\marr o -> f marr o >> g marr (o+a))+"writeAtMost/writeAtMost" forall a b (f::forall s. A.MArray s -> Int -> ST s Int)+                           (g::forall s. A.MArray s -> Int -> ST s Int).+    append (writeAtMost a f) (writeAtMost b g) =+        writeAtMost (a+b) (\marr o -> f marr o >>= \ n -> +                            g marr (o+n) >>= \ m ->+                            let s = n+m in s `seq` return s)  "ensureFree/ensureFree" forall a b .-        append (ensureFree a) (ensureFree b) = ensureFree (max a b)+    append (ensureFree a) (ensureFree b) = ensureFree (max a b)  "flush/flush"-        append flush flush = flush+    append flush flush = flush   #-}
+ Data/Text/Lazy/Builder/Functions.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE MagicHash #-}++-- |+-- Module      : Data.Text.Lazy.Builder.Functions+-- Copyright   : (c) 2011 MailRank, Inc.+--+-- License     : BSD-style+-- Maintainer  : bos@serpentine.com+-- Stability   : experimental+-- Portability : GHC+--+-- Useful functions and combinators.++module Data.Text.Lazy.Builder.Functions+    (+      (<>)+    , i2d+    ) where++import Data.Monoid (mappend)+import Data.Text.Lazy.Builder (Builder)+import GHC.Base++-- | Unsafe conversion for decimal digits.+{-# INLINE i2d #-}+i2d :: Int -> Char+i2d (I# i#) = C# (chr# (ord# '0'# +# i#))++-- | The normal 'mappend' function with right associativity instead of+-- left.+(<>) :: Builder -> Builder -> Builder+(<>) = mappend+{-# INLINE (<>) #-}++infixr 4 <>
+ Data/Text/Lazy/Builder/Int.hs view
@@ -0,0 +1,152 @@+{-# LANGUAGE BangPatterns, CPP, MagicHash, UnboxedTuples #-}++-- Module:      Data.Text.Lazy.Builder.Int+-- Copyright:   (c) 2011 MailRank, Inc.+-- License:     BSD3+-- Maintainer:  Bryan O'Sullivan <bos@serpentine.com>+-- Stability:   experimental+-- Portability: portable+--+-- Efficiently write an integral value to a 'Builder'.++module Data.Text.Lazy.Builder.Int+    (+      decimal+    , hexadecimal+    ) where++import Data.Int (Int8, Int16, Int32, Int64)+import Data.Monoid (mempty)+import Data.Text.Lazy.Builder.Functions ((<>), i2d)+import Data.Text.Lazy.Builder+import Data.Word (Word, Word8, Word16, Word32, Word64)+import GHC.Base (quotInt, remInt)+import GHC.Num (quotRemInteger)+import GHC.Types (Int(..))++#ifdef  __GLASGOW_HASKELL__+# if __GLASGOW_HASKELL__ < 611+import GHC.Integer.Internals+# else+import GHC.Integer.GMP.Internals+# endif+#endif++#ifdef INTEGER_GMP+# define PAIR(a,b) (# a,b #)+#else+# define PAIR(a,b) (a,b)+#endif++decimal :: Integral a => a -> Builder+{-# SPECIALIZE decimal :: Int -> Builder #-}+{-# SPECIALIZE decimal :: Int8 -> Builder #-}+{-# SPECIALIZE decimal :: Int16 -> Builder #-}+{-# SPECIALIZE decimal :: Int32 -> Builder #-}+{-# SPECIALIZE decimal :: Int64 -> Builder #-}+{-# SPECIALIZE decimal :: Word -> Builder #-}+{-# SPECIALIZE decimal :: Word8 -> Builder #-}+{-# SPECIALIZE decimal :: Word16 -> Builder #-}+{-# SPECIALIZE decimal :: Word32 -> Builder #-}+{-# SPECIALIZE decimal :: Word64 -> Builder #-}+{-# RULES "decimal/Integer" decimal = integer 10 :: Integer -> Builder #-}+decimal i+    | i < 0     = singleton '-' <> go (-i)+    | otherwise = go i+  where+    go n | n < 10    = digit n+         | otherwise = go (n `quot` 10) <> digit (n `rem` 10)++hexadecimal :: Integral a => a -> Builder+{-# SPECIALIZE hexadecimal :: Int -> Builder #-}+{-# SPECIALIZE hexadecimal :: Int8 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Int16 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Int32 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Int64 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Word -> Builder #-}+{-# SPECIALIZE hexadecimal :: Word8 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Word16 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Word32 -> Builder #-}+{-# SPECIALIZE hexadecimal :: Word64 -> Builder #-}+{-# RULES "hexadecimal/Integer" hexadecimal = integer 16 :: Integer -> Builder #-}+hexadecimal i+    | i < 0     = singleton '-' <> go (-i)+    | otherwise = go i+  where+    go n | n < 16    = hexDigit n+         | otherwise = go (n `quot` 16) <> hexDigit (n `rem` 16)++digit :: Integral a => a -> Builder+digit n = singleton $! i2d (fromIntegral n)+{-# INLINE digit #-}++hexDigit :: Integral a => a -> Builder+hexDigit n+    | n <= 9    = singleton $! i2d (fromIntegral n)+    | otherwise = singleton $! toEnum (fromIntegral n + 87)+{-# INLINE hexDigit #-}++int :: Int -> Builder+int = decimal+{-# INLINE int #-}++data T = T !Integer !Int++integer :: Int -> Integer -> Builder+integer 10 (S# i#) = decimal (I# i#)+integer 16 (S# i#) = hexadecimal (I# i#)+integer base i+    | i < 0     = singleton '-' <> go (-i)+    | otherwise = go i+  where+    go n | n < maxInt = int (fromInteger n)+         | otherwise  = putH (splitf (maxInt * maxInt) n)++    splitf p n+      | p > n       = [n]+      | otherwise   = splith p (splitf (p*p) n)++    splith p (n:ns) = case n `quotRemInteger` p of+                        PAIR(q,r) | q > 0     -> q : r : splitb p ns+                                  | otherwise -> r : splitb p ns+    splith _ _      = error "splith: the impossible happened."++    splitb p (n:ns) = case n `quotRemInteger` p of+                        PAIR(q,r) -> q : r : splitb p ns+    splitb _ _      = []++    T maxInt10 maxDigits10 =+        until ((>mi) . (*10) . fstT) (\(T n d) -> T (n*10) (d+1)) (T 10 1)+      where mi = fromIntegral (maxBound :: Int)+    T maxInt16 maxDigits16 =+        until ((>mi) . (*16) . fstT) (\(T n d) -> T (n*16) (d+1)) (T 16 1)+      where mi = fromIntegral (maxBound :: Int)++    fstT (T a _) = a++    maxInt | base == 10 = maxInt10+           | otherwise  = maxInt16+    maxDigits | base == 10 = maxDigits10+              | otherwise  = maxDigits16++    putH (n:ns) = case n `quotRemInteger` maxInt of+                    PAIR(x,y)+                        | q > 0     -> int q <> pblock r <> putB ns+                        | otherwise -> int r <> putB ns+                        where q = fromInteger x+                              r = fromInteger y+    putH _ = error "putH: the impossible happened"++    putB (n:ns) = case n `quotRemInteger` maxInt of+                    PAIR(x,y) -> pblock q <> pblock r <> putB ns+                        where q = fromInteger x+                              r = fromInteger y+    putB _ = mempty++    pblock = loop maxDigits+      where+        loop !d !n+            | d == 1    = digit n+            | otherwise = loop (d-1) q <> digit r+            where q = n `quotInt` base+                  r = n `remInt` base
+ Data/Text/Lazy/Builder/RealFloat.hs view
@@ -0,0 +1,239 @@+{-# LANGUAGE OverloadedStrings #-}++-- |+-- Module:    Data.Text.Lazy.Builder.RealFloat+-- Copyright: (c) The University of Glasgow 1994-2002+-- License:   see libraries/base/LICENSE+--+-- Write a floating point value to a 'Builder'.++module Data.Text.Lazy.Builder.RealFloat+    (+      FPFormat(..)+    , realFloat+    , formatRealFloat+    ) where++import Data.Array.Base (unsafeAt)+import Data.Array.IArray+import Data.Text.Lazy.Builder.Functions ((<>), i2d)+import Data.Text.Lazy.Builder.Int (decimal)+import Data.Text.Lazy.Builder.RealFloat.Functions (roundTo)+import Data.Text.Lazy.Builder+import qualified Data.Text as T++-- | Control the rendering of floating point numbers.+data FPFormat = Exponent+              -- ^ Scientific notation (e.g. @2.3e123@).+              | Fixed+              -- ^ Standard decimal notation.+              | Generic+              -- ^ Use decimal notation for values between @0.1@ and+              -- @9,999,999@, and scientific notation otherwise.+                deriving (Enum, Read, Show)++-- | Show a signed 'RealFloat' value to full precision,+-- using standard decimal notation for arguments whose absolute value lies+-- between @0.1@ and @9,999,999@, and scientific notation otherwise.+realFloat :: (RealFloat a) => a -> Builder+{-# SPECIALIZE realFloat :: Float -> Builder #-}+{-# SPECIALIZE realFloat :: Double -> Builder #-}+realFloat x = formatRealFloat Generic Nothing x++formatRealFloat :: (RealFloat a) =>+                   FPFormat+                -> Maybe Int  -- ^ Number of decimal places to render.+                -> a+                -> Builder+{-# SPECIALIZE formatRealFloat :: FPFormat -> Maybe Int -> Float -> Builder #-}+{-# SPECIALIZE formatRealFloat :: FPFormat -> Maybe Int -> Double -> Builder #-}+formatRealFloat fmt decs x+   | isNaN x                   = "NaN"+   | isInfinite x              = if x < 0 then "-Infinity" else "Infinity"+   | x < 0 || isNegativeZero x = singleton '-' <> doFmt fmt (floatToDigits (-x))+   | otherwise                 = doFmt fmt (floatToDigits x)+ where+  doFmt format (is, e) =+    let ds = map i2d is in+    case format of+     Generic ->+      doFmt (if e < 0 || e > 7 then Exponent else Fixed)+            (is,e)+     Exponent ->+      case decs of+       Nothing ->+        let show_e' = decimal (e-1) in+        case ds of+          "0"     -> "0.0e0"+          [d]     -> singleton d <> ".0e" <> show_e'+          (d:ds') -> singleton d <> singleton '.' <> fromString ds' <> singleton 'e' <> show_e'+          []      -> error "formatRealFloat/doFmt/Exponent: []"+       Just dec ->+        let dec' = max dec 1 in+        case is of+         [0] -> "0." <> fromText (T.replicate dec' "0") <> "e0"+         _ ->+          let+           (ei,is') = roundTo (dec'+1) is+           (d:ds') = map i2d (if ei > 0 then init is' else is')+          in+          singleton d <> singleton '.' <> fromString ds' <> singleton 'e' <> decimal (e-1+ei)+     Fixed ->+      let+       mk0 ls = case ls of { "" -> "0" ; _ -> fromString ls}+      in+      case decs of+       Nothing+          | e <= 0    -> "0." <> fromText (T.replicate (-e) "0") <> fromString ds+          | otherwise ->+             let+                f 0 s    rs  = mk0 (reverse s) <> singleton '.' <> mk0 rs+                f n s    ""  = f (n-1) ('0':s) ""+                f n s (r:rs) = f (n-1) (r:s) rs+             in+                f e "" ds+       Just dec ->+        let dec' = max dec 0 in+        if e >= 0 then+         let+          (ei,is') = roundTo (dec' + e) is+          (ls,rs)  = splitAt (e+ei) (map i2d is')+         in+         mk0 ls <> (if null rs then "" else singleton '.' <> fromString rs)+        else+         let+          (ei,is') = roundTo dec' (replicate (-e) 0 ++ is)+          d:ds' = map i2d (if ei > 0 then is' else 0:is')+         in+         singleton d <> (if null ds' then "" else singleton '.' <> fromString ds')+++-- Based on "Printing Floating-Point Numbers Quickly and Accurately"+-- by R.G. Burger and R.K. Dybvig in PLDI 96.+-- This version uses a much slower logarithm estimator. It should be improved.++-- | 'floatToDigits' takes a base and a non-negative 'RealFloat' number,+-- and returns a list of digits and an exponent.+-- In particular, if @x>=0@, and+--+-- > floatToDigits base x = ([d1,d2,...,dn], e)+--+-- then+--+--      (1) @n >= 1@+--+--      (2) @x = 0.d1d2...dn * (base**e)@+--+--      (3) @0 <= di <= base-1@++floatToDigits :: (RealFloat a) => a -> ([Int], Int)+{-# SPECIALIZE floatToDigits :: Float -> ([Int], Int) #-}+{-# SPECIALIZE floatToDigits :: Double -> ([Int], Int) #-}+floatToDigits 0 = ([0], 0)+floatToDigits x =+ let+  (f0, e0) = decodeFloat x+  (minExp0, _) = floatRange x+  p = floatDigits x+  b = floatRadix x+  minExp = minExp0 - p -- the real minimum exponent+  -- Haskell requires that f be adjusted so denormalized numbers+  -- will have an impossibly low exponent.  Adjust for this.+  (f, e) =+   let n = minExp - e0 in+   if n > 0 then (f0 `quot` (expt b n), e0+n) else (f0, e0)+  (r, s, mUp, mDn) =+   if e >= 0 then+    let be = expt b e in+    if f == expt b (p-1) then+      (f*be*b*2, 2*b, be*b, be)     -- according to Burger and Dybvig+    else+      (f*be*2, 2, be, be)+   else+    if e > minExp && f == expt b (p-1) then+      (f*b*2, expt b (-e+1)*2, b, 1)+    else+      (f*2, expt b (-e)*2, 1, 1)+  k :: Int+  k =+   let+    k0 :: Int+    k0 =+     if b == 2 then+        -- logBase 10 2 is very slightly larger than 8651/28738+        -- (about 5.3558e-10), so if log x >= 0, the approximation+        -- k1 is too small, hence we add one and need one fixup step less.+        -- If log x < 0, the approximation errs rather on the high side.+        -- That is usually more than compensated for by ignoring the+        -- fractional part of logBase 2 x, but when x is a power of 1/2+        -- or slightly larger and the exponent is a multiple of the+        -- denominator of the rational approximation to logBase 10 2,+        -- k1 is larger than logBase 10 x. If k1 > 1 + logBase 10 x,+        -- we get a leading zero-digit we don't want.+        -- With the approximation 3/10, this happened for+        -- 0.5^1030, 0.5^1040, ..., 0.5^1070 and values close above.+        -- The approximation 8651/28738 guarantees k1 < 1 + logBase 10 x+        -- for IEEE-ish floating point types with exponent fields+        -- <= 17 bits and mantissae of several thousand bits, earlier+        -- convergents to logBase 10 2 would fail for long double.+        -- Using quot instead of div is a little faster and requires+        -- fewer fixup steps for negative lx.+        let lx = p - 1 + e0+            k1 = (lx * 8651) `quot` 28738+        in if lx >= 0 then k1 + 1 else k1+     else+        -- f :: Integer, log :: Float -> Float,+        --               ceiling :: Float -> Int+        ceiling ((log (fromInteger (f+1) :: Float) ++                 fromIntegral e * log (fromInteger b)) /+                   log 10)+--WAS:            fromInt e * log (fromInteger b))++    fixup n =+      if n >= 0 then+        if r + mUp <= expt 10 n * s then n else fixup (n+1)+      else+        if expt 10 (-n) * (r + mUp) <= s then n else fixup (n+1)+   in+   fixup k0++  gen ds rn sN mUpN mDnN =+   let+    (dn, rn') = (rn * 10) `quotRem` sN+    mUpN' = mUpN * 10+    mDnN' = mDnN * 10+   in+   case (rn' < mDnN', rn' + mUpN' > sN) of+    (True,  False) -> dn : ds+    (False, True)  -> dn+1 : ds+    (True,  True)  -> if rn' * 2 < sN then dn : ds else dn+1 : ds+    (False, False) -> gen (dn:ds) rn' sN mUpN' mDnN'++  rds =+   if k >= 0 then+      gen [] r (s * expt 10 k) mUp mDn+   else+     let bk = expt 10 (-k) in+     gen [] (r * bk) s (mUp * bk) (mDn * bk)+ in+ (map fromIntegral (reverse rds), k)++-- Exponentiation with a cache for the most common numbers.+minExpt, maxExpt :: Int+minExpt = 0+maxExpt = 1100++expt :: Integer -> Int -> Integer+expt base n+    | base == 2 && n >= minExpt && n <= maxExpt = expts `unsafeAt` n+    | base == 10 && n <= maxExpt10              = expts10 `unsafeAt` n+    | otherwise                                 = base^n++expts :: Array Int Integer+expts = array (minExpt,maxExpt) [(n,2^n) | n <- [minExpt .. maxExpt]]++maxExpt10 :: Int+maxExpt10 = 324++expts10 :: Array Int Integer+expts10 = array (minExpt,maxExpt10) [(n,10^n) | n <- [minExpt .. maxExpt10]]
− tests/Benchmarks.hs
@@ -1,463 +0,0 @@-{-# LANGUAGE BangPatterns, GADTs, MagicHash #-}--import qualified Data.ByteString.Char8 as BS-import qualified Data.ByteString.Lazy.Char8 as BL-import qualified Data.ByteString.Lazy.Internal as BL-import Control.Monad.Trans (liftIO)-import Control.Exception (evaluate)-import Criterion.Main-import Data.Char-import Data.Monoid (mappend, mempty)-import qualified Data.ByteString.UTF8 as UTF8-import qualified Data.Text as TS-import qualified Data.Text.IO as TS-import qualified Data.Text.Lazy as TL-import qualified Data.Text.Lazy.Builder as TB-import qualified Data.Text.Lazy.IO as TL-import qualified Data.List as L-import qualified Data.Text.Encoding as TS-import qualified Data.Text.Lazy.Encoding as TL-import qualified Criterion.MultiMap as M-import Control.DeepSeq-import Criterion.Config-import GHC.Base---myConfig-    | False     = defaultConfig {-                    -- Always display an 800x600 window.-                    cfgPlot = M.singleton KernelDensity (Window 800 600)-                  }-    | otherwise = defaultConfig--instance NFData BS.ByteString--instance NFData BL.ByteString where-    rnf BL.Empty        = ()-    rnf (BL.Chunk _ ts) = rnf ts--data B where-    B :: NFData a => a -> B--instance NFData B where-    rnf (B b) = rnf b--main = do-  let dataFile = "text/test/russian.txt"-  bsa <- BS.readFile dataFile-  let tsa     = TS.decodeUtf8 bsa-      tsb     = TS.toUpper tsa-      tla     = TL.fromChunks (TS.chunksOf 16376 tsa)-      tlb     = TL.fromChunks (TS.chunksOf 16376 tsb)-      bsb     = TS.encodeUtf8 tsb-      bla     = BL.fromChunks (chunksOf 16376 bsa)-      blb     = BL.fromChunks (chunksOf 16376 bsb)-      bsa_len = BS.length bsa-      tsa_len = TS.length tsa-      bla_len = BL.length bla-      tla_len = TL.length tla-      la      = UTF8.toString bsa-      la_len  = L.length la-      tsb_len = TS.length tsb-      lb      = TS.unpack tsb-      bsl     = BS.lines bsa-      bll     = BL.lines bla-      tsl     = TS.lines tsa-      tll     = TL.lines tla-      ll      = L.lines la-  defaultMainWith-    myConfig-    (liftIO . evaluate $-     rnf [B tsa, B tsb, B tla, B tlb, B bsa, B bsb, B bla, B blb,-          B bsa_len, B tsa_len, B bla_len, B tla_len, B la, B la_len,-          B tsb_len, B lb, B bsl, B bll, B tsl, B tll, B ll])-    [-      bgroup "append" [-        bench "ts" $ nf (TS.append tsb) tsa-      , bench "tl" $ nf (TL.append tlb) tla-      , bench "bs" $ nf (BS.append bsb) bsa-      , bench "bl" $ nf (BL.append blb) bla-      , bench "l" $ nf ((++) lb) la-      ],-      bgroup "concat" [-        bench "ts" $ nf TS.concat tsl-      , bench "tl" $ nf TL.concat tll-      , bench "bs" $ nf BS.concat bsl-      , bench "bl" $ nf BL.concat bll-      , bench "l" $ nf L.concat ll-      ],-      bgroup "cons" [-        bench "ts" $ nf (TS.cons c) tsa-      , bench "tl" $ nf (TL.cons c) tla-      , bench "bs" $ nf (BS.cons c) bsa-      , bench "bl" $ nf (BL.cons c) bla-      , bench "l" $ nf (c:) la-      ],-      bgroup "concatMap" [-        bench "ts" $ nf (TS.concatMap (TS.replicate 3 . TS.singleton)) tsa-      , bench "tl" $ nf (TL.concatMap (TL.replicate 3 . TL.singleton)) tla-      , bench "bs" $ nf (BS.concatMap (BS.replicate 3)) bsa-      , bench "bl" $ nf (BL.concatMap (BL.replicate 3)) bla-      , bench "l" $ nf (L.concatMap (L.replicate 3 . (:[]))) la-      ],-      bgroup "decode" [-        bench "ts" $ nf TS.decodeUtf8 bsa-      , bench "tl" $ nf TL.decodeUtf8 bla-      , bench "bs" $ nf BS.unpack bsa-      , bench "bl" $ nf BL.unpack bla-      , bench "l" $ nf UTF8.toString bsa-      ],-      bgroup "drop" [-        bench "ts" $ nf (TS.drop (tsa_len `div` 3)) tsa-      , bench "tl" $ nf (TL.drop (tla_len `div` 3)) tla-      , bench "bs" $ nf (BS.drop (bsa_len `div` 3)) bsa-      , bench "bl" $ nf (BL.drop (bla_len `div` 3)) bla-      , bench "l" $ nf (L.drop (la_len `div` 3)) la-      ],-      bgroup "encode" [-        bench "ts" $ nf TS.encodeUtf8 tsa-      , bench "tl" $ nf TL.encodeUtf8 tla-      , bench "bs" $ nf BS.pack la-      , bench "bl" $ nf BL.pack la-      , bench "l" $ nf UTF8.fromString la-      ],-      bgroup "filter" [-        bench "ts" $ nf (TS.filter p0) tsa-      , bench "tl" $ nf (TL.filter p0) tla-      , bench "bs" $ nf (BS.filter p0) bsa-      , bench "bl" $ nf (BL.filter p0) bla-      , bench "l" $ nf (L.filter p0) la-      ],-      bgroup "filter.filter" [-        bench "ts" $ nf (TS.filter p1 . TS.filter p0) tsa-      , bench "tl" $ nf (TL.filter p1 . TL.filter p0) tla-      , bench "bs" $ nf (BS.filter p1 . BS.filter p0) bsa-      , bench "bl" $ nf (BL.filter p1 . BL.filter p0) bla-      , bench "l" $ nf (L.filter p1 . L.filter p0) la-      ],-      bgroup "foldl'" [-        bench "ts" $ nf (TS.foldl' len 0) tsa-      , bench "tl" $ nf (TL.foldl' len 0) tla-      , bench "bs" $ nf (BS.foldl' len 0) bsa-      , bench "bl" $ nf (BL.foldl' len 0) bla-      , bench "l" $ nf (L.foldl' len 0) la-      ],-      bgroup "foldr" [-        bench "ts" $ nf (L.length . TS.foldr (:) []) tsa-      , bench "tl" $ nf (L.length . TL.foldr (:) []) tla-      , bench "bs" $ nf (L.length . BS.foldr (:) []) bsa-      , bench "bl" $ nf (L.length . BL.foldr (:) []) bla-      , bench "l" $ nf (L.length . L.foldr (:) []) la-      ],-      bgroup "head" [-        bench "ts" $ nf TS.head tsa-      , bench "tl" $ nf TL.head tla-      , bench "bs" $ nf BS.head bsa-      , bench "bl" $ nf BL.head bla-      , bench "l" $ nf L.head la-      ],-      bgroup "init" [-        bench "ts" $ nf TS.init tsa-      , bench "tl" $ nf TL.init tla-      , bench "bs" $ nf BS.init bsa-      , bench "bl" $ nf BL.init bla-      , bench "l" $ nf L.init la-      ],-      bgroup "intercalate" [-        bench "ts" $ nf (TS.intercalate tsw) tsl-      , bench "tl" $ nf (TL.intercalate tlw) tll-      , bench "bs" $ nf (BS.intercalate bsw) bsl-      , bench "bl" $ nf (BL.intercalate blw) bll-      , bench "l" $ nf (L.intercalate lw) ll-      ],-      bgroup "intersperse" [-        bench "ts" $ nf (TS.intersperse c) tsa-      , bench "tl" $ nf (TL.intersperse c) tla-      , bench "bs" $ nf (BS.intersperse c) bsa-      , bench "bl" $ nf (BL.intersperse c) bla-      , bench "l" $ nf (L.intersperse c) la-      ],-      bgroup "isInfixOf" [-        bench "ts" $ nf (TS.isInfixOf tsw) tsa-      , bench "tl" $ nf (TL.isInfixOf tlw) tla-      , bench "bs" $ nf (BS.isInfixOf bsw) bsa-        -- no isInfixOf for lazy bytestrings-      , bench "l" $ nf (L.isInfixOf lw) la-      ],-      bgroup "last" [-        bench "ts" $ nf TS.last tsa-      , bench "tl" $ nf TL.last tla-      , bench "bs" $ nf BS.last bsa-      , bench "bl" $ nf BL.last bla-      , bench "l" $ nf L.last la-      ],-      bgroup "map" [-        bench "ts" $ nf (TS.map f) tsa-      , bench "tl" $ nf (TL.map f) tla-      , bench "bs" $ nf (BS.map f) bsa-      , bench "bl" $ nf (BL.map f) bla-      , bench "l" $ nf (L.map f) la-      ],-      bgroup "mapAccumL" [-        bench "ts" $ nf (TS.mapAccumL g 0) tsa-      , bench "tl" $ nf (TL.mapAccumL g 0) tla-      , bench "bs" $ nf (BS.mapAccumL g 0) bsa-      , bench "bl" $ nf (BL.mapAccumL g 0) bla-      , bench "l" $ nf (L.mapAccumL g 0) la-      ],-      bgroup "mapAccumR" [-        bench "ts" $ nf (TS.mapAccumR g 0) tsa-      , bench "tl" $ nf (TL.mapAccumR g 0) tla-      , bench "bs" $ nf (BS.mapAccumR g 0) bsa-      , bench "bl" $ nf (BL.mapAccumR g 0) bla-      , bench "l" $ nf (L.mapAccumR g 0) la-      ],-      bgroup "map.map" [-        bench "ts" $ nf (TS.map f . TS.map f) tsa-      , bench "tl" $ nf (TL.map f . TL.map f) tla-      , bench "bs" $ nf (BS.map f . BS.map f) bsa-      , bench "bl" $ nf (BL.map f . BL.map f) bla-      , bench "l" $ nf (L.map f . L.map f) la-      ],-      bgroup "readFile" [-        bench "ts" $ TS.readFile dataFile-      , bench "tl" $ nfIO (TL.readFile dataFile)-      , bench "bs" $ BS.readFile dataFile-      , bench "bl" $ nfIO (BL.length `fmap` BL.readFile dataFile)-      , bench "l" $ nfIO (length `fmap` readFile dataFile)-      ],-      bgroup "replicate char" [-        bench "ts" $ nf (TS.replicate bsa_len) (TS.singleton c)-      , bench "tl" $ nf (TL.replicate (fromIntegral bsa_len)) (TL.singleton c)-      , bench "bs" $ nf (BS.replicate bsa_len) c-      , bench "bl" $ nf (BL.replicate (fromIntegral bsa_len)) c-      , bench "l" $ nf (L.replicate bsa_len) c-      ],-      bgroup "replicate string" [-        bench "ts" $ nf (TS.replicate (bsa_len `div` TS.length tsw)) tsw-      , bench "tl" $ nf (TL.replicate (fromIntegral bsa_len `div` TL.length tlw)) tlw-      , bench "l" $ nf (replicat (bsa_len `div` TS.length tsw)) lw-      ],-      bgroup "reverse" [-        bench "ts" $ nf TS.reverse tsa-      , bench "tl" $ nf TL.reverse tla-      , bench "bs" $ nf BS.reverse bsa-      , bench "bl" $ nf BL.reverse bla-      , bench "l" $ nf L.reverse la-      ],-      bgroup "take" [-        bench "ts" $ nf (TS.take (tsa_len `div` 3)) tsa-      , bench "tl" $ nf (TL.take (tla_len `div` 3)) tla-      , bench "bs" $ nf (BS.take (bsa_len `div` 3)) bsa-      , bench "bl" $ nf (BL.take (bla_len `div` 3)) bla-      , bench "l" $ nf (L.take (la_len `div` 3)) la-      ],-      bgroup "tail" [-        bench "ts" $ nf TS.tail tsa-      , bench "tl" $ nf TL.tail tla-      , bench "bs" $ nf BS.tail bsa-      , bench "bl" $ nf BL.tail bla-      , bench "l" $ nf L.tail la-      ],-      bgroup "toLower" [-        bench "ts" $ nf TS.toLower tsa-      , bench "tl" $ nf TL.toLower tla-      , bench "bs" $ nf (BS.map toLower) bsa-      , bench "bl" $ nf (BL.map toLower) bla-      , bench "l" $ nf (L.map toLower) la-      ],-      bgroup "toUpper" [-        bench "ts" $ nf TS.toUpper tsa-      , bench "tl" $ nf TL.toUpper tla-      , bench "bs" $ nf (BS.map toUpper) bsa-      , bench "bl" $ nf (BL.map toUpper) bla-      , bench "l" $ nf (L.map toUpper) la-      ],-      bgroup "words" [-        bench "ts" $ nf TS.words tsa-      , bench "tl" $ nf TL.words tla-      , bench "bs" $ nf BS.words bsa-      , bench "bl" $ nf BL.words bla-      , bench "l" $ nf L.words la-      ],-      bgroup "zipWith" [-        bench "ts" $ nf (TS.zipWith min tsb) tsa-      , bench "tl" $ nf (TL.zipWith min tlb) tla-      , bench "bs" $ nf (BS.zipWith min bsb) bsa-      , bench "bl" $ nf (BL.zipWith min blb) bla-      , bench "l" $ nf (L.zipWith min lb) la-      ],-      bgroup "length" [-        bgroup "cons" [-          bench "ts" $ nf (TS.length . TS.cons c) tsa-        , bench "tl" $ nf (TL.length . TL.cons c) tla-        , bench "bs" $ nf (BS.length . BS.cons c) bsa-        , bench "bl" $ nf (BL.length . BL.cons c) bla-        , bench "l" $ nf (L.length . (:) c) la-        ],-        bgroup "decode" [-          bench "ts" $ nf (TS.length . TS.decodeUtf8) bsa-        , bench "tl" $ nf (TL.length . TL.decodeUtf8) bla-        , bench "bs" $ nf (L.length . BS.unpack) bsa-        , bench "bl" $ nf (L.length . BL.unpack) bla-        , bench "utf8-string" $ nf (L.length . UTF8.toString) bsa-        ],-        bgroup "drop" [-          bench "ts" $ nf (TS.length . TS.drop (tsa_len `div` 3)) tsa-        , bench "tl" $ nf (TL.length . TL.drop (tla_len `div` 3)) tla-        , bench "bs" $ nf (BS.length . BS.drop (bsa_len `div` 3)) bsa-        , bench "bl" $ nf (BL.length . BL.drop (bla_len `div` 3)) bla-        , bench "l" $ nf (L.length . L.drop (la_len `div` 3)) la-        ],-        bgroup "filter" [-          bench "ts" $ nf (TS.length . TS.filter p0) tsa-        , bench "tl" $ nf (TL.length . TL.filter p0) tla-        , bench "bs" $ nf (BS.length . BS.filter p0) bsa-        , bench "bl" $ nf (BL.length . BL.filter p0) bla-        , bench "l" $ nf (L.length . L.filter p0) la-        ],-        bgroup "filter.filter" [-          bench "ts" $ nf (TS.length . TS.filter p1 . TS.filter p0) tsa-        , bench "tl" $ nf (TL.length . TL.filter p1 . TL.filter p0) tla-        , bench "bs" $ nf (BS.length . BS.filter p1 . BS.filter p0) bsa-        , bench "bl" $ nf (BL.length . BL.filter p1 . BL.filter p0) bla-        , bench "l" $ nf (L.length . L.filter p1 . L.filter p0) la-        ],-        bgroup "init" [-          bench "ts" $ nf (TS.length . TS.init) tsa-        , bench "tl" $ nf (TL.length . TL.init) tla-        , bench "bs" $ nf (BS.length . BS.init) bsa-        , bench "bl" $ nf (BL.length . BL.init) bla-        , bench "l" $ nf (L.length . L.init) la-        ],-        bgroup "intercalate" [-          bench "ts" $ nf (TS.length . TS.intercalate tsw) tsl-        , bench "tl" $ nf (TL.length . TL.intercalate tlw) tll-        , bench "bs" $ nf (BS.length . BS.intercalate bsw) bsl-        , bench "bl" $ nf (BL.length . BL.intercalate blw) bll-        , bench "l" $ nf (L.length . L.intercalate lw) ll-        ],-        bgroup "intersperse" [-          bench "ts" $ nf (TS.length . TS.intersperse c) tsa-        , bench "tl" $ nf (TL.length . TL.intersperse c) tla-        , bench "bs" $ nf (BS.length . BS.intersperse c) bsa-        , bench "bl" $ nf (BL.length . BL.intersperse c) bla-        , bench "l" $ nf (L.length . L.intersperse c) la-        ],-        bgroup "map" [-          bench "ts" $ nf (TS.length . TS.map f) tsa-        , bench "tl" $ nf (TL.length . TL.map f) tla-        , bench "bs" $ nf (BS.length . BS.map f) bsa-        , bench "bl" $ nf (BL.length . BL.map f) bla-        , bench "l" $ nf (L.length . L.map f) la-        ],-        bgroup "map.map" [-          bench "ts" $ nf (TS.length . TS.map f . TS.map f) tsa-        , bench "tl" $ nf (TL.length . TL.map f . TL.map f) tla-        , bench "bs" $ nf (BS.length . BS.map f . BS.map f) bsa-        , bench "l" $ nf (L.length . L.map f . L.map f) la-        ],-        bgroup "replicate char" [-          bench "ts" $ nf (TS.length . TS.replicate bsa_len) (TS.singleton c)-        , bench "tl" $ nf (TL.length . TL.replicate (fromIntegral bsa_len)) (TL.singleton c)-        , bench "bs" $ nf (BS.length . BS.replicate bsa_len) c-        , bench "bl" $ nf (BL.length . BL.replicate (fromIntegral bsa_len)) c-        , bench "l" $ nf (L.length . L.replicate bsa_len) c-        ],-        bgroup "replicate string" [-          bench "ts" $ nf (TS.length . TS.replicate (bsa_len `div` TS.length tsw)) tsw-        , bench "tl" $ nf (TL.length . TL.replicate (fromIntegral bsa_len `div` TL.length tlw)) tlw-        , bench "l" $ nf (L.length . replicat (bsa_len `div` TS.length tsw)) lw-        ],-        bgroup "take" [-          bench "ts" $ nf (TS.length . TS.take (tsa_len `div` 3)) tsa-        , bench "tl" $ nf (TL.length . TL.take (tla_len `div` 3)) tla-        , bench "bs" $ nf (BS.length . BS.take (bsa_len `div` 3)) bsa-        , bench "bl" $ nf (BL.length . BL.take (bla_len `div` 3)) bla-        , bench "l" $ nf (L.length . L.take (la_len `div` 3)) la-        ],-        bgroup "tail" [-          bench "ts" $ nf (TS.length . TS.tail) tsa-        , bench "tl" $ nf (TL.length . TL.tail) tla-        , bench "bs" $ nf (BS.length . BS.tail) bsa-        , bench "bl" $ nf (BL.length . BL.tail) bla-        , bench "l" $ nf (L.length . L.tail) la-        ],-        bgroup "toLower" [-          bench "ts" $ nf (TS.length . TS.toLower) tsa-        , bench "tl" $ nf (TL.length . TL.toLower) tla-        , bench "bs" $ nf (BS.length . BS.map toLower) bsa-        , bench "bl" $ nf (BL.length . BL.map toLower) bla-        , bench "l" $ nf (L.length . L.map toLower) la-        ],-        bgroup "toUpper" [-          bench "ts" $ nf (TS.length . TS.toUpper) tsa-        , bench "tl" $ nf (TL.length . TL.toUpper) tla-        , bench "bs" $ nf (BS.length . BS.map toUpper) bsa-        , bench "bl" $ nf (BL.length . BL.map toUpper) bla-        , bench "l" $ nf (L.length . L.map toUpper) la-        ],-        bgroup "words" [-          bench "ts" $ nf (L.length . TS.words) tsa-        , bench "tl" $ nf (L.length . TL.words) tla-        , bench "bs" $ nf (L.length . BS.words) bsa-        , bench "bl" $ nf (L.length . BL.words) bla-        , bench "l" $ nf (L.length . L.words) la-        ],-        bgroup "zipWith" [-          bench "ts" $ nf (TS.length . TS.zipWith min tsb) tsa-        , bench "tl" $ nf (TL.length . TL.zipWith min tlb) tla-        , bench "bs" $ nf (L.length . BS.zipWith min bsb) bsa-        , bench "bl" $ nf (L.length . BL.zipWith min blb) bla-        , bench "l" $ nf (L.length . L.zipWith min lb) la-        ]-      ],-      bgroup "builder" [-        bench "mappend char" $ nf (TL.length . TB.toLazyText . mappendNChar 'a') 10000,-        bench "mappend 8 char" $ nf (TL.length . TB.toLazyText . mappend8Char) 'a',-        bench "mappend text" $ nf (TL.length . TB.toLazyText . mappendNText short) 10000-      ]-    ]-  where-    c  = 'й'-    p0 = (== c)-    p1 = (/= 'д')-    lw  = "право"-    bsw  = UTF8.fromString lw-    blw  = BL.fromChunks [bsw]-    tsw  = TS.pack lw-    tlw  = TL.fromChunks [tsw]-    f (C# c#) = C# (chr# (ord# c# +# 1#))-    g (I# i#) (C# c#) = (I# (i# +# 1#), C# (chr# (ord# c# +# i#)))-    len l _ = l + (1::Int)-    replicat n = concat . L.replicate n-    short = TS.pack "short"--chunksOf :: Int -> BS.ByteString -> [BS.ByteString]-chunksOf k = go-  where-    go t = case BS.splitAt k t of-             (a,b) | BS.null a -> []-                   | otherwise -> a : go b--mappendNChar :: Char -> Int -> TB.Builder-mappendNChar c n = go 0-  where-    go i-      | i < n     = TB.singleton c `mappend` go (i+1)-      | otherwise = mempty---- Gives more opportunity for inlining and elimination of unnecesary--- bounds checks.-mappend8Char :: Char -> TB.Builder-mappend8Char c = TB.singleton c `mappend` TB.singleton c `mappend`-                 TB.singleton c `mappend` TB.singleton c `mappend`-                 TB.singleton c `mappend` TB.singleton c `mappend`-                 TB.singleton c `mappend` TB.singleton c--mappendNText :: TS.Text -> Int -> TB.Builder-mappendNText t n = go 0-  where-    go i-      | i < n     = TB.fromText t `mappend` go (i+1)-      | otherwise = mempty
+ tests/Chartem.hs view
@@ -0,0 +1,153 @@+{-# LANGUAGE OverloadedStrings, ScopedTypeVariables #-}++import Data.Char+import Control.Monad (forM_)+import Data.Accessor ((^=))+import Data.Function+import Data.Maybe+import Data.List+import Debug.Trace+import Data.Text (Text)+import Data.Text.Encoding (decodeUtf8)+import Graphics.Rendering.Chart+import Graphics.Rendering.Chart.Gtk (renderableToWindow)+import System.Environment (getArgs)+import Text.Printf+import qualified Data.ByteString as B+import qualified Data.Map as M+import qualified Data.Text as T++data Row = Row {+      rowName :: !Text+    , rowMean :: !Double+    , rowMeanLB :: !Double+    , rowMeanUB :: !Double+    , rowStdDev :: !Double+    , rowStdDevLB :: !Double+    , rowStdDevUB :: !Double+    } deriving (Show)++parseRow :: Text -> Row+parseRow = f . T.split ","+  where f [n,m,ml,mu,s,sl,su] = Row {+                                  rowName = n+                                , rowMean = r m+                                , rowMeanLB = r ml+                                , rowMeanUB = r mu+                                , rowStdDev = r s+                                , rowStdDevLB = r sl+                                , rowStdDevUB = r su+                                }+        r = read . T.unpack++readCSV :: FilePath -> IO [Row]+readCSV = fmap (map parseRow . tail . T.lines . decodeUtf8) . B.readFile++groupRows :: [Row] -> M.Map Text [Row]+groupRows = M.map (sortBy (compare `on` rowName)) . foldr f M.empty+    where f r m = let (p,s) = T.breakEnd "/" (rowName r)+                  in M.insertWith' (++) (T.init . T.tail $ p)+                     [r { rowName = T.init s}] m++main = do+  args <- getArgs+  groups <- mapM (fmap groupRows . readCSV) args+  let dd = M.unionsWith (++) . map (M.map (:[])) $ groups+  forM_ (M.toList dd) $ \(tdesc,rows) -> do+      let desc = T.unpack tdesc+      if False+       then renderableToWindow (renderMark desc rows) 400 160+       else renderableToPNGFile (renderMark desc rows) 400 160+                                (printf "time-%s.png" (map clean desc))+  where clean '/' = '-'+        clean c | isSpace c = '-'+                | otherwise = c++instance BarsPlotValue LogValue where+    barsReference = LogValue 1e-300+    barsAdd (LogValue a) (LogValue b) = LogValue (a * b)++renderMark :: String -> [[Row]] -> Renderable ()+renderMark desc rows+  | useLog    = toRenderable linLayout+  | otherwise = toRenderable logLayout+  where+    useLog = minimum (map minimum values) >= maximum (map maximum values) / 25+    values = transpose . map (map rowMean) $ rows+    keys   = map git (head rows)+        where git r = let n = T.unpack . rowName $ r+                      in maybe n id . flip lookup mappings $ n+    mappings = [("bl", "lazy BS"), ("bs", "strict BS"), ("l", "list"),+                ("tl", "lazy T"), ("ts", "strict T")]++    linLayout = layout1_title ^= "Timings for \"" ++ desc ++ "\""+              $ layout1_plots ^= [ Left (plotBars linBars) ]+              $ layout1_left_axis ^= linLeftAxis+              $ layout1_bottom_axis ^= bottomAxis+              $ defaultLayout1 :: Layout1 Double Double++    logLayout = layout1_title ^= "Timings for \"" ++ desc +++                "\" (log scale)"+              $ layout1_plots ^= [ Left (plotBars logBars) ]+              $ layout1_left_axis ^= logLeftAxis+              $ layout1_bottom_axis ^= bottomAxis+              $ defaultLayout1 :: Layout1 Double LogValue++    logLeftAxis = laxis_generate ^= autoScaledLogAxis logSecAxis+                $ laxis_reverse ^= False+                $ defaultLayoutAxis++    linLeftAxis = laxis_generate ^= autoScaledAxis linSecAxis+                $ defaultLayoutAxis++    bottomAxis = laxis_generate ^= autoScaledAxis typeAxis+               $ defaultLayoutAxis++    linBars = plot_bars_values ^= (zip [0.5,1.5..] values)+            $ defaultPlotBars++    logBars = plot_bars_values ^= (zip [0.5,1.5..] . map (map LogValue) $ values)+            $ defaultPlotBars++    typeAxis = la_labelf ^= (ix keys . floor)+             $ la_nLabels ^= length keys+             $ defaultLinearAxis++    ix (x:xs) n | n <= 0    = x+                | otherwise = ix xs (n-1)+    ix [] _                 = ""++    linSecAxis = la_labelf ^= secs+               $ defaultLinearAxis++    logSecAxis = loga_labelf ^= (secs . fromLV)+               $ defaultLogAxis++    fromLV (LogValue v) = v++-- | Try to render meaningful time-axis labels.+--+-- /FIXME/: Trouble is, we need to know the range of times for this to+-- work properly, so that we don't accidentally display consecutive+-- values that appear identical (e.g. \"43 ms, 43 ms\").+secs :: Double -> String+secs k+    | k < 0      = '-' : secs (-k)+    | k >= 1e9   = (k/1e9)  `with` "Gs"+    | k >= 1e6   = (k/1e6)  `with` "Ms"+    | k >= 1e4   = (k/1e3)  `with` "Ks"+    | k >= 1     = k        `with` "s"+    | k >= 1e-3  = (k*1e3)  `with` "ms"+    | k >= 1e-6  = (k*1e6)  `with` "µs"+    | k >= 1e-9  = (k*1e9)  `with` "ns"+    | k >= 1e-12 = (k*1e12) `with` "ps"+    | otherwise  = printf "%g s" k+     where with (t :: Double) (u :: String)+               | t >= 1e9  = printf "%.4g %s" t u+               | t >= 1e6  = printf "%.0f %s" t u+               | t >= 1e5  = printf "%.0f %s" t u+               | t >= 1e4  = printf "%.0f %s" t u+               | t >= 1e3  = printf "%.0f %s" t u+               | t >= 1e2  = printf "%.0f %s" t u+               | t >= 1e1  = printf "%.0f %s" t u+               | otherwise = printf "%.0f %s" t u
tests/Makefile view
@@ -23,7 +23,7 @@  cabal := $(shell which cabal 2>/dev/null) -all: bm qc coverage regressions+all: qc coverage regressions  lib: $(lib) @@ -78,11 +78,6 @@ regressions: Regressions.o TestUtils.o 	$(ghc) $(ghc-test-flags) -o $@ $^ $(lib) -Benchmarks.o: ghc-opt-flags = -O-bm Benchmarks.o: ghc-flags += -package utf8-string-bm: Benchmarks.o-	$(ghc) $(ghc-flags) -o $@ $^ $(lib)- SlowFunctions.o: ghc-opt-flags = -O2 SearchBench.o: ghc-opt-flags = -O %.o: %.hs@@ -98,4 +93,4 @@ 	curl -O http://projects.haskell.org/text/text-testdata.tar.bz2  clean:-	-rm -rf *.o *.hi *.tix bm qc qc-hpc stdio-hpc hpcdir .hpc coverage-html+	-rm -rf *.o *.hi *.tix qc qc-hpc stdio-hpc hpcdir .hpc coverage-html
+ tests/README.markdown view
@@ -0,0 +1,43 @@+Tests+=====++This directory contains the tests for the Text library. To run these tests, you+will need the test data from:++    http://projects.haskell.org/text/text-testdata.tar.bz2++You should extract that archive to the same directory as this README (some tests+rely on this).++There are two categories of tests: functional tests (including QuickCheck+properties), and benchmarks.++Functional tests+----------------++TODO++Benchmarks+----------++The benchmarks are located in the `benchmarks` subdirectory. An overview of+what's in that directory:++    python            Python implementations of some benchmarks+    ruby              Ruby implementations of some benchmarks+    src               Source files of the haskell benchmarks+    benchmarks.cabal  Cabal file which compiles all benchmarks+    Makefile          Has targets for common tasks++To compile the benchmarks, navigate to the `benchmarks` subdirectory and run+`cabal configure && cabal build`. Then, you can run the benchmarks using:++    ./dist/build/benchmarks/benchmarks++However, since there quite a lot of benchmarks, you usually don't want to run+them all. Instead, use the `-l` flag to get a list of benchmarks:++    ./dist/build/benchmarks/benchmarks++And run the ones you want to inspect. If you want to configure the benchmarks+further, the exact parameters can be changed in `src/Data/Text/Benchmarks.hs`.
+ tests/Regressions.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE OverloadedStrings, ScopedTypeVariables #-}++-- Regression tests for specific bugs.++import Control.Exception (SomeException, handle)+import System.IO+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as LB+import qualified Data.Text as T+import qualified Data.Text.IO as T+import qualified Data.Text.Lazy as LT+import qualified Data.Text.Lazy.Encoding as LE+import qualified Test.Framework as F+import qualified Test.Framework.Providers.HUnit as F+import Test.HUnit (assertFailure)+import TestUtils (withTempFile)++-- Reported by Michael Snoyman: UTF-8 encoding a large lazy bytestring+-- caused either a segfault or attempt to allocate a negative number+-- of bytes.+lazy_encode_crash = withTempFile $ \ _ h ->+   LB.hPut h . LE.encodeUtf8 . LT.pack . replicate 100000 $ 'a'++-- Reported by Pieter Laeremans: attempting to read an incorrectly+-- encoded file can result in a crash in the RTS (i.e. not merely an+-- exception).+hGetContents_crash = withTempFile $ \ path h -> do+  B.hPut h (B.pack [0x78, 0xc4 ,0x0a]) >> hClose h+  h' <- openFile path ReadMode+  hSetEncoding h' utf8+  handle (\(_::SomeException) -> return ()) $+    T.hGetContents h' >> assertFailure "T.hGetContents should crash"++-- Reported by Ian Lynagh: attempting to allocate a sufficiently large+-- string (via either Array.new or Text.replicate) could result in an+-- integer overflow.+replicate_crash = handle (\(_::SomeException) -> return ()) $+                  T.replicate (2^power) "0123456789abcdef" `seq`+                  assertFailure "T.replicate should crash"+  where+    power | maxBound == (2147483647::Int) = 28+          | otherwise                     = 60 :: Int++tests :: F.Test+tests = F.testGroup "crashers" [+          F.testCase "hGetContents_crash" hGetContents_crash+        , F.testCase "lazy_encode_crash" lazy_encode_crash+        , F.testCase "replicate_crash" replicate_crash+        ]++main = F.defaultMain [tests]
+ tests/SearchBench.hs view
@@ -0,0 +1,115 @@+{-# LANGUAGE BangPatterns, OverloadedStrings #-}++import Criterion.Main+import Data.Text.Encoding+import Data.Text.Search+import qualified Data.ByteString.Char8 as B+import qualified Data.Text as T+import qualified SlowFunctions as Slow++main = defaultMain [+         bench "big/fast" $ (length . search indices)+       , bench "big/slow" $ (length . search Slow.indices)+       , bench "big/bytestring" $ (length . searchBS)+       , bench "dna/fast" $ (length . searchDNA indices)+       , bench "dna/slow" $ (length . searchDNA Slow.indices)+       , bench "dna/bytestring" $ (length . searchDNABS)+       ]++search f n = f needle' haystack+  where+    needle'  = T.drop (n `mod` 20) needle+    needle   = T.replicate 10 "abcdefghijklmnopqrstuvwxyz"+    haystack = T.replicate 100 $+               T.concat [ T.replicate 1000 "def"+                        , needle+                        , T.replicate 1000 "123"+                        ]+                        +searchDNA f n = f needle haystack+  where+    needle   = T.take 4 . T.drop (n `mod` (T.length dna - 4)) $ dna+    haystack = T.replicate 100 dna++replicateBS n = B.concat . replicate n++searchBS n = indicesBS needle' haystack+  where+    needle'  = B.drop (n `mod` 20) needle+    needle   = replicateBS 10 "abcdefghijklmnopqrstuvwxyz"+    haystack = replicateBS 100 $+               B.concat [ replicateBS 1000 "def"+                        , needle+                        , replicateBS 1000 "123"+                        ]+                        +searchDNABS n = indicesBS needle haystack+  where+    needle   = B.take 4 . B.drop (n `mod` (B.length bdna - 4)) $ bdna+    haystack = replicateBS 100 bdna++indicesBS :: B.ByteString -> B.ByteString -> [Int]+indicesBS pat+    | B.null pat = error "empty"+    | otherwise  = go 0+  where+    l  = B.length pat+    go !i src = case B.breakSubstring pat src of+                  (h,t) | B.null t -> []+                        | otherwise -> i' : go (i'+l) (B.drop l t)+                      where i' = i + B.length h++dna = decodeASCII bdna++bdna :: B.ByteString+bdna = "\+\CGTAACAAGGTTTCCGTAGGTGAACCTGCGGAAGGATCATTGTTGAGATCACATAATAATTGATCGGGTT\+\AATCTGGAGGATCTGTTTACTTTGGTCACCCATGAGCATTTGCTGTTGAAGTGACCTAGAATTGCCATCG\+\AGCCTCCTTGGGAGCTTTCTTGTTGGCGAGATCTAAACCCTTGCCCGGCGCAGTTTTGCTCCAAGTCGTT\+\TGACACATAATTGGTGAAGGGGGTGGCATCCTTCCCTGACCCTCCCCCAACTATTTTTTTAACAACTCTC\+\AGCAACGGAGACTCAGTCTTCGGCAAATGCGATAAATGGTGTGAATTGCAGAATCCCGTGCACCATCGAG\+\TCTTTGAACGCAAGTTGCGCCCGAGGCCATCAGGCCAAGGGCACGCCTGCCTGGGCATTGCGAGTCATAT\+\CTCTCCCTTAACGAGGCTGTCCATACATACTGTTCAGCCGGTGCGGATGTGAGTTTGGCCCCTTGTTCTT\+\TGGTACGGGGGGTCTAAGAGCTGCATGGGCTTTTGATGGTCCTAAATACGGCAAGAGGTGGACGAACTAT\+\GCTACAACAAAATTGTTGTGCAGAGGCCCCGGGTTGTCGTATTAGATGGGCCACCGTAATCTGAAGACCC\+\TTTTGAACCCCATTGGAGGCCCATCAACCCATGATCAGTTGATGGCCATTTGGTTGCGACCCCAGGTCAG\+\GTGAGCAACAGCTGTCGTAACAAGGTTTCCGTAGGGTGAACTGCGGAAGGATCATTGTTGAGATCACATA\+\ATAATTGATCGAGTTAATCTGGAGGATCTGTTTACTTGGGTCACCCATGGGCATTTGCTGTTGAAGTGAC\+\CTAGATTTGCCATCGAGCCTCCTTGGGAGCATCCTTGTTGGCGATATCTAAACCCTCAATTTTTCCCCCA\+\ATCAAATTACACAAAATTGGTGGAGGGGGTGGCATTCTTCCCTTACCCTCCCCCAAATATTTTTTTAACA\+\ACTCTCAGCAACGGATATCTCAGCTCTTGCATCGATGAAGAACCCACCGAAATGCGATAAATGGTGTGAA\+\TTGCAGAATCCCGTGAACCATCGAGTCTTTGAACGCAAGTTGCGCCCGAGGCCATCAGGCCAAGGGCACG\+\CCTGCCTGGGCATTGCGAGTCATATCTCTCCCTTAACGAGGCTGTCCATACATACTGTTCAGCCGGTGCG\+\GATGTGAGTTTGGCCCCTTGTTCTTTGGTACGGGGGGTCTAAGAGATGCATGGGCTTTTGATGGTCCTAA\+\ATACGGCAAGAGGTGGACGAACTATGCTACAACAAAATTGTTGTGCAAAGGCCCCGGGTTGTCGTATAAG\+\ATGGGCCACCGATATCTGAAGACCCTTTTGGACCCCATTGGAGCCCATCAACCCATGTCAGTTGATGGCC\+\ATTCGTAACAAGGTTTCCGTAGGTGAACCTGCGGAAGGATCATTGTTGAGATCACATAATAATTGATCGA\+\GTTAATCTGGAGGATCTGTTTACTTGGGTCACCCATGGGCATTTGCTGTTGAAGTGACCTAGATTTGCCA\+\TCGAGCCTCCTTGGGAGCTTTCTTGTTGGCGATATCTAAACCCTTGCCCGGCAGAGTTTTGGGAATCCCG\+\TGAACCATCGAGTCTTTGAACGCAAGTTGCGCCCGAGGCCATCAGGCCAAGGGCACGCCTGCCTGGGCAT\+\TGCGAGTCATATCTCTCCCTTAACGAGGCTGTCCATACACACCTGTTCAGCCGGTGCGGATGTGAGTTTG\+\GCCCCTTGTTCTTTGGTACGGGGGGTCTAAGAGCTGCATGGGCTTTTGATGGTCCTAAATACGGCAAGAG\+\GTGGACGAACTATGCTACAACAAAATTGTTGTGCAAAGGCCCCGGGTTGTCGTATTAGATGGGCCACCAT\+\AATCTGAAGACCCTTTTGAACCCCATTGGAGGCCCATCAACCCATGATCAGTTGATGGCCATTTGGTTGC\+\GACCCAGTCAGGTGAGGGTAGGTGAACCTGCGGAAGGATCATTGTTGAGATCACATAATAATTGATCGAG\+\TTAATCTGGAGGATCTGTTTACTTTGGTCACCCATGGGCATTTGCTGTTGAAGTGACCTAGATTTGCCAT\+\CGAGCCTCCTTGGGAGCTTTCTTGTTGGCGAGATCTAAACCCTTGCCCGGCGGAGTTTGGCGCCAAGTCA\+\TATGACACATAATTGGTGAAGGGGGTGGCATCCTGCCCTGACCCTCCCCAAATTATTTTTTTAACAACTC\+\TCAGCAACGGATATCTCGGCTCTTGCATCGATGAAGAACGCAGCGAAATGCGATAAATGGTGTGAATTGC\+\AGAATCCCGTGAACCATCGAGTCTTTGGAACGCAAGTTGCGCCCGAGGCCATCAGGCCAAGGGCACGCCT\+\GCCTGGGCATTGGGAATCATATCTCTCCCCTAACGAGGCTATCCAAACATACTGTTCATCCGGTGCGGAT\+\GTGAGTTTGGCCCCTTGTTCTTTGGTACCGGGGGTCTAAGAGCTGCATGGGCATTTGATGGTCCTCAAAA\+\CGGCAAGAGGTGGACGAACTATGCCACAACAAAATTGTTGTCCCAAGGCCCCGGGTTGTCGTATTAGATG\+\GGCCACCGTAACCTGAAGACCCTTTTGAACCCCATTGGAGGCCCATCAACCCATGATCAGTTGATGACCA\+\TTTGTTGCGACCCCAGTCAGCTGAGCAACCCGCTGAGTGGAAGGTCATTGCCGATATCACATAATAATTG\+\ATCGAGTTAATCTGGAGGATCTGTTTACTTGGTCACCCATGAGCATTTGCTGTTGAAGTGACCTAGATTT\+\GCCATCGAGCCTCCTTGGGAGTTTTCTTGTTGGCGAGATCTAAACCCTTGCCCGGCGGAGTTGTGCGCCA\+\AGTCATATGACACATAATTGGTGAAGGGGGTGGCATCCTGCCCTGACCCTCCCCAAATTATTTTTTTAAC\+\AACTCTCAGCAACGGATATCTCGGCTCTTGCATCGATGAAGAACGCAGCGAAATGCGATAAATGGTGTGA\+\ATTGCAGAATCCCGTGAACCATCGAGTCTTTGAACGCAAGTTGCGCCCGAGGCCATCAGGCCAAGGGCAC\+\GCCTGCCTGGGCATTGCGAGTCATATCTCTCCCTTAACGAGGCTGTCCATACATACTGTTCATCCGGTGC\+\GGATGTGAGTTTGGCCCCTTGTTCTTTGGTACGGGGGGTCTAAGAGCTGCATGGGCATTTGATGGTCCTC\+\AAAACGGCAAGAGGTGGACGAACTATGCTACAACCAAATTGTTGTCCCAAGGCCCCGGGTTGTCGTATTA\+\GATGGGCCACCGTAACCTGAAGACCCTTTTGAACCCCATTGGAGGCCCATCAACCCATGATCAGTTGATG\+\ACCATGTGTTGCGACCCCAGTCAGCTGAGCAACGCGCTGAGCGTAACAAGGTTTCCGTAGGTGGACCTCC\+\GGGAGGATCATTGTTGAGATCACATAATAATTGATCGAGGTAATCTGGAGGATCTGCATATTTTGGTCAC"
− tests/benchmarks/Cut.hs
@@ -1,60 +0,0 @@-import qualified Data.ByteString.Char8 as B-import qualified Data.ByteString.Lazy.Char8 as BL-import qualified Data.Text.IO as T-import qualified Data.Text as T-import qualified Data.Text.Encoding as T-import qualified Data.Text.Lazy.Encoding as TL-import qualified Data.Text.Lazy.IO as TL-import qualified Data.Text.Lazy as TL-import Data.Int (Int64)-import Numeric (readDec)-import System.Environment (getArgs)--bytestring file s e = do-  t <- B.readFile file-  B.putStr (cut t)-  where-    cut = B.unlines . map (B.take (e - s) . B.drop s) . B.lines--lazyBytestring file s e = do-  t <- BL.readFile file-  BL.putStr (cut (fromIntegral s) (fromIntegral e) t)-  where-    cut s e = BL.unlines . map (BL.take (e - s) . BL.drop s) . BL.lines--lazyText file s e = do-  t <- TL.readFile file-  TL.putStr (cut (fromIntegral s) (fromIntegral e) t)-  where-    cut s e = TL.unlines . map (TL.take (e - s) . TL.drop s) . TL.lines--text file s e = do-  t <- T.readFile file-  T.putStr (cut t)-  where-    cut = T.unlines . map (T.take (e - s) . T.drop s) . T.lines--textBS file s e = do-  bs <- B.readFile file-  T.putStr . cut . T.decodeUtf8 $ bs-  where-    cut = T.unlines . map (T.take (e - s) . T.drop s) . T.lines--lazyTextBS file s e = do-  t <- BL.readFile file-  TL.putStr (cut (fromIntegral s) (fromIntegral e) (TL.decodeUtf8 t))-  where-    cut s e = TL.unlines . map (TL.take (e - s) . TL.drop s) . TL.lines--main = do-  (name : ss : es : file : _) <- getArgs-  let [(s',"")] = readDec ss-      [(e,"")] = readDec es-      s = s' - 1-  case name of-    "bs" -> bytestring file s e-    "lbs" -> lazyBytestring file s e-    "ltext" -> lazyText file s e-    "text" -> text file s e-    "ltextBS" -> lazyTextBS file s e-    "textBS" -> textBS file s e
− tests/benchmarks/DecodeUtf8.hs
@@ -1,107 +0,0 @@-import qualified Data.ByteString as B-import qualified Data.ByteString.Lazy as BL-import qualified Data.Text as T-import qualified Data.Text.IO as T-import qualified Data.Text.Encoding as T-import qualified Data.Text.Lazy as TL-import qualified Data.Text.Lazy.Encoding as TL-import qualified Data.Text.Lazy.IO as TL-import qualified Codec.Binary.UTF8.Generic as U8-import Control.DeepSeq-import System.Environment-import System.IO--strict h = do-  bs <- B.hGetContents h-  rnf (T.decodeUtf8 bs) `seq` return ()--strict_len h = do-  bs <- B.hGetContents h-  print . T.length . T.decodeUtf8 $ bs--strict_init_len h = do-  bs <- B.hGetContents h-  print . T.length . T.init . T.decodeUtf8 $ bs--strict_io h = do-  hSetEncoding h utf8-  t <- T.hGetContents h-  rnf t `seq` return ()--strict_len_io h = do-  hSetEncoding h utf8-  t <- T.hGetContents h-  print (T.length t)--lazy h = do-  bs <- BL.hGetContents h-  rnf (TL.decodeUtf8 bs) `seq` return ()--lazy_len h = do-  bs <- BL.hGetContents h-  print . TL.length . TL.decodeUtf8 $ bs--lazy_init_len h = do-  bs <- BL.hGetContents h-  print . TL.length . TL.init . TL.decodeUtf8 $ bs--lazy_io h = do-  hSetEncoding h utf8-  t <- TL.hGetContents h-  rnf t `seq` return ()--lazy_len_io h = do-  hSetEncoding h utf8-  t <- TL.hGetContents h-  print (TL.length t)--string h = do-  hSetEncoding h utf8-  t <- hGetContents h-  rnf t `seq` return ()--string_len h = do-  hSetEncoding h utf8-  t <- hGetContents h-  print (length t)--lazy_string_utf8 h = do-  bs <- BL.hGetContents h-  let t = U8.toString bs-  rnf t `seq` return ()--lazy_string_utf8_len h = do-  bs <- BL.hGetContents h-  let t = U8.toString bs-  print (length t)--strict_string_utf8 h = do-  bs <- B.hGetContents h-  let t = U8.toString bs-  rnf t `seq` return ()--strict_string_utf8_len h = do-  bs <- B.hGetContents h-  let t = U8.toString bs-  print (length t)--main = do-  [kind,name] <- getArgs-  h <- openFile name ReadMode-  case kind of-    "strict" -> strict h-    "strict_len" -> strict_len h-    "strict_init_len" -> strict_init_len h-    "strict_io" -> strict_io h-    "strict_len_io" -> strict_len_io h-    "lazy" -> lazy h-    "lazy_len" -> lazy_len h-    "lazy_init_len" -> lazy_init_len h-    "lazy_io" -> lazy_io h-    "lazy_len_io" -> lazy_len_io h-    "string" -> string h-    "string_len" -> string_len h-    "lazy_string_utf8" -> lazy_string_utf8 h-    "lazy_string_utf8_len" -> lazy_string_utf8_len h-    "strict_string_utf8" -> strict_string_utf8 h-    "strict_string_utf8_len" -> strict_string_utf8_len h
− tests/benchmarks/EncodeUtf8.hs
@@ -1,55 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-import qualified Data.ByteString as B-import qualified Data.ByteString.Lazy as BL-import qualified Data.Text as T-import qualified Data.Text.IO as T-import qualified Data.Text.Encoding as T-import qualified Data.Text.Lazy as TL-import qualified Data.Text.Lazy.Encoding as TL-import qualified Data.Text.Lazy.IO as TL-import qualified Codec.Binary.UTF8.Generic as U8-import System.Environment-import System.IO--strict_bytestring k s = do-  let t = T.replicate k (T.pack s)-  B.putStr (T.encodeUtf8 t)--lazy_bytestring k s = do-  let t = TL.replicate (fromIntegral k) (TL.pack s)-  BL.putStr (TL.encodeUtf8 t)--strict_io k s = do-  let t = T.replicate k (T.pack s)-  hSetEncoding stdout utf8-  T.putStr t--lazy_io k s = do-  let t = TL.replicate (fromIntegral k) (TL.pack s)-  hSetEncoding stdout utf8-  TL.putStr t--string k s = do-  let t = concat $ replicate k s-  hSetEncoding stdout utf8-  putStr t--lazy_string_utf8 k s = do-  let t = concat $ replicate k s-  BL.putStr (U8.fromString t)--strict_string_utf8 k s = do-  let t = concat $ replicate k s-  B.putStr (U8.fromString t)--main = do-  [kind,str,kstr] <- getArgs-  let k = read kstr * 1000000-  case kind of-    "strict" -> strict_bytestring k str-    "lazy" -> lazy_bytestring k str-    "strict_io" -> strict_io k str-    "lazy_io" -> lazy_io k str-    "string" -> string k str-    "lazy_string_utf8" -> lazy_string_utf8 k str-    "strict_string_utf8" -> strict_string_utf8 k str
− tests/benchmarks/Equality.hs
@@ -1,31 +0,0 @@-import System.Environment-import qualified Data.ByteString.Char8 as B-import qualified Data.ByteString.Lazy.Char8 as BL-import qualified Data.Text as T-import qualified Data.Text.Encoding as T-import qualified Data.Text.Lazy as TL-import qualified Data.Text.Lazy.Encoding as TL--func :: (Eq a) => [a] -> IO ()-func ls =-  print . sum . map (\needle -> length . filter (==needle) $ ls) $ take 100 ls--bytestring haystack = func =<< B.lines `fmap` B.readFile haystack--lazyBytestring haystack = func =<< BL.lines `fmap` BL.readFile haystack--text haystack = func =<< (T.lines . T.decodeUtf8) `fmap` B.readFile haystack--lazyText haystack = func =<<-                    (TL.lines . TL.decodeUtf8) `fmap` BL.readFile haystack--string haystack = func =<< lines `fmap` readFile haystack--main = do-  args <- getArgs-  case args of-    ["bs",h] -> bytestring h-    ["lazybs",h] -> lazyBytestring h-    ["text",h] -> text h-    ["lazytext",h] -> lazyText h-    ["string",h] -> string h
− tests/benchmarks/FileIndices.hs
@@ -1,25 +0,0 @@-{-# LANGUAGE BangPatterns #-}--import System.Environment (getArgs)-import qualified Data.Text.Lazy.IO as T-import qualified Data.Text.Lazy as T-import qualified Data.Text.Lazy.Encoding as T-import qualified Data.ByteString.Lazy.Char8 as B-import qualified Data.ByteString.Char8 as BS-import qualified Data.ByteString.Lazy.Search as B--text :: FilePath -> String -> IO ()-text file pat = T.readFile file >>= print . T.count (T.pack pat)--textBS :: FilePath -> String -> IO ()-textBS file pat = B.readFile file >>= print . T.count (T.pack pat) . T.decodeUtf8--bytestring :: FilePath -> String -> IO ()-bytestring file pat = B.readFile file >>= print . length . B.indices (BS.pack pat)--main = do-  (name : file : pat : _) <- getArgs-  case name of-    "bs" -> bytestring file pat-    "text" -> text file pat-    "textBS" -> textBS file pat
− tests/benchmarks/FileRead.hs
@@ -1,57 +0,0 @@-{-# LANGUAGE BangPatterns #-}--import System.Environment (getArgs)-import qualified Data.Text.IO as T-import qualified Data.Text as T-import qualified Data.Text.Encoding as T-import qualified Data.Text.Lazy.IO as TL-import qualified Data.Text.Lazy as TL-import qualified Data.Text.Lazy.Encoding as TL-import qualified Data.ByteString.Char8 as B-import qualified Data.ByteString.Lazy.Char8 as BL-import System.IO--string :: Handle -> IO ()-string h = hGetContents h >>= print . length--ltext :: Handle -> IO ()-ltext h = do-  t <- {-# SCC "TL.hGetContents" #-} TL.hGetContents h-  print (TL.length t)--ltextBS :: Handle -> IO ()-ltextBS h = do-  bs <- {-# SCC "B.hGetContents" #-} BL.hGetContents h-  print . TL.length . TL.decodeUtf8 $ bs--text :: Handle -> IO ()-text h = do-  t <- {-# SCC "T.hGetContents" #-} T.hGetContents h-  print (T.length t)--textBS :: Handle -> IO ()-textBS h = do-  bs <- {-# SCC "B.hGetContents" #-} B.hGetContents h-  print . T.length . T.decodeUtf8 $ bs--lbytestring :: Handle -> IO ()-lbytestring h = do-  bs <- {-# SCC "BL.hGetContents" #-} BL.hGetContents h-  print (BL.length bs)--bytestring :: Handle -> IO ()-bytestring h = do-  bs <- {-# SCC "B.hGetContents" #-} B.hGetContents h-  print (B.length bs)--main = do-  (name : file : _) <- getArgs-  h <- openFile file ReadMode-  case name of-    "bs" -> bytestring h-    "lbs" -> lbytestring h-    "ltext" -> ltext h-    "ltextBS" -> ltextBS h-    "string" -> string h-    "text" -> text h-    "textBS" -> textBS h
− tests/benchmarks/FoldLines.hs
@@ -1,47 +0,0 @@-{-# LANGUAGE BangPatterns #-}--import System.Environment-import System.IO-import qualified Data.Text as T-import qualified Data.Text.IO as T-import qualified Data.ByteString as S---- Text-foldLinesT :: (a -> T.Text -> a) -> a -> Handle -> IO a-foldLinesT f z0 h = go z0-  where-    go !z = do-        eof <- hIsEOF h-        if eof-            then return z-            else do-                l <- T.hGetLine h-                let z' = f z l in go z'-{-# INLINE foldLinesT #-}--testT :: Handle -> IO Int-testT = foldLinesT (\n _ -> n + 1) 0----ByteString-foldLinesB :: (a -> S.ByteString -> a) -> a -> Handle -> IO a-foldLinesB f z0 h = go z0-  where-    go !z = do-        eof <- hIsEOF h-        if eof-            then return z-            else do-                l <- S.hGetLine h-                let z' = f z l in go z'-{-# INLINE foldLinesB #-}--testB :: Handle -> IO Int-testB = foldLinesB (\n _ -> n + 1) 0--main = do-  (name : file : _) <- getArgs-  h <- openFile file ReadMode-  hSetBuffering h (BlockBuffering (Just 16384))-  case name of-    "bs" -> testB h-    "text" -> testT h
− tests/benchmarks/HtmlCombinator.hs
@@ -1,24 +0,0 @@-{-# LANGUAGE BangPatterns, OverloadedStrings #-}-import Data.Monoid (mappend, mconcat)-import Prelude hiding (putStr)-import Data.Text.Lazy.Builder (Builder, fromText, toLazyText)-import Data.Text.Lazy.IO (putStr)--import qualified Data.Text as T--main :: IO ()-main = do-  putStr "Content-Type: text/html\n\n<table>"-  putStr . toLazyText $ mconcat (replicate 20000 makeRow) -  putStr "</table>"--makeRow :: Builder-makeRow = mconcat (map makeCol [1..50])--makeCol :: Int -> Builder-makeCol 1 = fromText "<tr><td>1</td>"-makeCol 50 = fromText "<td>50</td></tr>"-makeCol i = fromText "<td>" `mappend` (textInt i `mappend` fromText "</td>")--textInt :: Int -> Builder-textInt = fromText . T.pack . show
− tests/benchmarks/Makefile
@@ -1,18 +0,0 @@-CC := $(shell icu-config --cc)-CFLAGS := -g $(shell icu-config --cflags)-CPPFLAGS := $(shell icu-config --cppflags)-LDFLAGS := $(CFLAGS) $(shell icu-config --ldflags --ldflags-icuio)-ghc := ghc--all := FileRead FileRead_prof Replace Replace_prof fileread_c--all: $(all)--%: %.hs-	$(ghc) -O --make -o $@ $^--%_prof: %.hs-	$(ghc) -prof -auto-all -O --make -o $@ $^--clean:-	-rm -f *.hi *.o $(all)
− tests/benchmarks/Replace.hs
@@ -1,23 +0,0 @@-{-# LANGUAGE BangPatterns #-}-module Main (main) where--import System.Environment (getArgs)-import qualified Data.Text.Lazy as LT-import qualified Data.Text.Lazy.IO as LT-import qualified Data.ByteString.Lazy.Search as LB-import qualified Data.ByteString.Lazy.Char8 as LB-import qualified Data.ByteString.Char8 as B--lazyText file pat sub =-  LT.readFile file >>= LT.putStr . LT.replace (LT.pack pat) (LT.pack sub)--lazyBS file pat sub =-  LB.readFile file >>= LB.putStr . LB.replace (B.pack pat) (LB.pack sub)--main = do-  (kind : file : pat : sub : _) <- getArgs-  case kind of-    "lazyText" -> lazyText file pat sub-    "lazyTextNull" -> LT.readFile file >>= LT.putStr-    "lazyBS" -> lazyBS file pat sub-    "lazyBSNull" -> LB.readFile file >>= LB.putStr
− tests/benchmarks/ReplaceTags.hs
@@ -1,91 +0,0 @@--- Contributed by Ken Friis Larsen and Morten Ib Nielsen.--{-# LANGUAGE BangPatterns #-}-module Main (main) where--import System.Environment (getArgs)-import qualified Char--import qualified Data.Text as T-import qualified Data.Text.IO as T--import qualified Data.Text.Lazy as TL-import qualified Data.Text.Lazy.IO as TL-import qualified Data.ByteString.Lazy as BL-import qualified Data.Text.Lazy.Encoding as TLE---import qualified Data.ByteString.Char8 as BC-import qualified Data.ByteString as B-import qualified Data.Text.Encoding as TE--replaceTagsM file tag sub = -  BC.readFile file >>= BC.putStr . replaceTags tag sub . TE.encodeUtf8 . T.toLower . TE.decodeUtf8 -  where -    replaceTags tag replacement str = B.concat $ reverse $ replaceTags' [] (BC.pack $ '<' : tag) '>' (BC.pack replacement) str-    replaceTags' !res start end repl str =-      let (pre, post) = BC.breakSubstring start str-      in if BC.null post-           then  pre : res-           else replaceTags' (repl : pre : res) start end repl $ BC.drop 1 $-                BC.dropWhile (/= end) post--splitB sep str = seplen `seq` splitter str -  where -    splitter str = h : if B.null t then [] else splitter (B.drop seplen t)-      where (h,t) = B.breakSubstring sep str-    seplen = B.length sep-    -replaceTagsWrong file tagName sub = do-  content <- BC.readFile file-  let frags = map (BC.drop 1 . BC.dropWhile (/= '>')) -              $ splitB (BC.pack $ '<' : tagName) (BC.map Char.toLower content)-  BC.putStr $ BC.intercalate (BC.pack sub) frags- -replaceTagsK file tagName sub = do-  raw <- BC.readFile file -  let content = (TE.encodeUtf8 . T.toLower . TE.decodeUtf8) raw-  let frags = map (BC.drop 1 . BC.dropWhile (/= '>')) -              $ splitB (BC.pack $ '<' : tagName) content-  BC.putStr $ BC.intercalate (BC.pack sub) frags--replaceTagsO file tagName sub = do-  raw <- BC.readFile file -  let content = (TE.encodeUtf8 . T.toLower . TE.decodeUtf8) raw-  let frags = splitB (BC.pack $ '<' : tagName) content-  BC.putStr $ BC.intercalate (BC.pack sub) frags-  where -    splitB sep str = splitter str -      where -        splitter str = h : if BC.null t then [] else splitter (BC.drop 1 $ BC.dropWhile (/= '>') t)-          where (h,t) = B.breakSubstring sep str---    -replaceTagsT file tagName sub = do-  raw <- B.readFile file -  let content = TE.decodeUtf8 raw-  let frags = map (T.drop 1 . T.dropWhile (/= '>')) -              $ T.split (T.pack $ '<' : tagName) (T.toLower content)-  T.putStr $ T.intercalate (T.pack sub) frags-  -replaceTagsTL file tagName sub = do-  raw <- BL.readFile file -  let content = TLE.decodeUtf8 raw-  let frags = map (TL.drop 1 . TL.dropWhile (/= '>')) -              $ TL.split (TL.pack $ '<' : tagName) (TL.toLower content)-  TL.putStr $ TL.intercalate (TL.pack sub) frags---main = do-  (kind : file : tag : sub : _) <- getArgs-  case kind of-    "Text" -> replaceTagsT file tag sub-    "TextLazy" -> replaceTagsTL file tag sub-    "BytestringM" -> replaceTagsM file tag sub-    "BytestringK" -> replaceTagsK file tag sub-    "BytestringO" -> replaceTagsO file tag sub-    "TextNull" -> T.readFile file >>= T.putStr-    "ByteNull" -> B.readFile file >>= B.putStr-    "EncodeNull" -> B.readFile file >>= T.putStr . T.toLower . TE.decodeUtf8 -
+ tests/benchmarks/Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
− tests/benchmarks/fileread.py
@@ -1,41 +0,0 @@-#!/usr/bin/env python--import sys--def string(name):-    print len(open(name).read())--def lazystring(name):-    fp = open(name)-    n = 0-    d = True-    bs = 128 * 1024-    read = fp.read-    while d:-        d = len(read(bs))-        n += d-    print n--def lazytext(name):-    fp = open(name)-    n = 0-    d = True-    bs = 128 * 1024-    read = fp.read-    while d:-        s = read(bs)-        d = len(s.decode('utf-8', 'replace'))-        n += d-    print n--def text(name):-    print len(open(name).read().decode('utf-8', 'replace'))--if sys.argv[1] == 'bs':-    string(sys.argv[2])-if sys.argv[1] == 'lbs':-    lazystring(sys.argv[2])-elif sys.argv[1] == 'lazytext':-    lazytext(sys.argv[2])-elif sys.argv[1] == 'text':-    text(sys.argv[2])
− tests/benchmarks/fileread_c.c
@@ -1,96 +0,0 @@-#include <unicode/ustdio.h>-#include <stdio.h>-#include <stdlib.h>-#include <string.h>--void lazystring(const char *name)-{-    FILE *ufp = fopen(name, "r");-    const size_t bufsize = sizeof(char) * 32 * 1024;-    char *str = malloc(bufsize);-    long len = 0;-    int32_t n;--    do {-	n = fread(str, sizeof(char), bufsize, ufp);-	len += n;-    } while (n > 0);--    printf("%ld\n", len);-}--void lazytext(const char *name)-{-    UFILE *ufp = u_fopen(name, "r", NULL, "UTF-8");-    const size_t bufsize = sizeof(UChar) * 32 * 1024;-    UChar *str = malloc(bufsize);-    long len = 0;-    int32_t n;--    do {-	n = u_file_read(str, bufsize, ufp);-	len += n;-    } while (n > 0);--    printf("%ld\n", len);-}--void text(const char *name)-{-    UFILE *ufp = u_fopen(name, "r", NULL, "UTF-8");-    FILE *fp = u_fgetfile(ufp);-    UChar *str;-    long fsize;-    int32_t n;--    fseek(fp, 0, SEEK_END);-    fsize = ftell(fp);-    u_frewind(ufp);--    str = malloc(sizeof(*str) * fsize);--    n = u_file_read(str, fsize, ufp);--    printf("%d\n", n);-}--void string(const char *name)-{-    FILE *fp = fopen(name, "r");-    char *str;-    long fsize;-    int32_t n;--    fseek(fp, 0, SEEK_END);-    fsize = ftell(fp);-    fseek(fp, 0, SEEK_SET);--    str = malloc(sizeof(*str) * fsize);--    n = fread(str, sizeof(char), fsize, fp);--    printf("%d\n", n);-}--int main(int argc, char **argv)-{-    if (argc != 3) {-	fprintf(stderr, "Usage: %s handler filename\n", argv[0]);-	exit(1);-    }--    if (strcmp(argv[1], "lazystring") == 0)-	lazystring(argv[2]);-    else if (strcmp(argv[1], "lazytext") == 0)-	lazytext(argv[2]);-    else if (strcmp(argv[1], "string") == 0)-	string(argv[2]);-    else if (strcmp(argv[1], "text") == 0)-	text(argv[2]);-    else {-	fprintf(stderr, "no matching handler\n");-	return 1;-    }--    return 0;-}
+ tests/benchmarks/python/case_map.py view
@@ -0,0 +1,7 @@+#!/usr/bin/env python++import utils, sys++for f in sys.argv[1:]:+    t = utils.benchmark(lambda: utils.with_utf8_file(f, lambda c: c.upper()))+    sys.stderr.write('{0}: {1}\n'.format(f, t))
+ tests/benchmarks/python/file_read.py view
@@ -0,0 +1,7 @@+#!/usr/bin/env python++import utils, sys++for f in sys.argv[1:]:+    t = utils.benchmark(lambda: utils.with_utf8_file(f, lambda c: len(c)))+    sys.stderr.write('{0}: {1}\n'.format(f, t))
+ tests/benchmarks/python/sort.py view
@@ -0,0 +1,15 @@+#!/usr/bin/env python++import utils, sys++def sort(string):+    lines = string.splitlines()+    lines.sort()+    return '\n'.join(lines)++for f in sys.argv[1:]:+    t = utils.benchmark(lambda: sys.stdout.write(+                    				utils.with_utf8_file(f,sort).encode('utf-8'))+                    				)+    sys.stderr.write('{0}: {1}\n'.format(f, t))+
+ tests/benchmarks/python/strip_brackets.py view
@@ -0,0 +1,22 @@+#!/usr/bin/env python++import utils, sys++def strip_brackets(string):+    d = 0+    out = ''+    for c in string:+        if c == '{' or c == '[': d += 1++        if d > 0:+            out += ' '+        else:+            out += c++        if c == '}' or c == ']': d -= 1++    return out++for f in sys.argv[1:]:+    t = utils.benchmark(lambda: utils.with_utf8_file(f, strip_brackets))+    sys.stderr.write('{0}: {1}\n'.format(f, t))
+ tests/benchmarks/python/utils.py view
@@ -0,0 +1,22 @@+#!/usr/bin/env python++import sys, time++def benchmark_once(f):+    start = time.time()+    f()+    end = time.time()+    return end - start++def benchmark(f):+    runs = 100+    total = 0.0+    for i in range(runs):+        result = benchmark_once(f)+        sys.stderr.write('Run {0}: {1}\n'.format(i, result))+        total += result+    return total / runs++def with_utf8_file(filename, f):+    contents = open(filename).read().decode('utf-8')+    return f(contents)
+ tests/benchmarks/python/word_count.py view
@@ -0,0 +1,17 @@+#!/usr/bin/env python++import utils, sys++def word_count(string):+    freqs = {}+    for w in string.split():+        w = w.lower()+        if freqs.get(w):+            freqs[w] += 1+        else:+            freqs[w] = 1+    return freqs++for f in sys.argv[1:]:+    t = utils.benchmark(lambda: utils.with_utf8_file(f, word_count))+    sys.stderr.write('{0}: {1}\n'.format(f, t))
+ tests/benchmarks/ruby/case_map.rb view
@@ -0,0 +1,8 @@+#!/usr/bin/env ruby++require './utils.rb'++ARGV.each do |f|+  t = benchmark { with_utf8_file(f) { |c| c.upcase } }+  STDERR.puts "#{f}: #{t}"+end
+ tests/benchmarks/ruby/file_read.rb view
@@ -0,0 +1,8 @@+#!/usr/bin/env ruby++require './utils.rb'++ARGV.each do |f|+  t = benchmark { with_utf8_file(f) { |c| c.size } }+  STDERR.puts "#{f}: #{t}"+end
+ tests/benchmarks/ruby/sort.rb view
@@ -0,0 +1,14 @@+#!/usr/bin/env ruby++require './utils.rb'++def sort(str)+  str.lines.sort.join+end++ARGV.each do |f|+  t = benchmark do+    with_utf8_file(f) { |c| puts sort(c) }+  end+  STDERR.puts "#{f}: #{t}"+end
+ tests/benchmarks/ruby/strip_brackets.rb view
@@ -0,0 +1,21 @@+#!/usr/bin/env ruby++require './utils.rb'++def strip_brackets(str)+  d = 0+  out = ''++  str.each_char do |c|+    d += 1 if c == '{' || c == '['+    out << if d > 0 then ' ' else c end+    d -= 1 if c == '}' || c == ']'+  end++  out+end++ARGV.each do |f|+  t = benchmark { with_utf8_file(f) { |c| strip_brackets(c) } }+  STDERR.puts "#{f}: #{t}"+end
+ tests/benchmarks/ruby/utils.rb view
@@ -0,0 +1,20 @@+require 'benchmark'++def benchmark(&block)+  runs = 100+  total = 0++  runs.times do |i|+    result = Benchmark.measure(&block).total+    $stderr.puts "Run #{i}: #{result}"+    total += result+  end++  total / runs +end++def with_utf8_file(filename)+  File.open(filename, 'r:utf-8') do |file|+    yield file.read+  end+end
+ tests/benchmarks/ruby/word_count.rb view
@@ -0,0 +1,16 @@+#!/usr/bin/env ruby++require './utils.rb'++def word_count(str)+  freqs = Hash.new 0+  str.split.each do |w|+    freqs[w.downcase] += 1+  end+  freqs+end++ARGV.each do |f|+  t = benchmark { with_utf8_file(f) { |c| word_count(c) } }+  STDERR.puts "#{f}: #{t}"+end
+ tests/benchmarks/src/Data/Text/Benchmarks.hs view
@@ -0,0 +1,58 @@+-- | Main module to run the micro benchmarks+--+{-# LANGUAGE OverloadedStrings #-}+module Main+    ( main+    ) where++import Criterion.Main (Benchmark, defaultMain)+import System.FilePath ((</>))+import System.IO (IOMode (WriteMode), openFile, hSetEncoding, utf8)++import qualified Data.Text.Benchmarks.Builder as Builder+import qualified Data.Text.Benchmarks.CaseMap as CaseMap+import qualified Data.Text.Benchmarks.Cut as Cut+import qualified Data.Text.Benchmarks.DecodeUtf8 as DecodeUtf8+import qualified Data.Text.Benchmarks.EncodeUtf8 as EncodeUtf8+import qualified Data.Text.Benchmarks.Equality as Equality+import qualified Data.Text.Benchmarks.FileIndices as FileIndices+import qualified Data.Text.Benchmarks.FileRead as FileRead+import qualified Data.Text.Benchmarks.FoldLines as FoldLines+import qualified Data.Text.Benchmarks.HtmlCombinator as HtmlCombinator+import qualified Data.Text.Benchmarks.Ordering as Ordering+import qualified Data.Text.Benchmarks.Pure as Pure+import qualified Data.Text.Benchmarks.ReadNumbers as ReadNumbers+import qualified Data.Text.Benchmarks.Replace as Replace+import qualified Data.Text.Benchmarks.Sort as Sort+import qualified Data.Text.Benchmarks.StripBrackets as StripBrackets+import qualified Data.Text.Benchmarks.WordCount as WordCount++main :: IO ()+main = benchmarks >>= defaultMain++benchmarks :: IO [Benchmark]+benchmarks = do+    sink <- openFile "/dev/null" WriteMode+    hSetEncoding sink utf8+    sequence+        [ Builder.benchmark+        , CaseMap.benchmark (tf "russian.txt") sink+        , Cut.benchmark (tf "russian.txt") sink 30 60+        , DecodeUtf8.benchmark (tf "russian.txt")+        , EncodeUtf8.benchmark sink "επανάληψη 竺法蘭共譯"+        , Equality.benchmark (tf "japanese.txt")+        , FileIndices.benchmark (tf "russian.txt") "принимая"+        , FileRead.benchmark (tf "russian.txt")+        , FoldLines.benchmark (tf "russian.txt")+        , HtmlCombinator.benchmark sink+        , Ordering.benchmark (tf "russian.txt")+        , Pure.benchmark (tf "japanese.txt")+        , ReadNumbers.benchmark (tf "numbers.txt")+        , Replace.benchmark (tf "russian.txt") sink "принимая" "своем"+        , Sort.benchmark (tf "russian.txt") sink+        , StripBrackets.benchmark (tf "russian.txt") sink+        , WordCount.benchmark (tf "russian.txt")+        ]+  where+    -- Location of a test file+    tf = ("../text/test" </>)
+ tests/benchmarks/src/Data/Text/Benchmarks/Builder.hs view
@@ -0,0 +1,44 @@+-- | Testing the internal builder monoid+--+{-# LANGUAGE OverloadedStrings #-}+module Data.Text.Benchmarks.Builder+    ( benchmark+    ) where++import Criterion (Benchmark, bgroup, bench, nf)+import Data.Binary.Builder as B+import Data.ByteString.Char8 ()+import Data.Monoid (mconcat)+import qualified Blaze.ByteString.Builder as Blaze+import qualified Blaze.ByteString.Builder.Char.Utf8 as Blaze+import qualified Data.ByteString as SB+import qualified Data.ByteString.Lazy as LB+import qualified Data.Text as T+import qualified Data.Text.Lazy as LT+import qualified Data.Text.Lazy.Builder as LTB++benchmark :: IO Benchmark+benchmark = return $ bgroup "Builder"+    [ bench "LazyText" $ nf+        (LT.length . LTB.toLazyText . mconcat . map LTB.fromText) texts+    , bench "Binary" $ nf+        (LB.length . B.toLazyByteString . mconcat . map B.fromByteString)+        byteStrings+    , bench "Blaze" $ nf+        (LB.length . Blaze.toLazyByteString . mconcat . map Blaze.fromString)+        strings+    ]++texts :: [T.Text]+texts = take 200000 $ cycle ["foo", "λx", "由の"]+{-# NOINLINE texts #-}++-- Note that the non-ascii characters will be chopped+byteStrings :: [SB.ByteString]+byteStrings = take 200000 $ cycle ["foo", "λx", "由の"]+{-# NOINLINE byteStrings #-}++-- Note that the non-ascii characters will be chopped+strings :: [String]+strings = take 200000 $ cycle ["foo", "λx", "由の"]+{-# NOINLINE strings #-}
+ tests/benchmarks/src/Data/Text/Benchmarks/CaseMap.hs view
@@ -0,0 +1,15 @@+-- | This benchmark converts a number of UTF-8 encoded files to uppercase+--+module Data.Text.Benchmarks.CaseMap+    ( benchmark+    ) where++import Criterion (Benchmark, bench)+import System.IO (Handle)+import qualified Data.ByteString as B+import qualified Data.Text as T+import qualified Data.Text.Encoding as T++benchmark :: FilePath -> Handle -> IO Benchmark+benchmark fp sink = return $ bench "CaseMap" $+    B.readFile fp >>= B.hPutStr sink . T.encodeUtf8 . T.toUpper . T.decodeUtf8
+ tests/benchmarks/src/Data/Text/Benchmarks/Cut.hs view
@@ -0,0 +1,86 @@+-- | Cut into a file, selecting certain columns (e.g. lines 10 to 40)+--+module Data.Text.Benchmarks.Cut+    ( benchmark+    ) where++import Criterion (Benchmark, bgroup, bench)+import System.IO (Handle, hPutStr)+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as BC+import qualified Data.ByteString.Lazy as BL+import qualified Data.ByteString.Lazy.Char8 as BLC+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import qualified Data.Text.IO as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Encoding as TL+import qualified Data.Text.Lazy.IO as TL++benchmark :: FilePath -> Handle -> Int -> Int -> IO Benchmark+benchmark p sink from to = return $ bgroup "Cut"+    [ bench' "String" string+    , bench' "ByteString" byteString+    , bench' "LazyByteString" lazyByteString+    , bench' "Text" text+    , bench' "LazyText" lazyText+    , bench' "TextByteString" textByteString+    , bench' "LazyTextByteString" lazyTextByteString+    ]+  where+    bench' n s = bench n (s p sink from to)++string :: FilePath -> Handle -> Int -> Int -> IO ()+string fp sink from to = do+    s <- readFile fp+    hPutStr sink $ cut s+  where+    cut = unlines . map (take (to - from) . drop from) . lines++byteString :: FilePath -> Handle -> Int -> Int -> IO ()+byteString fp sink from to = do+    bs <- B.readFile fp+    B.hPutStr sink $ cut bs+  where+    cut = BC.unlines . map (B.take (to - from) . B.drop from) . BC.lines++lazyByteString :: FilePath -> Handle -> Int -> Int -> IO ()+lazyByteString fp sink from to = do+    bs <- BL.readFile fp+    BL.hPutStr sink $ cut bs+  where+    cut = BLC.unlines . map (BL.take (to' - from') . BL.drop from') . BLC.lines+    from' = fromIntegral from+    to' = fromIntegral to++text :: FilePath -> Handle -> Int -> Int -> IO ()+text fp sink from to = do+    t <- T.readFile fp+    T.hPutStr sink $ cut t+  where+    cut = T.unlines . map (T.take (to - from) . T.drop from) . T.lines++lazyText :: FilePath -> Handle -> Int -> Int -> IO ()+lazyText fp sink from to = do+    t <- TL.readFile fp+    TL.hPutStr sink $ cut t+  where+    cut = TL.unlines . map (TL.take (to' - from') . TL.drop from') . TL.lines+    from' = fromIntegral from+    to' = fromIntegral to++textByteString :: FilePath -> Handle -> Int -> Int -> IO ()+textByteString fp sink from to = do+    t <- T.decodeUtf8 `fmap` B.readFile fp+    B.hPutStr sink $ T.encodeUtf8 $ cut t+  where+    cut = T.unlines . map (T.take (to - from) . T.drop from) . T.lines++lazyTextByteString :: FilePath -> Handle -> Int -> Int -> IO ()+lazyTextByteString fp sink from to = do+    t <- TL.decodeUtf8 `fmap` BL.readFile fp+    BL.hPutStr sink $ TL.encodeUtf8 $ cut t+  where+    cut = TL.unlines . map (TL.take (to' - from') . TL.drop from') . TL.lines+    from' = fromIntegral from+    to' = fromIntegral to
+ tests/benchmarks/src/Data/Text/Benchmarks/DecodeUtf8.hs view
@@ -0,0 +1,95 @@+module Data.Text.Benchmarks.DecodeUtf8+    ( benchmark+    ) where++import Control.DeepSeq (rnf)+import Criterion (Benchmark, bgroup, bench)+import System.IO (IOMode (ReadMode), openFile, hGetContents, hSetEncoding, utf8)+import qualified Codec.Binary.UTF8.Generic as U8+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as BL+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import qualified Data.Text.IO as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Encoding as TL+import qualified Data.Text.Lazy.IO as TL++benchmark :: FilePath -> IO Benchmark+benchmark fp = return $ bgroup "DecodeUtf8"+    [ bench "Strict" $ do+        bs <- B.readFile fp+        rnf (T.decodeUtf8 bs) `seq` return ()++    , bench "StrictLength" $ do+        bs <- B.readFile fp+        rnf (T.length $ T.decodeUtf8 bs) `seq` return ()++    , bench "StrictInitLength" $ do+        bs <- B.readFile fp+        rnf (T.length $ T.init $ T.decodeUtf8 bs) `seq` return ()++    , bench "StrictIO" $ do+        h <- openFile fp ReadMode+        hSetEncoding h utf8+        t <- T.hGetContents h+        rnf t `seq` return ()++    , bench "StrictLengthIO" $ do+        h <- openFile fp ReadMode+        hSetEncoding h utf8+        t <- T.hGetContents h+        rnf (T.length t) `seq` return ()++    , bench "Lazy" $ do+        bs <- BL.readFile fp+        rnf (TL.decodeUtf8 bs) `seq` return ()++    , bench "LazyLength" $ do+        bs <- BL.readFile fp+        rnf (TL.length $ TL.decodeUtf8 bs) `seq` return ()++    , bench "LazyInitLength" $ do+        bs <- BL.readFile fp+        rnf (TL.length $ TL.init $ TL.decodeUtf8 bs) `seq` return ()++    , bench "LazyIO" $ do+        h <- openFile fp ReadMode+        hSetEncoding h utf8+        t <- TL.hGetContents h+        rnf t `seq` return ()++    , bench "LazyLengthIO" $ do+        h <- openFile fp ReadMode+        hSetEncoding h utf8+        t <- TL.hGetContents h+        rnf (TL.length t) `seq` return ()++    , bench "String" $ do+        h <- openFile fp ReadMode+        hSetEncoding h utf8+        t <- hGetContents h+        rnf t `seq` return ()++    , bench "StringLength" $ do+        h <- openFile fp ReadMode+        hSetEncoding h utf8+        t <- hGetContents h+        rnf (length t) `seq` return ()++    , bench "LazyStringUtf8" $ do+        s <- U8.toString `fmap` BL.readFile fp+        rnf s `seq` return ()++    , bench "LazyStringUtf8Length" $ do+        s <- U8.toString `fmap` BL.readFile fp+        rnf (length s) `seq` return ()++    , bench "StrictStringUtf8" $ do+        s <- U8.toString `fmap` B.readFile fp+        rnf s `seq` return ()++    , bench "StrictStringUtf8Length" $ do+        s <- U8.toString `fmap` B.readFile fp+        rnf (length s) `seq` return ()+    ]
+ tests/benchmarks/src/Data/Text/Benchmarks/EncodeUtf8.hs view
@@ -0,0 +1,33 @@+module Data.Text.Benchmarks.EncodeUtf8+    ( benchmark+    ) where++import Criterion (Benchmark, bgroup, bench)+import System.IO (Handle, hPutStr)+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as BL+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import qualified Data.Text.IO as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Encoding as TL+import qualified Data.Text.Lazy.IO as TL++benchmark :: Handle -> String -> IO Benchmark+benchmark sink string = return $ bgroup "EncodeUtf8"+    [ bench "String" $ hPutStr sink $ concat $ replicate k string+    , bench "Text" $ T.hPutStr sink $ T.replicate k text+    , bench "TextLazy" $ TL.hPutStr sink $+        TL.replicate (fromIntegral k) lazyText+    , bench "TextByteString" $ B.hPutStr sink $+        T.encodeUtf8 $ T.replicate k text+    , bench "TextByteStringLazy" $ BL.hPutStr sink $+        TL.encodeUtf8 $ TL.replicate (fromIntegral k) lazyText+    ]+  where+    -- The string in different formats+    text = T.pack string+    lazyText = TL.pack string++    -- Amount+    k = 100000
+ tests/benchmarks/src/Data/Text/Benchmarks/Equality.hs view
@@ -0,0 +1,30 @@+-- | Compare a string with a copy of itself that is identical except+-- for the last character.+--+module Data.Text.Benchmarks.Equality+    (+      benchmark+    ) where++import Criterion (Benchmark, bgroup, bench, whnf)+import qualified Data.ByteString.Char8 as B+import qualified Data.ByteString.Lazy.Char8 as BL+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Encoding as TL++benchmark :: FilePath -> IO Benchmark+benchmark fp = do+  b <- B.readFile fp+  bl <- BL.readFile fp+  l <- readFile fp+  let t  = T.decodeUtf8 b+      tl = TL.decodeUtf8 bl+  return $ bgroup "Equality"+    [ bench "Text" $ whnf (== T.init t `T.snoc` '\xfffd') t+    , bench "LazyText" $ whnf (== TL.init tl `TL.snoc` '\xfffd') tl+    , bench "ByteString" $ whnf (== B.init b `B.snoc` '\xfffd') b+    , bench "LazyByteString" $ whnf (== BL.init bl `BL.snoc` '\xfffd') bl+    , bench "String" $ whnf (== init l ++ "\xfffd") l+    ]
+ tests/benchmarks/src/Data/Text/Benchmarks/FileIndices.hs view
@@ -0,0 +1,28 @@+-- | Search for a pattern in a file, find the number of occurences+--+module Data.Text.Benchmarks.FileIndices+    ( benchmark+    ) where++import Control.Exception (evaluate)+import Criterion (Benchmark, bench, bgroup)+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as BL+import qualified Data.ByteString.Lazy.Search as BL+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Encoding as TL+import qualified Data.Text.Lazy.IO as TL++benchmark :: FilePath -> TL.Text -> IO Benchmark+benchmark fp t = return $ bgroup "FileIndices"+    [ bench "LazyText"           $ TL.readFile fp >>= evaluate . text t+    , bench "LazyByteString"     $ BL.readFile fp >>= evaluate . byteString b+    ]+  where+    b = B.concat $ BL.toChunks $ TL.encodeUtf8 t++text :: TL.Text -> TL.Text -> Int+text needle = fromIntegral . TL.count needle++byteString :: B.ByteString -> BL.ByteString -> Int+byteString needle = length . BL.indices needle
+ tests/benchmarks/src/Data/Text/Benchmarks/FileRead.hs view
@@ -0,0 +1,29 @@+-- | Benchmarks simple file reading+--+module Data.Text.Benchmarks.FileRead+    ( benchmark+    ) where++import Control.Exception (evaluate)+import Criterion (Benchmark, bgroup, bench)+import qualified Data.ByteString as SB+import qualified Data.ByteString.Lazy as LB+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import qualified Data.Text.IO as T+import qualified Data.Text.Lazy as LT+import qualified Data.Text.Lazy.Encoding as LT+import qualified Data.Text.Lazy.IO as LT++benchmark :: FilePath -> IO Benchmark+benchmark p = return $ bgroup "FileRead"+    [ bench "String" $ readFile p >>= evaluate . length+    , bench "ByteString" $ SB.readFile p >>= evaluate . SB.length+    , bench "LazyByteString" $ LB.readFile p >>= evaluate . LB.length+    , bench "Text" $ T.readFile p >>= evaluate . T.length+    , bench "LazyText" $ LT.readFile p >>= evaluate . LT.length+    , bench "TextByteString" $+        SB.readFile p >>= evaluate . T.length . T.decodeUtf8+    , bench "LazyTextByteString" $+        LB.readFile p >>= evaluate . LT.length . LT.decodeUtf8+    ]
+ tests/benchmarks/src/Data/Text/Benchmarks/FoldLines.hs view
@@ -0,0 +1,53 @@+-- | Fold over the lines in a file+--+{-# LANGUAGE BangPatterns #-}+module Data.Text.Benchmarks.FoldLines+    ( benchmark+    ) where++import Criterion (Benchmark, bgroup, bench)+import System.IO+import qualified Data.ByteString as B+import qualified Data.Text as T+import qualified Data.Text.IO as T++benchmark :: FilePath -> IO Benchmark+benchmark fp = return $ bgroup "FoldLines"+    [ bench "Text" $ withHandle $ foldLinesT (\n _ -> n + 1) (0 :: Int)+    , bench "ByteString" $ withHandle $ foldLinesB (\n _ -> n + 1) (0 :: Int)+    ]+  where+    withHandle f = do+        h <- openFile fp ReadMode+        hSetBuffering h (BlockBuffering (Just 16384))+        x <- f h+        hClose h+        return x++-- Text line fold+--+foldLinesT :: (a -> T.Text -> a) -> a -> Handle -> IO a+foldLinesT f z0 h = go z0+  where+    go !z = do+        eof <- hIsEOF h+        if eof+            then return z+            else do+                l <- T.hGetLine h+                let z' = f z l in go z'+{-# INLINE foldLinesT #-}++-- | ByteString line fold+--+foldLinesB :: (a -> B.ByteString -> a) -> a -> Handle -> IO a+foldLinesB f z0 h = go z0+  where+    go !z = do+        eof <- hIsEOF h+        if eof+            then return z+            else do+                l <- B.hGetLine h+                let z' = f z l in go z'+{-# INLINE foldLinesB #-}
+ tests/benchmarks/src/Data/Text/Benchmarks/HtmlCombinator.hs view
@@ -0,0 +1,36 @@+-- | Create a large HTML table and dump it to a handle+--+{-# LANGUAGE OverloadedStrings #-}+module Data.Text.Benchmarks.HtmlCombinator+    ( benchmark+    ) where++import Criterion (Benchmark, bench)+import Data.Monoid (mappend, mconcat)+import Data.Text.Lazy.Builder (Builder, fromText, toLazyText)+import Data.Text.Lazy.IO (hPutStr)+import System.IO (Handle)+import qualified Data.Text as T++benchmark :: Handle -> IO Benchmark+benchmark sink = return $ bench "HtmlCombinator" $ do+    hPutStr sink "Content-Type: text/html\n\n<table>"+    hPutStr sink . toLazyText . makeTable =<< rows+    hPutStr sink "</table>"+  where+    -- We provide the number of rows in IO so the builder value isn't shared+    -- between the benchmark samples.+    rows :: IO Int+    rows = return 20000+    {-# NOINLINE rows #-}++makeTable :: Int -> Builder+makeTable n = mconcat $ replicate n $ mconcat $ map makeCol [1 .. 50]++makeCol :: Int -> Builder+makeCol 1 = fromText "<tr><td>1</td>"+makeCol 50 = fromText "<td>50</td></tr>"+makeCol i = fromText "<td>" `mappend` (fromInt i `mappend` fromText "</td>")++fromInt :: Int -> Builder+fromInt = fromText . T.pack . show
+ tests/benchmarks/src/Data/Text/Benchmarks/Ordering.hs view
@@ -0,0 +1,58 @@+-- | For every 1000th line of a file, check how many lines in the file are+-- lexicographically smaller+--+module Data.Text.Benchmarks.Ordering+    ( benchmark+    ) where++import Control.Exception (evaluate)+import Criterion (Benchmark, bgroup, bench)+import qualified Data.ByteString.Char8 as B+import qualified Data.ByteString.Lazy.Char8 as BL+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Encoding as TL++benchmark :: FilePath -> IO Benchmark+benchmark fp = return $ bgroup "Ordering"+    [ bench "ByteString" $ B.readFile fp >>=+        evaluate . numSmaller . B.lines+    , bench "LazyByteString" $ BL.readFile fp >>=+        evaluate . numSmaller . BL.lines++    , bench "Text" $ B.readFile fp >>=+        evaluate . numSmaller . T.lines . T.decodeUtf8+    , bench "TextFusion" $ B.readFile fp >>=+        evaluate . numSmallerFusion . T.lines . T.decodeUtf8+    , bench "LazyText" $ BL.readFile fp >>=+        evaluate . numSmaller . TL.lines . TL.decodeUtf8++    , bench "String" $ readFile fp >>=+        evaluate . numSmaller . lines+    ]++-- | Take every Nth item from a list+--+every :: Int -> [a] -> [a]+every k = go k+  where+    go n (x : xs)+        | n < k     = go (n+1) xs+        | otherwise = x : go 1 xs+    go _ _          = []++-- | Benchmark logic+--+numSmaller :: (Ord a) => [a] -> Int+numSmaller ls = sum . map f $ every 1000 ls+  where+    f x = length . filter ((== GT) . compare x) $ ls++-- | Test a comparison that could be fused: compare (toLower a) (toLower b)+-- Currently, this funcion performs very badly!+--+numSmallerFusion :: [T.Text] -> Int+numSmallerFusion ls = sum . map f $ every 1000 ls+  where+    f x = length . filter ((== GT) . compare (T.toLower x) . T.toLower) $ ls
+ tests/benchmarks/src/Data/Text/Benchmarks/Pure.hs view
@@ -0,0 +1,470 @@+-- | Benchmarks various pure functions from the Text library+--+{-# LANGUAGE BangPatterns, GADTs, MagicHash #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+module Data.Text.Benchmarks.Pure+    ( benchmark+    ) where++import Control.DeepSeq (NFData (..))+import Control.Exception (evaluate)+import Criterion (Benchmark, bgroup, bench, nf)+import Data.Char (toLower, toUpper)+import Data.Monoid (mappend, mempty)+import GHC.Base (Char (..), Int (..), chr#, ord#, (+#))+import qualified Data.ByteString.Char8 as BS+import qualified Data.ByteString.Lazy.Char8 as BL+import qualified Data.ByteString.Lazy.Internal as BL+import qualified Data.ByteString.UTF8 as UTF8+import qualified Data.List as L+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Builder as TB+import qualified Data.Text.Lazy.Encoding as TL++benchmark :: FilePath -> IO Benchmark+benchmark fp = do+    -- Evaluate stuff before actually running the benchmark, we don't want to+    -- count it here.++    -- ByteString A+    bsa     <- BS.readFile fp++    -- Text A/B, LazyText A/B+    ta      <- evaluate $ T.decodeUtf8 bsa+    tb      <- evaluate $ T.toUpper ta+    tla     <- evaluate $ TL.fromChunks (T.chunksOf 16376 ta)+    tlb     <- evaluate $ TL.fromChunks (T.chunksOf 16376 tb)++    -- ByteString B, LazyByteString A/B+    bsb     <- evaluate $ T.encodeUtf8 tb+    bla     <- evaluate $ BL.fromChunks (chunksOf 16376 bsa)+    blb     <- evaluate $ BL.fromChunks (chunksOf 16376 bsb)++    -- String A/B+    sa      <- evaluate $ UTF8.toString bsa+    sb      <- evaluate $ T.unpack tb++    -- Lengths+    bsa_len <- evaluate $ BS.length bsa+    ta_len  <- evaluate $ T.length ta+    bla_len <- evaluate $ BL.length bla+    tla_len <- evaluate $ TL.length tla+    sa_len  <- evaluate $ L.length sa++    -- Lines+    bsl     <- evaluate $ BS.lines bsa+    bll     <- evaluate $ BL.lines bla+    tl      <- evaluate $ T.lines ta+    tll     <- evaluate $ TL.lines tla+    sl      <- evaluate $ L.lines sa++    return $ bgroup "Pure"+        [ bgroup "append"+            [ benchT   $ nf (T.append tb) ta+            , benchTL  $ nf (TL.append tlb) tla+            , benchBS  $ nf (BS.append bsb) bsa+            , benchBSL $ nf (BL.append blb) bla+            , benchS   $ nf ((++) sb) sa+            ]+        , bgroup "concat"+            [ benchT   $ nf T.concat tl+            , benchTL  $ nf TL.concat tll+            , benchBS  $ nf BS.concat bsl+            , benchBSL $ nf BL.concat bll+            , benchS   $ nf L.concat sl+            ]+        , bgroup "cons"+            [ benchT   $ nf (T.cons c) ta+            , benchTL  $ nf (TL.cons c) tla+            , benchBS  $ nf (BS.cons c) bsa+            , benchBSL $ nf (BL.cons c) bla+            , benchS   $ nf (c:) sa+            ]+        , bgroup "concatMap"+            [ benchT   $ nf (T.concatMap (T.replicate 3 . T.singleton)) ta+            , benchTL  $ nf (TL.concatMap (TL.replicate 3 . TL.singleton)) tla+            , benchBS  $ nf (BS.concatMap (BS.replicate 3)) bsa+            , benchBSL $ nf (BL.concatMap (BL.replicate 3)) bla+            , benchS   $ nf (L.concatMap (L.replicate 3 . (:[]))) sa+            ]+        , bgroup "decode"+            [ benchT   $ nf T.decodeUtf8 bsa+            , benchTL  $ nf TL.decodeUtf8 bla+            , benchBS  $ nf BS.unpack bsa+            , benchBSL $ nf BL.unpack bla+            , benchS   $ nf UTF8.toString bsa+            ]+        , bgroup "drop"+            [ benchT   $ nf (T.drop (ta_len `div` 3)) ta+            , benchTL  $ nf (TL.drop (tla_len `div` 3)) tla+            , benchBS  $ nf (BS.drop (bsa_len `div` 3)) bsa+            , benchBSL $ nf (BL.drop (bla_len `div` 3)) bla+            , benchS   $ nf (L.drop (sa_len `div` 3)) sa+            ]+        , bgroup "encode"+            [ benchT   $ nf T.encodeUtf8 ta+            , benchTL  $ nf TL.encodeUtf8 tla+            , benchBS  $ nf BS.pack sa+            , benchBSL $ nf BL.pack sa+            , benchS   $ nf UTF8.fromString sa+            ]+        , bgroup "filter"+            [ benchT   $ nf (T.filter p0) ta+            , benchTL  $ nf (TL.filter p0) tla+            , benchBS  $ nf (BS.filter p0) bsa+            , benchBSL $ nf (BL.filter p0) bla+            , benchS   $ nf (L.filter p0) sa+            ]+        , bgroup "filter.filter"+            [ benchT   $ nf (T.filter p1 . T.filter p0) ta+            , benchTL  $ nf (TL.filter p1 . TL.filter p0) tla+            , benchBS  $ nf (BS.filter p1 . BS.filter p0) bsa+            , benchBSL $ nf (BL.filter p1 . BL.filter p0) bla+            , benchS   $ nf (L.filter p1 . L.filter p0) sa+            ]+        , bgroup "foldl'"+            [ benchT   $ nf (T.foldl' len 0) ta+            , benchTL  $ nf (TL.foldl' len 0) tla+            , benchBS  $ nf (BS.foldl' len 0) bsa+            , benchBSL $ nf (BL.foldl' len 0) bla+            , benchS   $ nf (L.foldl' len 0) sa+            ]+        , bgroup "foldr"+            [ benchT   $ nf (L.length . T.foldr (:) []) ta+            , benchTL  $ nf (L.length . TL.foldr (:) []) tla+            , benchBS  $ nf (L.length . BS.foldr (:) []) bsa+            , benchBSL $ nf (L.length . BL.foldr (:) []) bla+            , benchS   $ nf (L.length . L.foldr (:) []) sa+            ]+        , bgroup "head"+            [ benchT   $ nf T.head ta+            , benchTL  $ nf TL.head tla+            , benchBS  $ nf BS.head bsa+            , benchBSL $ nf BL.head bla+            , benchS   $ nf L.head sa+            ]+        , bgroup "init"+            [ benchT   $ nf T.init ta+            , benchTL  $ nf TL.init tla+            , benchBS  $ nf BS.init bsa+            , benchBSL $ nf BL.init bla+            , benchS   $ nf L.init sa+            ]+        , bgroup "intercalate"+            [ benchT   $ nf (T.intercalate tsw) tl+            , benchTL  $ nf (TL.intercalate tlw) tll+            , benchBS  $ nf (BS.intercalate bsw) bsl+            , benchBSL $ nf (BL.intercalate blw) bll+            , benchS   $ nf (L.intercalate lw) sl+            ]+        , bgroup "intersperse"+            [ benchT   $ nf (T.intersperse c) ta+            , benchTL  $ nf (TL.intersperse c) tla+            , benchBS  $ nf (BS.intersperse c) bsa+            , benchBSL $ nf (BL.intersperse c) bla+            , benchS   $ nf (L.intersperse c) sa+            ]+        , bgroup "isInfixOf"+            [ benchT   $ nf (T.isInfixOf tsw) ta+            , benchTL  $ nf (TL.isInfixOf tlw) tla+            , benchBS  $ nf (BS.isInfixOf bsw) bsa+              -- no isInfixOf for lazy bytestrings+            , benchS   $ nf (L.isInfixOf lw) sa+            ]+        , bgroup "last"+            [ benchT   $ nf T.last ta+            , benchTL  $ nf TL.last tla+            , benchBS  $ nf BS.last bsa+            , benchBSL $ nf BL.last bla+            , benchS   $ nf L.last sa+            ]+        , bgroup "map"+            [ benchT   $ nf (T.map f) ta+            , benchTL  $ nf (TL.map f) tla+            , benchBS  $ nf (BS.map f) bsa+            , benchBSL $ nf (BL.map f) bla+            , benchS   $ nf (L.map f) sa+            ]+        , bgroup "mapAccumL"+            [ benchT   $ nf (T.mapAccumL g 0) ta+            , benchTL  $ nf (TL.mapAccumL g 0) tla+            , benchBS  $ nf (BS.mapAccumL g 0) bsa+            , benchBSL $ nf (BL.mapAccumL g 0) bla+            , benchS   $ nf (L.mapAccumL g 0) sa+            ]+        , bgroup "mapAccumR"+            [ benchT   $ nf (T.mapAccumR g 0) ta+            , benchTL  $ nf (TL.mapAccumR g 0) tla+            , benchBS  $ nf (BS.mapAccumR g 0) bsa+            , benchBSL $ nf (BL.mapAccumR g 0) bla+            , benchS   $ nf (L.mapAccumR g 0) sa+            ]+        , bgroup "map.map"+            [ benchT   $ nf (T.map f . T.map f) ta+            , benchTL  $ nf (TL.map f . TL.map f) tla+            , benchBS  $ nf (BS.map f . BS.map f) bsa+            , benchBSL $ nf (BL.map f . BL.map f) bla+            , benchS   $ nf (L.map f . L.map f) sa+            ]+        , bgroup "replicate char"+            [ benchT   $ nf (T.replicate bsa_len) (T.singleton c)+            , benchTL  $ nf (TL.replicate (fromIntegral bsa_len)) (TL.singleton c)+            , benchBS  $ nf (BS.replicate bsa_len) c+            , benchBSL $ nf (BL.replicate (fromIntegral bsa_len)) c+            , benchS   $ nf (L.replicate bsa_len) c+            ]+        , bgroup "replicate string"+            [ benchT   $ nf (T.replicate (bsa_len `div` T.length tsw)) tsw+            , benchTL  $ nf (TL.replicate (fromIntegral bsa_len `div` TL.length tlw)) tlw+            , benchS   $ nf (replicat (bsa_len `div` T.length tsw)) lw+            ]+        , bgroup "reverse"+            [ benchT   $ nf T.reverse ta+            , benchTL  $ nf TL.reverse tla+            , benchBS  $ nf BS.reverse bsa+            , benchBSL $ nf BL.reverse bla+            , benchS   $ nf L.reverse sa+            ]+        , bgroup "take"+            [ benchT   $ nf (T.take (ta_len `div` 3)) ta+            , benchTL  $ nf (TL.take (tla_len `div` 3)) tla+            , benchBS  $ nf (BS.take (bsa_len `div` 3)) bsa+            , benchBSL $ nf (BL.take (bla_len `div` 3)) bla+            , benchS   $ nf (L.take (sa_len `div` 3)) sa+            ]+        , bgroup "tail"+            [ benchT   $ nf T.tail ta+            , benchTL  $ nf TL.tail tla+            , benchBS  $ nf BS.tail bsa+            , benchBSL $ nf BL.tail bla+            , benchS   $ nf L.tail sa+            ]+        , bgroup "toLower"+            [ benchT   $ nf T.toLower ta+            , benchTL  $ nf TL.toLower tla+            , benchBS  $ nf (BS.map toLower) bsa+            , benchBSL $ nf (BL.map toLower) bla+            , benchS   $ nf (L.map toLower) sa+            ]+        , bgroup "toUpper"+            [ benchT   $ nf T.toUpper ta+            , benchTL  $ nf TL.toUpper tla+            , benchBS  $ nf (BS.map toUpper) bsa+            , benchBSL $ nf (BL.map toUpper) bla+            , benchS   $ nf (L.map toUpper) sa+            ]+        , bgroup "words"+            [ benchT   $ nf T.words ta+            , benchTL  $ nf TL.words tla+            , benchBS  $ nf BS.words bsa+            , benchBSL $ nf BL.words bla+            , benchS   $ nf L.words sa+            ]+        , bgroup "zipWith"+            [ benchT   $ nf (T.zipWith min tb) ta+            , benchTL  $ nf (TL.zipWith min tlb) tla+            , benchBS  $ nf (BS.zipWith min bsb) bsa+            , benchBSL $ nf (BL.zipWith min blb) bla+            , benchS   $ nf (L.zipWith min sb) sa+            ]+        , bgroup "length"+            [ bgroup "cons"+                [ benchT   $ nf (T.length . T.cons c) ta+                , benchTL  $ nf (TL.length . TL.cons c) tla+                , benchBS  $ nf (BS.length . BS.cons c) bsa+                , benchBSL $ nf (BL.length . BL.cons c) bla+                , benchS   $ nf (L.length . (:) c) sa+                ]+            , bgroup "decode"+                [ benchT   $ nf (T.length . T.decodeUtf8) bsa+                , benchTL  $ nf (TL.length . TL.decodeUtf8) bla+                , benchBS  $ nf (L.length . BS.unpack) bsa+                , benchBSL $ nf (L.length . BL.unpack) bla+                , bench "StringUTF8" $ nf (L.length . UTF8.toString) bsa+                ]+            , bgroup "drop"+                [ benchT   $ nf (T.length . T.drop (ta_len `div` 3)) ta+                , benchTL  $ nf (TL.length . TL.drop (tla_len `div` 3)) tla+                , benchBS  $ nf (BS.length . BS.drop (bsa_len `div` 3)) bsa+                , benchBSL $ nf (BL.length . BL.drop (bla_len `div` 3)) bla+                , benchS   $ nf (L.length . L.drop (sa_len `div` 3)) sa+                ]+            , bgroup "filter"+                [ benchT   $ nf (T.length . T.filter p0) ta+                , benchTL  $ nf (TL.length . TL.filter p0) tla+                , benchBS  $ nf (BS.length . BS.filter p0) bsa+                , benchBSL $ nf (BL.length . BL.filter p0) bla+                , benchS   $ nf (L.length . L.filter p0) sa+                ]+            , bgroup "filter.filter"+                [ benchT   $ nf (T.length . T.filter p1 . T.filter p0) ta+                , benchTL  $ nf (TL.length . TL.filter p1 . TL.filter p0) tla+                , benchBS  $ nf (BS.length . BS.filter p1 . BS.filter p0) bsa+                , benchBSL $ nf (BL.length . BL.filter p1 . BL.filter p0) bla+                , benchS   $ nf (L.length . L.filter p1 . L.filter p0) sa+                ]+            , bgroup "init"+                [ benchT   $ nf (T.length . T.init) ta+                , benchTL  $ nf (TL.length . TL.init) tla+                , benchBS  $ nf (BS.length . BS.init) bsa+                , benchBSL $ nf (BL.length . BL.init) bla+                , benchS   $ nf (L.length . L.init) sa+                ]+            , bgroup "intercalate"+                [ benchT   $ nf (T.length . T.intercalate tsw) tl+                , benchTL  $ nf (TL.length . TL.intercalate tlw) tll+                , benchBS  $ nf (BS.length . BS.intercalate bsw) bsl+                , benchBSL $ nf (BL.length . BL.intercalate blw) bll+                , benchS   $ nf (L.length . L.intercalate lw) sl+                ]+            , bgroup "intersperse"+                [ benchT   $ nf (T.length . T.intersperse c) ta+                , benchTL  $ nf (TL.length . TL.intersperse c) tla+                , benchBS  $ nf (BS.length . BS.intersperse c) bsa+                , benchBSL $ nf (BL.length . BL.intersperse c) bla+                , benchS   $ nf (L.length . L.intersperse c) sa+                ]+            , bgroup "map"+                [ benchT   $ nf (T.length . T.map f) ta+                , benchTL  $ nf (TL.length . TL.map f) tla+                , benchBS  $ nf (BS.length . BS.map f) bsa+                , benchBSL $ nf (BL.length . BL.map f) bla+                , benchS   $ nf (L.length . L.map f) sa+                ]+            , bgroup "map.map"+                [ benchT   $ nf (T.length . T.map f . T.map f) ta+                , benchTL  $ nf (TL.length . TL.map f . TL.map f) tla+                , benchBS  $ nf (BS.length . BS.map f . BS.map f) bsa+                , benchS   $ nf (L.length . L.map f . L.map f) sa+                ]+            , bgroup "replicate char"+                [ benchT   $ nf (T.length . T.replicate bsa_len) (T.singleton c)+                , benchTL  $ nf (TL.length . TL.replicate (fromIntegral bsa_len)) (TL.singleton c)+                , benchBS  $ nf (BS.length . BS.replicate bsa_len) c+                , benchBSL $ nf (BL.length . BL.replicate (fromIntegral bsa_len)) c+                , benchS   $ nf (L.length . L.replicate bsa_len) c+                ]+            , bgroup "replicate string"+                [ benchT   $ nf (T.length . T.replicate (bsa_len `div` T.length tsw)) tsw+                , benchTL  $ nf (TL.length . TL.replicate (fromIntegral bsa_len `div` TL.length tlw)) tlw+                , benchS   $ nf (L.length . replicat (bsa_len `div` T.length tsw)) lw+                ]+            , bgroup "take"+                [ benchT   $ nf (T.length . T.take (ta_len `div` 3)) ta+                , benchTL  $ nf (TL.length . TL.take (tla_len `div` 3)) tla+                , benchBS  $ nf (BS.length . BS.take (bsa_len `div` 3)) bsa+                , benchBSL $ nf (BL.length . BL.take (bla_len `div` 3)) bla+                , benchS   $ nf (L.length . L.take (sa_len `div` 3)) sa+                ]+            , bgroup "tail"+                [ benchT   $ nf (T.length . T.tail) ta+                , benchTL  $ nf (TL.length . TL.tail) tla+                , benchBS  $ nf (BS.length . BS.tail) bsa+                , benchBSL $ nf (BL.length . BL.tail) bla+                , benchS   $ nf (L.length . L.tail) sa+                ]+            , bgroup "toLower"+                [ benchT   $ nf (T.length . T.toLower) ta+                , benchTL  $ nf (TL.length . TL.toLower) tla+                , benchBS  $ nf (BS.length . BS.map toLower) bsa+                , benchBSL $ nf (BL.length . BL.map toLower) bla+                , benchS   $ nf (L.length . L.map toLower) sa+                ]+            , bgroup "toUpper"+                [ benchT   $ nf (T.length . T.toUpper) ta+                , benchTL  $ nf (TL.length . TL.toUpper) tla+                , benchBS  $ nf (BS.length . BS.map toUpper) bsa+                , benchBSL $ nf (BL.length . BL.map toUpper) bla+                , benchS   $ nf (L.length . L.map toUpper) sa+                ]+            , bgroup "words"+                [ benchT   $ nf (L.length . T.words) ta+                , benchTL  $ nf (L.length . TL.words) tla+                , benchBS  $ nf (L.length . BS.words) bsa+                , benchBSL $ nf (L.length . BL.words) bla+                , benchS   $ nf (L.length . L.words) sa+                ]+            , bgroup "zipWith"+                [ benchT   $ nf (T.length . T.zipWith min tb) ta+                , benchTL  $ nf (TL.length . TL.zipWith min tlb) tla+                , benchBS  $ nf (L.length . BS.zipWith min bsb) bsa+                , benchBSL $ nf (L.length . BL.zipWith min blb) bla+                , benchS   $ nf (L.length . L.zipWith min sb) sa+                ]+              ]+        , bgroup "Builder"+            [ bench "mappend char" $ nf (TL.length . TB.toLazyText . mappendNChar 'a') 10000+            , bench "mappend 8 char" $ nf (TL.length . TB.toLazyText . mappend8Char) 'a'+            , bench "mappend text" $ nf (TL.length . TB.toLazyText . mappendNText short) 10000+            ]+        ]+  where+    benchS   = bench "String"+    benchT   = bench "Text"+    benchTL  = bench "LazyText"+    benchBS  = bench "ByteString"+    benchBSL = bench "LazyByteString"++    c  = 'й'+    p0 = (== c)+    p1 = (/= 'д')+    lw  = "право"+    bsw  = UTF8.fromString lw+    blw  = BL.fromChunks [bsw]+    tsw  = T.pack lw+    tlw  = TL.fromChunks [tsw]+    f (C# c#) = C# (chr# (ord# c# +# 1#))+    g (I# i#) (C# c#) = (I# (i# +# 1#), C# (chr# (ord# c# +# i#)))+    len l _ = l + (1::Int)+    replicat n = concat . L.replicate n+    short = T.pack "short"++instance NFData BS.ByteString++instance NFData BL.ByteString where+    rnf BL.Empty        = ()+    rnf (BL.Chunk _ ts) = rnf ts++data B where+    B :: NFData a => a -> B++instance NFData B where+    rnf (B b) = rnf b++-- | Split a bytestring in chunks+--+chunksOf :: Int -> BS.ByteString -> [BS.ByteString]+chunksOf k = go+  where+    go t = case BS.splitAt k t of+             (a,b) | BS.null a -> []+                   | otherwise -> a : go b++-- | Append a character n times+--+mappendNChar :: Char -> Int -> TB.Builder+mappendNChar c n = go 0+  where+    go i+      | i < n     = TB.singleton c `mappend` go (i+1)+      | otherwise = mempty++-- | Gives more opportunity for inlining and elimination of unnecesary+-- bounds checks.+--+mappend8Char :: Char -> TB.Builder+mappend8Char c = TB.singleton c `mappend` TB.singleton c `mappend`+                 TB.singleton c `mappend` TB.singleton c `mappend`+                 TB.singleton c `mappend` TB.singleton c `mappend`+                 TB.singleton c `mappend` TB.singleton c++-- | Append a text N times+--+mappendNText :: T.Text -> Int -> TB.Builder+mappendNText t n = go 0+  where+    go i+      | i < n     = TB.fromText t `mappend` go (i+1)+      | otherwise = mempty
+ tests/benchmarks/src/Data/Text/Benchmarks/ReadNumbers.hs view
@@ -0,0 +1,83 @@+-- | Read numbers from a file with a just a number on each line, find the+-- minimum of those numbers.+--+module Data.Text.Benchmarks.ReadNumbers+    ( benchmark+    ) where++import Control.Exception (evaluate)+import Criterion (Benchmark, bgroup, bench)+import Data.List (foldl')+import Numeric (readDec, readFloat, readHex)+import qualified Data.ByteString.Char8 as B+import qualified Data.ByteString.Lazy.Char8 as BL+import qualified Data.ByteString.Lex.Double as B+import qualified Data.ByteString.Lex.Lazy.Double as BL+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Encoding as TL+import qualified Data.Text.Lazy.Read as TL+import qualified Data.Text.Read as T++benchmark :: FilePath -> IO Benchmark+benchmark fp = return $ bgroup "ReadNumbers"+    [ bench "DecimalString" $ readFile fp >>= evaluate .+        int . string readDec . lines+    , bench "HexadecimalString" $ readFile fp >>= evaluate .+        int . string readHex . lines+    , bench "DoubleString" $ readFile fp >>= evaluate .+        double . string readFloat . lines++    , bench "DecimalText" $ B.readFile fp >>= evaluate .+        int . text (T.signed T.decimal) . T.lines . T.decodeUtf8+    , bench "HexadecimalText" $ B.readFile fp >>= evaluate .+        int . text (T.signed T.hexadecimal) . T.lines . T.decodeUtf8+    , bench "DoubleText" $ B.readFile fp >>= evaluate .+        double . text T.double . T.lines . T.decodeUtf8+    , bench "RationalText" $ B.readFile fp >>= evaluate .+        double . text T.rational . T.lines . T.decodeUtf8++    , bench "DecimalLazyText" $ BL.readFile fp >>= evaluate .+        int . text (TL.signed TL.decimal) . TL.lines . TL.decodeUtf8+    , bench "HexadecimalLazyText" $ BL.readFile fp >>= evaluate .+        int . text (TL.signed TL.hexadecimal) . TL.lines . TL.decodeUtf8+    , bench "DoubleLazyText" $ BL.readFile fp >>= evaluate .+        double . text TL.double . TL.lines . TL.decodeUtf8+    , bench "RationalLazyText" $ BL.readFile fp >>= evaluate .+        double . text TL.rational . TL.lines . TL.decodeUtf8++    , bench "DecimalByteString" $ B.readFile fp >>= evaluate .+        int . byteString B.readInt . B.lines+    , bench "DoubleByteString" $ B.readFile fp >>= evaluate .+        double . byteString B.readDouble . B.lines++    , bench "DecimalLazyByteString" $ BL.readFile fp >>= evaluate .+        int . byteString BL.readInt . BL.lines+    , bench "DoubleLazyByteString" $ BL.readFile fp >>= evaluate .+        double . byteString BL.readDouble . BL.lines+    ]+  where+    -- Used for fixing types+    int :: Int -> Int+    int = id+    double :: Double -> Double+    double = id++string :: (Ord a, Num a) => (t -> [(a, t)]) -> [t] -> a+string reader = foldl' go 1000000+  where+    go z t = case reader t of [(n, _)] -> min n z+                              _        -> z++text :: (Ord a, Num a) => (t -> Either String (a,t)) -> [t] -> a+text reader = foldl' go 1000000+  where+    go z t = case reader t of Left _       -> z+                              Right (n, _) -> min n z+    +byteString :: (Ord a, Num a) => (t -> Maybe (a,t)) -> [t] -> a+byteString reader = foldl' go 1000000+  where+    go z t = case reader t of Nothing     -> z+                              Just (n, _) -> min n z
+ tests/benchmarks/src/Data/Text/Benchmarks/Replace.hs view
@@ -0,0 +1,33 @@+-- | Replace a string by another string in a file+--+module Data.Text.Benchmarks.Replace+    ( benchmark+    ) where++import Criterion (Benchmark, bgroup, bench)+import System.IO (Handle)+import qualified Data.ByteString.Char8 as B+import qualified Data.ByteString.Lazy as BL+import qualified Data.ByteString.Lazy.Search as BL+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Encoding as TL+import qualified Data.Text.Lazy.IO as TL++benchmark :: FilePath -> Handle -> String -> String -> IO Benchmark+benchmark fp sink pat sub = return $ bgroup "Replace"+    -- We have benchmarks for lazy text and lazy bytestrings. We also benchmark+    -- without the acual replacement, so we can get an idea of what time is+    -- spent on IO and computations.+    [ bench "LazyText" $ TL.readFile fp >>=+        TL.hPutStr sink . TL.replace tpat tsub+    , bench "LazyTextNull" $ TL.readFile fp >>= TL.hPutStr sink++    , bench "LazyByteString" $ BL.readFile fp >>=+        BL.hPutStr sink . BL.replace bpat bsub+    , bench "LazyByteStringNull" $ BL.readFile fp >>= BL.hPutStr sink+    ]+  where+    tpat = TL.pack pat+    tsub = TL.pack sub+    bpat = B.concat $ BL.toChunks $ TL.encodeUtf8 tpat+    bsub = B.concat $ BL.toChunks $ TL.encodeUtf8 tsub
+ tests/benchmarks/src/Data/Text/Benchmarks/Sort.hs view
@@ -0,0 +1,27 @@+-- | Implements the unix @sort@ program+--+{-# LANGUAGE OverloadedStrings #-}+module Data.Text.Benchmarks.Sort+    ( benchmark+    ) where++import Criterion (Benchmark, bench)+import Data.Monoid (mconcat)+import System.IO (Handle)+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as BL+import qualified Data.List as L+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Builder as TLB+import qualified Data.Text.Lazy.Encoding as TL++benchmark :: FilePath -> Handle -> IO Benchmark+benchmark fp sink = return $ bench "Sort" $ do+    t <- T.decodeUtf8 `fmap` B.readFile fp+    BL.hPutStr sink $ TL.encodeUtf8 $ sort t++sort :: T.Text -> TL.Text+sort = TLB.toLazyText . mconcat . L.intersperse (TLB.fromText "\n") .+    map TLB.fromText . L.sort . T.lines
+ tests/benchmarks/src/Data/Text/Benchmarks/StripBrackets.hs view
@@ -0,0 +1,33 @@+-- | Program to replace everything between brackets by spaces+--+-- This program was originally contributed by Petr Prokhorenkov.+--+module Data.Text.Benchmarks.StripBrackets+    ( benchmark+    ) where+     +import Criterion (Benchmark, bench)+import System.IO (Handle)+import qualified Data.ByteString as B+import qualified Data.Text as T+import qualified Data.Text.Encoding as T++benchmark :: FilePath -> Handle -> IO Benchmark+benchmark fp sink = return $ bench "StripBrackets" $ do+    t <- T.decodeUtf8 `fmap` B.readFile fp+    B.hPutStr sink $ T.encodeUtf8 $ stripBrackets t++stripBrackets :: T.Text -> T.Text+stripBrackets = snd . T.mapAccumL f (0 :: Int)+  where+    f depth c =+        let depth' = depth + d' c+            c' | depth > 0 || depth' > 0 = ' '+               | otherwise = c+        in (depth', c')++    d' '{' = 1+    d' '[' = 1+    d' '}' = -1+    d' ']' = -1+    d' _   = 0
+ tests/benchmarks/src/Data/Text/Benchmarks/WordCount.hs view
@@ -0,0 +1,22 @@+-- | A word frequence count program+--+module Data.Text.Benchmarks.WordCount+    ( benchmark+    ) where++import Control.Exception (evaluate)+import Criterion (Benchmark, bench)+import Data.List (foldl')+import Data.Map (Map)+import qualified Data.Map as M+import qualified Data.Text as T+import qualified Data.Text.IO as T++benchmark :: FilePath -> IO Benchmark+benchmark fp = return $ bench "WordCount" $ do+    t <- T.readFile fp+    evaluate $ M.size $ wordCount t++wordCount :: T.Text -> Map T.Text Int+wordCount =+    foldl' (\m k -> M.insertWith (+) k 1 m) M.empty . map T.toLower . T.words
+ tests/benchmarks/text-benchmarks.cabal view
@@ -0,0 +1,34 @@+name:                text-benchmarks+version:             0.0.0.0+synopsis:            Benchmarks for the text package+description:         Benchmarks for the text package+homepage:            https://bitbucket.org/bos/text+license:             BSD3+license-file:        ../../LICENSE+author:              Jasper Van der Jeugt <jaspervdj@gmail.com>,+                     Bryan O'Sullivan <bos@serpentine.com>,+                     Tom Harper <rtomharper@googlemail.com>,+                     Duncan Coutts <duncan@haskell.org>+maintainer:          jaspervdj@gmail.com+category:            Text+build-type:          Simple++cabal-version:       >=1.2++executable text-benchmarks+  hs-source-dirs: src ../..+  main-is:        Data/Text/Benchmarks.hs+  ghc-options:    -Wall -O2+  cpp-options:    -DHAVE_DEEPSEQ+  build-depends:  base              >= 4   && < 5,+                  criterion         >= 0.5 && < 0.6,+                  bytestring        >= 0.9 && < 0.10,+                  deepseq           >= 1.1 && < 1.2,+                  filepath          >= 1.1 && < 1.3,+                  directory         >= 1.1 && < 1.2,+                  containers        >= 0.3 && < 0.5,+                  binary            >= 0.5 && < 0.6,+                  utf8-string       >= 0.3 && < 0.4,+                  blaze-builder     >= 0.3 && < 0.4,+                  bytestring-lexing >= 0.2 && < 0.3,+                  stringsearch      >= 0.3 && < 0.4
text.cabal view
@@ -1,7 +1,7 @@ name:           text-version:        0.11.0.8-homepage:       http://bitbucket.org/bos/text-bug-reports:    http://bitbucket.org/bos/text/issues+version:        0.11.1.0+homepage:       https://bitbucket.org/bos/text+bug-reports:    https://bitbucket.org/bos/text/issues synopsis:       An efficient packed Unicode text type. description:         .@@ -45,31 +45,16 @@     README.markdown     -- scripts/CaseFolding.txt     -- scripts/SpecialCasing.txt-    scripts/ApiCompare.hs-    scripts/Arsec.hs-    scripts/CaseFolding.hs-    scripts/CaseMapping.hs-    scripts/SpecialCasing.hs-    tests/Benchmarks.hs+    scripts/*.hs+    tests/*.hs     tests/Makefile-    tests/Properties.hs-    tests/QuickCheckUtils.hs-    tests/SlowFunctions.hs-    tests/StdioCoverage.hs-    tests/TestUtils.hs-    tests/benchmarks/Cut.hs-    tests/benchmarks/DecodeUtf8.hs-    tests/benchmarks/EncodeUtf8.hs-    tests/benchmarks/Equality.hs-    tests/benchmarks/FileIndices.hs-    tests/benchmarks/FileRead.hs-    tests/benchmarks/FoldLines.hs-    tests/benchmarks/HtmlCombinator.hs-    tests/benchmarks/Makefile-    tests/benchmarks/Replace.hs-    tests/benchmarks/ReplaceTags.hs-    tests/benchmarks/fileread.py-    tests/benchmarks/fileread_c.c+    tests/README.markdown+    tests/benchmarks/Setup.hs+    tests/benchmarks/python/*.py+    tests/benchmarks/ruby/*.rb+    tests/benchmarks/src/Data/Text/*.hs+    tests/benchmarks/src/Data/Text/Benchmarks/*.hs+    tests/benchmarks/text-benchmarks.cabal     tests/cover-stdio.sh  flag developer@@ -87,6 +72,8 @@     Data.Text.Internal     Data.Text.Lazy     Data.Text.Lazy.Builder+    Data.Text.Lazy.Builder.Int+    Data.Text.Lazy.Builder.RealFloat     Data.Text.Lazy.Encoding     Data.Text.Lazy.IO     Data.Text.Lazy.Internal@@ -104,6 +91,7 @@     Data.Text.Fusion.Internal     Data.Text.Fusion.Size     Data.Text.IO.Internal+    Data.Text.Lazy.Builder.Functions     Data.Text.Lazy.Encoding.Fusion     Data.Text.Lazy.Fusion     Data.Text.Lazy.Search@@ -114,6 +102,7 @@     Data.Text.Util    build-depends:+    array,     base       < 5,     bytestring >= 0.9 && < 1.0   if impl(ghc >= 6.10)@@ -132,10 +121,18 @@     ghc-options: -Werror     cpp-options: -DASSERTS +  if impl(ghc >= 6.11)+    cpp-options: -DINTEGER_GMP+    build-depends: integer-gmp >= 0.2 && < 0.3++  if impl(ghc >= 6.9) && impl(ghc < 6.11)+    cpp-options: -DINTEGER_GMP+    build-depends: integer >= 0.1 && < 0.2+ source-repository head   type:     mercurial-  location: http://bitbucket.org/bos/text+  location: https://bitbucket.org/bos/text  source-repository head   type:     git-  location: http://github.com/bos/text+  location: https://github.com/bos/text