00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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 }
00223 }