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