aeson-2.1.2.0: src/Data/Aeson/Internal/Integer.hs
module Data.Aeson.Internal.Integer (
bsToInteger,
bsToIntegerSimple
) where
import qualified Data.ByteString as B
import Data.Aeson.Internal.Word8
------------------ Copy-pasted and adapted from base ------------------------
bsToInteger :: B.ByteString -> Integer
bsToInteger bs
| l > 40 = valInteger 10 l [ fromIntegral (w - W8_0) | w <- B.unpack bs ]
| otherwise = bsToIntegerSimple bs
where
l = B.length bs
bsToIntegerSimple :: B.ByteString -> Integer
bsToIntegerSimple = B.foldl' step 0 where
step a b = a * 10 + fromIntegral (b - W8_0)
-- A sub-quadratic algorithm for Integer. Pairs of adjacent radix b
-- digits are combined into a single radix b^2 digit. This process is
-- repeated until we are left with a single digit. This algorithm
-- performs well only on large inputs, so we use the simple algorithm
-- for smaller inputs.
valInteger :: Integer -> Int -> [Integer] -> Integer
valInteger = go
where
go :: Integer -> Int -> [Integer] -> Integer
go _ _ [] = 0
go _ _ [d] = d
go b l ds
| l > 40 = b' `seq` go b' l' (combine b ds')
| otherwise = valSimple b ds
where
-- ensure that we have an even number of digits
-- before we call combine:
ds' = if even l then ds else 0 : ds
b' = b * b
l' = (l + 1) `quot` 2
combine b (d1 : d2 : ds) = d `seq` (d : combine b ds)
where
d = d1 * b + d2
combine _ [] = []
combine _ [_] = errorWithoutStackTrace "this should not happen"
-- The following algorithm is only linear for types whose Num operations
-- are in constant time.
valSimple :: Integer -> [Integer] -> Integer
valSimple base = go 0
where
go r [] = r
go r (d : ds) = r' `seq` go r' ds
where
r' = r * base + fromIntegral d