@@ -74,6 +74,7 @@ class Queue : public event::EventEntity {
7474 /* *
7575 * The iterator type to access elements in the container
7676 */
77+ using const_iterator = typename container_t ::const_iterator;
7778 using iterator = typename container_t ::iterator;
7879
7980 Queue (const std::shared_ptr<event::EventLoop> &loop,
@@ -220,12 +221,15 @@ class Queue : public event::EventEntity {
220221
221222private:
222223 /* *
223- * Erase an element from the queue at the given time.
224+ * Kill an element from the queue at the given time.
224225 *
225- * @param time The time to erase at.
226- * @param at The index of the element to erase.
226+ * The element is set to dead at the given time and is not accessible
227+ * for pops with t > time.
228+ *
229+ * @param time The time to kill at.
230+ * @param at The index of the element to kill.
227231 */
228- void erase (const time::time_t &time, index_t at);
232+ void kill (const time::time_t &time, index_t at);
229233
230234 /* *
231235 * Get the first alive element inserted at t <= time.
@@ -274,6 +278,7 @@ typename Queue<T>::index_t Queue<T>::first_alive(const time::time_t &time) const
274278 // start searching from the last front position
275279 hint = this ->front_start ;
276280 }
281+ // else search from the beginning
277282
278283 // Iterate until we find an alive element
279284 while (hint != this ->container .size ()
@@ -290,24 +295,38 @@ typename Queue<T>::index_t Queue<T>::first_alive(const time::time_t &time) const
290295
291296template <typename T>
292297const T &Queue<T>::front(const time::time_t &time) const {
293- auto at = this ->first_alive (time);
294- ENSURE (at != this ->container .size (), " Tried accessing front at " << time << " but queue is empty." );
298+ index_t at = this ->first_alive (time);
299+ ENSURE (at < this ->container .size (),
300+ " Tried accessing front at " << time << " but index " << at << " is invalid. "
301+ << " The queue may be empty."
302+ << " (last_change: " << this ->last_change
303+ << " , front_start: " << this ->front_start
304+ << " , container size: " << this ->container .size ()
305+ << " )" );
295306
296307 return this ->container .at (at).value ;
297308}
298309
299310
300311template <class T >
301312const T &Queue<T>::pop_front(const time::time_t &time) {
302- auto at = this ->first_alive (time);
303- ENSURE (at != this ->container .size (), " Tried accessing front at " << time << " but queue is empty." );
313+ index_t at = this ->first_alive (time);
314+ ENSURE (at < this ->container .size (),
315+ " Tried accessing front at " << time << " but index " << at << " is invalid. "
316+ << " The queue may be empty."
317+ << " (last_change: " << this ->last_change
318+ << " , front_start: " << this ->front_start
319+ << " , container size: " << this ->container .size ()
320+ << " )" );
321+
322+ // kill the element at time t
323+ this ->kill (time, at);
304324
305325 // cache the search start position for the next front() call
306- this ->front_start = at;
326+ // for pop time t, there should be no more elements alive before t
327+ // so we can advance the front to the next element
307328 this ->last_change = time;
308-
309- // erase the element
310- this ->erase (time, at);
329+ this ->front_start = at + 1 ;
311330
312331 this ->changes (time);
313332
@@ -373,8 +392,8 @@ void Queue<T>::erase(const CurveIterator<T, Queue<T>> &it) {
373392
374393
375394template <class T >
376- void Queue<T>::erase (const time::time_t &time,
377- index_t at) {
395+ void Queue<T>::kill (const time::time_t &time,
396+ index_t at) {
378397 this ->container [at].set_dead (time);
379398}
380399
@@ -383,7 +402,7 @@ template <typename T>
383402QueueFilterIterator<T, Queue<T>> Queue<T>::insert(const time::time_t &time,
384403 const T &e) {
385404 index_t at = this ->container .size ();
386- while (at != 0 ) {
405+ while (at > 0 ) {
387406 --at;
388407 if (this ->container .at (at).alive () <= time) {
389408 ++at;
@@ -400,19 +419,12 @@ QueueFilterIterator<T, Queue<T>> Queue<T>::insert(const time::time_t &time,
400419
401420 // cache the insertion time
402421 this ->last_change = time;
403- if (this ->front_start == this ->container .size ()) [[unlikely]] {
404- // only true if the container is empty
405- // or all elements are dead
422+
423+ // if the new element is inserted before the current front element
424+ // cache it as the new front element
425+ if (at < this ->front_start ) {
406426 this ->front_start = at;
407427 }
408- else {
409- // if there are more alive elements, only cache if the
410- // insertion time is before the current front
411- if (time < this ->container .at (this ->front_start ).alive ()) {
412- // cache the search start position for the next front() call
413- this ->front_start = at;
414- }
415- }
416428
417429 auto ct = QueueFilterIterator<T, Queue<T>>(
418430 insertion_point,
0 commit comments