Skip to content

Commit a2c416a

Browse files
committed
Use specific builder functions for encoding.
Instead of keeping internal function for decoding we can reuse much more efficient builders from the bytestring library. It increases speed and improves memory usage and allows more code sharing between the libraries. Specialization pragmas were removed, they didn't provide much benefit anyway as the code is recursive and optimizer does not inline it. However internal functions were not removed so the user of cassava can use them for semi-efficient numeric types encoding in case if there are no efficient builders available directly for those types.
1 parent 2348030 commit a2c416a

File tree

2 files changed

+19
-47
lines changed

2 files changed

+19
-47
lines changed

src/Data/Csv/Conversion.hs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ import qualified Control.Monad.Fail as Fail
7979
import Data.Attoparsec.ByteString.Char8 (double)
8080
import qualified Data.Attoparsec.ByteString.Char8 as A8
8181
import qualified Data.ByteString as B
82+
import qualified Data.ByteString.Builder as Builder
8283
import qualified Data.ByteString.Char8 as B8
8384
import qualified Data.ByteString.Lazy as L
8485
#if MIN_VERSION_bytestring(0,10,4)
@@ -885,7 +886,7 @@ instance FromField Int where
885886

886887
-- | Uses decimal encoding with optional sign.
887888
instance ToField Int where
888-
toField = decimal
889+
toField = viaBuilder . Builder.intDec
889890
{-# INLINE toField #-}
890891

891892
-- | Accepts a signed decimal number. Ignores whitespace.
@@ -895,7 +896,7 @@ instance FromField Integer where
895896

896897
-- | Uses decimal encoding with optional sign.
897898
instance ToField Integer where
898-
toField = decimal
899+
toField = viaBuilder . Builder.integerDec
899900
{-# INLINE toField #-}
900901

901902
-- | Accepts a signed decimal number. Ignores whitespace.
@@ -905,7 +906,7 @@ instance FromField Int8 where
905906

906907
-- | Uses decimal encoding with optional sign.
907908
instance ToField Int8 where
908-
toField = decimal
909+
toField = viaBuilder . Builder.int8Dec
909910
{-# INLINE toField #-}
910911

911912
-- | Accepts a signed decimal number. Ignores whitespace.
@@ -915,7 +916,7 @@ instance FromField Int16 where
915916

916917
-- | Uses decimal encoding with optional sign.
917918
instance ToField Int16 where
918-
toField = decimal
919+
toField = viaBuilder . Builder.int16Dec
919920
{-# INLINE toField #-}
920921

921922
-- | Accepts a signed decimal number. Ignores whitespace.
@@ -925,7 +926,7 @@ instance FromField Int32 where
925926

926927
-- | Uses decimal encoding with optional sign.
927928
instance ToField Int32 where
928-
toField = decimal
929+
toField = viaBuilder . Builder.int32Dec
929930
{-# INLINE toField #-}
930931

931932
-- | Accepts a signed decimal number. Ignores whitespace.
@@ -935,7 +936,7 @@ instance FromField Int64 where
935936

936937
-- | Uses decimal encoding with optional sign.
937938
instance ToField Int64 where
938-
toField = decimal
939+
toField = viaBuilder . Builder.int64Dec
939940
{-# INLINE toField #-}
940941

941942
-- | Accepts an unsigned decimal number. Ignores whitespace.
@@ -945,7 +946,7 @@ instance FromField Word where
945946

946947
-- | Uses decimal encoding.
947948
instance ToField Word where
948-
toField = decimal
949+
toField = viaBuilder . Builder.wordDec
949950
{-# INLINE toField #-}
950951

951952
-- | Accepts an unsigned decimal number. Ignores whitespace.
@@ -969,7 +970,7 @@ instance FromField Word8 where
969970

970971
-- | Uses decimal encoding.
971972
instance ToField Word8 where
972-
toField = decimal
973+
toField = viaBuilder . Builder.word8Dec
973974
{-# INLINE toField #-}
974975

975976
-- | Accepts an unsigned decimal number. Ignores whitespace.
@@ -979,7 +980,7 @@ instance FromField Word16 where
979980

980981
-- | Uses decimal encoding.
981982
instance ToField Word16 where
982-
toField = decimal
983+
toField = viaBuilder . Builder.word16Dec
983984
{-# INLINE toField #-}
984985

985986
-- | Accepts an unsigned decimal number. Ignores whitespace.
@@ -989,7 +990,7 @@ instance FromField Word32 where
989990

990991
-- | Uses decimal encoding.
991992
instance ToField Word32 where
992-
toField = decimal
993+
toField = viaBuilder . Builder.word32Dec
993994
{-# INLINE toField #-}
994995

995996
-- | Accepts an unsigned decimal number. Ignores whitespace.
@@ -999,7 +1000,7 @@ instance FromField Word64 where
9991000

10001001
-- | Uses decimal encoding.
10011002
instance ToField Word64 where
1002-
toField = decimal
1003+
toField = viaBuilder . Builder.word64Dec
10031004
{-# INLINE toField #-}
10041005

10051006
instance FromField B.ByteString where

src/Data/Csv/Conversion/Internal.hs

Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ module Data.Csv.Conversion.Internal
22
( decimal
33
, scientific
44
, realFloat
5+
, viaBuilder
6+
, formatBoundedSigned
57
) where
68

79
import Data.ByteString.Builder (Builder, toLazyByteString, word8, char8,
@@ -12,7 +14,6 @@ import Data.Array.Base (unsafeAt)
1214
import Data.Array.IArray
1315
import qualified Data.ByteString as B
1416
import Data.Char (ord)
15-
import Data.Int
1617
import qualified Data.Monoid as Mon
1718
import Data.Scientific (Scientific)
1819
import Data.Word
@@ -29,26 +30,6 @@ decimal = toStrict . toLazyByteString . formatDecimal
2930
-- TODO: Add an optimized version for Integer.
3031

3132
formatDecimal :: Integral a => a -> Builder
32-
{-# RULES "formatDecimal/Int" formatDecimal = formatBoundedSigned
33-
:: Int -> Builder #-}
34-
{-# RULES "formatDecimal/Int8" formatDecimal = formatBoundedSigned
35-
:: Int8 -> Builder #-}
36-
{-# RULES "formatDecimal/Int16" formatDecimal = formatBoundedSigned
37-
:: Int16 -> Builder #-}
38-
{-# RULES "formatDecimal/Int32" formatDecimal = formatBoundedSigned
39-
:: Int32 -> Builder #-}
40-
{-# RULES "formatDecimal/Int64" formatDecimal = formatBoundedSigned
41-
:: Int64 -> Builder #-}
42-
{-# RULES "formatDecimal/Word" formatDecimal = formatPositive
43-
:: Word -> Builder #-}
44-
{-# RULES "formatDecimal/Word8" formatDecimal = formatPositive
45-
:: Word8 -> Builder #-}
46-
{-# RULES "formatDecimal/Word16" formatDecimal = formatPositive
47-
:: Word16 -> Builder #-}
48-
{-# RULES "formatDecimal/Word32" formatDecimal = formatPositive
49-
:: Word32 -> Builder #-}
50-
{-# RULES "formatDecimal/Word64" formatDecimal = formatPositive
51-
:: Word64 -> Builder #-}
5233
{-# NOINLINE formatDecimal #-}
5334
formatDecimal i
5435
| i < 0 = minus Mon.<>
@@ -58,11 +39,6 @@ formatDecimal i
5839
| otherwise = formatPositive i
5940

6041
formatBoundedSigned :: (Integral a, Bounded a) => a -> Builder
61-
{-# SPECIALIZE formatBoundedSigned :: Int -> Builder #-}
62-
{-# SPECIALIZE formatBoundedSigned :: Int8 -> Builder #-}
63-
{-# SPECIALIZE formatBoundedSigned :: Int16 -> Builder #-}
64-
{-# SPECIALIZE formatBoundedSigned :: Int32 -> Builder #-}
65-
{-# SPECIALIZE formatBoundedSigned :: Int64 -> Builder #-}
6642
formatBoundedSigned i
6743
| i < 0 = minus Mon.<>
6844
if i == minBound
@@ -71,16 +47,6 @@ formatBoundedSigned i
7147
| otherwise = formatPositive i
7248

7349
formatPositive :: Integral a => a -> Builder
74-
{-# SPECIALIZE formatPositive :: Int -> Builder #-}
75-
{-# SPECIALIZE formatPositive :: Int8 -> Builder #-}
76-
{-# SPECIALIZE formatPositive :: Int16 -> Builder #-}
77-
{-# SPECIALIZE formatPositive :: Int32 -> Builder #-}
78-
{-# SPECIALIZE formatPositive :: Int64 -> Builder #-}
79-
{-# SPECIALIZE formatPositive :: Word -> Builder #-}
80-
{-# SPECIALIZE formatPositive :: Word8 -> Builder #-}
81-
{-# SPECIALIZE formatPositive :: Word16 -> Builder #-}
82-
{-# SPECIALIZE formatPositive :: Word32 -> Builder #-}
83-
{-# SPECIALIZE formatPositive :: Word64 -> Builder #-}
8450
formatPositive = go
8551
where go n | n < 10 = digit n
8652
| otherwise = go (n `quot` 10) Mon.<> digit (n `rem` 10)
@@ -297,3 +263,8 @@ i2d i = fromIntegral (ord '0' + i)
297263
-- | Word8 list rendering
298264
word8s :: [Word8] -> Builder
299265
word8s = BP.primMapListFixed BP.word8
266+
267+
-- | Helper function that build strict bytestring via a provided builder.
268+
viaBuilder :: Builder -> B.ByteString
269+
viaBuilder = toStrict . toLazyByteString
270+
{-# INLINE viaBuilder #-}

0 commit comments

Comments
 (0)