Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/iceberg/exception.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ class ICEBERG_EXPORT IcebergError : public std::runtime_error {
explicit IcebergError(const std::string& what) : std::runtime_error(what) {}
};

/// \brief Exception thrown when expression construction fails.
class ICEBERG_EXPORT ExpressionError : public IcebergError {
public:
explicit ExpressionError(const std::string& what) : IcebergError(what) {}
};

#define ICEBERG_CHECK(condition, ...) \
do { \
if (!(condition)) [[unlikely]] { \
Expand Down
41 changes: 35 additions & 6 deletions src/iceberg/expression/expression.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,18 @@ const std::shared_ptr<False>& False::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)) {}
: 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());
Expand All @@ -56,7 +66,7 @@ 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 std::make_shared<Or>(std::move(left_negated), std::move(right_negated));
return Or::Make(std::move(left_negated), std::move(right_negated));
}

bool And::Equals(const Expression& expr) const {
Expand All @@ -69,8 +79,18 @@ bool And::Equals(const Expression& expr) const {
}

// 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)) {}
: 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());
Expand All @@ -80,7 +100,7 @@ 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 std::make_shared<And>(std::move(left_negated), std::move(right_negated));
return And::Make(std::move(left_negated), std::move(right_negated));
}

bool Or::Equals(const Expression& expr) const {
Expand All @@ -93,7 +113,16 @@ bool Or::Equals(const Expression& expr) const {
}

// Not implementation
Not::Not(std::shared_ptr<Expression> child) : child_(std::move(child)) {}
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)));
}

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()); }

Expand Down Expand Up @@ -199,7 +228,7 @@ Result<Expression::Operation> Negate(Expression::Operation op) {
case Expression::Operation::kMax:
case Expression::Operation::kMin:
case Expression::Operation::kCount:
return InvalidArgument("No negation for operation: {}", op);
return InvalidExpression("No negation for operation: {}", op);
}
std::unreachable();
}
Expand Down
21 changes: 15 additions & 6 deletions src/iceberg/expression/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,12 @@ class ICEBERG_EXPORT False : public Expression {
/// evaluate to true.
class ICEBERG_EXPORT And : public Expression {
public:
/// \brief Constructs an And expression from two sub-expressions.
/// \brief Creates an And expression from two sub-expressions.
///
/// \param left The left operand of the AND expression
/// \param right The right operand of the AND expression
And(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right);
static Result<std::unique_ptr<And>> Make(std::shared_ptr<Expression> left,
std::shared_ptr<Expression> right);

/// \brief Returns the left operand of the AND expression.
///
Expand All @@ -155,6 +156,8 @@ class ICEBERG_EXPORT And : public Expression {
bool Equals(const Expression& other) const override;

private:
And(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right);

std::shared_ptr<Expression> left_;
std::shared_ptr<Expression> right_;
};
Expand All @@ -165,11 +168,12 @@ class ICEBERG_EXPORT And : public Expression {
/// evaluates to true.
class ICEBERG_EXPORT Or : public Expression {
public:
/// \brief Constructs an Or expression from two sub-expressions.
/// \brief Creates an Or expression from two sub-expressions.
///
/// \param left The left operand of the OR expression
/// \param right The right operand of the OR expression
Or(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right);
static Result<std::unique_ptr<Or>> Make(std::shared_ptr<Expression> left,
std::shared_ptr<Expression> right);

/// \brief Returns the left operand of the OR expression.
///
Expand All @@ -190,6 +194,8 @@ class ICEBERG_EXPORT Or : public Expression {
bool Equals(const Expression& other) const override;

private:
Or(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right);

std::shared_ptr<Expression> left_;
std::shared_ptr<Expression> right_;
};
Expand All @@ -199,10 +205,11 @@ class ICEBERG_EXPORT Or : public Expression {
/// This expression negates its child expression.
class ICEBERG_EXPORT Not : public Expression {
public:
/// \brief Constructs a Not expression from a child expression.
/// \brief Creates a Not expression from a child expression.
///
/// \param child The expression to negate
explicit Not(std::shared_ptr<Expression> child);
/// \return A Result containing a unique pointer to Not, or an error if child is nullptr
static Result<std::unique_ptr<Not>> Make(std::shared_ptr<Expression> child);

/// \brief Returns the child expression.
///
Expand All @@ -218,6 +225,8 @@ class ICEBERG_EXPORT Not : public Expression {
bool Equals(const Expression& other) const override;

private:
explicit Not(std::shared_ptr<Expression> child);

std::shared_ptr<Expression> child_;
};

Expand Down
42 changes: 30 additions & 12 deletions src/iceberg/expression/expressions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "iceberg/exception.h"
#include "iceberg/transform.h"
#include "iceberg/type.h"
#include "iceberg/util/macros.h"

namespace iceberg {

Expand All @@ -41,41 +42,57 @@ std::shared_ptr<Expression> Expressions::Not(std::shared_ptr<Expression> child)
return not_expr.child();
}

return std::make_shared<::iceberg::Not>(std::move(child));
ICEBERG_ASSIGN_OR_THROW(auto not_expr, iceberg::Not::Make(std::move(child)));
return not_expr;
}

// Transform functions

std::shared_ptr<UnboundTransform> Expressions::Bucket(std::string name,
int32_t num_buckets) {
return std::make_shared<UnboundTransform>(Ref(std::move(name)),
Transform::Bucket(num_buckets));
ICEBERG_ASSIGN_OR_THROW(
auto transform,
UnboundTransform::Make(Ref(std::move(name)), Transform::Bucket(num_buckets)));
return transform;
}

std::shared_ptr<UnboundTransform> Expressions::Year(std::string name) {
return std::make_shared<UnboundTransform>(Ref(std::move(name)), Transform::Year());
ICEBERG_ASSIGN_OR_THROW(
auto transform, UnboundTransform::Make(Ref(std::move(name)), Transform::Year()));
return transform;
}

std::shared_ptr<UnboundTransform> Expressions::Month(std::string name) {
return std::make_shared<UnboundTransform>(Ref(std::move(name)), Transform::Month());
ICEBERG_ASSIGN_OR_THROW(
auto transform, UnboundTransform::Make(Ref(std::move(name)), Transform::Month()));
return transform;
}

std::shared_ptr<UnboundTransform> Expressions::Day(std::string name) {
return std::make_shared<UnboundTransform>(Ref(std::move(name)), Transform::Day());
ICEBERG_ASSIGN_OR_THROW(auto transform,
UnboundTransform::Make(Ref(std::move(name)), Transform::Day()));
return transform;
}

std::shared_ptr<UnboundTransform> Expressions::Hour(std::string name) {
return std::make_shared<UnboundTransform>(Ref(std::move(name)), Transform::Hour());
ICEBERG_ASSIGN_OR_THROW(
auto transform, UnboundTransform::Make(Ref(std::move(name)), Transform::Hour()));
return transform;
}

std::shared_ptr<UnboundTransform> Expressions::Truncate(std::string name, int32_t width) {
return std::make_shared<UnboundTransform>(Ref(std::move(name)),
Transform::Truncate(width));
ICEBERG_ASSIGN_OR_THROW(
auto transform,
UnboundTransform::Make(Ref(std::move(name)), Transform::Truncate(width)));
return transform;
}

std::shared_ptr<UnboundTransform> Expressions::Transform(
std::string name, std::shared_ptr<::iceberg::Transform> transform) {
return std::make_shared<UnboundTransform>(Ref(std::move(name)), std::move(transform));
ICEBERG_ASSIGN_OR_THROW(
auto unbound_transform,
UnboundTransform::Make(Ref(std::move(name)), std::move(transform)));
return unbound_transform;
}

// Template implementations for unary predicates
Expand Down Expand Up @@ -327,11 +344,12 @@ std::shared_ptr<False> Expressions::AlwaysFalse() { return False::Instance(); }
// Utilities

std::shared_ptr<NamedReference> Expressions::Ref(std::string name) {
return std::make_shared<NamedReference>(std::move(name));
ICEBERG_ASSIGN_OR_THROW(auto ref, NamedReference::Make(std::move(name)));
return ref;
}

Literal Expressions::Lit(Literal::Value value, std::shared_ptr<PrimitiveType> type) {
throw IcebergError("Literal creation is not implemented");
throw ExpressionError("Literal creation is not implemented");
}

} // namespace iceberg
14 changes: 11 additions & 3 deletions src/iceberg/expression/expressions.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,18 @@
#include <string>
#include <vector>

#include "iceberg/exception.h"
#include "iceberg/expression/literal.h"
#include "iceberg/expression/predicate.h"
#include "iceberg/expression/term.h"
#include "iceberg/iceberg_export.h"
#include "iceberg/util/macros.h"

namespace iceberg {

/// \brief Factory methods for creating expressions.
/// \brief Fluent APIs to create expressions.
///
/// \throw `ExpressionError` for invalid expression.
class ICEBERG_EXPORT Expressions {
public:
// Logical operations
Expand All @@ -60,7 +64,9 @@ class ICEBERG_EXPORT Expressions {
return left;
}

return std::make_shared<::iceberg::And>(std::move(left), std::move(right));
ICEBERG_ASSIGN_OR_THROW(auto and_expr,
iceberg::And::Make(std::move(left), std::move(right)));
return and_expr;
} else {
return And(And(std::move(left), std::move(right)), std::forward<Args>(args)...);
}
Expand All @@ -86,7 +92,9 @@ class ICEBERG_EXPORT Expressions {
return left;
}

return std::make_shared<::iceberg::Or>(std::move(left), std::move(right));
ICEBERG_ASSIGN_OR_THROW(auto or_expr,
iceberg::Or::Make(std::move(left), std::move(right)));
return or_expr;
} else {
return Or(Or(std::move(left), std::move(right)), std::forward<Args>(args)...);
}
Expand Down
Loading
Loading