{-# LANGUAGE BangPatterns, CPP, MagicHash, RankNTypes, ScopedTypeVariables,
UnboxedTuples #-}
{-# LANGUAGE Trustworthy #-}
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 Control.Monad.ST
#if MIN_VERSION_base(4,11,0)
import Prelude hiding ((<>))
#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 :: forall a. Integral a => a -> Builder
decimal a
i = forall a. Integral a => (a -> Bool) -> a -> Builder
decimal' (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 :: forall a. (Integral a, Bounded a) => a -> Builder
boundedDecimal a
i = forall a. Integral a => (a -> Bool) -> a -> Builder
decimal' (forall a. Eq a => a -> a -> Bool
== forall a. Bounded a => a
minBound) a
i
decimal' :: (Integral a) => (a -> Bool) -> a -> Builder
{-# INLINE decimal' #-}
decimal' :: forall a. Integral a => (a -> Bool) -> a -> Builder
decimal' a -> Bool
p a
i
| a
i forall a. Ord a => a -> a -> Bool
< a
0 = if a -> Bool
p a
i
then let (a
q, a
r) = a
i forall a. Integral a => a -> a -> (a, a)
`quotRem` a
10
qq :: a
qq = -a
q
!n :: Int
n = forall a. Integral a => a -> Int
countDigits a
qq
in Int -> (forall s. MArray s -> Int -> ST s ()) -> Builder
writeN (Int
n forall a. Num a => a -> a -> a
+ Int
2) forall a b. (a -> b) -> a -> b
$ \MArray s
marr Int
off -> do
forall s. MArray s -> Int -> Word16 -> ST s ()
unsafeWrite MArray s
marr Int
off Word16
minus
forall a s. Integral a => MArray s -> Int -> Int -> a -> ST s ()
posDecimal MArray s
marr (Int
offforall a. Num a => a -> a -> a
+Int
1) Int
n a
qq
forall s. MArray s -> Int -> Word16 -> ST s ()
unsafeWrite MArray s
marr (Int
offforall a. Num a => a -> a -> a
+Int
nforall a. Num a => a -> a -> a
+Int
1) (forall a. Integral a => a -> Word16
i2w (-a
r))
else let j :: a
j = -a
i
!n :: Int
n = forall a. Integral a => a -> Int
countDigits a
j
in Int -> (forall s. MArray s -> Int -> ST s ()) -> Builder
writeN (Int
n forall a. Num a => a -> a -> a
+ Int
1) forall a b. (a -> b) -> a -> b
$ \MArray s
marr Int
off ->
forall s. MArray s -> Int -> Word16 -> ST s ()
unsafeWrite MArray s
marr Int
off Word16
minus forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall a s. Integral a => MArray s -> Int -> Int -> a -> ST s ()
posDecimal MArray s
marr (Int
offforall a. Num a => a -> a -> a
+Int
1) Int
n a
j
| Bool
otherwise = 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 :: forall a. Integral a => a -> Builder
positive a
i
| a
i forall a. Ord a => a -> a -> Bool
< a
10 = Int -> (forall s. MArray s -> Int -> ST s ()) -> Builder
writeN Int
1 forall a b. (a -> b) -> a -> b
$ \MArray s
marr Int
off -> forall s. MArray s -> Int -> Word16 -> ST s ()
unsafeWrite MArray s
marr Int
off (forall a. Integral a => a -> Word16
i2w a
i)
| Bool
otherwise = let !n :: Int
n = forall a. Integral a => a -> Int
countDigits a
i
in Int -> (forall s. MArray s -> Int -> ST s ()) -> Builder
writeN Int
n forall a b. (a -> b) -> a -> b
$ \MArray s
marr Int
off -> 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 a s. Integral a => MArray s -> Int -> Int -> a -> ST s ()
posDecimal MArray s
marr Int
off0 Int
ds a
v0 = forall {p}. Integral p => Int -> p -> ST s ()
go (Int
off0 forall a. Num a => a -> a -> a
+ Int
ds forall a. Num a => a -> a -> a
- Int
1) a
v0
where go :: Int -> p -> ST s ()
go Int
off p
v
| p
v forall a. Ord a => a -> a -> Bool
>= p
100 = do
let (p
q, p
r) = p
v forall a. Integral a => a -> a -> (a, a)
`quotRem` p
100
forall {p}. Integral p => Int -> p -> ST s ()
write2 Int
off p
r
Int -> p -> ST s ()
go (Int
off forall a. Num a => a -> a -> a
- Int
2) p
q
| p
v forall a. Ord a => a -> a -> Bool
< p
10 = forall s. MArray s -> Int -> Word16 -> ST s ()
unsafeWrite MArray s
marr Int
off (forall a. Integral a => a -> Word16
i2w p
v)
| Bool
otherwise = forall {p}. Integral p => Int -> p -> ST s ()
write2 Int
off p
v
write2 :: Int -> p -> ST s ()
write2 Int
off p
i0 = do
let i :: Int
i = forall a b. (Integral a, Num b) => a -> b
fromIntegral p
i0; j :: Int
j = Int
i forall a. Num a => a -> a -> a
+ Int
i
forall s. MArray s -> Int -> Word16 -> ST s ()
unsafeWrite MArray s
marr Int
off forall a b. (a -> b) -> a -> b
$ Int -> Word16
get (Int
j forall a. Num a => a -> a -> a
+ Int
1)
forall s. MArray s -> Int -> Word16 -> ST s ()
unsafeWrite MArray s
marr (Int
off forall a. Num a => a -> a -> a
- Int
1) forall a b. (a -> b) -> a -> b
$ Int -> Word16
get Int
j
get :: Int -> Word16
get = Word8 -> Word16
word8ToWord16 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 :: forall a. Integral a => a -> Word16
i2w a
v = Word16
zero forall a. Num a => a -> a -> a
+ forall a b. (Integral a, Num b) => a -> b
fromIntegral a
v
countDigits :: (Integral a) => a -> Int
{-# INLINE countDigits #-}
countDigits :: forall a. Integral a => a -> Int
countDigits a
v0
| forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
v64 forall a. Eq a => a -> a -> Bool
== a
v0 = forall {t}. Num t => t -> Word64 -> t
go Int
1 Word64
v64
| Bool
otherwise = forall {t}. Num t => t -> Integer -> t
goBig Int
1 (forall a. Integral a => a -> Integer
toInteger a
v0)
where v64 :: Word64
v64 = forall a b. (Integral a, Num b) => a -> b
fromIntegral a
v0
goBig :: t -> Integer -> t
goBig !t
k (Integer
v :: Integer)
| Integer
v forall a. Ord a => a -> a -> Bool
> Integer
big = t -> Integer -> t
goBig (t
k forall a. Num a => a -> a -> a
+ t
19) (Integer
v forall a. Integral a => a -> a -> a
`quot` Integer
big)
| Bool
otherwise = forall {t}. Num t => t -> Word64 -> t
go t
k (forall a. Num a => Integer -> a
fromInteger Integer
v)
big :: Integer
big = Integer
10000000000000000000
go :: t -> Word64 -> t
go !t
k (Word64
v :: Word64)
| Word64
v forall a. Ord a => a -> a -> Bool
< Word64
10 = t
k
| Word64
v forall a. Ord a => a -> a -> Bool
< Word64
100 = t
k forall a. Num a => a -> a -> a
+ t
1
| Word64
v forall a. Ord a => a -> a -> Bool
< Word64
1000 = t
k forall a. Num a => a -> a -> a
+ t
2
| Word64
v forall a. Ord a => a -> a -> Bool
< Word64
1000000000000 =
t
k forall a. Num a => a -> a -> a
+ if Word64
v forall a. Ord a => a -> a -> Bool
< Word64
100000000
then if Word64
v forall a. Ord a => a -> a -> Bool
< Word64
1000000
then if Word64
v forall a. Ord a => a -> a -> Bool
< Word64
10000
then t
3
else t
4 forall a. Num a => a -> a -> a
+ forall {a} {a}. (Ord a, Num a) => a -> a -> a
fin Word64
v Word64
100000
else t
6 forall a. Num a => a -> a -> a
+ forall {a} {a}. (Ord a, Num a) => a -> a -> a
fin Word64
v Word64
10000000
else if Word64
v forall a. Ord a => a -> a -> Bool
< Word64
10000000000
then t
8 forall a. Num a => a -> a -> a
+ forall {a} {a}. (Ord a, Num a) => a -> a -> a
fin Word64
v Word64
1000000000
else t
10 forall a. Num a => a -> a -> a
+ forall {a} {a}. (Ord a, Num a) => a -> a -> a
fin Word64
v Word64
100000000000
| Bool
otherwise = t -> Word64 -> t
go (t
k forall a. Num a => a -> a -> a
+ t
12) (Word64
v forall a. Integral a => a -> a -> a
`quot` Word64
1000000000000)
fin :: a -> a -> a
fin a
v a
n = if a
v forall a. Ord a => a -> a -> Bool
>= a
n then a
1 else a
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 :: forall a. Integral a => a -> Builder
hexadecimal a
i
| a
i forall a. Ord a => a -> a -> Bool
< a
0 = forall a. HasCallStack => [Char] -> a
error [Char]
hexErrMsg
| 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) Builder -> Builder -> Builder
<> forall a. Integral a => a -> Builder
hexDigit (a
n forall a. Integral a => a -> a -> a
`rem` a
16)
{-# NOINLINE[0] hexadecimal #-}
hexInteger :: Integer -> Builder
hexInteger :: Integer -> Builder
hexInteger Integer
i
| Integer
i forall a. Ord a => a -> a -> Bool
< Integer
0 = 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 :: 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 #-}
data T = T !Integer !Int
integer :: Int -> Integer -> Builder
integer :: Int -> Integer -> Builder
integer Int
10 Integer
i
| Int
i' <- forall a. Num a => Integer -> a
fromInteger Integer
i, forall a. Integral a => a -> Integer
toInteger Int
i' forall a. Eq a => a -> a -> Bool
== Integer
i = forall a. Integral a => a -> Builder
decimal (Int
i' :: Int)
integer Int
16 Integer
i
| Int
i' <- forall a. Num a => Integer -> a
fromInteger Integer
i, forall a. Integral a => a -> Integer
toInteger Int
i' forall a. Eq a => a -> a -> Bool
== Integer
i = forall a. Integral a => a -> Builder
hexadecimal (Int
i' :: Int)
integer Int
base Integer
i
| Integer
i 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 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 (forall {t}. Integral t => t -> t -> [t]
splitf (Integer
maxInt forall a. Num a => a -> a -> a
* Integer
maxInt) Integer
n)
splitf :: t -> t -> [t]
splitf t
p t
n
| t
p forall a. Ord a => a -> a -> Bool
> t
n = [t
n]
| Bool
otherwise = forall {a}. Integral a => a -> [a] -> [a]
splith t
p (t -> t -> [t]
splitf (t
pforall a. Num a => a -> a -> a
*t
p) t
n)
splith :: a -> [a] -> [a]
splith a
p (a
n:[a]
ns) = case a
n forall a. Integral a => a -> a -> (a, a)
`quotRem` a
p of
(a
q, a
r) | a
q forall a. Ord a => a -> a -> Bool
> a
0 -> a
q forall a. a -> [a] -> [a]
: a
r forall a. a -> [a] -> [a]
: forall {a}. Integral a => a -> [a] -> [a]
splitb a
p [a]
ns
| Bool
otherwise -> a
r forall a. a -> [a] -> [a]
: forall {a}. Integral a => a -> [a] -> [a]
splitb a
p [a]
ns
splith a
_ [a]
_ = forall a. HasCallStack => [Char] -> a
error [Char]
"splith: the impossible happened."
splitb :: t -> [t] -> [t]
splitb t
p (t
n:[t]
ns) = case t
n forall a. Integral a => a -> a -> (a, a)
`quotRem` t
p of
(t
q, t
r) -> t
q forall a. a -> [a] -> [a]
: t
r forall a. a -> [a] -> [a]
: t -> [t] -> [t]
splitb t
p [t]
ns
splitb t
_ [t]
_ = []
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. Integral a => a -> Integer
toInteger (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. Integral a => a -> Integer
toInteger (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 forall a. Integral a => a -> a -> (a, a)
`quotRem` Integer
maxInt of
(Integer
x, Integer
y)
| Int
q 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 = 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 forall a. Integral a => a -> a -> (a, a)
`quotRem` Integer
maxInt of
(Integer
x, Integer
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 = 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
Data.Monoid.mempty
int :: Int -> Builder
int :: Int -> Builder
int Int
x | Int
base forall a. Eq a => a -> a -> Bool
== Int
10 = forall a. Integral a => a -> Builder
decimal Int
x
| Bool
otherwise = forall a. Integral a => a -> Builder
hexadecimal Int
x
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
hexDigit Int
n
| Bool
otherwise = t -> Int -> Builder
loop (t
dforall a. Num a => a -> a -> a
-t
1) Int
q Builder -> Builder -> 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
word8ToWord16 :: Word8 -> Word16
word8ToWord16 :: Word8 -> Word16
word8ToWord16 = forall a b. (Integral a, Num b) => a -> b
fromIntegral