CbmRoot
Loading...
Searching...
No Matches
/tmp/builds/computing/cbmroot/core/utility/CbmStructLooper.h

Let the following class be a composite of some sub-classes, which have a common interfaces:

class A { public: void Foo() const; void Bar(); // ... Some data };

class B { public: void Foo() const; void Bar(); // ... Some data };

class C { public: void Foo() const; void Bar(); // ... Some data };

// A composite class struct Composite { std::optional fA; std::optional fB; std::optional<C> fC; }

The class StructLooper allows to apply a callable to each registered variable/value: // The composite class, updated with a static constexpr looper struct Composite { std::optional fA; std::optional fB; std::optional<C> fC;

// A for-each method, which is applied to each VARIABLE. // If the variable is std::optional<T>, the argument of the visitor is treated as std::optional<T>. template<class Visitor> void ForEach(Visitor&& visitor) { kLooper.ForEachVariable(this, std::forward<Visitor>(visitor)); }

// A for-each method, which is applied to each VARIABLE. // If the variable is std::optional<T>, the argument of the visitor is treated as std::optional<T>. template<class Visitor> void ForEach(Visitor&& visitor) const { kLooper.ForEachVariable(this, std::forward<Visitor>(visitor)); }

// A for-each method, which is applied to each VALUE. // If the variable is std::optional<T>, the argument of the visitor is treated as T. The visitor is not // applied to variables, which are std::nullopt. template<class Visitor> void ForEachValue(Visitor&& visitor) { kLooper.ForEachValue(this, std::forward<Visitor>(visitor)); }

// A for-each method, which is applied to each VALUE. // If the variable is std::optional<T>, the argument of the visitor is treated as T. The visitor is not // applied to variables, which are std::nullopt. template<class Visitor> void ForEachValue(Visitor&& visitor) const { kLooper.ForEachValue(this, std::forward<Visitor>(visitor)); }

private: static constexpr auto kLooper = cbm::util::StructLooper(&Composite::fA, &Composite::fB, &Composite::fC); };

Following are examples of using the methods ForEach and ForEachValue

void CallBar(Composite& c) { // Applies a callable to components of mutable object reference c.ForEachValue([](auto&& val) { val.Bar(); }); }

void CallFoo(const Composite& c) { // Applies a callable to components of constant object reference c.ForEachValue([](const auto& val) { val.Foo(); }); }

int CountNonNullopt(const Composite& c) { // Count objects, which are not nullopt int counter{0}; c.ForEach([&counter](const auto& var) { if (var.has_value()) ++counter; }); return counter; }

/* Copyright (C) 2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Sergei Zharko [committer] */
#ifndef CbmStructLooper_h
#define CbmStructLooper_h 1
#include "CbmTypeTraits.h"
#include <functional>
#include <optional>
#include <tuple>
namespace cbm::util
{
template<class Handler, class... Variables>
class StructLooper {
public:
constexpr StructLooper(Variables Handler::*... vars)
: fVariableTuple(std::make_tuple(std::forward<decltype(vars)>(vars)...))
{
}
template<typename HandlerPtr, class Visitor, std::enable_if_t<is_pointer_to_v<HandlerPtr, Handler>, bool> = true>
constexpr void ForEachValue(HandlerPtr handler, Visitor&& visitor) const
{
std::apply([&](auto&&... v) { ((VisitValue(handler, std::forward<Visitor>(visitor), v)), ...); }, fVariableTuple);
}
template<typename HandlerPtr, class Visitor, std::enable_if_t<is_pointer_to_v<HandlerPtr, Handler>, bool> = true>
constexpr void ForEachVariable(HandlerPtr handler, Visitor&& visitor) const
{
std::apply([&](auto&&... v) { ((std::invoke(std::forward<Visitor>(visitor), handler->*v)), ...); },
}
private:
const std::tuple<Variables Handler::*...> fVariableTuple;
template<class Visitor, class VarPtrType, typename HandlerPtr,
std::enable_if_t<is_pointer_to_v<HandlerPtr, Handler>, bool> = true>
constexpr void VisitValue(HandlerPtr handler, Visitor&& visitor, VarPtrType&& varAddr) const
{
using VarType = std::remove_const_t<std::remove_reference_t<decltype(handler->*varAddr)>>;
// TODO: add other single-value contain types
if constexpr (is_std_optional_v<VarType>) {
// Invoke a visitor, if the variable contains a value
if ((handler->*varAddr).has_value()) {
std::invoke(std::forward<Visitor>(visitor), *(handler->*varAddr));
}
}
else {
std::invoke(std::forward<Visitor>(visitor), handler->*varAddr);
}
}
};
} // namespace cbm::util
#endif // CbmStructLooper_h
Different metaprogramming utilities (type traits) for CBM experiment.
fscal v[fmask::Size]
Definition KfSimdPseudo.h:4
constexpr StructLooper(Variables Handler::*... vars)
Constructor.
constexpr void ForEachVariable(HandlerPtr handler, Visitor &&visitor) const
Applies a visitor callable to variables.
constexpr void ForEachValue(HandlerPtr handler, Visitor &&visitor) const
Applies a visitor callable to values, which are stored in registered variables.
constexpr void VisitValue(HandlerPtr handler, Visitor &&visitor, VarPtrType &&varAddr) const
A visit function for variables.
const std::tuple< Variables Handler::*... > fVariableTuple
A tuple, containing addresses of the class variables.
constexpr bool is_std_optional_v