git-subtree-dir: xo-reactor git-subtree-mainline:dd1a6b1afcgit-subtree-split:e3a53d10e6
154 lines
5.3 KiB
C++
154 lines
5.3 KiB
C++
/* @file LastReducer.hpp */
|
|
|
|
#pragma once
|
|
|
|
#include "Reducer.hpp"
|
|
#include <array>
|
|
|
|
namespace xo {
|
|
namespace reactor {
|
|
/* implementation record used in LastReducer.
|
|
* LastReducer (see below) remembers a single event,
|
|
* + will be updated on successive calls to
|
|
* LastReducer.include_event()
|
|
*
|
|
* need to remember the _first_ (& therefore earliest)
|
|
* event timestamp in such a wave, since that establishes when simulator
|
|
* should deliver the event -- even if event is subsequently
|
|
* overwritten.
|
|
*
|
|
* once event is delivered, timestamp can reset
|
|
*
|
|
* otherwise if upstream producer sends events with
|
|
* future timestamps, can get indefinite postponement
|
|
* with simulation clock failing to catch up to event time.
|
|
*
|
|
*/
|
|
|
|
template<typename Event>
|
|
class EventRecd {
|
|
public:
|
|
using utc_nanos = xo::time::utc_nanos;
|
|
|
|
public:
|
|
EventRecd() = default;
|
|
EventRecd(utc_nanos tm, Event ev) : trigger_tm_{tm}, ev_{ev} {}
|
|
EventRecd(utc_nanos tm, Event && ev) : trigger_tm_{tm}, ev_{std::move(ev)} {}
|
|
|
|
public:
|
|
/* if sim, deliver event when simulation clock reaches
|
|
* .trigger_tm; .trigger_tm can be earlier than .ev time
|
|
*/
|
|
utc_nanos trigger_tm_;
|
|
/* event to deliver */
|
|
Event ev_;
|
|
};
|
|
|
|
/* reducer that just remembers the last event
|
|
*
|
|
* Require:
|
|
* - Event is null-contructible
|
|
* - Event is copyable
|
|
*
|
|
* LastReducer provides reentrancy support. This support doesn't operate
|
|
* if Event copy is not deep, e.g. for Event = rp<Foo>n
|
|
*
|
|
* .include_event()
|
|
* /-------\ -----------------> /------\
|
|
* | empty | | full |
|
|
* \-------/ <----------------- \------/
|
|
* . .annex_one() .
|
|
* . .
|
|
* .is_empty()=true .is_empty()=false
|
|
*/
|
|
template<typename Event, typename EventTimeFn = StructEventTimeFn<Event>>
|
|
class LastReducer : public ReducerBase<Event, EventTimeFn> {
|
|
public:
|
|
using utc_nanos = xo::time::utc_nanos;
|
|
|
|
public:
|
|
LastReducer() = default;
|
|
LastReducer(EventTimeFn const & evtfn) : ReducerBase<Event, EventTimeFn>(evtfn) {}
|
|
|
|
bool is_empty() const { return empty_flag_; }
|
|
/* require: .is_empty() = false */
|
|
utc_nanos next_tm() const {
|
|
return this->last_ev_[this->last_ix_].trigger_tm_;
|
|
//return this->event_tm(this->last_ev_[this->last_ix_]);
|
|
}
|
|
/* #of events stored in this reducer (0 or 1) */
|
|
uint32_t n_event() const { return this->empty_flag_ ? 0 : 1; }
|
|
|
|
Event const & last_annexed_ev() const {
|
|
return this->last_ev_[1 - this->last_ix_].ev_;
|
|
}
|
|
|
|
EventRecd<Event> & include_event_aux(Event const & ev) {
|
|
EventRecd<Event> & evr
|
|
= this->last_ev_[this->last_ix_];
|
|
|
|
if (this->empty_flag_) {
|
|
/* evr.trigger_tm will be preserved across
|
|
* successive calls to .include_event();
|
|
* until .annex_one()
|
|
*/
|
|
evr.trigger_tm_ = this->event_tm(ev);
|
|
|
|
this->empty_flag_ = false;
|
|
}
|
|
|
|
return evr;
|
|
} /*include_event_aux*/
|
|
|
|
void include_event(Event const & ev) {
|
|
EventRecd<Event> & evr
|
|
= this->include_event_aux(ev);
|
|
|
|
evr.ev_ = ev;
|
|
} /*include_event*/
|
|
|
|
void include_event(Event && ev) {
|
|
EventRecd<Event> & evr
|
|
= this->include_event_aux(ev);
|
|
|
|
evr.ev_ = std::move(ev);
|
|
} /*include_event*/
|
|
|
|
Event & annex_one() {
|
|
std::uint32_t annexed_ix = this->last_ix_;
|
|
|
|
/* since .empty_flag is true,
|
|
* next call to .include_event_aux() will
|
|
* capture new timestamp
|
|
*/
|
|
this->empty_flag_ = true;
|
|
this->last_ix_ = (1 - this->last_ix_);
|
|
|
|
return this->last_ev_[annexed_ix].ev_;
|
|
} /*annex_one*/
|
|
|
|
// ----- Inherited from ReducerBase -----
|
|
|
|
//utc_nanos event_tm(Event const & ev) const { return this->event_tm_fn_(ev); }
|
|
|
|
private:
|
|
/* true when reducer contains 0 queued events,
|
|
* not counting any annexed event
|
|
*/
|
|
bool empty_flag_ = true;
|
|
|
|
/* .last_ev[.last_ix] updated by .include_event()
|
|
*/
|
|
std::uint32_t last_ix_ = 0;
|
|
/* remember two events
|
|
* (a) a single queued event (updated by .include_event())
|
|
* (b) a single removed event (reported by .annex_one())
|
|
*
|
|
* roles of .last_ev[0], .last_ev[1] reverse each time .annex_one() runs
|
|
*/
|
|
std::array<EventRecd<Event>, 2> last_ev_;
|
|
}; /*LastReducer*/
|
|
} /*namespace reactor*/
|
|
} /*namespace xo*/
|
|
|
|
/* end LastReducer.hpp */
|