module Data.Text.Builder.Linear.Dec.Unbounded (
(|>$$),
($$<|),
)
where
import Data.Bits (Bits (..), FiniteBits (..))
import Data.Text.Array qualified as A
import Data.Word (Word64)
import GHC.Exts (
Int (..),
Int#,
State#,
Word (..),
Word#,
word2Int#,
(-#),
)
import GHC.Num.BigNat qualified as BN
import GHC.Num.Integer qualified as I
import GHC.Num.Natural qualified as N
import GHC.Ptr (plusPtr)
import GHC.ST (ST (..))
import Data.Text.Builder.Linear.Array (unsafeReplicate)
import Data.Text.Builder.Linear.Core (Buffer)
import Data.Text.Builder.Linear.Dec.Bounded (digits, maxDecLen, quotRem100)
import Data.Text.Builder.Linear.Dec.Bounded qualified as Bounded
import Data.Text.Builder.Linear.Internal (appendBounded', prependBounded')
(|>$$) ∷ Integral a ⇒ Buffer ⊸ a → Buffer
infixl 6 |>$$
Buffer
buffer |>$$ :: forall a. Integral a => Buffer %1 -> a -> Buffer
|>$$ a
n = case a -> Integer
forall a. Integral a => a -> Integer
toInteger a
n of
!Integer
n' →
Int
-> (forall s x.
((MArray s -> Int -> ST s Int) -> ST s x)
-> ((MArray s -> Int -> ST s Int) -> ST s x) -> ST s x)
-> Buffer
%1 -> Buffer
appendBounded'
(Integer -> Int
maxIntegerDecLen Integer
n')
(Integer
-> ((MArray s -> Int -> ST s Int) -> ST s x)
-> ((MArray s -> Int -> ST s Int) -> ST s x)
-> ST s x
forall s x.
Integer
-> ((MArray s -> Int -> ST s Int) -> ST s x)
-> ((MArray s -> Int -> ST s Int) -> ST s x)
-> ST s x
unsafeAppendDec Integer
n')
Buffer
buffer
{-# INLINEABLE (|>$$) #-}
unsafeAppendDec
∷ ∀ s x
. Integer
→ ((A.MArray s → Int → ST s Int) → ST s x)
→ ((A.MArray s → Int → ST s Int) → ST s x)
→ ST s x
unsafeAppendDec :: forall s x.
Integer
-> ((MArray s -> Int -> ST s Int) -> ST s x)
-> ((MArray s -> Int -> ST s Int) -> ST s x)
-> ST s x
unsafeAppendDec Integer
n = case Integer
n of
I.IS Int#
i# → \(MArray s -> Int -> ST s Int) -> ST s x
append (MArray s -> Int -> ST s Int) -> ST s x
_ → (MArray s -> Int -> ST s Int) -> ST s x
append (\MArray s
marr Int
off → MArray s -> Int -> Int -> ST s Int
forall a s.
(Integral a, FiniteBits a) =>
MArray s -> Int -> a -> ST s Int
Bounded.unsafeAppendDec MArray s
marr Int
off (Int# -> Int
I# Int#
i#))
Integer
_ → \(MArray s -> Int -> ST s Int) -> ST s x
_ (MArray s -> Int -> ST s Int) -> ST s x
prepend → (MArray s -> Int -> ST s Int) -> ST s x
prepend (\MArray s
marr Int
off → MArray s -> Int -> Integer -> ST s Int
forall s. MArray s -> Int -> Integer -> ST s Int
unsafePrependDec MArray s
marr Int
off Integer
n)
{-# INLINEABLE unsafeAppendDec #-}
($$<|) ∷ Integral a ⇒ a → Buffer ⊸ Buffer
infixr 6 $$<|
a
n $$<| :: forall a. Integral a => a -> Buffer %1 -> Buffer
$$<| Buffer
buffer = case a -> Integer
forall a. Integral a => a -> Integer
toInteger a
n of
!Integer
n' →
Int
-> (forall s. MArray s -> Int -> ST s Int) -> Buffer %1 -> Buffer
prependBounded'
(Integer -> Int
maxIntegerDecLen Integer
n')
(\MArray s
dst Int
dstOff → MArray s -> Int -> Integer -> ST s Int
forall s. MArray s -> Int -> Integer -> ST s Int
unsafePrependDec MArray s
dst Int
dstOff Integer
n')
Buffer
buffer
{-# INLINEABLE ($$<|) #-}
unsafePrependDec ∷ ∀ s. A.MArray s → Int → Integer → ST s Int
unsafePrependDec :: forall s. MArray s -> Int -> Integer -> ST s Int
unsafePrependDec MArray s
marr off :: Int
off@(I# Int#
off#) Integer
n = case Integer
n of
I.IS Int#
i# → MArray s -> Int -> Int -> ST s Int
forall s a.
(Integral a, FiniteBits a) =>
MArray s -> Int -> a -> ST s Int
Bounded.unsafePrependDec MArray s
marr Int
off (Int# -> Int
I# Int#
i#)
Integer
_ → MArray s -> DigitsWriter s
forall s. MArray s -> DigitsWriter s
unsafePrependBigNatDec MArray s
marr (Int#
off# Int# -> Int# -> Int#
-# Int#
1#) (Integer -> BigNat#
integerToBigNat# Integer
n) ST s Int -> (Int -> ST s Int) -> ST s Int
forall a b. ST s a -> (a -> ST s b) -> ST s b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Int -> ST s Int
prependSign
where
prependSign :: Int -> ST s Int
prependSign !Int
off' =
if Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
0
then do
MArray s -> Int -> Word8 -> ST s ()
forall s. MArray s -> Int -> Word8 -> ST s ()
A.unsafeWrite MArray s
marr (Int
off' Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Word8
0x2d
Int -> ST s Int
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
off' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
else Int -> ST s Int
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
off')
{-# INLINEABLE unsafePrependDec #-}
type DigitsWriter s = Int# → BN.BigNat# → ST s Int
unsafePrependBigNatDec ∷ ∀ s. A.MArray s → DigitsWriter s
unsafePrependBigNatDec :: forall s. MArray s -> DigitsWriter s
unsafePrependBigNatDec MArray s
marr !Int#
off0 !BigNat#
n0
| BigNat# -> Word
BN.bigNatSize BigNat#
n0 Word -> Word -> Bool
forall a. Ord a => a -> a -> Bool
< Word
hugeSizeThreshold = MArray s -> DigitsWriter s
forall s. MArray s -> DigitsWriter s
prependSmallNat MArray s
marr Int#
off0 BigNat#
n0
| Bool
otherwise = MArray s -> DigitsWriter s
forall s. MArray s -> DigitsWriter s
prependHugeNat MArray s
marr Int#
off0 BigNat#
n0
where
hugeSizeThreshold ∷ Word
hugeSizeThreshold :: Word
hugeSizeThreshold = Word
80
prependSmallNat ∷ ∀ s. A.MArray s → DigitsWriter s
prependSmallNat :: forall s. MArray s -> DigitsWriter s
prependSmallNat MArray s
marr = DigitsWriter s
go
where
!(# Word#
power, Word#
poweredBase, BigNat#
_poweredBase² #) = (# #) -> (# Word#, Word#, BigNat# #)
selectPower (# #)
go ∷ DigitsWriter s
go :: DigitsWriter s
go !Int#
o1 !BigNat#
n = case BigNat#
n BigNat# -> Word# -> (# BigNat#, Word# #)
`BN.bigNatQuotRemWord#` Word#
poweredBase of
(# BigNat#
q, Word#
r #) → do
!Int
o2 ← MArray s -> Int -> Word -> ST s Int
forall s. MArray s -> Int -> Word -> ST s Int
unsafePrependWordDec MArray s
marr (Int# -> Int
I# Int#
o1) (Word# -> Word
W# Word#
r)
if BigNat# -> Bool
BN.bigNatIsZero BigNat#
q
then Int -> ST s Int
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
o2
else do
let !o3 :: Int#
o3 = Int#
o1 Int# -> Int# -> Int#
-# (Word# -> Int#
word2Int# Word#
power Int# -> Int# -> Int#
-# Int#
1#)
MArray s -> Int -> Int -> ST s ()
forall s. MArray s -> Int -> Int -> ST s ()
padWithZeros MArray s
marr (Int# -> Int
I# Int#
o3) (Int
o2 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int# -> Int
I# Int#
o3)
DigitsWriter s
go (Int#
o3 Int# -> Int# -> Int#
-# Int#
1#) BigNat#
q
type DigitsWriter# s = Int# → BN.BigNat# → State# s → (# State# s, Int# #)
prependHugeNat ∷ ∀ s. A.MArray s → DigitsWriter s
prependHugeNat :: forall s. MArray s -> DigitsWriter s
prependHugeNat MArray s
marr Int#
off BigNat#
n = STRep s Int -> ST s Int
forall s a. STRep s a -> ST s a
ST (STRep s Int -> ST s Int) -> STRep s Int -> ST s Int
forall a b. (a -> b) -> a -> b
$ \State# s
s1 →
case (Bool -> DigitsWriter# s) -> BigNat# -> DigitsWriter# s
go Bool -> DigitsWriter# s
prependTiny# BigNat#
poweredBase² Int#
off BigNat#
n State# s
s1 of
(# State# s
s2, Int#
off'# #) → (# State# s
s2, Int# -> Int
I# Int#
off'# #)
where
!(# Word#
power, Word#
poweredBase, BigNat#
poweredBase² #) = (# #) -> (# Word#, Word#, BigNat# #)
selectPower (# #)
go ∷ (Bool → DigitsWriter# s) → BN.BigNat# → DigitsWriter# s
go :: (Bool -> DigitsWriter# s) -> BigNat# -> DigitsWriter# s
go !Bool -> DigitsWriter# s
write !BigNat#
pow10 !Int#
o !BigNat#
n# =
if BigNat# -> BigNat# -> Bool
BN.bigNatLt BigNat#
n# BigNat#
pow10
then Bool -> DigitsWriter# s
write Bool
True Int#
o BigNat#
n#
else (Bool -> DigitsWriter# s) -> BigNat# -> DigitsWriter# s
go ((Bool -> DigitsWriter# s) -> BigNat# -> Bool -> DigitsWriter# s
scaleWriter Bool -> DigitsWriter# s
write BigNat#
pow10) (BigNat# -> BigNat# -> BigNat#
BN.bigNatMul BigNat#
pow10 BigNat#
pow10) Int#
o BigNat#
n#
scaleWriter ∷ (Bool → DigitsWriter# s) → BN.BigNat# → Bool → DigitsWriter# s
scaleWriter :: (Bool -> DigitsWriter# s) -> BigNat# -> Bool -> DigitsWriter# s
scaleWriter !Bool -> DigitsWriter# s
write !BigNat#
pow10 = \ !Bool
high !Int#
o1 !BigNat#
n# State# s
s1 →
case BigNat# -> BigNat# -> (# BigNat#, BigNat# #)
BN.bigNatQuotRem# BigNat#
n# BigNat#
pow10 of
(# BigNat#
q, BigNat#
r #)
| Bool
high Bool -> Bool -> Bool
&& BigNat# -> Bool
BN.bigNatIsZero BigNat#
q → Bool -> DigitsWriter# s
write Bool
high Int#
o1 BigNat#
r State# s
s1
| Bool
otherwise → case Bool -> DigitsWriter# s
write Bool
False Int#
o1 BigNat#
r State# s
s1 of
(# State# s
s2, Int#
o2 #) → Bool -> DigitsWriter# s
write Bool
high (Int#
o2 Int# -> Int# -> Int#
-# Int#
1#) BigNat#
q State# s
s2
prependTiny# ∷ Bool → DigitsWriter# s
prependTiny# :: Bool -> DigitsWriter# s
prependTiny# !Bool
high !Int#
o1 !BigNat#
n# = case Bool -> DigitsWriter s
prependTiny Bool
high Int#
o1 BigNat#
n# of
ST STRep s Int
f → \State# s
s1 → case STRep s Int
f State# s
s1 of
(# State# s
s2, I# Int#
o2 #) → (# State# s
s2, Int#
o2 #)
{-# INLINE prependTiny #-}
prependTiny ∷ Bool → DigitsWriter s
prependTiny :: Bool -> DigitsWriter s
prependTiny !Bool
high !Int#
o1 !BigNat#
n# =
case BigNat# -> Word# -> (# BigNat#, Word# #)
BN.bigNatQuotRemWord# BigNat#
n# Word#
poweredBase of
(# BigNat#
q, Word#
r #) → do
!Int
o2 ← MArray s -> Int -> Word -> ST s Int
forall s. MArray s -> Int -> Word -> ST s Int
unsafePrependWordDec MArray s
marr (Int# -> Int
I# Int#
o1) (Word# -> Word
W# Word#
r)
if Bool
high Bool -> Bool -> Bool
&& BigNat# -> Bool
BN.bigNatIsZero BigNat#
q
then Int -> ST s Int
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
o2
else do
let !o3 :: Int
o3 = Int# -> Int
I# Int#
o1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- (Word -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word# -> Word
W# Word#
power) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)
MArray s -> Int -> Int -> ST s ()
forall s. MArray s -> Int -> Int -> ST s ()
padWithZeros MArray s
marr Int
o3 (Int
o2 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
o3)
!Int
o4 ← MArray s -> Int -> Word -> ST s Int
forall s. MArray s -> Int -> Word -> ST s Int
unsafePrependWordDec MArray s
marr (Int
o3 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) (BigNat# -> Word
BN.bigNatToWord BigNat#
q)
if Bool
high
then Int -> ST s Int
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
o4
else do
let !o5 :: Int
o5 = Int
o3 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Word -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word# -> Word
W# Word#
power)
MArray s -> Int -> Int -> ST s ()
forall s. MArray s -> Int -> Int -> ST s ()
padWithZeros MArray s
marr Int
o5 (Int
o4 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
o5)
Int -> ST s Int
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
o5
unsafePrependWordDec ∷ ∀ s. A.MArray s → Int → Word → ST s Int
unsafePrependWordDec :: forall s. MArray s -> Int -> Word -> ST s Int
unsafePrependWordDec = MArray s -> Int -> Word -> ST s Int
forall a s.
(Integral a, FiniteBits a) =>
MArray s -> Int -> a -> ST s Int
f
where
f :: MArray s -> Int -> a -> ST s Int
f MArray s
marr !Int
o !a
k
| a
k a -> a -> Bool
forall a. Ord a => a -> a -> Bool
>= a
10 = do
let (a
q, a
r) = a -> (a, a)
forall a. (Integral a, FiniteBits a) => a -> (a, a)
quotRem100 a
k
MArray s -> Int -> Ptr Word8 -> Int -> ST s ()
forall s. MArray s -> Int -> Ptr Word8 -> Int -> ST s ()
A.copyFromPointer MArray s
marr (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) (CString
digits CString -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` (a -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
r Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftL` Int
1)) Int
2
if a
k a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
100 then Int -> ST s Int
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) else MArray s -> Int -> a -> ST s Int
f MArray s
marr (Int
o Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2) a
q
| Bool
otherwise = do
MArray s -> Int -> Word8 -> ST s ()
forall s. MArray s -> Int -> Word8 -> ST s ()
A.unsafeWrite MArray s
marr Int
o (a -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a
0x30 a -> a -> a
forall a. Num a => a -> a -> a
+ a
k))
Int -> ST s Int
forall a. a -> ST s a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
o
maxIntegerDecLen ∷ Integer → Int
maxIntegerDecLen :: Integer -> Int
maxIntegerDecLen Integer
a = case Integer
a of
I.IS Int#
i# → Int -> Int
forall a. FiniteBits a => a -> Int
maxDecLen (Int# -> Int
I# Int#
i#)
I.IP BigNat#
n# → BigNat# -> Int
maxBitNatDecLen BigNat#
n#
I.IN BigNat#
n# → Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ BigNat# -> Int
maxBitNatDecLen BigNat#
n#
{-# INLINEABLE maxIntegerDecLen #-}
maxBitNatDecLen ∷ BN.BigNat# → Int
maxBitNatDecLen :: BigNat# -> Int
maxBitNatDecLen BigNat#
n#
| Int -> Int -> Int
forall a. Integral a => a -> a -> a
rem (forall a. FiniteBits a => a -> Int
finiteBitSize @Word Word
0) Int
16 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 =
Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Word -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (BigNat# -> Word
BN.bigNatSize BigNat#
n# Word -> Word -> Word
forall a. Num a => a -> a -> a
* Word -> Int -> Word
forall a. Bits a => a -> Int -> a
shiftR (Int -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. FiniteBits a => a -> Int
finiteBitSize @Word Word
0) Word -> Word -> Word
forall a. Num a => a -> a -> a
* Word
5) Int
4)
| Bool
otherwise =
Int
1
Int -> Int -> Int
forall a. Num a => a -> a -> a
+ forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word64
( (Word -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (BigNat# -> Word
BN.bigNatSize BigNat#
n#) Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. FiniteBits a => a -> Int
finiteBitSize @Word Word
0) Word64 -> Word64 -> Word64
forall a. Num a => a -> a -> a
* Word64
5)
Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
4
)
{-# INLINEABLE maxBitNatDecLen #-}
integerToBigNat# ∷ Integer → BN.BigNat#
integerToBigNat# :: Integer -> BigNat#
integerToBigNat# Integer
n = case Integer -> (# Int#, BigNat# #)
I.integerToBigNatSign# Integer
n of
(# Int#
_, BigNat#
n# #) → BigNat#
n#
{-# INLINE integerToBigNat# #-}
selectPower ∷ (# #) → (# Word#, Word#, BN.BigNat# #)
selectPower :: (# #) -> (# Word#, Word#, BigNat# #)
selectPower (# #)
_ = case forall a. FiniteBits a => a -> Int
finiteBitSize @Word Word
0 of
Int
64 → (# Word#
19##, Word#
10000000000000000000##, Natural -> BigNat#
N.naturalToBigNat# Natural
tenPower38 #)
Int
_ → (# Word#
9##, Word#
1000000000##, Natural -> BigNat#
N.naturalToBigNat# Natural
tenPower18 #)
tenPower18 ∷ N.Natural
tenPower18 :: Natural
tenPower18 = Natural
1e18
{-# NOINLINE tenPower18 #-}
tenPower38 ∷ N.Natural
tenPower38 :: Natural
tenPower38 = Natural
1e38
{-# NOINLINE tenPower38 #-}
padWithZeros ∷ ∀ s. A.MArray s → Int → Int → ST s ()
padWithZeros :: forall s. MArray s -> Int -> Int -> ST s ()
padWithZeros MArray s
marr Int
off Int
count = MArray s -> Int -> Int -> Int -> ST s ()
forall s. MArray s -> Int -> Int -> Int -> ST s ()
unsafeReplicate MArray s
marr Int
off Int
count Int
0x30
{-# INLINE padWithZeros #-}