git.iko.soy/typeable/attoparsec
on 0.11.1.0 help sign in
164 lines 7.0 kB history raw
1{-# LANGUAGE BangPatterns, CPP #-}
3import Control.Applicative
4import Control.DeepSeq (NFData(rnf))
5import Criterion.Main (bench, bgroup, defaultMain, nf, whnf)
6import Data.Bits (unsafeShiftL)
7import Data.ByteString.Internal (ByteString(..))
8import Data.Char
9import Data.Scientific (Scientific(..))
10import Data.Word (Word32)
11import Text.Parsec.Text ()
12import Text.Parsec.Text.Lazy ()
13import qualified Data.Attoparsec.ByteString as AB
14import qualified Data.Attoparsec.ByteString.Char8 as AC
15import qualified Data.Attoparsec.ByteString.Lazy as ABL
16import qualified Data.Attoparsec.Text as AT
17import qualified Data.Attoparsec.Text.Lazy as ATL
18import qualified Data.ByteString as B
19import qualified Data.ByteString.Char8 as BC
20import qualified Data.ByteString.Lazy as BL
21import qualified Data.Text as T
22import qualified Data.Text.Lazy as TL
23import Data.Word (Word8)
24import qualified Text.Parsec as P
26#if !MIN_VERSION_bytestring(0,10,0)
27instance NFData ByteString where
28 rnf (PS _ _ _) = ()
29#endif
31instance NFData P.ParseError where
32 rnf = rnf . show
34chunksOf :: Int -> [a] -> [[a]]
35chunksOf k = go
36 where go xs = case splitAt k xs of
37 ([],_) -> []
38 (y, ys) -> y : go ys
40fromLazy :: BL.ByteString -> B.ByteString
41fromLazy = B.concat . BL.toChunks
43main = do
44 let s = take 1024 . cycle $ ['a'..'z'] ++ ['A'..'Z']
45 !b = BC.pack s
46 !bl = BL.fromChunks . map BC.pack . chunksOf 4 $ s
47 !t = T.pack s
48 !tl = TL.fromChunks . map T.pack . chunksOf 4 $ s
49 defaultMain [
50 bgroup "many" [
51 bgroup "attoparsec" [
52 bench "B" $ nf (AB.parse (many (AC.satisfy AC.isAlpha_ascii))) b
53 , bench "BL" $ nf (ABL.parse (many (AC.satisfy AC.isAlpha_ascii))) bl
54 , bench "T" $ nf (AT.parse (many (AT.satisfy AC.isAlpha_ascii))) t
55 , bench "TL" $ nf (ATL.parse (many (AT.satisfy AC.isAlpha_ascii))) tl
56 ]
57 , bgroup "parsec" [
58 bench "S" $ nf (P.parse (many (P.satisfy AC.isAlpha_ascii)) "") s
59 , bench "B" $ nf (P.parse (many (P.satisfy AC.isAlpha_ascii)) "") b
60 , bench "BL" $ nf (P.parse (many (P.satisfy AC.isAlpha_ascii)) "") bl
61 , bench "T" $ nf (P.parse (many (P.satisfy AC.isAlpha_ascii)) "") t
62 , bench "TL" $ nf (P.parse (many (P.satisfy AC.isAlpha_ascii)) "") tl
63 ]
64 ]
65 , bgroup "comparison" [
66 bgroup "many-vs-takeWhile" [
67 bench "many" $ nf (AB.parse (many (AC.satisfy AC.isAlpha_ascii))) b
68 , bench "takeWhile" $ nf (AB.parse (AC.takeWhile AC.isAlpha_ascii)) b
69 ]
70 , bgroup "letter-vs-isAlpha" [
71 bench "letter" $ nf (AB.parse (many AC.letter_ascii)) b
72 , bench "isAlpha" $ nf (AB.parse (many (AC.satisfy AC.isAlpha_ascii))) b
73 ]
74 ]
75 , bgroup "takeWhile" [
76 bench "isAlpha" $ nf (ABL.parse (AC.takeWhile isAlpha)) bl
77 , bench "isAlpha_ascii" $ nf (ABL.parse (AC.takeWhile AC.isAlpha_ascii)) bl
78 , bench "isAlpha_iso8859_15" $ nf (ABL.parse (AC.takeWhile AC.isAlpha_iso8859_15)) bl
79 ]
80 , bench "word32LE" $ nf (AB.parse word32LE) b
81 , bgroup "scan" [
82 bench "short" $ nf (AB.parse quotedString) (BC.pack "abcdefghijk\"")
83 , bench "long" $ nf (AB.parse quotedString) b
84 ]
86 , let strN = "1234.56789"
87 strNePos = "1234.56789e3"
88 strNeNeg = "1234.56789e-3"
89 in
90 bgroup "numbers"
91 [ let !tN = T.pack strN
92 !tNePos = T.pack strNePos
93 !tNeNeg = T.pack strNeNeg
94 in bgroup "Text"
95 [
96 bgroup "no power"
97 [ bench "double" $ nf (AT.parseOnly AT.double) tN
98 , bench "number" $ nf (AT.parseOnly AT.number) tN
99 , bench "rational" $ nf (AT.parseOnly (AT.rational :: AT.Parser Rational)) tN
100 , bench "scientific" $ nf (AT.parseOnly (AT.rational :: AT.Parser Scientific)) tN
101 ]
102 , bgroup "positive power"
103 [ bench "double" $ nf (AT.parseOnly AT.double) tNePos
104 , bench "number" $ nf (AT.parseOnly AT.number) tNePos
105 , bench "rational" $ nf (AT.parseOnly (AT.rational :: AT.Parser Rational)) tNePos
106 , bench "scientific" $ nf (AT.parseOnly (AT.rational :: AT.Parser Scientific)) tNePos
107 ]
108 , bgroup "negative power"
109 [ bench "double" $ nf (AT.parseOnly AT.double) tNeNeg
110 , bench "number" $ nf (AT.parseOnly AT.number) tNeNeg
111 , bench "rational" $ nf (AT.parseOnly (AT.rational :: AT.Parser Rational)) tNeNeg
112 , bench "scientific" $ nf (AT.parseOnly (AT.rational :: AT.Parser Scientific)) tNeNeg
113 ]
114 ]
115 , let !bN = BC.pack strN
116 !bNePos = BC.pack strNePos
117 !bNeNeg = BC.pack strNeNeg
118 in bgroup "ByteString"
119 [ bgroup "no power"
120 [ bench "double" $ nf (AC.parseOnly AC.double) bN
121 , bench "number" $ nf (AC.parseOnly AC.number) bN
122 , bench "rational" $ nf (AC.parseOnly (AC.rational :: AC.Parser Rational)) bN
123 , bench "scientific" $ nf (AC.parseOnly (AC.rational :: AC.Parser Scientific)) bN
124 ]
125 , bgroup "positive power"
126 [ bench "double" $ nf (AC.parseOnly AC.double) bNePos
127 , bench "number" $ nf (AC.parseOnly AC.number) bNePos
128 , bench "rational" $ nf (AC.parseOnly (AC.rational :: AC.Parser Rational)) bNePos
129 , bench "scientific" $ nf (AC.parseOnly (AC.rational :: AC.Parser Scientific)) bNePos
130 ]
131 , bgroup "negative power"
132 [ bench "double" $ nf (AC.parseOnly AC.double) bNeNeg
133 , bench "number" $ nf (AC.parseOnly AC.number) bNeNeg
134 , bench "rational" $ nf (AC.parseOnly (AC.rational :: AC.Parser Rational)) bNeNeg
135 , bench "scientific" $ nf (AC.parseOnly (AC.rational :: AC.Parser Scientific)) bNeNeg
136 ]
137 ]
138 ]
139 ]
141-- Benchmarks bind and (potential) bounds-check merging.
142word32LE :: AB.Parser Word32
143word32LE = do
144 w1 <- AB.anyWord8
145 w2 <- AB.anyWord8
146 w3 <- AB.anyWord8
147 w4 <- AB.anyWord8
148 return $! (fromIntegral w1 :: Word32) +
149 fromIntegral w2 `unsafeShiftL` 8 +
150 fromIntegral w3 `unsafeShiftL` 16 +
151 fromIntegral w4 `unsafeShiftL` 32
153doubleQuote, backslash :: Word8
154doubleQuote = 34
155backslash = 92
156{-# INLINE backslash #-}
157{-# INLINE doubleQuote #-}
159-- | Parse a string without a leading quote.
160quotedString :: AB.Parser B.ByteString
161quotedString = AB.scan False $ \s c -> if s then Just False
162 else if c == doubleQuote
163 then Nothing
164 else Just (c == backslash)