diff --git a/src/Data/Csv/Conversion.hs b/src/Data/Csv/Conversion.hs index 1f2ab84..d4cedba 100644 --- a/src/Data/Csv/Conversion.hs +++ b/src/Data/Csv/Conversion.hs @@ -79,6 +79,7 @@ import qualified Control.Monad.Fail as Fail import Data.Attoparsec.ByteString.Char8 (double) import qualified Data.Attoparsec.ByteString.Char8 as A8 import qualified Data.ByteString as B +import qualified Data.ByteString.Builder as Builder import qualified Data.ByteString.Char8 as B8 import qualified Data.ByteString.Lazy as L #if MIN_VERSION_bytestring(0,10,4) @@ -885,7 +886,7 @@ instance FromField Int where -- | Uses decimal encoding with optional sign. instance ToField Int where - toField = decimal + toField = viaBuilder . Builder.intDec {-# INLINE toField #-} -- | Accepts a signed decimal number. Ignores whitespace. @@ -895,7 +896,7 @@ instance FromField Integer where -- | Uses decimal encoding with optional sign. instance ToField Integer where - toField = decimal + toField = viaBuilder . Builder.integerDec {-# INLINE toField #-} -- | Accepts a signed decimal number. Ignores whitespace. @@ -905,7 +906,7 @@ instance FromField Int8 where -- | Uses decimal encoding with optional sign. instance ToField Int8 where - toField = decimal + toField = viaBuilder . Builder.int8Dec {-# INLINE toField #-} -- | Accepts a signed decimal number. Ignores whitespace. @@ -915,7 +916,7 @@ instance FromField Int16 where -- | Uses decimal encoding with optional sign. instance ToField Int16 where - toField = decimal + toField = viaBuilder . Builder.int16Dec {-# INLINE toField #-} -- | Accepts a signed decimal number. Ignores whitespace. @@ -925,7 +926,7 @@ instance FromField Int32 where -- | Uses decimal encoding with optional sign. instance ToField Int32 where - toField = decimal + toField = viaBuilder . Builder.int32Dec {-# INLINE toField #-} -- | Accepts a signed decimal number. Ignores whitespace. @@ -935,7 +936,7 @@ instance FromField Int64 where -- | Uses decimal encoding with optional sign. instance ToField Int64 where - toField = decimal + toField = viaBuilder . Builder.int64Dec {-# INLINE toField #-} -- | Accepts an unsigned decimal number. Ignores whitespace. @@ -945,7 +946,7 @@ instance FromField Word where -- | Uses decimal encoding. instance ToField Word where - toField = decimal + toField = viaBuilder . Builder.wordDec {-# INLINE toField #-} -- | Accepts an unsigned decimal number. Ignores whitespace. @@ -969,7 +970,7 @@ instance FromField Word8 where -- | Uses decimal encoding. instance ToField Word8 where - toField = decimal + toField = viaBuilder . Builder.word8Dec {-# INLINE toField #-} -- | Accepts an unsigned decimal number. Ignores whitespace. @@ -979,7 +980,7 @@ instance FromField Word16 where -- | Uses decimal encoding. instance ToField Word16 where - toField = decimal + toField = viaBuilder . Builder.word16Dec {-# INLINE toField #-} -- | Accepts an unsigned decimal number. Ignores whitespace. @@ -989,7 +990,7 @@ instance FromField Word32 where -- | Uses decimal encoding. instance ToField Word32 where - toField = decimal + toField = viaBuilder . Builder.word32Dec {-# INLINE toField #-} -- | Accepts an unsigned decimal number. Ignores whitespace. @@ -999,7 +1000,7 @@ instance FromField Word64 where -- | Uses decimal encoding. instance ToField Word64 where - toField = decimal + toField = viaBuilder . Builder.word64Dec {-# INLINE toField #-} instance FromField B.ByteString where diff --git a/src/Data/Csv/Conversion/Internal.hs b/src/Data/Csv/Conversion/Internal.hs index fa368a7..264b1a9 100644 --- a/src/Data/Csv/Conversion/Internal.hs +++ b/src/Data/Csv/Conversion/Internal.hs @@ -2,6 +2,8 @@ module Data.Csv.Conversion.Internal ( decimal , scientific , realFloat + , viaBuilder + , formatBoundedSigned ) where import Data.ByteString.Builder (Builder, toLazyByteString, word8, char8, @@ -12,7 +14,6 @@ import Data.Array.Base (unsafeAt) import Data.Array.IArray import qualified Data.ByteString as B import Data.Char (ord) -import Data.Int import qualified Data.Monoid as Mon import Data.Scientific (Scientific) import Data.Word @@ -29,26 +30,6 @@ decimal = toStrict . toLazyByteString . formatDecimal -- TODO: Add an optimized version for Integer. formatDecimal :: Integral a => a -> Builder -{-# RULES "formatDecimal/Int" formatDecimal = formatBoundedSigned - :: Int -> Builder #-} -{-# RULES "formatDecimal/Int8" formatDecimal = formatBoundedSigned - :: Int8 -> Builder #-} -{-# RULES "formatDecimal/Int16" formatDecimal = formatBoundedSigned - :: Int16 -> Builder #-} -{-# RULES "formatDecimal/Int32" formatDecimal = formatBoundedSigned - :: Int32 -> Builder #-} -{-# RULES "formatDecimal/Int64" formatDecimal = formatBoundedSigned - :: Int64 -> Builder #-} -{-# RULES "formatDecimal/Word" formatDecimal = formatPositive - :: Word -> Builder #-} -{-# RULES "formatDecimal/Word8" formatDecimal = formatPositive - :: Word8 -> Builder #-} -{-# RULES "formatDecimal/Word16" formatDecimal = formatPositive - :: Word16 -> Builder #-} -{-# RULES "formatDecimal/Word32" formatDecimal = formatPositive - :: Word32 -> Builder #-} -{-# RULES "formatDecimal/Word64" formatDecimal = formatPositive - :: Word64 -> Builder #-} {-# NOINLINE formatDecimal #-} formatDecimal i | i < 0 = minus Mon.<> @@ -58,11 +39,6 @@ formatDecimal i | otherwise = formatPositive i formatBoundedSigned :: (Integral a, Bounded a) => a -> Builder -{-# SPECIALIZE formatBoundedSigned :: Int -> Builder #-} -{-# SPECIALIZE formatBoundedSigned :: Int8 -> Builder #-} -{-# SPECIALIZE formatBoundedSigned :: Int16 -> Builder #-} -{-# SPECIALIZE formatBoundedSigned :: Int32 -> Builder #-} -{-# SPECIALIZE formatBoundedSigned :: Int64 -> Builder #-} formatBoundedSigned i | i < 0 = minus Mon.<> if i == minBound @@ -71,16 +47,6 @@ formatBoundedSigned i | otherwise = formatPositive i formatPositive :: Integral a => a -> Builder -{-# SPECIALIZE formatPositive :: Int -> Builder #-} -{-# SPECIALIZE formatPositive :: Int8 -> Builder #-} -{-# SPECIALIZE formatPositive :: Int16 -> Builder #-} -{-# SPECIALIZE formatPositive :: Int32 -> Builder #-} -{-# SPECIALIZE formatPositive :: Int64 -> Builder #-} -{-# SPECIALIZE formatPositive :: Word -> Builder #-} -{-# SPECIALIZE formatPositive :: Word8 -> Builder #-} -{-# SPECIALIZE formatPositive :: Word16 -> Builder #-} -{-# SPECIALIZE formatPositive :: Word32 -> Builder #-} -{-# SPECIALIZE formatPositive :: Word64 -> Builder #-} formatPositive = go where go n | n < 10 = digit n | otherwise = go (n `quot` 10) Mon.<> digit (n `rem` 10) @@ -297,3 +263,8 @@ i2d i = fromIntegral (ord '0' + i) -- | Word8 list rendering word8s :: [Word8] -> Builder word8s = BP.primMapListFixed BP.word8 + +-- | Helper function that build strict bytestring via a provided builder. +viaBuilder :: Builder -> B.ByteString +viaBuilder = toStrict . toLazyByteString +{-# INLINE viaBuilder #-}