VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gtimerlist.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2017 Graeme Walker
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 // ===
17 //
18 // gtimerlist.cpp
19 //
20 
21 #include "gdef.h"
22 #include "gtimerlist.h"
23 #include "gtimer.h"
24 #include "geventloop.h"
25 #include "glog.h"
26 #include "gassert.h"
27 #include <algorithm>
28 #include <sstream>
29 
30 GNet::TimerList * GNet::TimerList::m_this = nullptr ;
31 
33  m_soonest(nullptr) ,
34  m_run_on_destruction(false) // moot
35 {
36  if( m_this == nullptr )
37  m_this = this ;
38 }
39 
41 {
42  if( m_run_on_destruction )
43  {
44  try
45  {
46  doTimeouts() ;
47  }
48  catch(...)
49  {
50  }
51  }
52 
53  if( m_this == this )
54  m_this = nullptr ;
55 }
56 
58 {
59  G_ASSERT( !t.active() ) ; // (called by ctor)
60  m_list.push_back( &t ) ;
61 }
62 
64 {
65  const List::iterator end = m_list.end() ;
66  List::iterator p = std::find( m_list.begin() , end , &timer ) ;
67  if( p != end )
68  *p = nullptr ;
69 
70  if( m_soonest == &timer )
71  {
72  m_soonest = findSoonest() ;
73  setTimeout() ;
74  }
75 }
76 
78 {
79  if( !timer.active() && m_soonest != &timer )
80  {
81  ; // no-op -- cancelled a non-soonest timer
82  }
83  else if( timer.active() && m_soonest != nullptr && timer.t() > m_soonest->t() )
84  {
85  ; // no-op -- started a non-soonest timer
86  }
87  else
88  {
89  G::EpochTime old_soonest = soonestTime() ;
90  m_soonest = (timer.active() && timer.immediate()) ? &timer : findSoonest() ;
91  if( soonestTime() != old_soonest )
92  setTimeout() ;
93  }
94 }
95 
96 G::EpochTime GNet::TimerList::soonestTime() const
97 {
98  return m_soonest == nullptr ? G::EpochTime(0) : m_soonest->t() ;
99 }
100 
101 GNet::TimerBase * GNet::TimerList::findSoonest()
102 {
103  // (we could keep the list sorted to make this O(1), but keep it simple for now)
104  TimerBase * result = nullptr ;
105  const List::const_iterator end = m_list.end() ;
106  for( List::const_iterator p = m_list.begin() ; p != end ; ++p )
107  {
108  if( *p != nullptr && (*p)->active() && ( result == nullptr || (*p)->t() < result->t() ) )
109  result = *p ;
110  }
111  return result ;
112 }
113 
114 G::EpochTime GNet::TimerList::interval( bool & infinite ) const
115 {
116  if( m_soonest == nullptr )
117  {
118  infinite = true ;
119  return G::EpochTime(0) ;
120  }
121  else if( m_soonest->immediate() )
122  {
123  infinite = false ;
124  return G::EpochTime(0) ;
125  }
126  else
127  {
128  infinite = false ;
130  G::EpochTime then = m_soonest->t() ;
131  return now >= then ? G::EpochTime(0) : (then-now) ;
132  }
133 }
134 
136 {
137  return m_this ;
138 }
139 
141 {
142  if( m_this == nullptr )
143  throw NoInstance() ;
144 
145  return * m_this ;
146 }
147 
149 {
150  G::EpochTime now( 0 ) ; // lazy initialisation to G::DateTime::now() in G::Timer::expired()
151  for( List::iterator p = m_list.begin() ; p != m_list.end() ; ++p )
152  {
153  if( *p != nullptr && (*p)->active() && (*p)->expired(now) )
154  (*p)->doTimeout() ;
155  }
156 
157  collectGarbage() ;
158 
159  m_soonest = findSoonest() ;
160  setTimeout() ;
161 }
162 
163 void GNet::TimerList::setTimeout()
164 {
165  if( EventLoop::exists() )
166  EventLoop::instance().setTimeout( soonestTime() ) ;
167 }
168 
169 void GNet::TimerList::collectGarbage()
170 {
171  for( List::iterator p = m_list.begin() ; p != m_list.end() ; )
172  {
173  if( *p == nullptr )
174  p = m_list.erase( p ) ;
175  else
176  ++p ;
177  }
178 }
179 
180 std::string GNet::TimerList::report() const
181 {
182  std::ostringstream ss ;
183  ss << m_list.size() ;
184  return ss.str() ;
185 }
186 
187 /// \file gtimerlist.cpp
A subsecond-resolution timestamp based on a time_t.
Definition: gdatetime.h:39
virtual void setTimeout(G::EpochTime t)=0
Used by GNet::TimerList.
bool active() const
Returns true if the timer is started and not cancelled.
Definition: gtimer.h:85
TimerList()
Default constructor.
Definition: gtimerlist.cpp:32
Overload discriminator class for TimerList.
Definition: gtimerlist.h:60
A singleton which maintains a list of all Timer objects, and interfaces to the event loop on their be...
Definition: gtimerlist.h:56
static EpochTime now()
Returns the current epoch time.
static TimerList & instance()
Singleton access. Throws an exception if none.
Definition: gtimerlist.cpp:140
G::EpochTime interval(bool &infinite) const
Returns the interval to the first timer expiry.
Definition: gtimerlist.cpp:114
void add(TimerBase &)
Adds a timer.
Definition: gtimerlist.cpp:57
void doTimeouts()
Triggers the timeout callbacks of any expired timers.
Definition: gtimerlist.cpp:148
~TimerList()
Destructor. Any expired timers have their timeouts called.
Definition: gtimerlist.cpp:40
void update(TimerBase &)
Called when a timer changes its value.
Definition: gtimerlist.cpp:77
An interface used by GNet::TimerList to keep track of pending timeouts and to deliver timeout events...
Definition: gtimer.h:41
bool immediate() const
Returns true if the timer is active() and zero-length.
Definition: gtimer.cpp:45
static bool exists()
Returns true if an instance exists.
Definition: geventloop.cpp:51
void remove(TimerBase &)
Removes a timer from the list.
Definition: gtimerlist.cpp:63
std::string report() const
Returns a line of text reporting the status of the timer list.
Definition: gtimerlist.cpp:180
static EventLoop & instance()
Returns a reference to an instance of the class, if any.
Definition: geventloop.cpp:43