snoyberg/conduit — pull request #102 by rycee (2013-07-06 14:46:02+00:00)
Title: [attoparsec-conduit] Performance improvements for Text parsing and improved positions

When parsing Text (actually XML using xml-conduit) I noticed that performance could be improved quite a lot by not using `T.take (T.length c - T.length rest) c` to extract the parsed portion of the input. Instead I introduced a function `stripFromEnd` in the `AttoparsecInput` type class and in the Text instance I use the function Data.Text.Internal.textP to directly construct a Text object of the correct length. Note, to avoid using an internal function of text, it would be possible to use [stripSuffix](http://hackage.haskell.org/packages/archive/text/0.11.3.1/doc/html/Data-Text.html#v:stripSuffix) but this would also perform an unnecessary equality test.

Using criterion to benchmark the code
```Haskell
parse xmltext = runException $ sourceList [xmltext] $$ parseText def =$= sinkNull
```
for the old and new code using some [sample XML](http://msdn.microsoft.com/en-us/library/windows/desktop/ms762271%28v=vs.85%29.aspx) file gives
```
benchmarking stripFromEnd
mean: 850.4717 us, lb 848.7623 us, ub 852.4637 us, ci 0.950
std dev: 9.442585 us, lb 7.923838 us, ub 11.74095 us, ci 0.950

benchmarking take'
mean: 2.409476 ms, lb 2.405919 ms, ub 2.414118 ms, ci 0.950
std dev: 20.66605 us, lb 16.31335 us, ub 27.57879 us, ci 0.950
```
which I think is a decent performance improvement ([html report](http://tau.rycee.net/conduit-9ba171f-benchmark.html)).

The second change concerns the reporting of positions, I've added two new test cases and refined the conduit test case to also check for positions of the yielded values. Using the old line/column reporting, these three cases fail. In particular, the problem occurs when an error happens directly after a new line since `T.lines t` and `T.length $ last ls` will conspire to give the line width of the line *before* the error.