packages feed

unicode-data-security-0.3.0: bench/Main.hs

{-# LANGUAGE ExistentialQuantification #-}

import Control.DeepSeq (NFData, deepseq)
import Data.Ix (Ix (..))
import GHC.Exts (Ptr (..))
import Test.Tasty.Bench (Benchmark, bcompare, bench, bgroup, defaultMain, nf)

import qualified Unicode.Char.Identifiers.Security as Security
import qualified Unicode.Internal.Char.Security.Confusables as Confusables
import qualified Unicode.Internal.Char.Security.IntentionalConfusables as Confusables

-- | A unit benchmark
data Bench = forall a. (NFData a) => Bench
  { _title :: !String  -- ^ Name
  , _func :: Char -> a -- ^ Function to benchmark
  }

main :: IO ()
main = defaultMain
    [ bgroup "Unicode.Char.Identifiers.Security"
        [ bgroup "Identifier Status"
            [ benchNF "isAllowedInIdentifier" Security.isAllowedInIdentifier
            ]
        , bgroup "Identifier Types"
            [ benchNF "identifierTypes"     (fmap fromEnum . Security.identifierTypes)
            ]
        , bgroup "Confusables"
            [ bgroup' "confusablePrototype"
                [ Bench "CString" (\c -> Ptr (Confusables.confusablePrototype c))
                , Bench "String"  Security.confusablePrototype
                ]
            -- , benchNF "prototype" Security.prototype
            , bgroup' "intentionalConfusables"
                [ Bench "CString" (\c -> Ptr (Confusables.intentionalConfusables c))
                , Bench "String"  Security.intentionalConfusables
                ]
            , benchNF "isIntentionallyConfusable" Security.intentionalConfusables
            ]
        ]
    ]
  where
    bgroup' groupTitle bs = bgroup groupTitle
        [ benchNF' groupTitle title f
        | Bench title f <- bs
        ]

    -- [NOTE] Works if groupTitle uniquely identifies the benchmark group.
    benchNF' groupTitle title = case title of
        "CString" -> benchNF title
        _         ->
            bcompare ("$NF == \"CString\" && $(NF-1) == \"" ++ groupTitle ++ "\"")
          . benchNF title

    benchNF :: forall a. (NFData a) => String -> (Char -> a) -> Benchmark
    benchNF t f = bench t $ nf (fold_ f) (minBound, maxBound)

    fold_ :: forall a. (NFData a) => (Char -> a) -> (Char, Char) -> ()
    fold_ f = foldr (deepseq . f) () . range