{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

-- | Benchmarks for generators
module Data.GenValidity.Criterion
  ( genValidBench,
    genBenchSizes,
    genBench,
    genBenchSized,
  )
where

import Control.DeepSeq
import Criterion
import Data.GenValidity
import Data.Typeable
import Test.QuickCheck.Gen
import Test.QuickCheck.Random

-- | Benchmarks for both genValid
genValidBench ::
  forall a.
  (Typeable a, NFData a, GenValid a) =>
  Benchmark
genValidBench :: Benchmark
genValidBench = String -> Gen a -> Benchmark
forall a. NFData a => String -> Gen a -> Benchmark
genBenchSizes ([String] -> String
unwords [String
"genValid", Typeable a => String
forall a. Typeable a => String
nameOf @a]) (GenValid a => Gen a
forall a. GenValid a => Gen a
genValid @a)

-- | Benchmarks a generator with some default sizes
genBenchSizes :: NFData a => String -> Gen a -> Benchmark
genBenchSizes :: String -> Gen a -> Benchmark
genBenchSizes String
name Gen a
gen =
  String -> [Benchmark] -> Benchmark
bgroup String
name ([Benchmark] -> Benchmark) -> [Benchmark] -> Benchmark
forall a b. (a -> b) -> a -> b
$
    let bi :: Int -> Benchmark
bi Int
i = String -> Int -> Gen a -> Benchmark
forall a. NFData a => String -> Int -> Gen a -> Benchmark
genBenchSized (String
"size " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show Int
i) Int
i Gen a
gen
     in [Int -> Benchmark
bi Int
15, Int -> Benchmark
bi Int
30]

-- | Benchmarks a generator with a given name with the default size: 30
genBench :: NFData a => String -> Gen a -> Benchmark
genBench :: String -> Gen a -> Benchmark
genBench String
name = String -> Int -> Gen a -> Benchmark
forall a. NFData a => String -> Int -> Gen a -> Benchmark
genBenchSized String
name Int
30

-- | Benchmarks a generator with a given name and size
genBenchSized :: NFData a => String -> Int -> Gen a -> Benchmark
genBenchSized :: String -> Int -> Gen a -> Benchmark
genBenchSized String
name Int
size (MkGen QCGen -> Int -> a
genFunc) =
  String -> Benchmarkable -> Benchmark
bench String
name (Benchmarkable -> Benchmark) -> Benchmarkable -> Benchmark
forall a b. (a -> b) -> a -> b
$ (QCGen -> a) -> QCGen -> Benchmarkable
forall b a. NFData b => (a -> b) -> a -> Benchmarkable
nf (\QCGen
seed -> QCGen -> Int -> a
genFunc QCGen
seed Int
size) (Int -> QCGen
mkQCGen Int
42)

nameOf ::
  forall a.
  Typeable a =>
  String
nameOf :: String
nameOf =
  let s :: String
s = TypeRep -> String
forall a. Show a => a -> String
show (TypeRep -> String) -> TypeRep -> String
forall a b. (a -> b) -> a -> b
$ Proxy a -> TypeRep
forall k (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy a
forall k (t :: k). Proxy t
Proxy @a)
   in if Char
' ' Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
s
        then String
"(" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"
        else String
s