AsyncEventRef.h
1// -*- C++ -*-
2
3// Copyright (c) 2005-2010, Isode Limited, London, England.
4// All rights reserved.
5//
6// Acquisition and use of this software and related materials for any
7// purpose requires a written licence agreement from Isode Limited,
8// or a written licence from an organisation licenced by Isode Limited
9// to grant such a licence.
10
11//
12//
13// AsyncEventRef.h
14//
15// Interface to the event queue classes
16//
17// @VERSION@
18
19#include "../include/timeutil.h"
20
21#include "Event_p.h"
22
23namespace Event {
24
26 class AsyncEventPlainQueue : AsyncEventRef {
27 private:
28 static AsyncEventPlainQueue *_freelist;
29
30 // A simple, doubly linked list
33
34 AsyncEventPlainQueue (AsyncEvent *event) : AsyncEventRef (event) {}
35
36 public:
38 _next = _prev = this;
39 }
40
42 void Insert (AsyncEvent *event) {
43 AsyncEventPlainQueue *newq = _freelist;
44 if ( newq ) {
45 _freelist = newq->_next;
46 newq->Set (event);
47 } else {
48 newq = new AsyncEventPlainQueue (event);
49 }
50
51 _prev->_next = newq;
52 newq->_prev = _prev;
53 newq->_next = this;
54 _prev = newq;
55 }
56
58 virtual void extract () {
59 _prev->_next = _next;
60 _next->_prev = _prev;
61 _next = _freelist;
62
63 _freelist = this;
64 }
65
67 AsyncEvent * First () {
68 if ( _next == this )
69 return 0;
70
71 return _next->Extract();
72 }
73
75 AsyncEvent * Last () {
76 if ( _prev == this )
77 return 0;
78
79 return _prev->Extract();
80 }
81
83 bool HasEvents () const {
84 return _next != this;
85 }
86 };
87
89 //
90 // This implementation is a skip list, as this should be
91 // efficient. The only operations required are insertion, removal
92 // and removal of the initial element.
93 //
94 // The probability used for determining level is 0.25, i.e. the
95 // effective 'tree' has an expected fan-out of 4. There is a trade-off
96 // here between getting to about the right point quickly and work involved
97 // maintaining levels.
98 //
99 // The maximum level used is an implementation parameter. It is set to 8,
100 // which means the tree will 'max out' at about 4^8 = 65536 nodes. Above
101 // this the efficiency of the list will decrease.
102 //
103 // The Random number generator utilizes the same algorithm as that in Tcl
104 // It generates numbers in the range [1, IM-1], where IM = 2^31 -1.
105 // The arithmetic is done in a way to avoid integer overflow.
106
107
108 template <class C, class F> class AsyncEventPrioQueue : AsyncEventRef {
109 private:
110 static const int _maxlevel = 8;
111 static const int _shift = 2;
112 static const int _mask = (1<<_shift) - 1;
113 static const int RAND_IA = 16807;
114 static const int RAND_IQ = 127773;
115 static const int RAND_IR = 2836;
116
117 static AsyncEventPrioQueue *_freelist;
118
119 C _prio;
120 int _rand;
121 AsyncEventPrioQueue *_next[_maxlevel];
122 AsyncEventPrioQueue *_prev[_maxlevel];
123 int _level;
124
125 inline AsyncEventPrioQueue (AsyncEvent *event,
126 int level,
127 C prio)
128 : AsyncEventRef (event) {
129 _prio = prio;
130 _level = level;
131 }
132
133 public:
134 inline AsyncEventPrioQueue () {
135 _level = 1;
136 _next[0] = _prev[0] = this;
137 memset (&_prio, 0, sizeof _prio);
138 _rand = 12345678;
139 }
140
141 virtual ~AsyncEventPrioQueue() {}
142
143 inline void Insert (AsyncEvent *event, C prio) {
144 // Generate next random number
145 long int tmp = _rand/RAND_IQ;
146 _rand = tmp = RAND_IA*(_rand - tmp*RAND_IQ) - RAND_IR*tmp;
147
148 // Fold the upper bits into the lower bits
149 tmp ^= tmp >>_maxlevel*_shift;
150
151 int level = 1;
152
153 while ( level < _maxlevel && level <= _level && (tmp & _mask) == _mask ) {
154 level++;
155 tmp >>= _shift;
156 }
157
158 if ( level > _level ) {
159 // Need to fill in the head to head pointers
160 // As level cannot be more than one more than _level,
161 // there is no more than one pair to fill in
162 _next[_level] = _prev[_level] = this;
163 _level++;
164 }
165
166 AsyncEventPrioQueue *newq = _freelist;
167 if ( newq ) {
168 _freelist = newq->_next[0];
169 newq->Set (event);
170 newq->_prio = prio;
171 newq->_level = level;
172
173 } else {
174 newq = new AsyncEventPrioQueue (event, level, prio);
175 }
176
177 AsyncEventPrioQueue *succ = this;
178 AsyncEventPrioQueue *pred = this;
179
180 // Need to traverse all levels
181 level = _level;
182
183 F comp(prio);
184
185 while ( --level >= 0 ) {
186 // At the start of the loop we know that the new item
187 // Follows succ and preceeds pred.
188
189 AsyncEventPrioQueue *prev = succ->_prev[level];
190
191 // If the item preceeding the successor at this level
192 // is the same as the predecessor at the previous level
193 // there is nothing to do.
194 if ( prev != pred ) {
195
196 // Chain along at the current level, while the key of
197 // the predecessor follows the key of the new event
198
199 while ( comp.preceeds (prev->_prio) ) {
200 succ = prev;
201 prev = succ->_prev[level];
202 }
203
204 pred = prev;
205 }
206
207
208 // Insert the new item at this point in the level
209 // if the item has this level
210
211 if ( level < newq->_level ) {
212 newq->_next[level] = succ;
213 newq->_prev[level] = prev;
214 succ->_prev[level] = newq;
215 pred->_next[level] = newq;
216 }
217 }
218 }
219
220 inline virtual void extract () {
221 int level = _level;
222 while ( --level >= 0 ) {
223 _next[level]->_prev[level] = _prev[level];
224 _prev[level]->_next[level] = _next[level];
225 }
226 _next[0] = _freelist;
227 _freelist = this;
228 }
229
230 inline AsyncEvent *First (const C prio) {
231 F comp (prio);
232
233 // Only return if there is something to return and
234 // The priority of the event is not lower than the given priority
235 if ( _next[0] == this || comp.preceeds (_next[0]->_prio) )
236 return 0;
237
238 return _next[0]->Extract();
239 }
240
241 inline AsyncEvent *First () {
242 // Only return if there is something to return
243 // The priority of the event is not lower than the given priority
244 if ( _next[0] == this )
245 return 0;
246
247 return _next[0]->Extract();
248 }
249
250 inline bool HasEvents () {
251 return _next[0] != this;
252 }
253
254 inline const C *NextPrio () {
255 if ( _next[0] == this )
256 return 0;
257
258 return &_next[0]->_prio;
259 }
260 };
261
262 template <class C, class F> AsyncEventPrioQueue<C,F> *
264
267
270 private:
271 unsigned int value;
272 public:
273 Integercompare (unsigned int v) : value(v) {}
274
275 bool preceeds (unsigned int v1) { return value < v1; }
276 };
277
280
281}
A simple FIFO queue for events.
AsyncEvent * First()
Remove first element of queue.
virtual void extract()
Subordinate extract mechanism.
bool HasEvents() const
Return true if there are queued events.
void Insert(AsyncEvent *event)
Insert in queue.
AsyncEvent * Last()
Remove last element of queue.
Priority queue template.
Integer comparator.

All rights reserved © 2002 - 2024 Isode Ltd.