packages feed

synthesizer-llvm-0.6: src/Synthesizer/LLVM/EventIterator.hs

{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ForeignFunctionInterface #-}
module Synthesizer.LLVM.EventIterator where

import qualified Data.EventList.Relative.BodyTime as EventList
import qualified Numeric.NonNegative.Wrapper as NonNeg

import qualified LLVM.Extra.Memory as Memory
import qualified LLVM.Extra.Class as Class

import Data.Word (Word32, )
import Foreign.Storable (Storable, poke, )
import Foreign.Ptr (Ptr, castPtr, )

import Foreign.StablePtr (StablePtr, newStablePtr, freeStablePtr, deRefStablePtr, )
import Foreign.Ptr (FunPtr, )
import Data.IORef (IORef, newIORef, readIORef, writeIORef, )

import Control.Monad ((<=<), )

import qualified Synthesizer.LLVM.Debug.StablePtr as DebugStable


{-
For problems on constraints, see ChunkIterator.
-}
data T a =
   (Storable a, Class.MakeValueTuple a, Memory.C (Class.ValueTuple a)) =>
   Cons (IORef (EventList.T NonNeg.Int a))

type MemoryPtr a = Ptr (Memory.Struct (Class.ValueTuple a))


foreign import ccall "&nextConstant"
   nextCallBack ::
      FunPtr (
         StablePtr (T a) ->
         MemoryPtr a -> IO Word32
      )

foreign export ccall "nextConstant"
   next ::
      StablePtr (T a) ->
      MemoryPtr a -> IO Word32


{- |
Events with subsequent duration 0 are ignored
(and for performance reasons it should not contain too many small values,
say below 100).
-}
new ::
   (Storable a, Class.MakeValueTuple a, Memory.C (Class.ValueTuple a)) =>
   EventList.T NonNeg.Int a -> IO (StablePtr (T a))
new evs =
   DebugStable.trace "new" =<<
   newStablePtr . Cons
    =<< newIORef
      (EventList.fromPairList $
       filter ((/=0) . snd) $
       EventList.toPairList evs)

dispose ::
   StablePtr (T a) -> IO ()
dispose = freeStablePtr <=< DebugStable.trace "dispose"

next ::
   StablePtr (T a) ->
   MemoryPtr a -> IO Word32
next stable eventPtr =
   DebugStable.trace "next" stable >>=
   deRefStablePtr >>= \state ->
   case state of
      Cons listRef ->
         readIORef listRef >>=
         EventList.switchL
            (return 0)
            (\body time xs ->
               writeIORef listRef xs >>
               poke (castPtr eventPtr) body >>
               return (fromIntegral time))