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 "errors.hpp"
12#include "introspect.hpp"
13#include "numeric_traits.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 NumericTraits = default_numeric_traits>
38 NumericTraits::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 NumericTraits = default_numeric_traits>
80 NumericTraits::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 NumericTraits = default_numeric_traits>
114 NumericTraits::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 NumericTraits, typename Downstream>
150 static_assert(
151 processor<Downstream, periodic_sequence_model_event<NumericTraits>>);
152
153 using abstime_type = NumericTraits::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 NumericTraits::abstime_type>
162 max_time_shift,
163 Downstream downstream)
164 : max_shift(max_time_shift.value), downstream(std::move(downstream)) {
165 if (max_shift < 0)
166 throw std::invalid_argument(
167 "retime_periodic_sequences max_time_shift must not be negative");
168 }
169
170 [[nodiscard]] auto introspect_node() const -> processor_info {
171 return processor_info(this, "retime_periodic_sequences");
172 }
173
174 [[nodiscard]] auto introspect_graph() const -> processor_graph {
175 return downstream.introspect_graph().push_entry_point(this);
176 }
177
178 template <typename NT>
179 void handle(periodic_sequence_model_event<NT> const &event) {
180 static_assert(std::is_same_v<typename NT::abstime_type, abstime_type>);
181
182 auto delta = std::floor(event.delay) - 1.0;
183 if (std::abs(delta) > static_cast<double>(max_shift))
184 throw data_validation_error(
185 "retime periodic sequence: abstime would shift more than max time shift");
186
187 abstime_type abstime{};
188 if constexpr (std::is_unsigned_v<abstime_type>) {
189 if (delta < 0.0) {
190 auto ndelta = static_cast<abstime_type>(-delta);
191 if (ndelta > event.abstime)
192 throw data_validation_error(
193 "retime periodic sequence: abstime would be negative but abstime_type is unsigned");
194 abstime = event.abstime - ndelta;
195 } else {
196 abstime = event.abstime + static_cast<abstime_type>(delta);
197 }
198 } else {
199 abstime = event.abstime + static_cast<abstime_type>(delta);
200 }
201
202 downstream.handle(periodic_sequence_model_event<NumericTraits>{
203 abstime, event.delay - delta, event.interval});
204 }
205
206 void flush() { downstream.flush(); }
207};
208
209} // namespace internal
210
265template <typename NumericTraits = default_numeric_traits, typename Downstream>
268 Downstream downstream) {
269 return internal::retime_periodic_sequences<NumericTraits, Downstream>(
270 max_time_shift, std::move(downstream));
271}
272
273namespace internal {
274
275template <typename NumericTraits, typename Downstream>
277 static_assert(
278 processor<Downstream, real_one_shot_timing_event<NumericTraits>>);
279
280 double m;
281 Downstream downstream;
282
283 public:
284 explicit extrapolate_periodic_sequences(
285 arg::tick_index<std::size_t> tick_index, Downstream downstream)
286 : m(static_cast<double>(tick_index.value)),
287 downstream(std::move(downstream)) {}
288
289 [[nodiscard]] auto introspect_node() const -> processor_info {
290 return processor_info(this, "extrapolate_periodic_sequences");
291 }
292
293 [[nodiscard]] auto introspect_graph() const -> processor_graph {
294 return downstream.introspect_graph().push_entry_point(this);
295 }
296
297 template <typename NT>
298 void handle(periodic_sequence_model_event<NT> const &event) {
299 static_assert(std::is_same_v<typename NT::abstime_type,
300 typename NumericTraits::abstime_type>);
301 downstream.handle(real_one_shot_timing_event<NumericTraits>{
302 event.abstime, event.delay + event.interval * m});
303 }
304
305 template <typename NT>
306 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
307 void handle(periodic_sequence_model_event<NT> &&event) {
308 handle(static_cast<periodic_sequence_model_event<NT> const &>(event));
309 }
310
311 template <typename OtherEvent>
312 requires handler_for<Downstream, std::remove_cvref_t<OtherEvent>>
313 void handle(OtherEvent &&event) {
314 downstream.handle(std::forward<OtherEvent>(event));
315 }
316
317 void flush() { downstream.flush(); }
318};
319
320} // namespace internal
321
360template <typename NumericTraits = default_numeric_traits, typename Downstream>
362 Downstream downstream) {
363 return internal::extrapolate_periodic_sequences<NumericTraits, Downstream>(
364 tick_index, std::move(downstream));
365}
366
367namespace internal {
368
369template <typename NumericTraits, typename Downstream>
370 requires processor<Downstream, real_linear_timing_event<NumericTraits>>
372 std::size_t ct;
373 Downstream downstream;
374
375 public:
376 explicit add_count_to_periodic_sequences(arg::count<std::size_t> count,
377 Downstream downstream)
378 : ct(count.value), downstream(std::move(downstream)) {}
379
380 [[nodiscard]] auto introspect_node() const -> processor_info {
381 return processor_info(this, "add_count_to_periodic_sequences");
382 }
383
384 [[nodiscard]] auto introspect_graph() const -> processor_graph {
385 return downstream.introspect_graph().push_entry_point(this);
386 }
387
388 template <typename NT>
389 void handle(periodic_sequence_model_event<NT> const &event) {
390 static_assert(std::is_same_v<typename NT::abstime_type,
391 typename NumericTraits::abstime_type>);
392 downstream.handle(real_linear_timing_event<NumericTraits>{
393 event.abstime, event.delay, event.interval, ct});
394 }
395
396 template <typename NT>
397 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
398 void handle(periodic_sequence_model_event<NT> &&event) {
399 handle(static_cast<periodic_sequence_model_event<NT> const &>(event));
400 }
401
402 template <typename OtherEvent>
403 requires handler_for<Downstream, std::remove_cvref_t<OtherEvent>>
404 void handle(OtherEvent &&event) {
405 downstream.handle(std::forward<OtherEvent>(event));
406 }
407
408 void flush() { downstream.flush(); }
409};
410
411} // namespace internal
412
446template <typename NumericTraits = default_numeric_traits, typename Downstream>
448 Downstream downstream) {
449 return internal::add_count_to_periodic_sequences<NumericTraits,
450 Downstream>(
451 count, std::move(downstream));
452}
453
454namespace internal {
455
456template <typename TickEvent, typename StartEvent, typename StopEvent,
457 typename Downstream>
458 requires processor<Downstream, StartEvent, StopEvent>
460 static_assert(
461 std::is_same_v<decltype(std::declval<TickEvent>().abstime),
462 decltype(std::declval<StartEvent>().abstime)>);
463 static_assert(std::is_same_v<decltype(std::declval<TickEvent>().abstime),
464 decltype(std::declval<StopEvent>().abstime)>);
465
466 std::size_t input_len;
467 std::size_t seen = 0;
468 Downstream downstream;
469
470 public:
471 explicit convert_sequences_to_start_stop(arg::count<std::size_t> count,
472 Downstream downstream)
473 : input_len(count.value + 1), downstream(std::move(downstream)) {}
474
475 [[nodiscard]] auto introspect_node() const -> processor_info {
476 return processor_info(this, "convert_sequences_to_start_stop");
477 }
478
479 [[nodiscard]] auto introspect_graph() const -> processor_graph {
480 return downstream.introspect_graph().push_entry_point(this);
481 }
482
483 void handle(TickEvent const &event) {
484 if (seen > 0) {
485 StopEvent e{};
486 e.abstime = event.abstime;
487 downstream.handle(std::move(e));
488 }
489 ++seen;
490 if (seen < input_len) {
491 StartEvent e{};
492 e.abstime = event.abstime;
493 downstream.handle(std::move(e));
494 } else {
495 seen = 0;
496 }
497 }
498
499 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
500 void handle(TickEvent &&event) {
501 handle(static_cast<TickEvent const &>(event));
502 }
503
504 template <typename OtherEvent>
505 requires handler_for<Downstream, std::remove_cvref_t<OtherEvent>>
506 void handle(OtherEvent &&event) {
507 downstream.handle(std::forward<OtherEvent>(event));
508 }
509
510 void flush() { downstream.flush(); }
511};
512
513} // namespace internal
514
559template <typename TickEvent, typename StartEvent, typename StopEvent,
560 typename Downstream>
562 Downstream downstream) {
563 return internal::convert_sequences_to_start_stop<TickEvent, StartEvent,
564 StopEvent, Downstream>(
565 count, std::move(downstream));
566}
567
568} // namespace tcspc
auto count(access_tracker< count_accessor > &&tracker, Downstream downstream)
Create a processor that counts events of a given type.
Definition count.hpp:312
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:561
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:361
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:447
auto retime_periodic_sequences(arg::max_time_shift< typename NumericTraits::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:266
libtcspc namespace.
Definition acquire.hpp:30
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 interval
Interval, in abstime units per index, of the modeled sequence.
Definition timing_misc.hpp:51
double delay
The estimated time of the first event, relative to abstime.
Definition timing_misc.hpp:46
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.
NumericTraits::abstime_type abstime
Absolute time of this event, used as a reference point.
Definition timing_misc.hpp:38
Event representing a prescription for linear timing generation with real (fractional) delay and inter...
Definition timing_misc.hpp:110
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
NumericTraits::abstime_type abstime
Absolute time of this event, used as a reference point.
Definition timing_misc.hpp:114
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
double delay
The time delay relative to abstime.
Definition timing_misc.hpp:85
friend auto operator==(real_one_shot_timing_event const &lhs, real_one_shot_timing_event const &rhs) noexcept -> bool=default
Equality comparison operator.
NumericTraits::abstime_type abstime
Absolute time of this event, used as a reference point.
Definition timing_misc.hpp:80