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