aeson-1.3.0.0: benchmarks/AesonMap.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Main (main) where
import Prelude ()
import Prelude.Compat
import Control.DeepSeq
import Criterion.Main
import Data.Hashable
import Data.Proxy (Proxy (..))
import Data.Tagged (Tagged (..))
import Data.Aeson
import Data.Aeson.Types (fromJSONKeyCoerce)
import qualified Data.ByteString.Lazy as LBS
import qualified Data.HashMap.Strict as HM
import qualified Data.Map as M
import qualified Data.Text as T
value :: Int -> HM.HashMap T.Text T.Text
value n = HM.fromList $ map f [1..n]
where
f m = let t = T.pack (show m) in (t, t)
-------------------------------------------------------------------------------
-- Orphans
-------------------------------------------------------------------------------
instance Hashable b => Hashable (Tagged a b) where
hashWithSalt salt (Tagged a) = hashWithSalt salt a
-------------------------------------------------------------------------------
-- Text
-------------------------------------------------------------------------------
newtype T1 = T1 T.Text
deriving (Eq, Ord)
instance NFData T1 where
rnf (T1 t) = rnf t
instance Hashable T1 where
hashWithSalt salt (T1 t) = hashWithSalt salt t
instance FromJSON T1 where
parseJSON = withText "T1" $ pure . T1
instance FromJSONKey T1 where
fromJSONKey = FromJSONKeyText T1
-------------------------------------------------------------------------------
-- Coerce
-------------------------------------------------------------------------------
newtype T2 = T2 T.Text
deriving (Eq, Ord)
instance NFData T2 where
rnf (T2 t) = rnf t
instance Hashable T2 where
hashWithSalt salt (T2 t) = hashWithSalt salt t
instance FromJSON T2 where
parseJSON = withText "T2" $ pure . T2
instance FromJSONKey T2 where
fromJSONKey = fromJSONKeyCoerce
-------------------------------------------------------------------------------
-- TextParser
-------------------------------------------------------------------------------
newtype T3 = T3 T.Text
deriving (Eq, Ord)
instance NFData T3 where
rnf (T3 t) = rnf t
instance Hashable T3 where
hashWithSalt salt (T3 t) = hashWithSalt salt t
instance FromJSON T3 where
parseJSON = withText "T3" $ pure . T3
instance FromJSONKey T3 where
fromJSONKey = FromJSONKeyTextParser (pure . T3)
-------------------------------------------------------------------------------
-- Values
-------------------------------------------------------------------------------
value10, value100, value1000, value10000 :: HM.HashMap T.Text T.Text
value10 = value 10
value100 = value 100
value1000 = value 1000
value10000 = value 10000
encodedValue10 :: LBS.ByteString
encodedValue10 = encode value10
encodedValue100 :: LBS.ByteString
encodedValue100 = encode value100
encodedValue1000 :: LBS.ByteString
encodedValue1000 = encode value1000
encodedValue10000 :: LBS.ByteString
encodedValue10000 = encode value10000
-------------------------------------------------------------------------------
-- Helpers
-------------------------------------------------------------------------------
decodeHM
:: (FromJSON (HM.HashMap k T.Text), Eq k, Hashable k)
=> Proxy k -> LBS.ByteString -> Maybe (HM.HashMap k T.Text)
decodeHM _ = decode
decodeMap
:: (FromJSON (M.Map k T.Text), Ord k)
=> Proxy k -> LBS.ByteString -> Maybe (M.Map k T.Text)
decodeMap _ = decode
proxyText :: Proxy T.Text
proxyText = Proxy
proxyT1 :: Proxy T1
proxyT1 = Proxy
proxyT2 :: Proxy T2
proxyT2 = Proxy
proxyT3 :: Proxy T3
proxyT3 = Proxy
proxyTagged :: Proxy a -> Proxy (Tagged () a)
proxyTagged _ = Proxy
-------------------------------------------------------------------------------
-- Main
-------------------------------------------------------------------------------
benchDecodeHM
:: String
-> LBS.ByteString
-> Benchmark
benchDecodeHM name val = bgroup name
[ bench "Text" $ nf (decodeHM proxyText) val
, bench "Identity" $ nf (decodeHM proxyT1) val
, bench "Coerce" $ nf (decodeHM proxyT2) val
, bench "Parser" $ nf (decodeHM proxyT3) val
, bench "Tagged Text" $ nf (decodeHM $ proxyTagged proxyText) val
, bench "Tagged Identity" $ nf (decodeHM $ proxyTagged proxyT1) val
, bench "Tagged Coerce" $ nf (decodeHM $ proxyTagged proxyT2) val
, bench "Tagged Parser" $ nf (decodeHM $ proxyTagged proxyT3) val
]
benchDecodeMap
:: String
-> LBS.ByteString
-> Benchmark
benchDecodeMap name val = bgroup name
[ bench "Text" $ nf (decodeMap proxyText) val
, bench "Identity" $ nf (decodeMap proxyT1) val
, bench "Coerce" $ nf (decodeMap proxyT2) val
, bench "Parser" $ nf (decodeMap proxyT3) val
]
benchEncodeHM
:: String
-> HM.HashMap T.Text T.Text
-> Benchmark
benchEncodeHM name val = bgroup name
[ bench "Text" $ nf encode val
]
benchEncodeMap
:: String
-> HM.HashMap T.Text T.Text
-> Benchmark
benchEncodeMap name val = bgroup name
[ bench "Text" $ nf encode val'
]
where
val' :: M.Map T.Text T.Text
val' = M.fromList . HM.toList $ val
main :: IO ()
main = defaultMain
[ bgroup "decode"
[ bgroup "HashMap"
[ benchDecodeHM "10" encodedValue10
, benchDecodeHM "100" encodedValue100
, benchDecodeHM "1000" encodedValue1000
, benchDecodeHM "10000" encodedValue10000
]
, bgroup "Map"
[ benchDecodeMap "10" encodedValue10
, benchDecodeMap "100" encodedValue100
, benchDecodeMap "1000" encodedValue1000
, benchDecodeMap "10000" encodedValue10000
]
]
, bgroup "encode"
[ bgroup "HashMap"
[ benchEncodeHM "100" value100
, benchEncodeHM "1000" value1000
, benchEncodeHM "10000" value10000
]
, bgroup "Map"
[ benchEncodeMap "100" value100
, benchEncodeMap "1000" value1000
, benchEncodeMap "10000" value10000
]
]
]