/proc/self/cwd/eval/eval/equality_steps.cc
Line | Count | Source |
1 | | // Copyright 2025 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 | | #include "eval/eval/equality_steps.h" |
15 | | |
16 | | #include <cstdint> |
17 | | #include <memory> |
18 | | #include <utility> |
19 | | |
20 | | #include "absl/status/status.h" |
21 | | #include "absl/status/statusor.h" |
22 | | #include "base/builtins.h" |
23 | | #include "common/value.h" |
24 | | #include "common/value_kind.h" |
25 | | #include "eval/eval/attribute_trail.h" |
26 | | #include "eval/eval/direct_expression_step.h" |
27 | | #include "eval/eval/evaluator_core.h" |
28 | | #include "eval/eval/expression_step_base.h" |
29 | | #include "internal/number.h" |
30 | | #include "internal/status_macros.h" |
31 | | #include "runtime/internal/errors.h" |
32 | | #include "runtime/standard/equality_functions.h" |
33 | | |
34 | | namespace google::api::expr::runtime { |
35 | | |
36 | | namespace { |
37 | | |
38 | | using ::cel::BoolValue; |
39 | | using ::cel::IntValue; |
40 | | using ::cel::MapValue; |
41 | | using ::cel::UintValue; |
42 | | using ::cel::Value; |
43 | | |
44 | | using ::cel::ValueKind; |
45 | | using ::cel::internal::Number; |
46 | | using ::cel::runtime_internal::ValueEqualImpl; |
47 | | |
48 | | absl::StatusOr<Value> EvaluateEquality( |
49 | | ExecutionFrameBase& frame, const Value& lhs, const AttributeTrail& lhs_attr, |
50 | 521k | const Value& rhs, const AttributeTrail& rhs_attr, bool negation) { |
51 | 521k | if (lhs.IsError()) { |
52 | 385k | return lhs; |
53 | 385k | } |
54 | | |
55 | 135k | if (rhs.IsError()) { |
56 | 6.59k | return rhs; |
57 | 6.59k | } |
58 | | |
59 | 128k | if (frame.unknown_processing_enabled()) { |
60 | 0 | auto accu = frame.attribute_utility().CreateAccumulator(); |
61 | 0 | accu.MaybeAdd(lhs, lhs_attr); |
62 | 0 | accu.MaybeAdd(rhs, rhs_attr); |
63 | 0 | if (!accu.IsEmpty()) { |
64 | 0 | return std::move(accu).Build(); |
65 | 0 | } |
66 | 0 | } |
67 | | |
68 | 257k | CEL_ASSIGN_OR_RETURN(auto is_equal, |
69 | 257k | ValueEqualImpl(lhs, rhs, frame.descriptor_pool(), |
70 | 257k | frame.message_factory(), frame.arena())); |
71 | 257k | if (!is_equal.has_value()) { |
72 | 0 | return cel::ErrorValue(cel::runtime_internal::CreateNoMatchingOverloadError( |
73 | 0 | negation ? cel::builtin::kInequal : cel::builtin::kEqual)); |
74 | 0 | } |
75 | 128k | return negation ? BoolValue(!*is_equal) : BoolValue(*is_equal); |
76 | 257k | } |
77 | | |
78 | | class DirectEqualityStep : public DirectExpressionStep { |
79 | | public: |
80 | | explicit DirectEqualityStep(std::unique_ptr<DirectExpressionStep> lhs, |
81 | | std::unique_ptr<DirectExpressionStep> rhs, |
82 | | bool negation, int64_t expr_id) |
83 | 0 | : DirectExpressionStep(expr_id), |
84 | 0 | lhs_(std::move(lhs)), |
85 | 0 | rhs_(std::move(rhs)), |
86 | 0 | negation_(negation) {} |
87 | | |
88 | | absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, |
89 | 0 | AttributeTrail& attribute_trail) const override { |
90 | 0 | AttributeTrail lhs_attr; |
91 | 0 | CEL_RETURN_IF_ERROR(lhs_->Evaluate(frame, result, lhs_attr)); |
92 | | |
93 | 0 | Value rhs_result; |
94 | 0 | AttributeTrail rhs_attr; |
95 | 0 | CEL_RETURN_IF_ERROR(rhs_->Evaluate(frame, rhs_result, rhs_attr)); |
96 | 0 | CEL_ASSIGN_OR_RETURN( |
97 | 0 | result, EvaluateEquality(frame, result, lhs_attr, rhs_result, rhs_attr, |
98 | 0 | negation_)); |
99 | 0 | return absl::OkStatus(); |
100 | 0 | } |
101 | | |
102 | | private: |
103 | | std::unique_ptr<DirectExpressionStep> lhs_; |
104 | | std::unique_ptr<DirectExpressionStep> rhs_; |
105 | | bool negation_; |
106 | | }; |
107 | | |
108 | | class IterativeEqualityStep : public ExpressionStepBase { |
109 | | public: |
110 | | explicit IterativeEqualityStep(bool negation, int64_t expr_id) |
111 | 8.63k | : ExpressionStepBase(expr_id), negation_(negation) {} |
112 | | |
113 | 521k | absl::Status Evaluate(ExecutionFrame* frame) const override { |
114 | 521k | if (!frame->value_stack().HasEnough(2)) { |
115 | 0 | return absl::Status(absl::StatusCode::kInternal, "Value stack underflow"); |
116 | 0 | } |
117 | 521k | auto args = frame->value_stack().GetSpan(2); |
118 | 521k | auto attrs = frame->value_stack().GetAttributeSpan(2); |
119 | | |
120 | 521k | CEL_ASSIGN_OR_RETURN(Value result, |
121 | 521k | EvaluateEquality(*frame, args[0], attrs[0], args[1], |
122 | 521k | attrs[1], negation_)); |
123 | | |
124 | 521k | frame->value_stack().PopAndPush(2, std::move(result)); |
125 | 521k | return absl::OkStatus(); |
126 | 521k | } |
127 | | |
128 | | private: |
129 | | bool negation_; |
130 | | }; |
131 | | |
132 | | absl::StatusOr<Value> EvaluateInMap(ExecutionFrameBase& frame, |
133 | | const Value& item, |
134 | 11.6k | const MapValue& container) { |
135 | 11.6k | switch (item.kind()) { |
136 | 1.13k | case ValueKind::kBool: |
137 | 1.70k | case ValueKind::kString: |
138 | 6.74k | case ValueKind::kInt: |
139 | 6.81k | case ValueKind::kUint: |
140 | 11.4k | case ValueKind::kDouble: |
141 | 11.4k | break; |
142 | 206 | default: |
143 | 206 | return cel::ErrorValue( |
144 | 206 | cel::runtime_internal::CreateNoMatchingOverloadError( |
145 | 206 | cel::builtin::kIn)); |
146 | 11.6k | } |
147 | 11.4k | Value result; |
148 | 11.4k | CEL_RETURN_IF_ERROR(container.Has(item, frame.descriptor_pool(), |
149 | 11.4k | frame.message_factory(), frame.arena(), |
150 | 11.4k | &result)); |
151 | | |
152 | 11.4k | if (result.IsTrue()) { |
153 | 697 | return result; |
154 | 697 | } |
155 | | |
156 | 10.7k | if (item.IsDouble() || item.IsUint()) { |
157 | 4.74k | Number number = item.IsDouble() |
158 | 4.74k | ? Number::FromDouble(item.GetDouble().NativeValue()) |
159 | 4.74k | : Number::FromUint64(item.GetUint().NativeValue()); |
160 | 4.74k | if (number.LosslessConvertibleToInt()) { |
161 | 878 | CEL_RETURN_IF_ERROR( |
162 | 878 | container.Has(IntValue(number.AsInt()), frame.descriptor_pool(), |
163 | 878 | frame.message_factory(), frame.arena(), &result)); |
164 | 878 | if (result.IsTrue()) { |
165 | 1 | return result; |
166 | 1 | } |
167 | 878 | } |
168 | 4.74k | } |
169 | | |
170 | 10.7k | if (item.IsDouble() || item.IsInt()) { |
171 | 9.70k | Number number = item.IsDouble() |
172 | 9.70k | ? Number::FromDouble(item.GetDouble().NativeValue()) |
173 | 9.70k | : Number::FromInt64(item.GetInt().NativeValue()); |
174 | 9.70k | if (number.LosslessConvertibleToUint()) { |
175 | 4.41k | CEL_RETURN_IF_ERROR( |
176 | 4.41k | container.Has(UintValue(number.AsUint()), frame.descriptor_pool(), |
177 | 4.41k | frame.message_factory(), frame.arena(), &result)); |
178 | 4.41k | if (result.IsTrue()) { |
179 | 1 | return result; |
180 | 1 | } |
181 | 4.41k | } |
182 | 9.70k | } |
183 | | |
184 | 10.7k | return BoolValue(false); |
185 | 10.7k | } |
186 | | |
187 | | absl::StatusOr<Value> EvaluateIn(ExecutionFrameBase& frame, const Value& item, |
188 | | const AttributeTrail& item_attr, |
189 | | const Value& container, |
190 | 216k | const AttributeTrail& container_attr) { |
191 | 216k | if (item.IsError()) { |
192 | 98.1k | return item; |
193 | 98.1k | } |
194 | 118k | if (container.IsError()) { |
195 | 1.02k | return container; |
196 | 1.02k | } |
197 | | |
198 | 117k | if (frame.unknown_processing_enabled()) { |
199 | 0 | auto accu = frame.attribute_utility().CreateAccumulator(); |
200 | 0 | accu.MaybeAdd(item, item_attr); |
201 | 0 | accu.MaybeAdd(container, container_attr); |
202 | 0 | if (!accu.IsEmpty()) { |
203 | 0 | return std::move(accu).Build(); |
204 | 0 | } |
205 | 0 | } |
206 | 117k | if (container.IsList()) { |
207 | 105k | return container.GetList().Contains(item, frame.descriptor_pool(), |
208 | 105k | frame.message_factory(), frame.arena()); |
209 | 105k | } |
210 | 12.5k | if (container.IsMap()) { |
211 | 11.6k | return EvaluateInMap(frame, item, container.GetMap()); |
212 | 11.6k | } |
213 | 869 | return cel::ErrorValue( |
214 | 869 | cel::runtime_internal::CreateNoMatchingOverloadError(cel::builtin::kIn)); |
215 | 12.5k | } |
216 | | |
217 | | class DirectInStep : public DirectExpressionStep { |
218 | | public: |
219 | | explicit DirectInStep(std::unique_ptr<DirectExpressionStep> item, |
220 | | std::unique_ptr<DirectExpressionStep> container, |
221 | | int64_t expr_id) |
222 | 0 | : DirectExpressionStep(expr_id), |
223 | 0 | item_(std::move(item)), |
224 | 0 | container_(std::move(container)) {} |
225 | | |
226 | | absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, |
227 | 0 | AttributeTrail& attribute_trail) const override { |
228 | 0 | AttributeTrail item_attr; |
229 | 0 | CEL_RETURN_IF_ERROR(item_->Evaluate(frame, result, item_attr)); |
230 | | |
231 | 0 | Value container_result; |
232 | 0 | AttributeTrail container_attr; |
233 | 0 | CEL_RETURN_IF_ERROR( |
234 | 0 | container_->Evaluate(frame, container_result, container_attr)); |
235 | 0 | CEL_ASSIGN_OR_RETURN(result, EvaluateIn(frame, result, item_attr, |
236 | 0 | container_result, container_attr)); |
237 | 0 | return absl::OkStatus(); |
238 | 0 | } |
239 | | |
240 | | private: |
241 | | std::unique_ptr<DirectExpressionStep> item_; |
242 | | std::unique_ptr<DirectExpressionStep> container_; |
243 | | }; |
244 | | |
245 | | class IterativeInStep : public ExpressionStepBase { |
246 | | public: |
247 | 3.24k | explicit IterativeInStep(int64_t expr_id) : ExpressionStepBase(expr_id) {} |
248 | | |
249 | 216k | absl::Status Evaluate(ExecutionFrame* frame) const override { |
250 | 216k | if (!frame->value_stack().HasEnough(2)) { |
251 | 0 | return absl::Status(absl::StatusCode::kInternal, "Value stack underflow"); |
252 | 0 | } |
253 | | |
254 | 216k | auto args = frame->value_stack().GetSpan(2); |
255 | 216k | auto attrs = frame->value_stack().GetAttributeSpan(2); |
256 | | |
257 | 216k | CEL_ASSIGN_OR_RETURN( |
258 | 216k | Value result, EvaluateIn(*frame, args[0], attrs[0], args[1], attrs[1])); |
259 | 216k | frame->value_stack().PopAndPush(2, std::move(result)); |
260 | 216k | return absl::OkStatus(); |
261 | 216k | } |
262 | | }; |
263 | | |
264 | | } // namespace |
265 | | |
266 | | // Factory method for recursive _==_ and _!=_ Execution step |
267 | | std::unique_ptr<DirectExpressionStep> CreateDirectEqualityStep( |
268 | | std::unique_ptr<DirectExpressionStep> lhs, |
269 | 0 | std::unique_ptr<DirectExpressionStep> rhs, bool negation, int64_t expr_id) { |
270 | 0 | return std::make_unique<DirectEqualityStep>(std::move(lhs), std::move(rhs), |
271 | 0 | negation, expr_id); |
272 | 0 | } |
273 | | |
274 | | // Factory method for iterative _==_ and _!=_ Execution step |
275 | | std::unique_ptr<ExpressionStep> CreateEqualityStep(bool negation, |
276 | 8.63k | int64_t expr_id) { |
277 | 8.63k | return std::make_unique<IterativeEqualityStep>(negation, expr_id); |
278 | 8.63k | } |
279 | | |
280 | | // Factory method for recursive @in Execution step |
281 | | std::unique_ptr<DirectExpressionStep> CreateDirectInStep( |
282 | | std::unique_ptr<DirectExpressionStep> item, |
283 | 0 | std::unique_ptr<DirectExpressionStep> container, int64_t expr_id) { |
284 | 0 | return std::make_unique<DirectInStep>(std::move(item), std::move(container), |
285 | 0 | expr_id); |
286 | 0 | } |
287 | | |
288 | | // Factory method for iterative @in Execution step |
289 | 3.24k | std::unique_ptr<ExpressionStep> CreateInStep(int64_t expr_id) { |
290 | 3.24k | return std::make_unique<IterativeInStep>(expr_id); |
291 | 3.24k | } |
292 | | |
293 | | } // namespace google::api::expr::runtime |