Coverage Report

Created: 2026-09-03 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/internal/number.h
Line
Count
Source
1
// Copyright 2022 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#ifndef THIRD_PARTY_CEL_CPP_INTERNAL_NUMBER_H_
16
#define THIRD_PARTY_CEL_CPP_INTERNAL_NUMBER_H_
17
18
#include <cstdint>
19
#include <limits>
20
21
#include "absl/types/variant.h"
22
23
namespace cel::internal {
24
25
constexpr int64_t kInt64Max = std::numeric_limits<int64_t>::max();
26
constexpr int64_t kInt64Min = std::numeric_limits<int64_t>::lowest();
27
constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
28
constexpr uint64_t kUintToIntMax = static_cast<uint64_t>(kInt64Max);
29
constexpr double kDoubleToIntMax = static_cast<double>(kInt64Max);
30
constexpr double kDoubleToIntMin = static_cast<double>(kInt64Min);
31
constexpr double kDoubleToUintMax = static_cast<double>(kUint64Max);
32
33
// The highest integer values that are round-trippable after rounding and
34
// casting to double.
35
template <typename T>
36
0
constexpr int RoundingError() {
37
0
  return 1 << (std::numeric_limits<T>::digits -
38
0
               std::numeric_limits<double>::digits - 1);
39
0
}
Unexecuted instantiation: int cel::internal::RoundingError<long>()
Unexecuted instantiation: int cel::internal::RoundingError<unsigned long>()
40
41
constexpr double kMaxDoubleRepresentableAsInt =
42
    static_cast<double>(kInt64Max - RoundingError<int64_t>());
43
constexpr double kMaxDoubleRepresentableAsUint =
44
    static_cast<double>(kUint64Max - RoundingError<uint64_t>());
45
46
#define CEL_ABSL_VISIT_CONSTEXPR
47
48
using NumberVariant = absl::variant<double, uint64_t, int64_t>;
49
50
enum class ComparisonResult {
51
  kLesser,
52
  kEqual,
53
  kGreater,
54
  // Special case for nan.
55
  kNanInequal
56
};
57
58
// Return the inverse relation (i.e. Invert(cmp(b, a)) is the same as cmp(a, b).
59
124k
constexpr ComparisonResult Invert(ComparisonResult result) {
60
124k
  switch (result) {
61
76.9k
    case ComparisonResult::kLesser:
62
76.9k
      return ComparisonResult::kGreater;
63
36.2k
    case ComparisonResult::kGreater:
64
36.2k
      return ComparisonResult::kLesser;
65
2.53k
    case ComparisonResult::kEqual:
66
2.53k
      return ComparisonResult::kEqual;
67
8.44k
    case ComparisonResult::kNanInequal:
68
8.44k
      return ComparisonResult::kNanInequal;
69
124k
  }
70
124k
}
71
72
template <typename OutType>
73
struct ConversionVisitor {
74
  template <typename InType>
75
489k
  constexpr OutType operator()(InType v) {
76
489k
    return static_cast<OutType>(v);
77
489k
  }
long cel::internal::ConversionVisitor<long>::operator()<double>(double)
Line
Count
Source
75
13.7k
  constexpr OutType operator()(InType v) {
76
13.7k
    return static_cast<OutType>(v);
77
13.7k
  }
long cel::internal::ConversionVisitor<long>::operator()<unsigned long>(unsigned long)
Line
Count
Source
75
19.9k
  constexpr OutType operator()(InType v) {
76
19.9k
    return static_cast<OutType>(v);
77
19.9k
  }
long cel::internal::ConversionVisitor<long>::operator()<long>(long)
Line
Count
Source
75
249k
  constexpr OutType operator()(InType v) {
76
249k
    return static_cast<OutType>(v);
77
249k
  }
unsigned long cel::internal::ConversionVisitor<unsigned long>::operator()<double>(double)
Line
Count
Source
75
2.67k
  constexpr OutType operator()(InType v) {
76
2.67k
    return static_cast<OutType>(v);
77
2.67k
  }
unsigned long cel::internal::ConversionVisitor<unsigned long>::operator()<unsigned long>(unsigned long)
Line
Count
Source
75
18.5k
  constexpr OutType operator()(InType v) {
76
18.5k
    return static_cast<OutType>(v);
77
18.5k
  }
unsigned long cel::internal::ConversionVisitor<unsigned long>::operator()<long>(long)
Line
Count
Source
75
184k
  constexpr OutType operator()(InType v) {
76
184k
    return static_cast<OutType>(v);
77
184k
  }
Unexecuted instantiation: double cel::internal::ConversionVisitor<double>::operator()<double>(double)
Unexecuted instantiation: double cel::internal::ConversionVisitor<double>::operator()<unsigned long>(unsigned long)
Unexecuted instantiation: double cel::internal::ConversionVisitor<double>::operator()<long>(long)
78
};
79
80
template <typename T>
81
73.3k
constexpr ComparisonResult Compare(T a, T b) {
82
73.3k
  return (a > b)    ? ComparisonResult::kGreater
83
73.3k
         : (a == b) ? ComparisonResult::kEqual
84
25.6k
                    : ComparisonResult::kLesser;
85
73.3k
}
cel::internal::ComparisonResult cel::internal::Compare<double>(double, double)
Line
Count
Source
81
58.3k
constexpr ComparisonResult Compare(T a, T b) {
82
58.3k
  return (a > b)    ? ComparisonResult::kGreater
83
58.3k
         : (a == b) ? ComparisonResult::kEqual
84
18.7k
                    : ComparisonResult::kLesser;
85
58.3k
}
cel::internal::ComparisonResult cel::internal::Compare<unsigned long>(unsigned long, unsigned long)
Line
Count
Source
81
14.9k
constexpr ComparisonResult Compare(T a, T b) {
82
14.9k
  return (a > b)    ? ComparisonResult::kGreater
83
14.9k
         : (a == b) ? ComparisonResult::kEqual
84
6.85k
                    : ComparisonResult::kLesser;
85
14.9k
}
Unexecuted instantiation: cel::internal::ComparisonResult cel::internal::Compare<long>(long, long)
86
87
72.8k
constexpr ComparisonResult DoubleCompare(double a, double b) {
88
  // constexpr friendly isnan check.
89
72.8k
  if (!(a == a) || !(b == b)) {
90
14.4k
    return ComparisonResult::kNanInequal;
91
14.4k
  }
92
58.3k
  return Compare(a, b);
93
72.8k
}
94
95
// Implement generic numeric comparison against double value.
96
struct DoubleCompareVisitor {
97
162k
  constexpr explicit DoubleCompareVisitor(double v) : v(v) {}
98
99
0
  constexpr ComparisonResult operator()(double other) const {
100
0
    return DoubleCompare(v, other);
101
0
  }
102
103
83.7k
  constexpr ComparisonResult operator()(uint64_t other) const {
104
83.7k
    if (v > kDoubleToUintMax) {
105
3.34k
      return ComparisonResult::kGreater;
106
80.4k
    } else if (v < 0) {
107
32.2k
      return ComparisonResult::kLesser;
108
48.1k
    } else {
109
48.1k
      return DoubleCompare(v, static_cast<double>(other));
110
48.1k
    }
111
83.7k
  }
112
113
78.4k
  constexpr ComparisonResult operator()(int64_t other) const {
114
78.4k
    if (v > kDoubleToIntMax) {
115
12.6k
      return ComparisonResult::kGreater;
116
65.7k
    } else if (v < kDoubleToIntMin) {
117
41.1k
      return ComparisonResult::kLesser;
118
41.1k
    } else {
119
24.6k
      return DoubleCompare(v, static_cast<double>(other));
120
24.6k
    }
121
78.4k
  }
122
  double v;
123
};
124
125
// Implement generic numeric comparison against uint value.
126
// Delegates to double comparison if either variable is double.
127
struct UintCompareVisitor {
128
80.4k
  constexpr explicit UintCompareVisitor(uint64_t v) : v(v) {}
129
130
53.2k
  constexpr ComparisonResult operator()(double other) const {
131
53.2k
    return Invert(DoubleCompareVisitor(other)(v));
132
53.2k
  }
133
134
0
  constexpr ComparisonResult operator()(uint64_t other) const {
135
0
    return Compare(v, other);
136
0
  }
137
138
27.2k
  constexpr ComparisonResult operator()(int64_t other) const {
139
27.2k
    if (v > kUintToIntMax || other < 0) {
140
12.2k
      return ComparisonResult::kGreater;
141
14.9k
    } else {
142
14.9k
      return Compare(v, static_cast<uint64_t>(other));
143
14.9k
    }
144
27.2k
  }
145
  uint64_t v;
146
};
147
148
// Implement generic numeric comparison against int value.
149
// Delegates to uint / double if either value is uint / double.
150
struct IntCompareVisitor {
151
70.8k
  constexpr explicit IntCompareVisitor(int64_t v) : v(v) {}
152
153
57.3k
  constexpr ComparisonResult operator()(double other) {
154
57.3k
    return Invert(DoubleCompareVisitor(other)(v));
155
57.3k
  }
156
157
13.5k
  constexpr ComparisonResult operator()(uint64_t other) {
158
13.5k
    return Invert(UintCompareVisitor(other)(v));
159
13.5k
  }
160
161
0
  constexpr ComparisonResult operator()(int64_t other) {
162
0
    return Compare(v, other);
163
0
  }
164
  int64_t v;
165
};
166
167
struct CompareVisitor {
168
189k
  explicit constexpr CompareVisitor(NumberVariant rhs) : rhs(rhs) {}
169
170
51.6k
  CEL_ABSL_VISIT_CONSTEXPR ComparisonResult operator()(double v) {
171
51.6k
    return absl::visit(DoubleCompareVisitor(v), rhs);
172
51.6k
  }
173
174
66.9k
  CEL_ABSL_VISIT_CONSTEXPR ComparisonResult operator()(uint64_t v) {
175
66.9k
    return absl::visit(UintCompareVisitor(v), rhs);
176
66.9k
  }
177
178
70.8k
  CEL_ABSL_VISIT_CONSTEXPR ComparisonResult operator()(int64_t v) {
179
70.8k
    return absl::visit(IntCompareVisitor(v), rhs);
180
70.8k
  }
181
  NumberVariant rhs;
182
};
183
184
struct LosslessConvertibleToIntVisitor {
185
51.8k
  constexpr bool operator()(double value) const {
186
51.8k
    return value >= kDoubleToIntMin && value <= kMaxDoubleRepresentableAsInt &&
187
49.5k
           value == static_cast<double>(static_cast<int64_t>(value));
188
51.8k
  }
189
21.4k
  constexpr bool operator()(uint64_t value) const {
190
21.4k
    return value <= kUintToIntMax;
191
21.4k
  }
192
249k
  constexpr bool operator()(int64_t value) const { return true; }
193
};
194
195
struct LosslessConvertibleToUintVisitor {
196
40.8k
  constexpr bool operator()(double value) const {
197
40.8k
    return value >= 0 && value <= kMaxDoubleRepresentableAsUint &&
198
37.5k
           value == static_cast<double>(static_cast<uint64_t>(value));
199
40.8k
  }
200
18.5k
  constexpr bool operator()(uint64_t value) const { return true; }
201
185k
  constexpr bool operator()(int64_t value) const { return value >= 0; }
202
};
203
204
// Utility class for CEL number operations.
205
//
206
// In CEL expressions, comparisons between different numeric types are treated
207
// as all happening on the same continuous number line. This generally means
208
// that integers and doubles in convertible range are compared after converting
209
// to doubles (tolerating some loss of precision).
210
//
211
// This extends to key lookups -- {1: 'abc'}[1.0f] is expected to work since
212
// 1.0 == 1 in CEL.
213
class Number {
214
 public:
215
  // Factories to resolve ambiguous overload resolution against literals.
216
366k
  static constexpr Number FromInt64(int64_t value) { return Number(value); }
217
77.6k
  static constexpr Number FromUint64(uint64_t value) { return Number(value); }
218
144k
  static constexpr Number FromDouble(double value) { return Number(value); }
219
220
215k
  constexpr explicit Number(double double_value) : value_(double_value) {}
221
420k
  constexpr explicit Number(int64_t int_value) : value_(int_value) {}
222
132k
  constexpr explicit Number(uint64_t uint_value) : value_(uint_value) {}
223
224
  // Return a double representation of the value.
225
0
  CEL_ABSL_VISIT_CONSTEXPR double AsDouble() const {
226
0
    return absl::visit(internal::ConversionVisitor<double>(), value_);
227
0
  }
228
229
  // Return signed int64 representation for the value.
230
  // Caller must guarantee the underlying value is representatble as an
231
  // int.
232
283k
  CEL_ABSL_VISIT_CONSTEXPR int64_t AsInt() const {
233
283k
    return absl::visit(internal::ConversionVisitor<int64_t>(), value_);
234
283k
  }
235
236
  // Return unsigned int64 representation for the value.
237
  // Caller must guarantee the underlying value is representable as an
238
  // uint.
239
206k
  CEL_ABSL_VISIT_CONSTEXPR uint64_t AsUint() const {
240
206k
    return absl::visit(internal::ConversionVisitor<uint64_t>(), value_);
241
206k
  }
242
243
  // For key lookups, check if the conversion to signed int is lossless.
244
322k
  CEL_ABSL_VISIT_CONSTEXPR bool LosslessConvertibleToInt() const {
245
322k
    return absl::visit(internal::LosslessConvertibleToIntVisitor(), value_);
246
322k
  }
247
248
  // For key lookups, check if the conversion to unsigned int is lossless.
249
245k
  CEL_ABSL_VISIT_CONSTEXPR bool LosslessConvertibleToUint() const {
250
245k
    return absl::visit(internal::LosslessConvertibleToUintVisitor(), value_);
251
245k
  }
252
253
39.0k
  CEL_ABSL_VISIT_CONSTEXPR bool operator<(Number other) const {
254
39.0k
    return Compare(other) == internal::ComparisonResult::kLesser;
255
39.0k
  }
256
257
10.4k
  CEL_ABSL_VISIT_CONSTEXPR bool operator<=(Number other) const {
258
10.4k
    internal::ComparisonResult cmp = Compare(other);
259
10.4k
    return cmp != internal::ComparisonResult::kGreater &&
260
6.24k
           cmp != internal::ComparisonResult::kNanInequal;
261
10.4k
  }
262
263
17.1k
  CEL_ABSL_VISIT_CONSTEXPR bool operator>(Number other) const {
264
17.1k
    return Compare(other) == internal::ComparisonResult::kGreater;
265
17.1k
  }
266
267
23.8k
  CEL_ABSL_VISIT_CONSTEXPR bool operator>=(Number other) const {
268
23.8k
    internal::ComparisonResult cmp = Compare(other);
269
23.8k
    return cmp != internal::ComparisonResult::kLesser &&
270
13.9k
           cmp != internal::ComparisonResult::kNanInequal;
271
23.8k
  }
272
273
99.0k
  CEL_ABSL_VISIT_CONSTEXPR bool operator==(Number other) const {
274
99.0k
    return Compare(other) == internal::ComparisonResult::kEqual;
275
99.0k
  }
276
277
0
  CEL_ABSL_VISIT_CONSTEXPR bool operator!=(Number other) const {
278
0
    return Compare(other) != internal::ComparisonResult::kEqual;
279
0
  }
280
281
  // Visit the underlying number representation, a variant of double, uint64_t,
282
  // or int64_t.
283
  template <typename T, typename Op>
284
  T visit(Op&& op) const {
285
    return absl::visit(std::forward<Op>(op), value_);
286
  }
287
288
 private:
289
  internal::NumberVariant value_;
290
291
  CEL_ABSL_VISIT_CONSTEXPR internal::ComparisonResult Compare(
292
189k
      Number other) const {
293
189k
    return absl::visit(internal::CompareVisitor(other.value_), value_);
294
189k
  }
295
};
296
297
}  // namespace cel::internal
298
299
#endif  // THIRD_PARTY_CEL_CPP_INTERNAL_NUMBER_H_