{- | Identifier generator

Generates unique elements but elements can be declared as unused, again.

-}

module Haskore.General.IdGenerator.Set where

import Data.Set (Set)
import qualified Data.Set as Set
import Control.Monad.Trans.RWS(RWS, evalRWS, modify, get, ask, )
import Control.Monad (when, )

{- |

The generator is a reader+state monad
where the state consists of the allocated identifiers
and the reader source is the least element ever used.

-}

type T i a = RWS i () (Set i) a

run :: i -> T i a -> a
run start gen = fst $ evalRWS gen start Set.empty

{- |

Reserve a new id.

-}

alloc :: (Ord i, Enum i) => T i i
alloc =
   do start <- ask
      allocated <- get
      let newId = head $ filter (not . flip Set.member allocated) [start ..]
      modify (Set.insert newId)
      return newId

{- |

Deallocate an id.

-}

free :: (Ord i, Enum i) => i -> T i ()
free oldId =
   do allocated <- get
      when (not $ Set.member oldId allocated)
           (error "IdGeneratorSet.free: deallocated free identifier")
      modify (Set.delete oldId)