Switch to faster/more naive implementation of String to Int conversion

Why?
====

This library converts lots of strings to positive integers
(specifically, when it's parsing output from search results). Because
these are always positive integers, we can make more assumptions about
the data and how to parse the values.

Corresponding benchmark: https://gist.github.com/joshuaclayton/767c507edf09215d08cdd79c93a5f383
This commit is contained in:
Joshua Clayton 2016-05-17 23:15:27 -04:00
parent 4c8e8b2d72
commit 6c9912fa29
3 changed files with 19 additions and 6 deletions

View File

@ -7,10 +7,10 @@ module Unused.Parser.Internal
import Control.Monad (void)
import Data.Maybe (fromMaybe)
import Text.Read (readMaybe)
import Text.Parsec
import Text.Parsec.String (Parser)
import Unused.Types (TermMatch(..))
import Unused.Util (stringToInt)
parseTermMatches :: Parser [TermMatch]
parseTermMatches = many1 parseTermMatch <* eof
@ -37,10 +37,7 @@ pathParser = many1 (noneOf ":")
occurrenceParser :: Parser Int
occurrenceParser =
toInt <$> many1 digit
where
toInt = fromMaybe 0 . maybeInt
maybeInt s = readMaybe s :: Maybe Int
fromMaybe 0 . stringToInt <$> many1 digit
eol :: Parser String
eol = try (string "\n\r")

View File

@ -1,12 +1,21 @@
module Unused.Util
( groupBy
, stringToInt
) where
import Control.Arrow ((&&&))
import qualified Data.List as L
import Data.Function
import Data.Char (digitToInt, isDigit)
groupBy :: (Ord b) => (a -> b) -> [a] -> [(b, [a])]
groupBy f = map (f . head &&& id)
. L.groupBy ((==) `on` f)
. L.sortBy (compare `on` f)
stringToInt :: String -> Maybe Int
stringToInt xs
| all isDigit xs = Just $ loop 0 xs
| otherwise = Nothing
where
loop = foldl (\acc x -> acc * 10 + digitToInt x)

View File

@ -15,7 +15,7 @@ main :: IO ()
main = hspec spec
spec :: Spec
spec = parallel $
spec = parallel $ do
describe "groupBy" $ do
it "groups by the result of a function" $ do
let numbers = [1..10] :: [Int]
@ -27,3 +27,10 @@ spec = parallel $
groupBy pName people `shouldBe` [("Jane", [Person "Jane" 10, Person "Jane" 20]), ("John", [Person "John" 20])]
groupBy pAge people `shouldBe` [(10, [Person "Jane" 10]), (20, [Person "Jane" 20, Person "John" 20])]
describe "stringToInt" $
it "converts a String value to Maybe Int" $ do
stringToInt "12345678" `shouldBe` Just 12345678
stringToInt "0" `shouldBe` Just 0
stringToInt "10591" `shouldBe` Just 10591
stringToInt "bad" `shouldBe` Nothing