blob: 5134b0ef8e29280c789ebdc761cc9a38da6e2de9 [file] [log] [blame]
Krzysztof Grobelny80697712021-03-04 09:49:27 +00001#include "collection_function.hpp"
2
3#include <cmath>
4
5namespace details
6{
7
Krzysztof Grobelny80697712021-03-04 09:49:27 +00008class FunctionMinimum : public CollectionFunction
9{
10 public:
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010011 double calculate(const std::vector<ReadingItem>& readings,
12 Milliseconds) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000013 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010014 return std::min_element(
15 readings.begin(), readings.end(),
16 [](const auto& left, const auto& right) {
17 return std::make_tuple(!std::isfinite(left.second),
18 left.second) <
19 std::make_tuple(!std::isfinite(right.second),
20 right.second);
21 })
22 ->second;
Krzysztof Grobelny80697712021-03-04 09:49:27 +000023 }
24
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010025 double calculateForStartupInterval(std::vector<ReadingItem>& readings,
26 Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000027 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010028 readings.assign(
29 {ReadingItem(timestamp, calculate(readings, timestamp))});
30 return readings.back().second;
Krzysztof Grobelny80697712021-03-04 09:49:27 +000031 }
32};
33
34class FunctionMaximum : public CollectionFunction
35{
36 public:
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010037 double calculate(const std::vector<ReadingItem>& readings,
38 Milliseconds) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000039 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010040 return std::max_element(
41 readings.begin(), readings.end(),
42 [](const auto& left, const auto& right) {
43 return std::make_tuple(std::isfinite(left.second),
44 left.second) <
45 std::make_tuple(std::isfinite(right.second),
46 right.second);
47 })
48 ->second;
Krzysztof Grobelny80697712021-03-04 09:49:27 +000049 }
50
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010051 double calculateForStartupInterval(std::vector<ReadingItem>& readings,
52 Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000053 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010054 readings.assign(
55 {ReadingItem(timestamp, calculate(readings, timestamp))});
56 return readings.back().second;
Krzysztof Grobelny80697712021-03-04 09:49:27 +000057 }
58};
59
60class FunctionAverage : public CollectionFunction
61{
62 public:
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010063 double calculate(const std::vector<ReadingItem>& readings,
64 Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000065 {
66 auto valueSum = 0.0;
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010067 auto timeSum = Milliseconds{0};
Krzysztof Grobelny80697712021-03-04 09:49:27 +000068 for (auto it = readings.begin(); it != std::prev(readings.end()); ++it)
69 {
70 if (std::isfinite(it->second))
71 {
72 const auto kt = std::next(it);
73 const auto duration = kt->first - it->first;
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010074 valueSum += it->second * duration.count();
Krzysztof Grobelny80697712021-03-04 09:49:27 +000075 timeSum += duration;
76 }
77 }
78
79 const auto duration = timestamp - readings.back().first;
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010080 valueSum += readings.back().second * duration.count();
Krzysztof Grobelny80697712021-03-04 09:49:27 +000081 timeSum += duration;
82
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010083 return valueSum / std::max(timeSum.count(), uint64_t{1u});
Krzysztof Grobelny80697712021-03-04 09:49:27 +000084 }
85
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010086 double calculateForStartupInterval(std::vector<ReadingItem>& readings,
87 Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000088 {
89 auto result = calculate(readings, timestamp);
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010090 if (std::isfinite(result))
Krzysztof Grobelny80697712021-03-04 09:49:27 +000091 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010092 readings.assign({ReadingItem(readings.front().first, result),
Krzysztof Grobelny80697712021-03-04 09:49:27 +000093 ReadingItem(timestamp, readings.back().second)});
94 }
95 return result;
96 }
97};
98
99class FunctionSummation : public CollectionFunction
100{
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100101 using Multiplier = std::chrono::duration<double>;
102
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000103 public:
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100104 double calculate(const std::vector<ReadingItem>& readings,
105 const Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000106 {
107 auto valueSum = 0.0;
108 for (auto it = readings.begin(); it != std::prev(readings.end()); ++it)
109 {
110 if (std::isfinite(it->second))
111 {
112 const auto kt = std::next(it);
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100113 const auto multiplier =
114 calculateMultiplier(kt->first - it->first);
115 valueSum += it->second * multiplier.count();
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000116 }
117 }
118
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100119 const auto multiplier =
120 calculateMultiplier(timestamp - readings.back().first);
121 valueSum += readings.back().second * multiplier.count();
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000122
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100123 return valueSum;
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000124 }
125
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100126 double
127 calculateForStartupInterval(std::vector<ReadingItem>& readings,
128 const Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000129 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100130 const auto result = calculate(readings, timestamp);
131 if (readings.size() > 2 && std::isfinite(result))
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000132 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100133 const auto multiplier =
134 calculateMultiplier(timestamp - readings.front().first).count();
135 if (multiplier > 0.)
136 {
137 const auto prevValue = result / multiplier;
138 readings.assign(
139 {ReadingItem(readings.front().first, prevValue),
140 ReadingItem(timestamp, readings.back().second)});
141 }
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000142 }
143 return result;
144 }
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100145
146 private:
147 static constexpr Multiplier calculateMultiplier(Milliseconds duration)
148 {
149 constexpr auto m = Multiplier{Seconds{1}};
150 return Multiplier{duration / m};
151 }
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000152};
153
154std::shared_ptr<CollectionFunction>
155 makeCollectionFunction(OperationType operationType)
156{
157 using namespace std::string_literals;
158
159 switch (operationType)
160 {
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000161 case OperationType::min:
162 return std::make_shared<FunctionMinimum>();
163 case OperationType::max:
164 return std::make_shared<FunctionMaximum>();
165 case OperationType::avg:
166 return std::make_shared<FunctionAverage>();
167 case OperationType::sum:
168 return std::make_shared<FunctionSummation>();
169 default:
170 throw std::runtime_error("op: "s +
171 utils::enumToString(operationType) +
172 " is not supported"s);
173 }
174}
175
176} // namespace details