From 4af2cb62463ed9c5672d76b67f8a0c7c2c77a053 Mon Sep 17 00:00:00 2001 From: Andras Varga Date: Thu, 4 Apr 2024 12:00:40 +0200 Subject: [PATCH] common: add Traced.h --- src/inet/common/Traced.h | 148 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 src/inet/common/Traced.h diff --git a/src/inet/common/Traced.h b/src/inet/common/Traced.h new file mode 100644 index 00000000000..dfc87cf7398 --- /dev/null +++ b/src/inet/common/Traced.h @@ -0,0 +1,148 @@ +// +// Copyright (C) 2024 OpenSim Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + + +#ifndef __INET_TRACED_H +#define __INET_TRACED_H + +#include "inet/common/INETDefs.h" + +namespace inet { + +/** + * @brief A template class that wraps a variable of type T (usually an primitive type like int, + * double, enum, etc.), and monitors its value for changes. On each change, the callback function + * is called with the old and the new value. This class is particularly useful for automatic + * logging or recording of state variables in a module. + */ +template +class Traced { + private: + T value_; + std::function callback_; + + void setValue(const T& newValue) { + T oldValue = value_; + value_ = newValue; + if (callback_) + callback_(oldValue, newValue); + } + + public: + Traced() = default; + + Traced(const T& value) : value_(value) {} + + Traced(const T& value, std::function callback) : value_(value), callback_(callback) {} + + // Set callback function + void addCallback(std::function callback) { + if (!callback_) + callback_ = callback; + else + // chaining + callback_ = [=](T oldValue, T newValue) { + callback_(oldValue, newValue); + callback(oldValue, newValue); + }; + } + + // Set up to emit signal on changes + void addEmitCallback(cComponent *component, simsignal_t signal) { + auto callback = [=](T oldValue, T newValue) { + if (oldValue != newValue) + component->emit(signal, newValue); + }; + addCallback(callback); + } + + void removeCallbacks() { + callback_ = nullptr; + } + + // Overload assignment operator + Traced& operator=(const T& value) { + setValue(value); + return *this; + } + + // Overload for += operator + Traced& operator+=(const T& rhs) { + setValue(value_ + rhs); + return *this; + } + + // Overload for -= operator + Traced& operator-=(const T& rhs) { + setValue(value_ - rhs); + return *this; + } + + // Overload for *= operator + Traced& operator*=(const T& rhs) { + setValue(value_ * rhs); + return *this; + } + + // Overload for /= operator + Traced& operator/=(const T& rhs) { + setValue(value_ / rhs); + return *this; + } + + // Overload for %= operator (only for integral types) + template + typename std::enable_if::value, Traced&>::type operator%=(const T& rhs) { + setValue(value_ % rhs); + return *this; + } + + // Overload for &= operator (only for integral types) + template + typename std::enable_if::value, Traced&>::type operator&=(const T& rhs) { + setValue(value_ & rhs); + return *this; + } + + // Overload for |= operator (only for integral types) + template + typename std::enable_if::value, Traced&>::type operator|=(const T& rhs) { + setValue(value_ | rhs); + return *this; + } + + // Overload for ^= operator (only for integral types) + template + typename std::enable_if::value, Traced&>::type operator^=(const T& rhs) { + setValue(value_ ^ rhs); + return *this; + } + + // Overload for <<= operator (only for integral types) + template + typename std::enable_if::value, Traced&>::type operator<<=(const T& rhs) { + setValue(value_ << rhs); + return *this; + } + + // Overload for >>= operator (only for integral types) + template + typename std::enable_if::value, Traced&>::type operator>>=(const T& rhs) { + setValue(value_ >> rhs); + return *this; + } + + // Overload type conversion operator to allow transparent use as T + operator T() const { + return value_; + } + +}; + +} // namespace inet + +#endif +