on master help sign in
Drop use of blaze-builder during encoding.

This improves performance by about 10%.

commit95d6a6a285fd1c90fdb1fb0951b88ab547f1fb8c authorBryan O'Sullivan <bos@serpentine.com> dateFri 23 Dec 2011, 13:34 (15 years ago) parentbb5e08d
2 files changed+30−36
Data/Aeson/Encode.hs+30−35 aeson.cabal−1
Data/Aeson/Encode.hs+30−35
@@ -17,75 +17,70 @@ module Data.Aeson.Encode
1717 , encode
1818 ) where
1919
20−import Blaze.ByteString.Builder (Builder, fromByteString, toLazyByteString)
21−import Blaze.Text (double, integral)
2220import Data.Aeson.Types (ToJSON(..), Value(..))
2321import Data.Attoparsec.Number (Number(..))
2422import Data.Monoid (mappend)
25−import Data.Text.Encoding (encodeUtf8)
23+import Data.Text.Lazy.Builder
24+import Data.Text.Lazy.Builder.Int (decimal)
25+import Data.Text.Lazy.Builder.RealFloat (realFloat)
26+import Data.Text.Lazy.Encoding (encodeUtf8)
2627import Numeric (showHex)
27−import qualified Blaze.ByteString.Builder.Char.Utf8 as Utf8
28−import qualified Blaze.ByteString.Builder.Char8 as Char8
29−import qualified Data.ByteString.Lazy.Char8 as L
28+import qualified Data.ByteString.Lazy as L
3029import qualified Data.HashMap.Strict as H
3130import qualified Data.Text as T
3231import qualified Data.Vector as V
3332
3433-- | Encode a JSON value to a 'Builder'.
3534fromValue :: Value -> Builder
36−fromValue Null = {-# SCC "fromValue/Null" #-} fromByteString "null"
35+fromValue Null = {-# SCC "fromValue/Null" #-} "null"
3736fromValue (Bool b) = {-# SCC "fromValue/Bool" #-}
38− if b then fromByteString "true"
39− else fromByteString "false"
37+ if b then "true"
38+ else "false"
4039fromValue (Number n) = {-# SCC "fromValue/Number" #-} fromNumber n
4140fromValue (String s) = {-# SCC "fromValue/String" #-} string s
4241fromValue (Array v)
43− | V.null v = {-# SCC "fromValue/Array" #-} fromByteString "[]"
42+ | V.null v = {-# SCC "fromValue/Array" #-} "[]"
4443 | otherwise = {-# SCC "fromValue/Array" #-}
45− Char8.fromChar '[' `mappend`
44+ singleton '[' `mappend`
4645 fromValue (V.unsafeHead v) `mappend`
47− V.foldr f (Char8.fromChar ']') (V.unsafeTail v)
48− where f a z = Char8.fromChar ',' `mappend` fromValue a `mappend` z
46+ V.foldr f (singleton ']') (V.unsafeTail v)
47+ where f a z = singleton ',' `mappend` fromValue a `mappend` z
4948fromValue (Object m) = {-# SCC "fromValue/Object" #-}
5049 case H.toList m of
51− (x:xs) -> Char8.fromChar '{' `mappend`
52− one x `mappend` foldr f (Char8.fromChar '}') xs
53− _ -> fromByteString "{}"
54− where f a z = Char8.fromChar ',' `mappend` one a `mappend` z
55− one (k,v) = string k `mappend` Char8.fromChar ':' `mappend` fromValue v
50+ (x:xs) -> singleton '{' `mappend`
51+ one x `mappend` foldr f (singleton '}') xs
52+ _ -> "{}"
53+ where f a z = singleton ',' `mappend` one a `mappend` z
54+ one (k,v) = string k `mappend` singleton ':' `mappend` fromValue v
5655
5756string :: T.Text -> Builder
5857string s = {-# SCC "string" #-}
59− Char8.fromChar '"' `mappend` quote s `mappend` Char8.fromChar '"'
58+ singleton '"' `mappend` quote s `mappend` singleton '"'
6059 where
6160 quote q = case T.uncons t of
6261 Just (c,t') -> fromText h `mappend` escape c `mappend` quote t'
6362 Nothing -> fromText h
64− where (h,t) = T.break isEscape q
63+ where (h,t) = {-# SCC "break" #-} T.break isEscape q
6564 isEscape c = c == '\"' || c == '\\' || c < '\x20'
66− escape '\"' = fromByteString "\\\""
67− escape '\\' = fromByteString "\\\\"
68− escape '\n' = fromByteString "\\n"
69− escape '\r' = fromByteString "\\r"
70− escape '\t' = fromByteString "\\t"
65+ escape '\"' = "\\\""
66+ escape '\\' = "\\\\"
67+ escape '\n' = "\\n"
68+ escape '\r' = "\\r"
69+ escape '\t' = "\\t"
7170 escape c
72− | c < '\x20' = Char8.fromString $
71+ | c < '\x20' = fromString $
7372 "\\u" ++ replicate (4 - length h) '0' ++ h
74− | otherwise = Utf8.fromChar c
73+ | otherwise = singleton c
7574 where h = showHex (fromEnum c) ""
7675
77−-- The version in blaze-builder is way slower.
78−fromText :: T.Text -> Builder
79−fromText t = fromByteString (encodeUtf8 t)
80−
8176fromNumber :: Number -> Builder
82−fromNumber (I i) = integral i
77+fromNumber (I i) = decimal i
8378fromNumber (D d)
84− | isNaN d || isInfinite d = fromByteString "null"
85− | otherwise = double d
79+ | isNaN d || isInfinite d = "null"
80+ | otherwise = realFloat d
8681
8782-- | Efficiently serialize a JSON value as a lazy 'L.ByteString'.
8883encode :: ToJSON a => a -> L.ByteString
89−encode = {-# SCC "encode" #-} toLazyByteString . fromValue .
84+encode = {-# SCC "encode" #-} encodeUtf8 . toLazyText . fromValue .
9085 {-# SCC "toJSON" #-} toJSON
9186{-# INLINE encode #-}
aeson.cabal−1
@@ -122,7 +122,6 @@ library
122122 attoparsec >= 0.8.6.1,
123123 base == 4.*,
124124 blaze-builder >= 0.2.1.4,
125− blaze-textual >= 0.2.0.2,
126125 bytestring,
127126 containers,
128127 deepseq,