blob: 360f0828178f4daf31be6717ef2f28b8135eb229 [file] [log] [blame]
Krzysztof Grobelny80697712021-03-04 09:49:27 +00001#include "collection_function.hpp"
2
3#include <cmath>
4
5namespace details
6{
7
8class FunctionSingle : 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 readings.back().second;
Krzysztof Grobelny80697712021-03-04 09:49:27 +000015 }
16
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010017 double calculateForStartupInterval(std::vector<ReadingItem>& readings,
18 Milliseconds) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000019 {
20 readings.assign({readings.back()});
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010021 return readings.back().second;
Krzysztof Grobelny80697712021-03-04 09:49:27 +000022 }
23};
24
25class FunctionMinimum : public CollectionFunction
26{
27 public:
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010028 double calculate(const std::vector<ReadingItem>& readings,
29 Milliseconds) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000030 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010031 return std::min_element(
32 readings.begin(), readings.end(),
33 [](const auto& left, const auto& right) {
34 return std::make_tuple(!std::isfinite(left.second),
35 left.second) <
36 std::make_tuple(!std::isfinite(right.second),
37 right.second);
38 })
39 ->second;
Krzysztof Grobelny80697712021-03-04 09:49:27 +000040 }
41
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010042 double calculateForStartupInterval(std::vector<ReadingItem>& readings,
43 Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000044 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010045 readings.assign(
46 {ReadingItem(timestamp, calculate(readings, timestamp))});
47 return readings.back().second;
Krzysztof Grobelny80697712021-03-04 09:49:27 +000048 }
49};
50
51class FunctionMaximum : public CollectionFunction
52{
53 public:
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010054 double calculate(const std::vector<ReadingItem>& readings,
55 Milliseconds) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000056 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010057 return std::max_element(
58 readings.begin(), readings.end(),
59 [](const auto& left, const auto& right) {
60 return std::make_tuple(std::isfinite(left.second),
61 left.second) <
62 std::make_tuple(std::isfinite(right.second),
63 right.second);
64 })
65 ->second;
Krzysztof Grobelny80697712021-03-04 09:49:27 +000066 }
67
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010068 double calculateForStartupInterval(std::vector<ReadingItem>& readings,
69 Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000070 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010071 readings.assign(
72 {ReadingItem(timestamp, calculate(readings, timestamp))});
73 return readings.back().second;
Krzysztof Grobelny80697712021-03-04 09:49:27 +000074 }
75};
76
77class FunctionAverage : public CollectionFunction
78{
79 public:
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010080 double calculate(const std::vector<ReadingItem>& readings,
81 Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +000082 {
83 auto valueSum = 0.0;
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010084 auto timeSum = Milliseconds{0};
Krzysztof Grobelny80697712021-03-04 09:49:27 +000085 for (auto it = readings.begin(); it != std::prev(readings.end()); ++it)
86 {
87 if (std::isfinite(it->second))
88 {
89 const auto kt = std::next(it);
90 const auto duration = kt->first - it->first;
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010091 valueSum += it->second * duration.count();
Krzysztof Grobelny80697712021-03-04 09:49:27 +000092 timeSum += duration;
93 }
94 }
95
96 const auto duration = timestamp - readings.back().first;
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010097 valueSum += readings.back().second * duration.count();
Krzysztof Grobelny80697712021-03-04 09:49:27 +000098 timeSum += duration;
99
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100100 return valueSum / std::max(timeSum.count(), uint64_t{1u});
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000101 }
102
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100103 double calculateForStartupInterval(std::vector<ReadingItem>& readings,
104 Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000105 {
106 auto result = calculate(readings, timestamp);
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100107 if (std::isfinite(result))
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000108 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100109 readings.assign({ReadingItem(readings.front().first, result),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000110 ReadingItem(timestamp, readings.back().second)});
111 }
112 return result;
113 }
114};
115
116class FunctionSummation : public CollectionFunction
117{
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100118 using Multiplier = std::chrono::duration<double>;
119
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000120 public:
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100121 double calculate(const std::vector<ReadingItem>& readings,
122 const Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000123 {
124 auto valueSum = 0.0;
125 for (auto it = readings.begin(); it != std::prev(readings.end()); ++it)
126 {
127 if (std::isfinite(it->second))
128 {
129 const auto kt = std::next(it);
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100130 const auto multiplier =
131 calculateMultiplier(kt->first - it->first);
132 valueSum += it->second * multiplier.count();
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000133 }
134 }
135
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100136 const auto multiplier =
137 calculateMultiplier(timestamp - readings.back().first);
138 valueSum += readings.back().second * multiplier.count();
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000139
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100140 return valueSum;
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000141 }
142
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100143 double
144 calculateForStartupInterval(std::vector<ReadingItem>& readings,
145 const Milliseconds timestamp) const override
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000146 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100147 const auto result = calculate(readings, timestamp);
148 if (readings.size() > 2 && std::isfinite(result))
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000149 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100150 const auto multiplier =
151 calculateMultiplier(timestamp - readings.front().first).count();
152 if (multiplier > 0.)
153 {
154 const auto prevValue = result / multiplier;
155 readings.assign(
156 {ReadingItem(readings.front().first, prevValue),
157 ReadingItem(timestamp, readings.back().second)});
158 }
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000159 }
160 return result;
161 }
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100162
163 private:
164 static constexpr Multiplier calculateMultiplier(Milliseconds duration)
165 {
166 constexpr auto m = Multiplier{Seconds{1}};
167 return Multiplier{duration / m};
168 }
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000169};
170
171std::shared_ptr<CollectionFunction>
172 makeCollectionFunction(OperationType operationType)
173{
174 using namespace std::string_literals;
175
176 switch (operationType)
177 {
178 case OperationType::single:
179 return std::make_shared<FunctionSingle>();
180 case OperationType::min:
181 return std::make_shared<FunctionMinimum>();
182 case OperationType::max:
183 return std::make_shared<FunctionMaximum>();
184 case OperationType::avg:
185 return std::make_shared<FunctionAverage>();
186 case OperationType::sum:
187 return std::make_shared<FunctionSummation>();
188 default:
189 throw std::runtime_error("op: "s +
190 utils::enumToString(operationType) +
191 " is not supported"s);
192 }
193}
194
195} // namespace details