{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE GHCForeignImportPrim #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE UnliftedFFITypes #-}
{-# LANGUAGE RebindableSyntax #-}
{-# LANGUAGE NegativeLiterals #-}
{-# LANGUAGE ExplicitForAll #-}
module GHC.Integer.Type where
#include "MachDeps.h"
#include "HsIntegerGmp.h"
#if !(defined(SIZEOF_LONG) && defined(SIZEOF_HSWORD) \
&& defined(WORD_SIZE_IN_BITS))
# error missing defines
#endif
import GHC.Classes
import GHC.Magic
import GHC.Prim
import GHC.Types
#if WORD_SIZE_IN_BITS < 64
import GHC.IntWord64
#endif
default ()
#define CONSTANT_FOLDED NOINLINE
type GmpLimb = Word
type GmpLimb# = Word#
type GmpSize = Int
type GmpSize# = Int#
narrowGmpSize# :: Int# -> Int#
#if SIZEOF_LONG == SIZEOF_HSWORD
narrowGmpSize# x = x
#elif (SIZEOF_LONG == 4) && (SIZEOF_HSWORD == 8)
narrowGmpSize# = narrow32Int#
#endif
type GmpBitCnt = Word
type GmpBitCnt# = Word#
type CInt = Int
type CInt# = Int#
narrowCInt# :: Int# -> Int#
narrowCInt# = narrow32Int#
gmpLimbBits :: Word
gmpLimbBits = W# WORD_SIZE_IN_BITS##
#if WORD_SIZE_IN_BITS == 64
# define GMP_LIMB_SHIFT 3
# define GMP_LIMB_BYTES 8
# define GMP_LIMB_BITS 64
# define INT_MINBOUND -0x8000000000000000
# define INT_MAXBOUND 0x7fffffffffffffff
# define ABS_INT_MINBOUND 0x8000000000000000
# define SQRT_INT_MAXBOUND 0xb504f333
#elif WORD_SIZE_IN_BITS == 32
# define GMP_LIMB_SHIFT 2
# define GMP_LIMB_BYTES 4
# define GMP_LIMB_BITS 32
# define INT_MINBOUND -0x80000000
# define INT_MAXBOUND 0x7fffffff
# define ABS_INT_MINBOUND 0x80000000
# define SQRT_INT_MAXBOUND 0xb504
#else
# error unsupported WORD_SIZE_IN_BITS config
#endif
data BigNat = BN# ByteArray#
instance Eq BigNat where
(==) = eqBigNat
instance Ord BigNat where
compare = compareBigNat
data Integer = S# !Int#
| Jp# {-# UNPACK #-} !BigNat
| Jn# {-# UNPACK #-} !BigNat
instance Eq Integer where
(==) = eqInteger
(/=) = neqInteger
instance Ord Integer where
compare = compareInteger
(>) = gtInteger
(>=) = geInteger
(<) = ltInteger
(<=) = leInteger
mkInteger :: Bool
-> [Int]
-> Integer
mkInteger nonNegative is
| nonNegative = f is
| True = negateInteger (f is)
where
f [] = S# 0#
f (I# i : is') = smallInteger (i `andI#` 0x7fffffff#) `orInteger`
shiftLInteger (f is') 31#
{-# CONSTANT_FOLDED mkInteger #-}
isValidInteger# :: Integer -> Int#
isValidInteger# (S# _) = 1#
isValidInteger# (Jp# bn)
= isValidBigNat# bn `andI#` (bn `gtBigNatWord#` INT_MAXBOUND##)
isValidInteger# (Jn# bn)
= isValidBigNat# bn `andI#` (bn `gtBigNatWord#` ABS_INT_MINBOUND##)
smallInteger :: Int# -> Integer
smallInteger i# = S# i#
{-# CONSTANT_FOLDED smallInteger #-}
#if WORD_SIZE_IN_BITS < 64
int64ToInteger :: Int64# -> Integer
int64ToInteger i
| isTrue# (i `leInt64#` intToInt64# 0x7FFFFFFF#)
, isTrue# (i `geInt64#` intToInt64# -0x80000000#)
= S# (int64ToInt# i)
| isTrue# (i `geInt64#` intToInt64# 0#)
= Jp# (word64ToBigNat (int64ToWord64# i))
| True
= Jn# (word64ToBigNat (int64ToWord64# (negateInt64# i)))
{-# CONSTANT_FOLDED int64ToInteger #-}
word64ToInteger :: Word64# -> Integer
word64ToInteger w
| isTrue# (w `leWord64#` wordToWord64# 0x7FFFFFFF##)
= S# (int64ToInt# (word64ToInt64# w))
| True
= Jp# (word64ToBigNat w)
{-# CONSTANT_FOLDED word64ToInteger #-}
integerToInt64 :: Integer -> Int64#
integerToInt64 (S# i#) = intToInt64# i#
integerToInt64 (Jp# bn) = word64ToInt64# (bigNatToWord64 bn)
integerToInt64 (Jn# bn) = negateInt64# (word64ToInt64# (bigNatToWord64 bn))
{-# CONSTANT_FOLDED integerToInt64 #-}
integerToWord64 :: Integer -> Word64#
integerToWord64 (S# i#) = int64ToWord64# (intToInt64# i#)
integerToWord64 (Jp# bn) = bigNatToWord64 bn
integerToWord64 (Jn# bn)
= int64ToWord64# (negateInt64# (word64ToInt64# (bigNatToWord64 bn)))
{-# CONSTANT_FOLDED integerToWord64 #-}
#if GMP_LIMB_BITS == 32
word64ToBigNat :: Word64# -> BigNat
word64ToBigNat w64 = wordToBigNat2 wh# wl#
where
wh# = word64ToWord# (uncheckedShiftRL64# w64 32#)
wl# = word64ToWord# w64
bigNatToWord64 :: BigNat -> Word64#
bigNatToWord64 bn
| isTrue# (sizeofBigNat# bn ># 1#)
= let wh# = wordToWord64# (indexBigNat# bn 1#)
in uncheckedShiftL64# wh# 32# `or64#` wl#
| True = wl#
where
wl# = wordToWord64# (bigNatToWord bn)
#endif
#endif
integerToInt :: Integer -> Int#
integerToInt (S# i#) = i#
integerToInt (Jp# bn) = bigNatToInt bn
integerToInt (Jn# bn) = negateInt# (bigNatToInt bn)
{-# CONSTANT_FOLDED integerToInt #-}
hashInteger :: Integer -> Int#
hashInteger = integerToInt
integerToWord :: Integer -> Word#
integerToWord (S# i#) = int2Word# i#
integerToWord (Jp# bn) = bigNatToWord bn
integerToWord (Jn# bn) = int2Word# (negateInt# (bigNatToInt bn))
{-# CONSTANT_FOLDED integerToWord #-}
wordToInteger :: Word# -> Integer
wordToInteger w#
| isTrue# (i# >=# 0#) = S# i#
| True = Jp# (wordToBigNat w#)
where
i# = word2Int# w#
{-# CONSTANT_FOLDED wordToInteger #-}
wordToNegInteger :: Word# -> Integer
wordToNegInteger w#
| isTrue# (i# <=# 0#) = S# i#
| True = Jn# (wordToBigNat w#)
where
i# = negateInt# (word2Int# w#)
compareInteger :: Integer -> Integer -> Ordering
compareInteger (Jn# x) (Jn# y) = compareBigNat y x
compareInteger (S# x) (S# y) = compareInt# x y
compareInteger (Jp# x) (Jp# y) = compareBigNat x y
compareInteger (Jn# _) _ = LT
compareInteger (S# _) (Jp# _) = LT
compareInteger (S# _) (Jn# _) = GT
compareInteger (Jp# _) _ = GT
{-# CONSTANT_FOLDED compareInteger #-}
isNegInteger# :: Integer -> Int#
isNegInteger# (S# i#) = i# <# 0#
isNegInteger# (Jp# _) = 0#
isNegInteger# (Jn# _) = 1#
neqInteger :: Integer -> Integer -> Bool
neqInteger x y = isTrue# (neqInteger# x y)
eqInteger, leInteger, ltInteger, gtInteger, geInteger
:: Integer -> Integer -> Bool
eqInteger x y = isTrue# (eqInteger# x y)
leInteger x y = isTrue# (leInteger# x y)
ltInteger x y = isTrue# (ltInteger# x y)
gtInteger x y = isTrue# (gtInteger# x y)
geInteger x y = isTrue# (geInteger# x y)
eqInteger#, neqInteger#, leInteger#, ltInteger#, gtInteger#, geInteger#
:: Integer -> Integer -> Int#
eqInteger# (S# x#) (S# y#) = x# ==# y#
eqInteger# (Jn# x) (Jn# y) = eqBigNat# x y
eqInteger# (Jp# x) (Jp# y) = eqBigNat# x y
eqInteger# _ _ = 0#
{-# CONSTANT_FOLDED eqInteger# #-}
neqInteger# (S# x#) (S# y#) = x# /=# y#
neqInteger# (Jn# x) (Jn# y) = neqBigNat# x y
neqInteger# (Jp# x) (Jp# y) = neqBigNat# x y
neqInteger# _ _ = 1#
{-# CONSTANT_FOLDED neqInteger# #-}
gtInteger# (S# x#) (S# y#) = x# ># y#
gtInteger# x y | inline compareInteger x y == GT = 1#
gtInteger# _ _ = 0#
{-# CONSTANT_FOLDED gtInteger# #-}
leInteger# (S# x#) (S# y#) = x# <=# y#
leInteger# x y | inline compareInteger x y /= GT = 1#
leInteger# _ _ = 0#
{-# CONSTANT_FOLDED leInteger# #-}
ltInteger# (S# x#) (S# y#) = x# <# y#
ltInteger# x y | inline compareInteger x y == LT = 1#
ltInteger# _ _ = 0#
{-# CONSTANT_FOLDED ltInteger# #-}
geInteger# (S# x#) (S# y#) = x# >=# y#
geInteger# x y | inline compareInteger x y /= LT = 1#
geInteger# _ _ = 0#
{-# CONSTANT_FOLDED geInteger# #-}
absInteger :: Integer -> Integer
absInteger (Jn# n) = Jp# n
absInteger (S# INT_MINBOUND#) = Jp# (wordToBigNat ABS_INT_MINBOUND##)
absInteger (S# i#) | isTrue# (i# <# 0#) = S# (negateInt# i#)
absInteger i@(S# _) = i
absInteger i@(Jp# _) = i
{-# CONSTANT_FOLDED absInteger #-}
signumInteger :: Integer -> Integer
signumInteger j = S# (signumInteger# j)
{-# CONSTANT_FOLDED signumInteger #-}
signumInteger# :: Integer -> Int#
signumInteger# (Jn# _) = -1#
signumInteger# (S# i#) = sgnI# i#
signumInteger# (Jp# _ ) = 1#
negateInteger :: Integer -> Integer
negateInteger (Jn# n) = Jp# n
negateInteger (S# INT_MINBOUND#) = Jp# (wordToBigNat ABS_INT_MINBOUND##)
negateInteger (S# i#) = S# (negateInt# i#)
negateInteger (Jp# bn)
| isTrue# (eqBigNatWord# bn ABS_INT_MINBOUND##) = S# INT_MINBOUND#
| True = Jn# bn
{-# CONSTANT_FOLDED negateInteger #-}
plusInteger :: Integer -> Integer -> Integer
plusInteger x (S# 0#) = x
plusInteger (S# 0#) y = y
plusInteger (S# x#) (S# y#)
= case addIntC# x# y# of
(# z#, 0# #) -> S# z#
(# 0#, _ #) -> Jn# (wordToBigNat2 1## 0##)
(# z#, _ #)
| isTrue# (z# ># 0#) -> Jn# (wordToBigNat ( (int2Word# (negateInt# z#))))
| True -> Jp# (wordToBigNat ( (int2Word# z#)))
plusInteger y@(S# _) x = plusInteger x y
plusInteger (Jp# x) (Jp# y) = Jp# (plusBigNat x y)
plusInteger (Jn# x) (Jn# y) = Jn# (plusBigNat x y)
plusInteger (Jp# x) (S# y#)
| isTrue# (y# >=# 0#) = Jp# (plusBigNatWord x (int2Word# y#))
| True = bigNatToInteger (minusBigNatWord x (int2Word#
(negateInt# y#)))
plusInteger (Jn# x) (S# y#)
| isTrue# (y# >=# 0#) = bigNatToNegInteger (minusBigNatWord x (int2Word# y#))
| True = Jn# (plusBigNatWord x (int2Word# (negateInt# y#)))
plusInteger y@(Jn# _) x@(Jp# _) = plusInteger x y
plusInteger (Jp# x) (Jn# y)
= case compareBigNat x y of
LT -> bigNatToNegInteger (minusBigNat y x)
EQ -> S# 0#
GT -> bigNatToInteger (minusBigNat x y)
{-# CONSTANT_FOLDED plusInteger #-}
minusInteger :: Integer -> Integer -> Integer
minusInteger x (S# 0#) = x
minusInteger (S# x#) (S# y#)
= case subIntC# x# y# of
(# z#, 0# #) -> S# z#
(# 0#, _ #) -> Jn# (wordToBigNat2 1## 0##)
(# z#, _ #)
| isTrue# (z# ># 0#) -> Jn# (wordToBigNat ( (int2Word# (negateInt# z#))))
| True -> Jp# (wordToBigNat ( (int2Word# z#)))
minusInteger (S# x#) (Jp# y)
| isTrue# (x# >=# 0#) = bigNatToNegInteger (minusBigNatWord y (int2Word# x#))
| True = Jn# (plusBigNatWord y (int2Word# (negateInt# x#)))
minusInteger (S# x#) (Jn# y)
| isTrue# (x# >=# 0#) = Jp# (plusBigNatWord y (int2Word# x#))
| True = bigNatToInteger (minusBigNatWord y (int2Word#
(negateInt# x#)))
minusInteger (Jp# x) (Jp# y)
= case compareBigNat x y of
LT -> bigNatToNegInteger (minusBigNat y x)
EQ -> S# 0#
GT -> bigNatToInteger (minusBigNat x y)
minusInteger (Jp# x) (Jn# y) = Jp# (plusBigNat x y)
minusInteger (Jn# x) (Jp# y) = Jn# (plusBigNat x y)
minusInteger (Jn# x) (Jn# y)
= case compareBigNat x y of
LT -> bigNatToInteger (minusBigNat y x)
EQ -> S# 0#
GT -> bigNatToNegInteger (minusBigNat x y)
minusInteger (Jp# x) (S# y#)
| isTrue# (y# >=# 0#) = bigNatToInteger (minusBigNatWord x (int2Word# y#))
| True = Jp# (plusBigNatWord x (int2Word# (negateInt# y#)))
minusInteger (Jn# x) (S# y#)
| isTrue# (y# >=# 0#) = Jn# (plusBigNatWord x (int2Word# y#))
| True = bigNatToNegInteger (minusBigNatWord x
(int2Word# (negateInt# y#)))
{-# CONSTANT_FOLDED minusInteger #-}
timesInteger :: Integer -> Integer -> Integer
timesInteger !_ (S# 0#) = S# 0#
timesInteger (S# 0#) _ = S# 0#
timesInteger x (S# 1#) = x
timesInteger (S# 1#) y = y
timesInteger x (S# -1#) = negateInteger x
timesInteger (S# -1#) y = negateInteger y
timesInteger (S# x#) (S# y#)
= case mulIntMayOflo# x# y# of
0# -> S# (x# *# y#)
_ -> timesInt2Integer x# y#
timesInteger x@(S# _) y = timesInteger y x
timesInteger (Jp# x) (Jp# y) = Jp# (timesBigNat x y)
timesInteger (Jp# x) (Jn# y) = Jn# (timesBigNat x y)
timesInteger (Jp# x) (S# y#)
| isTrue# (y# >=# 0#) = Jp# (timesBigNatWord x (int2Word# y#))
| True = Jn# (timesBigNatWord x (int2Word# (negateInt# y#)))
timesInteger (Jn# x) (Jn# y) = Jp# (timesBigNat x y)
timesInteger (Jn# x) (Jp# y) = Jn# (timesBigNat x y)
timesInteger (Jn# x) (S# y#)
| isTrue# (y# >=# 0#) = Jn# (timesBigNatWord x (int2Word# y#))
| True = Jp# (timesBigNatWord x (int2Word# (negateInt# y#)))
{-# CONSTANT_FOLDED timesInteger #-}
sqrInteger :: Integer -> Integer
sqrInteger (S# INT_MINBOUND#) = timesInt2Integer INT_MINBOUND# INT_MINBOUND#
sqrInteger (S# j#) | isTrue# (absI# j# <=# SQRT_INT_MAXBOUND#) = S# (j# *# j#)
sqrInteger (S# j#) = timesInt2Integer j# j#
sqrInteger (Jp# bn) = Jp# (sqrBigNat bn)
sqrInteger (Jn# bn) = Jp# (sqrBigNat bn)
timesInt2Integer :: Int# -> Int# -> Integer
timesInt2Integer x# y# = case (# isTrue# (x# >=# 0#), isTrue# (y# >=# 0#) #) of
(# False, False #) -> case timesWord2# (int2Word# (negateInt# x#))
(int2Word# (negateInt# y#)) of
(# 0##,l #) -> inline wordToInteger l
(# h ,l #) -> Jp# (wordToBigNat2 h l)
(# True, False #) -> case timesWord2# (int2Word# x#)
(int2Word# (negateInt# y#)) of
(# 0##,l #) -> wordToNegInteger l
(# h ,l #) -> Jn# (wordToBigNat2 h l)
(# False, True #) -> case timesWord2# (int2Word# (negateInt# x#))
(int2Word# y#) of
(# 0##,l #) -> wordToNegInteger l
(# h ,l #) -> Jn# (wordToBigNat2 h l)
(# True, True #) -> case timesWord2# (int2Word# x#)
(int2Word# y#) of
(# 0##,l #) -> inline wordToInteger l
(# h ,l #) -> Jp# (wordToBigNat2 h l)
bigNatToInteger :: BigNat -> Integer
bigNatToInteger bn
| isTrue# ((sizeofBigNat# bn ==# 1#) `andI#` (i# >=# 0#)) = S# i#
| True = Jp# bn
where
i# = word2Int# (bigNatToWord bn)
bigNatToNegInteger :: BigNat -> Integer
bigNatToNegInteger bn
| isTrue# ((sizeofBigNat# bn ==# 1#) `andI#` (i# <=# 0#)) = S# i#
| True = Jn# bn
where
i# = negateInt# (word2Int# (bigNatToWord bn))
popCountInteger :: Integer -> Int#
popCountInteger (S# i#)
| isTrue# (i# >=# 0#) = popCntI# i#
| True = negateInt# (popCntI# (negateInt# i#))
popCountInteger (Jp# bn) = popCountBigNat bn
popCountInteger (Jn# bn) = negateInt# (popCountBigNat bn)
{-# CONSTANT_FOLDED popCountInteger #-}
bitInteger :: Int# -> Integer
bitInteger i#
| isTrue# (i# <# (GMP_LIMB_BITS# -# 1#)) = S# (uncheckedIShiftL# 1# i#)
| True = Jp# (bitBigNat i#)
{-# CONSTANT_FOLDED bitInteger #-}
testBitInteger :: Integer -> Int# -> Bool
testBitInteger !_ n# | isTrue# (n# <# 0#) = False
testBitInteger (S# i#) n#
| isTrue# (n# <# GMP_LIMB_BITS#) = isTrue# (((uncheckedIShiftL# 1# n#)
`andI#` i#) /=# 0#)
| True = isTrue# (i# <# 0#)
testBitInteger (Jp# bn) n = testBitBigNat bn n
testBitInteger (Jn# bn) n = testBitNegBigNat bn n
{-# CONSTANT_FOLDED testBitInteger #-}
complementInteger :: Integer -> Integer
complementInteger (S# i#) = S# (notI# i#)
complementInteger (Jp# bn) = Jn# (plusBigNatWord bn 1##)
complementInteger (Jn# bn) = Jp# (minusBigNatWord bn 1##)
{-# CONSTANT_FOLDED complementInteger #-}
shiftRInteger :: Integer -> Int# -> Integer
shiftRInteger x 0# = x
shiftRInteger (S# i#) n# = S# (iShiftRA# i# n#)
where
iShiftRA# a b
| isTrue# (b >=# WORD_SIZE_IN_BITS#) = (a <# 0#) *# (-1#)
| True = a `uncheckedIShiftRA#` b
shiftRInteger (Jp# bn) n# = bigNatToInteger (shiftRBigNat bn n#)
shiftRInteger (Jn# bn) n#
= case bigNatToNegInteger (shiftRNegBigNat bn n#) of
S# 0# -> S# -1#
r -> r
{-# CONSTANT_FOLDED shiftRInteger #-}
shiftLInteger :: Integer -> Int# -> Integer
shiftLInteger x 0# = x
shiftLInteger (S# 0#) _ = S# 0#
shiftLInteger (S# 1#) n# = bitInteger n#
shiftLInteger (S# i#) n#
| isTrue# (i# >=# 0#) = bigNatToInteger (shiftLBigNat
(wordToBigNat (int2Word# i#)) n#)
| True = bigNatToNegInteger (shiftLBigNat
(wordToBigNat (int2Word#
(negateInt# i#))) n#)
shiftLInteger (Jp# bn) n# = Jp# (shiftLBigNat bn n#)
shiftLInteger (Jn# bn) n# = Jn# (shiftLBigNat bn n#)
{-# CONSTANT_FOLDED shiftLInteger #-}
orInteger :: Integer -> Integer -> Integer
orInteger (S# 0#) y = y
orInteger x (S# 0#) = x
orInteger (S# -1#) _ = S# -1#
orInteger _ (S# -1#) = S# -1#
orInteger (S# x#) (S# y#) = S# (orI# x# y#)
orInteger (Jp# x) (Jp# y) = Jp# (orBigNat x y)
orInteger (Jn# x) (Jn# y)
= bigNatToNegInteger (plusBigNatWord (andBigNat
(minusBigNatWord x 1##)
(minusBigNatWord y 1##)) 1##)
orInteger x@(Jn# _) y@(Jp# _) = orInteger y x
orInteger (Jp# x) (Jn# y)
= bigNatToNegInteger (plusBigNatWord (andnBigNat (minusBigNatWord y 1##) x)
1##)
orInteger x@(S# _) y = orInteger (unsafePromote x) y
orInteger x y = orInteger x (unsafePromote y)
{-# CONSTANT_FOLDED orInteger #-}
xorInteger :: Integer -> Integer -> Integer
xorInteger (S# 0#) y = y
xorInteger x (S# 0#) = x
xorInteger (S# x#) (S# y#) = S# (xorI# x# y#)
xorInteger (Jp# x) (Jp# y) = bigNatToInteger (xorBigNat x y)
xorInteger (Jn# x) (Jn# y)
= bigNatToInteger (xorBigNat (minusBigNatWord x 1##)
(minusBigNatWord y 1##))
xorInteger x@(Jn# _) y@(Jp# _) = xorInteger y x
xorInteger (Jp# x) (Jn# y)
= bigNatToNegInteger (plusBigNatWord (xorBigNat x (minusBigNatWord y 1##))
1##)
xorInteger x@(S# _) y = xorInteger (unsafePromote x) y
xorInteger x y = xorInteger x (unsafePromote y)
{-# CONSTANT_FOLDED xorInteger #-}
andInteger :: Integer -> Integer -> Integer
andInteger (S# 0#) !_ = S# 0#
andInteger _ (S# 0#) = S# 0#
andInteger (S# -1#) y = y
andInteger x (S# -1#) = x
andInteger (S# x#) (S# y#) = S# (andI# x# y#)
andInteger (Jp# x) (Jp# y) = bigNatToInteger (andBigNat x y)
andInteger (Jn# x) (Jn# y)
= bigNatToNegInteger (plusBigNatWord (orBigNat (minusBigNatWord x 1##)
(minusBigNatWord y 1##)) 1##)
andInteger x@(Jn# _) y@(Jp# _) = andInteger y x
andInteger (Jp# x) (Jn# y)
= bigNatToInteger (andnBigNat x (minusBigNatWord y 1##))
andInteger x@(S# _) y = andInteger (unsafePromote x) y
andInteger x y = andInteger x (unsafePromote y)
{-# CONSTANT_FOLDED andInteger #-}
unsafePromote :: Integer -> Integer
unsafePromote (S# x#)
| isTrue# (x# >=# 0#) = Jp# (wordToBigNat (int2Word# x#))
| True = Jn# (wordToBigNat (int2Word# (negateInt# x#)))
unsafePromote x = x
quotRemInteger :: Integer -> Integer -> (# Integer, Integer #)
quotRemInteger n (S# 1#) = (# n, S# 0# #)
quotRemInteger n (S# -1#) = let !q = negateInteger n in (# q, (S# 0#) #)
quotRemInteger !_ (S# 0#) = (# S# (quotInt# 0# 0#),S# (remInt# 0# 0#) #)
quotRemInteger (S# 0#) _ = (# S# 0#, S# 0# #)
quotRemInteger (S# n#) (S# d#) = case quotRemInt# n# d# of
(# q#, r# #) -> (# S# q#, S# r# #)
quotRemInteger (Jp# n) (Jp# d) = case quotRemBigNat n d of
(# q, r #) -> (# bigNatToInteger q, bigNatToInteger r #)
quotRemInteger (Jp# n) (Jn# d) = case quotRemBigNat n d of
(# q, r #) -> (# bigNatToNegInteger q, bigNatToInteger r #)
quotRemInteger (Jn# n) (Jn# d) = case quotRemBigNat n d of
(# q, r #) -> (# bigNatToInteger q, bigNatToNegInteger r #)
quotRemInteger (Jn# n) (Jp# d) = case quotRemBigNat n d of
(# q, r #) -> (# bigNatToNegInteger q, bigNatToNegInteger r #)
quotRemInteger (Jp# n) (S# d#)
| isTrue# (d# >=# 0#) = case quotRemBigNatWord n (int2Word# d#) of
(# q, r# #) -> (# bigNatToInteger q, inline wordToInteger r# #)
| True = case quotRemBigNatWord n (int2Word# (negateInt# d#)) of
(# q, r# #) -> (# bigNatToNegInteger q, inline wordToInteger r# #)
quotRemInteger (Jn# n) (S# d#)
| isTrue# (d# >=# 0#) = case quotRemBigNatWord n (int2Word# d#) of
(# q, r# #) -> (# bigNatToNegInteger q, wordToNegInteger r# #)
| True = case quotRemBigNatWord n (int2Word# (negateInt# d#)) of
(# q, r# #) -> (# bigNatToInteger q, wordToNegInteger r# #)
quotRemInteger n@(S# _) (Jn# _) = (# S# 0#, n #)
quotRemInteger n@(S# n#) (Jp# d)
| isTrue# (n# ># 0#) = (# S# 0#, n #)
| isTrue# (gtBigNatWord# d (int2Word# (negateInt# n#))) = (# S# 0#, n #)
| True = (# S# -1#, S# 0# #)
{-# CONSTANT_FOLDED quotRemInteger #-}
quotInteger :: Integer -> Integer -> Integer
quotInteger n (S# 1#) = n
quotInteger n (S# -1#) = negateInteger n
quotInteger !_ (S# 0#) = S# (quotInt# 0# 0#)
quotInteger (S# 0#) _ = S# 0#
quotInteger (S# n#) (S# d#) = S# (quotInt# n# d#)
quotInteger (Jp# n) (S# d#)
| isTrue# (d# >=# 0#) = bigNatToInteger (quotBigNatWord n (int2Word# d#))
| True = bigNatToNegInteger (quotBigNatWord n
(int2Word# (negateInt# d#)))
quotInteger (Jn# n) (S# d#)
| isTrue# (d# >=# 0#) = bigNatToNegInteger (quotBigNatWord n (int2Word# d#))
| True = bigNatToInteger (quotBigNatWord n
(int2Word# (negateInt# d#)))
quotInteger (Jp# n) (Jp# d) = bigNatToInteger (quotBigNat n d)
quotInteger (Jp# n) (Jn# d) = bigNatToNegInteger (quotBigNat n d)
quotInteger (Jn# n) (Jp# d) = bigNatToNegInteger (quotBigNat n d)
quotInteger (Jn# n) (Jn# d) = bigNatToInteger (quotBigNat n d)
quotInteger n d = case inline quotRemInteger n d of (# q, _ #) -> q
{-# CONSTANT_FOLDED quotInteger #-}
remInteger :: Integer -> Integer -> Integer
remInteger !_ (S# 1#) = S# 0#
remInteger _ (S# -1#) = S# 0#
remInteger _ (S# 0#) = S# (remInt# 0# 0#)
remInteger (S# 0#) _ = S# 0#
remInteger (S# n#) (S# d#) = S# (remInt# n# d#)
remInteger (Jp# n) (S# d#)
= wordToInteger (remBigNatWord n (int2Word# (absI# d#)))
remInteger (Jn# n) (S# d#)
= wordToNegInteger (remBigNatWord n (int2Word# (absI# d#)))
remInteger (Jp# n) (Jp# d) = bigNatToInteger (remBigNat n d)
remInteger (Jp# n) (Jn# d) = bigNatToInteger (remBigNat n d)
remInteger (Jn# n) (Jp# d) = bigNatToNegInteger (remBigNat n d)
remInteger (Jn# n) (Jn# d) = bigNatToNegInteger (remBigNat n d)
remInteger n d = case inline quotRemInteger n d of (# _, r #) -> r
{-# CONSTANT_FOLDED remInteger #-}
divModInteger :: Integer -> Integer -> (# Integer, Integer #)
divModInteger n d
| isTrue# (signumInteger# r ==# negateInt# (signumInteger# d))
= let !q' = plusInteger q (S# -1#)
!r' = plusInteger r d
in (# q', r' #)
| True = qr
where
!qr@(# q, r #) = quotRemInteger n d
{-# CONSTANT_FOLDED divModInteger #-}
divInteger :: Integer -> Integer -> Integer
divInteger n d | isTrue# (isNegInteger# n ==# isNegInteger# d) = quotInteger n d
divInteger n d = case inline divModInteger n d of (# q, _ #) -> q
{-# CONSTANT_FOLDED divInteger #-}
modInteger :: Integer -> Integer -> Integer
modInteger n d | isTrue# (isNegInteger# n ==# isNegInteger# d) = remInteger n d
modInteger n d = case inline divModInteger n d of (# _, r #) -> r
{-# CONSTANT_FOLDED modInteger #-}
gcdInteger :: Integer -> Integer -> Integer
gcdInteger (S# 0#) b = absInteger b
gcdInteger a (S# 0#) = absInteger a
gcdInteger (S# 1#) _ = S# 1#
gcdInteger (S# -1#) _ = S# 1#
gcdInteger _ (S# 1#) = S# 1#
gcdInteger _ (S# -1#) = S# 1#
gcdInteger (S# a#) (S# b#)
= wordToInteger (gcdWord# (int2Word# (absI# a#)) (int2Word# (absI# b#)))
gcdInteger a@(S# _) b = gcdInteger b a
gcdInteger (Jn# a) b = gcdInteger (Jp# a) b
gcdInteger (Jp# a) (Jp# b) = bigNatToInteger (gcdBigNat a b)
gcdInteger (Jp# a) (Jn# b) = bigNatToInteger (gcdBigNat a b)
gcdInteger (Jp# a) (S# b#)
= wordToInteger (gcdBigNatWord a (int2Word# (absI# b#)))
{-# CONSTANT_FOLDED gcdInteger #-}
lcmInteger :: Integer -> Integer -> Integer
lcmInteger (S# 0#) !_ = S# 0#
lcmInteger (S# 1#) b = absInteger b
lcmInteger (S# -1#) b = absInteger b
lcmInteger _ (S# 0#) = S# 0#
lcmInteger a (S# 1#) = absInteger a
lcmInteger a (S# -1#) = absInteger a
lcmInteger a b = (aa `quotInteger` (aa `gcdInteger` ab)) `timesInteger` ab
where
aa = absInteger a
ab = absInteger b
{-# CONSTANT_FOLDED lcmInteger #-}
gcdInt :: Int# -> Int# -> Int#
gcdInt x# y#
= word2Int# (gcdWord# (int2Word# (absI# x#)) (int2Word# (absI# y#)))
gcdWord :: Word# -> Word# -> Word#
gcdWord = gcdWord#
compareBigNat :: BigNat -> BigNat -> Ordering
compareBigNat x@(BN# x#) y@(BN# y#)
| isTrue# (nx# ==# ny#)
= compareInt# (narrowCInt# (c_mpn_cmp x# y# nx#)) 0#
| isTrue# (nx# <# ny#) = LT
| True = GT
where
nx# = sizeofBigNat# x
ny# = sizeofBigNat# y
compareBigNatWord :: BigNat -> GmpLimb# -> Ordering
compareBigNatWord bn w#
| isTrue# (sizeofBigNat# bn ==# 1#) = cmpW# (bigNatToWord bn) w#
| True = GT
gtBigNatWord# :: BigNat -> GmpLimb# -> Int#
gtBigNatWord# bn w#
= (sizeofBigNat# bn ># 1#) `orI#` (bigNatToWord bn `gtWord#` w#)
eqBigNat :: BigNat -> BigNat -> Bool
eqBigNat x y = isTrue# (eqBigNat# x y)
eqBigNat# :: BigNat -> BigNat -> Int#
eqBigNat# x@(BN# x#) y@(BN# y#)
| isTrue# (nx# ==# ny#) = c_mpn_cmp x# y# nx# ==# 0#
| True = 0#
where
nx# = sizeofBigNat# x
ny# = sizeofBigNat# y
neqBigNat# :: BigNat -> BigNat -> Int#
neqBigNat# x@(BN# x#) y@(BN# y#)
| isTrue# (nx# ==# ny#) = c_mpn_cmp x# y# nx# /=# 0#
| True = 1#
where
nx# = sizeofBigNat# x
ny# = sizeofBigNat# y
eqBigNatWord :: BigNat -> GmpLimb# -> Bool
eqBigNatWord bn w# = isTrue# (eqBigNatWord# bn w#)
eqBigNatWord# :: BigNat -> GmpLimb# -> Int#
eqBigNatWord# bn w#
= (sizeofBigNat# bn ==# 1#) `andI#` (bigNatToWord bn `eqWord#` w#)
bigNatToWord :: BigNat -> Word#
bigNatToWord bn = indexBigNat# bn 0#
bigNatToInt :: BigNat -> Int#
bigNatToInt (BN# ba#) = indexIntArray# ba# 0#
zeroBigNat :: BigNat
zeroBigNat = runS $ do
mbn <- newBigNat# 1#
_ <- svoid (writeBigNat# mbn 0# 0##)
unsafeFreezeBigNat# mbn
{-# NOINLINE zeroBigNat #-}
isZeroBigNat :: BigNat -> Bool
isZeroBigNat bn = eqBigNatWord bn 0##
oneBigNat :: BigNat
oneBigNat = runS $ do
mbn <- newBigNat# 1#
_ <- svoid (writeBigNat# mbn 0# 1##)
unsafeFreezeBigNat# mbn
{-# NOINLINE oneBigNat #-}
czeroBigNat :: BigNat
czeroBigNat = runS $ do
mbn <- newBigNat# 1#
_ <- svoid (writeBigNat# mbn 0# (not# 0##))
unsafeFreezeBigNat# mbn
{-# NOINLINE czeroBigNat #-}
nullBigNat :: BigNat
nullBigNat = runS (newBigNat# 0# >>= unsafeFreezeBigNat#)
{-# NOINLINE nullBigNat #-}
isNullBigNat# :: BigNat -> Int#
isNullBigNat# (BN# ba#) = sizeofByteArray# ba# ==# 0#
wordToBigNat :: Word# -> BigNat
wordToBigNat 0## = zeroBigNat
wordToBigNat 1## = oneBigNat
wordToBigNat w#
| isTrue# (not# w# `eqWord#` 0##) = czeroBigNat
| True = runS $ do
mbn <- newBigNat# 1#
_ <- svoid (writeBigNat# mbn 0# w#)
unsafeFreezeBigNat# mbn
wordToBigNat2 :: Word# -> Word# -> BigNat
wordToBigNat2 0## lw# = wordToBigNat lw#
wordToBigNat2 hw# lw# = runS $ do
mbn <- newBigNat# 2#
_ <- svoid (writeBigNat# mbn 0# lw#)
_ <- svoid (writeBigNat# mbn 1# hw#)
unsafeFreezeBigNat# mbn
plusBigNat :: BigNat -> BigNat -> BigNat
plusBigNat x y
| isTrue# (eqBigNatWord# x 0##) = y
| isTrue# (eqBigNatWord# y 0##) = x
| isTrue# (nx# >=# ny#) = go x nx# y ny#
| True = go y ny# x nx#
where
go (BN# a#) na# (BN# b#) nb# = runS $ do
mbn@(MBN# mba#) <- newBigNat# na#
(W# c#) <- liftIO (c_mpn_add mba# a# na# b# nb#)
case c# of
0## -> unsafeFreezeBigNat# mbn
_ -> unsafeSnocFreezeBigNat# mbn c#
nx# = sizeofBigNat# x
ny# = sizeofBigNat# y
plusBigNatWord :: BigNat -> GmpLimb# -> BigNat
plusBigNatWord x 0## = x
plusBigNatWord x@(BN# x#) y# = runS $ do
mbn@(MBN# mba#) <- newBigNat# nx#
(W# c#) <- liftIO (c_mpn_add_1 mba# x# nx# y#)
case c# of
0## -> unsafeFreezeBigNat# mbn
_ -> unsafeSnocFreezeBigNat# mbn c#
where
nx# = sizeofBigNat# x
minusBigNat :: BigNat -> BigNat -> BigNat
minusBigNat x@(BN# x#) y@(BN# y#)
| isZeroBigNat y = x
| isTrue# (nx# >=# ny#) = runS $ do
mbn@(MBN# mba#) <- newBigNat# nx#
(W# b#) <- liftIO (c_mpn_sub mba# x# nx# y# ny#)
case b# of
0## -> unsafeRenormFreezeBigNat# mbn
_ -> return nullBigNat
| True = nullBigNat
where
nx# = sizeofBigNat# x
ny# = sizeofBigNat# y
minusBigNatWord :: BigNat -> GmpLimb# -> BigNat
minusBigNatWord x 0## = x
minusBigNatWord x@(BN# x#) y# = runS $ do
mbn@(MBN# mba#) <- newBigNat# nx#
(W# b#) <- liftIO $ c_mpn_sub_1 mba# x# nx# y#
case b# of
0## -> unsafeRenormFreezeBigNat# mbn
_ -> return nullBigNat
where
nx# = sizeofBigNat# x
timesBigNat :: BigNat -> BigNat -> BigNat
timesBigNat x y
| isZeroBigNat x = zeroBigNat
| isZeroBigNat y = zeroBigNat
| isTrue# (nx# >=# ny#) = go x nx# y ny#
| True = go y ny# x nx#
where
go (BN# a#) na# (BN# b#) nb# = runS $ do
let n# = nx# +# ny#
mbn@(MBN# mba#) <- newBigNat# n#
(W# msl#) <- liftIO (c_mpn_mul mba# a# na# b# nb#)
case msl# of
0## -> unsafeShrinkFreezeBigNat# mbn (n# -# 1#)
_ -> unsafeFreezeBigNat# mbn
nx# = sizeofBigNat# x
ny# = sizeofBigNat# y
sqrBigNat :: BigNat -> BigNat
sqrBigNat x
| isZeroBigNat x = zeroBigNat
sqrBigNat x = timesBigNat x x
timesBigNatWord :: BigNat -> GmpLimb# -> BigNat
timesBigNatWord !_ 0## = zeroBigNat
timesBigNatWord x 1## = x
timesBigNatWord x@(BN# x#) y#
| isTrue# (nx# ==# 1#) =
let !(# !h#, !l# #) = timesWord2# (bigNatToWord x) y#
in wordToBigNat2 h# l#
| True = runS $ do
mbn@(MBN# mba#) <- newBigNat# nx#
(W# msl#) <- liftIO (c_mpn_mul_1 mba# x# nx# y#)
case msl# of
0## -> unsafeFreezeBigNat# mbn
_ -> unsafeSnocFreezeBigNat# mbn msl#
where
nx# = sizeofBigNat# x
bitBigNat :: Int# -> BigNat
bitBigNat i#
| isTrue# (i# <# 0#) = zeroBigNat
| isTrue# (i# ==# 0#) = oneBigNat
| True = runS $ do
mbn@(MBN# mba#) <- newBigNat# (li# +# 1#)
_ <- svoid (clearWordArray# mba# 0# li#)
_ <- svoid (writeBigNat# mbn li# (uncheckedShiftL# 1## bi#))
unsafeFreezeBigNat# mbn
where
!(# li#, bi# #) = quotRemInt# i# GMP_LIMB_BITS#
testBitBigNat :: BigNat -> Int# -> Bool
testBitBigNat bn i#
| isTrue# (i# <# 0#) = False
| isTrue# (li# <# nx#) = isTrue# (testBitWord# (indexBigNat# bn li#) bi#)
| True = False
where
!(# li#, bi# #) = quotRemInt# i# GMP_LIMB_BITS#
nx# = sizeofBigNat# bn
testBitNegBigNat :: BigNat -> Int# -> Bool
testBitNegBigNat bn i#
| isTrue# (i# <# 0#) = False
| isTrue# (li# >=# nx#) = True
| allZ li# = isTrue# ((testBitWord#
(indexBigNat# bn li# `minusWord#` 1##) bi#) ==# 0#)
| True = isTrue# ((testBitWord# (indexBigNat# bn li#) bi#) ==# 0#)
where
!(# li#, bi# #) = quotRemInt# i# GMP_LIMB_BITS#
nx# = sizeofBigNat# bn
allZ 0# = True
allZ j | isTrue# (indexBigNat# bn (j -# 1#) `eqWord#` 0##) = allZ (j -# 1#)
| True = False
clearBitBigNat :: BigNat -> Int# -> BigNat
clearBitBigNat bn i#
| not (inline testBitBigNat bn i#) = bn
| isTrue# (nx# ==# 1#) = wordToBigNat (bigNatToWord bn `xor#` bitWord# bi#)
| isTrue# (li# +# 1# ==# nx#) =
case indexBigNat# bn li# `xor#` bitWord# bi# of
0## -> do
case fmssl bn (li# -# 1#) of
0# -> zeroBigNat
n# -> runS $ do
mbn <- newBigNat# n#
_ <- copyWordArray bn 0# mbn 0# n#
unsafeFreezeBigNat# mbn
newlimb# -> runS $ do
mbn <- newBigNat# nx#
_ <- copyWordArray bn 0# mbn 0# li#
_ <- svoid (writeBigNat# mbn li# newlimb#)
unsafeFreezeBigNat# mbn
| True = runS $ do
mbn <- newBigNat# nx#
_ <- copyWordArray bn 0# mbn 0# nx#
let newlimb# = indexBigNat# bn li# `xor#` bitWord# bi#
_ <- svoid (writeBigNat# mbn li# newlimb#)
unsafeFreezeBigNat# mbn
where
!(# li#, bi# #) = quotRemInt# i# GMP_LIMB_BITS#
nx# = sizeofBigNat# bn
setBitBigNat :: BigNat -> Int# -> BigNat
setBitBigNat bn i#
| inline testBitBigNat bn i# = bn
| isTrue# (d# ># 0#) = runS $ do
mbn@(MBN# mba#) <- newBigNat# (li# +# 1#)
_ <- copyWordArray bn 0# mbn 0# nx#
_ <- svoid (clearWordArray# mba# nx# (d# -# 1#))
_ <- svoid (writeBigNat# mbn li# (bitWord# bi#))
unsafeFreezeBigNat# mbn
| True = runS $ do
mbn <- newBigNat# nx#
_ <- copyWordArray bn 0# mbn 0# nx#
_ <- svoid (writeBigNat# mbn li# (indexBigNat# bn li#
`or#` bitWord# bi#))
unsafeFreezeBigNat# mbn
where
!(# li#, bi# #) = quotRemInt# i# GMP_LIMB_BITS#
nx# = sizeofBigNat# bn
d# = li# +# 1# -# nx#
complementBitBigNat :: BigNat -> Int# -> BigNat
complementBitBigNat bn i#
| testBitBigNat bn i# = clearBitBigNat bn i#
| True = setBitBigNat bn i#
popCountBigNat :: BigNat -> Int#
popCountBigNat bn@(BN# ba#) = word2Int# (c_mpn_popcount ba# (sizeofBigNat# bn))
shiftLBigNat :: BigNat -> Int# -> BigNat
shiftLBigNat x 0# = x
shiftLBigNat x _ | isZeroBigNat x = zeroBigNat
shiftLBigNat x@(BN# xba#) n# = runS $ do
ymbn@(MBN# ymba#) <- newBigNat# yn#
W# ymsl <- liftIO (c_mpn_lshift ymba# xba# xn# (int2Word# n#))
case ymsl of
0## -> unsafeShrinkFreezeBigNat# ymbn (yn# -# 1#)
_ -> unsafeFreezeBigNat# ymbn
where
xn# = sizeofBigNat# x
yn# = xn# +# nlimbs# +# (nbits# /=# 0#)
!(# nlimbs#, nbits# #) = quotRemInt# n# GMP_LIMB_BITS#
shiftRBigNat :: BigNat -> Int# -> BigNat
shiftRBigNat x 0# = x
shiftRBigNat x _ | isZeroBigNat x = zeroBigNat
shiftRBigNat x@(BN# xba#) n#
| isTrue# (nlimbs# >=# xn#) = zeroBigNat
| True = runS $ do
ymbn@(MBN# ymba#) <- newBigNat# yn#
W# ymsl <- liftIO (c_mpn_rshift ymba# xba# xn# (int2Word# n#))
case ymsl of
0## -> unsafeRenormFreezeBigNat# ymbn
_ -> unsafeFreezeBigNat# ymbn
where
xn# = sizeofBigNat# x
yn# = xn# -# nlimbs#
nlimbs# = quotInt# n# GMP_LIMB_BITS#
shiftRNegBigNat :: BigNat -> Int# -> BigNat
shiftRNegBigNat x 0# = x
shiftRNegBigNat x _ | isZeroBigNat x = zeroBigNat
shiftRNegBigNat x@(BN# xba#) n#
| isTrue# (nlimbs# >=# xn#) = zeroBigNat
| True = runS $ do
ymbn@(MBN# ymba#) <- newBigNat# yn#
W# ymsl <- liftIO (c_mpn_rshift_2c ymba# xba# xn# (int2Word# n#))
case ymsl of
0## -> unsafeRenormFreezeBigNat# ymbn
_ -> unsafeFreezeBigNat# ymbn
where
xn# = sizeofBigNat# x
yn# = xn# -# nlimbs#
nlimbs# = quotInt# (n# -# 1#) GMP_LIMB_BITS#
orBigNat :: BigNat -> BigNat -> BigNat
orBigNat x@(BN# x#) y@(BN# y#)
| isZeroBigNat x = y
| isZeroBigNat y = x
| isTrue# (nx# >=# ny#) = runS (ior' x# nx# y# ny#)
| True = runS (ior' y# ny# x# nx#)
where
ior' a# na# b# nb# = do
mbn@(MBN# mba#) <- newBigNat# na#
_ <- liftIO (c_mpn_ior_n mba# a# b# nb#)
_ <- case isTrue# (na# ==# nb#) of
False -> svoid (copyWordArray# a# nb# mba# nb# (na# -# nb#))
True -> return ()
unsafeFreezeBigNat# mbn
nx# = sizeofBigNat# x
ny# = sizeofBigNat# y
xorBigNat :: BigNat -> BigNat -> BigNat
xorBigNat x@(BN# x#) y@(BN# y#)
| isZeroBigNat x = y
| isZeroBigNat y = x
| isTrue# (nx# >=# ny#) = runS (xor' x# nx# y# ny#)
| True = runS (xor' y# ny# x# nx#)
where
xor' a# na# b# nb# = do
mbn@(MBN# mba#) <- newBigNat# na#
_ <- liftIO (c_mpn_xor_n mba# a# b# nb#)
case isTrue# (na# ==# nb#) of
False -> do _ <- svoid (copyWordArray# a# nb# mba# nb# (na# -# nb#))
unsafeFreezeBigNat# mbn
True -> unsafeRenormFreezeBigNat# mbn
nx# = sizeofBigNat# x
ny# = sizeofBigNat# y
andnBigNat :: BigNat -> BigNat -> BigNat
andnBigNat x@(BN# x#) y@(BN# y#)
| isZeroBigNat x = zeroBigNat
| isZeroBigNat y = x
| True = runS $ do
mbn@(MBN# mba#) <- newBigNat# nx#
_ <- liftIO (c_mpn_andn_n mba# x# y# n#)
_ <- case isTrue# (nx# ==# n#) of
False -> svoid (copyWordArray# x# n# mba# n# (nx# -# n#))
True -> return ()
unsafeRenormFreezeBigNat# mbn
where
n# | isTrue# (nx# <# ny#) = nx#
| True = ny#
nx# = sizeofBigNat# x
ny# = sizeofBigNat# y
andBigNat :: BigNat -> BigNat -> BigNat
andBigNat x@(BN# x#) y@(BN# y#)
| isZeroBigNat x = zeroBigNat
| isZeroBigNat y = zeroBigNat
| True = runS $ do
mbn@(MBN# mba#) <- newBigNat# n#
_ <- liftIO (c_mpn_and_n mba# x# y# n#)
unsafeRenormFreezeBigNat# mbn
where
n# | isTrue# (nx# <# ny#) = nx#
| True = ny#
nx# = sizeofBigNat# x
ny# = sizeofBigNat# y
quotRemBigNat :: BigNat -> BigNat -> (# BigNat,BigNat #)
quotRemBigNat n@(BN# nba#) d@(BN# dba#)
| isZeroBigNat d = (# nullBigNat, nullBigNat #)
| eqBigNatWord d 1## = (# n, zeroBigNat #)
| n < d = (# zeroBigNat, n #)
| True = case runS go of (!q,!r) -> (# q, r #)
where
nn# = sizeofBigNat# n
dn# = sizeofBigNat# d
qn# = 1# +# nn# -# dn#
rn# = dn#
go = do
qmbn@(MBN# qmba#) <- newBigNat# qn#
rmbn@(MBN# rmba#) <- newBigNat# rn#
_ <- liftIO (c_mpn_tdiv_qr qmba# rmba# 0# nba# nn# dba# dn#)
q <- unsafeRenormFreezeBigNat# qmbn
r <- unsafeRenormFreezeBigNat# rmbn
return (q, r)
quotBigNat :: BigNat -> BigNat -> BigNat
quotBigNat n@(BN# nba#) d@(BN# dba#)
| isZeroBigNat d = nullBigNat
| eqBigNatWord d 1## = n
| n < d = zeroBigNat
| True = runS $ do
let nn# = sizeofBigNat# n
let dn# = sizeofBigNat# d
let qn# = 1# +# nn# -# dn#
qmbn@(MBN# qmba#) <- newBigNat# qn#
_ <- liftIO (c_mpn_tdiv_q qmba# nba# nn# dba# dn#)
unsafeRenormFreezeBigNat# qmbn
remBigNat :: BigNat -> BigNat -> BigNat
remBigNat n@(BN# nba#) d@(BN# dba#)
| isZeroBigNat d = nullBigNat
| eqBigNatWord d 1## = zeroBigNat
| n < d = n
| True = runS $ do
let nn# = sizeofBigNat# n
let dn# = sizeofBigNat# d
rmbn@(MBN# rmba#) <- newBigNat# dn#
_ <- liftIO (c_mpn_tdiv_r rmba# nba# nn# dba# dn#)
unsafeRenormFreezeBigNat# rmbn
quotRemBigNatWord :: BigNat -> GmpLimb# -> (# BigNat, GmpLimb# #)
quotRemBigNatWord !_ 0## = (# nullBigNat, 0## #)
quotRemBigNatWord n 1## = (# n, 0## #)
quotRemBigNatWord n@(BN# nba#) d# = case compareBigNatWord n d# of
LT -> (# zeroBigNat, bigNatToWord n #)
EQ -> (# oneBigNat, 0## #)
GT -> case runS go of (!q,!(W# r#)) -> (# q, r# #)
where
go = do
let nn# = sizeofBigNat# n
qmbn@(MBN# qmba#) <- newBigNat# nn#
r <- liftIO (c_mpn_divrem_1 qmba# 0# nba# nn# d#)
q <- unsafeRenormFreezeBigNat# qmbn
return (q,r)
quotBigNatWord :: BigNat -> GmpLimb# -> BigNat
quotBigNatWord n d# = case inline quotRemBigNatWord n d# of (# q, _ #) -> q
remBigNatWord :: BigNat -> GmpLimb# -> Word#
remBigNatWord n@(BN# nba#) d# = c_mpn_mod_1 nba# (sizeofBigNat# n) d#
gcdBigNatWord :: BigNat -> Word# -> Word#
gcdBigNatWord bn@(BN# ba#) = c_mpn_gcd_1# ba# (sizeofBigNat# bn)
gcdBigNat :: BigNat -> BigNat -> BigNat
gcdBigNat x@(BN# x#) y@(BN# y#)
| isZeroBigNat x = y
| isZeroBigNat y = x
| isTrue# (nx# >=# ny#) = runS (gcd' x# nx# y# ny#)
| True = runS (gcd' y# ny# x# nx#)
where
gcd' a# na# b# nb# = do
mbn@(MBN# mba#) <- newBigNat# nb#
I# rn'# <- liftIO (c_mpn_gcd# mba# a# na# b# nb#)
let rn# = narrowGmpSize# rn'#
case isTrue# (rn# ==# nb#) of
False -> unsafeShrinkFreezeBigNat# mbn rn#
True -> unsafeFreezeBigNat# mbn
nx# = sizeofBigNat# x
ny# = sizeofBigNat# y
{-# NOINLINE gcdExtInteger #-}
gcdExtInteger :: Integer -> Integer -> (# Integer, Integer #)
gcdExtInteger a b = case gcdExtSBigNat a' b' of
(# g, s #) -> let !g' = bigNatToInteger g
!s' = sBigNatToInteger s
in (# g', s' #)
where
a' = integerToSBigNat a
b' = integerToSBigNat b
gcdExtSBigNat :: SBigNat -> SBigNat -> (# BigNat, SBigNat #)
gcdExtSBigNat x y = case runS go of (g,s) -> (# g, s #)
where
go = do
g@(MBN# g#) <- newBigNat# gn0#
s@(MBN# s#) <- newBigNat# (absI# xn#)
I# ssn_# <- liftIO (integer_gmp_gcdext# s# g# x# xn# y# yn#)
let ssn# = narrowGmpSize# ssn_#
sn# = absI# ssn#
s' <- unsafeShrinkFreezeBigNat# s sn#
g' <- unsafeRenormFreezeBigNat# g
case isTrue# (ssn# >=# 0#) of
False -> return ( g', NegBN s' )
True -> return ( g', PosBN s' )
!(BN# x#) = absSBigNat x
!(BN# y#) = absSBigNat y
xn# = ssizeofSBigNat# x
yn# = ssizeofSBigNat# y
gn0# = minI# (absI# xn#) (absI# yn#)
{-# NOINLINE powModInteger #-}
powModInteger :: Integer -> Integer -> Integer -> Integer
powModInteger (S# b#) (S# e#) (S# m#)
| isTrue# (b# >=# 0#), isTrue# (e# >=# 0#)
= wordToInteger (powModWord (int2Word# b#) (int2Word# e#)
(int2Word# (absI# m#)))
powModInteger b e m = case m of
(S# m#) -> wordToInteger (powModSBigNatWord b' e' (int2Word# (absI# m#)))
(Jp# m') -> bigNatToInteger (powModSBigNat b' e' m')
(Jn# m') -> bigNatToInteger (powModSBigNat b' e' m')
where
b' = integerToSBigNat b
e' = integerToSBigNat e
{-# NOINLINE powModSecInteger #-}
powModSecInteger :: Integer -> Integer -> Integer -> Integer
powModSecInteger b e m = bigNatToInteger (powModSecSBigNat b' e' m')
where
b' = integerToSBigNat b
e' = integerToSBigNat e
m' = absSBigNat (integerToSBigNat m)
#if HAVE_SECURE_POWM == 0
{-# WARNING powModSecInteger "The underlying GMP library does not support a secure version of powModInteger which is side-channel resistant - you need at least GMP version 5 to support this" #-}
#endif
powModBigNat :: BigNat -> BigNat -> BigNat -> BigNat
powModBigNat b e m = inline powModSBigNat (PosBN b) (PosBN e) m
powModBigNatWord :: BigNat -> BigNat -> GmpLimb# -> GmpLimb#
powModBigNatWord b e m# = inline powModSBigNatWord (PosBN b) (PosBN e) m#
foreign import ccall unsafe "integer_gmp_powm_word"
powModWord :: GmpLimb# -> GmpLimb# -> GmpLimb# -> GmpLimb#
powModSBigNat :: SBigNat -> SBigNat -> BigNat -> BigNat
powModSBigNat b e m@(BN# m#) = runS $ do
r@(MBN# r#) <- newBigNat# mn#
I# rn_# <- liftIO (integer_gmp_powm# r# b# bn# e# en# m# mn#)
let rn# = narrowGmpSize# rn_#
case isTrue# (rn# ==# mn#) of
False -> unsafeShrinkFreezeBigNat# r rn#
True -> unsafeFreezeBigNat# r
where
!(BN# b#) = absSBigNat b
!(BN# e#) = absSBigNat e
bn# = ssizeofSBigNat# b
en# = ssizeofSBigNat# e
mn# = sizeofBigNat# m
foreign import ccall unsafe "integer_gmp_powm"
integer_gmp_powm# :: MutableByteArray# RealWorld
-> ByteArray# -> GmpSize# -> ByteArray# -> GmpSize#
-> ByteArray# -> GmpSize# -> IO GmpSize
powModSBigNatWord :: SBigNat -> SBigNat -> GmpLimb# -> GmpLimb#
powModSBigNatWord b e m# = integer_gmp_powm1# b# bn# e# en# m#
where
!(BN# b#) = absSBigNat b
!(BN# e#) = absSBigNat e
bn# = ssizeofSBigNat# b
en# = ssizeofSBigNat# e
foreign import ccall unsafe "integer_gmp_powm1"
integer_gmp_powm1# :: ByteArray# -> GmpSize# -> ByteArray# -> GmpSize#
-> GmpLimb# -> GmpLimb#
powModSecSBigNat :: SBigNat -> SBigNat -> BigNat -> BigNat
powModSecSBigNat b e m@(BN# m#) = runS $ do
r@(MBN# r#) <- newBigNat# mn#
I# rn_# <- liftIO (integer_gmp_powm_sec# r# b# bn# e# en# m# mn#)
let rn# = narrowGmpSize# rn_#
case isTrue# (rn# ==# mn#) of
False -> unsafeShrinkFreezeBigNat# r rn#
True -> unsafeFreezeBigNat# r
where
!(BN# b#) = absSBigNat b
!(BN# e#) = absSBigNat e
bn# = ssizeofSBigNat# b
en# = ssizeofSBigNat# e
mn# = sizeofBigNat# m
foreign import ccall unsafe "integer_gmp_powm_sec"
integer_gmp_powm_sec# :: MutableByteArray# RealWorld
-> ByteArray# -> GmpSize# -> ByteArray# -> GmpSize#
-> ByteArray# -> GmpSize# -> IO GmpSize
{-# NOINLINE recipModInteger #-}
recipModInteger :: Integer -> Integer -> Integer
recipModInteger (S# x#) (S# m#)
| isTrue# (x# >=# 0#)
= wordToInteger (recipModWord (int2Word# x#) (int2Word# (absI# m#)))
recipModInteger x m = bigNatToInteger (recipModSBigNat x' m')
where
x' = integerToSBigNat x
m' = absSBigNat (integerToSBigNat m)
recipModBigNat :: BigNat -> BigNat -> BigNat
recipModBigNat x m = inline recipModSBigNat (PosBN x) m
foreign import ccall unsafe "integer_gmp_invert_word"
recipModWord :: GmpLimb# -> GmpLimb# -> GmpLimb#
recipModSBigNat :: SBigNat -> BigNat -> BigNat
recipModSBigNat x m@(BN# m#) = runS $ do
r@(MBN# r#) <- newBigNat# mn#
I# rn_# <- liftIO (integer_gmp_invert# r# x# xn# m# mn#)
let rn# = narrowGmpSize# rn_#
case isTrue# (rn# ==# mn#) of
False -> unsafeShrinkFreezeBigNat# r rn#
True -> unsafeFreezeBigNat# r
where
!(BN# x#) = absSBigNat x
xn# = ssizeofSBigNat# x
mn# = sizeofBigNat# m
foreign import ccall unsafe "integer_gmp_invert"
integer_gmp_invert# :: MutableByteArray# RealWorld
-> ByteArray# -> GmpSize#
-> ByteArray# -> GmpSize# -> IO GmpSize
decodeDoubleInteger :: Double# -> (# Integer, Int# #)
#if WORD_SIZE_IN_BITS == 64
decodeDoubleInteger x = case decodeDouble_Int64# x of
(# m#, e# #) -> (# S# m#, e# #)
#elif WORD_SIZE_IN_BITS == 32
decodeDoubleInteger x = case decodeDouble_Int64# x of
(# m#, e# #) -> (# int64ToInteger m#, e# #)
#endif
{-# CONSTANT_FOLDED decodeDoubleInteger #-}
foreign import ccall unsafe "__int_encodeDouble"
int_encodeDouble# :: Int# -> Int# -> Double#
encodeDoubleInteger :: Integer -> Int# -> Double#
encodeDoubleInteger (S# m#) 0# = int2Double# m#
encodeDoubleInteger (S# m#) e# = int_encodeDouble# m# e#
encodeDoubleInteger (Jp# bn@(BN# bn#)) e#
= c_mpn_get_d bn# (sizeofBigNat# bn) e#
encodeDoubleInteger (Jn# bn@(BN# bn#)) e#
= c_mpn_get_d bn# (negateInt# (sizeofBigNat# bn)) e#
{-# CONSTANT_FOLDED encodeDoubleInteger #-}
foreign import ccall unsafe "integer_gmp_mpn_get_d"
c_mpn_get_d :: ByteArray# -> GmpSize# -> Int# -> Double#
doubleFromInteger :: Integer -> Double#
doubleFromInteger (S# m#) = int2Double# m#
doubleFromInteger (Jp# bn@(BN# bn#))
= c_mpn_get_d bn# (sizeofBigNat# bn) 0#
doubleFromInteger (Jn# bn@(BN# bn#))
= c_mpn_get_d bn# (negateInt# (sizeofBigNat# bn)) 0#
{-# CONSTANT_FOLDED doubleFromInteger #-}
floatFromInteger :: Integer -> Float#
floatFromInteger i = double2Float# (doubleFromInteger i)
encodeFloatInteger :: Integer -> Int# -> Float#
encodeFloatInteger m e = double2Float# (encodeDoubleInteger m e)
foreign import ccall unsafe "integer_gmp_gcd_word"
gcdWord# :: GmpLimb# -> GmpLimb# -> GmpLimb#
foreign import ccall unsafe "integer_gmp_mpn_gcd_1"
c_mpn_gcd_1# :: ByteArray# -> GmpSize# -> GmpLimb# -> GmpLimb#
foreign import ccall unsafe "integer_gmp_mpn_gcd"
c_mpn_gcd# :: MutableByteArray# s -> ByteArray# -> GmpSize#
-> ByteArray# -> GmpSize# -> IO GmpSize
foreign import ccall unsafe "integer_gmp_gcdext"
integer_gmp_gcdext# :: MutableByteArray# s -> MutableByteArray# s
-> ByteArray# -> GmpSize#
-> ByteArray# -> GmpSize# -> IO GmpSize
foreign import ccall unsafe "gmp.h __gmpn_add_1"
c_mpn_add_1 :: MutableByteArray# s -> ByteArray# -> GmpSize# -> GmpLimb#
-> IO GmpLimb
foreign import ccall unsafe "gmp.h __gmpn_sub_1"
c_mpn_sub_1 :: MutableByteArray# s -> ByteArray# -> GmpSize# -> GmpLimb#
-> IO GmpLimb
foreign import ccall unsafe "gmp.h __gmpn_mul_1"
c_mpn_mul_1 :: MutableByteArray# s -> ByteArray# -> GmpSize# -> GmpLimb#
-> IO GmpLimb
foreign import ccall unsafe "gmp.h __gmpn_add"
c_mpn_add :: MutableByteArray# s -> ByteArray# -> GmpSize#
-> ByteArray# -> GmpSize# -> IO GmpLimb
foreign import ccall unsafe "gmp.h __gmpn_sub"
c_mpn_sub :: MutableByteArray# s -> ByteArray# -> GmpSize# -> ByteArray#
-> GmpSize# -> IO GmpLimb
foreign import ccall unsafe "gmp.h __gmpn_mul"
c_mpn_mul :: MutableByteArray# s -> ByteArray# -> GmpSize# -> ByteArray#
-> GmpSize# -> IO GmpLimb
foreign import ccall unsafe "gmp.h __gmpn_cmp"
c_mpn_cmp :: ByteArray# -> ByteArray# -> GmpSize# -> CInt#
foreign import ccall unsafe "gmp.h __gmpn_tdiv_qr"
c_mpn_tdiv_qr :: MutableByteArray# s -> MutableByteArray# s -> GmpSize#
-> ByteArray# -> GmpSize# -> ByteArray# -> GmpSize# -> IO ()
foreign import ccall unsafe "integer_gmp_mpn_tdiv_q"
c_mpn_tdiv_q :: MutableByteArray# s -> ByteArray# -> GmpSize# -> ByteArray#
-> GmpSize# -> IO ()
foreign import ccall unsafe "integer_gmp_mpn_tdiv_r"
c_mpn_tdiv_r :: MutableByteArray# s -> ByteArray# -> GmpSize# -> ByteArray#
-> GmpSize# -> IO ()
foreign import ccall unsafe "gmp.h __gmpn_divrem_1"
c_mpn_divrem_1 :: MutableByteArray# s -> GmpSize# -> ByteArray# -> GmpSize#
-> GmpLimb# -> IO GmpLimb
foreign import ccall unsafe "gmp.h __gmpn_mod_1"
c_mpn_mod_1 :: ByteArray# -> GmpSize# -> GmpLimb# -> GmpLimb#
foreign import ccall unsafe "integer_gmp_mpn_rshift"
c_mpn_rshift :: MutableByteArray# s -> ByteArray# -> GmpSize# -> GmpBitCnt#
-> IO GmpLimb
foreign import ccall unsafe "integer_gmp_mpn_rshift_2c"
c_mpn_rshift_2c :: MutableByteArray# s -> ByteArray# -> GmpSize# -> GmpBitCnt#
-> IO GmpLimb
foreign import ccall unsafe "integer_gmp_mpn_lshift"
c_mpn_lshift :: MutableByteArray# s -> ByteArray# -> GmpSize# -> GmpBitCnt#
-> IO GmpLimb
foreign import ccall unsafe "integer_gmp_mpn_and_n"
c_mpn_and_n :: MutableByteArray# s -> ByteArray# -> ByteArray# -> GmpSize#
-> IO ()
foreign import ccall unsafe "integer_gmp_mpn_andn_n"
c_mpn_andn_n :: MutableByteArray# s -> ByteArray# -> ByteArray# -> GmpSize#
-> IO ()
foreign import ccall unsafe "integer_gmp_mpn_ior_n"
c_mpn_ior_n :: MutableByteArray# s -> ByteArray# -> ByteArray# -> GmpSize#
-> IO ()
foreign import ccall unsafe "integer_gmp_mpn_xor_n"
c_mpn_xor_n :: MutableByteArray# s -> ByteArray# -> ByteArray# -> GmpSize#
-> IO ()
foreign import ccall unsafe "gmp.h __gmpn_popcount"
c_mpn_popcount :: ByteArray# -> GmpSize# -> GmpBitCnt#
sizeofBigNat# :: BigNat -> GmpSize#
sizeofBigNat# (BN# x#)
= sizeofByteArray# x# `uncheckedIShiftRL#` GMP_LIMB_SHIFT#
data MutBigNat s = MBN# !(MutableByteArray# s)
getSizeofMutBigNat# :: MutBigNat s -> State# s -> (# State# s, GmpSize# #)
getSizeofMutBigNat# (MBN# x#) s =
case getSizeofMutableByteArray# x# s of
(# s', n# #) -> (# s', n# `uncheckedIShiftRL#` GMP_LIMB_SHIFT# #)
newBigNat# :: GmpSize# -> S s (MutBigNat s)
newBigNat# limbs# s =
case newByteArray# (limbs# `uncheckedIShiftL#` GMP_LIMB_SHIFT#) s of
(# s', mba# #) -> (# s', MBN# mba# #)
writeBigNat# :: MutBigNat s -> GmpSize# -> GmpLimb# -> State# s -> State# s
writeBigNat# (MBN# mba#) = writeWordArray# mba#
indexBigNat# :: BigNat -> GmpSize# -> GmpLimb#
indexBigNat# (BN# ba#) = indexWordArray# ba#
unsafeFreezeBigNat# :: MutBigNat s -> S s BigNat
unsafeFreezeBigNat# (MBN# mba#) s = case unsafeFreezeByteArray# mba# s of
(# s', ba# #) -> (# s', BN# ba# #)
resizeMutBigNat# :: MutBigNat s -> GmpSize# -> S s (MutBigNat s)
resizeMutBigNat# (MBN# mba0#) nsz# s
| isTrue# (bsz# ==# n#) = (# s', MBN# mba0# #)
| True =
case resizeMutableByteArray# mba0# bsz# s' of
(# s'', mba# #) -> (# s'', MBN# mba# #)
where
bsz# = nsz# `uncheckedIShiftL#` GMP_LIMB_SHIFT#
!(# s', n# #) = getSizeofMutableByteArray# mba0# s
shrinkMutBigNat# :: MutBigNat s -> GmpSize# -> State# s -> State# s
shrinkMutBigNat# (MBN# mba0#) nsz# s
| isTrue# (bsz# ==# n#) = s'
| True = shrinkMutableByteArray# mba0# bsz# s'
where
bsz# = nsz# `uncheckedIShiftL#` GMP_LIMB_SHIFT#
!(# s', n# #) = getSizeofMutableByteArray# mba0# s
unsafeSnocFreezeBigNat# :: MutBigNat s -> GmpLimb# -> S s BigNat
unsafeSnocFreezeBigNat# mbn0@(MBN# mba0#) limb# s = go s'
where
n# = nb0# `uncheckedIShiftRL#` GMP_LIMB_SHIFT#
!(# s', nb0# #) = getSizeofMutableByteArray# mba0# s
go = do
(MBN# mba#) <- resizeMutBigNat# mbn0 (n# +# 1#)
_ <- svoid (writeWordArray# mba# n# limb#)
unsafeFreezeBigNat# (MBN# mba#)
unsafeRenormFreezeBigNat# :: MutBigNat s -> S s BigNat
unsafeRenormFreezeBigNat# mbn s
| isTrue# (n0# ==# 0#) = (# s'', nullBigNat #)
| isTrue# (n# ==# 0#) = (# s'', zeroBigNat #)
| isTrue# (n# ==# n0#) = (unsafeFreezeBigNat# mbn) s''
| True = (unsafeShrinkFreezeBigNat# mbn n#) s''
where
!(# s', n0# #) = getSizeofMutBigNat# mbn s
!(# s'', n# #) = normSizeofMutBigNat'# mbn n0# s'
unsafeShrinkFreezeBigNat# :: MutBigNat s -> GmpSize# -> S s BigNat
unsafeShrinkFreezeBigNat# x@(MBN# xmba) 1#
= \s -> case readWordArray# xmba 0# s of
(# s', w# #) -> freezeOneLimb w# s'
where
freezeOneLimb 0## = return zeroBigNat
freezeOneLimb 1## = return oneBigNat
freezeOneLimb w# | isTrue# (not# w# `eqWord#` 0##) = return czeroBigNat
freezeOneLimb _ = do
_ <- svoid (shrinkMutBigNat# x 1#)
unsafeFreezeBigNat# x
unsafeShrinkFreezeBigNat# x y# = do
_ <- svoid (shrinkMutBigNat# x y#)
unsafeFreezeBigNat# x
copyWordArray# :: ByteArray# -> Int# -> MutableByteArray# s -> Int# -> Int#
-> State# s -> State# s
copyWordArray# src src_ofs dst dst_ofs len
= copyByteArray# src (src_ofs `uncheckedIShiftL#` GMP_LIMB_SHIFT#)
dst (dst_ofs `uncheckedIShiftL#` GMP_LIMB_SHIFT#)
(len `uncheckedIShiftL#` GMP_LIMB_SHIFT#)
copyWordArray :: BigNat -> Int# -> MutBigNat s -> Int# -> Int# -> S s ()
copyWordArray (BN# ba#) ofs_ba# (MBN# mba#) ofs_mba# len#
= svoid (copyWordArray# ba# ofs_ba# mba# ofs_mba# len#)
clearWordArray# :: MutableByteArray# s -> Int# -> Int# -> State# s -> State# s
clearWordArray# mba ofs len
= setByteArray# mba (ofs `uncheckedIShiftL#` GMP_LIMB_SHIFT#)
(len `uncheckedIShiftL#` GMP_LIMB_SHIFT#) 0#
normSizeofMutBigNat# :: MutBigNat s -> State# s -> (# State# s, Int# #)
normSizeofMutBigNat# mbn@(MBN# mba) s = normSizeofMutBigNat'# mbn sz# s'
where
!(# s', n# #) = getSizeofMutableByteArray# mba s
sz# = n# `uncheckedIShiftRA#` GMP_LIMB_SHIFT#
normSizeofMutBigNat'# :: MutBigNat s -> GmpSize#
-> State# s -> (# State# s, GmpSize# #)
normSizeofMutBigNat'# (MBN# mba) = go
where
go 0# s = (# s, 0# #)
go i0# s = case readWordArray# mba (i0# -# 1#) s of
(# s', 0## #) -> go (i0# -# 1#) s'
(# s', _ #) -> (# s', i0# #)
byteArrayToBigNat# :: ByteArray# -> GmpSize# -> BigNat
byteArrayToBigNat# ba# n0#
| isTrue# (n# ==# 0#) = zeroBigNat
| isTrue# (baszr# ==# 0#)
, isTrue# (baszq# ==# n#) = (BN# ba#)
| True = runS $ \s ->
let !(# s', mbn@(MBN# mba#) #) = newBigNat# n# s
!(# s'', ba_sz# #) = getSizeofMutableByteArray# mba# s'
go = do _ <- svoid (copyByteArray# ba# 0# mba# 0# ba_sz# )
unsafeFreezeBigNat# mbn
in go s''
where
!(# baszq#, baszr# #) = quotRemInt# (sizeofByteArray# ba#) GMP_LIMB_BYTES#
n# = fmssl (BN# ba#) (n0# -# 1#)
importIntegerFromAddr :: Addr# -> Word# -> Int# -> IO Integer
importIntegerFromAddr addr len msbf = IO $ do
bn <- liftIO (importBigNatFromAddr addr len msbf)
return (bigNatToInteger bn)
importBigNatFromAddr :: Addr# -> Word# -> Int# -> IO BigNat
importBigNatFromAddr _ 0## _ = IO (\s -> (# s, zeroBigNat #))
importBigNatFromAddr addr len0 1# = IO $ do
W# ofs <- liftIO (c_scan_nzbyte_addr addr 0## len0)
let len = len0 `minusWord#` ofs
addr' = addr `plusAddr#` (word2Int# ofs)
importBigNatFromAddr# addr' len 1#
importBigNatFromAddr addr len0 _ = IO $ do
W# len <- liftIO (c_rscan_nzbyte_addr addr 0## len0)
importBigNatFromAddr# addr len 0#
foreign import ccall unsafe "integer_gmp_scan_nzbyte"
c_scan_nzbyte_addr :: Addr# -> Word# -> Word# -> IO Word
foreign import ccall unsafe "integer_gmp_rscan_nzbyte"
c_rscan_nzbyte_addr :: Addr# -> Word# -> Word# -> IO Word
importBigNatFromAddr# :: Addr# -> Word# -> Int# -> S RealWorld BigNat
importBigNatFromAddr# _ 0## _ = return zeroBigNat
importBigNatFromAddr# addr len msbf = do
mbn@(MBN# mba#) <- newBigNat# n#
() <- liftIO (c_mpn_import_addr mba# addr 0## len msbf)
unsafeFreezeBigNat# mbn
where
n# = (word2Int# len +# (SIZEOF_HSWORD# -# 1#)) `quotInt#` SIZEOF_HSWORD#
foreign import ccall unsafe "integer_gmp_mpn_import"
c_mpn_import_addr :: MutableByteArray# RealWorld -> Addr# -> Word# -> Word#
-> Int# -> IO ()
importIntegerFromByteArray :: ByteArray# -> Word# -> Word# -> Int# -> Integer
importIntegerFromByteArray ba ofs len msbf
= bigNatToInteger (importBigNatFromByteArray ba ofs len msbf)
importBigNatFromByteArray :: ByteArray# -> Word# -> Word# -> Int# -> BigNat
importBigNatFromByteArray _ _ 0## _ = zeroBigNat
importBigNatFromByteArray ba ofs0 len0 1# = runS $ do
W# ofs <- liftIO (c_scan_nzbyte_bytearray ba ofs0 len0)
let len = (len0 `plusWord#` ofs0) `minusWord#` ofs
importBigNatFromByteArray# ba ofs len 1#
importBigNatFromByteArray ba ofs len0 _ = runS $ do
W# len <- liftIO (c_rscan_nzbyte_bytearray ba ofs len0)
importBigNatFromByteArray# ba ofs len 0#
foreign import ccall unsafe "integer_gmp_scan_nzbyte"
c_scan_nzbyte_bytearray :: ByteArray# -> Word# -> Word# -> IO Word
foreign import ccall unsafe "integer_gmp_rscan_nzbyte"
c_rscan_nzbyte_bytearray :: ByteArray# -> Word# -> Word# -> IO Word
importBigNatFromByteArray# :: ByteArray# -> Word# -> Word# -> Int#
-> S RealWorld BigNat
importBigNatFromByteArray# _ _ 0## _ = return zeroBigNat
importBigNatFromByteArray# ba ofs len msbf = do
mbn@(MBN# mba#) <- newBigNat# n#
() <- liftIO (c_mpn_import_bytearray mba# ba ofs len msbf)
unsafeFreezeBigNat# mbn
where
n# = (word2Int# len +# (SIZEOF_HSWORD# -# 1#)) `quotInt#` SIZEOF_HSWORD#
foreign import ccall unsafe "integer_gmp_mpn_import"
c_mpn_import_bytearray :: MutableByteArray# RealWorld -> ByteArray# -> Word#
-> Word# -> Int# -> IO ()
isValidBigNat# :: BigNat -> Int#
isValidBigNat# (BN# ba#)
= (szq# ># 0#) `andI#` (szr# ==# 0#) `andI#` isNorm#
where
isNorm#
| isTrue# (szq# ># 1#) = (indexWordArray# ba# (szq# -# 1#)) `neWord#` 0##
| True = 1#
sz# = sizeofByteArray# ba#
!(# szq#, szr# #) = quotRemInt# sz# GMP_LIMB_BYTES#
nextPrimeBigNat :: BigNat -> BigNat
nextPrimeBigNat bn@(BN# ba#) = runS $ do
mbn@(MBN# mba#) <- newBigNat# n#
(W# c#) <- liftIO (nextPrime# mba# ba# n#)
case c# of
0## -> unsafeFreezeBigNat# mbn
_ -> unsafeSnocFreezeBigNat# mbn c#
where
n# = sizeofBigNat# bn
foreign import ccall unsafe "integer_gmp_next_prime"
nextPrime# :: MutableByteArray# RealWorld -> ByteArray# -> GmpSize#
-> IO GmpLimb
type S s a = State# s -> (# State# s, a #)
infixl 1 >>=
infixl 1 >>
infixr 0 $
{-# INLINE ($) #-}
($) :: (a -> b) -> a -> b
f $ x = f x
{-# INLINE (>>=) #-}
(>>=) :: S s a -> (a -> S s b) -> S s b
(>>=) m k = \s -> case m s of (# s', a #) -> k a s'
{-# INLINE (>>) #-}
(>>) :: S s a -> S s b -> S s b
(>>) m k = \s -> case m s of (# s', _ #) -> k s'
{-# INLINE svoid #-}
svoid :: (State# s -> State# s) -> S s ()
svoid m0 = \s -> case m0 s of s' -> (# s', () #)
{-# INLINE return #-}
return :: a -> S s a
return a = \s -> (# s, a #)
{-# INLINE liftIO #-}
liftIO :: IO a -> S RealWorld a
liftIO (IO m) = m
runS :: S RealWorld a -> a
runS m = case runRW# m of (# _, a #) -> a
fail :: [Char] -> S s a
fail s = return (raise# s)
data SBigNat = NegBN !BigNat | PosBN !BigNat
absSBigNat :: SBigNat -> BigNat
absSBigNat (NegBN bn) = bn
absSBigNat (PosBN bn) = bn
ssizeofSBigNat# :: SBigNat -> GmpSize#
ssizeofSBigNat# (NegBN bn) = negateInt# (sizeofBigNat# bn)
ssizeofSBigNat# (PosBN bn) = sizeofBigNat# bn
intToSBigNat# :: Int# -> SBigNat
intToSBigNat# 0# = PosBN zeroBigNat
intToSBigNat# 1# = PosBN oneBigNat
intToSBigNat# (-1#) = NegBN oneBigNat
intToSBigNat# i# | isTrue# (i# ># 0#) = PosBN (wordToBigNat (int2Word# i#))
| True = NegBN (wordToBigNat (int2Word# (negateInt# i#)))
integerToSBigNat :: Integer -> SBigNat
integerToSBigNat (S# i#) = intToSBigNat# i#
integerToSBigNat (Jp# bn) = PosBN bn
integerToSBigNat (Jn# bn) = NegBN bn
sBigNatToInteger :: SBigNat -> Integer
sBigNatToInteger (NegBN bn) = bigNatToNegInteger bn
sBigNatToInteger (PosBN bn) = bigNatToInteger bn
cmpW# :: Word# -> Word# -> Ordering
cmpW# x# y#
| isTrue# (x# `ltWord#` y#) = LT
| isTrue# (x# `eqWord#` y#) = EQ
| True = GT
{-# INLINE cmpW# #-}
bitWord# :: Int# -> Word#
bitWord# = uncheckedShiftL# 1##
{-# INLINE bitWord# #-}
testBitWord# :: Word# -> Int# -> Int#
testBitWord# w# i# = (bitWord# i# `and#` w#) `neWord#` 0##
{-# INLINE testBitWord# #-}
popCntI# :: Int# -> Int#
popCntI# i# = word2Int# (popCnt# (int2Word# i#))
{-# INLINE popCntI# #-}
absI# :: Int# -> Int#
absI# i# = (i# `xorI#` nsign) -# nsign
where
nsign = uncheckedIShiftRA# i# (WORD_SIZE_IN_BITS# -# 1#)
sgnI# :: Int# -> Int#
sgnI# x# = (x# ># 0#) -# (x# <# 0#)
cmpI# :: Int# -> Int# -> Int#
cmpI# x# y# = (x# ># y#) -# (x# <# y#)
minI# :: Int# -> Int# -> Int#
minI# x# y# | isTrue# (x# <=# y#) = x#
| True = y#
fmssl :: BigNat -> Int# -> Int#
fmssl !bn i0# = go i0#
where
go i# | isTrue# (i# <# 0#) = 0#
| isTrue# (neWord# (indexBigNat# bn i#) 0##) = i# +# 1#
| True = go (i# -# 1#)