xref: /openbmc/phosphor-dbus-monitor/src/count.hpp (revision 223c40931e4f413431ab2f84d92c5f404e2d9cf2)
1 #pragma once
2 
3 #include "callback.hpp"
4 #include "data_types.hpp"
5 
6 #include <algorithm>
7 #include <functional>
8 
9 namespace phosphor
10 {
11 namespace dbus
12 {
13 namespace monitoring
14 {
15 
16 /** @class CountCondition
17  *  @brief Count properties that satisfy a condition.
18  *
19  *  When invoked, a count class instance performs its condition
20  *  test in two passes.
21  *
22  *  In pass one, apply a C++ relational operator to the value of
23  *  each property in the index and a value provided by the
24  *  configuration file.
25  *
26  *  Count the number of properties that pass the test in pass
27  *  one.  In pass two, apply a second C++ relational operator
28  *  to the number of properties that pass the test from pass one
29  *  to a count provided by the configuration file.
30  *
31  *  If the oneshot parameter is true, then this condition won't pass
32  *  again until it fails at least once.
33  */
34 template <typename T>
35 class CountCondition : public IndexedConditional
36 {
37   public:
38     CountCondition() = delete;
39     CountCondition(const CountCondition&) = default;
40     CountCondition(CountCondition&&) = default;
41     CountCondition& operator=(const CountCondition&) = default;
42     CountCondition& operator=(CountCondition&&) = default;
43     ~CountCondition() = default;
44 
45     CountCondition(const PropertyIndex& conditionIndex,
46                    const std::function<bool(size_t)>& _countOp,
47                    const std::function<bool(T)>& _propertyOp,
48                    bool oneshot = false) :
49         IndexedConditional(conditionIndex),
50         countOp(_countOp), propertyOp(_propertyOp), oneshot(oneshot)
51     {
52     }
53 
54     bool operator()() override
55     {
56         // Count the number of properties in the index that
57         // pass the condition specified in the config file.
58         auto count = std::count_if(
59             index.cbegin(), index.cend(),
60             [this](const auto& item)
61             // *INDENT-OFF*
62             {
63                 // Get the property value from storage[0],
64                 // and save the op result in storage[1].
65                 const auto& storage = std::get<storageIndex>(item.second);
66                 // Don't count properties that don't exist.
67                 if (std::get<valueIndex>(storage.get()).empty())
68                 {
69                     return false;
70                 }
71                 const auto& value =
72                     any_ns::any_cast<T>(std::get<valueIndex>(storage.get()));
73                 auto r = propertyOp(value);
74 
75                 std::get<resultIndex>(storage.get()) = r;
76 
77                 return r;
78             });
79         // *INDENT-ON*
80 
81         // Now apply the count condition to the count.
82         auto result = countOp(count);
83 
84         // If this was a oneshot and the the condition has already
85         // passed, then don't let it pass again until the condition
86         // has gone back to false.
87         if (oneshot && result && lastResult)
88         {
89             return false;
90         }
91 
92         lastResult = result;
93         return result;
94     }
95 
96   private:
97     /** @brief The comparison to perform on the count. */
98     std::function<bool(size_t)> countOp;
99     /** @brief The comparison to perform on each property. */
100     std::function<bool(T)> propertyOp;
101     /** @brief If the condition can be allowed to pass again
102                on subsequent checks that are also true. */
103     const bool oneshot;
104     /** @brief The result of the previous check. */
105     bool lastResult = false;
106 };
107 } // namespace monitoring
108 } // namespace dbus
109 } // namespace phosphor
110