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(
46             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),
52             propertyOp(_propertyOp),
53             oneshot(oneshot) {}
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(),
61                              index.cend(),
62                              [this](const auto & item)
63             // *INDENT-OFF*
64                              {
65                                  //Get the property value from storage[0],
66                                  //and save the op result in storage[1].
67                                  const auto& storage = std::get<2>(
68                                      item.second);
69                                  // Don't count properties that don't exist.
70                                  if (std::get<0>(storage.get()).empty())
71                                  {
72                                      return false;
73                                  }
74                                  const auto& value = any_ns::any_cast<T>(
75                                      std::get<0>(storage.get()));
76                                  auto r = propertyOp(value);
77 
78                                  std::get<1>(storage.get()) = r;
79 
80                                  return r;
81                              });
82             // *INDENT-ON*
83 
84             // Now apply the count condition to the count.
85             auto result = countOp(count);
86 
87             // If this was a oneshot and the the condition has already
88             // passed, then don't let it pass again until the condition
89             // has gone back to false.
90             if (oneshot && result && lastResult)
91             {
92                 return false;
93             }
94 
95             lastResult = result;
96             return result;
97         }
98 
99     private:
100         /** @brief The comparison to perform on the count. */
101         std::function<bool(size_t)> countOp;
102         /** @brief The comparison to perform on each property. */
103         std::function<bool(T)> propertyOp;
104         /** @brief If the condition can be allowed to pass again
105                    on subsequent checks that are also true. */
106         const bool oneshot;
107         /** @brief The result of the previous check. */
108         bool lastResult = false;
109 };
110 } // namespace monitoring
111 } // namespace dbus
112 } // namespace phosphor
113