Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

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.
  • Loading branch information...
commit 2ceb5777ab7b0cbbd03a0c3c4edc3c79fe82063f 1 parent bd23332
@bos authored
View
22 Data/Text.hs
@@ -1,11 +1,11 @@
-{-# 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,
@@ -208,6 +208,7 @@ import Data.String (IsString(..))
import qualified Data.Text.Fusion as S
import qualified Data.Text.Fusion.Common as S
import Data.Text.Fusion (stream, reverseStream, unstream)
+import Data.Text.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,
@@ -1081,13 +1082,8 @@ splitAt n t@(Text arr off len)
-- 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
@@ -1182,7 +1178,7 @@ split _ t@(Text _off _arr 0) = [t]
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
@@ -1397,7 +1393,7 @@ lines ps | null ps = []
| otherwise = h : if null t
then []
else lines (unsafeTail t)
- where (h,t) = span (/= '\n') ps
+ where (# h,t #) = span_ (/= '\n') ps
{-# INLINE lines #-}
{-
View
9 Data/Text/Encoding.hs
@@ -2,9 +2,9 @@
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,
@@ -175,7 +175,8 @@ encodeUtf8 (Text arr off len) = unsafePerformIO $ do
-- 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)
View
37 Data/Text/Lazy/Read.hs
@@ -2,11 +2,10 @@
-- |
-- 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
--
@@ -23,8 +22,10 @@ module Data.Text.Lazy.Read
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.
@@ -43,7 +44,16 @@ type Reader a = Text -> Either String (a,Text)
-- '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)
@@ -71,8 +81,17 @@ hexadecimal txt
where (h,t) = T.splitAt 2 txt
hex :: Integral a => Reader a
-{-# SPECIALIZE hex :: Reader Int #-}
-{-# SPECIALIZE hex :: Reader Integer #-}
+{-# SPECIALIZE hexadecimal :: Reader Int #-}
@liskin
liskin added a note

Is this okay? hex vs. hexadecimal?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+{-# 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)
@@ -114,7 +133,7 @@ signed f = runP (signa (P f))
--
-- >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
@@ -138,6 +157,10 @@ double = floaty $ \real 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 == '+')
@@ -168,7 +191,7 @@ char p = P $ \t -> case T.uncons t of
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 == '+')
View
28 Data/Text/Private.hs
@@ -0,0 +1,28 @@
+{-# 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_ #-}
View
49 Data/Text/Read.hs
@@ -1,12 +1,11 @@
-{-# 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
--
@@ -23,8 +22,11 @@ module Data.Text.Read
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.
@@ -43,11 +45,20 @@ type Reader a = Text -> Either String (a,Text)
-- '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
@@ -64,7 +75,16 @@ decimal txt
-- '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
@@ -72,11 +92,20 @@ hexadecimal 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
@@ -114,7 +143,7 @@ signed f = runP (signa (P f))
--
-- >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
@@ -138,6 +167,10 @@ double = floaty $ \real 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 == '+')
@@ -168,7 +201,7 @@ char p = P $ \t -> case T.uncons t of
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 == '+')
View
1  text.cabal
@@ -100,6 +100,7 @@ library
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
Please sign in to comment.
Something went wrong with that request. Please try again.