iceberg-cpp
Loading...
Searching...
No Matches
expression_visitor.h
Go to the documentation of this file.
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20#pragma once
21
24
25#include <concepts>
26#include <memory>
27#include <typeinfo>
28
31#include "iceberg/expression/literal.h"
34#include "iceberg/iceberg_export.h"
35#include "iceberg/result.h"
37#include "iceberg/util/macros.h"
38
39namespace iceberg {
40
48template <typename R>
49class ICEBERG_EXPORT ExpressionVisitor {
50 using ParamType = std::conditional_t<std::is_fundamental_v<R>, R, const R&>;
51
52 public:
53 virtual ~ExpressionVisitor() = default;
54
56 virtual Result<R> AlwaysTrue() = 0;
57
59 virtual Result<R> AlwaysFalse() = 0;
60
63 virtual Result<R> Not(ParamType child_result) = 0;
64
68 virtual Result<R> And(ParamType left_result, ParamType right_result) = 0;
69
73 virtual Result<R> Or(ParamType left_result, ParamType right_result) = 0;
74
77 virtual Result<R> Predicate(const std::shared_ptr<BoundPredicate>& pred) = 0;
78
81 virtual Result<R> Predicate(const std::shared_ptr<UnboundPredicate>& pred) = 0;
82
85 virtual Result<R> Aggregate(const std::shared_ptr<BoundAggregate>& aggregate) {
86 ICEBERG_DCHECK(aggregate != nullptr, "Bound aggregate cannot be null");
87 return NotSupported("Visitor {} does not support bound aggregate",
88 typeid(*this).name());
89 }
90
93 virtual Result<R> Aggregate(const std::shared_ptr<UnboundAggregate>& aggregate) {
94 ICEBERG_DCHECK(aggregate != nullptr, "Unbound aggregate cannot be null");
95 return NotSupported("Visitor {} does not support unbound aggregate",
96 typeid(*this).name());
97 }
98};
99
105template <typename R>
106class ICEBERG_EXPORT BoundVisitor : public ExpressionVisitor<R> {
107 public:
108 ~BoundVisitor() override = default;
109
112 virtual Result<R> IsNull(const std::shared_ptr<Bound>& expr) = 0;
113
116 virtual Result<R> NotNull(const std::shared_ptr<Bound>& expr) = 0;
117
120 virtual Result<R> IsNaN(const std::shared_ptr<Bound>& expr) {
121 return NotSupported("IsNaN operation is not supported by this visitor");
122 }
123
126 virtual Result<R> NotNaN(const std::shared_ptr<Bound>& expr) {
127 return NotSupported("NotNaN operation is not supported by this visitor");
128 }
129
133 virtual Result<R> Lt(const std::shared_ptr<Bound>& expr, const Literal& lit) = 0;
134
138 virtual Result<R> LtEq(const std::shared_ptr<Bound>& expr, const Literal& lit) = 0;
139
143 virtual Result<R> Gt(const std::shared_ptr<Bound>& expr, const Literal& lit) = 0;
144
148 virtual Result<R> GtEq(const std::shared_ptr<Bound>& expr, const Literal& lit) = 0;
149
153 virtual Result<R> Eq(const std::shared_ptr<Bound>& expr, const Literal& lit) = 0;
154
158 virtual Result<R> NotEq(const std::shared_ptr<Bound>& expr, const Literal& lit) = 0;
159
163 virtual Result<R> StartsWith([[maybe_unused]] const std::shared_ptr<Bound>& expr,
164 [[maybe_unused]] const Literal& lit) {
165 return NotSupported("StartsWith operation is not supported by this visitor");
166 }
167
171 virtual Result<R> NotStartsWith([[maybe_unused]] const std::shared_ptr<Bound>& expr,
172 [[maybe_unused]] const Literal& lit) {
173 return NotSupported("NotStartsWith operation is not supported by this visitor");
174 }
175
179 virtual Result<R> In(
180 [[maybe_unused]] const std::shared_ptr<Bound>& expr,
181 [[maybe_unused]] const BoundSetPredicate::LiteralSet& literal_set) {
182 return NotSupported("In operation is not supported by this visitor");
183 }
184
188 virtual Result<R> NotIn(
189 [[maybe_unused]] const std::shared_ptr<Bound>& expr,
190 [[maybe_unused]] const BoundSetPredicate::LiteralSet& literal_set) {
191 return NotSupported("NotIn operation is not supported by this visitor");
192 }
193
200 Result<R> Predicate(const std::shared_ptr<BoundPredicate>& pred) override {
201 ICEBERG_DCHECK(pred != nullptr, "BoundPredicate cannot be null");
202
203 switch (pred->kind()) {
204 case BoundPredicate::Kind::kUnary: {
205 switch (pred->op()) {
206 case Expression::Operation::kIsNull:
207 return IsNull(pred->term());
208 case Expression::Operation::kNotNull:
209 return NotNull(pred->term());
210 case Expression::Operation::kIsNan:
211 return IsNaN(pred->term());
212 case Expression::Operation::kNotNan:
213 return NotNaN(pred->term());
214 default:
215 return InvalidExpression("Invalid operation for BoundUnaryPredicate: {}",
216 ToString(pred->op()));
217 }
218 }
219 case BoundPredicate::Kind::kLiteral: {
220 const auto& literal_pred =
221 internal::checked_cast<const BoundLiteralPredicate&>(*pred);
222 switch (pred->op()) {
223 case Expression::Operation::kLt:
224 return Lt(pred->term(), literal_pred.literal());
225 case Expression::Operation::kLtEq:
226 return LtEq(pred->term(), literal_pred.literal());
227 case Expression::Operation::kGt:
228 return Gt(pred->term(), literal_pred.literal());
229 case Expression::Operation::kGtEq:
230 return GtEq(pred->term(), literal_pred.literal());
231 case Expression::Operation::kEq:
232 return Eq(pred->term(), literal_pred.literal());
233 case Expression::Operation::kNotEq:
234 return NotEq(pred->term(), literal_pred.literal());
235 case Expression::Operation::kStartsWith:
236 return StartsWith(pred->term(), literal_pred.literal());
237 case Expression::Operation::kNotStartsWith:
238 return NotStartsWith(pred->term(), literal_pred.literal());
239 default:
240 return InvalidExpression("Invalid operation for BoundLiteralPredicate: {}",
241 ToString(pred->op()));
242 }
243 }
244 case BoundPredicate::Kind::kSet: {
245 const auto& set_pred = internal::checked_cast<const BoundSetPredicate&>(*pred);
246 switch (pred->op()) {
247 case Expression::Operation::kIn:
248 return In(pred->term(), set_pred.literal_set());
249 case Expression::Operation::kNotIn:
250 return NotIn(pred->term(), set_pred.literal_set());
251 default:
252 return InvalidExpression("Invalid operation for BoundSetPredicate: {}",
253 ToString(pred->op()));
254 }
255 }
256 }
257
258 return InvalidExpression("Unsupported bound predicate: {}", pred->ToString());
259 }
260
264 Result<R> Predicate(const std::shared_ptr<UnboundPredicate>& pred) override {
265 ICEBERG_DCHECK(pred != nullptr, "UnboundPredicate cannot be null");
266 return NotSupported("Not a bound predicate: {}", pred->ToString());
267 }
268};
269
281template <typename R, typename V>
282 requires std::derived_from<V, ExpressionVisitor<R>>
283Result<R> Visit(const std::shared_ptr<Expression>& expr, V& visitor) {
284 ICEBERG_DCHECK(expr != nullptr, "Expression cannot be null");
285
286 if (expr->is_bound_predicate()) {
287 return visitor.Predicate(std::dynamic_pointer_cast<BoundPredicate>(expr));
288 }
289
290 if (expr->is_unbound_predicate()) {
291 return visitor.Predicate(std::dynamic_pointer_cast<UnboundPredicate>(expr));
292 }
293
294 if (expr->is_bound_aggregate()) {
295 return visitor.Aggregate(std::dynamic_pointer_cast<BoundAggregate>(expr));
296 }
297
298 if (expr->is_unbound_aggregate()) {
299 return visitor.Aggregate(std::dynamic_pointer_cast<UnboundAggregate>(expr));
300 }
301
302 switch (expr->op()) {
303 case Expression::Operation::kTrue:
304 return visitor.AlwaysTrue();
305 case Expression::Operation::kFalse:
306 return visitor.AlwaysFalse();
307 case Expression::Operation::kNot: {
308 const auto& not_expr = internal::checked_pointer_cast<Not>(expr);
309 ICEBERG_ASSIGN_OR_RAISE(auto child_result,
310 (Visit<R, V>(not_expr->child(), visitor)));
311 return visitor.Not(std::move(child_result));
312 }
313 case Expression::Operation::kAnd: {
314 const auto& and_expr = internal::checked_pointer_cast<And>(expr);
315 ICEBERG_ASSIGN_OR_RAISE(auto left_result, (Visit<R, V>(and_expr->left(), visitor)));
316 ICEBERG_ASSIGN_OR_RAISE(auto right_result,
317 (Visit<R, V>(and_expr->right(), visitor)));
318 return visitor.And(std::move(left_result), std::move(right_result));
319 }
320 case Expression::Operation::kOr: {
321 const auto& or_expr = internal::checked_pointer_cast<Or>(expr);
322 ICEBERG_ASSIGN_OR_RAISE(auto left_result, (Visit<R, V>(or_expr->left(), visitor)));
323 ICEBERG_ASSIGN_OR_RAISE(auto right_result,
324 (Visit<R, V>(or_expr->right(), visitor)));
325 return visitor.Or(std::move(left_result), std::move(right_result));
326 }
327 default:
328 return InvalidExpression("Unknown expression operation: {}", expr->ToString());
329 }
330}
331
332} // namespace iceberg
Checked cast functions for dynamic_cast and static_cast. Adapted from Apache Arrow https://github....
Visitor for bound expressions.
Definition expression_visitor.h:106
virtual Result< R > Gt(const std::shared_ptr< Bound > &expr, const Literal &lit)=0
Visit a greater-than bound expression.
virtual Result< R > Lt(const std::shared_ptr< Bound > &expr, const Literal &lit)=0
Visit a less-than bound expression.
virtual Result< R > IsNull(const std::shared_ptr< Bound > &expr)=0
Visit an IS_NULL bound expression.
Result< R > Predicate(const std::shared_ptr< UnboundPredicate > &pred) override
Visit an unbound predicate.
Definition expression_visitor.h:264
virtual Result< R > NotStartsWith(const std::shared_ptr< Bound > &expr, const Literal &lit)
Visit a not-starts-with bound expression.
Definition expression_visitor.h:171
virtual Result< R > LtEq(const std::shared_ptr< Bound > &expr, const Literal &lit)=0
Visit a less-than-or-equal bound expression.
virtual Result< R > In(const std::shared_ptr< Bound > &expr, const BoundSetPredicate::LiteralSet &literal_set)
Visit an IN set bound expression.
Definition expression_visitor.h:179
virtual Result< R > NotIn(const std::shared_ptr< Bound > &expr, const BoundSetPredicate::LiteralSet &literal_set)
Visit a NOT_IN set bound expression.
Definition expression_visitor.h:188
virtual Result< R > GtEq(const std::shared_ptr< Bound > &expr, const Literal &lit)=0
Visit a greater-than-or-equal bound expression.
virtual Result< R > NotNull(const std::shared_ptr< Bound > &expr)=0
Visit a NOT_NULL bound expression.
virtual Result< R > NotEq(const std::shared_ptr< Bound > &expr, const Literal &lit)=0
Visit a not-equal bound expression.
Result< R > Predicate(const std::shared_ptr< BoundPredicate > &pred) override
Visit a bound predicate.
Definition expression_visitor.h:200
virtual Result< R > Eq(const std::shared_ptr< Bound > &expr, const Literal &lit)=0
Visit an equality bound expression.
virtual Result< R > IsNaN(const std::shared_ptr< Bound > &expr)
Visit an IS_NAN bound expression.
Definition expression_visitor.h:120
virtual Result< R > NotNaN(const std::shared_ptr< Bound > &expr)
Visit a NOT_NAN bound expression.
Definition expression_visitor.h:126
virtual Result< R > StartsWith(const std::shared_ptr< Bound > &expr, const Literal &lit)
Visit a starts-with bound expression.
Definition expression_visitor.h:163
Base visitor for traversing expression trees.
Definition expression_visitor.h:49
virtual Result< R > And(ParamType left_result, ParamType right_result)=0
Visit an And expression.
virtual Result< R > Predicate(const std::shared_ptr< UnboundPredicate > &pred)=0
Visit an unbound predicate.
virtual Result< R > Not(ParamType child_result)=0
Visit a Not expression.
virtual Result< R > Aggregate(const std::shared_ptr< BoundAggregate > &aggregate)
Visit a bound aggregate.
Definition expression_visitor.h:85
virtual Result< R > Aggregate(const std::shared_ptr< UnboundAggregate > &aggregate)
Visit an unbound aggregate.
Definition expression_visitor.h:93
virtual Result< R > Or(ParamType left_result, ParamType right_result)=0
Visit an Or expression.
virtual Result< R > AlwaysFalse()=0
Visit a False expression (always evaluates to false).
virtual Result< R > Predicate(const std::shared_ptr< BoundPredicate > &pred)=0
Visit a bound predicate.
virtual Result< R > AlwaysTrue()=0
Visit a True expression (always evaluates to true).
Literal is a literal value that is associated with a primitive type.
Definition literal.h:39
Result< R > Visit(const std::shared_ptr< Expression > &expr, V &visitor)
Traverse an expression tree with a visitor.
Definition expression_visitor.h:283