module Numeric.GMP.Utils
(
withInInteger'
, withInInteger
, withInOutInteger
, withInOutInteger_
, withOutInteger
, withOutInteger_
, peekInteger'
, peekInteger
, pokeInteger
, withInRational'
, withInRational
, withInOutRational
, withInOutRational_
, withOutRational
, withOutRational_
, peekRational'
, peekRational
, pokeRational
) where
import Control.Exception (bracket_)
import Data.Ratio ((%), numerator, denominator)
import Foreign (allocaBytes, alloca, with, sizeOf, peek)
import GHC.Integer.GMP.Internals
( Integer(..)
, BigNat(..)
, sizeofBigNat#
, byteArrayToBigNat#
, bigNatToInteger
, bigNatToNegInteger
)
import GHC.Prim
( ByteArray#
, sizeofByteArray#
, copyByteArrayToAddr#
, newByteArray#
, copyAddrToByteArray#
, unsafeFreezeByteArray#
)
import GHC.Exts (Int(..), Ptr(..))
import GHC.Types (IO(..))
import Numeric.GMP.Types
import Numeric.GMP.Raw.Unsafe
( mpz_init
, mpz_clear
, mpq_init
, mpq_clear
, mpz_set
)
foreign import ccall unsafe "mpz_set_HsInt"
mpz_set_HsInt :: Ptr MPZ -> Int -> IO ()
withInInteger' :: Integer -> (MPZ -> IO r) -> IO r
withInInteger' i action = case i of
S# n# -> alloca $ \src -> bracket_ (mpz_init src) (mpz_clear src) $ do
mpz_set_HsInt src (I# n#)
z <- peek src
r <- action z
return r
Jp# bn@(BN# ba#) -> withByteArray ba# $ \d _ -> action MPZ
{ mpzAlloc = 0
, mpzSize = fromIntegral (I# (sizeofBigNat# bn))
, mpzD = d
}
Jn# bn@(BN# ba#) -> withByteArray ba# $ \d _ -> action MPZ
{ mpzAlloc = 0
, mpzSize = fromIntegral (I# (sizeofBigNat# bn))
, mpzD = d
}
withByteArray :: ByteArray# -> (Ptr a -> Int -> IO r) -> IO r
withByteArray ba# f = do
let bytes = I# (sizeofByteArray# ba#)
allocaBytes bytes $ \ptr@(Ptr addr#) -> do
IO (\s -> (# copyByteArrayToAddr# ba# 0# addr# (sizeofByteArray# ba#) s, () #))
f ptr bytes
withInInteger :: Integer -> (Ptr MPZ -> IO r) -> IO r
withInInteger i action = withInInteger' i $ \z -> with z action
withInOutInteger :: Integer -> (Ptr MPZ -> IO a) -> IO (Integer, a)
withInOutInteger n action = withOutInteger $ \z -> do
pokeInteger z n
action z
withInOutInteger_ :: Integer -> (Ptr MPZ -> IO a) -> IO Integer
withInOutInteger_ n action = do
(z, _) <- withInOutInteger n action
return z
withOutInteger :: (Ptr MPZ -> IO a) -> IO (Integer, a)
withOutInteger action = alloca $ \ptr ->
bracket_ (mpz_init ptr) (mpz_clear ptr) $ do
a <- action ptr
z <- peekInteger ptr
return (z, a)
withOutInteger_ :: (Ptr MPZ -> IO a) -> IO Integer
withOutInteger_ action = do
(z, _) <- withOutInteger action
return z
pokeInteger :: Ptr MPZ -> Integer -> IO ()
pokeInteger dst (S# n#) = mpz_set_HsInt dst (I# n#)
pokeInteger dst j = withInInteger j $ mpz_set dst
peekInteger' :: MPZ -> IO Integer
peekInteger' MPZ{ mpzSize = size, mpzD = d } = do
if size == 0 then return 0 else
asByteArray d (fromIntegral (abs size) * sizeOf (undefined :: MPLimb))
(\ba# -> return $ case fromIntegral (abs size) of
I# size# -> (if size < 0 then bigNatToNegInteger else bigNatToInteger)
(byteArrayToBigNat# ba# size#)
)
asByteArray :: Ptr a -> Int -> (ByteArray# -> IO r) -> IO r
asByteArray (Ptr addr#) (I# bytes#) f = do
IO $ \s# -> case newByteArray# bytes# s# of
(# s'#, mba# #) ->
case unsafeFreezeByteArray# mba# (copyAddrToByteArray# addr# mba# 0# bytes# s'#) of
(# s''#, ba# #) -> case f ba# of IO r -> r s''#
peekInteger :: Ptr MPZ -> IO Integer
peekInteger src = do
z <- peek src
peekInteger' z
withInRational' :: Rational -> (MPQ -> IO r) -> IO r
withInRational' q action =
withInInteger' (numerator q) $ \nz ->
withInInteger' (denominator q) $ \dz ->
action (MPQ nz dz)
withInRational :: Rational -> (Ptr MPQ -> IO r) -> IO r
withInRational q action = withInRational' q $ \qq -> with qq action
withInOutRational :: Rational -> (Ptr MPQ -> IO a) -> IO (Rational, a)
withInOutRational n action = withOutRational $ \q -> do
pokeRational q n
action q
withInOutRational_ :: Rational -> (Ptr MPQ -> IO a) -> IO Rational
withInOutRational_ n action = do
(q, _) <- withInOutRational n action
return q
withOutRational :: (Ptr MPQ -> IO a) -> IO (Rational, a)
withOutRational action = alloca $ \ptr ->
bracket_ (mpq_init ptr) (mpq_clear ptr) $ do
a <- action ptr
q <- peekRational ptr
return (q, a)
withOutRational_ :: (Ptr MPQ -> IO a) -> IO Rational
withOutRational_ action = do
(q, _) <- withOutRational action
return q
pokeRational :: Ptr MPQ -> Rational -> IO ()
pokeRational ptr q = do
pokeInteger (mpq_numref ptr) (numerator q)
pokeInteger (mpq_denref ptr) (denominator q)
peekRational' :: MPQ -> IO Rational
peekRational' (MPQ n d) = do
num <- peekInteger' n
den <- peekInteger' d
return (num % den)
peekRational :: Ptr MPQ -> IO Rational
peekRational src = do
q <- peek src
peekRational' q