susumu.yata
null+****@clear*****
Mon Jul 14 15:37:44 JST 2014
susumu.yata 2014-07-14 15:37:44 +0900 (Mon, 14 Jul 2014) New Revision: ecb97581b46cd8437fef7839b502a5c137d7f2ca https://github.com/groonga/grnxx/commit/ecb97581b46cd8437fef7839b502a5c137d7f2ca Message: Add logical operators. Modified files: include/grnxx/expression.hpp lib/grnxx/expression.cpp test/test_grnxx.cpp Modified: include/grnxx/expression.hpp (+7 -0) =================================================================== --- include/grnxx/expression.hpp 2014-07-14 15:12:20 +0900 (4ed0b7b) +++ include/grnxx/expression.hpp 2014-07-14 15:37:44 +0900 (1fb97cb) @@ -12,6 +12,10 @@ enum OperatorType { // -- Binary operators -- + // Logical operators. + LOGICAL_AND_OPERATOR, + LOGICAL_OR_OPERATOR, + // Equality operators. EQUAL_OPERATOR, NOT_EQUAL_OPERATOR, @@ -122,6 +126,9 @@ class ExpressionBuilder { explicit ExpressionBuilder(const Table *table); + // Push an operator && or ||. + template <typename T> + bool push_logical_operator(Error *error); // Push an operator == or !=. template <typename T> bool push_equality_operator(Error *error); Modified: lib/grnxx/expression.cpp (+56 -0) =================================================================== --- lib/grnxx/expression.cpp 2014-07-14 15:12:20 +0900 (77cf135) +++ lib/grnxx/expression.cpp 2014-07-14 15:37:44 +0900 (3d8ab70) @@ -216,6 +216,28 @@ 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 { @@ -452,6 +474,12 @@ bool ExpressionBuilder::push_column(Error *error, String name) { bool ExpressionBuilder::push_operator(Error *error, OperatorType operator_type) { switch (operator_type) { + case LOGICAL_AND_OPERATOR: { + return push_logical_operator<LogicalAnd>(error); + } + case LOGICAL_OR_OPERATOR: { + return push_logical_operator<LogicalOr>(error); + } case EQUAL_OPERATOR: { return push_equality_operator<Equal>(error); } @@ -495,6 +523,34 @@ unique_ptr<Expression> ExpressionBuilder::release(Error *error) { ExpressionBuilder::ExpressionBuilder(const Table *table) : table_(table) {} template <typename T> +bool ExpressionBuilder::push_logical_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; + typename T::Functor functor; + node.reset(new (nothrow) BinaryNode<decltype(functor)>( + functor, 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; +} + +template <typename T> bool ExpressionBuilder::push_equality_operator(Error *error) { if (stack_.size() < 2) { // TODO: Define a better error code. Modified: test/test_grnxx.cpp (+19 -0) =================================================================== --- test/test_grnxx.cpp 2014-07-14 15:12:20 +0900 (a8bb175) +++ test/test_grnxx.cpp 2014-07-14 15:37:44 +0900 (be38fa6) @@ -416,6 +416,25 @@ void test_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, grnxx::CursorOptions()); + assert(cursor); + assert(cursor->read(&error, 2, &record_set) == 2); + + // 論理演算を試す. + assert(builder->push_column(&error, "IntColumn")); + assert(builder->push_datum(&error, grnxx::Int(300))); + assert(builder->push_operator(&error, grnxx::GREATER_OPERATOR)); + assert(builder->push_column(&error, "BoolColumn")); + assert(builder->push_operator(&error, grnxx::LOGICAL_AND_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); } } // namespace -------------- next part -------------- HTML����������������������������... 下載