xref: /openbmc/phosphor-dbus-monitor/src/count.hpp (revision d1eac88d18ae7dd11033dba87b6aebb220da9064)
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> class CountCondition : public IndexedConditional
35 {
36   public:
37     CountCondition() = delete;
38     CountCondition(const CountCondition&) = default;
39     CountCondition(CountCondition&&) = default;
40     CountCondition& operator=(const CountCondition&) = default;
41     CountCondition& operator=(CountCondition&&) = default;
42     ~CountCondition() = default;
43 
44     CountCondition(const PropertyIndex& conditionIndex,
45                    const std::function<bool(size_t)>& _countOp,
46                    const std::function<bool(T)>& _propertyOp,
47                    bool oneshot = false) :
48         IndexedConditional(conditionIndex),
49         countOp(_countOp), propertyOp(_propertyOp), oneshot(oneshot)
50     {
51     }
52 
53     bool operator()() override
54     {
55         // Count the number of properties in the index that
56         // pass the condition specified in the config file.
57         auto count = std::count_if(
58             index.cbegin(), index.cend(),
59             [this](const auto& item)
60             // *INDENT-OFF*
61             {
62                 // Get the property value from storage[0],
63                 // and save the op result in storage[1].
64                 const auto& storage = std::get<storageIndex>(item.second);
65                 // Don't count properties that don't exist.
66                 if (std::get<valueIndex>(storage.get()).empty())
67                 {
68                     return false;
69                 }
70                 const auto& value =
71                     any_ns::any_cast<T>(std::get<valueIndex>(storage.get()));
72                 auto r = propertyOp(value);
73 
74                 std::get<resultIndex>(storage.get()) = r;
75 
76                 return r;
77             });
78         // *INDENT-ON*
79 
80         // Now apply the count condition to the count.
81         auto result = countOp(count);
82 
83         // If this was a oneshot and the the condition has already
84         // passed, then don't let it pass again until the condition
85         // has gone back to false.
86         if (oneshot && result && lastResult)
87         {
88             return false;
89         }
90 
91         lastResult = result;
92         return result;
93     }
94 
95   private:
96     /** @brief The comparison to perform on the count. */
97     std::function<bool(size_t)> countOp;
98     /** @brief The comparison to perform on each property. */
99     std::function<bool(T)> propertyOp;
100     /** @brief If the condition can be allowed to pass again
101                on subsequent checks that are also true. */
102     const bool oneshot;
103     /** @brief The result of the previous check. */
104     bool lastResult = false;
105 };
106 } // namespace monitoring
107 } // namespace dbus
108 } // namespace phosphor
109