{-
- Copyright (c) 2008, Jochem Berndsen
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the author nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-}-- |-- Module : Control.Hasim.DES-- Copyright : (c) Jochem Berndsen 2008-- License : BSD3---- Maintainer : jochem@functor.nl-- Stability : experimental-- Portability : unportable---- This module defines a /DES/, which stands for /Discrete Event Set/.-- There are functions for creating and inserting events.---- For each process, an 'Event' may be scheduled. This event consists of-- a 'Time' and a 'Runnable'. There can be at most one 'Event' scheduled-- for each 'Process'.moduleControl.Hasim.DES(-- * Events-- ** Abstract data typeEvent,-- ** Querying eventseTime,eRunnable,eProcess,-- * Discrete Event Set-- ** ADT for Discrete Event SetDES,-- ** Creating Discrete Event SetinitDES,emptyDES,-- ** Querying Discrete Event SetisEmpty,-- * Updating Discrete Event SetremoveNext,update)where-- Internal importsimportControl.Hasim.ProcessimportControl.Hasim.Types-- External importsimportControl.MonadimportData.IORefimportData.Maybe-- | Event. An event consists of a 'Time' and a 'Runnable'dataEvent=Event{eTime::Time-- ^ The 'Time' at which the event takes place.,eRunnable::Runnable-- ^ The 'Runnable' that should be run at this time}-- | The process of an 'Event'eProcess::Event->ProcesseProcess=runnable2process.eRunnableinstanceShowEventwhereshowe="Event { t = "++t++", proc = "++p++" }"wheret=show(eTimee)p=show(eProcesse)-- | Discrete Event Set. A discrete event set is a data structure-- that supports the operations 'update' and 'removeNext'.newtypeDES=DES{unDES::[Event]}instanceShowDESwhereshow=show.unDES-- | Is the Discrete Event Set empty?isEmpty::DES->BoolisEmpty=null.unDES-- | Get an event with lowest time that will take place next.-- Returns a tuple @(evt, des)@ where @evt@ is the next 'Event'-- and @des@ is the new 'DES' where this event is removed.---- Calls 'error' if the 'DES' is empty.removeNext::DES->(Event,DES)removeNext(DES(e:es))=(e,DESes)removeNext(DES[])=error"Control.Hasim.DES.removeNext : empty discrete event set"insert::Event->DES->DESinserte'=DES.go.unDESwheregoes=left++[e']++rightwhere(left,right)=span(\e->eTimee'>=eTimee)es-- | Schedule an event in a discrete event set. Note that an old-- event of the same process is removed from the discrete event set.update::Time-- ^ The time at which the event takes place->Runnable-- ^ The 'Runnable' that should be run at that time->DES-- ^ The old discrete event set->DES-- ^ The discrete event set with the event addedupdatenewtimerunnable=insertevt.DES.rmv.unDESwhereproc=runnable2processrunnablermv=filter((/=proc).eProcess)evt=Event{eTime=newtime,eRunnable=runnable}-- | Create a new 'DES'. For each 'Process', an 'Event' is scheduled-- at time 0 and with 'Runnable' the associated 'Runnable' of the 'Process'.initDES::[Process]-- ^ The list of processes->IODES-- ^ IO, with result the created DESinitDESps=DES`liftM`mapM(\(Processp)->domRunnable<-readIORef(actionp)when(isNothingmRunnable)(fail"Control.Hasim.DES.initDES: Process without action")return$!Event{eTime=0,eRunnable=fromJustmRunnable})ps-- | An empty discrete event set.emptyDES::DESemptyDES=DES[]