module Datafix.NodeAllocator
( NodeAllocator
, allocateNode
, runAllocator
) where
import Control.Monad.Fix (mfix)
import Control.Monad.Primitive
import Control.Monad.Trans.Class
import Control.Monad.Trans.State.Strict
import Data.Primitive.Array
import Datafix.Explicit
import Datafix.Utils.GrowableVector (GrowableVector)
import qualified Datafix.Utils.GrowableVector as GV
import System.IO.Unsafe (unsafePerformIO)
newtype NodeAllocator v a
= NodeAllocator { unwrapNodeAllocator :: StateT (GrowableVector (PrimState IO) v) IO a }
deriving (Functor, Applicative, Monad)
allocateNode :: (Node -> NodeAllocator v (a, v)) -> NodeAllocator v a
allocateNode f = NodeAllocator $ do
node <- gets GV.length
(result, _) <- mfix $ \ ~(_, entry) -> do
vec <- get
lift (GV.pushBack vec entry) >>= put
unwrapNodeAllocator (f (Node node))
return result
runAllocator :: NodeAllocator v a -> (a, Array v)
runAllocator (NodeAllocator alloc) = unsafePerformIO $ do
vec <- GV.new 8
(a, vec') <- runStateT alloc vec
vec'' <- GV.freeze vec'
return (a, vec'')