Repository navigation
Expand file tree
/
Copy patharithmetic_functions.cc
More file actions
244 lines (209 loc) · 7.79 KB
/
Copy patharithmetic_functions.cc
File metadata and controls
244 lines (209 loc) · 7.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "runtime/standard/arithmetic_functions.h"
#include <cstdint>
#include <limits>
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "base/builtins.h"
#include "base/function_adapter.h"
#include "common/value.h"
#include "internal/overflow.h"
#include "internal/status_macros.h"
#include "runtime/function.h"
#include "runtime/function_registry.h"
#include "runtime/runtime_options.h"
namespace cel {
namespace {
// Template functions providing arithmetic operations
template <class Type>
Value Add(Type v0, Type v1, const Function::InvokeContext& context);
template <>
Value Add<int64_t>(int64_t v0, int64_t v1,
const Function::InvokeContext& context) {
auto sum = cel::internal::CheckedAdd(v0, v1);
if (!sum.ok()) {
return ErrorValue::From(sum.status(), context.arena());
}
return IntValue(*sum);
}
template <>
Value Add<uint64_t>(uint64_t v0, uint64_t v1,
const Function::InvokeContext& context) {
auto sum = cel::internal::CheckedAdd(v0, v1);
if (!sum.ok()) {
return ErrorValue::From(sum.status(), context.arena());
}
return UintValue(*sum);
}
template <>
Value Add<double>(double v0, double v1, const Function::InvokeContext&) {
return DoubleValue(v0 + v1);
}
template <class Type>
Value Sub(Type v0, Type v1, const Function::InvokeContext& context);
template <>
Value Sub<int64_t>(int64_t v0, int64_t v1,
const Function::InvokeContext& context) {
auto diff = cel::internal::CheckedSub(v0, v1);
if (!diff.ok()) {
return ErrorValue::From(diff.status(), context.arena());
}
return IntValue(*diff);
}
template <>
Value Sub<uint64_t>(uint64_t v0, uint64_t v1,
const Function::InvokeContext& context) {
auto diff = cel::internal::CheckedSub(v0, v1);
if (!diff.ok()) {
return ErrorValue::From(diff.status(), context.arena());
}
return UintValue(*diff);
}
template <>
Value Sub<double>(double v0, double v1, const Function::InvokeContext&) {
return DoubleValue(v0 - v1);
}
template <class Type>
Value Mul(Type v0, Type v1, const Function::InvokeContext& context);
template <>
Value Mul<int64_t>(int64_t v0, int64_t v1,
const Function::InvokeContext& context) {
auto prod = cel::internal::CheckedMul(v0, v1);
if (!prod.ok()) {
return ErrorValue::From(prod.status(), context.arena());
}
return IntValue(*prod);
}
template <>
Value Mul<uint64_t>(uint64_t v0, uint64_t v1,
const Function::InvokeContext& context) {
auto prod = cel::internal::CheckedMul(v0, v1);
if (!prod.ok()) {
return ErrorValue::From(prod.status(), context.arena());
}
return UintValue(*prod);
}
template <>
Value Mul<double>(double v0, double v1, const Function::InvokeContext&) {
return DoubleValue(v0 * v1);
}
template <class Type>
Value Div(Type v0, Type v1, const Function::InvokeContext& context);
// Division operations for integer types should check for
// division by 0
template <>
Value Div<int64_t>(int64_t v0, int64_t v1,
const Function::InvokeContext& context) {
auto quot = cel::internal::CheckedDiv(v0, v1);
if (!quot.ok()) {
return ErrorValue::From(quot.status(), context.arena());
}
return IntValue(*quot);
}
// Division operations for integer types should check for
// division by 0
template <>
Value Div<uint64_t>(uint64_t v0, uint64_t v1,
const Function::InvokeContext& context) {
auto quot = cel::internal::CheckedDiv(v0, v1);
if (!quot.ok()) {
return ErrorValue::From(quot.status(), context.arena());
}
return UintValue(*quot);
}
template <>
Value Div<double>(double v0, double v1, const Function::InvokeContext&) {
static_assert(std::numeric_limits<double>::is_iec559,
"Division by zero for doubles must be supported");
// For double, division will result in +/- inf
return DoubleValue(v0 / v1);
}
// Modulo operation
template <class Type>
Value Modulo(Type v0, Type v1, const Function::InvokeContext& context);
// Modulo operations for integer types should check for
// division by 0
template <>
Value Modulo<int64_t>(int64_t v0, int64_t v1,
const Function::InvokeContext& context) {
auto mod = cel::internal::CheckedMod(v0, v1);
if (!mod.ok()) {
return ErrorValue::From(mod.status(), context.arena());
}
return IntValue(*mod);
}
template <>
Value Modulo<uint64_t>(uint64_t v0, uint64_t v1,
const Function::InvokeContext& context) {
auto mod = cel::internal::CheckedMod(v0, v1);
if (!mod.ok()) {
return ErrorValue::From(mod.status(), context.arena());
}
return UintValue(*mod);
}
// Helper method
// Registers all arithmetic functions for template parameter type.
template <class Type>
absl::Status RegisterArithmeticFunctionsForType(FunctionRegistry& registry) {
using FunctionAdapter = cel::BinaryFunctionAdapter<Value, Type, Type>;
CEL_RETURN_IF_ERROR(registry.Register(
FunctionAdapter::CreateDescriptor(cel::builtin::kAdd, false),
FunctionAdapter::WrapFunction(&Add<Type>)));
CEL_RETURN_IF_ERROR(registry.Register(
FunctionAdapter::CreateDescriptor(cel::builtin::kSubtract, false),
FunctionAdapter::WrapFunction(&Sub<Type>)));
CEL_RETURN_IF_ERROR(registry.Register(
FunctionAdapter::CreateDescriptor(cel::builtin::kMultiply, false),
FunctionAdapter::WrapFunction(&Mul<Type>)));
return registry.Register(
FunctionAdapter::CreateDescriptor(cel::builtin::kDivide, false),
FunctionAdapter::WrapFunction(&Div<Type>));
}
} // namespace
absl::Status RegisterArithmeticFunctions(FunctionRegistry& registry,
const RuntimeOptions& options) {
CEL_RETURN_IF_ERROR(RegisterArithmeticFunctionsForType<int64_t>(registry));
CEL_RETURN_IF_ERROR(RegisterArithmeticFunctionsForType<uint64_t>(registry));
CEL_RETURN_IF_ERROR(RegisterArithmeticFunctionsForType<double>(registry));
// Modulo
CEL_RETURN_IF_ERROR(registry.Register(
BinaryFunctionAdapter<Value, int64_t, int64_t>::CreateDescriptor(
cel::builtin::kModulo, false),
BinaryFunctionAdapter<Value, int64_t, int64_t>::WrapFunction(
&Modulo<int64_t>)));
CEL_RETURN_IF_ERROR(registry.Register(
BinaryFunctionAdapter<Value, uint64_t, uint64_t>::CreateDescriptor(
cel::builtin::kModulo, false),
BinaryFunctionAdapter<Value, uint64_t, uint64_t>::WrapFunction(
&Modulo<uint64_t>)));
// Negation group
CEL_RETURN_IF_ERROR(registry.Register(
UnaryFunctionAdapter<Value, int64_t>::CreateDescriptor(cel::builtin::kNeg,
false),
UnaryFunctionAdapter<Value, int64_t>::WrapFunction(
[](int64_t value, const Function::InvokeContext& context) -> Value {
auto inv = cel::internal::CheckedNegation(value);
if (!inv.ok()) {
return ErrorValue::From(inv.status(), context.arena());
}
return IntValue(*inv);
})));
return registry.Register(
UnaryFunctionAdapter<double, double>::CreateDescriptor(cel::builtin::kNeg,
false),
UnaryFunctionAdapter<double, double>::WrapFunction(
[](double value) -> double { return -value; }));
}
} // namespace cel