#pragma once #include "callback.hpp" #include "data_types.hpp" #include #include namespace phosphor { namespace dbus { namespace monitoring { /** @class CountCondition * @brief Count properties that satisfy a condition. * * When invoked, a count class instance performs its condition * test in two passes. * * In pass one, apply a C++ relational operator to the value of * each property in the index and a value provided by the * configuration file. * * Count the number of properties that pass the test in pass * one. In pass two, apply a second C++ relational operator * to the number of properties that pass the test from pass one * to a count provided by the configuration file. * * If the oneshot parameter is true, then this condition won't pass * again until it fails at least once. */ template class CountCondition : public IndexedConditional { public: CountCondition() = delete; CountCondition(const CountCondition&) = default; CountCondition(CountCondition&&) = default; CountCondition& operator=(const CountCondition&) = default; CountCondition& operator=(CountCondition&&) = default; ~CountCondition() = default; CountCondition(const PropertyIndex& conditionIndex, const std::function& _countOp, const std::function& _propertyOp, bool oneshot = false) : IndexedConditional(conditionIndex), countOp(_countOp), propertyOp(_propertyOp), oneshot(oneshot) { } bool operator()() override { // Count the number of properties in the index that // pass the condition specified in the config file. auto count = std::count_if( index.cbegin(), index.cend(), [this](const auto& item) // *INDENT-OFF* { // Get the property value from storage[0], // and save the op result in storage[1]. const auto& storage = std::get(item.second); // Don't count properties that don't exist. if (std::get(storage.get()).empty()) { return false; } const auto& value = any_ns::any_cast(std::get(storage.get())); auto r = propertyOp(value); std::get(storage.get()) = r; return r; }); // *INDENT-ON* // Now apply the count condition to the count. auto result = countOp(count); // If this was a oneshot and the the condition has already // passed, then don't let it pass again until the condition // has gone back to false. if (oneshot && result && lastResult) { return false; } lastResult = result; return result; } private: /** @brief The comparison to perform on the count. */ std::function countOp; /** @brief The comparison to perform on each property. */ std::function propertyOp; /** @brief If the condition can be allowed to pass again on subsequent checks that are also true. */ const bool oneshot; /** @brief The result of the previous check. */ bool lastResult = false; }; } // namespace monitoring } // namespace dbus } // namespace phosphor