Skip to content

Commit 919b10a

Browse files
HeartLinkedwgtmac
authored andcommitted
refactor: use factory pattern and throw exception for expression
1 parent dc23f76 commit 919b10a

File tree

10 files changed

+272
-72
lines changed

10 files changed

+272
-72
lines changed

src/iceberg/exception.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ class ICEBERG_EXPORT IcebergError : public std::runtime_error {
3838
explicit IcebergError(const std::string& what) : std::runtime_error(what) {}
3939
};
4040

41+
/// \brief Exception thrown when expression construction fails.
42+
class ICEBERG_EXPORT ExpressionError : public IcebergError {
43+
public:
44+
explicit ExpressionError(const std::string& what) : IcebergError(what) {}
45+
};
46+
4147
#define ICEBERG_CHECK(condition, ...) \
4248
do { \
4349
if (!(condition)) [[unlikely]] { \

src/iceberg/expression/expression.cc

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,19 @@ const std::shared_ptr<False>& False::Instance() {
4545
Result<std::shared_ptr<Expression>> False::Negate() const { return True::Instance(); }
4646

4747
// And implementation
48+
Result<std::unique_ptr<And>> And::Make(std::shared_ptr<Expression> left,
49+
std::shared_ptr<Expression> right) {
50+
if (!left || !right) [[unlikely]] {
51+
return InvalidExpression("And expression cannot have null children");
52+
}
53+
return std::unique_ptr<And>(new And(std::move(left), std::move(right)));
54+
}
55+
4856
And::And(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right)
49-
: left_(std::move(left)), right_(std::move(right)) {}
57+
: left_(std::move(left)), right_(std::move(right)) {
58+
ICEBERG_DCHECK(left_ != nullptr, "And left operand cannot be null");
59+
ICEBERG_DCHECK(right_ != nullptr, "And right operand cannot be null");
60+
}
5061

5162
std::string And::ToString() const {
5263
return std::format("({} and {})", left_->ToString(), right_->ToString());
@@ -56,7 +67,7 @@ Result<std::shared_ptr<Expression>> And::Negate() const {
5667
// De Morgan's law: not(A and B) = (not A) or (not B)
5768
ICEBERG_ASSIGN_OR_RAISE(auto left_negated, left_->Negate());
5869
ICEBERG_ASSIGN_OR_RAISE(auto right_negated, right_->Negate());
59-
return std::make_shared<Or>(std::move(left_negated), std::move(right_negated));
70+
return Or::Make(std::move(left_negated), std::move(right_negated));
6071
}
6172

6273
bool And::Equals(const Expression& expr) const {
@@ -69,8 +80,22 @@ bool And::Equals(const Expression& expr) const {
6980
}
7081

7182
// Or implementation
83+
Result<std::unique_ptr<Or>> Or::Make(std::shared_ptr<Expression> left,
84+
std::shared_ptr<Expression> right) {
85+
if (!left) {
86+
return InvalidArgument("Or expression left operand cannot be null");
87+
}
88+
if (!right) {
89+
return InvalidArgument("Or expression right operand cannot be null");
90+
}
91+
return std::unique_ptr<Or>(new Or(std::move(left), std::move(right)));
92+
}
93+
7294
Or::Or(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right)
73-
: left_(std::move(left)), right_(std::move(right)) {}
95+
: left_(std::move(left)), right_(std::move(right)) {
96+
ICEBERG_DCHECK(left_ != nullptr, "Or left operand cannot be null");
97+
ICEBERG_DCHECK(right_ != nullptr, "Or right operand cannot be null");
98+
}
7499

75100
std::string Or::ToString() const {
76101
return std::format("({} or {})", left_->ToString(), right_->ToString());
@@ -80,7 +105,7 @@ Result<std::shared_ptr<Expression>> Or::Negate() const {
80105
// De Morgan's law: not(A or B) = (not A) and (not B)
81106
ICEBERG_ASSIGN_OR_RAISE(auto left_negated, left_->Negate());
82107
ICEBERG_ASSIGN_OR_RAISE(auto right_negated, right_->Negate());
83-
return std::make_shared<And>(std::move(left_negated), std::move(right_negated));
108+
return And::Make(std::move(left_negated), std::move(right_negated));
84109
}
85110

86111
bool Or::Equals(const Expression& expr) const {
@@ -93,7 +118,16 @@ bool Or::Equals(const Expression& expr) const {
93118
}
94119

95120
// Not implementation
96-
Not::Not(std::shared_ptr<Expression> child) : child_(std::move(child)) {}
121+
Result<std::unique_ptr<Not>> Not::Make(std::shared_ptr<Expression> child) {
122+
if (!child) {
123+
return InvalidExpression("Not expression cannot have null child");
124+
}
125+
return std::unique_ptr<Not>(new Not(std::move(child)));
126+
}
127+
128+
Not::Not(std::shared_ptr<Expression> child) : child_(std::move(child)) {
129+
ICEBERG_DCHECK(child_ != nullptr, "Not child expression cannot be null");
130+
}
97131

98132
std::string Not::ToString() const { return std::format("not({})", child_->ToString()); }
99133

src/iceberg/expression/expression.h

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,14 @@ class ICEBERG_EXPORT False : public Expression {
130130
/// evaluate to true.
131131
class ICEBERG_EXPORT And : public Expression {
132132
public:
133-
/// \brief Constructs an And expression from two sub-expressions.
133+
/// \brief Creates an And expression from two sub-expressions.
134134
///
135135
/// \param left The left operand of the AND expression
136136
/// \param right The right operand of the AND expression
137-
And(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right);
137+
/// \return A Result containing a unique pointer to And, or an error if either parameter
138+
/// is nullptr
139+
static Result<std::unique_ptr<And>> Make(std::shared_ptr<Expression> left,
140+
std::shared_ptr<Expression> right);
138141

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

157160
private:
161+
And(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right);
162+
158163
std::shared_ptr<Expression> left_;
159164
std::shared_ptr<Expression> right_;
160165
};
@@ -165,11 +170,14 @@ class ICEBERG_EXPORT And : public Expression {
165170
/// evaluates to true.
166171
class ICEBERG_EXPORT Or : public Expression {
167172
public:
168-
/// \brief Constructs an Or expression from two sub-expressions.
173+
/// \brief Creates an Or expression from two sub-expressions.
169174
///
170175
/// \param left The left operand of the OR expression
171176
/// \param right The right operand of the OR expression
172-
Or(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right);
177+
/// \return A Result containing a unique pointer to Or, or an error if either parameter
178+
/// is nullptr
179+
static Result<std::unique_ptr<Or>> Make(std::shared_ptr<Expression> left,
180+
std::shared_ptr<Expression> right);
173181

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

192200
private:
201+
Or(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right);
202+
193203
std::shared_ptr<Expression> left_;
194204
std::shared_ptr<Expression> right_;
195205
};
@@ -199,10 +209,11 @@ class ICEBERG_EXPORT Or : public Expression {
199209
/// This expression negates its child expression.
200210
class ICEBERG_EXPORT Not : public Expression {
201211
public:
202-
/// \brief Constructs a Not expression from a child expression.
212+
/// \brief Creates a Not expression from a child expression.
203213
///
204214
/// \param child The expression to negate
205-
explicit Not(std::shared_ptr<Expression> child);
215+
/// \return A Result containing a unique pointer to Not, or an error if child is nullptr
216+
static Result<std::unique_ptr<Not>> Make(std::shared_ptr<Expression> child);
206217

207218
/// \brief Returns the child expression.
208219
///
@@ -218,6 +229,8 @@ class ICEBERG_EXPORT Not : public Expression {
218229
bool Equals(const Expression& other) const override;
219230

220231
private:
232+
explicit Not(std::shared_ptr<Expression> child);
233+
221234
std::shared_ptr<Expression> child_;
222235
};
223236

src/iceberg/expression/expressions.cc

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "iceberg/exception.h"
2323
#include "iceberg/transform.h"
2424
#include "iceberg/type.h"
25+
#include "iceberg/util/macros.h"
2526

2627
namespace iceberg {
2728

@@ -41,41 +42,58 @@ std::shared_ptr<Expression> Expressions::Not(std::shared_ptr<Expression> child)
4142
return not_expr.child();
4243
}
4344

44-
return std::make_shared<::iceberg::Not>(std::move(child));
45+
auto result = ::iceberg::Not::Make(std::move(child));
46+
ICEBERG_ASSIGN_OR_THROW(auto not_expr, std::move(result));
47+
return {std::move(not_expr)};
4548
}
4649

4750
// Transform functions
4851

4952
std::shared_ptr<UnboundTransform> Expressions::Bucket(std::string name,
5053
int32_t num_buckets) {
51-
return std::make_shared<UnboundTransform>(Ref(std::move(name)),
52-
Transform::Bucket(num_buckets));
54+
ICEBERG_ASSIGN_OR_THROW(
55+
auto transform,
56+
UnboundTransform::Make(Ref(std::move(name)), Transform::Bucket(num_buckets)));
57+
return {std::move(transform)};
5358
}
5459

5560
std::shared_ptr<UnboundTransform> Expressions::Year(std::string name) {
56-
return std::make_shared<UnboundTransform>(Ref(std::move(name)), Transform::Year());
61+
ICEBERG_ASSIGN_OR_THROW(
62+
auto transform, UnboundTransform::Make(Ref(std::move(name)), Transform::Year()));
63+
return {std::move(transform)};
5764
}
5865

5966
std::shared_ptr<UnboundTransform> Expressions::Month(std::string name) {
60-
return std::make_shared<UnboundTransform>(Ref(std::move(name)), Transform::Month());
67+
ICEBERG_ASSIGN_OR_THROW(
68+
auto transform, UnboundTransform::Make(Ref(std::move(name)), Transform::Month()));
69+
return {std::move(transform)};
6170
}
6271

6372
std::shared_ptr<UnboundTransform> Expressions::Day(std::string name) {
64-
return std::make_shared<UnboundTransform>(Ref(std::move(name)), Transform::Day());
73+
ICEBERG_ASSIGN_OR_THROW(auto transform,
74+
UnboundTransform::Make(Ref(std::move(name)), Transform::Day()));
75+
return {std::move(transform)};
6576
}
6677

6778
std::shared_ptr<UnboundTransform> Expressions::Hour(std::string name) {
68-
return std::make_shared<UnboundTransform>(Ref(std::move(name)), Transform::Hour());
79+
ICEBERG_ASSIGN_OR_THROW(
80+
auto transform, UnboundTransform::Make(Ref(std::move(name)), Transform::Hour()));
81+
return {std::move(transform)};
6982
}
7083

7184
std::shared_ptr<UnboundTransform> Expressions::Truncate(std::string name, int32_t width) {
72-
return std::make_shared<UnboundTransform>(Ref(std::move(name)),
73-
Transform::Truncate(width));
85+
ICEBERG_ASSIGN_OR_THROW(
86+
auto transform,
87+
UnboundTransform::Make(Ref(std::move(name)), Transform::Truncate(width)));
88+
return {std::move(transform)};
7489
}
7590

7691
std::shared_ptr<UnboundTransform> Expressions::Transform(
7792
std::string name, std::shared_ptr<::iceberg::Transform> transform) {
78-
return std::make_shared<UnboundTransform>(Ref(std::move(name)), std::move(transform));
93+
ICEBERG_ASSIGN_OR_THROW(
94+
auto unbound_transform,
95+
UnboundTransform::Make(Ref(std::move(name)), std::move(transform)));
96+
return {std::move(unbound_transform)};
7997
}
8098

8199
// Template implementations for unary predicates
@@ -327,11 +345,12 @@ std::shared_ptr<False> Expressions::AlwaysFalse() { return False::Instance(); }
327345
// Utilities
328346

329347
std::shared_ptr<NamedReference> Expressions::Ref(std::string name) {
330-
return std::make_shared<NamedReference>(std::move(name));
348+
ICEBERG_ASSIGN_OR_THROW(auto ref, NamedReference::Make(std::move(name)));
349+
return {std::move(ref)};
331350
}
332351

333352
Literal Expressions::Lit(Literal::Value value, std::shared_ptr<PrimitiveType> type) {
334-
throw IcebergError("Literal creation is not implemented");
353+
throw ExpressionError("Literal creation is not implemented");
335354
}
336355

337356
} // namespace iceberg

src/iceberg/expression/expressions.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,18 @@
2727
#include <string>
2828
#include <vector>
2929

30+
#include "iceberg/exception.h"
3031
#include "iceberg/expression/literal.h"
3132
#include "iceberg/expression/predicate.h"
3233
#include "iceberg/expression/term.h"
3334
#include "iceberg/iceberg_export.h"
35+
#include "iceberg/util/macros.h"
3436

3537
namespace iceberg {
3638

37-
/// \brief Factory methods for creating expressions.
39+
/// \brief Fluent APIs to create expressions.
40+
///
41+
/// \throw `ExpressionError` for invalid expression.
3842
class ICEBERG_EXPORT Expressions {
3943
public:
4044
// Logical operations
@@ -60,7 +64,9 @@ class ICEBERG_EXPORT Expressions {
6064
return left;
6165
}
6266

63-
return std::make_shared<::iceberg::And>(std::move(left), std::move(right));
67+
auto result = ::iceberg::And::Make(std::move(left), std::move(right));
68+
ICEBERG_ASSIGN_OR_THROW(auto and_expr, std::move(result));
69+
return {std::move(and_expr)};
6470
} else {
6571
return And(And(std::move(left), std::move(right)), std::forward<Args>(args)...);
6672
}
@@ -86,7 +92,9 @@ class ICEBERG_EXPORT Expressions {
8692
return left;
8793
}
8894

89-
return std::make_shared<::iceberg::Or>(std::move(left), std::move(right));
95+
auto result = ::iceberg::Or::Make(std::move(left), std::move(right));
96+
ICEBERG_ASSIGN_OR_THROW(auto or_expr, std::move(result));
97+
return {std::move(or_expr)};
9098
} else {
9199
return Or(Or(std::move(left), std::move(right)), std::forward<Args>(args)...);
92100
}

0 commit comments

Comments
 (0)