import Control.DeepSeq (NFData, deepseq)
import Data.Ix (Ix(..))
import Test.Tasty.Bench (Benchmark, bgroup, bench, bcompare, nf, defaultMain)
import qualified Data.Char as B
import qualified Unicode.Char.Case as C
import qualified Unicode.Char.Case.Compat as CC
import qualified Unicode.Char.General as G
import qualified Unicode.Char.General.Compat as GC
import qualified Unicode.Char.Identifiers as I
import qualified Unicode.Char.Normalization as N
import qualified Unicode.Char.Numeric as Num
-- | A unit benchmark
data Bench a = Bench
{ _title :: !String -- ^ Name
, _func :: Char -> a -- ^ Function to benchmark
}
main :: IO ()
main = defaultMain
[ bgroup "Unicode.Char.Case"
[ bgroup "isLowerCase"
[ benchNF "unicode-data" C.isLowerCase
]
, bgroup "isUpperCase"
[ benchNF "unicode-data" C.isUpperCase
]
]
, bgroup "Unicode.Char.Case.Compat"
[ bgroup' "isLower"
[ Bench "base" B.isLower
, Bench "unicode-data" CC.isLower
]
, bgroup' "isUpper"
[ Bench "base" B.isUpper
, Bench "unicode-data" CC.isUpper
]
, bgroup' "toLower"
[ Bench "base" B.toLower
, Bench "unicode-data" CC.toLower
]
, bgroup' "toTitle"
[ Bench "base" B.toTitle
, Bench "unicode-data" CC.toTitle
]
, bgroup' "toUpper"
[ Bench "base" B.toUpper
, Bench "unicode-data" CC.toUpper
]
]
, bgroup "Unicode.Char.General"
-- Character classification
[ bgroup' "generalCategory"
[ Bench "base" (show . B.generalCategory)
, Bench "unicode-data" (show . G.generalCategory)
]
, bgroup "isAlphabetic"
[ benchNF "unicode-data" G.isAlphabetic
]
, bgroup' "isAlphaNum"
[ Bench "base" B.isAlphaNum
, Bench "unicode-data" G.isAlphaNum
]
, bgroup' "isControl"
[ Bench "base" B.isControl
, Bench "unicode-data" G.isControl
]
, bgroup' "isMark"
[ Bench "base" B.isMark
, Bench "unicode-data" G.isMark
]
, bgroup' "isPrint"
[ Bench "base" B.isPrint
, Bench "unicode-data" G.isPrint
]
, bgroup' "isPunctuation"
[ Bench "base" B.isPunctuation
, Bench "unicode-data" G.isPunctuation
]
, bgroup' "isSeparator"
[ Bench "base" B.isSeparator
, Bench "unicode-data" G.isSeparator
]
, bgroup' "isSymbol"
[ Bench "base" B.isSymbol
, Bench "unicode-data" G.isSymbol
]
, bgroup "isWhiteSpace"
[ benchNF "unicode-data" G.isWhiteSpace
]
-- Korean Hangul Characters
, bgroup "isHangul"
[ benchNF "unicode-data" G.isHangul
]
, bgroup "isHangulLV"
[ benchNF "unicode-data" G.isHangul
]
, bgroup "isJamo"
[ benchNF "unicode-data" G.isJamo
]
, bgroup "jamoLIndex"
[ benchNF "unicode-data" G.jamoLIndex
]
, bgroup "jamoVIndex"
[ benchNF "unicode-data" G.jamoVIndex
]
, bgroup "jamoTIndex"
[ benchNF "unicode-data" G.jamoTIndex
]
]
, bgroup "Unicode.Char.General.Compat"
[ bgroup' "isAlpha"
[ Bench "base" B.isAlpha
, Bench "unicode-data" GC.isAlpha
]
, bgroup' "isLetter"
[ Bench "base" B.isLetter
, Bench "unicode-data" GC.isLetter
]
, bgroup' "isSpace"
[ Bench "base" B.isSpace
, Bench "unicode-data" GC.isSpace
]
]
, bgroup "Unicode.Char.Identifiers"
[ bgroup "isIDContinue"
[ benchNF "unicode-data" I.isIDContinue
]
, bgroup "isIDStart"
[ benchNF "unicode-data" I.isIDStart
]
, bgroup "isXIDContinue"
[ benchNF "unicode-data" I.isXIDContinue
]
, bgroup "isXIDStart"
[ benchNF "unicode-data" I.isXIDStart
]
, bgroup "isPatternSyntax"
[ benchNF "unicode-data" I.isPatternSyntax
]
, bgroup "isPatternWhitespace"
[ benchNF "unicode-data" I.isPatternWhitespace
]
]
, bgroup "Unicode.Char.Normalization"
[ bgroup "isCombining"
[ benchNF "unicode-data" N.isCombining
]
, bgroup "combiningClass"
[ benchNF "unicode-data" N.combiningClass
]
, bgroup "isCombiningStarter"
[ benchNF "unicode-data" N.isCombiningStarter
]
-- [TODO] compose, composeStarters
, bgroup "isDecomposable"
[ bgroup "Canonical"
[ benchNF "unicode-data" (N.isDecomposable N.Canonical)
]
, bgroup "Kompat"
[ benchNF "unicode-data" (N.isDecomposable N.Kompat)
]
]
-- [FIXME] Fail due to non-exhaustive pattern matching
-- , bgroup "decompose"
-- [ bgroup "Canonical"
-- [ benchNF "unicode-data" (N.decompose N.Canonical)
-- ]
-- , bgroup "Kompat"
-- [ benchNF "unicode-data" (N.decompose N.Kompat)
-- ]
-- ]
, bgroup "decomposeHangul"
[ benchNF "unicode-data" N.decomposeHangul
]
]
, bgroup "Unicode.Char.Numeric"
[ bgroup' "isNumber"
[ Bench "base" B.isNumber
, Bench "unicode-data" Num.isNumber
]
]
]
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
"base" -> benchNF title
_ -> bcompare ("$NF == \"base\" && $(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