on master help sign in
Make integer encoding 30% faster again! Oh, and some CPP cleanups.
70fbcc8Bryan O'Sullivan
Data/Aeson/Encode/Number.hs+31−44
@@ -17,7 +17,7 @@ module Data.Aeson.Encode.Number
17import Data.Monoid (mappend, mempty)
17import Data.Monoid (mappend, mempty)
18import Data.Attoparsec.Number (Number(..))
18import Data.Attoparsec.Number (Number(..))
19import Blaze.ByteString.Builder
19import Blaze.ByteString.Builder
20−import GHC.Num (quotRemInt, quotRemInteger)
20+import GHC.Num (quotRemInteger)
21import GHC.Types (Int(..))
21import GHC.Types (Int(..))
22import qualified Text.Show.ByteString as S
22import qualified Text.Show.ByteString as S
23
23
@@ -29,6 +29,12 @@ import GHC.Integer.GMP.Internals
29# endif
29# endif
30#endif
30#endif
31
31
32+#ifdef INTEGER_GMP
33+# define PAIR(a,b) (# a,b #)
34+#else
35+# define PAIR(a,b) (a,b)
36+#endif
37+
32fromNumber :: Number -> Builder
38fromNumber :: Number -> Builder
33fromNumber (I i) = integer i
39fromNumber (I i) = integer i
34fromNumber (D d) = fromLazyByteString (S.show d)
40fromNumber (D d) = fromLazyByteString (S.show d)
@@ -36,48 +42,35 @@ fromNumber (D d) = fromLazyByteString (S.show d)
36integer :: Integer -> Builder
42integer :: Integer -> Builder
37integer (S# i#) = int (I# i#)
43integer (S# i#) = int (I# i#)
38integer i
44integer i
39− | i < 0 = fromWord8 45 `mappend` go (-i)
45+ | i < 0 = minus `mappend` go (-i)
40 | otherwise = go i
46 | otherwise = go i
41 where
47 where
42 go n | n < maxInt = int (fromInteger n)
48 go n | n < maxInt = int (fromInteger n)
43 | otherwise = putH (splitf (maxInt * maxInt) n)
49 | otherwise = putH (splitf (maxInt * maxInt) n)
44
50
45− splitf :: Integer -> Integer -> [Integer]
46 splitf p n
51 splitf p n
47− | p > n = [n]
52+ | p > n = [n]
48− | otherwise = splith p (splitf (p*p) n)
53+ | otherwise = splith p (splitf (p*p) n)
49
54
50− splith :: Integer -> [Integer] -> [Integer]
51− splith _ [ ] = error "splith: the impossible happened."
52 splith p (n:ns) = case n `quotRemInteger` p of
55 splith p (n:ns) = case n `quotRemInteger` p of
53−#ifdef INTEGER_GMP
54− (# q, r #) ->
55−#else
56− (q, r) ->
57−#endif
58− if q > 0
59− then q : r : splitb p ns
56+ PAIR(q,r) | q > 0 -> q : r : splitb p ns
60− else r : splitb p ns
57+ | otherwise -> r : splitb p ns
61− splitb :: Integer -> [Integer] -> [Integer]
58+ splith _ _ = error "splith: the impossible happened."
62− splitb _ [ ] = []
59+
63 splitb p (n:ns) = case n `quotRemInteger` p of
60 splitb p (n:ns) = case n `quotRemInteger` p of
64−#ifdef INTEGER_GMP
65− (# q, r #) ->
66−#else
67− (q, r) ->
68−#endif
69− q : r : splitb p ns
61+ PAIR(q,r) -> q : r : splitb p ns
62+ splitb _ _ = []
70
63
71int :: Int -> Builder
64int :: Int -> Builder
72int i
65int i
73− | i < 0 = fromWord8 45 `mappend` go (-i)
66+ | i < 0 = minus `mappend` go (-i)
74 | otherwise = go i
67 | otherwise = go i
75 where
68 where
76 go n | n < 10 = digit n
69 go n | n < 10 = digit n
77 | otherwise = go (n `rem` 10) `mappend` digit (n `quot` 10)
70 | otherwise = go (n `rem` 10) `mappend` digit (n `quot` 10)
78
71
79digit :: Int -> Builder
72digit :: Int -> Builder
80−digit n = fromWord8 (fromIntegral n + 48)
73+digit n = fromWord8 $! fromIntegral n + 48
81
74
82data T = T !Integer !Int
75data T = T !Integer !Int
83
76
@@ -92,28 +85,18 @@ T maxInt maxDigits =
92
85
93putH :: [Integer] -> Builder
86putH :: [Integer] -> Builder
94putH (n:ns) = case n `quotRemInteger` maxInt of
87putH (n:ns) = case n `quotRemInteger` maxInt of
95−#ifdef INTEGER_GMP
88+ PAIR(x,y)
96− (# q', r' #) ->
97−#else
98− (q', r') ->
99−#endif
100− let q = fromInteger q'
101− r = fromInteger r'
102− in if q > 0
103− then int q `mappend` pblock r `mappend` putB ns
89+ | q > 0 -> int q `mappend` pblock r `mappend` putB ns
104− else int r `mappend` putB ns
90+ | otherwise -> int r `mappend` putB ns
91+ where q = fromInteger x
92+ r = fromInteger y
105putH _ = error "putH: the impossible happened"
93putH _ = error "putH: the impossible happened"
106
94
107putB :: [Integer] -> Builder
95putB :: [Integer] -> Builder
108putB (n:ns) = case n `quotRemInteger` maxInt of
96putB (n:ns) = case n `quotRemInteger` maxInt of
109−#ifdef INTEGER_GMP
110− (# q', r' #) ->
111−#else
112− (q', r') ->
113−#endif
114− let q = fromInteger q'
115− r = fromInteger r'
116− in pblock q `mappend` pblock r `mappend` putB ns
97+ PAIR(x,y) -> pblock q `mappend` pblock r `mappend` putB ns
98+ where q = fromInteger x
99+ r = fromInteger y
117putB _ = mempty
100putB _ = mempty
118
101
119pblock :: Int -> Builder
102pblock :: Int -> Builder
@@ -122,4 +105,8 @@ pblock = go maxDigits
122 go !d !n
105 go !d !n
123 | d == 1 = digit n
106 | d == 1 = digit n
124 | otherwise = go (d-1) q `mappend` digit r
107 | otherwise = go (d-1) q `mappend` digit r
125− where (q, r) = n `quotRemInt` 10
108+ where q = n `quot` 10
109+ r = n `rem` 10
110+
111+minus :: Builder
112+minus = fromWord8 45