9#include "arg_wrappers.hpp"
12#include "int_arith.hpp"
13#include "introspect.hpp"
14#include "numeric_traits.hpp"
15#include "processor.hpp"
16#include "type_list.hpp"
17#include "variant_event.hpp"
31template <
typename EventList,
typename NumericTraits,
typename Downstream>
34 static_assert(type_list_like<EventList>);
35 static_assert(is_move_constructible_list_v<EventList>,
36 "recover_order requires every event in EventList to be "
37 "move-constructible (events are buffered in a vector)");
38 static_assert(is_move_assignable_list_v<EventList>,
39 "recover_order requires every event in EventList to be "
40 "move-assignable (the buffer is kept sorted by shifting)");
45 using abstime_type = NumericTraits::abstime_type;
46 abstime_type window_size;
51 std::vector<variant_or_single_event<EventList>> buf;
54 abstime_type last_emitted_time = std::numeric_limits<abstime_type>::min();
56 Downstream downstream;
59 explicit recover_order(arg::time_window<abstime_type> time_window,
60 Downstream downstream)
61 : window_size(time_window.value), downstream(std::move(downstream)) {
63 throw std::invalid_argument(
64 "recover_order time_window must not be negative");
67 [[nodiscard]]
auto introspect_node() const -> processor_info {
68 return processor_info(
this,
"recover_order");
71 [[nodiscard]]
auto introspect_graph() const -> processor_graph {
72 return downstream.introspect_graph().push_entry_point(
this);
75 template <
typename Event>
76 requires convertible_to_type_list_member<std::remove_cvref_t<Event>,
78 void handle(Event &&event) {
79 static_assert(std::is_same_v<
decltype(
event.abstime), abstime_type>);
80 if constexpr (std::is_lvalue_reference_v<Event>) {
82 std::copy_constructible<std::remove_cvref_t<Event>>,
83 "recover_order copies const-lvalue inputs into its buffer; "
84 "pass the event as an rvalue or make it copy-constructible");
86 if (event.abstime < last_emitted_time) {
87 throw data_validation_error(
88 "recover_order encountered event outside of time window");
101 auto const cutoff = pairing_cutoff(event.abstime, window_size);
103 std::find_if_not(buf.begin(), buf.end(), [&](
auto const &v) {
104 return visit_variant_or_single_event(
105 [&](auto const &e) { return e.abstime < cutoff; }, v);
108 std::for_each(buf.begin(), keep_it, [&](
auto &v) {
109 visit_variant_or_single_event(
110 [&]<typename E>(E &&e) {
111 last_emitted_time = e.abstime;
112 downstream.handle(std::forward<E>(e));
116 buf.erase(buf.begin(), keep_it);
119 std::find_if(buf.rbegin(), buf.rend(), [&](
auto const &v) {
120 return visit_variant_or_single_event(
121 [&](auto const &e) { return e.abstime < event.abstime; },
124 if (ins_it == buf.rend())
125 buf.insert(buf.begin(), std::forward<Event>(event));
127 buf.insert(ins_it.base(), std::forward<Event>(event));
133 std::for_each(buf.begin(), buf.end(), [&](
auto &v) {
134 visit_variant_or_single_event(
135 [&]<typename E>(E &&e) {
136 downstream.handle(std::forward<E>(e));
175template <
typename EventList,
typename NumericTraits = default_numeric_traits,
179 Downstream downstream) {
181 "recover_order requires non-empty event list");
182 return internal::recover_order<EventList, NumericTraits, Downstream>(
183 time_window, std::move(downstream));
constexpr bool is_processor_of_list_v
Trait variable to check whether a processor handles a list of event types and flush.
Definition processor.hpp:223
auto recover_order(arg::time_window< typename NumericTraits::abstime_type > time_window, Downstream downstream)
Create a processor that sorts events by abstime, provided that they are out of order only within a bo...
Definition recover_order.hpp:177
constexpr std::size_t type_list_size_v
Helper variable template for tcspc::type_list_size.
Definition type_list.hpp:133
libtcspc namespace.
Definition acquire.hpp:30
Function argument wrapper for time window parameter.
Definition arg_wrappers.hpp:417