11#pragma once
22
3+ #include < memory>
34#include < stdexcept>
45
56namespace attwoodn ::expression_tree {
@@ -53,13 +54,13 @@ namespace attwoodn::expression_tree {
5354 }
5455 }
5556
56- enum class boolean_op {
57- AND,
58- OR
59- };
60-
6157 namespace node {
6258
59+ enum class boolean_op {
60+ AND,
61+ OR
62+ };
63+
6364 template <typename Obj, typename LeftChild, typename RightChild>
6465 class expression_tree_op_node ;
6566
@@ -84,6 +85,16 @@ namespace attwoodn::expression_tree {
8485 * nodes under this node in the expression tree.
8586 */
8687 virtual bool evaluate (const Obj& obj) = 0;
88+
89+ /* *
90+ * @brief Performs a deep clone of pointers to this base class to avoid object slicing.
91+ */
92+ auto clone () {
93+ return std::unique_ptr<expression_tree_node<Obj>>(clone_impl ());
94+ }
95+
96+ protected:
97+ virtual expression_tree_node<Obj>* clone_impl () const = 0;
8798 };
8899
89100 /* *
@@ -209,6 +220,11 @@ namespace attwoodn::expression_tree {
209220 boolean_op bool_op_;
210221 LeftChild* left_ { nullptr };
211222 RightChild* right_ { nullptr };
223+
224+ protected:
225+ virtual expression_tree_op_node<Obj, LeftChild, RightChild>* clone_impl () const override {
226+ return new expression_tree_op_node<Obj, LeftChild, RightChild>(*this );
227+ }
212228 };
213229
214230 /* *
@@ -332,6 +348,11 @@ namespace attwoodn::expression_tree {
332348 const CompValue Obj::* member_var_ = nullptr ;
333349 Op logical_op_;
334350 CompValue comp_value_;
351+
352+ protected:
353+ virtual expression_tree_leaf_node<Obj, Op, CompValue>* clone_impl () const override {
354+ return new expression_tree_leaf_node<Obj, Op, CompValue>(*this );
355+ }
335356 };
336357
337358 }
@@ -362,4 +383,67 @@ namespace attwoodn::expression_tree {
362383 node::expression_tree_leaf_node<Obj, Op, CompValue>* make_expr ( CompValue (Obj::* member_func)() const , Op op, CompValue comp_value ) {
363384 return new node::expression_tree_leaf_node<Obj, Op, CompValue>( member_func, op, comp_value );
364385 }
386+
387+ template <typename Obj>
388+ class expression_tree {
389+ public:
390+ expression_tree () = delete ;
391+
392+ expression_tree (node::expression_tree_node<Obj>* expr) {
393+ if (!expr) {
394+ throw std::runtime_error (" Attempted to construct an expression_tree with a null root expression node" );
395+ }
396+
397+ expr_ = expr->clone ().release ();
398+ delete expr;
399+ }
400+
401+ expression_tree (const expression_tree& other)
402+ : expr_(other.expr_->clone ().release()) {}
403+
404+ expression_tree (expression_tree&& other)
405+ : expr_(other.expr_) {
406+ other.expr_ = nullptr ;
407+ }
408+
409+ expression_tree& operator =(const expression_tree& other) {
410+ delete expr_;
411+ expr_ = other.expr_ ->clone ().release ();
412+ return *this ;
413+ }
414+
415+ expression_tree& operator =(const expression_tree&& other) {
416+ if (this != &other) {
417+ delete expr_;
418+ expr_ = other.expr_ ;
419+ other.expr_ = nullptr ;
420+ }
421+ return *this ;
422+ }
423+
424+ ~expression_tree () {
425+ delete expr_;
426+ }
427+
428+ /* *
429+ * @brief Evaluates the given object to determine if it satisfies the expressions defined in this expression tree.
430+ *
431+ * @returns True if the given object satisfied the expression tree conditions;
432+ * False if the given object did not satisfy the expression tree conditions.
433+ */
434+ bool evaluate (const Obj& obj) {
435+ if (!expr_) {
436+ throw std::runtime_error (" expression_tree has a null root expression node" );
437+ }
438+
439+ try {
440+ return expr_->evaluate (obj);
441+ } catch (std::exception& e) {
442+ return false ;
443+ }
444+ }
445+
446+ private:
447+ node::expression_tree_node<Obj>* expr_ = nullptr ;
448+ };
365449}
0 commit comments