-- | -- Copyright : (c) 2020 Peter Duchovni -- License : BSD3-style (see LICENSE) -- -- Maintainer : Peter Duchovni -- -- Benchmark elemIndex, findIndex, elemIndices, and findIndices module BenchIndices (benchIndices) where import Data.Foldable (foldMap) import Data.Maybe (listToMaybe) import Data.Monoid import Data.String import Test.Tasty.Bench import Prelude hiding (words, head, tail) import Data.Word (Word8) import qualified Data.ByteString as S import qualified Data.ByteString.Unsafe as S ------------------------------------------------------------------------------ -- Benchmark ------------------------------------------------------------------------------ -- ASCII \n to ensure no typos nl :: Word8 nl = 0xa {-# INLINE nl #-} -- non-inlined equality test nilEq :: Word8 -> Word8 -> Bool {-# NOINLINE nilEq #-} nilEq = (==) -- lines of 200 letters from a to e, followed by repeated letter f absurdlong :: S.ByteString absurdlong = (S.replicate 200 0x61 <> S.singleton nl <> S.replicate 200 0x62 <> S.singleton nl <> S.replicate 200 0x63 <> S.singleton nl <> S.replicate 200 0x64 <> S.singleton nl <> S.replicate 200 0x65 <> S.singleton nl) <> S.replicate 999999 0x66 benchIndices :: Benchmark benchIndices = absurdlong `seq` bgroup "Indices" [ bgroup "ByteString strict first index" $ [ bench "FindIndices" $ nf (listToMaybe . S.findIndices (== nl)) absurdlong , bench "ElemIndices" $ nf (listToMaybe . S.elemIndices nl) absurdlong , bench "FindIndex" $ nf (S.findIndex (== nl)) absurdlong , bench "ElemIndex" $ nf (S.elemIndex nl) absurdlong ] , bgroup "ByteString strict second index" $ [ bench "FindIndices" $ nf (listToMaybe . drop 1 . S.findIndices (== nl)) absurdlong , bench "ElemIndices" $ nf (listToMaybe . drop 1 . S.elemIndices nl) absurdlong , bench "FindIndex" $ nf bench_find_index_second absurdlong , bench "ElemIndex" $ nf bench_elem_index_second absurdlong ] , bgroup "ByteString index equality inlining" $ [ bench "FindIndices/inlined" $ nf (S.findIndices (== nl)) absurdlong , bench "FindIndices/non-inlined" $ nf (S.findIndices (nilEq nl)) absurdlong , bench "FindIndex/inlined" $ nf (S.findIndex (== nl)) absurdlong , bench "FindIndex/non-inlined" $ nf (S.findIndex (nilEq nl)) absurdlong ] ] bench_find_index_second :: S.ByteString -> Maybe Int bench_find_index_second bs = let isNl = (== nl) in case S.findIndex isNl bs of Just !i -> S.findIndex isNl (S.unsafeDrop (i+1) bs) Nothing -> Nothing {-# INLINE bench_find_index_second #-} bench_elem_index_second :: S.ByteString -> Maybe Int bench_elem_index_second bs = case S.elemIndex nl bs of Just !i -> S.elemIndex nl (S.unsafeDrop (i+1) bs) Nothing -> Nothing {-# INLINE bench_elem_index_second #-}