{-# OPTIONS_GHC -Wall -fwarn-tabs #-}
module Data.ByteString.Lex.Internal
(
numDigits
, numTwoPowerDigits
, numDecimalDigits
) where
import Data.Word (Word64)
import Data.Bits (Bits(shiftR))
numDigits :: Integer -> Integer -> Int
{-# INLINE numDigits #-}
numDigits :: Integer -> Integer -> Int
numDigits b0 :: Integer
b0 n0 :: Integer
n0
| Integer
b0 Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= 1 = [Char] -> Int
forall a. HasCallStack => [Char] -> a
error ([Char]
_numDigits [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
_nonpositiveBase)
| Integer
n0 Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< 0 = [Char] -> Int
forall a. HasCallStack => [Char] -> a
error ([Char]
_numDigits [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
_negativeNumber)
| Bool
otherwise = 1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (Int, Integer) -> Int
forall a b. (a, b) -> a
fst (Integer -> Integer -> (Int, Integer)
forall t a. (Integral t, Num a) => t -> t -> (a, t)
ilog Integer
b0 Integer
n0)
where
ilog :: t -> t -> (a, t)
ilog b :: t
b n :: t
n
| t
n t -> t -> Bool
forall a. Ord a => a -> a -> Bool
< t
b = (0, t
n)
| t
r t -> t -> Bool
forall a. Ord a => a -> a -> Bool
< t
b = ((,) (a -> t -> (a, t)) -> a -> t -> (a, t)
forall a b. (a -> b) -> a -> b
$! 2a -> a -> a
forall a. Num a => a -> a -> a
*a
e) t
r
| Bool
otherwise = ((,) (a -> t -> (a, t)) -> a -> t -> (a, t)
forall a b. (a -> b) -> a -> b
$! 2a -> a -> a
forall a. Num a => a -> a -> a
*a
ea -> a -> a
forall a. Num a => a -> a -> a
+1) (t -> (a, t)) -> t -> (a, t)
forall a b. (a -> b) -> a -> b
$! (t
r t -> t -> t
forall a. Integral a => a -> a -> a
`quot` t
b)
where
(e :: a
e, r :: t
r) = t -> t -> (a, t)
ilog (t
bt -> t -> t
forall a. Num a => a -> a -> a
*t
b) t
n
numTwoPowerDigits :: (Integral a, Bits a) => Int -> a -> Int
{-# INLINE numTwoPowerDigits #-}
numTwoPowerDigits :: Int -> a -> Int
numTwoPowerDigits p :: Int
p n0 :: a
n0
| Int
p Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= 0 = [Char] -> Int
forall a. HasCallStack => [Char] -> a
error ([Char]
_numTwoPowerDigits [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
_nonpositiveBase)
| a
n0 a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< 0 = [Char] -> Int
forall a. HasCallStack => [Char] -> a
error ([Char]
_numTwoPowerDigits [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
_negativeNumber)
| a
n0 a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== 0 = 1
| Bool
otherwise = Int -> a -> Int
forall t p. (Ord t, Num t, Num p, Bits t) => p -> t -> p
go 0 a
n0
where
go :: p -> t -> p
go d :: p
d n :: t
n
| p
d p -> Bool -> Bool
forall a b. a -> b -> b
`seq` t
n t -> Bool -> Bool
forall a b. a -> b -> b
`seq` Bool
False = p
forall a. HasCallStack => a
undefined
| t
n t -> t -> Bool
forall a. Ord a => a -> a -> Bool
> 0 = p -> t -> p
go (p
dp -> p -> p
forall a. Num a => a -> a -> a
+1) (t
n t -> Int -> t
forall a. Bits a => a -> Int -> a
`shiftR` Int
p)
| Bool
otherwise = p
d
numDecimalDigits :: (Integral a) => a -> Int
{-# INLINE numDecimalDigits #-}
numDecimalDigits :: a -> Int
numDecimalDigits n0 :: a
n0
| a
n0 a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< 0 = [Char] -> Int
forall a. HasCallStack => [Char] -> a
error ([Char]
_numDecimalDigits [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
_negativeNumber)
| a
n0 a -> a -> Bool
forall a. Ord a => a -> a -> Bool
> a
limit = Integer -> Integer -> Int
numDigits 10 (a -> Integer
forall a. Integral a => a -> Integer
toInteger a
n0)
| Bool
otherwise = Int -> Word64 -> Int
forall t t. (Num t, Integral t) => t -> t -> t
go 1 (a -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n0 :: Word64)
where
limit :: a
limit = Word64 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
forall a. Bounded a => a
maxBound :: Word64)
fin :: a -> a -> p
fin n :: a
n bound :: a
bound = if a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
bound then 1 else 0
go :: t -> t -> t
go k :: t
k n :: t
n
| t
k t -> Bool -> Bool
forall a b. a -> b -> b
`seq` Bool
False = t
forall a. HasCallStack => a
undefined
| t
n t -> t -> Bool
forall a. Ord a => a -> a -> Bool
< 10 = t
k
| t
n t -> t -> Bool
forall a. Ord a => a -> a -> Bool
< 100 = t
k t -> t -> t
forall a. Num a => a -> a -> a
+ 1
| t
n t -> t -> Bool
forall a. Ord a => a -> a -> Bool
< 1000 = t
k t -> t -> t
forall a. Num a => a -> a -> a
+ 2
| t
n t -> t -> Bool
forall a. Ord a => a -> a -> Bool
< 1000000000000 =
t
k t -> t -> t
forall a. Num a => a -> a -> a
+ if t
n t -> t -> Bool
forall a. Ord a => a -> a -> Bool
< 100000000
then if t
n t -> t -> Bool
forall a. Ord a => a -> a -> Bool
< 1000000
then if t
n t -> t -> Bool
forall a. Ord a => a -> a -> Bool
< 10000
then 3
else 4 t -> t -> t
forall a. Num a => a -> a -> a
+ t -> t -> t
forall a p. (Ord a, Num p) => a -> a -> p
fin t
n 100000
else 6 t -> t -> t
forall a. Num a => a -> a -> a
+ t -> t -> t
forall a p. (Ord a, Num p) => a -> a -> p
fin t
n 10000000
else if t
n t -> t -> Bool
forall a. Ord a => a -> a -> Bool
< 10000000000
then 8 t -> t -> t
forall a. Num a => a -> a -> a
+ t -> t -> t
forall a p. (Ord a, Num p) => a -> a -> p
fin t
n 1000000000
else 10 t -> t -> t
forall a. Num a => a -> a -> a
+ t -> t -> t
forall a p. (Ord a, Num p) => a -> a -> p
fin t
n 100000000000
| Bool
otherwise = t -> t -> t
go (t
k t -> t -> t
forall a. Num a => a -> a -> a
+ 12) (t
n t -> t -> t
forall a. Integral a => a -> a -> a
`quot` 1000000000000)
_numDigits :: String
_numDigits :: [Char]
_numDigits = "numDigits"
{-# NOINLINE _numDigits #-}
_numTwoPowerDigits :: String
_numTwoPowerDigits :: [Char]
_numTwoPowerDigits = "numTwoPowerDigits"
{-# NOINLINE _numTwoPowerDigits #-}
_numDecimalDigits :: String
_numDecimalDigits :: [Char]
_numDecimalDigits = "numDecimalDigits"
{-# NOINLINE _numDecimalDigits #-}
_nonpositiveBase :: String
_nonpositiveBase :: [Char]
_nonpositiveBase = ": base must be greater than one"
{-# NOINLINE _nonpositiveBase #-}
_negativeNumber :: String
_negativeNumber :: [Char]
_negativeNumber = ": number must be non-negative"
{-# NOINLINE _negativeNumber #-}