Commits

Bryan O'Sullivan committed 204da16

Many improvements, all small.

Add a span_ function, using unboxed tuples, to Text.Private.

Use span_ in a few places where it can help a little.

Relax the constraint on rational to Fractional.

Specialize over many more integral types.

Comments (0)

Files changed (6)

-{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}
+{-# LANGUAGE BangPatterns, CPP, Rank2Types, UnboxedTuples #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 
 -- |
 -- Module      : Data.Text
--- Copyright   : (c) 2008, 2009 Tom Harper,
---               (c) 2009, 2010 Bryan O'Sullivan,
---               (c) 2009 Duncan Coutts
+-- Copyright   : (c) 2009, 2010, 2011 Bryan O'Sullivan,
+--               (c) 2009 Duncan Coutts,
+--               (c) 2008, 2009 Tom Harper
 --
 -- License     : BSD-style
 -- Maintainer  : bos@serpentine.com, rtomharper@googlemail.com,
 import qualified Data.Text.Fusion as S
 import qualified Data.Text.Fusion.Common as S
 import Data.Text.Fusion (stream, reverseStream, unstream)
+import Data.Text.Private (span_)
 import Data.Text.Internal (Text(..), empty, firstf, safe, text, textP)
 import qualified Prelude as P
 import Data.Text.Unsafe (Iter(..), iter, iter_, lengthWord16, reverseIter,
 -- of @t@ of elements that satisfy @p@, and whose second is the
 -- remainder of the list.
 span :: (Char -> Bool) -> Text -> (Text, Text)
-span p t@(Text arr off len) = (hd,tl)
-  where hd = textP arr off k
-        tl = textP arr (off+k) (len-k)
-        !k = loop 0
-        loop !i | i < len && p c = loop (i+d)
-                | otherwise      = i
-            where Iter c d       = iter t i
+span p t = case span_ p t of
+             (# hd,tl #) -> (hd,tl)
 {-# INLINE span #-}
 
 -- | /O(n)/ 'break' is like 'span', but the prefix returned is
 split p t = loop t
     where loop s | null s'   = [l]
                  | otherwise = l : loop (unsafeTail s')
-              where (l, s') = break p s
+              where (# l, s' #) = span_ (not . p) s
 {-# INLINE split #-}
 
 -- | /O(n)/ Splits a 'Text' into components of length @k@.  The last
          | otherwise = h : if null t
                            then []
                            else lines (unsafeTail t)
-    where (h,t) = span (/= '\n') ps
+    where (# h,t #) = span_ (/= '\n') ps
 {-# INLINE lines #-}
 
 {-

Data/Text/Encoding.hs

     UnliftedFFITypes #-}
 -- |
 -- Module      : Data.Text.Encoding
--- Copyright   : (c) 2008, 2009 Tom Harper,
---               (c) 2009, 2010 Bryan O'Sullivan,
---               (c) 2009 Duncan Coutts
+-- Copyright   : (c) 2009, 2010, 2011 Bryan O'Sullivan,
+--               (c) 2009 Duncan Coutts,
+--               (c) 2008, 2009 Tom Harper
 --
 -- License     : BSD-style
 -- Maintainer  : bos@serpentine.com, rtomharper@googlemail.com,
                   -- special-case this assumption.
                   let end = ptr `plusPtr` size
                       ascii !t !u
-                        | t == offLen || u == end || v >= 0x80 = go t (u `minusPtr` ptr)
+                        | t == offLen || u == end || v >= 0x80 =
+                            go t (u `minusPtr` ptr)
                         | otherwise = do
                             poke u (fromIntegral v :: Word8)
                             ascii (t+1) (u `plusPtr` 1)

Data/Text/Lazy/Read.hs

 
 -- |
 -- Module      : Data.Text.Lazy.Read
--- Copyright   : (c) 2010 Bryan O'Sullivan
+-- Copyright   : (c) 2010, 2011 Bryan O'Sullivan
 --
 -- License     : BSD-style
--- Maintainer  : bos@serpentine.com, rtomharper@googlemail.com,
---               duncan@haskell.org
+-- Maintainer  : bos@serpentine.com
 -- Stability   : experimental
 -- Portability : GHC
 --
 
 import Control.Monad (liftM)
 import Data.Char (isDigit, isHexDigit, ord)
+import Data.Int (Int8, Int16, Int32, Int64)
 import Data.Ratio ((%))
 import Data.Text.Lazy as T
+import Data.Word (Word, Word8, Word16, Word32, Word64)
 
 -- | Read some text.  If the read succeeds, return its value and the
 -- remaining text, otherwise an error message.
 -- 'Integer' for your result type.
 decimal :: Integral a => Reader a
 {-# SPECIALIZE decimal :: Reader Int #-}
+{-# SPECIALIZE decimal :: Reader Int8 #-}
+{-# SPECIALIZE decimal :: Reader Int16 #-}
+{-# SPECIALIZE decimal :: Reader Int32 #-}
+{-# SPECIALIZE decimal :: Reader Int64 #-}
 {-# SPECIALIZE decimal :: Reader Integer #-}
+{-# SPECIALIZE decimal :: Reader Word #-}
+{-# SPECIALIZE decimal :: Reader Word8 #-}
+{-# SPECIALIZE decimal :: Reader Word16 #-}
+{-# SPECIALIZE decimal :: Reader Word32 #-}
+{-# SPECIALIZE decimal :: Reader Word64 #-}
 decimal txt
     | T.null h  = Left "input does not start with a digit"
     | otherwise = Right (T.foldl' go 0 h, t)
  where (h,t) = T.splitAt 2 txt
 
 hex :: Integral a => Reader a
-{-# SPECIALIZE hex :: Reader Int #-}
-{-# SPECIALIZE hex :: Reader Integer #-}
+{-# SPECIALIZE hexadecimal :: Reader Int #-}
+{-# SPECIALIZE hexadecimal :: Reader Int8 #-}
+{-# SPECIALIZE hexadecimal :: Reader Int16 #-}
+{-# SPECIALIZE hexadecimal :: Reader Int32 #-}
+{-# SPECIALIZE hexadecimal :: Reader Int64 #-}
+{-# SPECIALIZE hexadecimal :: Reader Integer #-}
+{-# SPECIALIZE hexadecimal :: Reader Word #-}
+{-# SPECIALIZE hexadecimal :: Reader Word8 #-}
+{-# SPECIALIZE hexadecimal :: Reader Word16 #-}
+{-# SPECIALIZE hexadecimal :: Reader Word32 #-}
+{-# SPECIALIZE hexadecimal :: Reader Word64 #-}
 hex txt
     | T.null h  = Left "input does not start with a hexadecimal digit"
     | otherwise = Right (T.foldl' go 0 h, t)
 --
 -- >rational "3.foo" == Right (3.0, ".foo")
 -- >rational "3e"    == Right (3.0, "e")
-rational :: RealFloat a => Reader a
+rational :: Fractional a => Reader a
 {-# SPECIALIZE rational :: Reader Double #-}
 rational = floaty $ \real frac fracDenom -> fromRational $
                      real % 1 + frac % fracDenom
 
 signa :: Num a => Parser a -> Parser a
 {-# SPECIALIZE signa :: Parser Int -> Parser Int #-}
+{-# SPECIALIZE signa :: Parser Int8 -> Parser Int8 #-}
+{-# SPECIALIZE signa :: Parser Int16 -> Parser Int16 #-}
+{-# SPECIALIZE signa :: Parser Int32 -> Parser Int32 #-}
+{-# SPECIALIZE signa :: Parser Int64 -> Parser Int64 #-}
 {-# SPECIALIZE signa :: Parser Integer -> Parser Integer #-}
 signa p = do
   sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')
 
 data T = T !Integer !Int
 
-floaty :: RealFloat a => (Integer -> Integer -> Integer -> a) -> Reader a
+floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Reader a
 {-# INLINE floaty #-}
 floaty f = runP $ do
   sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')

Data/Text/Private.hs

+{-# LANGUAGE BangPatterns, UnboxedTuples #-}
+
+-- |
+-- Module      : Data.Text.Private
+-- Copyright   : (c) 2011 Bryan O'Sullivan
+--
+-- License     : BSD-style
+-- Maintainer  : bos@serpentine.com
+-- Stability   : experimental
+-- Portability : GHC
+
+module Data.Text.Private
+    (
+      span_
+    ) where
+
+import Data.Text.Internal (Text(..), textP)
+import Data.Text.Unsafe (Iter(..), iter)
+
+span_ :: (Char -> Bool) -> Text -> (# Text, Text #)
+span_ p t@(Text arr off len) = (# hd,tl #)
+  where hd = textP arr off k
+        tl = textP arr (off+k) (len-k)
+        !k = loop 0
+        loop !i | i < len && p c = loop (i+d)
+                | otherwise      = i
+            where Iter c d       = iter t i
+{-# INLINE span_ #-}

Data/Text/Read.hs

-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE OverloadedStrings, UnboxedTuples #-}
 
 -- |
 -- Module      : Data.Text.Read
--- Copyright   : (c) 2010 Bryan O'Sullivan
+-- Copyright   : (c) 2010, 2011 Bryan O'Sullivan
 --
 -- License     : BSD-style
--- Maintainer  : bos@serpentine.com, rtomharper@googlemail.com,
---               duncan@haskell.org
+-- Maintainer  : bos@serpentine.com
 -- Stability   : experimental
 -- Portability : GHC
 --
 
 import Control.Monad (liftM)
 import Data.Char (isDigit, isHexDigit, ord)
+import Data.Int (Int8, Int16, Int32, Int64)
 import Data.Ratio ((%))
 import Data.Text as T
+import Data.Text.Private (span_)
+import Data.Word (Word, Word8, Word16, Word32, Word64)
 
 -- | Read some text.  If the read succeeds, return its value and the
 -- remaining text, otherwise an error message.
 -- 'Integer' for your result type.
 decimal :: Integral a => Reader a
 {-# SPECIALIZE decimal :: Reader Int #-}
+{-# SPECIALIZE decimal :: Reader Int8 #-}
+{-# SPECIALIZE decimal :: Reader Int16 #-}
+{-# SPECIALIZE decimal :: Reader Int32 #-}
+{-# SPECIALIZE decimal :: Reader Int64 #-}
 {-# SPECIALIZE decimal :: Reader Integer #-}
+{-# SPECIALIZE decimal :: Reader Word #-}
+{-# SPECIALIZE decimal :: Reader Word8 #-}
+{-# SPECIALIZE decimal :: Reader Word16 #-}
+{-# SPECIALIZE decimal :: Reader Word32 #-}
+{-# SPECIALIZE decimal :: Reader Word64 #-}
 decimal txt
     | T.null h  = Left "input does not start with a digit"
     | otherwise = Right (T.foldl' go 0 h, t)
-  where (h,t)  = T.span isDigit txt
+  where (# h,t #)  = span_ isDigit txt
         go n d = (n * 10 + fromIntegral (digitToInt d))
 
 -- | Read a hexadecimal integer, consisting of an optional leading
 -- 'Integer' for your result type.
 hexadecimal :: Integral a => Reader a
 {-# SPECIALIZE hexadecimal :: Reader Int #-}
+{-# SPECIALIZE hexadecimal :: Reader Int8 #-}
+{-# SPECIALIZE hexadecimal :: Reader Int16 #-}
+{-# SPECIALIZE hexadecimal :: Reader Int32 #-}
+{-# SPECIALIZE hexadecimal :: Reader Int64 #-}
 {-# SPECIALIZE hexadecimal :: Reader Integer #-}
+{-# SPECIALIZE hexadecimal :: Reader Word #-}
+{-# SPECIALIZE hexadecimal :: Reader Word8 #-}
+{-# SPECIALIZE hexadecimal :: Reader Word16 #-}
+{-# SPECIALIZE hexadecimal :: Reader Word32 #-}
+{-# SPECIALIZE hexadecimal :: Reader Word64 #-}
 hexadecimal txt
     | h == "0x" || h == "0X" = hex t
     | otherwise              = hex txt
 
 hex :: Integral a => Reader a
 {-# SPECIALIZE hex :: Reader Int #-}
+{-# SPECIALIZE hex :: Reader Int8 #-}
+{-# SPECIALIZE hex :: Reader Int16 #-}
+{-# SPECIALIZE hex :: Reader Int32 #-}
+{-# SPECIALIZE hex :: Reader Int64 #-}
 {-# SPECIALIZE hex :: Reader Integer #-}
+{-# SPECIALIZE hex :: Reader Word #-}
+{-# SPECIALIZE hex :: Reader Word8 #-}
+{-# SPECIALIZE hex :: Reader Word16 #-}
+{-# SPECIALIZE hex :: Reader Word32 #-}
+{-# SPECIALIZE hex :: Reader Word64 #-}
 hex txt
     | T.null h  = Left "input does not start with a hexadecimal digit"
     | otherwise = Right (T.foldl' go 0 h, t)
-  where (h,t)  = T.span isHexDigit txt
+  where (# h,t #)  = span_ isHexDigit txt
         go n d = (n * 16 + fromIntegral (hexDigitToInt d))
 
 hexDigitToInt :: Char -> Int
 --
 -- >rational "3.foo" == Right (3.0, ".foo")
 -- >rational "3e"    == Right (3.0, "e")
-rational :: RealFloat a => Reader a
+rational :: Fractional a => Reader a
 {-# SPECIALIZE rational :: Reader Double #-}
 rational = floaty $ \real frac fracDenom -> fromRational $
                      real % 1 + frac % fracDenom
 
 signa :: Num a => Parser a -> Parser a
 {-# SPECIALIZE signa :: Parser Int -> Parser Int #-}
+{-# SPECIALIZE signa :: Parser Int8 -> Parser Int8 #-}
+{-# SPECIALIZE signa :: Parser Int16 -> Parser Int16 #-}
+{-# SPECIALIZE signa :: Parser Int32 -> Parser Int32 #-}
+{-# SPECIALIZE signa :: Parser Int64 -> Parser Int64 #-}
 {-# SPECIALIZE signa :: Parser Integer -> Parser Integer #-}
 signa p = do
   sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')
 
 data T = T !Integer !Int
 
-floaty :: RealFloat a => (Integer -> Integer -> Integer -> a) -> Reader a
+floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Reader a
 {-# INLINE floaty #-}
 floaty f = runP $ do
   sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')
     Data.Text.Lazy.Encoding.Fusion
     Data.Text.Lazy.Fusion
     Data.Text.Lazy.Search
+    Data.Text.Private
     Data.Text.Search
     Data.Text.Unsafe
     Data.Text.Unsafe.Base
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.