on master help sign in
warp : Replace readInt function with something faster and more correct.

The old version of the function would produce garbage values for strings containing non-digits. The new version will covert all digits available into a number and drop trailing rubbish. The new version is provably faster. Benchmarking program : test/readInt.hs.

commit2d6f9ed4626f459cb733c4aa8273fa7d54c0bf37 authorErik de Castro Lopo <erikd@mega-nerd.com> dateTue 24 Jan 2012, 12:10 (15 years ago) parent70e492d
1 file changed+7−5
warp/Network/Wai/Handler/Warp.hs+7−5
warp/Network/Wai/Handler/Warp.hs+7−5
@@ -315,7 +315,7 @@ parseRequest' port (firstLine:otherLines) remoteHost' src = do
315315 let len =
316316 case lookup "content-length" heads of
317317 Nothing -> 0
318− Just bs -> fromIntegral $ B.foldl' (\i c -> i * 10 + C.digitToInt c) 0 $ B.takeWhile C.isDigit bs
318+ Just bs -> readInt bs
319319 let serverName' = takeUntil 58 host -- ':'
320320 -- FIXME isolate takes an Integer instead of Int or Int64. If this is a
321321 -- performance penalty, we may need our own version.
@@ -649,10 +649,12 @@ checkCR bs pos =
649649 else pos
650650{-# INLINE checkCR #-}
651651
652−-- Note: This function produces garbage on invalid input. But serving an
653−-- invalid content-length is a bad idea, mkay?
654−readInt :: S.ByteString -> Integer
655−readInt = S.foldl' (\x w -> x * 10 + fromIntegral w - 48) 0
652+-- This function is used to parse the Content-Length field of HTTP headers and
653+-- is a performance hot spot. It should only be replaced with something
654+-- significantly and provably faster.
655+readInt :: Integral a => ByteString -> a
656+readInt bs = fromIntegral
657+ $ B.foldl' (\i c -> i * 10 + C.digitToInt c) 0 $ B.takeWhile C.isDigit bs
656658
657659-- | Call the inner function with a timeout manager.
658660withManager :: Int -- ^ timeout in microseconds