[Groonga-commit] groonga/grnxx at 2d7b2ea [master] Specialize LOGICAL_AND/OR.

Back to archive index

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 



More information about the Groonga-commit mailing list
Back to archive index