{-# LANGUAGE BangPatterns, CPP, MagicHash, UnboxedTuples #-}
module Data.Text.Format.Int
(
decimal
, hexadecimal
, minus
) where
import Data.Int (Int8, Int16, Int32, Int64)
import Data.Monoid (mempty)
import Data.Semigroup ((<>))
import Data.Text.Format.Functions (i2d)
import Data.Text.Lazy.Builder
import Data.Word (Word, Word8, Word16, Word32, Word64)
import GHC.Base (quotInt, remInt)
import GHC.Num (quotRemInteger)
import GHC.Types (Int(..))
#ifdef __GLASGOW_HASKELL__
# if __GLASGOW_HASKELL__ < 611
import GHC.Integer.Internals
# else
import GHC.Integer.GMP.Internals (Integer(..))
# endif
#endif
#ifdef INTEGER_GMP
# define PAIR(a,b) (# a,b #)
#else
# define PAIR(a,b) (a,b)
#endif
decimal :: Integral a => a -> Builder
{-# SPECIALIZE decimal :: Int -> Builder #-}
{-# SPECIALIZE decimal :: Int8 -> Builder #-}
{-# SPECIALIZE decimal :: Int16 -> Builder #-}
{-# SPECIALIZE decimal :: Int32 -> Builder #-}
{-# SPECIALIZE decimal :: Int64 -> Builder #-}
{-# SPECIALIZE decimal :: Word -> Builder #-}
{-# SPECIALIZE decimal :: Word8 -> Builder #-}
{-# SPECIALIZE decimal :: Word16 -> Builder #-}
{-# SPECIALIZE decimal :: Word32 -> Builder #-}
{-# SPECIALIZE decimal :: Word64 -> Builder #-}
{-# RULES "decimal/Integer" decimal = integer 10 :: Integer -> Builder #-}
decimal :: forall a. Integral a => a -> Builder
decimal a
i
| a
i forall a. Ord a => a -> a -> Bool
< a
0 = Builder
minus forall a. Semigroup a => a -> a -> a
<> forall a. Integral a => a -> Builder
go (-a
i)
| Bool
otherwise = forall a. Integral a => a -> Builder
go a
i
where
go :: a -> Builder
go a
n | a
n forall a. Ord a => a -> a -> Bool
< a
10 = forall a. Integral a => a -> Builder
digit a
n
| Bool
otherwise = a -> Builder
go (a
n forall a. Integral a => a -> a -> a
`quot` a
10) forall a. Semigroup a => a -> a -> a
<> forall a. Integral a => a -> Builder
digit (a
n forall a. Integral a => a -> a -> a
`rem` a
10)
{-# NOINLINE[0] decimal #-}
hexadecimal :: Integral a => a -> Builder
{-# SPECIALIZE hexadecimal :: Int -> Builder #-}
{-# SPECIALIZE hexadecimal :: Int8 -> Builder #-}
{-# SPECIALIZE hexadecimal :: Int16 -> Builder #-}
{-# SPECIALIZE hexadecimal :: Int32 -> Builder #-}
{-# SPECIALIZE hexadecimal :: Int64 -> Builder #-}
{-# SPECIALIZE hexadecimal :: Word -> Builder #-}
{-# SPECIALIZE hexadecimal :: Word8 -> Builder #-}
{-# SPECIALIZE hexadecimal :: Word16 -> Builder #-}
{-# SPECIALIZE hexadecimal :: Word32 -> Builder #-}
{-# SPECIALIZE hexadecimal :: Word64 -> Builder #-}
{-# RULES "hexadecimal/Integer" hexadecimal = integer 16 :: Integer -> Builder #-}
hexadecimal :: forall a. Integral a => a -> Builder
hexadecimal a
i
| a
i forall a. Ord a => a -> a -> Bool
< a
0 = Builder
minus forall a. Semigroup a => a -> a -> a
<> forall a. Integral a => a -> Builder
go (-a
i)
| Bool
otherwise = forall a. Integral a => a -> Builder
go a
i
where
go :: a -> Builder
go a
n | a
n forall a. Ord a => a -> a -> Bool
< a
16 = forall a. Integral a => a -> Builder
hexDigit a
n
| Bool
otherwise = a -> Builder
go (a
n forall a. Integral a => a -> a -> a
`quot` a
16) forall a. Semigroup a => a -> a -> a
<> forall a. Integral a => a -> Builder
hexDigit (a
n forall a. Integral a => a -> a -> a
`rem` a
16)
{-# NOINLINE[0] hexadecimal #-}
digit :: Integral a => a -> Builder
digit :: forall a. Integral a => a -> Builder
digit a
n = Char -> Builder
singleton forall a b. (a -> b) -> a -> b
$! Int -> Char
i2d (forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n)
{-# INLINE digit #-}
hexDigit :: Integral a => a -> Builder
hexDigit :: forall a. Integral a => a -> Builder
hexDigit a
n
| a
n forall a. Ord a => a -> a -> Bool
<= a
9 = Char -> Builder
singleton forall a b. (a -> b) -> a -> b
$! Int -> Char
i2d (forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n)
| Bool
otherwise = Char -> Builder
singleton forall a b. (a -> b) -> a -> b
$! forall a. Enum a => Int -> a
toEnum (forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n forall a. Num a => a -> a -> a
+ Int
87)
{-# INLINE hexDigit #-}
minus :: Builder
minus :: Builder
minus = Char -> Builder
singleton Char
'-'
int :: Int -> Builder
int :: Int -> Builder
int = forall a. Integral a => a -> Builder
decimal
{-# INLINE int #-}
data T = T !Integer !Int
integer :: Int -> Integer -> Builder
integer :: Int -> Integer -> Builder
integer Int
10 (S# Int#
i#) = forall a. Integral a => a -> Builder
decimal (Int# -> Int
I# Int#
i#)
integer Int
16 (S# Int#
i#) = forall a. Integral a => a -> Builder
hexadecimal (Int# -> Int
I# Int#
i#)
integer Int
base Integer
i
| Integer
i forall a. Ord a => a -> a -> Bool
< Integer
0 = Builder
minus forall a. Semigroup a => a -> a -> a
<> Integer -> Builder
go (-Integer
i)
| Bool
otherwise = Integer -> Builder
go Integer
i
where
go :: Integer -> Builder
go Integer
n | Integer
n forall a. Ord a => a -> a -> Bool
< Integer
maxInt = Int -> Builder
int (forall a. Num a => Integer -> a
fromInteger Integer
n)
| Bool
otherwise = [Integer] -> Builder
putH (Integer -> Integer -> [Integer]
splitf (Integer
maxInt forall a. Num a => a -> a -> a
* Integer
maxInt) Integer
n)
splitf :: Integer -> Integer -> [Integer]
splitf Integer
p Integer
n
| Integer
p forall a. Ord a => a -> a -> Bool
> Integer
n = [Integer
n]
| Bool
otherwise = Integer -> [Integer] -> [Integer]
splith Integer
p (Integer -> Integer -> [Integer]
splitf (Integer
pforall a. Num a => a -> a -> a
*Integer
p) Integer
n)
splith :: Integer -> [Integer] -> [Integer]
splith Integer
p (Integer
n:[Integer]
ns) = case Integer
n Integer -> Integer -> (# Integer, Integer #)
`quotRemInteger` Integer
p of
PAIR(Integer
q,r) | Integer
q forall a. Ord a => a -> a -> Bool
> Integer
0 -> Integer
q forall a. a -> [a] -> [a]
: Integer
r forall a. a -> [a] -> [a]
: Integer -> [Integer] -> [Integer]
splitb Integer
p [Integer]
ns
| Bool
otherwise -> Integer
r forall a. a -> [a] -> [a]
: Integer -> [Integer] -> [Integer]
splitb Integer
p [Integer]
ns
splith Integer
_ [Integer]
_ = forall a. HasCallStack => [Char] -> a
error [Char]
"splith: the impossible happened."
splitb :: Integer -> [Integer] -> [Integer]
splitb Integer
p (Integer
n:[Integer]
ns) = case Integer
n Integer -> Integer -> (# Integer, Integer #)
`quotRemInteger` Integer
p of
PAIR(Integer
q,r) -> Integer
q forall a. a -> [a] -> [a]
: Integer
r forall a. a -> [a] -> [a]
: Integer -> [Integer] -> [Integer]
splitb Integer
p [Integer]
ns
splitb Integer
_ [Integer]
_ = []
T Integer
maxInt10 Int
maxDigits10 =
forall a. (a -> Bool) -> (a -> a) -> a -> a
until ((forall a. Ord a => a -> a -> Bool
>Integer
mi) forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. Num a => a -> a -> a
*Integer
10) forall b c a. (b -> c) -> (a -> b) -> a -> c
. T -> Integer
fstT) (\(T Integer
n Int
d) -> Integer -> Int -> T
T (Integer
nforall a. Num a => a -> a -> a
*Integer
10) (Int
dforall a. Num a => a -> a -> a
+Int
1)) (Integer -> Int -> T
T Integer
10 Int
1)
where mi :: Integer
mi = forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Bounded a => a
maxBound :: Int)
T Integer
maxInt16 Int
maxDigits16 =
forall a. (a -> Bool) -> (a -> a) -> a -> a
until ((forall a. Ord a => a -> a -> Bool
>Integer
mi) forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a. Num a => a -> a -> a
*Integer
16) forall b c a. (b -> c) -> (a -> b) -> a -> c
. T -> Integer
fstT) (\(T Integer
n Int
d) -> Integer -> Int -> T
T (Integer
nforall a. Num a => a -> a -> a
*Integer
16) (Int
dforall a. Num a => a -> a -> a
+Int
1)) (Integer -> Int -> T
T Integer
16 Int
1)
where mi :: Integer
mi = forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Bounded a => a
maxBound :: Int)
fstT :: T -> Integer
fstT (T Integer
a Int
_) = Integer
a
maxInt :: Integer
maxInt | Int
base forall a. Eq a => a -> a -> Bool
== Int
10 = Integer
maxInt10
| Bool
otherwise = Integer
maxInt16
maxDigits :: Int
maxDigits | Int
base forall a. Eq a => a -> a -> Bool
== Int
10 = Int
maxDigits10
| Bool
otherwise = Int
maxDigits16
putH :: [Integer] -> Builder
putH (Integer
n:[Integer]
ns) = case Integer
n Integer -> Integer -> (# Integer, Integer #)
`quotRemInteger` Integer
maxInt of
PAIR(Integer
x,y)
| Int
q forall a. Ord a => a -> a -> Bool
> Int
0 -> Int -> Builder
int Int
q forall a. Semigroup a => a -> a -> a
<> Int -> Builder
pblock Int
r forall a. Semigroup a => a -> a -> a
<> [Integer] -> Builder
putB [Integer]
ns
| Bool
otherwise -> Int -> Builder
int Int
r forall a. Semigroup a => a -> a -> a
<> [Integer] -> Builder
putB [Integer]
ns
where q :: Int
q = forall a. Num a => Integer -> a
fromInteger Integer
x
r :: Int
r = forall a. Num a => Integer -> a
fromInteger Integer
y
putH [Integer]
_ = forall a. HasCallStack => [Char] -> a
error [Char]
"putH: the impossible happened"
putB :: [Integer] -> Builder
putB (Integer
n:[Integer]
ns) = case Integer
n Integer -> Integer -> (# Integer, Integer #)
`quotRemInteger` Integer
maxInt of
PAIR(Integer
x,y) -> Int -> Builder
pblock Int
q forall a. Semigroup a => a -> a -> a
<> Int -> Builder
pblock Int
r forall a. Semigroup a => a -> a -> a
<> [Integer] -> Builder
putB [Integer]
ns
where q :: Int
q = forall a. Num a => Integer -> a
fromInteger Integer
x
r :: Int
r = forall a. Num a => Integer -> a
fromInteger Integer
y
putB [Integer]
_ = forall a. Monoid a => a
mempty
pblock :: Int -> Builder
pblock = forall {t}. (Eq t, Num t) => t -> Int -> Builder
loop Int
maxDigits
where
loop :: t -> Int -> Builder
loop !t
d !Int
n
| t
d forall a. Eq a => a -> a -> Bool
== t
1 = forall a. Integral a => a -> Builder
digit Int
n
| Bool
otherwise = t -> Int -> Builder
loop (t
dforall a. Num a => a -> a -> a
-t
1) Int
q forall a. Semigroup a => a -> a -> a
<> forall a. Integral a => a -> Builder
digit Int
r
where q :: Int
q = Int
n Int -> Int -> Int
`quotInt` Int
base
r :: Int
r = Int
n Int -> Int -> Int
`remInt` Int
base