2929
3030namespace iceberg {
3131
32- template <typename T>
33- concept Bindable = requires (const T& expr, const Schema& schema, bool case_sensitive) {
34- // Must have a BoundType alias that defines what type it binds to
35- typename T::BoundType;
36-
37- // Must have a Bind method with the correct signature
38- { expr.Bind (schema, case_sensitive) } -> std::same_as<Result<typename T::BoundType>>;
39- };
40-
41- // / \brief Concept for types that behave like predicates (bound or unbound)
42- template <typename T>
43- concept PredicateLike = requires (const T& pred) {
44- // Must have an operation type
45- { pred.op () } -> std::same_as<Operation>;
46-
47- // Must be convertible to string
48- { pred.ToString () } -> std::same_as<std::string>;
49-
50- // Must have a Negate method that returns a shared_ptr to the same concept
51- { pred.Negate () } -> std::convertible_to<std::shared_ptr<T>>;
52-
53- // Must support equality comparison
54- { pred.Equals (pred) } -> std::same_as<bool >;
55- };
56-
57- // / \brief Concept specifically for unbound predicates that can be bound
58- template <typename T>
59- concept UnboundPredicate = PredicateLike<T> && requires (const T& pred) {
60- // Must have a BoundType alias
61- typename T::BoundType;
62-
63- // Must be bindable to a schema
64- requires Bindable<T>;
65- };
66-
67- // / \brief Concept specifically for bound predicates
68- template <typename T>
69- concept BoundPredicateLike = PredicateLike<T> && requires (const T& pred) {
70- // Must have type information
71- { pred.type () } -> std::convertible_to<std::shared_ptr<Type>>;
72-
73- // Must report that it's bound
74- { pred.IsBound () } -> std::convertible_to<bool >;
75- };
76-
7732// Internal implementation classes
7833
7934// / \brief An Expression that is always true.
80- class True final : public Predicate {
35+ template <PredicateLike PredicateType>
36+ class TrueImpl final : public PredicateType {
8137 public:
8238 // / \brief Returns the singleton instance
83- static const std::shared_ptr<True>& Instance ();
39+ static const std::shared_ptr<TrueImpl>& Instance () {
40+ static const std::shared_ptr<TrueImpl> instance =
41+ std::shared_ptr<TrueImpl>(new TrueImpl ());
42+ return instance;
43+ }
8444
8545 Operation op () const override { return Operation::kTrue ; }
8646
@@ -92,35 +52,49 @@ class True final : public Predicate {
9252 return other.op () == Operation::kTrue ;
9353 }
9454
95- private :
96- constexpr True () = default;
55+ protected :
56+ constexpr TrueImpl () = default;
9757};
9858
9959// / \brief An expression that is always false.
100- class False final : public Predicate {
60+ template <PredicateLike PredicateType>
61+ class FalseImpl final : public PredicateType {
10162 public:
10263 // / \brief Returns the singleton instance
103- static const std::shared_ptr<False>& Instance ();
64+ static const std::shared_ptr<PredicateType>& Instance () {
65+ static const std::shared_ptr<PredicateType> instance =
66+ std::shared_ptr<FalseImpl>(new FalseImpl ());
67+ return instance;
68+ }
10469
10570 Operation op () const override { return Operation::kFalse ; }
10671
10772 std::string ToString () const override { return " false" ; }
10873
109- std::shared_ptr<Predicate> Negate () const override ;
74+ std::shared_ptr<Predicate> Negate () const override {
75+ return TrueImpl<PredicateType>::Instance ();
76+ }
11077
11178 bool Equals (const Expression& other) const override {
11279 return other.op () == Operation::kFalse ;
11380 }
11481
11582 private:
116- constexpr False () = default;
83+ constexpr FalseImpl () = default;
11784};
11885
86+ template <PredicateLike PredicateType>
87+ std::shared_ptr<Predicate> TrueImpl<PredicateType>::Negate() const {
88+ return FalseImpl<PredicateType>::Instance ();
89+ }
90+
11991// / \brief An Expression that represents a logical AND operation between two expressions.
120- class AndImpl final : public Predicate {
92+ template <PredicateLike PredicateType>
93+ class AndImpl final : public PredicateType {
12194 public:
12295 // / \brief Constructs an And expression from two sub-expressions.
123- AndImpl (std::shared_ptr<Predicate> left, std::shared_ptr<Predicate> right);
96+ AndImpl (std::shared_ptr<Predicate> left, std::shared_ptr<Predicate> right)
97+ : left_(std::move(left)), right_(std::move(right)) {}
12498
12599 // / \brief Returns the left operand of the AND expression.
126100 const std::shared_ptr<Predicate>& left () const { return left_; }
@@ -130,105 +104,89 @@ class AndImpl final : public Predicate {
130104
131105 Operation op () const override { return Operation::kAnd ; }
132106
133- std::string ToString () const override ;
107+ std::string ToString () const override {
108+ return std::format (" ({} and {})" , left_->ToString (), right_->ToString ());
109+ }
134110
135- std::shared_ptr<Predicate > Negate () const override ;
111+ std::shared_ptr<PredicateType > Negate () const override ;
136112
137- bool Equals (const Expression& other) const override ;
113+ bool Equals (const Expression& expr) const override {
114+ if (expr.op () == Operation::kAnd ) {
115+ const auto & other =
116+ iceberg::internal::checked_cast<const AndImpl<PredicateType>&>(expr);
117+ return (left_->Equals (*other.left ()) && right_->Equals (*other.right ())) ||
118+ (left_->Equals (*other.right ()) && right_->Equals (*other.left ()));
119+ }
120+ return false ;
121+ }
138122
139123 private:
140124 std::shared_ptr<Predicate> left_;
141125 std::shared_ptr<Predicate> right_;
142126};
143127
144128// / \brief An Expression that represents a logical OR operation between two expressions.
145- class OrImpl final : public Predicate {
129+ template <PredicateLike PredicateType>
130+ class OrImpl final : public PredicateType {
146131 public:
147132 // / \brief Constructs an Or expression from two sub-expressions.
148- OrImpl (std::shared_ptr<Predicate> left, std::shared_ptr<Predicate> right);
133+ OrImpl (std::shared_ptr<PredicateType> left, std::shared_ptr<PredicateType> right)
134+ : left_(std::move(left)), right_(std::move(right)) {}
149135
150136 // / \brief Returns the left operand of the OR expression.
151- const std::shared_ptr<Predicate >& left () const { return left_; }
137+ const std::shared_ptr<PredicateType >& left () const { return left_; }
152138
153139 // / \brief Returns the right operand of the OR expression.
154- const std::shared_ptr<Predicate >& right () const { return right_; }
140+ const std::shared_ptr<PredicateType >& right () const { return right_; }
155141
156142 Operation op () const override { return Operation::kOr ; }
157143
158- std::string ToString () const override ;
144+ std::string ToString () const override {
145+ return std::format (" ({} or {})" , left_->ToString (), right_->ToString ());
146+ }
159147
160- std::shared_ptr<Predicate > Negate () const override ;
148+ std::shared_ptr<PredicateType > Negate () const override ;
161149
162- bool Equals (const Expression& other) const override ;
150+ bool Equals (const Expression& expr) const override {
151+ if (expr.op () == Operation::kOr ) {
152+ const auto & other =
153+ iceberg::internal::checked_cast<const OrImpl<PredicateType>&>(expr);
154+ return (left_->Equals (*other.left ()) && right_->Equals (*other.right ())) ||
155+ (left_->Equals (*other.right ()) && right_->Equals (*other.left ()));
156+ }
157+ return false ;
158+ }
163159
164160 private:
165- std::shared_ptr<Predicate > left_;
166- std::shared_ptr<Predicate > right_;
161+ std::shared_ptr<PredicateType > left_;
162+ std::shared_ptr<PredicateType > right_;
167163};
168164
169- // Implementation of True
170- const std::shared_ptr<True>& True::Instance () {
171- static const std::shared_ptr<True> instance{new True ()};
172- return instance;
173- }
174-
175- std::shared_ptr<Predicate> True::Negate () const { return False::Instance (); }
176-
177- // Implementation of False
178- const std::shared_ptr<False>& False::Instance () {
179- static const std::shared_ptr<False> instance = std::shared_ptr<False>(new False ());
180- return instance;
181- }
182-
183- std::shared_ptr<Predicate> False::Negate () const { return True::Instance (); }
184-
185- // Implementation of AndImpl
186- AndImpl::AndImpl (std::shared_ptr<Predicate> left, std::shared_ptr<Predicate> right)
187- : left_(std::move(left)), right_(std::move(right)) {}
188-
189- std::string AndImpl::ToString () const {
190- return std::format (" ({} and {})" , left_->ToString (), right_->ToString ());
191- }
192-
193- std::shared_ptr<Predicate> AndImpl::Negate () const {
165+ template <PredicateLike PredicateType>
166+ std::shared_ptr<PredicateType> AndImpl<PredicateType>::Negate() const {
194167 // De Morgan's law: not(A and B) = (not A) or (not B)
195168 auto left_negated = left_->Negate ();
196169 auto right_negated = right_->Negate ();
197- return std::make_shared<OrImpl>(left_negated, right_negated);
170+ return std::make_shared<OrImpl<PredicateType>>(std::move (left_negated),
171+ std::move (right_negated));
198172}
199173
200- bool AndImpl::Equals (const Expression& expr) const {
201- if (expr.op () == Operation::kAnd ) {
202- const auto & other = iceberg::internal::checked_cast<const AndImpl&>(expr);
203- return (left_->Equals (*other.left ()) && right_->Equals (*other.right ())) ||
204- (left_->Equals (*other.right ()) && right_->Equals (*other.left ()));
205- }
206- return false ;
207- }
208-
209- // Implementation of OrImpl
210- OrImpl::OrImpl (std::shared_ptr<Predicate> left, std::shared_ptr<Predicate> right)
211- : left_(std::move(left)), right_(std::move(right)) {}
212-
213- std::string OrImpl::ToString () const {
214- return std::format (" ({} or {})" , left_->ToString (), right_->ToString ());
215- }
216-
217- std::shared_ptr<Predicate> OrImpl::Negate () const {
174+ template <PredicateLike PredicateType>
175+ std::shared_ptr<PredicateType> OrImpl<PredicateType>::Negate() const {
218176 // De Morgan's law: not(A or B) = (not A) and (not B)
219177 auto left_negated = left_->Negate ();
220178 auto right_negated = right_->Negate ();
221- return std::make_shared<AndImpl>(left_negated, right_negated);
179+ return std::make_shared<AndImpl<PredicateType> >(left_negated, right_negated);
222180}
223181
224- bool OrImpl::Equals ( const Expression& expr) const {
225- if (expr. op () == Operation:: kOr ) {
226- const auto & other = iceberg::internal::checked_cast< const OrImpl&>(expr) ;
227- return (left_-> Equals (*other. left ()) && right_-> Equals (*other. right ())) ||
228- (left_-> Equals (*other. right ()) && right_-> Equals (*other. left ())) ;
229- }
230- return false ;
231- }
182+ using True = TrueImpl<Predicate>;
183+ using BoundTrue = TrueImpl<BoundPredicate>;
184+ using False = FalseImpl<Predicate> ;
185+ using BoundFalse = FalseImpl<BoundPredicate>;
186+ using AndPredicate = AndImpl<Predicate> ;
187+ using BoundAndPredicate = AndImpl<BoundPredicate>;
188+ using OrPredicate = OrImpl<Predicate> ;
189+ using BoundOrPredicate = OrImpl<BoundPredicate>;
232190
233191// Implementation of Predicate static factory methods
234192const std::shared_ptr<Predicate>& Predicate::AlwaysTrue () {
@@ -253,7 +211,7 @@ std::shared_ptr<Predicate> Predicate::And(std::shared_ptr<Predicate> left,
253211 return left;
254212 }
255213 */
256- return std::make_shared<AndImpl >(std::move (left), std::move (right));
214+ return std::make_shared<AndPredicate >(std::move (left), std::move (right));
257215}
258216
259217std::shared_ptr<Predicate> Predicate::Or (std::shared_ptr<Predicate> left,
@@ -268,7 +226,7 @@ std::shared_ptr<Predicate> Predicate::Or(std::shared_ptr<Predicate> left,
268226 return left;
269227 }
270228 */
271- return std::make_shared<OrImpl >(std::move (left), std::move (right));
229+ return std::make_shared<OrPredicate >(std::move (left), std::move (right));
272230}
273231
274232// / Unary predicate, for example, `a IS NULL`, which `a` is a Term.
0 commit comments