Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

TimerEventTracker.cxx

00001 /*
00002  * Copyright 2002 Eric M. Hopper <hopper@omnifarious.org>
00003  * 
00004  *     This program is free software; you can redistribute it and/or modify it
00005  *     under the terms of the GNU Lesser General Public License as published
00006  *     by the Free Software Foundation; either version 2 of the License, or
00007  *     (at your option) any later version.
00008  * 
00009  *     This program is distributed in the hope that it will be useful, but
00010  *     WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  *     Lesser General Public License for more details.
00013  * 
00014  *     You should have received a copy of the GNU Lesser General Public
00015  *     License along with this program; if not, write to the Free Software
00016  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017  */
00018 
00019 /* $Header: /home/hopper/src/cvs/C++/UniEvent/TimerEventTracker.cxx,v 1.5 2002/08/29 00:58:05 hopper Exp $ */
00020 
00021 // For a log, see ChangeLog
00022 
00023 #ifdef __GNUG__
00024 #  pragma implementation "TimerEventTracker.h"
00025 #endif
00026 
00027 #include "UniEvent/TimerEventTracker.h"
00028 #include "UniEvent/EventPtr.h"
00029 #include "UniEvent/Dispatcher.h"
00030 #include <map>
00031 #include <ctime>
00032 #include <stdexcept>
00033 #include <iostream>
00034 
00035 namespace strmod {
00036 namespace unievent {
00037 
00038 const UNEVT_ClassIdent TimerEventTracker::identifier(14UL);
00039 
00040 typedef Timer::interval_t interval_t;
00041 typedef Timer::absolute_t absolute_t;
00042 
00043 namespace {
00044 struct compare_intervals
00045 {
00046    inline bool operator ()(const interval_t &a, const interval_t &b) const;
00047 };
00048 
00049 inline bool
00050 compare_intervals::operator ()(const interval_t &a, const interval_t &b) const
00051 {
00052    return (a.seconds < b.seconds) ||
00053       ((a.seconds == b.seconds) && (a.nanoseconds < b.nanoseconds));
00054 }
00055 
00056 }
00057 
00058 typedef std::multimap<interval_t, EventPtr, compare_intervals> timerheap_t;
00059 
00060 class TimerEventTracker::Imp
00061 {
00062  public:
00063    timerheap_t map1_;
00064    timerheap_t map2_;
00065    bool map1_current_;
00066 
00067    Imp() : map1_current_(true) {}
00068 };
00069 
00070 TimerEventTracker::TimerEventTracker()
00071      : old_base_(::time(0)), current_base_(old_base_),
00072        base_diff_(0, 0), impl_(*new Imp)
00073 {
00074 }
00075 
00076 TimerEventTracker::TimerEventTracker(const absolute_t &now)
00077      : old_base_(now.time), current_base_(old_base_),
00078        base_diff_(0, 0), impl_(*new Imp)
00079 {
00080 }
00081 
00082 TimerEventTracker::~TimerEventTracker()
00083 {
00084    delete &impl_;
00085 }
00086 
00087 void TimerEventTracker::postAt(const absolute_t &t, const EventPtr &ev)
00088 {
00089    timerheap_t &theheap = impl_.map1_current_ ? impl_.map1_ : impl_.map2_;
00090    absolute_t curbase = absolute_t(current_base_);
00091    interval_t timexp = (curbase < t) ? (t - curbase) : interval_t(0, 0);
00092    theheap.insert(timerheap_t::value_type(timexp, ev));
00093 }
00094 
00095 unsigned int
00096 TimerEventTracker::postExpired(const absolute_t &now, Dispatcher *postto)
00097 {
00098    if (now < current_base_)
00099    {
00100       throw ::std::range_error("TimerEventTracker::postExpired: The now "
00101                                "parameter is not >= than all previous now "
00102                                "parameters.");
00103    }
00104    unsigned int numposted = 0;
00105    timerheap_t &theheap = impl_.map1_current_ ? impl_.map1_ : impl_.map2_;
00106    timerheap_t &theoldheap = impl_.map1_current_ ? impl_.map2_ : impl_.map1_;
00107    {
00108       const timerheap_t::iterator curend = theheap.upper_bound(now - current_base_);
00109       const timerheap_t::iterator oldend = (theoldheap.size() <= 0) ?
00110          theoldheap.begin() :
00111          theoldheap.upper_bound(now - old_base_);
00112       timerheap_t::iterator curi = theheap.begin();
00113       timerheap_t::iterator oldi = theoldheap.begin();
00114       while ((curi != curend) || (oldi != oldend))
00115       {
00116          bool postold = true;
00117          if (oldi == oldend)
00118          {
00119             postold = false;
00120          }
00121          else if ((curi != curend) && (curi->first < (oldi->first + base_diff_)))
00122          {
00123             postold = false;
00124          }
00125          if (postold)
00126          {
00127             postto->addEvent(oldi->second);
00128             ++oldi;
00129             ++numposted;
00130          }
00131          else
00132          {
00133             postto->addEvent(curi->second);
00134             ++curi;
00135             ++numposted;
00136          }
00137       }
00138       theheap.erase(theheap.begin(), curend);
00139       theoldheap.erase(theoldheap.begin(), oldend);
00140    }
00141    if ((now.time != current_base_) &&
00142        (now - current_base_).seconds >= (7U * 24U * 60U * 60U))
00143    {
00144       const timerheap_t::iterator oldend = theoldheap.end();
00145       for (timerheap_t::iterator i = theoldheap.begin(); i != oldend; ++i)
00146       {
00147          theheap.insert(timerheap_t::value_type(i->first + base_diff_, i->second));
00148       }
00149       theoldheap.clear();
00150       old_base_ = current_base_;
00151       current_base_ = now.time;
00152       base_diff_ = absolute_t(current_base_) - absolute_t(old_base_);
00153       impl_.map1_current_ = !impl_.map1_current_;
00154    }
00155    return numposted;
00156 }
00157 
00158 Timer::interval_t
00159 TimerEventTracker::nextExpirationIn(const absolute_t &now,
00160                                     const interval_t &maxtime) const
00161 {
00162    if (now < current_base_)
00163    {
00164       throw ::std::range_error("TimerEventTracker::nextExpirationIn: The now "
00165                                "parameter is not >= than all previous now "
00166                                "parameters.");
00167    }
00168    const timerheap_t &curheap = impl_.map1_current_ ? impl_.map1_ : impl_.map2_;
00169    const timerheap_t &oldheap = impl_.map1_current_ ? impl_.map2_ : impl_.map1_;
00170    absolute_t earliest = now;
00171    if (curheap.size() > 0)
00172    {
00173       earliest = absolute_t(current_base_, curheap.begin()->first);
00174       if (oldheap.size() > 0)
00175       {
00176          absolute_t contender = absolute_t(old_base_, oldheap.begin()->first);
00177          if (contender < earliest)
00178          {
00179             earliest = contender;
00180          }
00181       }
00182    }
00183    else if (oldheap.size() > 0)
00184    {
00185       earliest = absolute_t(old_base_, oldheap.begin()->first);
00186    }
00187    else
00188    {
00189       return maxtime;
00190    }
00191    if (now < earliest)
00192    {
00193       const interval_t next = earliest - now;
00194       if (maxtime < next)
00195       {
00196          return maxtime;
00197       }
00198       else
00199       {
00200          return next;
00201       }
00202    }
00203    else
00204    {
00205       return interval_t(0, 0);
00206    }
00207 }
00208 
00209 void TimerEventTracker::printState(::std::ostream &os) const
00210 {
00211    os << "TimerEventTracker - Base time: " << absolute_t(current_base_)
00212       << " (\n";
00213    const timerheap_t &curheap = impl_.map1_current_ ? impl_.map1_ : impl_.map2_;
00214    const timerheap_t::const_iterator end = curheap.end();
00215    for (timerheap_t::const_iterator i = curheap.begin(); i != end; ++i)
00216    {
00217       os << "   [" << i->first << ", " << i->second.GetPtr() << "]\n";
00218    }
00219    os << ")";
00220 }
00221 
00222 } // namespace unievent
00223 } // namespace strmod

Generated on Wed Jan 29 00:32:45 2003 for libNet by doxygen1.3-rc1