@@ -1,4 +1,4 @@
1−{-# LANGUAGE OverloadedStrings #-}
1+{-# LANGUAGE OverloadedStrings, MagicHash, BangPatterns #-}
22
33-- Copyright : Erik de Castro Lopo <erikd@mega-nerd.com>
44-- License : BSD3
@@ -19,6 +19,8 @@ import qualified Data.Char as C
1919import qualified Numeric as N
2020import qualified Test.QuickCheck as QC
2121
22+import GHC.Prim
23+import GHC.Types
2224
2325-- This is the absolute mimimal solution. It will return garbage if the
2426-- imput string contains anything other than ASCI digits.
@@ -58,6 +60,42 @@ readInt64 = readIntTC
5860readInteger :: ByteString -> Integer
5961readInteger = readIntTC
6062
63+
64+-- MagicHash version suggested by Vincent Hanquez.
65+readIntMH :: ByteString -> Int64
66+readIntMH bs =
67+ B.foldl' (\i c -> i * 10 + fromIntegral (mhDigitToInt c)) 0
68+ $ B.takeWhile C.isDigit bs
69+
70+readIntegerMH :: ByteString -> Integer
71+readIntegerMH bs = fromIntegral $ readIntMH bs
72+
73+data Table = Table !Addr#
74+
75+mhDigitToInt :: Char -> Int
76+mhDigitToInt (C# i) = I# (word2Int# $ indexWord8OffAddr# addr (ord# i))
77+ where
78+ !(Table addr) = table
79+ table :: Table
80+ table = Table
81+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
82+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
83+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
84+ \\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\x00\x00\x00\x00\x00\
85+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
86+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
87+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
88+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
89+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
90+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
91+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
92+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
93+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
94+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
95+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
96+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"#
97+
98+
6199-- A QuickCheck property. Test that for a number >= 0, converting it to
62100-- a string using show and then reading the value back with the function
63101-- under test returns the original value.
@@ -75,17 +113,20 @@ runQuickCheckTests = do
75113 QC.quickCheck (prop_read_show_idempotent readInt)
76114 QC.quickCheck (prop_read_show_idempotent readInt64)
77115 QC.quickCheck (prop_read_show_idempotent readInteger)
78−
116+ QC.quickCheck (prop_read_show_idempotent readIntMH)
117+ QC.quickCheck (prop_read_show_idempotent readIntegerMH)
79118
80119runCriterionTests :: ByteString -> IO ()
81120runCriterionTests number =
82121 defaultMain
83− [ bench "readIntOrig" $ nf readIntOrig number
84− , bench "readDec" $ nf readDec number
85− , bench "readRaw" $ nf readIntRaw number
86− , bench "readInt" $ nf readInt number
87− , bench "readInt64" $ nf readInt64 number
88− , bench "readInteger" $ nf readInteger number
122+ [ bench "readIntOrig" $ nf readIntOrig number
123+ , bench "readDec" $ nf readDec number
124+ , bench "readRaw" $ nf readIntRaw number
125+ , bench "readInt" $ nf readInt number
126+ , bench "readInt64" $ nf readInt64 number
127+ , bench "readInteger" $ nf readInteger number
128+ , bench "readIntMH" $ nf readIntMH number
129+ , bench "readIntegerMH" $ nf readIntegerMH number
89130 ]
90131
91132