{-# LINE 1 "src/Data/Number/Flint/Flint/FFI.hsc" #-}
{-|
module      :  Data.Number.Flint.Flint.FFI
copyright   :  (c) 2022 Hartmut Monien
license     :  GNU GPL, version 2 or above (see LICENSE)
maintainer  :  hmonien@uni-bonn.de
-}
module Data.Number.Flint.Flint.FFI (
  -- * Allocation Functions
    flint_malloc
  , flint_realloc
  , flint_calloc
  -- * Constants
  , flint_bits
  -- * Random Numbers
  , FRandState (..)
  , CFRandState (..)
  , newFRandState
  , withFRandState
  , flint_rand_alloc
  , flint_rand_free
  , flint_randinit
  , flint_randclear
  -- * Thread functions
  , flint_set_num_threads
  , flint_get_num_threads
  , flint_set_num_workers
  , flint_reset_num_workers
) where 

-- global definitions ----------------------------------------------------------

import Foreign.C.String
import Foreign.C.Types
import Foreign.ForeignPtr
import Foreign.Ptr ( Ptr, FunPtr, plusPtr )
import Foreign.Storable
import Foreign.Marshal ( free )

import Data.Number.Flint.Flint.Internal



-- Allocation Functions --------------------------------------------------------

-- | /flint_malloc/ /size/ 
-- 
-- Allocate @size@ bytes of memory.
foreign import ccall "flint.h flint_malloc"
  flint_malloc :: Ptr CSize -> IO ()

-- | /flint_realloc/ /ptr/ /size/ 
-- 
-- Reallocate an area of memory previously allocated by @flint_malloc@,
-- @flint_realloc@, or @flint_calloc@.
foreign import ccall "flint.h flint_realloc"
  flint_realloc :: Ptr () -> Ptr CSize -> IO ()

-- | /flint_calloc/ /num/ /size/ 
-- 
-- Allocate @num@ objects of @size@ bytes each, and zero the allocated
-- memory.
foreign import ccall "flint.h flint_calloc"
  flint_calloc :: Ptr CSize -> Ptr CSize -> IO ()

-- Constants -------------------------------------------------------------------

flint_release :: CULong
flint_release :: CULong
flint_release = CULong
30000
{-# LINE 69 "src/Data/Number/Flint/Flint/FFI.hsc" #-}
flint_bits :: CULong
flint_bits :: CULong
flint_bits = CULong
64
{-# LINE 71 "src/Data/Number/Flint/Flint/FFI.hsc" #-}
flint_d_bits :: CULong
flint_d_bits :: CULong
flint_d_bits = CULong
53
{-# LINE 73 "src/Data/Number/Flint/Flint/FFI.hsc" #-}

-- Random Numbers --------------------------------------------------------------

data FRandState = FRandState {-# UNPACK #-} !(ForeignPtr CFRandState)
type CFRandState = CFlint FRandState

instance Storable CFRandState where
  {-# INLINE sizeOf #-}
  sizeOf :: CFRandState -> Int
sizeOf CFRandState
_ = (Int
56)
{-# LINE 82 "src/Data/Number/Flint/Flint/FFI.hsc" #-}
  {-# INLINE alignment #-}
  alignment :: CFRandState -> Int
alignment CFRandState
_ = Int
8
{-# LINE 84 "src/Data/Number/Flint/Flint/FFI.hsc" #-}
  peek = error "CFRandState.peek: Not defined"
  poke :: Ptr CFRandState -> CFRandState -> IO ()
poke = [Char] -> Ptr CFRandState -> CFRandState -> IO ()
forall a. HasCallStack => [Char] -> a
error [Char]
"CFRandState.poke: Not defined"

newFRandState :: IO FRandState
newFRandState = do
  ForeignPtr CFRandState
p <- IO (ForeignPtr CFRandState)
forall a. Storable a => IO (ForeignPtr a)
mallocForeignPtr
  ForeignPtr CFRandState -> (Ptr CFRandState -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CFRandState
p Ptr CFRandState -> IO ()
flint_randinit
  FinalizerPtr CFRandState -> ForeignPtr CFRandState -> IO ()
forall a. FinalizerPtr a -> ForeignPtr a -> IO ()
addForeignPtrFinalizer FinalizerPtr CFRandState
p_flint_randclear ForeignPtr CFRandState
p
  FRandState -> IO FRandState
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (FRandState -> IO FRandState) -> FRandState -> IO FRandState
forall a b. (a -> b) -> a -> b
$ ForeignPtr CFRandState -> FRandState
FRandState ForeignPtr CFRandState
p

{-# INLINE withFRandState #-}
withFRandState :: FRandState -> (Ptr CFRandState -> IO a) -> IO (FRandState, a)
withFRandState (FRandState ForeignPtr CFRandState
p) Ptr CFRandState -> IO a
f = do
  ForeignPtr CFRandState
-> (Ptr CFRandState -> IO (FRandState, a)) -> IO (FRandState, a)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr CFRandState
p ((Ptr CFRandState -> IO (FRandState, a)) -> IO (FRandState, a))
-> (Ptr CFRandState -> IO (FRandState, a)) -> IO (FRandState, a)
forall a b. (a -> b) -> a -> b
$ \Ptr CFRandState
fp -> Ptr CFRandState -> IO a
f Ptr CFRandState
fp IO a -> (a -> IO (FRandState, a)) -> IO (FRandState, a)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (FRandState, a) -> IO (FRandState, a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((FRandState, a) -> IO (FRandState, a))
-> (a -> (FRandState, a)) -> a -> IO (FRandState, a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ForeignPtr CFRandState -> FRandState
FRandState ForeignPtr CFRandState
p,)

--------------------------------------------------------------------------------

-- | /flint_rand_alloc/ 
-- 
-- Allocates a @flint_rand_t@ object to be used like a heap-allocated
-- @flint_rand_t@ in external libraries. The random state is not
-- initialised.
foreign import ccall "flint.h flint_rand_alloc"
  flint_rand_alloc :: IO (Ptr CFRandState)

-- | /flint_rand_free/ /state/ 
-- 
-- Frees a random state object as allocated using @flint_rand_alloc@.
foreign import ccall "flint.h flint_rand_free"
  flint_rand_free :: Ptr CFRandState -> IO ()

-- | /flint_randinit/ /state/ 
-- 
-- Initialize a @flint_rand_t@.
foreign import ccall "flint.h flint_randinit"
  flint_randinit :: Ptr CFRandState -> IO ()

-- | /flint_randclear/ /state/ 
-- 
-- Free all memory allocated by @flint_rand_init@.
foreign import ccall "flint.h flint_randclear"
  flint_randclear :: Ptr CFRandState -> IO ()

foreign import ccall "flint.h &flint_randclear"
  p_flint_randclear :: FunPtr (Ptr CFRandState -> IO ())

-- Thread functions ------------------------------------------------------------

-- | /flint_set_num_threads/ /num_threads/ 
-- 
-- Set up a thread pool of @num_threads - 1@ worker threads (in addition to
-- the master thread) and set the maximum number of worker threads the
-- master thread can start to @num_threads - 1@.
-- 
-- This function may only be called globally from the master thread. It can
-- also be called at a global level to change the size of the thread pool,
-- but an exception is raised if the thread pool is in use (threads have
-- been woken but not given back). The function cannot be called from
-- inside worker threads.
foreign import ccall "flint.h flint_set_num_threads"
  flint_set_num_threads :: CInt -> IO ()

-- | /flint_get_num_threads/ 
-- 
-- When called at the global level, this function returns one more than the
-- number of worker threads in the Flint thread pool, i.e. it counts the
-- workers in the thread pool plus one more for the master thread.
-- 
-- In general, this function returns one more than the number of additional
-- worker threads that can be started by the current thread.
-- 
-- Use @thread_pool_wake@ to set this number for a given worker thread.
foreign import ccall "flint.h flint_get_num_threads"
  flint_get_num_threads :: IO ()

-- | /flint_set_num_workers/ /num_workers/ 
-- 
-- Restricts the number of worker threads that can be started by the
-- current thread to @num_workers@. This function can be called from any
-- thread.
-- 
-- Assumes that the Flint thread pool is already set up.
-- 
-- The function returns the old number of worker threads that can be
-- started.
-- 
-- The function can only be used to reduce the number of workers that can
-- be started from a thread. It cannot be used to increase the number. If a
-- higher number is passed, the function has no effect.
-- 
-- The number of workers must be restored to the original value by a call
-- to @flint_reset_num_workers@ before the thread is returned to the thread
-- pool.
-- 
-- The main use of this function and @flint_reset_num_workers@ is to
-- cheaply and temporarily restrict the number of workers that can be
-- started, e.g. by a function that one wishes to call from a thread, and
-- cheaply restore the number of workers to its original value before
-- exiting the current thread.
foreign import ccall "flint.h flint_set_num_workers"
  flint_set_num_workers :: CInt -> IO CInt

-- | /flint_reset_num_workers/ /num_workers/ 
-- 
-- After a call to @flint_set_num_workers@ this function must be called to
-- set the number of workers that may be started by the current thread back
-- to its original value.
foreign import ccall "flint.h flint_reset_num_workers"
  flint_reset_num_workers :: CInt -> IO ()