libtcspc C++ API
Streaming TCSPC and time tag data processing
Loading...
Searching...
No Matches
count.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 "context.hpp"
12#include "int_types.hpp"
13#include "introspect.hpp"
14#include "processor.hpp"
15
16#include <functional>
17#include <stdexcept>
18#include <type_traits>
19#include <utility>
20
21namespace tcspc {
22
23namespace internal {
24
25template <typename TickEvent, typename FireEvent, typename ResetEvent,
26 bool FireAfterTick, typename Downstream>
27class count_up_to {
28 // Do not require handling of ResetEvent, as it may not be used at all.
29 static_assert(processor<Downstream, TickEvent, FireEvent>);
30
31 u64 count;
32 u64 init;
33 u64 thresh;
34 u64 lmt;
35
36 Downstream downstream;
37
38 template <typename Abstime> void pre_tick(Abstime abstime) {
39 if constexpr (!FireAfterTick) {
40 if (count == thresh)
41 downstream.handle(FireEvent{abstime});
42 }
43 }
44
45 template <typename Abstime> void post_tick(Abstime abstime) {
46 ++count;
47
48 if constexpr (FireAfterTick) {
49 if (count == thresh)
50 downstream.handle(FireEvent{abstime});
51 }
52
53 if (count == lmt)
54 count = init;
55 }
56
57 public:
58 explicit count_up_to(arg::threshold<u64> threshold, arg::limit<u64> limit,
59 arg::initial_count<u64> initial_count,
60 Downstream downstream)
61 : count(initial_count.value), init(initial_count.value),
62 thresh(threshold.value), lmt(limit.value),
63 downstream(std::move(downstream)) {
64 if (init >= lmt)
65 throw std::invalid_argument(
66 "count_up_to limit must be greater than initial_count");
67 }
68
69 [[nodiscard]] auto introspect_node() const -> processor_info {
70 return processor_info(this, "count_up_to");
71 }
72
73 [[nodiscard]] auto introspect_graph() const -> processor_graph {
74 return downstream.introspect_graph().push_entry_point(this);
75 }
76
77 void handle(TickEvent const &event) {
78 pre_tick(event.abstime);
79 downstream.handle(event);
80 post_tick(event.abstime);
81 }
82
83 void handle(TickEvent &&event) {
84 auto const abstime = event.abstime;
85 pre_tick(abstime);
86 downstream.handle(std::move(event));
87 post_tick(abstime);
88 }
89
90 template <typename E>
91 requires handler_for<Downstream, std::remove_cvref_t<E>>
92 void handle(E &&event) {
93 if constexpr (std::is_convertible_v<std::remove_cvref_t<E>,
94 ResetEvent>) {
95 count = init;
96 }
97 downstream.handle(std::forward<E>(event));
98 }
99
100 void flush() { downstream.flush(); }
101};
102
103} // namespace internal
104
176template <typename TickEvent, typename FireEvent, typename ResetEvent,
177 bool FireAfterTick, typename Downstream>
179 arg::initial_count<u64> initial_count,
180 Downstream downstream) {
181 return internal::count_up_to<TickEvent, FireEvent, ResetEvent,
182 FireAfterTick, Downstream>(
183 threshold, limit, initial_count, std::move(downstream));
184}
185
197template <typename TickEvent, typename FireEvent, typename ResetEvent,
198 bool FireAfterTick, typename Downstream>
200 arg::initial_count<u64> initial_count,
201 Downstream downstream) {
202 // Alter parameters to emulate count down using count up.
203 if (limit.value >= initial_count.value)
204 throw std::invalid_argument(
205 "count_down_to limit must be less than initial_count");
206 if (threshold.value > initial_count.value ||
207 threshold.value < limit.value) {
208 // Counter will never fire; no change to threshold needed.
209 } else {
210 // Mirror threshold around midpoint of initial_count and limit.
211 threshold.value =
212 limit.value + (initial_count.value - threshold.value);
213 }
214 using std::swap;
215 swap(initial_count.value, limit.value);
216
217 return internal::count_up_to<TickEvent, FireEvent, ResetEvent,
218 FireAfterTick, Downstream>(
219 threshold, limit, initial_count, std::move(downstream));
220}
221
227class count_access {
228 std::function<u64()> count_fn;
229
230 public:
232 template <typename Func>
233 explicit count_access(Func count_func) : count_fn(count_func) {}
234
238 auto count() -> u64 { return count_fn(); }
239};
240
241namespace internal {
242
243template <typename Event, typename Downstream> class count {
244 static_assert(processor<Downstream, Event>);
245
246 u64 ct = 0;
247
248 Downstream downstream;
249
250 // Cold data after downstream.
251 access_tracker<count_access> trk;
252
253 public:
254 explicit count(access_tracker<count_access> &&tracker,
255 Downstream downstream)
256 : downstream(std::move(downstream)), trk(std::move(tracker)) {
257 trk.register_access_factory([](auto &tracker) {
258 auto *self = LIBTCSPC_OBJECT_FROM_TRACKER(count, trk, tracker);
259 return count_access([self] { return self->ct; });
260 });
261 }
262
263 [[nodiscard]] auto introspect_node() const -> processor_info {
264 return processor_info(this, "count");
265 }
266
267 [[nodiscard]] auto introspect_graph() const -> processor_graph {
268 return downstream.introspect_graph().push_entry_point(this);
269 }
270
271 template <typename E>
272 requires handler_for<Downstream, std::remove_cvref_t<E>>
273 void handle(E &&event) {
274 if constexpr (std::is_convertible_v<std::remove_cvref_t<E>, Event>)
275 ++ct;
276 downstream.handle(std::forward<E>(event));
277 }
278
279 void flush() { downstream.flush(); }
280};
281
282} // namespace internal
283
312template <typename Event, typename Downstream>
313auto count(access_tracker<count_access> &&tracker, Downstream downstream) {
314 return internal::count<Event, Downstream>(std::move(tracker),
315 std::move(downstream));
316}
317
318} // namespace tcspc
Tracker that mediates access to objects via a tcspc::context.
Definition context.hpp:39
auto count() -> u64
Return the count value of the associated processor.
Definition count.hpp:238
#define LIBTCSPC_OBJECT_FROM_TRACKER(obj_type, tracker_field_name, tracker)
Recover the object address from a tcspc::access_tracker embedded in the object.
Definition context.hpp:253
auto count(access_tracker< count_access > &&tracker, Downstream downstream)
Create a processor that counts events of a given type.
Definition count.hpp:313
auto count_down_to(arg::threshold< u64 > threshold, arg::limit< u64 > limit, arg::initial_count< u64 > initial_count, Downstream downstream)
Like tcspc::count_up_to(), but decrement the count on each tick event.
Definition count.hpp:199
auto count_up_to(arg::threshold< u64 > threshold, arg::limit< u64 > limit, arg::initial_count< u64 > initial_count, Downstream downstream)
Create a processor that counts a specific event and emits an event when the count reaches a threshold...
Definition count.hpp:178
std::uint64_t u64
Short name for uint64_t.
Definition int_types.hpp:33
libtcspc namespace.
Definition acquire.hpp:29
Function argument wrapper for initial count parameter.
Definition arg_wrappers.hpp:167
T value
The argument value.
Definition arg_wrappers.hpp:169
Function argument wrapper for limit parameter.
Definition arg_wrappers.hpp:207
T value
The argument value.
Definition arg_wrappers.hpp:209
Function argument wrapper for threshold parameter.
Definition arg_wrappers.hpp:397
T value
The argument value.
Definition arg_wrappers.hpp:399