libtcspc C++ API
Streaming TCSPC and time tag data processing
Loading...
Searching...
No Matches
generate.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 "introspect.hpp"
13#include "processor.hpp"
14
15#include <cstddef>
16#include <optional>
17#include <stdexcept>
18#include <type_traits>
19#include <utility>
20
21namespace tcspc {
22
23namespace internal {
24
25template <typename TriggerEvent, typename OutputEvent,
26 typename TimingGenerator, typename Downstream>
27class generate {
28 static_assert(processor<Downstream, TriggerEvent, OutputEvent>);
29
30 using abstime_type = decltype(std::declval<TriggerEvent>().abstime);
31 static_assert(
32 std::is_same_v<std::remove_reference_t<
33 decltype(*std::declval<TimingGenerator>().peek())>,
34 abstime_type>);
35 static_assert(std::is_same_v<decltype(std::declval<OutputEvent>().abstime),
36 abstime_type>);
37
38 TimingGenerator generator;
39
40 Downstream downstream;
41
42 // Pred: bool(abstime_type const &)
43 template <typename Pred> void emit(Pred predicate) {
44 auto const &const_gen = generator; // Enforce peek() const.
45 for (std::optional<abstime_type> t = const_gen.peek();
46 t && predicate(*t); t = const_gen.peek()) {
47 OutputEvent event;
48 event.abstime = *t;
49 generator.pop();
50 downstream.handle(std::move(event));
51 }
52 }
53
54 public:
55 explicit generate(TimingGenerator generator, Downstream downstream)
56 : generator(std::move(generator)), downstream(std::move(downstream)) {}
57
58 [[nodiscard]] auto introspect_node() const -> processor_info {
59 return processor_info(this, "generate");
60 }
61
62 [[nodiscard]] auto introspect_graph() const -> processor_graph {
63 return downstream.introspect_graph().push_entry_point(this);
64 }
65
66 template <typename E>
67 requires handler_for<Downstream, std::remove_cvref_t<E>>
68 void handle(E &&event) {
69 emit([now = event.abstime](auto t) { return t <= now; });
70 if constexpr (std::is_convertible_v<std::remove_cvref_t<E>,
71 TriggerEvent>) {
72 generator.trigger(event);
73 }
74 downstream.handle(std::forward<E>(event));
75 }
76
77 void flush() {
78 // Note that we do _not_ generate the remaining timings. Usually timing
79 // events beyond the end of the event stream are not useful, and not
80 // generating them means that infinite generators can be used.
81 downstream.flush();
82 }
83};
84
85} // namespace internal
86
137template <typename TriggerEvent, typename OutputEvent,
138 typename TimingGenerator, typename Downstream>
139auto generate(TimingGenerator generator, Downstream downstream) {
140 return internal::generate<TriggerEvent, OutputEvent, TimingGenerator,
141 Downstream>(std::move(generator),
142 std::move(downstream));
143}
144
152template <typename DataTypes = default_data_types>
154 public:
156 template <typename TriggerEvent> void trigger(TriggerEvent const &event) {
157 static_assert(std::is_same_v<decltype(event.abstime),
158 typename DataTypes::abstime_type>);
159 }
160
162 [[nodiscard]] auto peek() const
163 -> std::optional<typename DataTypes::abstime_type> {
164 return std::nullopt;
165 }
166
168 void pop() { internal::unreachable(); }
169};
170
178template <typename DataTypes = default_data_types>
180 std::optional<typename DataTypes::abstime_type> next;
181 typename DataTypes::abstime_type dly;
182
183 public:
192 : dly(delay.value) {
193 if (dly < 0)
194 throw std::invalid_argument(
195 "one_shot_timing_generator delay must not be negative");
196 }
197
199 template <typename TriggerEvent> void trigger(TriggerEvent const &event) {
200 static_assert(std::is_same_v<decltype(event.abstime),
201 typename DataTypes::abstime_type>);
202 next = event.abstime + dly;
203 }
204
206 [[nodiscard]] auto peek() const
207 -> std::optional<typename DataTypes::abstime_type> {
208 return next;
209 }
210
212 void pop() { next.reset(); }
213};
214
226template <typename DataTypes = default_data_types>
228 std::optional<typename DataTypes::abstime_type> next;
229
230 public:
232 template <typename TriggerEvent> void trigger(TriggerEvent const &event) {
233 static_assert(std::is_same_v<decltype(event.abstime),
234 typename DataTypes::abstime_type>);
235 static_assert(std::is_same_v<decltype(event.delay),
236 typename DataTypes::abstime_type>);
237 next = event.abstime + event.delay;
238 }
239
241 [[nodiscard]] auto peek() const
242 -> std::optional<typename DataTypes::abstime_type> {
243 return next;
244 }
245
247 void pop() { next.reset(); }
248};
249
257template <typename DataTypes = default_data_types>
259 typename DataTypes::abstime_type next = 0;
260 std::size_t remaining = 0;
261
262 typename DataTypes::abstime_type dly;
263 typename DataTypes::abstime_type intval;
264 std::size_t ct;
265
266 public:
277 : dly(delay.value), intval(interval.value), ct(count.value) {
278 if (dly < 0)
279 throw std::invalid_argument(
280 "linear_timing_generator delay must not be negative");
281 if (intval <= 0)
282 throw std::invalid_argument(
283 "linear_timing_generator interval must be positive");
284 }
285
287 template <typename TriggerEvent> void trigger(TriggerEvent const &event) {
288 static_assert(std::is_same_v<decltype(event.abstime),
289 typename DataTypes::abstime_type>);
290 next = event.abstime + dly;
291 remaining = ct;
292 }
293
295 [[nodiscard]] auto peek() const
296 -> std::optional<typename DataTypes::abstime_type> {
297 if (remaining > 0)
298 return next;
299 return std::nullopt;
300 }
301
303 void pop() {
304 next += intval;
305 --remaining;
306 }
307};
308
320template <typename DataTypes = default_data_types>
322 typename DataTypes::abstime_type next = 0;
323 std::size_t remaining = 0;
324 typename DataTypes::abstime_type interval = 0;
325
326 public:
328 template <typename TriggerEvent> void trigger(TriggerEvent const &event) {
329 static_assert(std::is_same_v<decltype(event.abstime),
330 typename DataTypes::abstime_type>);
331 next = event.abstime + event.delay;
332 remaining = event.count;
333 interval = event.interval;
334 }
335
337 [[nodiscard]] auto peek() const
338 -> std::optional<typename DataTypes::abstime_type> {
339 if (remaining > 0)
340 return next;
341 return std::nullopt;
342 }
343
345 void pop() {
346 next += interval;
347 --remaining;
348 }
349};
350
351} // namespace tcspc
Timing generator that generates an equally spaced series of timings, configured by the trigger event.
Definition generate.hpp:321
auto peek() const -> std::optional< typename DataTypes::abstime_type >
Implements timing generator requirement.
Definition generate.hpp:337
void pop()
Implements timing generator requirement.
Definition generate.hpp:345
void trigger(TriggerEvent const &event)
Implements timing generator requirement.
Definition generate.hpp:328
Timing generator that generates a single, delayed timing, configured by the trigger event.
Definition generate.hpp:227
void trigger(TriggerEvent const &event)
Implements timing generator requirement.
Definition generate.hpp:232
auto peek() const -> std::optional< typename DataTypes::abstime_type >
Implements timing generator requirement.
Definition generate.hpp:241
void pop()
Implements timing generator requirement.
Definition generate.hpp:247
void pop()
Implements timing generator requirement.
Definition generate.hpp:303
auto peek() const -> std::optional< typename DataTypes::abstime_type >
Implements timing generator requirement.
Definition generate.hpp:295
linear_timing_generator(arg::delay< typename DataTypes::abstime_type > delay, arg::interval< typename DataTypes::abstime_type > interval, arg::count< std::size_t > count)
Construct an instance that generates count timings at interval after delay relative to each trigger.
Definition generate.hpp:273
void trigger(TriggerEvent const &event)
Implements timing generator requirement.
Definition generate.hpp:287
Timing generator that generates no timings.
Definition generate.hpp:153
void trigger(TriggerEvent const &event)
Implements timing generator requirement.
Definition generate.hpp:156
auto peek() const -> std::optional< typename DataTypes::abstime_type >
Implements timing generator requirement.
Definition generate.hpp:162
void pop()
Implements timing generator requirement.
Definition generate.hpp:168
void pop()
Implements timing generator requirement.
Definition generate.hpp:212
void trigger(TriggerEvent const &event)
Implements timing generator requirement.
Definition generate.hpp:199
auto peek() const -> std::optional< typename DataTypes::abstime_type >
Implements timing generator requirement.
Definition generate.hpp:206
one_shot_timing_generator(arg::delay< typename DataTypes::abstime_type > delay)
Construct an instance that generates a timing after delay relative to each trigger.
Definition generate.hpp:190
auto count(access_tracker< count_access > &&tracker, Downstream downstream)
Create a processor that counts events of a given type.
Definition count.hpp:313
auto delay(arg::delta< typename DataTypes::abstime_type > delta, Downstream downstream)
Create a processor that applies an abstime offset to all events.
Definition delay.hpp:123
auto generate(TimingGenerator generator, Downstream downstream)
Create a processor that generates a pattern of timing events in response to a trigger.
Definition generate.hpp:139
libtcspc namespace.
Definition acquire.hpp:29
Function argument wrapper for count parameter.
Definition arg_wrappers.hpp:97
Function argument wrapper for delay parameter.
Definition arg_wrappers.hpp:117
Function argument wrapper for interval parameter.
Definition arg_wrappers.hpp:177