module Simulation.Aivika.Dynamics.Parameter
(newParameter,
newTableParameter,
newIndexedParameter) where
import Data.Array
import Data.IORef
import qualified Data.Map as M
import Control.Concurrent.MVar
import Simulation.Aivika.Dynamics.Internal.Simulation
import Simulation.Aivika.Dynamics.Internal.Dynamics
newParameter :: IO a -> IO (Dynamics a)
newParameter a = newIndexedParameter $ \_ -> a
newTableParameter :: Array Int a -> IO (Dynamics a)
newTableParameter t = newIndexedParameter (\i -> return $ t ! (((i i1) `mod` n) + i1))
where (i1, i2) = bounds t
n = i2 i1 + 1
newIndexedParameter :: (Int -> IO a) -> IO (Dynamics a)
newIndexedParameter f =
do lock <- newMVar ()
dict <- newIORef M.empty
return $ Dynamics $ \p ->
do let i = runIndex $ pointRun p
m <- readIORef dict
if M.member i m
then do let Just v = M.lookup i m
return v
else withMVar lock $
\() -> do { m <- readIORef dict;
if M.member i m
then do let Just v = M.lookup i m
return v
else do v <- f i
writeIORef dict $ M.insert i v m
return v }