-- | NewNames is used for generating new names for Node's, Arc's, -- NodeType's and ArcType's in a graph on a globally unique basis. module Graphs.NewNames ( NameSource, NameSourceBranch, -- instance of Show/Read branch, -- :: NameSource -> IO NameSourceBranch useBranch, -- :: NameSourceBranch -> IO NameSource -- To make a new separate root use branch followed by useBranch initialBranch, -- :: NameSourceBranch -- Use this with useBranch to start the thing off. getNewName, -- :: NameSource -> IO String -- These strings always begin with a '.'. FrozenNameSource, -- instance of Read/Show freezeNameSource, -- :: NameSource -> IO FrozenNameSource defrostNameSource, -- :: NameSource -> FrozenNameSource -> IO () -- freeze/defrostNameSource convert and restore the current name source -- to and from a string. -- defrostNameSource should be handed a NameSource created from the -- same NameSourceBranch as that for which freezeNameSource was -- called, otherwise it raises an error. ) where import Util.Computation import Control.Concurrent data NameSource = NameSource { nameSourceId :: [Int], branchCounter :: MVar Int, nameCounter :: MVar Int -- Locking policy. Either branchCounter or nameCounter can be emptied -- separately, but may only remain empty for a short time in which -- no other locking/unlocking operations are done. -- If the two are emptied together, branchCounter should be emptied -- first. } ----------------------------------------------------------------------------- -- Creating and branching NameSource's ----------------------------------------------------------------------------- newtype NameSourceBranch = NameSourceBranch [Int] deriving (Read,Show) branch :: NameSource -> IO NameSourceBranch branch (NameSource {nameSourceId = nameSourceId,branchCounter = branchCounter}) = do branchNo <- takeMVar branchCounter putMVar branchCounter (branchNo+1) return (NameSourceBranch (branchNo:nameSourceId)) useBranch :: NameSourceBranch -> IO NameSource useBranch (NameSourceBranch nameSourceId) = do branchCounter <- newMVar 0 nameCounter <- newMVar 0 return (NameSource { nameSourceId = nameSourceId, branchCounter = branchCounter, nameCounter = nameCounter }) initialBranch :: NameSourceBranch initialBranch = NameSourceBranch [] ----------------------------------------------------------------------------- -- Getting new strings ----------------------------------------------------------------------------- getNewName :: NameSource -> IO String getNewName (NameSource {nameSourceId = nameSourceId,nameCounter=nameCounter}) = do nameNo <- takeMVar nameCounter putMVar nameCounter (nameNo+1) return (listToString (nameNo:nameSourceId)) listToString :: [Int] -> String -- produces compact representation of the argument beginning with a period. listToString numbers = concat (map (\ n -> '.':(show n)) numbers) ----------------------------------------------------------------------------- -- freeze/restoreNameSource ----------------------------------------------------------------------------- data FrozenNameSource = FrozenNameSource { frozenId :: [Int], frozenBranch :: Int, frozenName :: Int } deriving (Read,Show) freezeNameSource :: NameSource -> IO FrozenNameSource freezeNameSource (NameSource { nameSourceId = nameSourceId, branchCounter = branchCounter, nameCounter = nameCounter }) = do frozenBranch <- takeMVar branchCounter frozenName <- takeMVar nameCounter putMVar nameCounter frozenName putMVar branchCounter frozenBranch return (FrozenNameSource { frozenId = nameSourceId, frozenBranch = frozenBranch, frozenName = frozenName }) defrostNameSource :: NameSource -> FrozenNameSource -> IO () defrostNameSource (NameSource { nameSourceId = nameSourceId, branchCounter = branchCounter, nameCounter = nameCounter }) (FrozenNameSource { frozenId = frozenId, frozenBranch = frozenBranch, frozenName = frozenName }) = do let fail mess = ioError(userError("NewNames.defrostNameSource: "++mess)) if (nameSourceId /= frozenId) then fail "Name source mismatch" else done oldBranch <- takeMVar branchCounter putMVar branchCounter frozenBranch oldName <- takeMVar nameCounter putMVar nameCounter frozenName