@@ -0,0 +1,67 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE MagicHash #-}
3+{-# LANGUAGE BangPatterns #-}
4+
5+-- Copyright : Erik de Castro Lopo <erikd@mega-nerd.com>
6+-- License : BSD3
7+
8+module Warp.ReadInt (
9+ readInt
10+ , readInt64
11+ ) where
12+
13+-- This function lives in its own file because the MagicHash pragma interacts
14+-- poorly with the CPP pragma.
15+
16+import Data.ByteString (ByteString)
17+import qualified Data.ByteString as S
18+import Data.Int (Int64)
19+import GHC.Prim
20+import GHC.Types
21+import GHC.Word
22+
23+{-# INLINE readInt #-}
24+readInt :: Integral a => ByteString -> a
25+readInt bs = fromIntegral $ readInt64 bs
26+
27+-- This function is used to parse the Content-Length field of HTTP headers and
28+-- is a performance hot spot. It should only be replaced with something
29+-- significantly and provably faster.
30+--
31+-- It needs to be able work correctly on 32 bit CPUs for file sizes > 2G so we
32+-- use Int64 here and then make a generic 'readInt' that allows conversion to
33+-- Int and Integer.
34+
35+{-# NOINLINE readInt64 #-}
36+readInt64 :: ByteString -> Int64
37+readInt64 bs = S.foldl' (\ !i !c -> i * 10 + fromIntegral (mhDigitToInt c)) 0
38+ $ S.takeWhile isDigit bs
39+
40+data Table = Table !Addr#
41+
42+{-# NOINLINE mhDigitToInt #-}
43+mhDigitToInt :: Word8 -> Int
44+mhDigitToInt (W8# i) = I# (word2Int# (indexWord8OffAddr# addr (word2Int# i)))
45+ where
46+ !(Table addr) = table
47+ table :: Table
48+ table = Table
49+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
50+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
51+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
52+ \\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\x00\x00\x00\x00\x00\
53+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
54+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
55+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
56+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
57+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
58+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
59+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
60+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
61+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
62+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
63+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
64+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"#
65+
66+isDigit :: Word8 -> Bool
67+isDigit w = w >= 48 && w <= 57