9#include "arg_wrappers.hpp"
11#include "introspect.hpp"
12#include "numeric_traits.hpp"
13#include "processor.hpp"
14#include "time_tagged_events.hpp"
15#include "vector_queue.hpp"
31template <std::size_t NStopChannels,
typename NumericTraits,
35 processor<Downstream, std::array<detection_event<NumericTraits>, 2>>);
37 NumericTraits::channel_type start_chan;
38 std::array<typename NumericTraits::channel_type, NStopChannels> stop_chans;
39 NumericTraits::abstime_type window_size;
42 internal::vector_queue<typename NumericTraits::abstime_type> starts;
44 Downstream downstream;
46 void expel_old_starts(NumericTraits::abstime_type earliest_stop) {
47 auto const cutoff = pairing_cutoff(earliest_stop, window_size);
48 while (not starts.empty() && starts.front() < cutoff)
54 arg::start_channel<typename NumericTraits::channel_type> start_channel,
55 std::array<typename NumericTraits::channel_type, NStopChannels>
57 arg::time_window<typename NumericTraits::abstime_type> time_window,
58 Downstream downstream)
59 : start_chan(start_channel.value), stop_chans(stop_channels),
60 window_size(time_window.value), downstream(std::move(downstream)) {
62 throw std::invalid_argument(
63 "pair_all time_window must not be negative");
66 [[nodiscard]]
auto introspect_node() const -> processor_info {
67 return processor_info(
this,
"pair_all");
70 [[nodiscard]]
auto introspect_graph() const -> processor_graph {
71 return downstream.introspect_graph().push_entry_point(
this);
74 template <
typename NT>
void handle(detection_event<NT>
const &event) {
75 static_assert(std::is_same_v<
typename NT::abstime_type,
76 typename NumericTraits::abstime_type>);
77 static_assert(std::is_same_v<
typename NT::channel_type,
78 typename NumericTraits::channel_type>);
80 expel_old_starts(event.abstime);
81 auto chan_index = std::distance(
83 std::find(stop_chans.cbegin(), stop_chans.cend(), event.channel));
84 if (std::size_t(chan_index) < NStopChannels) {
85 starts.for_each([&](
auto start_time) {
87 std::array<detection_event<NumericTraits>, 2>{
88 {{start_time, start_chan},
event}});
91 if (event.channel == start_chan)
92 starts.push(event.abstime);
93 downstream.handle(event);
97 template <
typename NT>
void handle(detection_event<NT> &&event) {
98 handle(
static_cast<detection_event<NT>
const &
>(event));
101 template <
typename OtherEvent>
102 requires handler_for<Downstream, std::remove_cvref_t<OtherEvent>>
103 void handle(OtherEvent &&event) {
104 downstream.handle(std::forward<OtherEvent>(event));
107 void flush() { downstream.flush(); }
110template <std::size_t NStopChannels,
typename NumericTraits,
114 processor<Downstream, std::array<detection_event<NumericTraits>, 2>>);
116 NumericTraits::channel_type start_chan;
117 std::array<typename NumericTraits::channel_type, NStopChannels> stop_chans;
118 NumericTraits::abstime_type window_size;
122 struct start_and_flags {
123 NumericTraits::abstime_type time;
124 std::bitset<NStopChannels> stopped;
126 internal::vector_queue<start_and_flags> starts;
128 Downstream downstream;
130 void expel_old_starts(NumericTraits::abstime_type earliest_stop) {
131 auto const cutoff = pairing_cutoff(earliest_stop, window_size);
132 while (not starts.empty() &&
133 (starts.front().time < cutoff || starts.front().stopped.all()))
139 arg::start_channel<typename NumericTraits::channel_type> start_channel,
140 std::array<typename NumericTraits::channel_type, NStopChannels>
142 arg::time_window<typename NumericTraits::abstime_type> time_window,
143 Downstream downstream)
144 : start_chan(start_channel.value), stop_chans(stop_channels),
145 window_size(time_window.value), downstream(std::move(downstream)) {
147 throw std::invalid_argument(
148 "pair_one time_window must not be negative");
151 [[nodiscard]]
auto introspect_node() const -> processor_info {
152 return processor_info(
this,
"pair_one");
155 [[nodiscard]]
auto introspect_graph() const -> processor_graph {
156 return downstream.introspect_graph().push_entry_point(
this);
159 template <
typename NT>
void handle(detection_event<NT>
const &event) {
160 static_assert(std::is_same_v<
typename NT::abstime_type,
161 typename NumericTraits::abstime_type>);
162 static_assert(std::is_same_v<
typename NT::channel_type,
163 typename NumericTraits::channel_type>);
165 expel_old_starts(event.abstime);
166 auto const chan_index =
static_cast<std::size_t
>(std::distance(
168 std::find(stop_chans.cbegin(), stop_chans.cend(), event.channel)));
169 if (chan_index < NStopChannels) {
170 starts.for_each([&](start_and_flags &sf) {
171 if (not sf.stopped[chan_index]) {
173 std::array<detection_event<NumericTraits>, 2>{
174 {{sf.time, start_chan},
event}});
175 sf.stopped[chan_index] =
true;
179 if (event.channel == start_chan)
180 starts.push(start_and_flags{
event.abstime, {}});
181 downstream.handle(event);
185 template <
typename NT>
void handle(detection_event<NT> &&event) {
186 handle(
static_cast<detection_event<NT>
const &
>(event));
189 template <
typename OtherEvent>
190 requires handler_for<Downstream, std::remove_cvref_t<OtherEvent>>
191 void handle(OtherEvent &&event) {
192 downstream.handle(std::forward<OtherEvent>(event));
195 void flush() { downstream.flush(); }
198template <std::size_t NStopChannels,
typename NumericTraits,
200class pair_all_between {
202 processor<Downstream, std::array<detection_event<NumericTraits>, 2>>);
204 NumericTraits::channel_type start_chan;
205 std::array<typename NumericTraits::channel_type, NStopChannels> stop_chans;
206 NumericTraits::abstime_type window_size;
209 std::optional<typename NumericTraits::abstime_type> start;
211 Downstream downstream;
213 void expel_old_start(NumericTraits::abstime_type earliest_stop) {
214 auto const cutoff = pairing_cutoff(earliest_stop, window_size);
215 if (start.has_value() && *start < cutoff)
216 start = std::nullopt;
220 explicit pair_all_between(
221 arg::start_channel<typename NumericTraits::channel_type> start_channel,
222 std::array<typename NumericTraits::channel_type, NStopChannels>
224 arg::time_window<typename NumericTraits::abstime_type> time_window,
225 Downstream downstream)
226 : start_chan(start_channel.value), stop_chans(stop_channels),
227 window_size(time_window.value), downstream(std::move(downstream)) {
229 throw std::invalid_argument(
230 "pair_all_between time_window must not be negative");
233 [[nodiscard]]
auto introspect_node() const -> processor_info {
234 return processor_info(
this,
"pair_all_between");
237 [[nodiscard]]
auto introspect_graph() const -> processor_graph {
238 return downstream.introspect_graph().push_entry_point(
this);
241 template <
typename NT>
void handle(detection_event<NT>
const &event) {
242 static_assert(std::is_same_v<
typename NT::abstime_type,
243 typename NumericTraits::abstime_type>);
244 static_assert(std::is_same_v<
typename NT::channel_type,
245 typename NumericTraits::channel_type>);
247 expel_old_start(event.abstime);
248 if (start.has_value()) {
250 std::distance(stop_chans.cbegin(),
251 std::find(stop_chans.cbegin(), stop_chans.cend(),
253 if (std::size_t(chan_index) < NStopChannels) {
255 std::array<detection_event<NumericTraits>, 2>{
256 {{*start, start_chan},
event}});
259 if (event.channel == start_chan)
260 start =
event.abstime;
261 downstream.handle(event);
265 template <
typename NT>
void handle(detection_event<NT> &&event) {
266 handle(
static_cast<detection_event<NT>
const &
>(event));
269 template <
typename OtherEvent>
270 requires handler_for<Downstream, std::remove_cvref_t<OtherEvent>>
271 void handle(OtherEvent &&event) {
272 downstream.handle(std::forward<OtherEvent>(event));
275 void flush() { downstream.flush(); }
278template <std::size_t NStopChannels,
typename NumericTraits,
280class pair_one_between {
282 processor<Downstream, std::array<detection_event<NumericTraits>, 2>>);
284 NumericTraits::channel_type start_chan;
285 std::array<typename NumericTraits::channel_type, NStopChannels> stop_chans;
286 NumericTraits::abstime_type window_size;
290 struct start_and_flags {
291 NumericTraits::abstime_type time;
292 std::bitset<NStopChannels> stopped;
294 std::optional<start_and_flags> start;
296 Downstream downstream;
298 void expel_old_start(NumericTraits::abstime_type earliest_stop) {
299 auto const cutoff = pairing_cutoff(earliest_stop, window_size);
300 if (start.has_value() &&
301 (start->time < cutoff || start->stopped.all()))
302 start = std::nullopt;
306 explicit pair_one_between(
307 arg::start_channel<typename NumericTraits::channel_type> start_channel,
308 std::array<typename NumericTraits::channel_type, NStopChannels>
310 arg::time_window<typename NumericTraits::abstime_type> time_window,
311 Downstream downstream)
312 : start_chan(start_channel.value), stop_chans(stop_channels),
313 window_size(time_window.value), downstream(std::move(downstream)) {
315 throw std::invalid_argument(
316 "pair_one_between time_window must not be negative");
319 [[nodiscard]]
auto introspect_node() const -> processor_info {
320 return processor_info(
this,
"pair_one_between");
323 [[nodiscard]]
auto introspect_graph() const -> processor_graph {
324 return downstream.introspect_graph().push_entry_point(
this);
327 template <
typename NT>
void handle(detection_event<NT>
const &event) {
328 static_assert(std::is_same_v<
typename NT::abstime_type,
329 typename NumericTraits::abstime_type>);
330 static_assert(std::is_same_v<
typename NT::channel_type,
331 typename NumericTraits::channel_type>);
333 expel_old_start(event.abstime);
334 if (start.has_value()) {
335 auto const chan_index =
static_cast<std::size_t
>(
336 std::distance(stop_chans.cbegin(),
337 std::find(stop_chans.cbegin(), stop_chans.cend(),
339 if (chan_index < NStopChannels && not start->stopped[chan_index]) {
341 std::array<detection_event<NumericTraits>, 2>{
342 {{start->time, start_chan},
event}});
343 start->stopped[chan_index] =
true;
346 if (event.channel == start_chan)
347 start = start_and_flags{
event.abstime, {}};
348 downstream.handle(event);
352 template <
typename NT>
void handle(detection_event<NT> &&event) {
353 handle(
static_cast<detection_event<NT>
const &
>(event));
356 template <
typename OtherEvent>
357 requires handler_for<Downstream, std::remove_cvref_t<OtherEvent>>
358 void handle(OtherEvent &&event) {
359 downstream.handle(std::forward<OtherEvent>(event));
362 void flush() { downstream.flush(); }
406template <std::size_t NStopChannels,
410 std::array<typename NumericTraits::channel_type, NStopChannels>
413 Downstream downstream) {
414 return internal::pair_all<NStopChannels, NumericTraits, Downstream>(
415 start_channel, stop_channels, time_window, std::move(downstream));
459template <std::size_t NStopChannels,
460 typename NumericTraits = default_numeric_traits,
typename Downstream>
463 std::array<typename NumericTraits::channel_type, NStopChannels>
466 Downstream downstream) {
467 return internal::pair_one<NStopChannels, NumericTraits, Downstream>(
468 start_channel, stop_channels, time_window, std::move(downstream));
511template <std::size_t NStopChannels,
512 typename NumericTraits = default_numeric_traits,
typename Downstream>
515 std::array<typename NumericTraits::channel_type, NStopChannels>
518 Downstream downstream) {
519 return internal::pair_all_between<NStopChannels, NumericTraits,
521 start_channel, stop_channels, time_window, std::move(downstream));
565template <std::size_t NStopChannels,
566 typename NumericTraits = default_numeric_traits,
typename Downstream>
569 std::array<typename NumericTraits::channel_type, NStopChannels>
572 Downstream downstream) {
573 return internal::pair_one_between<NStopChannels, NumericTraits,
575 start_channel, stop_channels, time_window, std::move(downstream));
auto pair_all_between(arg::start_channel< typename NumericTraits::channel_type > start_channel, std::array< typename NumericTraits::channel_type, NStopChannels > stop_channels, arg::time_window< typename NumericTraits::abstime_type > time_window, Downstream downstream)
Create a processor that generates ordered pairs of detection events within a time window,...
Definition pair.hpp:513
auto pair_one_between(arg::start_channel< typename NumericTraits::channel_type > start_channel, std::array< typename NumericTraits::channel_type, NStopChannels > stop_channels, arg::time_window< typename NumericTraits::abstime_type > time_window, Downstream downstream)
Create a processor that generates ordered pairs of detection events within a time window,...
Definition pair.hpp:567
auto pair_one(arg::start_channel< typename NumericTraits::channel_type > start_channel, std::array< typename NumericTraits::channel_type, NStopChannels > stop_channels, arg::time_window< typename NumericTraits::abstime_type > time_window, Downstream downstream)
Create a processor that generates ordered pairs of detection events within a time window,...
Definition pair.hpp:461
auto pair_all(arg::start_channel< typename NumericTraits::channel_type > start_channel, std::array< typename NumericTraits::channel_type, NStopChannels > stop_channels, arg::time_window< typename NumericTraits::abstime_type > time_window, Downstream downstream)
Create a processor that generates all ordered pairs of detection events within a time window.
Definition pair.hpp:408
libtcspc namespace.
Definition acquire.hpp:30
Function argument wrapper for start channel parameter.
Definition arg_wrappers.hpp:367
Function argument wrapper for time window parameter.
Definition arg_wrappers.hpp:417
The default numeric traits.
Definition numeric_traits.hpp:27