///////////////////////////////////////////////////////////////////////////// // 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_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