{-# LANGUAGE BangPatterns, CPP, MagicHash, RankNTypes, ScopedTypeVariables,
    UnboxedTuples #-}
#if __GLASGOW_HASKELL__ >= 702
{-# LANGUAGE Trustworthy #-}
#endif

-- Module:      Data.Text.Lazy.Builder.Int
-- Copyright:   (c) 2013 Bryan O'Sullivan
--              (c) 2011 MailRank, Inc.
-- License:     BSD-style
-- Maintainer:  Bryan O'Sullivan <bos@serpentine.com>
-- Portability: portable
--
-- Efficiently write an integral value to a 'Builder'.

module Data.Text.Lazy.Builder.Int
    (
      decimal
    , hexadecimal
    ) where

import Data.Int (Int8, Int16, Int32, Int64)
import Data.Monoid (mempty)
import qualified Data.ByteString.Unsafe as B
import Data.Text.Internal.Builder.Functions ((<>), i2d)
import Data.Text.Internal.Builder
import Data.Text.Internal.Builder.Int.Digits (digits)
import Data.Text.Array
import Data.Word (Word, Word8, Word16, Word32, Word64)
import GHC.Base (quotInt, remInt)
import GHC.Num (quotRemInteger)
import GHC.Types (Int(..))
import Control.Monad.ST
#if MIN_VERSION_base(4,11,0)
import Prelude hiding ((<>))
#endif

#ifdef  __GLASGOW_HASKELL__
# if defined(INTEGER_GMP)
import GHC.Integer.GMP.Internals (Integer(S#))
# elif defined(INTEGER_SIMPLE)
import GHC.Integer
# else
# error "You need to use either GMP or integer-simple."
# endif
#endif

#if defined(INTEGER_GMP) || defined(INTEGER_SIMPLE)
# define PAIR(a,b) (# a,b #)
#else
# define PAIR(a,b) (a,b)
#endif

decimal :: Integral a => a -> Builder
{-# RULES "decimal/Int8" decimal = boundedDecimal :: Int8 -> Builder #-}
{-# RULES "decimal/Int" decimal = boundedDecimal :: Int -> Builder #-}
{-# RULES "decimal/Int16" decimal = boundedDecimal :: Int16 -> Builder #-}
{-# RULES "decimal/Int32" decimal = boundedDecimal :: Int32 -> Builder #-}
{-# RULES "decimal/Int64" decimal = boundedDecimal :: Int64 -> Builder #-}
{-# RULES "decimal/Word" decimal = positive :: Data.Word.Word -> Builder #-}
{-# RULES "decimal/Word8" decimal = positive :: Word8 -> Builder #-}
{-# RULES "decimal/Word16" decimal = positive :: Word16 -> Builder #-}
{-# RULES "decimal/Word32" decimal = positive :: Word32 -> Builder #-}
{-# RULES "decimal/Word64" decimal = positive :: Word64 -> Builder #-}
{-# RULES "decimal/Integer" decimal = integer 10 :: Integer -> Builder #-}
decimal :: a -> Builder
decimal a
i = (a -> Bool) -> a -> Builder
forall a. Integral a => (a -> Bool) -> a -> Builder
decimal' (a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= -a
128) a
i
{-# NOINLINE decimal #-}

boundedDecimal :: (Integral a, Bounded a) => a -> Builder
{-# SPECIALIZE boundedDecimal :: Int -> Builder #-}
{-# SPECIALIZE boundedDecimal :: Int8 -> Builder #-}
{-# SPECIALIZE boundedDecimal :: Int16 -> Builder #-}
{-# SPECIALIZE boundedDecimal :: Int32 -> Builder #-}
{-# SPECIALIZE boundedDecimal :: Int64 -> Builder #-}
boundedDecimal :: a -> Builder
boundedDecimal a
i = (a -> Bool) -> a -> Builder
forall a. Integral a => (a -> Bool) -> a -> Builder
decimal' (a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
forall a. Bounded a => a
minBound) a
i

decimal' :: (Integral a) => (a -> Bool) -> a -> Builder
{-# INLINE decimal' #-}
decimal' :: (a -> Bool) -> a -> Builder
decimal' a -> Bool
p a
i
    | a
i a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0 = if a -> Bool
p a
i
              then let (a
q, a
r) = a
i a -> a -> (a, a)
forall a. Integral a => a -> a -> (a, a)
`quotRem` a
10
                       qq :: a
qq = -a
q
                       !n :: Int
n = a -> Int
forall a. Integral a => a -> Int
countDigits a
qq
                   in Int -> (forall s. MArray s -> Int -> ST s ()) -> Builder
writeN (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2) ((forall s. MArray s -> Int -> ST s ()) -> Builder)
-> (forall s. MArray s -> Int -> ST s ()) -> Builder
forall a b. (a -> b) -> a -> b
$ \MArray s
marr Int
off -> do
                       MArray s -> Int -> Word16 -> ST s ()
forall s. MArray s -> Int -> Word16 -> ST s ()
unsafeWrite MArray s
marr Int
off Word16
minus
                       MArray s -> Int -> Int -> a -> ST s ()
forall a s. Integral a => MArray s -> Int -> Int -> a -> ST s ()
posDecimal MArray s
marr (Int
offInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) Int
n a
qq
                       MArray s -> Int -> Word16 -> ST s ()
forall s. MArray s -> Int -> Word16 -> ST s ()
unsafeWrite MArray s
marr (Int
offInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) (a -> Word16
forall a. Integral a => a -> Word16
i2w (-a
r))
              else let j :: a
j = -a
i
                       !n :: Int
n = a -> Int
forall a. Integral a => a -> Int
countDigits a
j
                   in Int -> (forall s. MArray s -> Int -> ST s ()) -> Builder
writeN (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) ((forall s. MArray s -> Int -> ST s ()) -> Builder)
-> (forall s. MArray s -> Int -> ST s ()) -> Builder
forall a b. (a -> b) -> a -> b
$ \MArray s
marr Int
off ->
                       MArray s -> Int -> Word16 -> ST s ()
forall s. MArray s -> Int -> Word16 -> ST s ()
unsafeWrite MArray s
marr Int
off Word16
minus ST s () -> ST s () -> ST s ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> MArray s -> Int -> Int -> a -> ST s ()
forall a s. Integral a => MArray s -> Int -> Int -> a -> ST s ()
posDecimal MArray s
marr (Int
offInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) Int
n a
j
    | Bool
otherwise = a -> Builder
forall a. Integral a => a -> Builder
positive a
i

positive :: (Integral a) => a -> Builder
{-# SPECIALIZE positive :: Int -> Builder #-}
{-# SPECIALIZE positive :: Int8 -> Builder #-}
{-# SPECIALIZE positive :: Int16 -> Builder #-}
{-# SPECIALIZE positive :: Int32 -> Builder #-}
{-# SPECIALIZE positive :: Int64 -> Builder #-}
{-# SPECIALIZE positive :: Word -> Builder #-}
{-# SPECIALIZE positive :: Word8 -> Builder #-}
{-# SPECIALIZE positive :: Word16 -> Builder #-}
{-# SPECIALIZE positive :: Word32 -> Builder #-}
{-# SPECIALIZE positive :: Word64 -> Builder #-}
positive :: a -> Builder
positive a
i
    | a
i a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
10    = Int -> (forall s. MArray s -> Int -> ST s ()) -> Builder
writeN Int
1 ((forall s. MArray s -> Int -> ST s ()) -> Builder)
-> (forall s. MArray s -> Int -> ST s ()) -> Builder
forall a b. (a -> b) -> a -> b
$ \MArray s
marr Int
off -> MArray s -> Int -> Word16 -> ST s ()
forall s. MArray s -> Int -> Word16 -> ST s ()
unsafeWrite MArray s
marr Int
off (a -> Word16
forall a. Integral a => a -> Word16
i2w a
i)
    | Bool
otherwise = let !n :: Int
n = a -> Int
forall a. Integral a => a -> Int
countDigits a
i
                  in Int -> (forall s. MArray s -> Int -> ST s ()) -> Builder
writeN Int
n ((forall s. MArray s -> Int -> ST s ()) -> Builder)
-> (forall s. MArray s -> Int -> ST s ()) -> Builder
forall a b. (a -> b) -> a -> b
$ \MArray s
marr Int
off -> MArray s -> Int -> Int -> a -> ST s ()
forall a s. Integral a => MArray s -> Int -> Int -> a -> ST s ()
posDecimal MArray s
marr Int
off Int
n a
i

posDecimal :: (Integral a) =>
              forall s. MArray s -> Int -> Int -> a -> ST s ()
{-# INLINE posDecimal #-}
posDecimal :: forall s. MArray s -> Int -> Int -> a -> ST s ()
posDecimal MArray s
marr Int
off0 Int
ds a
v0 = Int -> a -> ST s ()
forall a. Integral a => Int -> a -> ST s ()
go (Int
off0 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
ds Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) a
v0
  where go :: Int -> a -> ST s ()
go Int
off a
v
           | a
v a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
100 = do
               let (a
q, a
r) = a
v a -> a -> (a, a)
forall a. Integral a => a -> a -> (a, a)
`quotRem` a
100
               Int -> a -> ST s ()
forall a. Integral a => Int -> a -> ST s ()
write2 Int
off a
r
               Int -> a -> ST s ()
go (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2) a
q
           | a
v a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
10    = MArray s -> Int -> Word16 -> ST s ()
forall s. MArray s -> Int -> Word16 -> ST s ()
unsafeWrite MArray s
marr Int
off (a -> Word16
forall a. Integral a => a -> Word16
i2w a
v)
           | Bool
otherwise = Int -> a -> ST s ()
forall a. Integral a => Int -> a -> ST s ()
write2 Int
off a
v
        write2 :: Int -> a -> ST s ()
write2 Int
off a
i0 = do
          let i :: Int
i = a -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
i0; j :: Int
j = Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
i
          MArray s -> Int -> Word16 -> ST s ()
forall s. MArray s -> Int -> Word16 -> ST s ()
unsafeWrite MArray s
marr Int
off (Word16 -> ST s ()) -> Word16 -> ST s ()
forall a b. (a -> b) -> a -> b
$ Int -> Word16
get (Int
j Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
          MArray s -> Int -> Word16 -> ST s ()
forall s. MArray s -> Int -> Word16 -> ST s ()
unsafeWrite MArray s
marr (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) (Word16 -> ST s ()) -> Word16 -> ST s ()
forall a b. (a -> b) -> a -> b
$ Int -> Word16
get Int
j
        get :: Int -> Word16
get = Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8 -> Word16) -> (Int -> Word8) -> Int -> Word16
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Int -> Word8
B.unsafeIndex ByteString
digits

minus, zero :: Word16
{-# INLINE minus #-}
{-# INLINE zero #-}
minus :: Word16
minus = Word16
45
zero :: Word16
zero = Word16
48

i2w :: (Integral a) => a -> Word16
{-# INLINE i2w #-}
i2w :: a -> Word16
i2w a
v = Word16
zero Word16 -> Word16 -> Word16
forall a. Num a => a -> a -> a
+ a -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
v

countDigits :: (Integral a) => a -> Int
{-# INLINE countDigits #-}
countDigits :: a -> Int
countDigits a
v0
  | Word64 -> a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
v64 a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
v0 = Int -> Word64 -> Int
forall t. Num t => t -> Word64 -> t
go Int
1 Word64
v64
  | Bool
otherwise              = Int -> Integer -> Int
forall p. Num p => p -> Integer -> p
goBig Int
1 (a -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
v0)
  where v64 :: Word64
v64 = a -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
v0
        goBig :: p -> Integer -> p
goBig !p
k (Integer
v :: Integer)
           | Integer
v Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
big   = p -> Integer -> p
goBig (p
k p -> p -> p
forall a. Num a => a -> a -> a
+ p
19) (Integer
v Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`quot` Integer
big)
           | Bool
otherwise = p -> Word64 -> p
forall t. Num t => t -> Word64 -> t
go p
k (Integer -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
v)
        big :: Integer
big = Integer
10000000000000000000
        go :: t -> Word64 -> t
go !t
k (Word64
v :: Word64)
           | Word64
v Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
10    = t
k
           | Word64
v Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
100   = t
k t -> t -> t
forall a. Num a => a -> a -> a
+ t
1
           | Word64
v Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
1000  = t
k t -> t -> t
forall a. Num a => a -> a -> a
+ t
2
           | Word64
v Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
1000000000000 =
               t
k t -> t -> t
forall a. Num a => a -> a -> a
+ if Word64
v Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
100000000
                   then if Word64
v Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
1000000
                        then if Word64
v Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
10000
                             then t
3
                             else t
4 t -> t -> t
forall a. Num a => a -> a -> a
+ Word64 -> Word64 -> t
forall a p. (Ord a, Num p) => a -> a -> p
fin Word64
v Word64
100000
                        else t
6 t -> t -> t
forall a. Num a => a -> a -> a
+ Word64 -> Word64 -> t
forall a p. (Ord a, Num p) => a -> a -> p
fin Word64
v Word64
10000000
                   else if Word64
v Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
10000000000
                        then t
8 t -> t -> t
forall a. Num a => a -> a -> a
+ Word64 -> Word64 -> t
forall a p. (Ord a, Num p) => a -> a -> p
fin Word64
v Word64
1000000000
                        else t
10 t -> t -> t
forall a. Num a => a -> a -> a
+ Word64 -> Word64 -> t
forall a p. (Ord a, Num p) => a -> a -> p
fin Word64
v Word64
100000000000
           | Bool
otherwise = t -> Word64 -> t
go (t
k t -> t -> t
forall a. Num a => a -> a -> a
+ t
12) (Word64
v Word64 -> Word64 -> Word64
forall a. Integral a => a -> a -> a
`quot` Word64
1000000000000)
        fin :: a -> a -> p
fin a
v a
n = if a
v a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
n then p
1 else p
0

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 = hexInteger :: Integer -> Builder #-}
hexadecimal :: a -> Builder
hexadecimal a
i
    | a
i a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
0     = [Char] -> Builder
forall a. HasCallStack => [Char] -> a
error [Char]
hexErrMsg
    | Bool
otherwise = a -> Builder
forall a. Integral a => a -> Builder
go a
i
  where
    go :: a -> Builder
go a
n | a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
16    = a -> Builder
forall a. Integral a => a -> Builder
hexDigit a
n
         | Bool
otherwise = a -> Builder
go (a
n a -> a -> a
forall a. Integral a => a -> a -> a
`quot` a
16) Builder -> Builder -> Builder
<> a -> Builder
forall a. Integral a => a -> Builder
hexDigit (a
n a -> a -> a
forall a. Integral a => a -> a -> a
`rem` a
16)
{-# NOINLINE[0] hexadecimal #-}

hexInteger :: Integer -> Builder
hexInteger :: Integer -> Builder
hexInteger Integer
i
    | Integer
i Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
0     = [Char] -> Builder
forall a. HasCallStack => [Char] -> a
error [Char]
hexErrMsg
    | Bool
otherwise = Int -> Integer -> Builder
integer Int
16 Integer
i

hexErrMsg :: String
hexErrMsg :: [Char]
hexErrMsg = [Char]
"Data.Text.Lazy.Builder.Int.hexadecimal: applied to negative number"

hexDigit :: Integral a => a -> Builder
hexDigit :: a -> Builder
hexDigit a
n
    | a
n a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
9    = Char -> Builder
singleton (Char -> Builder) -> Char -> Builder
forall a b. (a -> b) -> a -> b
$! Int -> Char
i2d (a -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n)
    | Bool
otherwise = Char -> Builder
singleton (Char -> Builder) -> Char -> Builder
forall a b. (a -> b) -> a -> b
$! Int -> Char
forall a. Enum a => Int -> a
toEnum (a -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
87)
{-# INLINE hexDigit #-}

data T = T !Integer !Int

integer :: Int -> Integer -> Builder
#ifdef INTEGER_GMP
integer :: Int -> Integer -> Builder
integer Int
10 (S# Int#
i#) = Int -> Builder
forall a. Integral a => a -> Builder
decimal (Int# -> Int
I# Int#
i#)
integer Int
16 (S# Int#
i#) = Int -> Builder
forall a. Integral a => a -> Builder
hexadecimal (Int# -> Int
I# Int#
i#)
#endif
integer Int
base Integer
i
    | Integer
i Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
0     = Char -> Builder
singleton Char
'-' Builder -> Builder -> Builder
<> Integer -> Builder
go (-Integer
i)
    | Bool
otherwise = Integer -> Builder
go Integer
i
  where
    go :: Integer -> Builder
go Integer
n | Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
maxInt = Int -> Builder
int (Integer -> Int
forall a. Num a => Integer -> a
fromInteger Integer
n)
         | Bool
otherwise  = [Integer] -> Builder
putH (Integer -> Integer -> [Integer]
splitf (Integer
maxInt Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
maxInt) Integer
n)

    splitf :: Integer -> Integer -> [Integer]
splitf Integer
p Integer
n
      | Integer
p Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
n       = [Integer
n]
      | Bool
otherwise   = Integer -> [Integer] -> [Integer]
splith Integer
p (Integer -> Integer -> [Integer]
splitf (Integer
pInteger -> Integer -> Integer
forall 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 Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
0     -> Integer
q Integer -> [Integer] -> [Integer]
forall a. a -> [a] -> [a]
: Integer
r Integer -> [Integer] -> [Integer]
forall a. a -> [a] -> [a]
: Integer -> [Integer] -> [Integer]
splitb Integer
p [Integer]
ns
                                  | Bool
otherwise -> Integer
r Integer -> [Integer] -> [Integer]
forall a. a -> [a] -> [a]
: Integer -> [Integer] -> [Integer]
splitb Integer
p [Integer]
ns
    splith Integer
_ [Integer]
_      = [Char] -> [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 Integer -> [Integer] -> [Integer]
forall a. a -> [a] -> [a]
: Integer
r Integer -> [Integer] -> [Integer]
forall a. a -> [a] -> [a]
: Integer -> [Integer] -> [Integer]
splitb Integer
p [Integer]
ns
    splitb Integer
_ [Integer]
_      = []

    T Integer
maxInt10 Int
maxDigits10 =
        (T -> Bool) -> (T -> T) -> T -> T
forall a. (a -> Bool) -> (a -> a) -> a -> a
until ((Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>Integer
mi) (Integer -> Bool) -> (T -> Integer) -> T -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
*Integer
10) (Integer -> Integer) -> (T -> Integer) -> T -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. T -> Integer
fstT) (\(T Integer
n Int
d) -> Integer -> Int -> T
T (Integer
nInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
*Integer
10) (Int
dInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)) (Integer -> Int -> T
T Integer
10 Int
1)
      where mi :: Integer
mi = Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
forall a. Bounded a => a
maxBound :: Int)
    T Integer
maxInt16 Int
maxDigits16 =
        (T -> Bool) -> (T -> T) -> T -> T
forall a. (a -> Bool) -> (a -> a) -> a -> a
until ((Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>Integer
mi) (Integer -> Bool) -> (T -> Integer) -> T -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
*Integer
16) (Integer -> Integer) -> (T -> Integer) -> T -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. T -> Integer
fstT) (\(T Integer
n Int
d) -> Integer -> Int -> T
T (Integer
nInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
*Integer
16) (Int
dInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)) (Integer -> Int -> T
T Integer
16 Int
1)
      where mi :: Integer
mi = Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
forall a. Bounded a => a
maxBound :: Int)

    fstT :: T -> Integer
fstT (T Integer
a Int
_) = Integer
a

    maxInt :: Integer
maxInt | Int
base Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
10 = Integer
maxInt10
           | Bool
otherwise  = Integer
maxInt16
    maxDigits :: Int
maxDigits | Int
base Int -> Int -> Bool
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 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0     -> Int -> Builder
int Int
q Builder -> Builder -> Builder
<> Int -> Builder
pblock Int
r Builder -> Builder -> Builder
<> [Integer] -> Builder
putB [Integer]
ns
                        | Bool
otherwise -> Int -> Builder
int Int
r Builder -> Builder -> Builder
<> [Integer] -> Builder
putB [Integer]
ns
                        where q :: Int
q = Integer -> Int
forall a. Num a => Integer -> a
fromInteger Integer
x
                              r :: Int
r = Integer -> Int
forall a. Num a => Integer -> a
fromInteger Integer
y
    putH [Integer]
_ = [Char] -> Builder
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 Builder -> Builder -> Builder
<> Int -> Builder
pblock Int
r Builder -> Builder -> Builder
<> [Integer] -> Builder
putB [Integer]
ns
                        where q :: Int
q = Integer -> Int
forall a. Num a => Integer -> a
fromInteger Integer
x
                              r :: Int
r = Integer -> Int
forall a. Num a => Integer -> a
fromInteger Integer
y
    putB [Integer]
_ = Builder
forall a. Monoid a => a
Data.Monoid.mempty

    int :: Int -> Builder
    int :: Int -> Builder
int Int
x | Int
base Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
10 = Int -> Builder
forall a. Integral a => a -> Builder
decimal Int
x
          | Bool
otherwise  = Int -> Builder
forall a. Integral a => a -> Builder
hexadecimal Int
x

    pblock :: Int -> Builder
pblock = Int -> Int -> Builder
forall t. (Eq t, Num t) => t -> Int -> Builder
loop Int
maxDigits
      where
        loop :: t -> Int -> Builder
loop !t
d !Int
n
            | t
d t -> t -> Bool
forall a. Eq a => a -> a -> Bool
== t
1    = Int -> Builder
forall a. Integral a => a -> Builder
hexDigit Int
n
            | Bool
otherwise = t -> Int -> Builder
loop (t
dt -> t -> t
forall a. Num a => a -> a -> a
-t
1) Int
q Builder -> Builder -> Builder
<> Int -> Builder
forall a. Integral a => a -> Builder
hexDigit 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