on master help sign in
Merge pull request #36 from basvandijk/optimizations

Optimizations

commit17de902db4e7f71b5aa18e973bf0bd421946f5f5 authorBryan O'Sullivan <bos@serpentine.com> dateMon 7 Nov 2011, 21:45 (15 years ago) parentbe81de8fa9c2ab
6 files changed+114−77
Data/Aeson/TH.hs+9−9 Data/Aeson/Types/Class.hs+12−5 Data/Aeson/Types/Generic.hs+65−28 Data/Aeson/Types/Internal.hs+1−6 aeson.cabal+2−4 benchmarks/AesonCompareAutoInstances.hs+25−25
Data/Aeson/TH.hs+9−9
@@ -89,9 +89,9 @@ instance 'FromJSON' a => 'FromJSON' (D a) where
8989 case conVal of
9090 'Array' arr ->
9191 if V.length arr == 3
92− then Product \<$\> 'parseJSON' (arr V.! 0)
93− \<*\> 'parseJSON' (arr V.! 1)
94− \<*\> 'parseJSON' (arr V.! 2)
92+ then Product \<$\> 'parseJSON' (arr `V.unsafeIndex` 0)
93+ \<*\> 'parseJSON' (arr `V.unsafeIndex` 1)
94+ \<*\> 'parseJSON' (arr `V.unsafeIndex` 2)
9595 else fail \"\<error message\>\"
9696 _ -> fail \"\<error message\>\"
9797 | conKey == T.pack \"Record\" ->
@@ -168,7 +168,7 @@ import Prelude ( String, (-), Integer, error )
168168import Text.Printf ( printf )
169169import Text.Show ( show )
170170#if __GLASGOW_HASKELL__ < 700
171−import Control.Monad ( (>>=) )
171+import Control.Monad ( (>>=), fail )
172172import Prelude ( fromInteger )
173173#endif
174174-- from containers:
@@ -178,7 +178,7 @@ import Language.Haskell.TH
178178-- from text:
179179import qualified Data.Text as T ( Text, pack, unpack )
180180-- from vector:
181−import qualified Data.Vector as V ( (!), null, length )
181+import qualified Data.Vector as V ( unsafeIndex, null, length )
182182
183183
184184
@@ -385,8 +385,8 @@ encodeArgs withExp withField (ForallC _ _ con) =
385385-- \value -> case value of
386386-- 'Array' arr ->
387387-- if (V.length arr == 2)
388−-- then Foo \<$\> 'parseJSON' (arr V.! 0)
389−-- \<*\> 'parseJSON' (arr V.! 1)
388+-- then Foo \<$\> 'parseJSON' (arr `V.unsafeIndex` 0)
389+-- \<*\> 'parseJSON' (arr `V.unsafeIndex` 1)
390390-- else fail \"\<error message\>\"
391391-- other -> fail \"\<error message\>\"
392392-- @
@@ -600,11 +600,11 @@ parseProduct :: Name -- ^ Name of the type to which the constructor belongs.
600600 -> [Q Match]
601601parseProduct tName conName numArgs =
602602 [ do arr <- newName "arr"
603− -- List of: "parseJSON (arr V.! <IX>)"
603+ -- List of: "parseJSON (arr `V.unsafeIndex` <IX>)"
604604 let x:xs = [ [|parseJSON|]
605605 `appE`
606606 infixApp (varE arr)
607− [|(V.!)|]
607+ [|V.unsafeIndex|]
608608 (litE $ integerL ix)
609609 | ix <- [0 .. numArgs - 1]
610610 ]
Data/Aeson/Types/Class.hs+12−5
@@ -1,6 +1,13 @@
1−{-# LANGUAGE CPP, DeriveDataTypeable, FlexibleContexts, FlexibleInstances,
2− GeneralizedNewtypeDeriving, IncoherentInstances, OverlappingInstances,
3− OverloadedStrings, UndecidableInstances, ViewPatterns #-}
1+{-# LANGUAGE CPP
2+ , DeriveDataTypeable
3+ , FlexibleContexts
4+ , FlexibleInstances
5+ , GeneralizedNewtypeDeriving
6+ , OverlappingInstances
7+ , OverloadedStrings
8+ , UndecidableInstances
9+ , ViewPatterns
10+ #-}
411
512#ifdef GENERICS
613{-# LANGUAGE DefaultSignatures #-}
@@ -104,7 +111,7 @@ class GFromJSON f where
104111--
105112-- * 'Data.Aeson.Generic' provides a generic @toJSON@ function that accepts any
106113-- type which is an instance of 'Data'.
107−--
114+--
108115-- * If your compiler has support for the @DeriveGeneric@ and
109116-- @DefaultSignatures@ language extensions, @toJSON@ will have a default generic
110117-- implementation.
@@ -143,7 +150,7 @@ class ToJSON a where
143150-- @{-\# LANGUAGE OverloadedStrings #-}
144151--
145152-- data Coord { x :: Double, y :: Double }
146−--
153+--
147154-- instance FromJSON Coord where
148155-- parseJSON ('Object' v) = Coord '<$>'
149156-- v '.:' \"x\" '<*>'
Data/Aeson/Types/Generic.hs+65−28
@@ -1,7 +1,15 @@
1−{-# LANGUAGE DefaultSignatures, EmptyDataDecls, FlexibleContexts,
2− FlexibleInstances, FunctionalDependencies, IncoherentInstances,
3− KindSignatures, OverlappingInstances, ScopedTypeVariables, TypeOperators,
4− UndecidableInstances, ViewPatterns #-}
1+{-# LANGUAGE DefaultSignatures
2+ , EmptyDataDecls
3+ , FlexibleInstances
4+ , FunctionalDependencies
5+ , KindSignatures
6+ , OverlappingInstances
7+ , ScopedTypeVariables
8+ , TypeOperators
9+ , UndecidableInstances
10+ , ViewPatterns
11+ #-}
12+
513{-# OPTIONS_GHC -fno-warn-orphans #-}
614
715-- |
@@ -18,10 +26,10 @@ module Data.Aeson.Types.Generic ( ) where
1826
1927import Control.Applicative
2028import Control.Monad.State.Strict
29+import Data.Bits (shiftR)
2130import Data.Aeson.Types.Class
2231import Data.Aeson.Types.Internal
2332import Data.Text (pack, unpack)
24−import Data.Vector ((!?))
2533import GHC.Generics
2634import qualified Data.Map as M
2735import qualified Data.Text as T
@@ -60,6 +68,8 @@ instance (GObject a, GObject b) => GToJSON (a :+: b) where
6068class ConsToJSON f where consToJSON :: f a -> Value
6169class ConsToJSON' b f where consToJSON' :: Tagged b (f a -> Value)
6270
71+newtype Tagged s b = Tagged {unTagged :: b}
72+
6373instance (IsRecord f b, ConsToJSON' b f) => ConsToJSON f where
6474 consToJSON = unTagged (consToJSON' :: Tagged b (f a -> Value))
6575 {-# INLINE consToJSON #-}
@@ -109,7 +119,7 @@ instance (GObject a, GObject b) => GObject (a :+: b) where
109119 {-# INLINE gObject #-}
110120
111121instance (Constructor c, GToJSON a, ConsToJSON a) => GObject (C1 c a) where
112− gObject m1 = M.singleton (pack (conName m1)) (gToJSON m1)
122+ gObject = M.singleton (pack $ conName (undefined :: t c a p)) . gToJSON
113123 {-# INLINE gObject #-}
114124
115125--------------------------------------------------------------------------------
@@ -133,16 +143,33 @@ instance (ConsFromJSON a) => GFromJSON (C1 c a) where
133143 gParseJSON = fmap M1 . consParseJSON
134144 {-# INLINE gParseJSON #-}
135145
136−instance (GFromProduct a, GFromProduct b) => GFromJSON (a :*: b) where
137− gParseJSON (Array arr) = gParseProduct arr
146+instance ( GFromProduct a, GFromProduct b
147+ , ProductSize a, ProductSize b) => GFromJSON (a :*: b) where
148+ gParseJSON (Array arr)
149+ | lenArray == lenProduct = gParseProduct arr 0 lenProduct
150+ | otherwise =
151+ fail $ "When expecting a product of " ++ show lenProduct ++
152+ " values, encountered an Array of " ++ show lenArray ++
153+ " elements instead"
154+ where
155+ lenArray = V.length arr
156+ lenProduct = unTagged2 (productSize :: Tagged2 (a :*: b) Int)
157+
138158 gParseJSON v = typeMismatch "product (:*:)" v
139159 {-# INLINE gParseJSON #-}
140160
141161instance (GFromSum a, GFromSum b) => GFromJSON (a :+: b) where
142− gParseJSON (Object (M.toList -> [keyVal])) = gParseSum keyVal
162+ gParseJSON (Object (M.toList -> [keyVal@(key, _)])) =
163+ case gParseSum keyVal of
164+ Nothing -> notFound $ unpack key
165+ Just p -> p
143166 gParseJSON v = typeMismatch "sum (:+:)" v
144167 {-# INLINE gParseJSON #-}
145168
169+notFound :: String -> Parser a
170+notFound key = fail $ "The key \"" ++ key ++ "\" was not found"
171+{-# INLINE notFound #-}
172+
146173--------------------------------------------------------------------------------
147174
148175class ConsFromJSON f where consParseJSON :: Value -> Parser (f a)
@@ -173,56 +200,66 @@ instance (GFromRecord a, GFromRecord b) => GFromRecord (a :*: b) where
173200 {-# INLINE gParseRecord #-}
174201
175202instance (Selector s, GFromJSON a) => GFromRecord (S1 s a) where
176− gParseRecord obj = case M.lookup (T.pack key) obj of
177− Nothing -> notFound key
178− Just v -> gParseJSON v
203+ gParseRecord = maybe (notFound key) gParseJSON . M.lookup (T.pack key)
179204 where
180205 key = selName (undefined :: t s a p)
181206 {-# INLINE gParseRecord #-}
182207
183208--------------------------------------------------------------------------------
184209
210+class ProductSize f where
211+ productSize :: Tagged2 f Int
212+
213+newtype Tagged2 (s :: * -> *) b = Tagged2 {unTagged2 :: b}
214+
215+instance (ProductSize a, ProductSize b) => ProductSize (a :*: b) where
216+ productSize = Tagged2 $ unTagged2 (productSize :: Tagged2 a Int) +
217+ unTagged2 (productSize :: Tagged2 b Int)
218+
219+instance ProductSize (S1 s a) where
220+ productSize = Tagged2 1
221+
222+--------------------------------------------------------------------------------
223+
185224class GFromProduct f where
186− gParseProduct :: Array -> Parser (f a)
225+ gParseProduct :: Array -> Int -> Int -> Parser (f a)
187226
188227instance (GFromProduct a, GFromProduct b) => GFromProduct (a :*: b) where
189− gParseProduct arr = (:*:) <$> gParseProduct arrL <*> gParseProduct arrR
228+ gParseProduct arr ix len = (:*:) <$> gParseProduct arr ix lenL
229+ <*> gParseProduct arr ixR lenR
190230 where
191− (arrL, arrR) = V.splitAt (V.length arr `div` 2) arr
231+ lenL = len `shiftR` 1
232+ ixR = ix + lenL
233+ lenR = len - lenL
192234 {-# INLINE gParseProduct #-}
193235
194−instance (GFromJSON a) => GFromProduct a where
195− gParseProduct ((!? 0) -> Just v) = gParseJSON v
196− gParseProduct _ = fail "Array to small"
236+instance (GFromJSON a) => GFromProduct (S1 s a) where
237+ gParseProduct arr ix _ = gParseJSON $ V.unsafeIndex arr ix
197238 {-# INLINE gParseProduct #-}
198239
199240--------------------------------------------------------------------------------
200241
201242class GFromSum f where
202− gParseSum :: Pair -> Parser (f a)
243+ gParseSum :: Pair -> Maybe (Parser (f a))
203244
204245instance (GFromSum a, GFromSum b) => GFromSum (a :+: b) where
205− gParseSum keyVal = (L1 <$> gParseSum keyVal) <|> (R1 <$> gParseSum keyVal)
246+ gParseSum keyVal = (fmap L1 <$> gParseSum keyVal) <|>
247+ (fmap R1 <$> gParseSum keyVal)
206248 {-# INLINE gParseSum #-}
207249
208250instance (Constructor c, GFromJSON a, ConsFromJSON a) => GFromSum (C1 c a) where
209251 gParseSum (key, value)
210− | key == pack (conName (undefined :: t c a p)) = gParseJSON value
211− | otherwise = notFound $ unpack key
252+ | key == pack (conName (undefined :: t c a p)) = Just $ gParseJSON value
253+ | otherwise = Nothing
212254 {-# INLINE gParseSum #-}
213255
214−notFound :: String -> Parser a
215−notFound key = fail $ "The key \"" ++ key ++ "\" was not found"
216−
217256--------------------------------------------------------------------------------
218257
219−newtype Tagged s b = Tagged {unTagged :: b}
258+class IsRecord (f :: * -> *) b | f -> b
220259
221260data True
222261data False
223262
224−class IsRecord (f :: * -> *) b | f -> b
225−
226263instance (IsRecord f b) => IsRecord (f :*: g) b
227264instance IsRecord (M1 S NoSelector f) False
228265instance (IsRecord f b) => IsRecord (M1 S c f) b
Data/Aeson/Types/Internal.hs+1−6
@@ -1,9 +1,4 @@
1−{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, GeneralizedNewtypeDeriving,
2− IncoherentInstances, OverlappingInstances, OverloadedStrings, Rank2Types,
3− ViewPatterns, FlexibleContexts, UndecidableInstances,
4− ScopedTypeVariables, PatternGuards #-}
5−
6−{-# LANGUAGE CPP #-}
1+{-# LANGUAGE CPP, DeriveDataTypeable, Rank2Types #-}
72
83-- |
94-- Module: Data.Aeson.Types.Internal
aeson.cabal+2−4
@@ -120,6 +120,8 @@ library
120120 Data.Aeson.Types.Internal
121121
122122 if impl(ghc >= 7.2.1)
123+ cpp-options: -DGENERICS
124+ build-depends: ghc-prim >= 0.2
123125 other-modules:
124126 Data.Aeson.Types.Generic
125127
@@ -145,10 +147,6 @@ library
145147 ghc-options: -Werror
146148 ghc-prof-options: -auto-all
147149
148− if impl(ghc >= 7.2.1)
149− cpp-options: -DGENERICS
150− build-depends: ghc-prim >= 0.2
151−
152150 ghc-options: -Wall
153151
154152test-suite tests
benchmarks/AesonCompareAutoInstances.hs+25−25
@@ -25,7 +25,7 @@ data D a = Nullary
2525 | Record { testOne :: Double
2626 , testTwo :: Bool
2727 , testThree :: D a
28− } deriving (Eq, Generic, Data, Typeable)
28+ } deriving (Show, Eq, Generic, Data, Typeable)
2929
3030instance NFData a => NFData (D a) where
3131 rnf Nullary = ()
@@ -62,20 +62,20 @@ thDFromJSON = parse thDParseJSON
6262--------------------------------------------------------------------------------
6363
6464data BigRecord = BigRecord
65− { field01 :: !(), field02 :: !(), field03 :: !(), field04 :: !(), field05 :: !()
66− , field06 :: !(), field07 :: !(), field08 :: !(), field09 :: !(), field10 :: !()
67− , field11 :: !(), field12 :: !(), field13 :: !(), field14 :: !(), field15 :: !()
68− , field16 :: !(), field17 :: !(), field18 :: !(), field19 :: !(), field20 :: !()
69− , field21 :: !(), field22 :: !(), field23 :: !(), field24 :: !(), field25 :: !()
70− } deriving (Eq, Generic, Data, Typeable)
65+ { field01 :: !Int, field02 :: !Int, field03 :: !Int, field04 :: !Int, field05 :: !Int
66+ , field06 :: !Int, field07 :: !Int, field08 :: !Int, field09 :: !Int, field10 :: !Int
67+ , field11 :: !Int, field12 :: !Int, field13 :: !Int, field14 :: !Int, field15 :: !Int
68+ , field16 :: !Int, field17 :: !Int, field18 :: !Int, field19 :: !Int, field20 :: !Int
69+ , field21 :: !Int, field22 :: !Int, field23 :: !Int, field24 :: !Int, field25 :: !Int
70+ } deriving (Show, Eq, Generic, Data, Typeable)
7171
7272instance NFData BigRecord
7373
74−bigRecord = BigRecord () () () () ()
75− () () () () ()
76− () () () () ()
77− () () () () ()
78− () () () () ()
74+bigRecord = BigRecord 1 2 3 4 5
75+ 6 7 8 9 10
76+ 11 12 13 14 15
77+ 16 17 18 19 20
78+ 21 22 23 24 25
7979
8080instance ToJSON BigRecord
8181instance FromJSON BigRecord
@@ -92,20 +92,20 @@ thBigRecordFromJSON = parse thBigRecordParseJSON
9292--------------------------------------------------------------------------------
9393
9494data BigProduct = BigProduct
95− !() !() !() !() !()
96− !() !() !() !() !()
97− !() !() !() !() !()
98− !() !() !() !() !()
99− !() !() !() !() !()
100− deriving (Eq, Generic, Data, Typeable)
95+ !Int !Int !Int !Int !Int
96+ !Int !Int !Int !Int !Int
97+ !Int !Int !Int !Int !Int
98+ !Int !Int !Int !Int !Int
99+ !Int !Int !Int !Int !Int
100+ deriving (Show, Eq, Generic, Data, Typeable)
101101
102102instance NFData BigProduct
103103
104−bigProduct = BigProduct () () () () ()
105− () () () () ()
106− () () () () ()
107− () () () () ()
108− () () () () ()
104+bigProduct = BigProduct 1 2 3 4 5
105+ 6 7 8 9 10
106+ 11 12 13 14 15
107+ 16 17 18 19 20
108+ 21 22 23 24 25
109109
110110instance ToJSON BigProduct
111111instance FromJSON BigProduct
@@ -126,11 +126,11 @@ data BigSum = F01 | F02 | F03 | F04 | F05
126126 | F11 | F12 | F13 | F14 | F15
127127 | F16 | F17 | F18 | F19 | F20
128128 | F21 | F22 | F23 | F24 | F25
129− deriving (Eq, Generic, Data, Typeable)
129+ deriving (Show, Eq, Generic, Data, Typeable)
130130
131131instance NFData BigSum
132132
133−bigSum = F12
133+bigSum = F25
134134
135135instance ToJSON BigSum
136136instance FromJSON BigSum