9#include "arg_wrappers.hpp"
12#include "histogram_events.hpp"
13#include "int_arith.hpp"
14#include "int_types.hpp"
15#include "introspect.hpp"
16#include "numeric_traits.hpp"
17#include "processor.hpp"
44template <
typename T,
typename Event,
typename Datapo
int>
46 std::move_constructible<T> &&
requires(T
const &m, Event
const &e) {
47 { m(e) } -> std::same_as<Datapoint>;
66template <
typename T,
typename Datapo
int,
typename BinIndex>
68 std::move_constructible<T> &&
requires(T &m, Datapoint d) {
69 { m(d) } -> std::same_as<std::optional<BinIndex>>;
74template <
typename Event,
typename NumericTraits,
typename DataMapper,
77 typename NumericTraits::datapoint_type> &&
82 Downstream downstream;
86 : mapper(std::move(mapper)), downstream(std::move(downstream)) {}
88 [[nodiscard]]
auto introspect_node() const -> processor_info {
89 return processor_info(
this,
"map_to_datapoints");
92 [[nodiscard]]
auto introspect_graph() const -> processor_graph {
93 return downstream.introspect_graph().push_entry_point(
this);
96 void handle(Event
const &event) {
98 datapoint_event<NumericTraits>{std::invoke(mapper, event)});
102 void handle(Event &&event) { handle(
static_cast<Event
const &
>(event)); }
104 template <
typename OtherEvent>
105 requires handler_for<Downstream, std::remove_cvref_t<OtherEvent>>
106 void handle(OtherEvent &&event) {
107 downstream.handle(std::forward<OtherEvent>(event));
110 void flush() { downstream.flush(); }
147 typename DataMapper,
typename Downstream>
149 return internal::map_to_datapoints<Event, NumericTraits, DataMapper,
150 Downstream>(std::move(mapper),
151 std::move(downstream));
163template <
typename NumericTraits = default_numeric_traits>
167 template <
typename Event>
169 -> NumericTraits::datapoint_type {
171 internal::representable_in<
decltype(
event.difftime),
172 typename NumericTraits::datapoint_type>,
173 "difftime_data_mapper does not allow narrowing conversion");
174 return event.difftime;
187template <
typename NumericTraits = default_numeric_traits>
191 template <
typename Event>
193 -> NumericTraits::datapoint_type {
195 internal::representable_in<
decltype(
event.count),
196 typename NumericTraits::datapoint_type>,
197 "count_data_mapper does not allow narrowing conversion");
211template <
typename NumericTraits = default_numeric_traits>
215 template <
typename Event>
217 -> NumericTraits::datapoint_type {
219 internal::representable_in<
decltype(
event.channel),
220 typename NumericTraits::datapoint_type>,
221 "channel_data_mapper does not allow narrowing conversion");
222 return event.channel;
228template <
typename NumericTraits,
typename BinMapper,
typename Downstream>
229 requires bin_mapper_for<BinMapper,
typename NumericTraits::datapoint_type,
230 typename NumericTraits::bin_index_type> &&
231 processor<Downstream, bin_increment_event<NumericTraits>>
233 static_assert(with_datapoint_type<NumericTraits>);
234 static_assert(with_bin_index_type<NumericTraits>);
236 BinMapper bin_mapper;
237 Downstream downstream;
240 explicit map_to_bins(BinMapper bin_mapper, Downstream downstream)
241 : bin_mapper(std::move(bin_mapper)),
242 downstream(std::move(downstream)) {}
244 [[nodiscard]]
auto introspect_node() const -> processor_info {
245 return processor_info(
this,
"map_to_bins");
248 [[nodiscard]]
auto introspect_graph() const -> processor_graph {
249 return downstream.introspect_graph().push_entry_point(
this);
252 template <
typename NT>
void handle(datapoint_event<NT>
const &event) {
253 static_assert(std::is_same_v<
typename NT::datapoint_type,
254 typename NumericTraits::datapoint_type>);
255 auto bin = std::invoke(bin_mapper, event.value);
257 downstream.handle(bin_increment_event<NumericTraits>{bin.value()});
261 template <
typename NT>
void handle(datapoint_event<NT> &&event) {
262 handle(
static_cast<datapoint_event<NT>
const &
>(event));
265 template <
typename OtherEvent>
266 requires handler_for<Downstream, std::remove_cvref_t<OtherEvent>>
267 void handle(OtherEvent &&event) {
268 downstream.handle(std::forward<OtherEvent>(event));
271 void flush() { downstream.flush(); }
309 return internal::map_to_bins<NumericTraits, BinMapper, Downstream>(
310 std::move(bin_mapper), std::move(downstream));
338template <
unsigned NDataBits,
unsigned NHistoBits,
bool Flip =
false,
339 typename NumericTraits = default_numeric_traits>
343 static_assert(NHistoBits <= 64);
344 static_assert(NDataBits >= NHistoBits);
345 static_assert(NDataBits <=
346 8 *
sizeof(
typename NumericTraits::datapoint_type));
347 static_assert(NHistoBits <=
348 8 *
sizeof(
typename NumericTraits::bin_index_type));
350 static_assert(std::is_unsigned_v<typename NumericTraits::bin_index_type> ||
352 8 *
sizeof(
typename NumericTraits::bin_index_type));
355 [[nodiscard]]
auto n_bins() const -> std::
size_t {
356 return std::size_t{1} << NHistoBits;
360 auto operator()(NumericTraits::datapoint_type datapoint)
const
361 -> std::optional<typename NumericTraits::bin_index_type> {
362 using datapoint_type = NumericTraits::datapoint_type;
363 using bin_index_type = NumericTraits::bin_index_type;
365 static constexpr int shift = NDataBits - NHistoBits;
366 static_assert(shift <= 8 *
sizeof(datapoint_type));
367 if constexpr (shift == 8 *
sizeof(datapoint_type))
368 return bin_index_type{0};
372 auto const shifted = internal::ensure_unsigned(datapoint >> shift);
373 static constexpr auto max_bin_index =
static_cast<bin_index_type
>(
374 NHistoBits == 64 ? std::numeric_limits<u64>::max()
375 : (
u64(1) << NHistoBits) - 1);
376 if (shifted > max_bin_index)
379 auto const bin_index =
static_cast<bin_index_type
>(shifted);
381 return static_cast<bin_index_type
>(max_bin_index - bin_index);
395template <
typename NumericTraits = default_numeric_traits>
397 NumericTraits::datapoint_type off;
398 NumericTraits::datapoint_type bwidth;
399 NumericTraits::bin_index_type max_index;
406 static_assert(
sizeof(
typename NumericTraits::datapoint_type) <=
408 static_assert(
sizeof(
typename NumericTraits::bin_index_type) <=
436 : off(offset.value), bwidth(bin_width.value),
437 max_index(max_bin_index.value), clamp(clamp.value) {
439 throw std::invalid_argument(
440 "linear_bin_mapper bin_width must not be zero");
442 throw std::invalid_argument(
443 "linear_bin_mapper max_bin_index must not be negative");
447 [[nodiscard]]
auto n_bins() const -> std::
size_t {
448 return std::size_t(max_index) + 1;
452 auto operator()(NumericTraits::datapoint_type datapoint)
const
453 -> std::optional<typename NumericTraits::bin_index_type> {
454 using bin_index_type = NumericTraits::bin_index_type;
456 if (bwidth < 0 ? datapoint > off : datapoint < off)
457 return clamp ? std::make_optional(bin_index_type{0})
461 auto const scaled = (datapoint - off) / bwidth;
463 if (
u64(scaled) >
u64(max_index))
464 return clamp ? std::make_optional(max_index) : std::nullopt;
465 return static_cast<bin_index_type
>(scaled);
474template <
typename T>
class unique_bin_mapper_accessor {
475 std::function<std::vector<T>()> values_fn;
479 template <
typename Func>
480 explicit unique_bin_mapper_accessor(Func values_func)
481 : values_fn(values_func) {}
486 auto values() -> std::vector<T> {
return values_fn(); }
506template <
typename NumericTraits = default_numeric_traits>
508 using datapoint_type = NumericTraits::datapoint_type;
509 using bin_index_type = NumericTraits::bin_index_type;
510 bin_index_type max_index;
511 std::vector<datapoint_type> values;
528 : max_index(max_bin_index.value), trk(std::move(tracker)) {
530 throw std::invalid_argument(
531 "unique_bin_mapper max_bin_index must not be negative");
532 trk.register_accessor_factory([](
auto &tracker) {
536 [self] {
return self->values; });
541 [[nodiscard]]
auto n_bins() const -> std::
size_t {
542 return std::size_t(max_index) + 1;
547 -> std::optional<typename NumericTraits::bin_index_type> {
548 auto it = std::find(values.begin(), values.end(), datapoint);
549 if (it == values.end()) {
550 values.push_back(datapoint);
551 it = std::prev(values.end());
553 auto idx = std::distance(values.begin(), it);
554 return u64(idx) <=
u64(max_index)
555 ? std::make_optional(bin_index_type(idx))
562template <
typename StartEvent,
typename StopEvent,
typename NumericTraits,
566 processor<Downstream, bin_increment_cluster_event<NumericTraits>>);
568 bool in_cluster =
false;
569 std::vector<typename NumericTraits::bin_index_type> cur_cluster;
571 Downstream downstream;
574 explicit cluster_bin_increments(Downstream downstream)
575 : downstream(std::move(downstream)) {}
577 [[nodiscard]]
auto introspect_node() const -> processor_info {
578 return processor_info(
this,
"cluster_bin_increments");
581 [[nodiscard]]
auto introspect_graph() const -> processor_graph {
582 return downstream.introspect_graph().push_entry_point(
this);
585 template <
typename NT>
void handle(bin_increment_event<NT>
const &event) {
586 static_assert(std::is_same_v<
typename NT::bin_index_type,
587 typename NumericTraits::bin_index_type>);
589 cur_cluster.push_back(event.bin_index);
592 void handle(StartEvent
const & ) {
597 void handle(StopEvent
const & ) {
599 auto const e = bin_increment_cluster_event<NumericTraits>{
601 downstream.handle(e);
607 template <
typename NT>
void handle(bin_increment_event<NT> &&event) {
608 handle(
static_cast<bin_increment_event<NT>
const &
>(event));
612 void handle(StartEvent &&event) {
613 handle(
static_cast<StartEvent
const &
>(event));
617 void handle(StopEvent &&event) {
618 handle(
static_cast<StopEvent
const &
>(event));
621 template <
typename OtherEvent>
622 requires handler_for<Downstream, std::remove_cvref_t<OtherEvent>>
623 void handle(OtherEvent &&event) {
624 downstream.handle(std::forward<OtherEvent>(event));
627 void flush() { downstream.flush(); }
658template <
typename StartEvent,
typename StopEvent,
661 return internal::cluster_bin_increments<StartEvent, StopEvent,
662 NumericTraits, Downstream>(
663 std::move(downstream));
Tracker that mediates access to objects via a tcspc::context.
Definition context.hpp:39
Data mapper mapping channel to the data value.
Definition binning.hpp:212
auto operator()(Event const &event) const -> NumericTraits::datapoint_type
Implements data mapper requirement.
Definition binning.hpp:216
Data mapper mapping count to the data value.
Definition binning.hpp:188
auto operator()(Event const &event) const -> NumericTraits::datapoint_type
Implements data mapper requirement.
Definition binning.hpp:192
Data mapper mapping difference time to the data value.
Definition binning.hpp:164
auto operator()(Event const &event) const -> NumericTraits::datapoint_type
Implements data mapper requirement.
Definition binning.hpp:168
linear_bin_mapper(arg::offset< typename NumericTraits::datapoint_type > offset, arg::bin_width< typename NumericTraits::datapoint_type > bin_width, arg::max_bin_index< typename NumericTraits::bin_index_type > max_bin_index, arg::clamp< bool > clamp=arg::clamp{false})
Construct with parameters.
Definition binning.hpp:430
auto operator()(NumericTraits::datapoint_type datapoint) const -> std::optional< typename NumericTraits::bin_index_type >
Implements bin mapper requirement.
Definition binning.hpp:452
auto n_bins() const -> std::size_t
Implements bin mapper requirement.
Definition binning.hpp:447
Accessor for tcspc::unique_bin_mapper data.
Definition binning.hpp:474
auto values() -> std::vector< T >
Return the datapoint values assigned to bin indices.
Definition binning.hpp:486
auto operator()(NumericTraits::datapoint_type datapoint) -> std::optional< typename NumericTraits::bin_index_type >
Implements bin mapper requirement.
Definition binning.hpp:546
auto n_bins() const -> std::size_t
Implements bin mapper requirement.
Definition binning.hpp:541
unique_bin_mapper(access_tracker< unique_bin_mapper_accessor< typename NumericTraits::datapoint_type > > &&tracker, arg::max_bin_index< typename NumericTraits::bin_index_type > max_bin_index)
Construct with context and parameter.
Definition binning.hpp:522
Concept that is satisfied when T conforms to the libtcspc bin mapper interface mapping datapoints of ...
Definition binning.hpp:67
Concept that is satisfied when T conforms to the libtcspc data mapper interface for event type Event ...
Definition binning.hpp:45
Concept that is satisfied when a processor handles the given event types and flush.
Definition processor.hpp:119
Concept that is satisfied when NT provides an integral bin_index_type.
Definition numeric_traits.hpp:123
Concept that is satisfied when NT provides an integral datapoint_type.
Definition numeric_traits.hpp:114
auto ad_hoc_bucket(std::span< T > s) -> bucket< T >
Create a tcspc::bucket referencing a span.
Definition bucket.hpp:488
#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 map_to_datapoints(DataMapper mapper, Downstream downstream)
Create a processor that maps arbitrary time-tagged events to datapoint events.
Definition binning.hpp:148
auto map_to_bins(BinMapper bin_mapper, Downstream downstream)
Create a processor that maps datapoints to histogram bin indices.
Definition binning.hpp:308
auto cluster_bin_increments(Downstream downstream)
Create a processor collecting binned data into clusters.
Definition binning.hpp:660
std::uint64_t u64
Short name for uint64_t.
Definition int_types.hpp:33
libtcspc namespace.
Definition acquire.hpp:30
Function argument wrapper for bin width parameter.
Definition arg_wrappers.hpp:57
Function argument wrapper for clamp parameter.
Definition arg_wrappers.hpp:87
Function argument wrapper for maximum bin index parameter.
Definition arg_wrappers.hpp:217
Function argument wrapper for offset parameter.
Definition arg_wrappers.hpp:347
The default numeric traits.
Definition numeric_traits.hpp:27
Bin mapper that discards the least significant bits.
Definition binning.hpp:340
auto operator()(NumericTraits::datapoint_type datapoint) const -> std::optional< typename NumericTraits::bin_index_type >
Implements bin mapper requirement.
Definition binning.hpp:360
auto n_bins() const -> std::size_t
Implements bin mapper requirement.
Definition binning.hpp:355