git.iko.soy/typeable/attoparsec
on ae63be5 help sign in
.travis.yml+79−149
since splitsnapshots
unifiedsplit
@@ -1,161 +1,91 @@
1−# This Travis job script has been generated by a script via
1+# This file has been generated -- see https://github.com/hvr/multi-ghc-travis
2−#
3−# haskell-ci '--tests-jobs=>=7.4' '--no-benchmarks' 'attoparsec.cabal'
4−#
5−# For more information, see https://github.com/haskell-CI/haskell-ci
6−#
7−# version: 0.3.20190815
8−#
9language: c
2language: c
10−dist: xenial
3+sudo: false
11−git:
4+
12− # whether to recursively clone submodules
5+# Bryan threatens to turn off Travis-CI if he gets any email :-)
6+notifications:
13− submodules: false
7+ email: false
8+
14cache:
9cache:
15 directories:
10 directories:
11+ - $HOME/.cabsnap
16 - $HOME/.cabal/packages
12 - $HOME/.cabal/packages
17− - $HOME/.cabal/store
13+
18before_cache:
14before_cache:
19− - rm -fv $CABALHOME/packages/hackage.haskell.org/build-reports.log
15+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
20− # remove files that are regenerated by 'cabal update'
21− - rm -fv $CABALHOME/packages/hackage.haskell.org/00-index.*
16+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.tar
22− - rm -fv $CABALHOME/packages/hackage.haskell.org/*.json
17+
23− - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.cache
24− - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar
25− - rm -fv $CABALHOME/packages/hackage.haskell.org/01-index.tar.idx
26− - rm -rfv $CABALHOME/packages/head.hackage
27matrix:
18matrix:
28 include:
19 include:
29− - compiler: ghc-8.8.1
20+ - env: CABALVER=1.16 GHCVER=7.4.2
30− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.8.1","cabal-install-3.0"]}}
21+ compiler: ": #GHC 7.4.2"
31− - compiler: ghc-8.6.5
32− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.6.5","cabal-install-2.4"]}}
33− - compiler: ghc-8.4.4
34− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.4.4","cabal-install-2.4"]}}
22+ addons: {apt: {packages: [cabal-install-1.16,ghc-7.4.2], sources: [hvr-ghc]}}
35− - compiler: ghc-8.2.2
23+ - env: CABALVER=1.16 GHCVER=7.6.3
36− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.2.2","cabal-install-2.4"]}}
24+ compiler: ": #GHC 7.6.3"
37− - compiler: ghc-8.0.2
38− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-8.0.2","cabal-install-2.4"]}}
39− - compiler: ghc-7.10.3
40− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-7.10.3","cabal-install-2.4"]}}
41− - compiler: ghc-7.8.4
42− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-7.8.4","cabal-install-2.4"]}}
25+ addons: {apt: {packages: [cabal-install-1.16,ghc-7.6.3], sources: [hvr-ghc]}}
43− - compiler: ghc-7.6.3
26+ - env: CABALVER=1.18 GHCVER=7.8.4
44− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-7.6.3","cabal-install-2.4"]}}
45− - compiler: ghc-7.4.2
27+ compiler: ": #GHC 7.8.4"
46− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-7.4.2","cabal-install-2.4"]}}
28+ addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4], sources: [hvr-ghc]}}
29+ - env: CABALVER=1.22 GHCVER=7.10.3
47− - compiler: ghc-7.2.2
30+ compiler: ": #GHC 7.10.3"
48− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-7.2.2","cabal-install-2.4"]}}
31+ addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3], sources: [hvr-ghc]}}
32+ - env: CABALVER=1.24 GHCVER=8.0.1
49− - compiler: ghc-7.0.4
33+ compiler: ": #GHC 8.0.1"
50− addons: {"apt":{"sources":["hvr-ghc"],"packages":["ghc-7.0.4","cabal-install-2.4"]}}
34+ addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.1], sources: [hvr-ghc]}}
35+
51before_install:
36before_install:
52− - HC=$(echo "/opt/$CC/bin/ghc" | sed 's/-/\//')
53− - WITHCOMPILER="-w $HC"
54− - HCPKG="$HC-pkg"
55− - unset CC
37+ - unset CC
56− - CABAL=/opt/ghc/bin/cabal
38+ - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
57− - CABALHOME=$HOME/.cabal
39+
58− - export PATH="$CABALHOME/bin:$PATH"
59− - TOP=$(pwd)
60− - "HCNUMVER=$(${HC} --numeric-version|perl -ne '/^(\\d+)\\.(\\d+)\\.(\\d+)(\\.(\\d+))?$/; print(10000 * $1 + 100 * $2 + ($3 == 0 ? $5 != 1 : $3))')"
61− - echo $HCNUMVER
62− - CABAL="$CABAL -vnormal+nowrap+markoutput"
63− - set -o pipefail
64− - |
65− echo 'function blue(s) { printf "\033[0;34m" s "\033[0m " }' >> .colorful.awk
66− echo 'BEGIN { state = "output"; }' >> .colorful.awk
67− echo '/^-----BEGIN CABAL OUTPUT-----$/ { state = "cabal" }' >> .colorful.awk
68− echo '/^-----END CABAL OUTPUT-----$/ { state = "output" }' >> .colorful.awk
69− echo '!/^(-----BEGIN CABAL OUTPUT-----|-----END CABAL OUTPUT-----)/ {' >> .colorful.awk
70− echo ' if (state == "cabal") {' >> .colorful.awk
71− echo ' print blue($0)' >> .colorful.awk
72− echo ' } else {' >> .colorful.awk
73− echo ' print $0' >> .colorful.awk
74− echo ' }' >> .colorful.awk
75− echo '}' >> .colorful.awk
76− - cat .colorful.awk
77− - |
78− color_cabal_output () {
79− awk -f $TOP/.colorful.awk
80− }
81− - echo text | color_cabal_output
82install:
40install:
83− - ${CABAL} --version
41+ - cabal --version
84− - echo "$(${HC} --version) [$(${HC} --print-project-git-commit-id 2> /dev/null || echo '?')]"
42+ - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"
85− - TEST=--enable-tests
43+ - if [ -f $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz ];
86− - if [ $HCNUMVER -lt 70400 ] ; then TEST=--disable-tests ; fi
44+ then
87− - BENCH=--enable-benchmarks
45+ zcat $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz >
88− - BENCH=--disable-benchmarks
46+ $HOME/.cabal/packages/hackage.haskell.org/00-index.tar;
89− - HEADHACKAGE=false
47+ fi
90− - rm -f $CABALHOME/config
91− - |
92− echo "verbose: normal +nowrap +markoutput" >> $CABALHOME/config
93− echo "remote-build-reporting: anonymous" >> $CABALHOME/config
94− echo "write-ghc-environment-files: always" >> $CABALHOME/config
95− echo "remote-repo-cache: $CABALHOME/packages" >> $CABALHOME/config
96− echo "logs-dir: $CABALHOME/logs" >> $CABALHOME/config
97− echo "world-file: $CABALHOME/world" >> $CABALHOME/config
98− echo "extra-prog-path: $CABALHOME/bin" >> $CABALHOME/config
99− echo "symlink-bindir: $CABALHOME/bin" >> $CABALHOME/config
100− echo "installdir: $CABALHOME/bin" >> $CABALHOME/config
101− echo "build-summary: $CABALHOME/logs/build.log" >> $CABALHOME/config
102− echo "store-dir: $CABALHOME/store" >> $CABALHOME/config
103− echo "install-dirs user" >> $CABALHOME/config
104− echo " prefix: $CABALHOME" >> $CABALHOME/config
105− echo "repository hackage.haskell.org" >> $CABALHOME/config
106− echo " url: http://hackage.haskell.org/" >> $CABALHOME/config
107− - cat $CABALHOME/config
108− - rm -fv cabal.project cabal.project.local cabal.project.freeze
109− - travis_retry ${CABAL} v2-update -v
48+ - travis_retry cabal update -v
110− # Generate cabal.project
49+ - sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config
111− - rm -rf cabal.project cabal.project.local cabal.project.freeze
50+ - cabal install --only-dependencies --enable-tests --dry -v > installplan.txt
112− - touch cabal.project
51+ - sed -i -e '1,/^Resolving /d' installplan.txt; cat installplan.txt
113− - |
52+
114− echo "packages: ." >> cabal.project
53+# check whether current requested install-plan matches cached package-db snapshot
115− - |
54+ - if diff -u installplan.txt $HOME/.cabsnap/installplan.txt;
116− - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(attoparsec)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
55+ then
117− - cat cabal.project || true
56+ echo "cabal build-cache HIT";
118− - cat cabal.project.local || true
57+ rm -rfv .ghc;
119− - if [ -f "./configure.ac" ]; then (cd "." && autoreconf -i); fi
58+ cp -a $HOME/.cabsnap/ghc $HOME/.ghc;
120− - ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH} | color_cabal_output
59+ cp -a $HOME/.cabsnap/lib $HOME/.cabsnap/share $HOME/.cabsnap/bin $HOME/.cabal/;
121− - "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
60+ else
122− - rm cabal.project.freeze
61+ echo "cabal build-cache MISS";
123− - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} --dep -j2 all | color_cabal_output
62+ rm -rf $HOME/.cabsnap;
124− - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks --dep -j2 all | color_cabal_output
63+ mkdir -p $HOME/.ghc $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin;
64+ cabal install --only-dependencies --enable-tests;
65+ fi
66+
67+# snapshot package-db on cache miss
68+ - if [ ! -d $HOME/.cabsnap ];
69+ then
70+ echo "snapshotting package-db to build-cache";
71+ mkdir $HOME/.cabsnap;
72+ cp -a $HOME/.ghc $HOME/.cabsnap/ghc;
73+ cp -a $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin installplan.txt $HOME/.cabsnap/;
74+ fi
75+
76+# Here starts the actual work to be performed for the package under test;
77+# any command which exits with a non-zero exit code causes the build to fail.
125script:
78script:
126− - DISTDIR=$(mktemp -d /tmp/dist-test.XXXX)
79+ - if [ -f configure.ac ]; then autoreconf -i; fi
127− # Packaging...
80+ - cabal configure --enable-tests -v2 # -v2 provides useful information for debugging
128− - ${CABAL} v2-sdist all | color_cabal_output
129− # Unpacking...
130− - mv dist-newstyle/sdist/*.tar.gz ${DISTDIR}/
131− - cd ${DISTDIR} || false
132− - find . -maxdepth 1 -type f -name '*.tar.gz' -exec tar -xvf '{}' \;
133− - find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm '{}' \;
134− - PKGDIR_attoparsec="$(find . -maxdepth 1 -type d -regex '.*/attoparsec-[0-9.]*')"
135− # Generate cabal.project
136− - rm -rf cabal.project cabal.project.local cabal.project.freeze
137− - touch cabal.project
138− - |
139− echo "packages: ${PKGDIR_attoparsec}" >> cabal.project
140− - |
141− - "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(attoparsec)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
142− - cat cabal.project || true
143− - cat cabal.project.local || true
144− # Building...
145− # this builds all libraries and executables (without tests/benchmarks)
81+ - cabal build # this builds all libraries and executables (including tests)
146− - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all | color_cabal_output
82+ - cabal test
147− # Building with tests and benchmarks...
83+ - cabal sdist # tests that a source-distribution can be generated
148− # build & run tests, build benchmarks
84+
149− - ${CABAL} v2-build $WITHCOMPILER ${TEST} ${BENCH} all | color_cabal_output
85+# Check that the resulting source distribution can be built & installed.
150− # Testing...
86+# If there are no other `.tar.gz` files in `dist`, this can be even simpler:
151− - if [ $HCNUMVER -ge 70400 ] ; then ${CABAL} v2-test $WITHCOMPILER ${TEST} ${BENCH} all | color_cabal_output ; fi
87+# `cabal install --force-reinstalls dist/*-*.tar.gz`
152− # cabal check...
88+ - SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz &&
153− - (cd ${PKGDIR_attoparsec} && ${CABAL} -vnormal check)
89+ (cd dist && cabal install --force-reinstalls "$SRC_TGZ")
154− # haddock...
155− - ${CABAL} v2-haddock $WITHCOMPILER ${TEST} ${BENCH} all | color_cabal_output
156− # Building without installed constraints for packages in global-db...
157− - rm -f cabal.project.local
158− - ${CABAL} v2-build $WITHCOMPILER --disable-tests --disable-benchmarks all | color_cabal_output
159
90
160−# REGENDATA ["--tests-jobs=>=7.4","--no-benchmarks","attoparsec.cabal"]
161# EOF
91# EOF
Data/Attoparsec/Internal/Types.hs+4−7
@@ -1,4 +1,4 @@
1−{-# LANGUAGE CPP, BangPatterns, GeneralizedNewtypeDeriving, OverloadedStrings,
1+{-# LANGUAGE BangPatterns, GeneralizedNewtypeDeriving, OverloadedStrings,
2 Rank2Types, RecordWildCards, TypeFamilies #-}
2 Rank2Types, RecordWildCards, TypeFamilies #-}
3-- |
3-- |
4-- Module : Data.Attoparsec.Internal.Types
4-- Module : Data.Attoparsec.Internal.Types
@@ -39,7 +39,7 @@ import Data.ByteString.Internal (w2c)
39import Data.Text (Text)
39import Data.Text (Text)
40import qualified Data.Text as Text
40import qualified Data.Text as Text
41import Data.Text.Unsafe (Iter(..))
41import Data.Text.Unsafe (Iter(..))
42−import Prelude hiding (succ)
42+import Prelude hiding (getChar, succ)
43import qualified Data.Attoparsec.ByteString.Buffer as B
43import qualified Data.Attoparsec.ByteString.Buffer as B
44import qualified Data.Attoparsec.Text.Buffer as T
44import qualified Data.Attoparsec.Text.Buffer as T
45
45
@@ -136,10 +136,8 @@ instance Mon.Monoid More where
136 mempty = Incomplete
136 mempty = Incomplete
137
137
138instance Monad (Parser i) where
138instance Monad (Parser i) where
139−#if !(MIN_VERSION_base(4,13,0))
140 fail = Fail.fail
139 fail = Fail.fail
141 {-# INLINE fail #-}
140 {-# INLINE fail #-}
142−#endif
143
141
144 return = App.pure
142 return = App.pure
145 {-# INLINE return #-}
143 {-# INLINE return #-}
@@ -209,9 +207,8 @@ instance Alternative (Parser i) where
209 {-# INLINE (<|>) #-}
207 {-# INLINE (<|>) #-}
210
208
211 many v = many_v
209 many v = many_v
212− where
213− many_v = some_v <|> pure []
210+ where many_v = some_v <|> pure []
214− some_v = (:) <$> v <*> many_v
211+ some_v = (:) App.<$> v <*> many_v
215 {-# INLINE many #-}
212 {-# INLINE many #-}
216
213
217 some v = some_v
214 some v = some_v
Data/Attoparsec/Text/Internal.hs+5−2
@@ -1,4 +1,4 @@
1−{-# LANGUAGE BangPatterns, FlexibleInstances, GADTs, OverloadedStrings,
1+{-# LANGUAGE BangPatterns, CPP, FlexibleInstances, GADTs, OverloadedStrings,
2 Rank2Types, RecordWildCards, TypeFamilies, TypeSynonymInstances #-}
2 Rank2Types, RecordWildCards, TypeFamilies, TypeSynonymInstances #-}
3{-# OPTIONS_GHC -fno-warn-orphans #-}
3{-# OPTIONS_GHC -fno-warn-orphans #-}
4-- |
4-- |
@@ -65,7 +65,10 @@ module Data.Attoparsec.Text.Internal
65 , atEnd
65 , atEnd
66 ) where
66 ) where
67
67
68+#if !MIN_VERSION_base(4,8,0)
68−import Control.Applicative ((<|>), (<$>), pure, (*>))
69+import Control.Applicative ((<$>))
70+#endif
71+import Control.Applicative ((<|>))
69import Control.Monad (when)
72import Control.Monad (when)
70import Data.Attoparsec.Combinator ((<?>))
73import Data.Attoparsec.Combinator ((<?>))
71import Data.Attoparsec.Internal
74import Data.Attoparsec.Internal
Data/Attoparsec/Zepto.hs−2
@@ -92,10 +92,8 @@ instance Monad m => Monad (ZeptoT m) where
92 Fail err -> return (Fail err)
92 Fail err -> return (Fail err)
93 {-# INLINE (>>=) #-}
93 {-# INLINE (>>=) #-}
94
94
95−#if !(MIN_VERSION_base(4,13,0))
96 fail = Fail.fail
95 fail = Fail.fail
97 {-# INLINE fail #-}
96 {-# INLINE fail #-}
98−#endif
99
97
100instance Monad m => Fail.MonadFail (ZeptoT m) where
98instance Monad m => Fail.MonadFail (ZeptoT m) where
101 fail msg = Parser $ \_ -> return (Fail msg)
99 fail msg = Parser $ \_ -> return (Fail msg)
attoparsec.cabal+10−11
@@ -1,13 +1,12 @@
1name: attoparsec
1name: attoparsec
2−version: 0.13.2.2
2+version: 0.13.2.1
3−x-revision: 3
4license: BSD3
3license: BSD3
5license-file: LICENSE
4license-file: LICENSE
6category: Text, Parsing
5category: Text, Parsing
7author: Bryan O'Sullivan <bos@serpentine.com>
6author: Bryan O'Sullivan <bos@serpentine.com>
8maintainer: Bryan O'Sullivan <bos@serpentine.com>, Ben Gamari <ben@smart-cactus.org>
7maintainer: Bryan O'Sullivan <bos@serpentine.com>, Ben Gamari <ben@smart-cactus.org>
9stability: experimental
8stability: experimental
10−tested-with: GHC == 7.0.4, GHC == 7.2.2, GHC == 7.4.2, GHC ==7.6.3, GHC ==7.8.4, GHC ==7.10.3, GHC ==8.0.2, GHC ==8.2.2, GHC==8.4.4, GHC==8.6.5, GHC==8.8.1
9+tested-with: GHC == 7.0.1, GHC == 7.2.1, GHC == 7.4.2, GHC ==7.6.3, GHC ==7.8.4, GHC ==7.10.3
11synopsis: Fast combinator parsing for bytestrings and text
10synopsis: Fast combinator parsing for bytestrings and text
12cabal-version: >= 1.8
11cabal-version: >= 1.8
13homepage: https://github.com/bos/attoparsec
12homepage: https://github.com/bos/attoparsec
@@ -40,12 +39,12 @@ Flag developer
40
39
41library
40library
42 build-depends: array,
41 build-depends: array,
43− base >= 4.3 && < 5,
42+ base >= 4.2 && < 5,
44 bytestring,
43 bytestring,
45 containers,
44 containers,
46 deepseq,
45 deepseq,
47 scientific >= 0.3.1 && < 0.4,
46 scientific >= 0.3.1 && < 0.4,
48− transformers >= 0.2 && (< 0.4 || >= 0.4.1.0) && < 0.6,
47+ transformers,
49 text >= 1.1.1.3
48 text >= 1.1.1.3
50 if impl(ghc < 7.4)
49 if impl(ghc < 7.4)
51 build-depends:
50 build-depends:
@@ -54,7 +53,7 @@ library
54 if !impl(ghc >= 8.0)
53 if !impl(ghc >= 8.0)
55 -- Data.Semigroup && Control.Monad.Fail are available in base-4.9+
54 -- Data.Semigroup && Control.Monad.Fail are available in base-4.9+
56 build-depends: fail == 4.9.*,
55 build-depends: fail == 4.9.*,
57− semigroups >=0.16.1 && <0.20
56+ semigroups >=0.16.1 && <0.19
58
57
59 exposed-modules: Data.Attoparsec
58 exposed-modules: Data.Attoparsec
60 Data.Attoparsec.ByteString
59 Data.Attoparsec.ByteString
@@ -125,22 +124,22 @@ test-suite tests
125
124
126 build-depends:
125 build-depends:
127 array,
126 array,
128− base,
127+ base >= 4 && < 5,
129 bytestring,
128 bytestring,
130 deepseq >= 1.1,
129 deepseq >= 1.1,
131− QuickCheck >= 2.13.2 && < 2.14,
130+ QuickCheck >= 2.7 && < 2.10,
132 quickcheck-unicode,
131 quickcheck-unicode,
133 scientific,
132 scientific,
134 tasty >= 0.11,
133 tasty >= 0.11,
135 tasty-quickcheck >= 0.8,
134 tasty-quickcheck >= 0.8,
136 text,
135 text,
137− transformers >= 0.2 && (< 0.4 || >= 0.4.1.0) && < 0.6,
136+ transformers,
138 vector
137 vector
139
138
140 if !impl(ghc >= 8.0)
139 if !impl(ghc >= 8.0)
141 -- Data.Semigroup && Control.Monad.Fail are available in base-4.9+
140 -- Data.Semigroup && Control.Monad.Fail are available in base-4.9+
142 build-depends: fail == 4.9.*,
141 build-depends: fail == 4.9.*,
143− semigroups >=0.16.1 && <0.20
142+ semigroups >=0.16.1 && <0.19
144
143
145benchmark benchmarks
144benchmark benchmarks
146 type: exitcode-stdio-1.0
145 type: exitcode-stdio-1.0
@@ -179,7 +178,7 @@ benchmark benchmarks
179 parsec >= 3.1.2,
178 parsec >= 3.1.2,
180 scientific,
179 scientific,
181 text >= 1.1.1.0,
180 text >= 1.1.1.0,
182− transformers >= 0.2 && (< 0.4 || >= 0.4.1.0) && < 0.6,
181+ transformers,
183 unordered-containers,
182 unordered-containers,
184 vector
183 vector
185
184
benchmarks/HeadersByteString.hs+1−10
@@ -9,15 +9,6 @@ import qualified Data.Attoparsec.ByteString.Char8 as B
9import qualified Data.Attoparsec.ByteString.Lazy as BL
9import qualified Data.Attoparsec.ByteString.Lazy as BL
10import qualified Data.ByteString.Char8 as B
10import qualified Data.ByteString.Char8 as B
11
11
12−-- Note: In the benchmarks for parsing an http request
13−-- from a strict bytestring, we consider warp's implementation,
14−-- which has highly optimized code for handling the first
15−-- line in particular. It's treatment of the headers
16−-- is more relaxed from the treatment they are given by the
17−-- attoparsec parser benchmarked here. Consequently, it
18−-- is should not be possible to match its performance since
19−-- it accepts header names with disallowed characters.
20−
21headers :: IO Benchmark
12headers :: IO Benchmark
22headers = do
13headers = do
23 req <- B.readFile =<< pathTo "http-request.txt"
14 req <- B.readFile =<< pathTo "http-request.txt"
@@ -27,7 +18,7 @@ headers = do
27 return $ bgroup "headers" [
18 return $ bgroup "headers" [
28 bgroup "B" [
19 bgroup "B" [
29 bench "request" $ nf (B.parseOnly request) req
20 bench "request" $ nf (B.parseOnly request) req
30− , bench "warp" $ nfIO (parseHeaderLines (B.split '\n' req))
21+ , bench "warp" $ nfIO (parseHeaderLines [req])
31 , bench "response" $ nf (B.parseOnly response) resp
22 , bench "response" $ nf (B.parseOnly response) resp
32 ]
23 ]
33 , bgroup "BL" [
24 , bgroup "BL" [
benchmarks/HeadersByteString/Atto.hs+1−9
@@ -15,16 +15,8 @@ import qualified Data.ByteString.Char8 as B
15instance NFData HttpVersion where
15instance NFData HttpVersion where
16 rnf !_ = ()
16 rnf !_ = ()
17
17
18−isHeaderChar :: Char -> Bool
19−isHeaderChar c =
20− (c >= 'a' && c <= 'z') ||
21− (c >= 'A' && c <= 'Z') ||
22− (c >= '0' && c <= '9') ||
23− (c == '_') ||
24− (c == '-')
25−
26header = do
18header = do
27− name <- B.takeWhile1 isHeaderChar <* B.char ':' <* B.skipSpace
19+ name <- B.takeWhile1 (B.inClass "a-zA-Z0-9_-") <* B.char ':' <* B.skipSpace
28 body <- bodyLine
20 body <- bodyLine
29 return (name, body)
21 return (name, body)
30
22
benchmarks/http-request.txt+8−3
@@ -1,9 +1,14 @@
1GET / HTTP/1.1
1GET / HTTP/1.1
2Host: twitter.com
2Host: twitter.com
3−Accept: text/html, application/xhtml+xml, application/xml; q=0.9, image/webp, */*; q=0.8
3+Accept: text/html, application/xhtml+xml, application/xml; q=0.9,
4+ image/webp, */*; q=0.8
4Accept-Encoding: gzip,deflate,sdch
5Accept-Encoding: gzip,deflate,sdch
5Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
6Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
6Cache-Control: max-age=0
7Cache-Control: max-age=0
7−Cookie: guest_id=v1%3A139; _twitter_sess=BAh7CSIKZmxhc2hJQz-e1e1; __utma=43838368.452555194.1399611824.1; __utmb=43838368; __utmc=43838368; __utmz=1399611824.1.1.utmcsr=(direct)|utmcmd=(none)
8+Cookie: guest_id=v1%3A139; _twitter_sess=BAh7CSIKZmxhc2hJQz-e1e1;
9+ __utma=43838368.452555194.1399611824.1; __utmb=43838368;
10+ __utmc=43838368; __utmz=1399611824.1.1.utmcsr=(direct)|utmcmd=(none)
11+User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5)
8−User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.86 Safari/537.36
12+ AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.86
13+ Safari/537.36
9
14
benchmarks/http-response.txt+4−2
@@ -3,8 +3,10 @@ Date: Fri, 09 May 2014 04:24:57 GMT
3Expires: -1
3Expires: -1
4Cache-Control: private, max-age=0
4Cache-Control: private, max-age=0
5Content-Type: text/html; charset=ISO-8859-1
5Content-Type: text/html; charset=ISO-8859-1
6−Set-Cookie: PREF=ID=1a871afc4240db5e:FF:LM=1399609497:S=e5MZ0itEekjVwNcU; expires=Sun, 08-May-2016 04:24:57 GMT; path=/; domain=.google.com
6+Set-Cookie: PREF=ID=1a871afc4240db5e:FF:LM=1399609497:S=e5MZ0itEekjVwNcU;
7+ expires=Sun, 08-May-2016 04:24:57 GMT; path=/; domain=.google.com
7−Set-Cookie: NID=67=-WlfaDG6VSEPk7abAjrK98HBSoCD2ID6JKkUR95tEumzDmg7Fc8pSQ8; expires=Sat, 08-Nov-2014 04:24:57 GMT; path=/; domain=.google.com; HttpOnly
8+Set-Cookie: NID=67=-WlfaDG6VSEPk7abAjrK98HBSoCD2ID6JKkUR95tEumzDmg7Fc8pSQ8;
9+ expires=Sat, 08-Nov-2014 04:24:57 GMT; path=/; domain=.google.com; HttpOnly
8P3P: CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info."
10P3P: CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info."
9Server: gws
11Server: gws
10X-XSS-Protection: 1; mode=block
12X-XSS-Protection: 1; mode=block
tests/QC/ByteString.hs+2−4
@@ -26,11 +26,9 @@ import qualified Data.ByteString.Lazy.Char8 as L8
26satisfy :: Word8 -> L.ByteString -> Property
26satisfy :: Word8 -> L.ByteString -> Property
27satisfy w s = parseBS (P.satisfy (<=w)) (L.cons w s) === Just w
27satisfy w s = parseBS (P.satisfy (<=w)) (L.cons w s) === Just w
28
28
29−satisfyWith :: Word8 -> L.ByteString -> Property
29+satisfyWith :: Char -> L.ByteString -> Property
30−satisfyWith w s = parseBS (P.satisfyWith (chr . fromIntegral) (<=c))
30+satisfyWith c s = parseBS (P.satisfyWith (chr . fromIntegral) (<=c))
31 (L.cons (fromIntegral (ord c)) s) === Just c
31 (L.cons (fromIntegral (ord c)) s) === Just c
32− where
33− c = chr (fromIntegral w)
34
32
35word8 :: Word8 -> L.ByteString -> Property
33word8 :: Word8 -> L.ByteString -> Property
36word8 w s = parseBS (P.word8 w) (L.cons w s) === Just w
34word8 w s = parseBS (P.word8 w) (L.cons w s) === Just w
tests/QC/Text.hs+3−11
@@ -6,7 +6,6 @@ module QC.Text (tests) where
6import Control.Applicative ((<*>), (<$>))
6import Control.Applicative ((<*>), (<$>))
7#endif
7#endif
8import Data.Int (Int64)
8import Data.Int (Int64)
9−import Data.Word (Word8)
10import Prelude hiding (take, takeWhile)
9import Prelude hiding (take, takeWhile)
11import QC.Common (liftOp, parseT)
10import QC.Common (liftOp, parseT)
12import qualified QC.Text.FastSet as FastSet
11import qualified QC.Text.FastSet as FastSet
@@ -17,10 +16,8 @@ import Test.QuickCheck
17import qualified Data.Attoparsec.Text as P
16import qualified Data.Attoparsec.Text as P
18import qualified Data.Attoparsec.Text.Lazy as PL
17import qualified Data.Attoparsec.Text.Lazy as PL
19import qualified Data.Attoparsec.Text.FastSet as S
18import qualified Data.Attoparsec.Text.FastSet as S
20−import qualified Data.ByteString as BS
21import qualified Data.Char as Char
19import qualified Data.Char as Char
22import qualified Data.Text as T
20import qualified Data.Text as T
23−import qualified Data.Text.Encoding as TE
24import qualified Data.Text.Lazy as L
21import qualified Data.Text.Lazy as L
25
22
26-- Basic byte-level combinators.
23-- Basic byte-level combinators.
@@ -73,12 +70,9 @@ strings s t u =
73 === Just t'
70 === Just t'
74 where t' = toStrict t
71 where t' = toStrict t
75
72
76−-- | Note: "simple, and efficient" works for well formed input...
77−-- i.e. e.g. Latin1 texts
78−stringCI :: [Word8] -> Property
73+stringCI :: T.Text -> Property
79−stringCI ws = P.parseOnly (P.stringCI fs) s === Right s
74+stringCI s = P.parseOnly (P.stringCI fs) s === Right s
80 where fs = T.toCaseFold s
75 where fs = T.toCaseFold s
81− s = TE.decodeLatin1 (BS.pack ws)
82
76
83asciiCI :: T.Text -> Gen Bool
77asciiCI :: T.Text -> Gen Bool
84asciiCI x =
78asciiCI x =
@@ -156,9 +150,7 @@ endOfLine s =
156 (c, fst <$> L.uncons s') === ('\r', Just '\n')
150 (c, fst <$> L.uncons s') === ('\r', Just '\n')
157
151
158scan :: L.Text -> Positive Int64 -> Property
152scan :: L.Text -> Positive Int64 -> Property
159−-- for some reason, if counterexample is removed, this test fails?
160−scan s (Positive k) = counterexample (show s)
161− $ parseT p s === Just (toStrict $ L.take k s)
153+scan s (Positive k) = parseT p s === Just (toStrict $ L.take k s)
162 where p = P.scan k $ \ n _ ->
154 where p = P.scan k $ \ n _ ->
163 if n > 0 then let !n' = n - 1 in Just n' else Nothing
155 if n > 0 then let !n' = n - 1 in Just n' else Nothing
164
156