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 "introspect.hpp"
12#include "numeric_traits.hpp"
13#include "processor.hpp"
14
15#include <concepts>
16#include <cstddef>
17#include <optional>
18#include <stdexcept>
19#include <type_traits>
20#include <utility>
21
22namespace tcspc {
23
35template <typename T, typename TriggerEvent>
37 std::move_constructible<T> &&
38 requires(T &g, T const &cg, TriggerEvent const &event) {
39 { g.trigger(event) } -> std::same_as<void>;
40 {
41 cg.peek()
42 } -> std::same_as<
43 std::optional<decltype(std::declval<TriggerEvent>().abstime)>>;
44 { g.pop() } -> std::same_as<void>;
45 };
46
47namespace internal {
48
49template <typename TriggerEvent, typename OutputEvent,
50 typename TimingGenerator, typename Downstream>
53class generate {
54 using abstime_type = decltype(std::declval<TriggerEvent>().abstime);
55 static_assert(std::is_same_v<decltype(std::declval<OutputEvent>().abstime),
56 abstime_type>);
57
58 TimingGenerator generator;
59
60 Downstream downstream;
61
62 // Pred: bool(abstime_type const &)
63 template <typename Pred> void emit(Pred predicate) {
64 auto const &const_gen = generator; // Enforce peek() const.
65 for (std::optional<abstime_type> t = const_gen.peek();
66 t && predicate(*t); t = const_gen.peek()) {
67 OutputEvent event;
68 event.abstime = *t;
69 generator.pop();
70 downstream.handle(std::move(event));
71 }
72 }
73
74 public:
75 explicit generate(TimingGenerator generator, Downstream downstream)
76 : generator(std::move(generator)), downstream(std::move(downstream)) {}
77
78 [[nodiscard]] auto introspect_node() const -> processor_info {
79 return processor_info(this, "generate");
80 }
81
82 [[nodiscard]] auto introspect_graph() const -> processor_graph {
83 return downstream.introspect_graph().push_entry_point(this);
84 }
85
86 template <typename E>
87 requires handler_for<Downstream, std::remove_cvref_t<E>>
88 void handle(E &&event) {
89 emit([now = event.abstime](auto t) { return t <= now; });
90 if constexpr (std::is_convertible_v<std::remove_cvref_t<E>,
91 TriggerEvent>) {
92 generator.trigger(event);
93 }
94 downstream.handle(std::forward<E>(event));
95 }
96
97 void flush() {
98 // Note that we do _not_ generate the remaining timings. Usually timing
99 // events beyond the end of the event stream are not useful, and not
100 // generating them means that infinite generators can be used.
101 downstream.flush();
102 }
103};
104
105} // namespace internal
106
157template <typename TriggerEvent, typename OutputEvent,
158 typename TimingGenerator, typename Downstream>
159auto generate(TimingGenerator generator, Downstream downstream) {
160 return internal::generate<TriggerEvent, OutputEvent, TimingGenerator,
161 Downstream>(std::move(generator),
162 std::move(downstream));
163}
164
172template <typename NumericTraits = default_numeric_traits>
174 public:
176 template <typename TriggerEvent> void trigger(TriggerEvent const &event) {
177 static_assert(std::is_same_v<decltype(event.abstime),
178 typename NumericTraits::abstime_type>);
179 }
180
182 [[nodiscard]] auto peek() const
183 -> std::optional<typename NumericTraits::abstime_type> {
184 return std::nullopt;
185 }
186
188 void pop() { internal::unreachable(); }
189};
190
198template <typename NumericTraits = default_numeric_traits>
200 std::optional<typename NumericTraits::abstime_type> next;
201 NumericTraits::abstime_type dly;
202
203 public:
212 : dly(delay.value) {
213 if (dly < 0)
214 throw std::invalid_argument(
215 "one_shot_timing_generator delay must not be negative");
216 }
217
219 template <typename TriggerEvent> void trigger(TriggerEvent const &event) {
220 static_assert(std::is_same_v<decltype(event.abstime),
221 typename NumericTraits::abstime_type>);
222 next = event.abstime + dly;
223 }
224
226 [[nodiscard]] auto peek() const
227 -> std::optional<typename NumericTraits::abstime_type> {
228 return next;
229 }
230
232 void pop() { next.reset(); }
233};
234
246template <typename NumericTraits = default_numeric_traits>
248 std::optional<typename NumericTraits::abstime_type> next;
249
250 public:
252 template <typename TriggerEvent> void trigger(TriggerEvent const &event) {
253 static_assert(std::is_same_v<decltype(event.abstime),
254 typename NumericTraits::abstime_type>);
255 static_assert(std::is_same_v<decltype(event.delay),
256 typename NumericTraits::abstime_type>);
257 next = event.abstime + event.delay;
258 }
259
261 [[nodiscard]] auto peek() const
262 -> std::optional<typename NumericTraits::abstime_type> {
263 return next;
264 }
265
267 void pop() { next.reset(); }
268};
269
277template <typename NumericTraits = default_numeric_traits>
279 NumericTraits::abstime_type next = 0;
280 std::size_t remaining = 0;
281
282 NumericTraits::abstime_type dly;
283 NumericTraits::abstime_type intval;
284 std::size_t ct;
285
286 public:
297 : dly(delay.value), intval(interval.value), ct(count.value) {
298 if (dly < 0)
299 throw std::invalid_argument(
300 "linear_timing_generator delay must not be negative");
301 if (intval <= 0)
302 throw std::invalid_argument(
303 "linear_timing_generator interval must be positive");
304 }
305
307 template <typename TriggerEvent> void trigger(TriggerEvent const &event) {
308 static_assert(std::is_same_v<decltype(event.abstime),
309 typename NumericTraits::abstime_type>);
310 next = event.abstime + dly;
311 remaining = ct;
312 }
313
315 [[nodiscard]] auto peek() const
316 -> std::optional<typename NumericTraits::abstime_type> {
317 if (remaining > 0)
318 return next;
319 return std::nullopt;
320 }
321
323 void pop() {
324 next += intval;
325 --remaining;
326 }
327};
328
340template <typename NumericTraits = default_numeric_traits>
342 NumericTraits::abstime_type next = 0;
343 std::size_t remaining = 0;
344 NumericTraits::abstime_type interval = 0;
345
346 public:
348 template <typename TriggerEvent> void trigger(TriggerEvent const &event) {
349 static_assert(std::is_same_v<decltype(event.abstime),
350 typename NumericTraits::abstime_type>);
351 next = event.abstime + event.delay;
352 remaining = event.count;
353 interval = event.interval;
354 }
355
357 [[nodiscard]] auto peek() const
358 -> std::optional<typename NumericTraits::abstime_type> {
359 if (remaining > 0)
360 return next;
361 return std::nullopt;
362 }
363
365 void pop() {
366 next += interval;
367 --remaining;
368 }
369};
370
371} // namespace tcspc
Timing generator that generates an equally spaced series of timings, configured by the trigger event.
Definition generate.hpp:341
auto peek() const -> std::optional< typename NumericTraits::abstime_type >
Implements timing generator requirement.
Definition generate.hpp:357
void pop()
Implements timing generator requirement.
Definition generate.hpp:365
void trigger(TriggerEvent const &event)
Implements timing generator requirement.
Definition generate.hpp:348
Timing generator that generates a single, delayed timing, configured by the trigger event.
Definition generate.hpp:247
void trigger(TriggerEvent const &event)
Implements timing generator requirement.
Definition generate.hpp:252
void pop()
Implements timing generator requirement.
Definition generate.hpp:267
auto peek() const -> std::optional< typename NumericTraits::abstime_type >
Implements timing generator requirement.
Definition generate.hpp:261
void trigger(TriggerEvent const &event)
Implements timing generator requirement.
Definition generate.hpp:307
linear_timing_generator(arg::delay< typename NumericTraits::abstime_type > delay, arg::interval< typename NumericTraits::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:293
void pop()
Implements timing generator requirement.
Definition generate.hpp:323
auto peek() const -> std::optional< typename NumericTraits::abstime_type >
Implements timing generator requirement.
Definition generate.hpp:315
Timing generator that generates no timings.
Definition generate.hpp:173
auto peek() const -> std::optional< typename NumericTraits::abstime_type >
Implements timing generator requirement.
Definition generate.hpp:182
void pop()
Implements timing generator requirement.
Definition generate.hpp:188
void trigger(TriggerEvent const &event)
Implements timing generator requirement.
Definition generate.hpp:176
auto peek() const -> std::optional< typename NumericTraits::abstime_type >
Implements timing generator requirement.
Definition generate.hpp:226
one_shot_timing_generator(arg::delay< typename NumericTraits::abstime_type > delay)
Construct an instance that generates a timing after delay relative to each trigger.
Definition generate.hpp:210
void trigger(TriggerEvent const &event)
Implements timing generator requirement.
Definition generate.hpp:219
void pop()
Implements timing generator requirement.
Definition generate.hpp:232
Concept that is satisfied when a processor handles the given event types and flush.
Definition processor.hpp:119
Concept that is satisfied when T conforms to the libtcspc timing generator interface for trigger even...
Definition generate.hpp:36
auto count(access_tracker< count_accessor > &&tracker, Downstream downstream)
Create a processor that counts events of a given type.
Definition count.hpp:312
auto delay(arg::delta< typename NumericTraits::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:159
libtcspc namespace.
Definition acquire.hpp:30
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