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
25// Do not require handling of ResetEvent, as it may not be used at all.
26template <typename TickEvent, typename FireEvent, typename ResetEvent,
27 bool FireAfterTick, typename Downstream>
28 requires processor<Downstream, TickEvent, FireEvent>
29class count_up_to {
30 u64 count;
31 u64 init;
32 u64 thresh;
33 u64 lmt;
34
35 Downstream downstream;
36
37 template <typename Abstime> void pre_tick(Abstime abstime) {
38 if constexpr (!FireAfterTick) {
39 if (count == thresh)
40 downstream.handle(FireEvent{abstime});
41 }
42 }
43
44 template <typename Abstime> void post_tick(Abstime abstime) {
45 ++count;
46
47 if constexpr (FireAfterTick) {
48 if (count == thresh)
49 downstream.handle(FireEvent{abstime});
50 }
51
52 if (count == lmt)
53 count = init;
54 }
55
56 public:
57 explicit count_up_to(arg::threshold<u64> threshold, arg::limit<u64> limit,
58 arg::initial_count<u64> initial_count,
59 Downstream downstream)
60 : count(initial_count.value), init(initial_count.value),
61 thresh(threshold.value), lmt(limit.value),
62 downstream(std::move(downstream)) {
63 if (init >= lmt)
64 throw std::invalid_argument(
65 "count_up_to limit must be greater than initial_count");
66 }
67
68 [[nodiscard]] auto introspect_node() const -> processor_info {
69 return processor_info(this, "count_up_to");
70 }
71
72 [[nodiscard]] auto introspect_graph() const -> processor_graph {
73 return downstream.introspect_graph().push_entry_point(this);
74 }
75
76 void handle(TickEvent const &event) {
77 pre_tick(event.abstime);
78 downstream.handle(event);
79 post_tick(event.abstime);
80 }
81
82 void handle(TickEvent &&event) {
83 auto const abstime = event.abstime;
84 pre_tick(abstime);
85 downstream.handle(std::move(event));
86 post_tick(abstime);
87 }
88
89 template <typename E>
90 requires handler_for<Downstream, std::remove_cvref_t<E>>
91 void handle(E &&event) {
92 if constexpr (std::is_convertible_v<std::remove_cvref_t<E>,
93 ResetEvent>) {
94 count = init;
95 }
96 downstream.handle(std::forward<E>(event));
97 }
98
99 void flush() { downstream.flush(); }
100};
101
102} // namespace internal
103
175template <typename TickEvent, typename FireEvent, typename ResetEvent,
176 bool FireAfterTick, typename Downstream>
178 arg::initial_count<u64> initial_count,
179 Downstream downstream) {
180 return internal::count_up_to<TickEvent, FireEvent, ResetEvent,
181 FireAfterTick, Downstream>(
182 threshold, limit, initial_count, std::move(downstream));
183}
184
196template <typename TickEvent, typename FireEvent, typename ResetEvent,
197 bool FireAfterTick, typename Downstream>
199 arg::initial_count<u64> initial_count,
200 Downstream downstream) {
201 // Alter parameters to emulate count down using count up.
202 if (limit.value >= initial_count.value)
203 throw std::invalid_argument(
204 "count_down_to limit must be less than initial_count");
205 if (threshold.value > initial_count.value ||
206 threshold.value < limit.value) {
207 // Counter will never fire; no change to threshold needed.
208 } else {
209 // Mirror threshold around midpoint of initial_count and limit.
210 threshold.value =
211 limit.value + (initial_count.value - threshold.value);
212 }
213 using std::swap;
214 swap(initial_count.value, limit.value);
215
216 return internal::count_up_to<TickEvent, FireEvent, ResetEvent,
217 FireAfterTick, Downstream>(
218 threshold, limit, initial_count, std::move(downstream));
219}
220
226class count_accessor {
227 std::function<u64()> count_fn;
228
229 public:
231 template <typename Func>
232 explicit count_accessor(Func count_func) : count_fn(count_func) {}
233
237 auto count() -> u64 { return count_fn(); }
238};
239
240namespace internal {
241
242template <typename Event, typename Downstream>
243 requires processor<Downstream, Event>
244class count {
245 u64 ct = 0;
246
247 Downstream downstream;
248
249 // Cold data after downstream.
250 access_tracker<count_accessor> trk;
251
252 public:
253 explicit count(access_tracker<count_accessor> &&tracker,
254 Downstream downstream)
255 : downstream(std::move(downstream)), trk(std::move(tracker)) {
256 trk.register_accessor_factory([](auto &tracker) {
257 auto *self = LIBTCSPC_OBJECT_FROM_TRACKER(count, trk, tracker);
258 return count_accessor([self] { return self->ct; });
259 });
260 }
261
262 [[nodiscard]] auto introspect_node() const -> processor_info {
263 return processor_info(this, "count");
264 }
265
266 [[nodiscard]] auto introspect_graph() const -> processor_graph {
267 return downstream.introspect_graph().push_entry_point(this);
268 }
269
270 template <typename E>
271 requires handler_for<Downstream, std::remove_cvref_t<E>>
272 void handle(E &&event) {
273 if constexpr (std::is_convertible_v<std::remove_cvref_t<E>, Event>)
274 ++ct;
275 downstream.handle(std::forward<E>(event));
276 }
277
278 void flush() { downstream.flush(); }
279};
280
281} // namespace internal
282
311template <typename Event, typename Downstream>
312auto count(access_tracker<count_accessor> &&tracker, Downstream downstream) {
313 return internal::count<Event, Downstream>(std::move(tracker),
314 std::move(downstream));
315}
316
317} // 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:237
#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:255
auto count(access_tracker< count_accessor > &&tracker, Downstream downstream)
Create a processor that counts events of a given type.
Definition count.hpp:312
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:198
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:177
std::uint64_t u64
Short name for uint64_t.
Definition int_types.hpp:33
libtcspc namespace.
Definition acquire.hpp:30
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