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 
CountCondition(const PropertyIndex & conditionIndex,const std::function<bool (size_t)> & _countOp,const std::function<bool (T)> & _propertyOp,bool oneshot=false)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), countOp(_countOp),
51         propertyOp(_propertyOp), oneshot(oneshot)
52     {}
53 
operator ()()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()).has_value())
68                 {
69                     return false;
70                 }
71                 const auto& value =
72                     std::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