| #pragma once |
| |
| #include "callback.hpp" |
| #include "data_types.hpp" |
| |
| #include <algorithm> |
| #include <functional> |
| |
| 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 <typename T> |
| 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<bool(size_t)>& _countOp, |
| const std::function<bool(T)>& _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<storageIndex>(item.second); |
| // Don't count properties that don't exist. |
| if (std::get<valueIndex>(storage.get()).empty()) |
| { |
| return false; |
| } |
| const auto& value = |
| any_ns::any_cast<T>(std::get<valueIndex>(storage.get())); |
| auto r = propertyOp(value); |
| |
| std::get<resultIndex>(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<bool(size_t)> countOp; |
| /** @brief The comparison to perform on each property. */ |
| std::function<bool(T)> 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 |