1 /*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "NumericValue.h"
18
19 #include <cmath>
20 #include <functional>
21 #include <limits>
22 #include <string>
23 #include <utility>
24 #include <variant>
25
26 #include "HistogramValue.h"
27
28 namespace android {
29 namespace os {
30 namespace statsd {
31 namespace {
32
33 // std::variant uses the visitor pattern to interact with stored types via std::visit, which applies
34 // a Callable (a function object) that accepts all combination of types from the variant. Here, the
35 // Callables are implemented as structs with operator() overloads for each combination of types from
36 // the variant in NumericValue.
37
38 // Templated visitor for binary operations involving two NumericValues
39 // Used for implementing operator+= and operator-= for NumericValue.
40 template <typename BinaryOp>
41 class BinaryOperationVisitor {
42 public:
BinaryOperationVisitor(BinaryOp && op)43 constexpr explicit BinaryOperationVisitor(BinaryOp&& op) : mOp(std::forward<BinaryOp>(op)) {
44 }
45
operator ()(std::monostate,std::monostate) const46 void operator()(std::monostate, std::monostate) const {
47 }
48
49 template <typename V>
operator ()(V & lhs,const V & rhs) const50 void operator()(V& lhs, const V& rhs) const {
51 lhs = mOp(lhs, rhs);
52 }
53
operator ()(auto,auto) const54 void operator()(auto, auto) const {
55 }
56
57 private:
58 const BinaryOp mOp;
59 };
60 constexpr BinaryOperationVisitor subtract(std::minus{});
61 constexpr BinaryOperationVisitor add(std::plus{});
62
63 // Visitor for printing type information currently stored in the NumericValue variant.
64 struct ToStringVisitor {
operator ()android::os::statsd::__anoned9e2b6d0111::ToStringVisitor65 std::string operator()(int64_t value) const {
66 return std::to_string(value) + "[L]";
67 }
68
operator ()android::os::statsd::__anoned9e2b6d0111::ToStringVisitor69 std::string operator()(double value) const {
70 return std::to_string(value) + "[D]";
71 }
72
operator ()android::os::statsd::__anoned9e2b6d0111::ToStringVisitor73 std::string operator()(const HistogramValue& value) const {
74 return value.toString();
75 }
76
operator ()android::os::statsd::__anoned9e2b6d0111::ToStringVisitor77 std::string operator()(auto) const {
78 return "[UNKNOWN]";
79 }
80 };
81
82 // Visitor for determining whether the NumericValue variant stores a 0.
83 struct IsZeroVisitor {
operator ()android::os::statsd::__anoned9e2b6d0111::IsZeroVisitor84 bool operator()(int64_t value) const {
85 return value == 0;
86 }
87
operator ()android::os::statsd::__anoned9e2b6d0111::IsZeroVisitor88 bool operator()(double value) const {
89 return fabs(value) <= std::numeric_limits<double>::epsilon();
90 }
91
operator ()android::os::statsd::__anoned9e2b6d0111::IsZeroVisitor92 bool operator()(const HistogramValue& value) const {
93 return value.isEmpty();
94 }
95
96 // "Empty" variant does not store 0.
operator ()android::os::statsd::__anoned9e2b6d0111::IsZeroVisitor97 bool operator()(std::monostate) const {
98 return false;
99 }
100 };
101
102 struct GetSizeVisitor {
operator ()android::os::statsd::__anoned9e2b6d0111::GetSizeVisitor103 size_t operator()(const HistogramValue& value) const {
104 return value.getSize();
105 }
106
operator ()android::os::statsd::__anoned9e2b6d0111::GetSizeVisitor107 size_t operator()(const auto& value) const {
108 return sizeof(value);
109 }
110 };
111
112 } // anonymous namespace
113
toString() const114 std::string NumericValue::toString() const {
115 return std::visit(ToStringVisitor{}, mData);
116 }
117
reset()118 void NumericValue::reset() {
119 mData.emplace<std::monostate>(std::monostate{});
120 }
121
122 template <typename V>
is() const123 bool NumericValue::is() const {
124 return std::holds_alternative<V>(mData);
125 }
126 template bool NumericValue::is<int64_t>() const;
127 template bool NumericValue::is<double>() const;
128 template bool NumericValue::is<HistogramValue>() const;
129
hasValue() const130 bool NumericValue::hasValue() const {
131 return !is<std::monostate>();
132 }
133
134 template <typename V>
getValue()135 V& NumericValue::getValue() {
136 return std::get<V>(mData);
137 }
138 template int64_t& NumericValue::getValue<int64_t>();
139 template double& NumericValue::getValue<double>();
140 template HistogramValue& NumericValue::getValue<HistogramValue>();
141
142 template <typename V>
getValue() const143 const V& NumericValue::getValue() const {
144 return std::get<V>(mData);
145 }
146 template const int64_t& NumericValue::getValue<int64_t>() const;
147 template const double& NumericValue::getValue<double>() const;
148 template const HistogramValue& NumericValue::getValue<HistogramValue>() const;
149
150 template <typename V>
getValueOrDefault(V & defaultValue)151 V& NumericValue::getValueOrDefault(V& defaultValue) {
152 return is<V>() ? getValue<V>() : defaultValue;
153 }
154 template int64_t& NumericValue::getValueOrDefault<int64_t>(int64_t& defaultValue);
155 template double& NumericValue::getValueOrDefault<double>(double& defaultValue);
156 template HistogramValue& NumericValue::getValueOrDefault<HistogramValue>(
157 HistogramValue& defaultValue);
158
159 template <typename V>
getValueOrDefault(const V & defaultValue) const160 const V& NumericValue::getValueOrDefault(const V& defaultValue) const {
161 return is<V>() ? getValue<V>() : defaultValue;
162 }
163 template const int64_t& NumericValue::getValueOrDefault<int64_t>(const int64_t& defaultValue) const;
164 template const double& NumericValue::getValueOrDefault<double>(const double& defaultValue) const;
165 template const HistogramValue& NumericValue::getValueOrDefault<HistogramValue>(
166 const HistogramValue& defaultValue) const;
167
isZero() const168 bool NumericValue::isZero() const {
169 return std::visit(IsZeroVisitor{}, mData);
170 }
171
getSize() const172 size_t NumericValue::getSize() const {
173 return std::visit(GetSizeVisitor{}, mData);
174 }
175
operator +=(const NumericValue & rhs)176 NumericValue& NumericValue::operator+=(const NumericValue& rhs) {
177 std::visit(add, mData, rhs.mData);
178 return *this;
179 }
180
operator +(NumericValue lhs,const NumericValue & rhs)181 NumericValue operator+(NumericValue lhs, const NumericValue& rhs) {
182 lhs += rhs;
183 return lhs;
184 }
185
operator -=(const NumericValue & rhs)186 NumericValue& NumericValue::operator-=(const NumericValue& rhs) {
187 std::visit(subtract, mData, rhs.mData);
188 return *this;
189 }
190
operator -(NumericValue lhs,const NumericValue & rhs)191 NumericValue operator-(NumericValue lhs, const NumericValue& rhs) {
192 lhs -= rhs;
193 return lhs;
194 }
195
operator ==(const NumericValue & lhs,const NumericValue & rhs)196 bool operator==(const NumericValue& lhs, const NumericValue& rhs) {
197 return lhs.mData == rhs.mData;
198 }
199
operator !=(const NumericValue & lhs,const NumericValue & rhs)200 bool operator!=(const NumericValue& lhs, const NumericValue& rhs) {
201 return !(lhs == rhs);
202 }
203
operator <(const NumericValue & lhs,const NumericValue & rhs)204 bool operator<(const NumericValue& lhs, const NumericValue& rhs) {
205 return lhs.mData < rhs.mData;
206 }
207
operator >(const NumericValue & lhs,const NumericValue & rhs)208 bool operator>(const NumericValue& lhs, const NumericValue& rhs) {
209 return rhs < lhs;
210 }
211
operator <=(const NumericValue & lhs,const NumericValue & rhs)212 bool operator<=(const NumericValue& lhs, const NumericValue& rhs) {
213 return !(lhs > rhs);
214 }
215
operator >=(const NumericValue & lhs,const NumericValue & rhs)216 bool operator>=(const NumericValue& lhs, const NumericValue& rhs) {
217 return !(lhs < rhs);
218 }
219
220 } // namespace statsd
221 } // namespace os
222 } // namespace android
223