/////////////////////////////////////////////////////////////////////////////
// calendar.cc
//
// SIMLIB version: 2.18
// Date: 2005-11-18
//
// Copyright (c) 1991-2005 Petr Peringer
//
// This library is licensed under GNU Library GPL. See the file COPYING.
//
//
// description: implementation of class Calendar
// uses double-linked list
//
////////////////////////////////////////////////////////////////////////////
// interface
//
#include "simlib.h"
#include "internal.h"
////////////////////////////////////////////////////////////////////////////
// implementation
//
SIMLIB_IMPLEMENTATION
class Calendar; // (internal)
/////////////////////////////////////////////////////////////////////////////
// EventNotice --- calendar item - PRIVATE for any implementation
//
struct EventNotice {
EventNotice * pred; // previous object in list
EventNotice * succ; // next object in list
Entity * entity; // which entity is scheduled
double time; // (re)activation time of entity
Entity::Priority_t priority; // priority at time of scheduling
EventNotice() : pred(this), succ(this), entity(0),
time(0), priority(0) {} // (for Calendar init)
EventNotice(Entity *p, double t) :
pred(this), succ(this), // NOT linked
entity(p), // which entity
time(t), // activation time
priority(p->Priority) // scheduling priority
{
entity->_Ev = this; // reverse connection to this activation record
}
~EventNotice() {
if(pred != this) { // remove from calendar
Unlink();
entity->_Ev = 0; // disconect: entity link
}
}
void Unlink() { // remove from calendar list
pred->succ = succ;
succ->pred = pred;
pred = succ = this; // NOT linked
}
void insert(EventNotice * s) {
if(pred != this) Unlink(); // is in calendar, remove first
// --- insert before item s
succ = s;
pred = s->pred;
pred->succ = this;
s->pred = this;
}
private:
EventNotice(const EventNotice&); // disable
void operator=(const EventNotice&);
};
////////////////////////////////////////////////////////////////////////////
// class Calendar --- list implementation of calendar
// +-----------------------------------------------+
// | +---+ +---+ +---+ |
// +-->| |<-- ...... -->| |<---->| |<--+
// +--+ +---+ +---+ +---+
// | Calendar |
// +----------+
// double-linked circular list (faster than std::list)
//
class Calendar : private EventNotice {
public:
class iterator { // bidirectional iterator
EventNotice *p;
public:
iterator(EventNotice*pos) : p(pos) {}
// only prefix version
iterator &operator++() { p = p->succ; return *this; }
iterator &operator--() { p = p->pred; return *this; }
// implicit operator = and copy constructor OK
EventNotice * operator*() { return p; }
bool operator != (iterator q) { return p!=q.p; }
bool operator == (iterator q) { return p==q.p; }
}; // iterator
iterator begin() { return succ; }
iterator end() { return this; }
bool empty() { return begin() == end(); }
///////////////////////////////////////////////////////////
EventNotice *EvNot(Entity *p, double t); // create/reuse EventNotice
static double ActivationTime(Entity *e) { // activation time
return ((EventNotice*)e->_Ev)->time; // e!=0 ###
}
void ScheduleFirst(Entity *p);
void ScheduleAt(Entity *p, double t);
Entity *Current(); // active process/event
Entity *Get(Entity *p); // remove process p from calendar
Entity *GetFirst() { // remove first from calendar
if(empty()) SIMLIB_internal_error(); // empty
EventNotice *first = *begin();
Entity *e = first->entity;
delete first; // remove from list, delete
return e;
}
void PredIns(EventNotice *what, iterator pos) {
what->insert(*pos);
}
static void clear(bool destroy=false); // remove/destroy all items
static void create() { // create single instance
dprintf(("Calendar::create()"));
if(instance==0) instance = new Calendar;
else SIMLIB_error(DuplicateCalendar);
SIMLIB_atexit(destroy); // last SIMLIB module cleanup calls this
_SetTime(NextTime,SIMLIB_MAXTIME);
}
static void destroy() { // destroy single instance
dprintf(("Calendar::destroy()"));
clear(true); // remove all contents
delete instance;
instance = 0;
}
private:
Calendar() { dprintf(("Calendar::Calendar()")); }
~Calendar() { dprintf(("Calendar::~Calendar()")); }
iterator Find(EventNotice *value);
public: ///###remove
static Calendar *instance; // unique calendar pointer [SINGLETON]
#ifndef NDEBUG
friend void Calendar_print(); // print of calendar contents
#endif
};
// static member initialization
Calendar *Calendar::instance = 0; // unique calendar pointer
////////////////////////////////////////////////////////////////////////////
// public INTERFACE = exported functions...
//
double SQS::ActivationTime(Entity *e) { // for Facility service interrupt
if(e->Idle()) SIMLIB_internal_error(); // passive entity
return Calendar::ActivationTime(e);
}
void SQS::ScheduleFirst(Entity *e) { // special for Process::Interrupt
if(Calendar::instance==0) Calendar::create();
Calendar::instance->ScheduleFirst(e);
}
void SQS::ScheduleAt(Entity *e, double t) { // schedule
if(Calendar::instance==0) Calendar::create();
Calendar::instance->ScheduleAt(e,t);
}
Entity *SQS::Get(Entity *e) { // remove entity p
if(Calendar::instance==0) Calendar::create();
return Calendar::instance->Get(e);
}
void SQS::Clear() { // remove all
if(Calendar::instance==0) Calendar::create();
Calendar::clear(true);
}
bool SQS::Empty() { // used by Run()
if(Calendar::instance==0) Calendar::create();
return Calendar::instance->empty();
}
Entity *SQS::Current() { // used by Run()
if(Calendar::instance==0) Calendar::create();
return Calendar::instance->Current();
}
////////////////////////////////////////////////////////////////////////////
// Calendar implementation
//
#define CHECKENTITY(eptr) if(!eptr) SIMLIB_error(EntityRefError)
#define CHECKTIME(t) if(t<Time) SIMLIB_error(SchedulingBeforeTime)
#define CHECKSCHEDULED(e) if(!e->_Ev) SIMLIB_error(EntityIsNotScheduled)
////////////////////////////////////////////////////////////////////////////
// EvNot - creates the EventNotice
//
inline EventNotice *Calendar::EvNot(Entity *p, double t)
{
register EventNotice *evn = (EventNotice*)p->_Ev;
if(evn) { // is scheduled already --- REUSE
evn->Unlink(); // remove from calendar list, ### should be connected
evn->time = t; // change reactivation time
evn->priority = p->Priority; // set priority
}
else {
evn = new EventNotice(p,t);
}
// dprintf(("newCalendarEntity(ent=%p,t=%g,prio=%u) %p",
// p, evn->time, evn->priority, this));
return evn;
}
////////////////////////////////////////////////////////////////////////////
// Find --- find insert position (Time,priority) // higher priority first
//
inline Calendar::iterator Calendar::Find(EventNotice *en)
{
Entity::Priority_t prio = en->priority;
double Time = en->time;
if(empty())
return end();
register iterator evn = --end(); // search from back
while(evn!=end() && (*evn)->time > Time) { // search time
--evn;
}
while(evn!=end() && (*evn)->time==Time && // equal time...
(*evn)->priority < prio) { // ...search priority
--evn;
}
++evn;
return evn; // return insert position or end()
}
////////////////////////////////////////////////////////////////////////////
// ScheduleAt - schedule entity e at time t
//
void Calendar::ScheduleAt(Entity *e, double t)
{
dprintf(("Calendar::ScheduleAt(%s,%g)", e->Name(), t));
CHECKENTITY(e);
CHECKTIME(t);
EventNotice *evn = EvNot(e,t);
iterator pos = Find(evn);
PredIns( evn, pos );
// if first item inserted:
_SetTime(NextTime, (*begin())->time);
}
////////////////////////////////////////////////////////////////////////////
// ScheduleFirst - schedule entity e -- first in calendar
//
void Calendar::ScheduleFirst(Entity *e)
{
dprintf(("Calendar::ScheduleFirst(%s)", e->Name()));
CHECKENTITY(e);
EventNotice *evn = EvNot(e,Time);
PredIns( evn, begin() );
_SetTime(NextTime, evn->time);
}
////////////////////////////////////////////////////////////////////////////
// Current - pointer to first -- active entity
//
Entity *Calendar::Current()
{
if(empty()) SIMLIB_error(EmptyCalendar);
return (*begin())->entity;
}
////////////////////////////////////////////////////////////////////////////
// Get - remove entity e from calendar
//
Entity *Calendar::Get(Entity *e)
{
if(empty()) SIMLIB_error(EmptyCalendar);
CHECKSCHEDULED(e);
delete (EventNotice*)e->_Ev; // disconnect, remove item
if(empty()) _SetTime(NextTime, SIMLIB_MAXTIME);
else _SetTime(NextTime, (*begin())->time);
return e;
}
////////////////////////////////////////////////////////////////////////////
// Clear --- remove all event notices, destroy
//
void Calendar::clear(bool destroy)
{
dprintf(("Calendar::clear(%s)", destroy?"true":"false"));
while(!instance->empty()) {
Entity *p = instance->GetFirst();
if (destroy && p->IsAllocated()) delete p; // delete entity
}
_SetTime(NextTime, SIMLIB_MAXTIME); // no scheduled event
}
#ifndef NDEBUG
////////////////////////////////////////////////////////////////////////////
void Calendar_print() // print of calendar contents - FOR DEBUGGING ONLY
{
Print("Calendar (SQS):\n");
if(Calendar::instance==0) return;
Calendar::iterator p = Calendar::instance->begin();
Calendar::iterator end = Calendar::instance->end();
for( int u=1; p!=end; ++p, ++u ) {
Print(" [%u]: \t", u ); // schedule time
Print("%s\t", (*p)->entity->Name() ); // print entity ID
Print("activation time = %g \n", (*p)->time ); // schedule time
}
Print("\n");
}
#endif
// end
syntax highlighted by Code2HTML, v. 0.9.1