packages feed

bytestring-read 0.2.1 → 0.3.0

raw patch · 6 files changed

+112/−84 lines, 6 filesdep ~criterionPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: criterion

API changes (from Hackage documentation)

+ Data.ByteString.Read: class Source a
+ Data.ByteString.Read.Class: class Source a
+ Data.ByteString.Read.Class: empty :: Source a => a
+ Data.ByteString.Read.Class: head :: Source a => a -> Word8
+ Data.ByteString.Read.Class: instance Source ByteString
+ Data.ByteString.Read.Class: null :: Source a => a -> Bool
+ Data.ByteString.Read.Class: tail :: Source a => a -> a
- Data.ByteString.Read: double :: ByteString -> Maybe (Double, ByteString)
+ Data.ByteString.Read: double :: Source s => s -> Maybe (Double, s)
- Data.ByteString.Read: fractional :: ReadFractional r => ByteString -> Maybe (r, ByteString)
+ Data.ByteString.Read: fractional :: (ReadFractional r, Source s) => s -> Maybe (r, s)
- Data.ByteString.Read: int :: ByteString -> Maybe (Int, ByteString)
+ Data.ByteString.Read: int :: Source s => s -> Maybe (Int, s)
- Data.ByteString.Read: integral :: Num n => ByteString -> Maybe (n, ByteString)
+ Data.ByteString.Read: integral :: (Num n, Source s) => s -> Maybe (n, s)
- Data.ByteString.Read: signed :: Num r => (ByteString -> Maybe (r, ByteString)) -> ByteString -> Maybe (r, ByteString)
+ Data.ByteString.Read: signed :: (Source s, Num r) => (s -> Maybe (r, s)) -> s -> Maybe (r, s)
- Data.ByteString.Read.Fractional: double :: ByteString -> Maybe (Double, ByteString)
+ Data.ByteString.Read.Fractional: double :: Source s => s -> Maybe (Double, s)
- Data.ByteString.Read.Fractional: fractional :: ReadFractional r => ByteString -> Maybe (r, ByteString)
+ Data.ByteString.Read.Fractional: fractional :: (ReadFractional r, Source s) => s -> Maybe (r, s)
- Data.ByteString.Read.Fractional: fractional' :: (Radix b, ReadFractional r) => proxy b -> ByteString -> Maybe (r, ByteString)
+ Data.ByteString.Read.Fractional: fractional' :: (Radix b, ReadFractional r, Source s) => proxy b -> s -> Maybe (r, s)
- Data.ByteString.Read.Fractional: fractional10 :: ReadFractional r => ByteString -> Maybe (r, ByteString)
+ Data.ByteString.Read.Fractional: fractional10 :: (ReadFractional r, Source s) => s -> Maybe (r, s)
- Data.ByteString.Read.Integral: int :: ByteString -> Maybe (Int, ByteString)
+ Data.ByteString.Read.Integral: int :: Source s => s -> Maybe (Int, s)
- Data.ByteString.Read.Integral: integral :: Num n => ByteString -> Maybe (n, ByteString)
+ Data.ByteString.Read.Integral: integral :: (Num n, Source s) => s -> Maybe (n, s)
- Data.ByteString.Read.Integral: integral' :: (Radix b, Num n) => proxy b -> ByteString -> Maybe (n, ByteString)
+ Data.ByteString.Read.Integral: integral' :: (Radix b, Num n, Source s) => proxy b -> s -> Maybe (n, s)

Files

bench/main.hs view
@@ -6,6 +6,7 @@  import Data.ByteString(ByteString) import qualified Data.ByteString.Char8 as SC+import qualified Data.ByteString.Lazy as L  import qualified Data.Text.Encoding as T @@ -14,13 +15,13 @@  import qualified Data.ByteString.Read as R import qualified Data.Text.Read as T-import qualified Data.ByteString.Lex.Double as L+import qualified Data.ByteString.Lex.Double as Lex import qualified Data.Attoparsec.ByteString.Char8 as A -short :: ByteString+short :: IsString s => s short = "-2342395232123424.3424346343524e3" -long :: ByteString+long :: IsString s => s long = "-234232345678976521345895325678987654321345678987654321345689643213595232123424.34243463435223456789321367899231808534492500740957389523850293482093852039587495203586329850238562834290374029844e3"  checkConsumed :: (IsString a, Eq a) => (v, a) -> v@@ -30,11 +31,14 @@ bytestringRead :: ByteString -> Double bytestringRead = maybe (error "parse error") checkConsumed . R.signed R.fractional +lazyBytestringRead :: L.ByteString -> Double+lazyBytestringRead = maybe (error "parse error") checkConsumed . R.signed R.fractional+ text :: ByteString -> Double text = either (const $ error "parse error") checkConsumed . T.signed T.double . T.decodeUtf8  bytestringLexing :: ByteString -> Double-bytestringLexing = maybe (error "parse error") checkConsumed . L.readDouble+bytestringLexing = maybe (error "parse error") checkConsumed . Lex.readDouble  attoparsec :: ByteString -> Double attoparsec = either (const $ error "parse error") id . A.parseOnly (fmap toRealFloat A.scientific)@@ -42,7 +46,7 @@ read' :: ByteString -> Double read' = read . SC.unpack -doBench :: String -> (ByteString -> Double) -> Benchmark+doBench :: IsString s => String -> (s -> Double) -> Benchmark doBench n f = bgroup n     [ bench "short" $ nf f short     , bench "long"  $ nf f long@@ -51,6 +55,7 @@ main :: IO () main = defaultMain     [ doBench "bytestring-read" bytestringRead+    , doBench "bytestring-read(Lazy)" lazyBytestringRead     , doBench "text" text     , doBench "bytestring-lexing" bytestringLexing     , doBench "attoparsec" attoparsec
bytestring-read.cabal view
@@ -1,5 +1,5 @@ name:                bytestring-read-version:             0.2.1+version:             0.3.0 synopsis:            fast ByteString to number converting library description:         benchmark: <http://philopon.github.io/bytestring-read/bench.html> license:             MIT@@ -34,7 +34,7 @@                      , bytestring                      , text                      , bytestring-lexing >=0.4  && <0.5-                     , criterion         >=1.0  && <1.1+                     , criterion         >=1.0  && <1.2                      , scientific                      , attoparsec   ghc-options:         -Wall -O2
src/Data/ByteString/Read.hs view
@@ -1,6 +1,7 @@ module Data.ByteString.Read-    ( -- * fractional-      ReadFractional+    ( Source+      -- * fractional+    , ReadFractional     , fractional     , double @@ -17,17 +18,15 @@  import Control.Arrow -import Data.ByteString(ByteString)-import Data.ByteString.Unsafe-import qualified Data.ByteString as S--import Data.ByteString.Read.Class+import Data.ByteString.Read.Class as C import Data.ByteString.Read.Integral import Data.ByteString.Read.Fractional import Data.ByteString.Read.DEPRECATED  -- $setup -- >>> :set -XDataKinds -XOverloadedStrings+-- >>> import qualified Data.ByteString as S+-- >>> import qualified Data.ByteString.Lazy as L  -- | convert unsigned parser to signed parser. --@@ -35,17 +34,17 @@ -- -- * sign (+, -) (optional) ----- >>> signed double "12.4"+-- >>> signed double ("12.4" :: S.ByteString) -- Just (12.4,"")--- >>> signed double "-3.21e3"+-- >>> signed double ("-3.21e3" :: L.ByteString) -- Just (-3210.0,"")--- >>> signed double "+0x1f.4"+-- >>> signed double ("+0x1f.4" :: S.ByteString) -- Just (31.25,"")-signed :: Num r => (ByteString -> Maybe (r, ByteString)) -> ByteString -> Maybe (r, ByteString)+signed :: (Source s, Num r) => (s -> Maybe (r, s)) -> s -> Maybe (r, s) signed f s-    | S.null s = Nothing-    | unsafeHead s == minus = first negate `fmap` f (unsafeTail s)-    | unsafeHead s == plus  = f (unsafeTail s)+    | C.null s = Nothing+    | C.head s == minus = first negate `fmap` f (C.tail s)+    | C.head s == plus  = f (C.tail s)     | otherwise = f s   where     minus = 45
src/Data/ByteString/Read/Class.hs view
@@ -8,10 +8,14 @@ module Data.ByteString.Read.Class     ( ReadFractional(..)     , Radix(..)+    , Source(..)     ) where  import Data.Word import GHC.TypeLits.Compat+import qualified Data.ByteString as S+import Data.ByteString.Unsafe+import qualified Data.ByteString.Lazy as L  class (Fractional a, Num (Fraction a), Ord (Fraction a)) => ReadFractional a where     -- | data type to store fractional part of floating@@ -121,3 +125,27 @@ defineRadixOver10(34, 88, 120) defineRadixOver10(35, 89, 121) defineRadixOver10(36, 90, 122)++class Source a where+    null  :: a -> Bool+    empty :: a+    head  :: a -> Word8+    tail  :: a -> a++instance Source S.ByteString where+    null  = S.null+    empty = S.empty+    head  = unsafeHead+    tail  = unsafeTail+    {-# INLINE null #-}+    {-# INLINE head #-}+    {-# INLINE tail #-}++instance Source L.ByteString where+    null  = L.null+    empty = L.empty+    head  = L.head+    tail  = L.tail+    {-# INLINE null #-}+    {-# INLINE head #-}+    {-# INLINE tail #-}
src/Data/ByteString/Read/Fractional.hs view
@@ -18,32 +18,30 @@     , fractional'     ) where -import Data.ByteString.Unsafe-import Data.ByteString(ByteString)-import qualified Data.ByteString as S- import GHC.TypeLits.Compat import Data.Proxy.Compat -import Data.ByteString.Read.Class+import Data.ByteString.Read.Class as C  -- $setup -- >>> :set -XDataKinds -XOverloadedStrings+-- >>> import qualified Data.ByteString as S+-- >>> import qualified Data.ByteString.Lazy as L -integral :: forall proxy n r. (Radix n, ReadFractional r, Ord (Fraction r), Num (Fraction r))-         => proxy n -> ByteString -> (Fraction r, Int, Int, ByteString)+integral :: forall proxy n r s. (Radix n, ReadFractional r, Ord (Fraction r), Num (Fraction r), Source s)+         => proxy n -> s -> (Fraction r, Int, Int, s) integral pn = loop 0 0 0   where     pr :: Proxy r     pr = Proxy      loop !i !d !ad !s-        | S.null s                         = (i, d, ad, s)-        | not (isDigit pn (unsafeHead s))  = (i, d, ad, s)-        | maybe False (i >=) (maxValue pr) = loop i d (ad + 1) (unsafeTail s)+        | C.null s                         = (i, d, ad, s)+        | not (isDigit pn (C.head s))      = (i, d, ad, s)+        | maybe False (i >=) (maxValue pr) = loop i d (ad + 1) (C.tail s)         | otherwise                        = loop-            (i * fromIntegral (natVal pn) + (fromIntegral $ unsafeToDigit pn (unsafeHead s) :: Fraction r))-            (d+1) ad (unsafeTail s)+            (i * fromIntegral (natVal pn) + (fromIntegral $ unsafeToDigit pn (C.head s) :: Fraction r))+            (d+1) ad (C.tail s) {-# INLINABLE integral #-}  toFractional :: (Radix b, ReadFractional r, Fractional r)@@ -59,30 +57,30 @@ -- -- * fractional(0.1, 12224.3543) ----- >>> fractional' (Proxy :: Proxy 36) "12z" :: Maybe (Double, ByteString)+-- >>> fractional' (Proxy :: Proxy 36) "12z" :: Maybe (Double, S.ByteString) -- Just (1403.0,"")--- >>> fractional' (Proxy :: Proxy 2) "1012" :: Maybe (Double, ByteString)+-- >>> fractional' (Proxy :: Proxy 2) "1012" :: Maybe (Double, L.ByteString) -- Just (5.0,"2")--- >>> fractional' (Proxy :: Proxy 10) "a12" :: Maybe (Double, ByteString)+-- >>> fractional' (Proxy :: Proxy 10) "a12" :: Maybe (Double, S.ByteString) -- Nothing-fractional' :: (Radix b, ReadFractional r) => proxy b -> ByteString -> Maybe (r, ByteString)+fractional' :: (Radix b, ReadFractional r, Source s) => proxy b -> s -> Maybe (r, s) fractional' pn s = case integral pn s of     (_, 0, _,   _) -> Nothing-    (q, _, d, "") -> Just (fromFraction q * fromIntegral (natVal pn) ^ d, "")     (q, _, d, s1)-        | unsafeHead s1 /= dot -> Just (fromFraction q, s1)-        | otherwise -> case integral pn (unsafeTail s1) of+        | C.null s1        -> Just (fromFraction q * fromIntegral (natVal pn) ^ d, C.empty)+        | C.head s1 /= dot -> Just (fromFraction q, s1)+        | otherwise -> case integral pn (C.tail s1) of             (_, 0,  _, _)  -> Just (fromFraction q, s1)             (r, d', _, s2) -> Just (toFractional pn q r d d', s2)   where     dot = 46 {-# INLINABLE fractional' #-} -exponential :: ByteString -> (Int, ByteString)+exponential :: forall s. Source s => s -> (Int, s) exponential s0-    | S.null s0           = (0, s0)-    | isE (unsafeHead s0) = sign (unsafeTail s0)-    | otherwise           = (0, s0)+    | C.null s0       = (0, s0)+    | isE (C.head s0) = sign (C.tail s0)+    | otherwise       = (0, s0)   where     isE w = w == 101 || w == 69 @@ -90,12 +88,12 @@     plus  = 43      sign s1-        | S.null s1              = (0, s0)-        | unsafeHead s1 == plus  = expPart $ unsafeTail s1-        | unsafeHead s1 == minus = let (e, s) = expPart $ unsafeTail s1 in (-e, s)-        | otherwise              = expPart s1+        | C.null s1          = (0, s0)+        | C.head s1 == plus  = expPart $ C.tail s1+        | C.head s1 == minus = let (e, s) = expPart $ C.tail s1 in (-e, s)+        | otherwise          = expPart s1 -    expPart s2 = case integral (Proxy :: Proxy 10) s2 :: (Fraction Double, Int, Int, ByteString) of+    expPart s2 = case integral (Proxy :: Proxy 10) s2 :: (Fraction Double, Int, Int, s) of         (_, 0, _, _) -> (0, s0)         (e, _, _, s) -> (fromFraction e, s) {-# INLINABLE exponential #-}@@ -115,15 +113,15 @@ -- * fractional(0.1, 12224.3543) -- * exponential (e1, E+2, e-123) (optional) ----- >>> fractional10 "12.5" :: Maybe (Double, ByteString)+-- >>> fractional10 "12.5" :: Maybe (Double, S.ByteString) -- Just (12.5,"")--- >>> fractional10 "124.1e12" :: Maybe (Double, ByteString)+-- >>> fractional10 "124.1e12" :: Maybe (Double, L.ByteString) -- Just (1.241e14,"")--- >>> fractional10 "12.5e-3" :: Maybe (Double, ByteString)+-- >>> fractional10 "12.5e-3" :: Maybe (Double, S.ByteString) -- Just (1.25e-2,"")--- >>> fractional10 "3.11e+3" :: Maybe (Double, ByteString)+-- >>> fractional10 "3.11e+3" :: Maybe (Double, L.ByteString) -- Just (3110.0,"")-fractional10 :: ReadFractional r => ByteString -> Maybe (r, ByteString)+fractional10 :: (ReadFractional r, Source s) => s -> Maybe (r, s) fractional10 s = fractional' (Proxy :: Proxy 10) s >>= \(f, s') ->     let (e, s'') = exponential s'     in Just (setExpPart e f, s'')@@ -137,33 +135,33 @@ -- * fractional(0.1, 12224.3543) -- * exponential (e1, E+2, e-123) (10-radixed only, optional) ----- >>> fractional "12.4" :: Maybe (Double, ByteString)+-- >>> fractional "12.4" :: Maybe (Double, S.ByteString) -- Just (12.4,"")--- >>> fractional "1.23e12" :: Maybe (Double, ByteString)+-- >>> fractional "1.23e12" :: Maybe (Double, L.ByteString) -- Just (1.23e12,"")--- >>> fractional "0o0.4" :: Maybe (Double, ByteString)+-- >>> fractional "0o0.4" :: Maybe (Double, S.ByteString) -- Just (0.5,"")--- >>> fractional "0x3f.12" :: Maybe (Double, ByteString)+-- >>> fractional "0x3f.12" :: Maybe (Double, L.ByteString) -- Just (63.0703125,"")-fractional :: ReadFractional r => ByteString -> Maybe (r, ByteString)+fractional :: (ReadFractional r, Source s) => s -> Maybe (r, s) fractional s0-    | S.null s0             = Nothing-    | unsafeHead s0 == zero = radix $ unsafeTail s0-    | otherwise             = fractional10 s0+    | C.null s0         = Nothing+    | C.head s0 == zero = radix $ C.tail s0+    | otherwise         = fractional10 s0   where     zero  = 48     isX w = w == 120 || w == 88     isO w = w == 111 || w == 79      radix s1-        | S.null s1           = Just (0, "")-        | isX (unsafeHead s1) = fractional' (Proxy :: Proxy 16) (unsafeTail s1)-        | isO (unsafeHead s1) = fractional' (Proxy :: Proxy 8)  (unsafeTail s1)-        | otherwise           = fractional10 s0+        | C.null s1       = Just (0, C.empty)+        | isX (C.head s1) = fractional' (Proxy :: Proxy 16) (C.tail s1)+        | isO (C.head s1) = fractional' (Proxy :: Proxy 8)  (C.tail s1)+        | otherwise       = fractional10 s0 {-# INLINABLE fractional #-}  -- | @ -- double = fractional -- @-double :: ByteString -> Maybe (Double, ByteString)+double :: Source s => s -> Maybe (Double, s) double = fractional 
src/Data/ByteString/Read/Integral.hs view
@@ -7,38 +7,36 @@     , int     ) where -import Data.ByteString(ByteString)-import qualified Data.ByteString as S-import Data.ByteString.Unsafe- import Data.Proxy.Compat import GHC.TypeLits.Compat -import Data.ByteString.Read.Class+import Data.ByteString.Read.Class as C  -- $setup -- >>> :set -XDataKinds -XOverloadedStrings+-- >>> import qualified Data.ByteString as S+-- >>> import qualified Data.ByteString.Lazy as L -integral_ :: (Radix b, Num n) => proxy b -> ByteString -> (n, Int, ByteString)+integral_ :: (Radix b, Num n, Source s) => proxy b -> s -> (n, Int, s) integral_ pn = loop 0 0   where     loop !i !d !s-        | S.null s                        = (i, d, s)-        | not (isDigit pn (unsafeHead s)) = (i, d, s)-        | otherwise                       = loop-            (i * fromIntegral (natVal pn) + (fromIntegral $ unsafeToDigit pn (unsafeHead s)))-            (d+1) (unsafeTail s)+        | C.null s                    = (i, d, s)+        | not (isDigit pn (C.head s)) = (i, d, s)+        | otherwise                   = loop+            (i * fromIntegral (natVal pn) + (fromIntegral $ unsafeToDigit pn (C.head s)))+            (d+1) (C.tail s) {-# INLINABLE integral_ #-}  -- | convert bytestring into unsigned integral using radix ----- >>> integral' (Proxy :: Proxy 10) "12345" :: Maybe (Int, ByteString)+-- >>> integral' (Proxy :: Proxy 10) "12345" :: Maybe (Int, S.ByteString) -- Just (12345,"")--- >>> integral' (Proxy :: Proxy 2) "10112" :: Maybe (Int, ByteString)+-- >>> integral' (Proxy :: Proxy 2) "10112" :: Maybe (Int, L.ByteString) -- Just (11,"2")--- >>> integral' (Proxy :: Proxy 36) "Z" :: Maybe (Double, ByteString)+-- >>> integral' (Proxy :: Proxy 36) "Z" :: Maybe (Double, S.ByteString) -- Just (35.0,"")-integral' :: (Radix b, Num n) => proxy b -> ByteString -> Maybe (n, ByteString)+integral' :: (Radix b, Num n, Source s) => proxy b -> s -> Maybe (n, s) integral' pn s0 = case integral_ pn s0 of     (_, 0, _) -> Nothing     (n, _, s) -> Just (n, s)@@ -46,13 +44,13 @@ -- | @ -- integral = 'integral'' (Proxy :: Proxy 10) -- @-integral :: Num n => ByteString -> Maybe (n, ByteString)+integral :: (Num n, Source s) => s -> Maybe (n, s) integral = integral' (Proxy :: Proxy 10) {-# INLINABLE integral #-}  -- | @ -- int = integral -- @-int :: ByteString -> Maybe (Int, ByteString)+int :: Source s => s -> Maybe (Int, s) int = integral {-# INLINABLE int #-}