git.iko.soy/typeable/attoparsec
on master help sign in
Merge from 0.11 branch
commitd7a77f68ecab9e0a71bb20429b18f05a287d864b authorBryan O'Sullivan <bos@serpentine.com> dateSun 11 May 2014, 14:55 (12 years ago) parentaa65cc30f98896
4 files changed+69−2
attoparsec.cabal+1 benchmarks/Benchmarks.hs+4−2 benchmarks/Links.hs+63 benchmarks/attoparsec-benchmarks.cabal+1
attoparsec.cabal+1
@@ -103,6 +103,7 @@ benchmark benchmarks
103103 Common
104104 HeadersByteString
105105 HeadersText
106+ Links
106107 Numbers
107108 ghc-options: -O2 -Wall
108109
benchmarks/Benchmarks.hs+4−2
@@ -8,8 +8,6 @@ import Data.Word (Word32)
88import Data.Word (Word8)
99import Numbers (numbers)
1010import Common (chunksOf)
11−import qualified HeadersByteString
12−import qualified HeadersText
1311import Text.Parsec.Text ()
1412import Text.Parsec.Text.Lazy ()
1513import qualified Data.Attoparsec.ByteString as AB
@@ -22,6 +20,9 @@ import qualified Data.ByteString.Char8 as BC
2220import qualified Data.ByteString.Lazy as BL
2321import qualified Data.Text as T
2422import qualified Data.Text.Lazy as TL
23+import qualified HeadersByteString
24+import qualified HeadersText
25+import qualified Links
2526import qualified Text.Parsec as P
2627
2728main :: IO ()
@@ -72,6 +73,7 @@ main = do
7273 ]
7374 , headersBS
7475 , headersT
76+ , Links.links
7577 , numbers
7678 ]
7779
benchmarks/Links.hsnew file+63
@@ -0,0 +1,63 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+
3+module Links (links) where
4+
5+import Control.Applicative
6+import Control.DeepSeq (NFData(..))
7+import Criterion.Main (Benchmark, bench, nf)
8+import Data.Attoparsec as A
9+import Data.Attoparsec.Char8 as A8
10+import Data.ByteString.Char8 as B8
11+
12+data Link = Link {
13+ linkURL :: ByteString
14+ , linkParams :: [(ByteString, ByteString)]
15+ } deriving (Eq, Show)
16+
17+instance NFData Link where
18+ rnf l = rnf (linkURL l) `seq` rnf (linkParams l)
19+
20+link :: Parser Link
21+link = Link <$> url <*> many (char8 ';' *> skipSpace *> param)
22+ where url = char8 '<' *> A8.takeTill (=='>') <* char8 '>' <* skipSpace
23+
24+param :: Parser (ByteString, ByteString)
25+param = do
26+ name <- paramName
27+ skipSpace *> "=" *> skipSpace
28+ c <- peekChar'
29+ let isTokenChar = A.inClass "!#$%&'()*+./0-9:<=>?@a-zA-Z[]^_`{|}~-"
30+ val <- case c of
31+ '"' -> quotedString
32+ _ -> A.takeWhile isTokenChar
33+ skipSpace
34+ return (name, val)
35+
36+data Quot = Literal | Backslash
37+
38+quotedString :: Parser ByteString
39+quotedString = char '"' *> (fixup <$> body) <* char '"'
40+ where body = A8.scan Literal $ \s c ->
41+ case (s,c) of
42+ (Literal, '\\') -> backslash
43+ (Literal, '"') -> Nothing
44+ _ -> literal
45+ literal = Just Literal
46+ backslash = Just Backslash
47+ fixup = B8.pack . go . B8.unpack
48+ where go ('\\' : x@'\\' : xs) = x : go xs
49+ go ('\\' : x@'"' : xs) = x : go xs
50+ go (x : xs) = x : go xs
51+ go xs = xs
52+
53+paramName :: Parser ByteString
54+paramName = do
55+ name <- A.takeWhile1 $ A.inClass "a-zA-Z0-9!#$&+-.^_`|~"
56+ c <- peekChar
57+ return $ case c of
58+ Just '*' -> B8.snoc name '*'
59+ _ -> name
60+
61+links :: Benchmark
62+links = bench "links" $ nf (A.parseOnly link) lnk
63+ where lnk = "<https://api.github.com/search/code?q=addClass+user%3Amozilla&page=2>; rel=\"next\", <https://api.github.com/search/code?q=addClass+user%3Amozilla&page=34>; rel=\"last\""
benchmarks/attoparsec-benchmarks.cabal+1
@@ -12,6 +12,7 @@ executable attoparsec-benchmarks
1212 Common
1313 HeadersByteString
1414 HeadersText
15+ Links
1516 Numbers
1617 hs-source-dirs: .. .
1718 ghc-options: -O2 -Wall