on master help sign in
Port a bunch of code over to blaze-textual for reuse.
commitc18c5d4603d2c12fa9f30e14c63d8da38aedd139 authorBryan O'Sullivan <bos@mailrank.com> dateThu 28 Apr 2011, 15:15 (15 years ago) parentc45b792
5 files changed+8−269
Data/Aeson/Encode.hs+6−1 Data/Aeson/Encode/Double.hs−120 Data/Aeson/Encode/Int.hs−34 Data/Aeson/Encode/Number.hs−100 aeson.cabal+2−14
Data/Aeson/Encode.hs+6−1
@@ -18,10 +18,11 @@ module Data.Aeson.Encode
1818
1919import Blaze.ByteString.Builder
2020import Blaze.ByteString.Builder.Char.Utf8
21−import Data.Aeson.Encode.Number (fromNumber)
21+import Data.Attoparsec.Number (Number(..))
2222import Data.Aeson.Types (ToJSON(..), Value(..))
2323import Data.Monoid (mappend)
2424import Numeric (showHex)
25+import Blaze.Text (double, integral)
2526import qualified Data.ByteString.Lazy.Char8 as L
2627import qualified Data.Map as M
2728import qualified Data.Text as T
@@ -66,6 +67,10 @@ string s = fromChar '"' `mappend` quote s `mappend` fromChar '"'
6667 | otherwise = fromChar c
6768 where h = showHex (fromEnum c) ""
6869
70+fromNumber :: Number -> Builder
71+fromNumber (I i) = integral i
72+fromNumber (D d) = double d
73+
6974-- | Efficiently serialize a JSON value as a lazy 'L.ByteString'.
7075encode :: ToJSON a => a -> L.ByteString
7176encode = toLazyByteString . fromValue . toJSON
Data/Aeson/Encode/Double.hsdeleted−120
@@ -1,120 +0,0 @@
1−{-# LANGUAGE BangPatterns, CPP, MagicHash, OverloadedStrings, UnboxedTuples #-}
2−
3−-- Module: Data.Aeson.Encode.Number
4−-- Copyright: (c) 2011 MailRank, Inc.
5−-- License: Apache
6−-- Maintainer: Bryan O'Sullivan <bos@mailrank.com>
7−-- Stability: experimental
8−-- Portability: portable
9−--
10−-- Efficiently serialize a Double as a lazy 'L.ByteString'.
11−
12−module Data.Aeson.Encode.Double
13− (
14− double
15− ) where
16−
17−import Blaze.ByteString.Builder (Builder, fromByteString)
18−import Blaze.ByteString.Builder.Char8 (fromChar)
19−import Data.Aeson.Encode.Int (digit, int, minus)
20−import Data.ByteString.Char8 ()
21−import Data.Monoid (mappend, mconcat, mempty)
22−import qualified Data.Vector as V
23−
24−-- The code below is originally from GHC.Float, but has been optimised
25−-- in quite a few ways.
26−
27−data T = T [Int] {-# UNPACK #-} !Int
28−
29−double :: Double -> Builder
30−double f
31− | isNaN f || isInfinite f = fromByteString "null"
32− | f < 0 || isNegativeZero f = minus `mappend` goGeneric (floatToDigits (-f))
33− | otherwise = goGeneric (floatToDigits f)
34− where
35− goGeneric p@(T _ e)
36− | e < 0 || e > 7 = goExponent p
37− | otherwise = goFixed p
38− goExponent (T is e) =
39− case is of
40− [] -> error "putFormattedFloat"
41− [0] -> fromByteString "0.0e0"
42− [d] -> digit d `mappend` fromByteString ".0e" `mappend` int (e-1)
43− (d:ds) -> digit d `mappend` fromChar '.' `mappend` digits ds `mappend`
44− fromChar 'e' `mappend` int (e-1)
45− goFixed (T is e)
46− | e <= 0 = fromChar '0' `mappend` fromChar '.' `mappend`
47− mconcat (replicate (-e) (fromChar '0')) `mappend`
48− digits is
49− | otherwise = let g 0 rs = fromChar '.' `mappend` mk0 rs
50− g n [] = fromChar '0' `mappend` g (n-1) []
51− g n (r:rs) = digit r `mappend` g (n-1) rs
52− in g e is
53− mk0 [] = fromChar '0'
54− mk0 rs = digits rs
55−
56−digits :: [Int] -> Builder
57−digits (d:ds) = digit d `mappend` digits ds
58−digits _ = mempty
59−{-# INLINE digits #-}
60−
61−floatToDigits :: Double -> T
62−floatToDigits 0 = T [0] 0
63−floatToDigits x = T (reverse rds) k
64− where
65− (f0, e0) = decodeFloat x
66− (minExp0, _) = floatRange (undefined::Double)
67− p = floatDigits x
68− b = floatRadix x
69− minExp = minExp0 - p -- the real minimum exponent
70− -- Haskell requires that f be adjusted so denormalized numbers
71− -- will have an impossibly low exponent. Adjust for this.
72− (# f, e #) =
73− let n = minExp - e0 in
74− if n > 0 then (# f0 `div` (b^n), e0+n #) else (# f0, e0 #)
75− (# r, s, mUp, mDn #) =
76− if e >= 0
77− then let be = b^ e
78− in if f == b^(p-1)
79− then (# f*be*b*2, 2*b, be*b, b #)
80− else (# f*be*2, 2, be, be #)
81− else if e > minExp && f == b^(p-1)
82− then (# f*b*2, b^(-e+1)*2, b, 1 #)
83− else (# f*2, b^(-e)*2, 1, 1 #)
84− k = fixup k0
85− where
86− k0 | b == 2 = (p - 1 + e0) * 3 `div` 10
87− -- logBase 10 2 is slightly bigger than 3/10 so the following
88− -- will err on the low side. Ignoring the fraction will make
89− -- it err even more. Haskell promises that p-1 <= logBase b f
90− -- < p.
91− | otherwise = ceiling ((log (fromInteger (f+1) :: Double) +
92− fromIntegral e * log (fromInteger b)) / log 10)
93− fixup n
94− | n >= 0 = if r + mUp <= exp10 n * s then n else fixup (n+1)
95− | otherwise = if exp10 (-n) * (r + mUp) <= s then n else fixup (n+1)
96−
97− gen ds !rn !sN !mUpN !mDnN =
98− let (dn0, rn') = (rn * 10) `divMod` sN
99− mUpN' = mUpN * 10
100− mDnN' = mDnN * 10
101− !dn = fromInteger dn0
102− !dn' = dn + 1
103− in case (# rn' < mDnN', rn' + mUpN' > sN #) of
104− (# True, False #) -> dn : ds
105− (# False, True #) -> dn' : ds
106− (# True, True #) -> if rn' * 2 < sN then dn : ds else dn' : ds
107− (# False, False #) -> gen (dn:ds) rn' sN mUpN' mDnN'
108−
109− rds | k >= 0 = gen [] r (s * exp10 k) mUp mDn
110− | otherwise = gen [] (r * bk) s (mUp * bk) (mDn * bk)
111− where bk = exp10 (-k)
112−
113−exp10 :: Int -> Integer
114−exp10 n
115− | n >= 0 && n < maxExpt = V.unsafeIndex expts n
116− | otherwise = 10 ^ n
117− where expts = V.generate maxExpt (10^)
118− {-# NOINLINE expts #-}
119− maxExpt = 17
120−{-# INLINE exp10 #-}
Data/Aeson/Encode/Int.hsdeleted−34
@@ -1,34 +0,0 @@
1−{-# LANGUAGE BangPatterns, CPP, MagicHash, UnboxedTuples #-}
2−
3−-- Module: Data.Aeson.Encode.Int
4−-- Copyright: (c) 2011 MailRank, Inc.
5−-- License: Apache
6−-- Maintainer: Bryan O'Sullivan <bos@mailrank.com>
7−-- Stability: experimental
8−-- Portability: portable
9−--
10−-- Efficiently serialize an integral JSON value as a lazy 'L.ByteString'.
11−
12−module Data.Aeson.Encode.Int
13− (
14− digit
15− , int
16− , minus
17− ) where
18−
19−import Blaze.ByteString.Builder (Builder, fromWord8)
20−import Data.Monoid (mappend)
21−
22−int :: Int -> Builder
23−int i
24− | i < 0 = minus `mappend` go (-i)
25− | otherwise = go i
26− where
27− go n | n < 10 = digit n
28− | otherwise = go (n `quot` 10) `mappend` digit (n `rem` 10)
29−
30−digit :: Int -> Builder
31−digit n = fromWord8 $! fromIntegral n + 48
32−
33−minus :: Builder
34−minus = fromWord8 45
Data/Aeson/Encode/Number.hsdeleted−100
@@ -1,100 +0,0 @@
1−{-# LANGUAGE BangPatterns, CPP, MagicHash, UnboxedTuples #-}
2−
3−-- Module: Data.Aeson.Encode.Number
4−-- Copyright: (c) 2011 MailRank, Inc.
5−-- License: Apache
6−-- Maintainer: Bryan O'Sullivan <bos@mailrank.com>
7−-- Stability: experimental
8−-- Portability: portable
9−--
10−-- Efficiently serialize a numeric JSON value as a lazy 'L.ByteString'.
11−
12−module Data.Aeson.Encode.Number
13− (
14− fromNumber
15− ) where
16−
17−import Data.Monoid (mappend, mempty)
18−import Data.Attoparsec.Number (Number(..))
19−import Data.Aeson.Encode.Double
20−import Data.Aeson.Encode.Int
21−import Blaze.ByteString.Builder
22−import GHC.Base (quotInt, remInt)
23−import GHC.Num (quotRemInteger)
24−import GHC.Types (Int(..))
25−
26−#ifdef __GLASGOW_HASKELL__
27−# if __GLASGOW_HASKELL__ < 611
28−import GHC.Integer.Internals
29−# else
30−import GHC.Integer.GMP.Internals
31−# endif
32−#endif
33−
34−#ifdef INTEGER_GMP
35−# define PAIR(a,b) (# a,b #)
36−#else
37−# define PAIR(a,b) (a,b)
38−#endif
39−
40−fromNumber :: Number -> Builder
41−fromNumber (I i) = integer i
42−fromNumber (D d) = double d
43−
44−integer :: Integer -> Builder
45−integer (S# i#) = int (I# i#)
46−integer i
47− | i < 0 = minus `mappend` go (-i)
48− | otherwise = go i
49− where
50− go n | n < maxInt = int (fromInteger n)
51− | otherwise = putH (splitf (maxInt * maxInt) n)
52−
53− splitf p n
54− | p > n = [n]
55− | otherwise = splith p (splitf (p*p) n)
56−
57− splith p (n:ns) = case n `quotRemInteger` p of
58− PAIR(q,r) | q > 0 -> q : r : splitb p ns
59− | otherwise -> r : splitb p ns
60− splith _ _ = error "splith: the impossible happened."
61−
62− splitb p (n:ns) = case n `quotRemInteger` p of
63− PAIR(q,r) -> q : r : splitb p ns
64− splitb _ _ = []
65−
66−data T = T !Integer !Int
67−
68−fstT :: T -> Integer
69−fstT (T a _) = a
70−
71−maxInt :: Integer
72−maxDigits :: Int
73−T maxInt maxDigits =
74− until ((>mi) . (*10) . fstT) (\(T n d) -> T (n*10) (d+1)) (T 10 1)
75− where mi = fromIntegral (maxBound :: Int)
76−
77−putH :: [Integer] -> Builder
78−putH (n:ns) = case n `quotRemInteger` maxInt of
79− PAIR(x,y)
80− | q > 0 -> int q `mappend` pblock r `mappend` putB ns
81− | otherwise -> int r `mappend` putB ns
82− where q = fromInteger x
83− r = fromInteger y
84−putH _ = error "putH: the impossible happened"
85−
86−putB :: [Integer] -> Builder
87−putB (n:ns) = case n `quotRemInteger` maxInt of
88− PAIR(x,y) -> pblock q `mappend` pblock r `mappend` putB ns
89− where q = fromInteger x
90− r = fromInteger y
91−putB _ = mempty
92−
93−pblock :: Int -> Builder
94−pblock = go maxDigits
95− where
96− go !d !n
97− | d == 1 = digit n
98− | otherwise = go (d-1) q `mappend` digit r
99− where q = n `quotInt` 10
100− r = n `remInt` 10
aeson.cabal+2−14
@@ -1,5 +1,5 @@
11name: aeson
2−version: 0.3.2.4
2+version: 0.3.2.5
33license: BSD3
44license-file: LICENSE
55category: Text, Web, JSON
@@ -91,21 +91,17 @@ library
9191 Data.Aeson.Types
9292
9393 other-modules:
94− Data.Aeson.Encode.Double
95− Data.Aeson.Encode.Int
96− Data.Aeson.Encode.Number
9794 Data.Aeson.Functions
9895
9996 build-depends:
10097 attoparsec >= 0.8.5.3,
10198 base == 4.*,
10299 blaze-builder >= 0.2.1.4,
100+ blaze-textual,
103101 bytestring,
104102 containers,
105103 deepseq,
106− ghc-prim,
107104 hashable,
108− integer-gmp,
109105 mtl,
110106 old-locale,
111107 syb,
@@ -120,14 +116,6 @@ library
120116
121117 ghc-options: -Wall
122118
123− if impl(ghc >= 6.11)
124− cpp-options: -DINTEGER_GMP
125− build-depends: integer-gmp >= 0.2 && < 0.3
126−
127− if impl(ghc >= 6.9) && impl(ghc < 6.11)
128− cpp-options: -DINTEGER_GMP
129− build-depends: integer >= 0.1 && < 0.2
130−
131119source-repository head
132120 type: git
133121 location: http://github.com/mailrank/aeson