susumu.yata
null+****@clear*****
Thu Jul 17 12:52:13 JST 2014
susumu.yata 2014-07-17 12:52:13 +0900 (Thu, 17 Jul 2014) New Revision: 2d7b2eaa93f5de101e5175e7392e847ea8f6afcc https://github.com/groonga/grnxx/commit/2d7b2eaa93f5de101e5175e7392e847ea8f6afcc Message: Specialize LOGICAL_AND/OR. Modified files: include/grnxx/expression.hpp lib/grnxx/expression.cpp test/test_grnxx.cpp Modified: include/grnxx/expression.hpp (+4 -3) =================================================================== --- include/grnxx/expression.hpp 2014-07-17 10:40:54 +0900 (d131315) +++ include/grnxx/expression.hpp 2014-07-17 12:52:13 +0900 (99f5ea9) @@ -161,9 +161,10 @@ class ExpressionBuilder { explicit ExpressionBuilder(const Table *table); - // Push an operator && or ||. - template <typename T> - bool push_logical_operator(Error *error); + // Push an operator &&. + bool push_logical_and_operator(Error *error); + // Push an operator ||. + bool push_logical_or_operator(Error *error); // Push an operator == or !=. template <typename T> bool push_equality_operator(Error *error); Modified: lib/grnxx/expression.cpp (+135 -46) =================================================================== --- lib/grnxx/expression.cpp 2014-07-17 10:40:54 +0900 (aee95ca) +++ lib/grnxx/expression.cpp 2014-07-17 12:52:13 +0900 (c89d398) @@ -245,28 +245,6 @@ class ColumnNode : public Node<T> { // -- OperatorNode -- -struct LogicalAnd { - struct Functor { - using Arg1 = Bool; - using Arg2 = Bool; - using Result = Bool; - Bool operator()(Arg1 lhs, Arg2 rhs) const { - return lhs && rhs; - }; - }; -}; - -struct LogicalOr { - struct Functor { - using Arg1 = Bool; - using Arg2 = Bool; - using Result = Bool; - Bool operator()(Arg1 lhs, Arg2 rhs) const { - return lhs || rhs; - }; - }; -}; - struct Equal { template <typename T> struct Functor { @@ -394,22 +372,7 @@ class BinaryNode : public Node<typename Op::Result> { return OPERATOR_NODE; } - bool evaluate(Error *error, const RecordSet &record_set) { - try { - this->values_.resize(record_set.size()); - } catch (...) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - return false; - } - if (!lhs_->evaluate(error, record_set) || - !rhs_->evaluate(error, record_set)) { - return false; - } - for (Int i = 0; i < record_set.size(); ++i) { - this->values_[i] = operator_(lhs_->get(i), rhs_->get(i)); - } - return true; - } + bool evaluate(Error *error, const RecordSet &record_set); private: Op operator_; @@ -417,6 +380,109 @@ class BinaryNode : public Node<typename Op::Result> { unique_ptr<Node<Arg2>> rhs_; }; +template <typename Op> +bool BinaryNode<Op>::evaluate(Error *error, const RecordSet &record_set) { + try { + this->values_.resize(record_set.size()); + } catch (...) { + GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); + return false; + } + if (!lhs_->evaluate(error, record_set) || + !rhs_->evaluate(error, record_set)) { + return false; + } + for (Int i = 0; i < record_set.size(); ++i) { + this->values_[i] = operator_(lhs_->get(i), rhs_->get(i)); + } + return true; +} + +class LogicalAndNode : public Node<Bool> { + public: + LogicalAndNode(unique_ptr<ExpressionNode> &&lhs, + unique_ptr<ExpressionNode> &&rhs) + : Node<Bool>(), + lhs_(static_cast<Node<Bool> *>(lhs.release())), + rhs_(static_cast<Node<Bool> *>(rhs.release())) {} + virtual ~LogicalAndNode() {} + + NodeType node_type() const { + return OPERATOR_NODE; + } + + bool filter(Error *error, RecordSet *record_set); + + bool evaluate(Error *error, const RecordSet &record_set); + + private: + unique_ptr<Node<Bool>> lhs_; + unique_ptr<Node<Bool>> rhs_; +}; + +bool LogicalAndNode::filter(Error *error, RecordSet *record_set) { + return lhs_->filter(error, record_set) && rhs_->filter(error, record_set); +} + +bool LogicalAndNode::evaluate(Error *error, const RecordSet &record_set) { + // TODO: Don't evaluate rhs entries if lhs entries are false. + try { + this->values_.resize(record_set.size()); + } catch (...) { + GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); + return false; + } + if (!lhs_->evaluate(error, record_set) || + !rhs_->evaluate(error, record_set)) { + return false; + } + for (Int i = 0; i < record_set.size(); ++i) { + this->values_[i] = lhs_->get(i) && rhs_->get(i); + } + return true; +} + +class LogicalOrNode : public Node<Bool> { + public: + LogicalOrNode(unique_ptr<ExpressionNode> &&lhs, + unique_ptr<ExpressionNode> &&rhs) + : Node<Bool>(), + lhs_(static_cast<Node<Bool> *>(lhs.release())), + rhs_(static_cast<Node<Bool> *>(rhs.release())) {} + virtual ~LogicalOrNode() {} + + NodeType node_type() const { + return OPERATOR_NODE; + } + + // TODO: filter() must be specialized. +// bool filter(Error *error, RecordSet *record_set); + + bool evaluate(Error *error, const RecordSet &record_set); + + private: + unique_ptr<Node<Bool>> lhs_; + unique_ptr<Node<Bool>> rhs_; +}; + +bool LogicalOrNode::evaluate(Error *error, const RecordSet &record_set) { + // TODO: Don't evaluate rhs entries if lhs entries are true. + try { + this->values_.resize(record_set.size()); + } catch (...) { + GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); + return false; + } + if (!lhs_->evaluate(error, record_set) || + !rhs_->evaluate(error, record_set)) { + return false; + } + for (Int i = 0; i < record_set.size(); ++i) { + this->values_[i] = lhs_->get(i) || rhs_->get(i); + } + return true; +} + } // namespace // -- Expression -- @@ -572,10 +638,10 @@ bool ExpressionBuilder::push_operator(Error *error, OperatorType operator_type) { switch (operator_type) { case LOGICAL_AND_OPERATOR: { - return push_logical_operator<LogicalAnd>(error); + return push_logical_and_operator(error); } case LOGICAL_OR_OPERATOR: { - return push_logical_operator<LogicalOr>(error); + return push_logical_or_operator(error); } case EQUAL_OPERATOR: { return push_equality_operator<Equal>(error); @@ -628,8 +694,7 @@ unique_ptr<Expression> ExpressionBuilder::release(Error *error) { ExpressionBuilder::ExpressionBuilder(const Table *table) : table_(table) {} -template <typename T> -bool ExpressionBuilder::push_logical_operator(Error *error) { +bool ExpressionBuilder::push_logical_and_operator(Error *error) { if (stack_.size() < 2) { // TODO: Define a better error code. GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Not enough operands"); @@ -643,10 +708,34 @@ bool ExpressionBuilder::push_logical_operator(Error *error) { GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Wrong type"); return false; } - unique_ptr<ExpressionNode> node; - typename T::Functor functor; - node.reset(new (nothrow) BinaryNode<decltype(functor)>( - functor, std::move(lhs), std::move(rhs))); + unique_ptr<ExpressionNode> node( + new (nothrow) LogicalAndNode(std::move(lhs), std::move(rhs))); + if (!node) { + GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); + return false; + } + stack_.pop_back(); + stack_.back() = std::move(node); + return true; +} + + +bool ExpressionBuilder::push_logical_or_operator(Error *error) { + if (stack_.size() < 2) { + // TODO: Define a better error code. + GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Not enough operands"); + return false; + } + auto &lhs = stack_[stack_.size() - 2]; + auto &rhs = stack_[stack_.size() - 1]; + if ((lhs->data_type() != BOOL_DATA) || + (rhs->data_type() != BOOL_DATA)) { + // TODO: Define a better error code. + GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Wrong type"); + return false; + } + unique_ptr<ExpressionNode> node( + new (nothrow) LogicalOrNode(std::move(lhs), std::move(rhs))); if (!node) { GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); return false; Modified: test/test_grnxx.cpp (+17 -0) =================================================================== --- test/test_grnxx.cpp 2014-07-17 10:40:54 +0900 (0a29cfb) +++ test/test_grnxx.cpp 2014-07-17 12:52:13 +0900 (28fbd11) @@ -534,6 +534,23 @@ void test_expression() { assert(cursor); assert(cursor->read_all(&error, &record_set) == 2); + // 論理演算を試す. + assert(builder->push_datum(&error, grnxx::Bool(false))); + assert(builder->push_column(&error, "BoolColumn")); + assert(builder->push_operator(&error, grnxx::LOGICAL_OR_OPERATOR)); + expression = builder->release(&error); + assert(expression); + + // フィルタとして使ったときの結果を確認する. + assert(expression->filter(&error, &record_set)); + assert(record_set.size() == 1); + assert(record_set.get(0).row_id == 2); + + record_set.clear(); + cursor = table->create_cursor(&error); + assert(cursor); + assert(cursor->read_all(&error, &record_set) == 2); + // ビット論理積を試す. assert(builder->push_column(&error, "IntColumn")); assert(builder->push_datum(&error, grnxx::Int(255))); -------------- next part -------------- HTML����������������������������...Download