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),
51         countOp(_countOp), 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(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()).has_value())
67             {
68                 return false;
69             }
70             const auto& value =
71                 std::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