{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE RankNTypes #-}
module Data.HeterogeneousEnvironment
( KeyGen
, HeterogeneousEnvironment
, Key
, newKeyGen
, empty
, makeKey
, lookup
, insert
, delete
, adjust
, getKeyId
) where
import Control.Monad
import Data.IntMap (IntMap)
import qualified Data.IntMap as IM
import Data.IORef
import GHC.Exts
import Prelude hiding (lookup)
import Unsafe.Coerce
data HeterogeneousEnvironment = HeterogeneousEnvironment (IntMap Any)
newtype Key a = Key Int
newtype KeyGen = KeyGen (IORef Int)
newKeyGen :: IO KeyGen
newKeyGen = liftM KeyGen $ newIORef 0
getKeyId :: Key a -> Int
getKeyId (Key x) = x
empty :: HeterogeneousEnvironment
empty = HeterogeneousEnvironment $ IM.empty
makeKey :: KeyGen -> IO (Key a)
makeKey (KeyGen gen) = do
k <- atomicModifyIORef gen nextKey
return $ Key k
where
nextKey !x = if x >= maxBound-1
then error "too many keys generated"
else let !x' = x+1 in (x',x)
lookup :: Key a -> HeterogeneousEnvironment -> Maybe a
lookup (Key k) (HeterogeneousEnvironment m) = fmap unsafeCoerce $ IM.lookup k m
insert :: Key a -> a -> HeterogeneousEnvironment -> HeterogeneousEnvironment
insert (Key k) v (HeterogeneousEnvironment m) = HeterogeneousEnvironment $
IM.insert k (unsafeCoerce v) m
delete :: Key a -> HeterogeneousEnvironment -> HeterogeneousEnvironment
delete (Key k) (HeterogeneousEnvironment m) = HeterogeneousEnvironment $
IM.delete k m
adjust :: (a -> a) -> Key a -> HeterogeneousEnvironment -> HeterogeneousEnvironment
adjust f (Key k) (HeterogeneousEnvironment m) = HeterogeneousEnvironment $
IM.adjust f' k m
where
f' = unsafeCoerce . f . unsafeCoerce