on master help sign in
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.

commit2ceb5777ab7b0cbbd03a0c3c4edc3c79fe82063f authorBryan O'Sullivan <bos@serpentine.com> dateFri 23 Dec 2011, 14:12 (15 years ago) parentbd23332
6 files changed+114−32
Data/Text.hs+9−13 Data/Text/Encoding.hs+5−4 Data/Text/Lazy/Read.hs+30−7 Data/Text/Private.hs+28 Data/Text/Read.hs+41−8 text.cabal+1
Data/Text.hs+9−13
@@ -1,11 +1,11 @@
1−{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}
1+{-# LANGUAGE BangPatterns, CPP, Rank2Types, UnboxedTuples #-}
22{-# OPTIONS_GHC -fno-warn-orphans #-}
33
44-- |
55-- Module : Data.Text
6−-- Copyright : (c) 2008, 2009 Tom Harper,
7−-- (c) 2009, 2010 Bryan O'Sullivan,
8−-- (c) 2009 Duncan Coutts
6+-- Copyright : (c) 2009, 2010, 2011 Bryan O'Sullivan,
7+-- (c) 2009 Duncan Coutts,
8+-- (c) 2008, 2009 Tom Harper
99--
1010-- License : BSD-style
1111-- Maintainer : bos@serpentine.com, rtomharper@googlemail.com,
@@ -208,6 +208,7 @@ import Data.String (IsString(..))
208208import qualified Data.Text.Fusion as S
209209import qualified Data.Text.Fusion.Common as S
210210import Data.Text.Fusion (stream, reverseStream, unstream)
211+import Data.Text.Private (span_)
211212import Data.Text.Internal (Text(..), empty, firstf, safe, text, textP)
212213import qualified Prelude as P
213214import Data.Text.Unsafe (Iter(..), iter, iter_, lengthWord16, reverseIter,
@@ -1081,13 +1082,8 @@ splitAt n t@(Text arr off len)
10811082-- of @t@ of elements that satisfy @p@, and whose second is the
10821083-- remainder of the list.
10831084span :: (Char -> Bool) -> Text -> (Text, Text)
1084−span p t@(Text arr off len) = (hd,tl)
1085− where hd = textP arr off k
1086− tl = textP arr (off+k) (len-k)
1087− !k = loop 0
1088− loop !i | i < len && p c = loop (i+d)
1089− | otherwise = i
1090− where Iter c d = iter t i
1085+span p t = case span_ p t of
1086+ (# hd,tl #) -> (hd,tl)
10911087{-# INLINE span #-}
10921088
10931089-- | /O(n)/ 'break' is like 'span', but the prefix returned is
@@ -1182,7 +1178,7 @@ split _ t@(Text _off _arr 0) = [t]
11821178split p t = loop t
11831179 where loop s | null s' = [l]
11841180 | otherwise = l : loop (unsafeTail s')
1185− where (l, s') = break p s
1181+ where (# l, s' #) = span_ (not . p) s
11861182{-# INLINE split #-}
11871183
11881184-- | /O(n)/ Splits a 'Text' into components of length @k@. The last
@@ -1397,7 +1393,7 @@ lines ps | null ps = []
13971393 | otherwise = h : if null t
13981394 then []
13991395 else lines (unsafeTail t)
1400− where (h,t) = span (/= '\n') ps
1396+ where (# h,t #) = span_ (/= '\n') ps
14011397{-# INLINE lines #-}
14021398
14031399{-
Data/Text/Encoding.hs+5−4
@@ -2,9 +2,9 @@
22 UnliftedFFITypes #-}
33-- |
44-- Module : Data.Text.Encoding
5−-- Copyright : (c) 2008, 2009 Tom Harper,
6−-- (c) 2009, 2010 Bryan O'Sullivan,
7−-- (c) 2009 Duncan Coutts
5+-- Copyright : (c) 2009, 2010, 2011 Bryan O'Sullivan,
6+-- (c) 2009 Duncan Coutts,
7+-- (c) 2008, 2009 Tom Harper
88--
99-- License : BSD-style
1010-- Maintainer : bos@serpentine.com, rtomharper@googlemail.com,
@@ -175,7 +175,8 @@ encodeUtf8 (Text arr off len) = unsafePerformIO $ do
175175 -- special-case this assumption.
176176 let end = ptr `plusPtr` size
177177 ascii !t !u
178− | t == offLen || u == end || v >= 0x80 = go t (u `minusPtr` ptr)
178+ | t == offLen || u == end || v >= 0x80 =
179+ go t (u `minusPtr` ptr)
179180 | otherwise = do
180181 poke u (fromIntegral v :: Word8)
181182 ascii (t+1) (u `plusPtr` 1)
Data/Text/Lazy/Read.hs+30−7
@@ -2,11 +2,10 @@
22
33-- |
44-- Module : Data.Text.Lazy.Read
5−-- Copyright : (c) 2010 Bryan O'Sullivan
5+-- Copyright : (c) 2010, 2011 Bryan O'Sullivan
66--
77-- License : BSD-style
8−-- Maintainer : bos@serpentine.com, rtomharper@googlemail.com,
9−-- duncan@haskell.org
8+-- Maintainer : bos@serpentine.com
109-- Stability : experimental
1110-- Portability : GHC
1211--
@@ -23,8 +22,10 @@ module Data.Text.Lazy.Read
2322
2423import Control.Monad (liftM)
2524import Data.Char (isDigit, isHexDigit, ord)
25+import Data.Int (Int8, Int16, Int32, Int64)
2626import Data.Ratio ((%))
2727import Data.Text.Lazy as T
28+import Data.Word (Word, Word8, Word16, Word32, Word64)
2829
2930-- | Read some text. If the read succeeds, return its value and the
3031-- remaining text, otherwise an error message.
@@ -43,7 +44,16 @@ type Reader a = Text -> Either String (a,Text)
4344-- 'Integer' for your result type.
4445decimal :: Integral a => Reader a
4546{-# SPECIALIZE decimal :: Reader Int #-}
47+{-# SPECIALIZE decimal :: Reader Int8 #-}
48+{-# SPECIALIZE decimal :: Reader Int16 #-}
49+{-# SPECIALIZE decimal :: Reader Int32 #-}
50+{-# SPECIALIZE decimal :: Reader Int64 #-}
4651{-# SPECIALIZE decimal :: Reader Integer #-}
52+{-# SPECIALIZE decimal :: Reader Word #-}
53+{-# SPECIALIZE decimal :: Reader Word8 #-}
54+{-# SPECIALIZE decimal :: Reader Word16 #-}
55+{-# SPECIALIZE decimal :: Reader Word32 #-}
56+{-# SPECIALIZE decimal :: Reader Word64 #-}
4757decimal txt
4858 | T.null h = Left "input does not start with a digit"
4959 | otherwise = Right (T.foldl' go 0 h, t)
@@ -71,8 +81,17 @@ hexadecimal txt
7181 where (h,t) = T.splitAt 2 txt
7282
7383hex :: Integral a => Reader a
74−{-# SPECIALIZE hex :: Reader Int #-}
75−{-# SPECIALIZE hex :: Reader Integer #-}
84+{-# SPECIALIZE hexadecimal :: Reader Int #-}
85+{-# SPECIALIZE hexadecimal :: Reader Int8 #-}
86+{-# SPECIALIZE hexadecimal :: Reader Int16 #-}
87+{-# SPECIALIZE hexadecimal :: Reader Int32 #-}
88+{-# SPECIALIZE hexadecimal :: Reader Int64 #-}
89+{-# SPECIALIZE hexadecimal :: Reader Integer #-}
90+{-# SPECIALIZE hexadecimal :: Reader Word #-}
91+{-# SPECIALIZE hexadecimal :: Reader Word8 #-}
92+{-# SPECIALIZE hexadecimal :: Reader Word16 #-}
93+{-# SPECIALIZE hexadecimal :: Reader Word32 #-}
94+{-# SPECIALIZE hexadecimal :: Reader Word64 #-}
7695hex txt
7796 | T.null h = Left "input does not start with a hexadecimal digit"
7897 | otherwise = Right (T.foldl' go 0 h, t)
@@ -114,7 +133,7 @@ signed f = runP (signa (P f))
114133--
115134-- >rational "3.foo" == Right (3.0, ".foo")
116135-- >rational "3e" == Right (3.0, "e")
117−rational :: RealFloat a => Reader a
136+rational :: Fractional a => Reader a
118137{-# SPECIALIZE rational :: Reader Double #-}
119138rational = floaty $ \real frac fracDenom -> fromRational $
120139 real % 1 + frac % fracDenom
@@ -138,6 +157,10 @@ double = floaty $ \real frac fracDenom ->
138157
139158signa :: Num a => Parser a -> Parser a
140159{-# SPECIALIZE signa :: Parser Int -> Parser Int #-}
160+{-# SPECIALIZE signa :: Parser Int8 -> Parser Int8 #-}
161+{-# SPECIALIZE signa :: Parser Int16 -> Parser Int16 #-}
162+{-# SPECIALIZE signa :: Parser Int32 -> Parser Int32 #-}
163+{-# SPECIALIZE signa :: Parser Int64 -> Parser Int64 #-}
141164{-# SPECIALIZE signa :: Parser Integer -> Parser Integer #-}
142165signa p = do
143166 sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')
@@ -168,7 +191,7 @@ char p = P $ \t -> case T.uncons t of
168191
169192data T = T !Integer !Int
170193
171−floaty :: RealFloat a => (Integer -> Integer -> Integer -> a) -> Reader a
194+floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Reader a
172195{-# INLINE floaty #-}
173196floaty f = runP $ do
174197 sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')
Data/Text/Private.hsnew file+28
@@ -0,0 +1,28 @@
1+{-# LANGUAGE BangPatterns, UnboxedTuples #-}
2+
3+-- |
4+-- Module : Data.Text.Private
5+-- Copyright : (c) 2011 Bryan O'Sullivan
6+--
7+-- License : BSD-style
8+-- Maintainer : bos@serpentine.com
9+-- Stability : experimental
10+-- Portability : GHC
11+
12+module Data.Text.Private
13+ (
14+ span_
15+ ) where
16+
17+import Data.Text.Internal (Text(..), textP)
18+import Data.Text.Unsafe (Iter(..), iter)
19+
20+span_ :: (Char -> Bool) -> Text -> (# Text, Text #)
21+span_ p t@(Text arr off len) = (# hd,tl #)
22+ where hd = textP arr off k
23+ tl = textP arr (off+k) (len-k)
24+ !k = loop 0
25+ loop !i | i < len && p c = loop (i+d)
26+ | otherwise = i
27+ where Iter c d = iter t i
28+{-# INLINE span_ #-}
Data/Text/Read.hs+41−8
@@ -1,12 +1,11 @@
1−{-# LANGUAGE OverloadedStrings #-}
1+{-# LANGUAGE OverloadedStrings, UnboxedTuples #-}
22
33-- |
44-- Module : Data.Text.Read
5−-- Copyright : (c) 2010 Bryan O'Sullivan
5+-- Copyright : (c) 2010, 2011 Bryan O'Sullivan
66--
77-- License : BSD-style
8−-- Maintainer : bos@serpentine.com, rtomharper@googlemail.com,
9−-- duncan@haskell.org
8+-- Maintainer : bos@serpentine.com
109-- Stability : experimental
1110-- Portability : GHC
1211--
@@ -23,8 +22,11 @@ module Data.Text.Read
2322
2423import Control.Monad (liftM)
2524import Data.Char (isDigit, isHexDigit, ord)
25+import Data.Int (Int8, Int16, Int32, Int64)
2626import Data.Ratio ((%))
2727import Data.Text as T
28+import Data.Text.Private (span_)
29+import Data.Word (Word, Word8, Word16, Word32, Word64)
2830
2931-- | Read some text. If the read succeeds, return its value and the
3032-- remaining text, otherwise an error message.
@@ -43,11 +45,20 @@ type Reader a = Text -> Either String (a,Text)
4345-- 'Integer' for your result type.
4446decimal :: Integral a => Reader a
4547{-# SPECIALIZE decimal :: Reader Int #-}
48+{-# SPECIALIZE decimal :: Reader Int8 #-}
49+{-# SPECIALIZE decimal :: Reader Int16 #-}
50+{-# SPECIALIZE decimal :: Reader Int32 #-}
51+{-# SPECIALIZE decimal :: Reader Int64 #-}
4652{-# SPECIALIZE decimal :: Reader Integer #-}
53+{-# SPECIALIZE decimal :: Reader Word #-}
54+{-# SPECIALIZE decimal :: Reader Word8 #-}
55+{-# SPECIALIZE decimal :: Reader Word16 #-}
56+{-# SPECIALIZE decimal :: Reader Word32 #-}
57+{-# SPECIALIZE decimal :: Reader Word64 #-}
4758decimal txt
4859 | T.null h = Left "input does not start with a digit"
4960 | otherwise = Right (T.foldl' go 0 h, t)
50− where (h,t) = T.span isDigit txt
61+ where (# h,t #) = span_ isDigit txt
5162 go n d = (n * 10 + fromIntegral (digitToInt d))
5263
5364-- | Read a hexadecimal integer, consisting of an optional leading
@@ -64,7 +75,16 @@ decimal txt
6475-- 'Integer' for your result type.
6576hexadecimal :: Integral a => Reader a
6677{-# SPECIALIZE hexadecimal :: Reader Int #-}
78+{-# SPECIALIZE hexadecimal :: Reader Int8 #-}
79+{-# SPECIALIZE hexadecimal :: Reader Int16 #-}
80+{-# SPECIALIZE hexadecimal :: Reader Int32 #-}
81+{-# SPECIALIZE hexadecimal :: Reader Int64 #-}
6782{-# SPECIALIZE hexadecimal :: Reader Integer #-}
83+{-# SPECIALIZE hexadecimal :: Reader Word #-}
84+{-# SPECIALIZE hexadecimal :: Reader Word8 #-}
85+{-# SPECIALIZE hexadecimal :: Reader Word16 #-}
86+{-# SPECIALIZE hexadecimal :: Reader Word32 #-}
87+{-# SPECIALIZE hexadecimal :: Reader Word64 #-}
6888hexadecimal txt
6989 | h == "0x" || h == "0X" = hex t
7090 | otherwise = hex txt
@@ -72,11 +92,20 @@ hexadecimal txt
7292
7393hex :: Integral a => Reader a
7494{-# SPECIALIZE hex :: Reader Int #-}
95+{-# SPECIALIZE hex :: Reader Int8 #-}
96+{-# SPECIALIZE hex :: Reader Int16 #-}
97+{-# SPECIALIZE hex :: Reader Int32 #-}
98+{-# SPECIALIZE hex :: Reader Int64 #-}
7599{-# SPECIALIZE hex :: Reader Integer #-}
100+{-# SPECIALIZE hex :: Reader Word #-}
101+{-# SPECIALIZE hex :: Reader Word8 #-}
102+{-# SPECIALIZE hex :: Reader Word16 #-}
103+{-# SPECIALIZE hex :: Reader Word32 #-}
104+{-# SPECIALIZE hex :: Reader Word64 #-}
76105hex txt
77106 | T.null h = Left "input does not start with a hexadecimal digit"
78107 | otherwise = Right (T.foldl' go 0 h, t)
79− where (h,t) = T.span isHexDigit txt
108+ where (# h,t #) = span_ isHexDigit txt
80109 go n d = (n * 16 + fromIntegral (hexDigitToInt d))
81110
82111hexDigitToInt :: Char -> Int
@@ -114,7 +143,7 @@ signed f = runP (signa (P f))
114143--
115144-- >rational "3.foo" == Right (3.0, ".foo")
116145-- >rational "3e" == Right (3.0, "e")
117−rational :: RealFloat a => Reader a
146+rational :: Fractional a => Reader a
118147{-# SPECIALIZE rational :: Reader Double #-}
119148rational = floaty $ \real frac fracDenom -> fromRational $
120149 real % 1 + frac % fracDenom
@@ -138,6 +167,10 @@ double = floaty $ \real frac fracDenom ->
138167
139168signa :: Num a => Parser a -> Parser a
140169{-# SPECIALIZE signa :: Parser Int -> Parser Int #-}
170+{-# SPECIALIZE signa :: Parser Int8 -> Parser Int8 #-}
171+{-# SPECIALIZE signa :: Parser Int16 -> Parser Int16 #-}
172+{-# SPECIALIZE signa :: Parser Int32 -> Parser Int32 #-}
173+{-# SPECIALIZE signa :: Parser Int64 -> Parser Int64 #-}
141174{-# SPECIALIZE signa :: Parser Integer -> Parser Integer #-}
142175signa p = do
143176 sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')
@@ -168,7 +201,7 @@ char p = P $ \t -> case T.uncons t of
168201
169202data T = T !Integer !Int
170203
171−floaty :: RealFloat a => (Integer -> Integer -> Integer -> a) -> Reader a
204+floaty :: Fractional a => (Integer -> Integer -> Integer -> a) -> Reader a
172205{-# INLINE floaty #-}
173206floaty f = runP $ do
174207 sign <- perhaps '+' $ char (\c -> c == '-' || c == '+')
text.cabal+1
@@ -100,6 +100,7 @@ library
100100 Data.Text.Lazy.Encoding.Fusion
101101 Data.Text.Lazy.Fusion
102102 Data.Text.Lazy.Search
103+ Data.Text.Private
103104 Data.Text.Search
104105 Data.Text.Unsafe
105106 Data.Text.Unsafe.Base