| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 |
| * |
| * http://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 "iceberg/expression/expression.h" |
| |
| #include <format> |
| #include <utility> |
| |
| #include "iceberg/util/checked_cast.h" |
| #include "iceberg/util/formatter_internal.h" |
| #include "iceberg/util/macros.h" |
| |
| namespace iceberg { |
| |
| // True implementation |
| const std::shared_ptr<True>& True::Instance() { |
| static const std::shared_ptr<True> instance{new True()}; |
| return instance; |
| } |
| |
| Result<std::shared_ptr<Expression>> True::Negate() const { return False::Instance(); } |
| |
| // False implementation |
| const std::shared_ptr<False>& False::Instance() { |
| static const std::shared_ptr<False> instance = std::shared_ptr<False>(new False()); |
| return instance; |
| } |
| |
| Result<std::shared_ptr<Expression>> False::Negate() const { return True::Instance(); } |
| |
| // And implementation |
| Result<std::unique_ptr<And>> And::Make(std::shared_ptr<Expression> left, |
| std::shared_ptr<Expression> right) { |
| if (!left || !right) [[unlikely]] { |
| return InvalidExpression("And expression cannot have null children"); |
| } |
| return std::unique_ptr<And>(new And(std::move(left), std::move(right))); |
| } |
| |
| And::And(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right) |
| : left_(std::move(left)), right_(std::move(right)) { |
| ICEBERG_DCHECK(left_ && right_, "And cannot have null children"); |
| } |
| |
| std::string And::ToString() const { |
| return std::format("({} and {})", left_->ToString(), right_->ToString()); |
| } |
| |
| Result<std::shared_ptr<Expression>> And::Negate() const { |
| // De Morgan's law: not(A and B) = (not A) or (not B) |
| ICEBERG_ASSIGN_OR_RAISE(auto left_negated, left_->Negate()); |
| ICEBERG_ASSIGN_OR_RAISE(auto right_negated, right_->Negate()); |
| return Or::Make(std::move(left_negated), std::move(right_negated)); |
| } |
| |
| bool And::Equals(const Expression& expr) const { |
| if (expr.op() == Operation::kAnd) { |
| const auto& other = static_cast<const And&>(expr); |
| return (left_->Equals(*other.left()) && right_->Equals(*other.right())) || |
| (left_->Equals(*other.right()) && right_->Equals(*other.left())); |
| } |
| return false; |
| } |
| |
| // Or implementation |
| Result<std::unique_ptr<Or>> Or::Make(std::shared_ptr<Expression> left, |
| std::shared_ptr<Expression> right) { |
| if (!left || !right) [[unlikely]] { |
| return InvalidExpression("Or cannot have null children"); |
| } |
| return std::unique_ptr<Or>(new Or(std::move(left), std::move(right))); |
| } |
| |
| Or::Or(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right) |
| : left_(std::move(left)), right_(std::move(right)) { |
| ICEBERG_DCHECK(left_ && right_, "Or cannot have null children"); |
| } |
| |
| std::string Or::ToString() const { |
| return std::format("({} or {})", left_->ToString(), right_->ToString()); |
| } |
| |
| Result<std::shared_ptr<Expression>> Or::Negate() const { |
| // De Morgan's law: not(A or B) = (not A) and (not B) |
| ICEBERG_ASSIGN_OR_RAISE(auto left_negated, left_->Negate()); |
| ICEBERG_ASSIGN_OR_RAISE(auto right_negated, right_->Negate()); |
| return And::Make(std::move(left_negated), std::move(right_negated)); |
| } |
| |
| bool Or::Equals(const Expression& expr) const { |
| if (expr.op() == Operation::kOr) { |
| const auto& other = static_cast<const Or&>(expr); |
| return (left_->Equals(*other.left()) && right_->Equals(*other.right())) || |
| (left_->Equals(*other.right()) && right_->Equals(*other.left())); |
| } |
| return false; |
| } |
| |
| // Not implementation |
| Result<std::unique_ptr<Not>> Not::Make(std::shared_ptr<Expression> child) { |
| if (!child) [[unlikely]] { |
| return InvalidExpression("Not expression cannot have null child"); |
| } |
| return std::unique_ptr<Not>(new Not(std::move(child))); |
| } |
| |
| Result<std::shared_ptr<Expression>> Not::MakeFolded(std::shared_ptr<Expression> child) { |
| if (child->op() == Expression::Operation::kTrue) { |
| return False::Instance(); |
| } |
| |
| if (child->op() == Expression::Operation::kFalse) { |
| return True::Instance(); |
| } |
| |
| // not(not(x)) = x |
| if (child->op() == Expression::Operation::kNot) { |
| const auto& not_expr = internal::checked_cast<const ::iceberg::Not&>(*child); |
| return not_expr.child(); |
| } |
| |
| return Not::Make(std::move(child)); |
| } |
| |
| Not::Not(std::shared_ptr<Expression> child) : child_(std::move(child)) { |
| ICEBERG_DCHECK(child_ != nullptr, "Not expression cannot have null child"); |
| } |
| |
| std::string Not::ToString() const { return std::format("not({})", child_->ToString()); } |
| |
| Result<std::shared_ptr<Expression>> Not::Negate() const { return child_; } |
| |
| bool Not::Equals(const Expression& other) const { |
| return other.op() == Operation::kNot && |
| internal::checked_cast<const Not&>(other).child_->Equals(*child_); |
| } |
| |
| std::string_view ToString(Expression::Operation op) { |
| switch (op) { |
| case Expression::Operation::kAnd: |
| return "AND"; |
| case Expression::Operation::kOr: |
| return "OR"; |
| case Expression::Operation::kTrue: |
| return "TRUE"; |
| case Expression::Operation::kFalse: |
| return "FALSE"; |
| case Expression::Operation::kIsNull: |
| return "IS_NULL"; |
| case Expression::Operation::kNotNull: |
| return "NOT_NULL"; |
| case Expression::Operation::kIsNan: |
| return "IS_NAN"; |
| case Expression::Operation::kNotNan: |
| return "NOT_NAN"; |
| case Expression::Operation::kLt: |
| return "LT"; |
| case Expression::Operation::kLtEq: |
| return "LT_EQ"; |
| case Expression::Operation::kGt: |
| return "GT"; |
| case Expression::Operation::kGtEq: |
| return "GT_EQ"; |
| case Expression::Operation::kEq: |
| return "EQ"; |
| case Expression::Operation::kNotEq: |
| return "NOT_EQ"; |
| case Expression::Operation::kIn: |
| return "IN"; |
| case Expression::Operation::kNotIn: |
| return "NOT_IN"; |
| case Expression::Operation::kStartsWith: |
| return "STARTS_WITH"; |
| case Expression::Operation::kNotStartsWith: |
| return "NOT_STARTS_WITH"; |
| case Expression::Operation::kCount: |
| return "COUNT"; |
| case Expression::Operation::kCountNull: |
| return "COUNT_NULL"; |
| case Expression::Operation::kNot: |
| return "NOT"; |
| case Expression::Operation::kCountStar: |
| return "COUNT_STAR"; |
| case Expression::Operation::kMax: |
| return "MAX"; |
| case Expression::Operation::kMin: |
| return "MIN"; |
| } |
| std::unreachable(); |
| } |
| |
| Result<Expression::Operation> Negate(Expression::Operation op) { |
| switch (op) { |
| case Expression::Operation::kIsNull: |
| return Expression::Operation::kNotNull; |
| case Expression::Operation::kNotNull: |
| return Expression::Operation::kIsNull; |
| case Expression::Operation::kIsNan: |
| return Expression::Operation::kNotNan; |
| case Expression::Operation::kNotNan: |
| return Expression::Operation::kIsNan; |
| case Expression::Operation::kLt: |
| return Expression::Operation::kGtEq; |
| case Expression::Operation::kLtEq: |
| return Expression::Operation::kGt; |
| case Expression::Operation::kGt: |
| return Expression::Operation::kLtEq; |
| case Expression::Operation::kGtEq: |
| return Expression::Operation::kLt; |
| case Expression::Operation::kEq: |
| return Expression::Operation::kNotEq; |
| case Expression::Operation::kNotEq: |
| return Expression::Operation::kEq; |
| case Expression::Operation::kIn: |
| return Expression::Operation::kNotIn; |
| case Expression::Operation::kNotIn: |
| return Expression::Operation::kIn; |
| case Expression::Operation::kStartsWith: |
| return Expression::Operation::kNotStartsWith; |
| case Expression::Operation::kNotStartsWith: |
| return Expression::Operation::kStartsWith; |
| case Expression::Operation::kTrue: |
| return Expression::Operation::kFalse; |
| case Expression::Operation::kFalse: |
| return Expression::Operation::kTrue; |
| case Expression::Operation::kAnd: |
| return Expression::Operation::kOr; |
| case Expression::Operation::kOr: |
| return Expression::Operation::kAnd; |
| case Expression::Operation::kNot: |
| case Expression::Operation::kCountStar: |
| case Expression::Operation::kMax: |
| case Expression::Operation::kMin: |
| case Expression::Operation::kCount: |
| case Expression::Operation::kCountNull: |
| return InvalidExpression("No negation for operation: {}", op); |
| } |
| std::unreachable(); |
| } |
| |
| } // namespace iceberg |