libtcspc C++ API
Streaming TCSPC and time tag data processing
Loading...
Searching...
No Matches
timing_misc.hpp
1/*
2 * This file is part of libtcspc
3 * Copyright 2019-2026 Board of Regents of the University of Wisconsin System
4 * SPDX-License-Identifier: MIT
5 */
6
7#pragma once
8
9#include "arg_wrappers.hpp"
10#include "common.hpp"
11#include "data_types.hpp"
12#include "errors.hpp"
13#include "introspect.hpp"
14#include "processor.hpp"
15
16#include <cmath>
17#include <cstddef>
18#include <ostream>
19#include <stdexcept>
20#include <type_traits>
21#include <utility>
22
23namespace tcspc {
24
33template <typename DataTypes = default_data_types>
38 typename DataTypes::abstime_type abstime;
39
46 double delay;
47
51 double interval;
52
55 periodic_sequence_model_event const &rhs) noexcept
56 -> bool = default;
57
59 friend auto operator<<(std::ostream &stream,
61 -> std::ostream & {
62 return stream << "offset_and_interval(" << event.abstime << " + "
63 << event.delay << ", " << event.interval << ')';
64 }
65};
66
75template <typename DataTypes = default_data_types>
80 typename DataTypes::abstime_type abstime;
81
85 double delay;
86
88 friend auto operator==(real_one_shot_timing_event const &lhs,
89 real_one_shot_timing_event const &rhs) noexcept
90 -> bool = default;
91
93 friend auto operator<<(std::ostream &stream,
94 real_one_shot_timing_event const &event)
95 -> std::ostream & {
96 return stream << "real_one_shot_timing(" << event.abstime << " + "
97 << event.delay << ')';
98 }
99};
100
109template <typename DataTypes = default_data_types>
114 typename DataTypes::abstime_type abstime;
115
119 double delay;
120
124 double interval;
125
129 std::size_t count;
130
132 friend auto operator==(real_linear_timing_event const &lhs,
133 real_linear_timing_event const &rhs) noexcept
134 -> bool = default;
135
137 friend auto operator<<(std::ostream &stream,
138 real_linear_timing_event const &event)
139 -> std::ostream & {
140 return stream << "real_linear_timing(" << event.abstime << " + "
141 << event.delay << ", " << event.interval << ", "
142 << event.count << ')';
143 }
144};
145
146namespace internal {
147
148template <typename DataTypes, typename Downstream>
150 static_assert(
151 processor<Downstream, periodic_sequence_model_event<DataTypes>>);
152
153 using abstime_type = typename DataTypes::abstime_type;
154
155 abstime_type max_shift;
156
157 Downstream downstream;
158
159 public:
160 explicit retime_periodic_sequences(
161 arg::max_time_shift<typename DataTypes::abstime_type> max_time_shift,
162 Downstream downstream)
163 : max_shift(max_time_shift.value), downstream(std::move(downstream)) {
164 if (max_shift < 0)
165 throw std::invalid_argument(
166 "retime_periodic_sequences max_time_shift must not be negative");
167 }
168
169 [[nodiscard]] auto introspect_node() const -> processor_info {
170 return processor_info(this, "retime_periodic_sequences");
171 }
172
173 [[nodiscard]] auto introspect_graph() const -> processor_graph {
174 return downstream.introspect_graph().push_entry_point(this);
175 }
176
177 template <typename DT>
178 void handle(periodic_sequence_model_event<DT> const &event) {
179 static_assert(std::is_same_v<typename DT::abstime_type, abstime_type>);
180
181 auto delta = std::floor(event.delay) - 1.0;
182 if (std::abs(delta) > static_cast<double>(max_shift))
183 throw data_validation_error(
184 "retime periodic sequence: abstime would shift more than max time shift");
185
186 abstime_type abstime{};
187 if constexpr (std::is_unsigned_v<abstime_type>) {
188 if (delta < 0.0) {
189 auto ndelta = static_cast<abstime_type>(-delta);
190 if (ndelta > event.abstime)
191 throw data_validation_error(
192 "retime periodic sequence: abstime would be negative but abstime_type is unsigned");
193 abstime = event.abstime - ndelta;
194 } else {
195 abstime = event.abstime + static_cast<abstime_type>(delta);
196 }
197 } else {
198 abstime = event.abstime + static_cast<abstime_type>(delta);
199 }
200
201 downstream.handle(periodic_sequence_model_event<DataTypes>{
202 abstime, event.delay - delta, event.interval});
203 }
204
205 void flush() { downstream.flush(); }
206};
207
208} // namespace internal
209
263template <typename DataTypes = default_data_types, typename Downstream>
266 Downstream downstream) {
267 return internal::retime_periodic_sequences<DataTypes, Downstream>(
268 max_time_shift, std::move(downstream));
269}
270
271namespace internal {
272
273template <typename DataTypes, typename Downstream>
275 static_assert(
276 processor<Downstream, real_one_shot_timing_event<DataTypes>>);
277
278 double m;
279 Downstream downstream;
280
281 public:
282 explicit extrapolate_periodic_sequences(
283 arg::tick_index<std::size_t> tick_index, Downstream downstream)
284 : m(static_cast<double>(tick_index.value)),
285 downstream(std::move(downstream)) {}
286
287 [[nodiscard]] auto introspect_node() const -> processor_info {
288 return processor_info(this, "extrapolate_periodic_sequences");
289 }
290
291 [[nodiscard]] auto introspect_graph() const -> processor_graph {
292 return downstream.introspect_graph().push_entry_point(this);
293 }
294
295 template <typename DT>
296 void handle(periodic_sequence_model_event<DT> const &event) {
297 static_assert(std::is_same_v<typename DT::abstime_type,
298 typename DataTypes::abstime_type>);
299 downstream.handle(real_one_shot_timing_event<DataTypes>{
300 event.abstime, event.delay + event.interval * m});
301 }
302
303 template <typename DT>
304 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
305 void handle(periodic_sequence_model_event<DT> &&event) {
306 handle(static_cast<periodic_sequence_model_event<DT> const &>(event));
307 }
308
309 template <typename OtherEvent>
310 requires handler_for<Downstream, std::remove_cvref_t<OtherEvent>>
311 void handle(OtherEvent &&event) {
312 downstream.handle(std::forward<OtherEvent>(event));
313 }
314
315 void flush() { downstream.flush(); }
316};
317
318} // namespace internal
319
357template <typename DataTypes = default_data_types, typename Downstream>
359 Downstream downstream) {
360 return internal::extrapolate_periodic_sequences<DataTypes, Downstream>(
361 tick_index, std::move(downstream));
362}
363
364namespace internal {
365
366template <typename DataTypes, typename Downstream>
368 static_assert(processor<Downstream, real_linear_timing_event<DataTypes>>);
369
370 std::size_t ct;
371 Downstream downstream;
372
373 public:
374 explicit add_count_to_periodic_sequences(arg::count<std::size_t> count,
375 Downstream downstream)
376 : ct(count.value), downstream(std::move(downstream)) {}
377
378 [[nodiscard]] auto introspect_node() const -> processor_info {
379 return processor_info(this, "add_count_to_periodic_sequences");
380 }
381
382 [[nodiscard]] auto introspect_graph() const -> processor_graph {
383 return downstream.introspect_graph().push_entry_point(this);
384 }
385
386 template <typename DT>
387 void handle(periodic_sequence_model_event<DT> const &event) {
388 static_assert(std::is_same_v<typename DT::abstime_type,
389 typename DataTypes::abstime_type>);
390 downstream.handle(real_linear_timing_event<DataTypes>{
391 event.abstime, event.delay, event.interval, ct});
392 }
393
394 template <typename DT>
395 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
396 void handle(periodic_sequence_model_event<DT> &&event) {
397 handle(static_cast<periodic_sequence_model_event<DT> const &>(event));
398 }
399
400 template <typename OtherEvent>
401 requires handler_for<Downstream, std::remove_cvref_t<OtherEvent>>
402 void handle(OtherEvent &&event) {
403 downstream.handle(std::forward<OtherEvent>(event));
404 }
405
406 void flush() { downstream.flush(); }
407};
408
409} // namespace internal
410
443template <typename DataTypes = default_data_types, typename Downstream>
445 Downstream downstream) {
446 return internal::add_count_to_periodic_sequences<DataTypes, Downstream>(
447 count, std::move(downstream));
448}
449
450namespace internal {
451
452template <typename TickEvent, typename StartEvent, typename StopEvent,
453 typename Downstream>
455 static_assert(processor<Downstream, StartEvent, StopEvent>);
456
457 static_assert(
458 std::is_same_v<decltype(std::declval<TickEvent>().abstime),
459 decltype(std::declval<StartEvent>().abstime)>);
460 static_assert(std::is_same_v<decltype(std::declval<TickEvent>().abstime),
461 decltype(std::declval<StopEvent>().abstime)>);
462
463 std::size_t input_len;
464 std::size_t seen = 0;
465 Downstream downstream;
466
467 public:
468 explicit convert_sequences_to_start_stop(arg::count<std::size_t> count,
469 Downstream downstream)
470 : input_len(count.value + 1), downstream(std::move(downstream)) {}
471
472 [[nodiscard]] auto introspect_node() const -> processor_info {
473 return processor_info(this, "convert_sequences_to_start_stop");
474 }
475
476 [[nodiscard]] auto introspect_graph() const -> processor_graph {
477 return downstream.introspect_graph().push_entry_point(this);
478 }
479
480 void handle(TickEvent const &event) {
481 if (seen > 0) {
482 StopEvent e{};
483 e.abstime = event.abstime;
484 downstream.handle(std::move(e));
485 }
486 ++seen;
487 if (seen < input_len) {
488 StartEvent e{};
489 e.abstime = event.abstime;
490 downstream.handle(std::move(e));
491 } else {
492 seen = 0;
493 }
494 }
495
496 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
497 void handle(TickEvent &&event) {
498 handle(static_cast<TickEvent const &>(event));
499 }
500
501 template <typename OtherEvent>
502 requires handler_for<Downstream, std::remove_cvref_t<OtherEvent>>
503 void handle(OtherEvent &&event) {
504 downstream.handle(std::forward<OtherEvent>(event));
505 }
506
507 void flush() { downstream.flush(); }
508};
509
510} // namespace internal
511
556template <typename TickEvent, typename StartEvent, typename StopEvent,
557 typename Downstream>
559 Downstream downstream) {
560 return internal::convert_sequences_to_start_stop<TickEvent, StartEvent,
561 StopEvent, Downstream>(
562 count, std::move(downstream));
563}
564
565} // namespace tcspc
auto count(access_tracker< count_access > &&tracker, Downstream downstream)
Create a processor that counts events of a given type.
Definition count.hpp:313
auto retime_periodic_sequences(arg::max_time_shift< typename DataTypes::abstime_type > max_time_shift, Downstream downstream)
Create a processor that adjusts the abstime of tcspc::periodic_sequence_model_event to be earlier tha...
Definition timing_misc.hpp:264
auto convert_sequences_to_start_stop(arg::count< std::size_t > count, Downstream downstream)
Create a processor that converts sequences of ticks to sequences of start-stop event pairs with no ga...
Definition timing_misc.hpp:558
auto extrapolate_periodic_sequences(arg::tick_index< std::size_t > tick_index, Downstream downstream)
Create a processor that emits an extrapolated one-shot timing event based on tcspc::periodic_sequence...
Definition timing_misc.hpp:358
auto add_count_to_periodic_sequences(arg::count< std::size_t > count, Downstream downstream)
Create a processor that emits a linear timing event based on tcspc::periodic_sequence_model_event by ...
Definition timing_misc.hpp:444
libtcspc namespace.
Definition acquire.hpp:29
Function argument wrapper for count parameter.
Definition arg_wrappers.hpp:97
Function argument wrapper for maximum time shift parameter.
Definition arg_wrappers.hpp:307
Function argument wrapper for tick index parameter.
Definition arg_wrappers.hpp:407
Event representing a summarized model of a periodic sequence of events.
Definition timing_misc.hpp:34
double delay
The estimated time of the first event, relative to abstime.
Definition timing_misc.hpp:46
double interval
Interval, in abstime units per index, of the modeled sequence.
Definition timing_misc.hpp:51
DataTypes::abstime_type abstime
Absolute time of this event, used as a reference point.
Definition timing_misc.hpp:38
friend auto operator<<(std::ostream &stream, periodic_sequence_model_event const &event) -> std::ostream &
Stream insertion operator.
Definition timing_misc.hpp:59
friend auto operator==(periodic_sequence_model_event const &lhs, periodic_sequence_model_event const &rhs) noexcept -> bool=default
Equality comparison operator.
Event representing a prescription for linear timing generation with real (fractional) delay and inter...
Definition timing_misc.hpp:110
DataTypes::abstime_type abstime
Absolute time of this event, used as a reference point.
Definition timing_misc.hpp:114
double delay
The time delay relative to abstime.
Definition timing_misc.hpp:119
friend auto operator==(real_linear_timing_event const &lhs, real_linear_timing_event const &rhs) noexcept -> bool=default
Equality comparison operator.
friend auto operator<<(std::ostream &stream, real_linear_timing_event const &event) -> std::ostream &
Stream insertion operator.
Definition timing_misc.hpp:137
double interval
Interval between the events in the represented sequence.
Definition timing_misc.hpp:124
std::size_t count
Number of events in the represented sequence.
Definition timing_misc.hpp:129
Event representing a prescription for one-shot timing generation with real (fractional) delay.
Definition timing_misc.hpp:76
friend auto operator<<(std::ostream &stream, real_one_shot_timing_event const &event) -> std::ostream &
Stream insertion operator.
Definition timing_misc.hpp:93
friend auto operator==(real_one_shot_timing_event const &lhs, real_one_shot_timing_event const &rhs) noexcept -> bool=default
Equality comparison operator.
DataTypes::abstime_type abstime
Absolute time of this event, used as a reference point.
Definition timing_misc.hpp:80
double delay
The time delay relative to abstime.
Definition timing_misc.hpp:85