[Groonga-commit] groonga/grnxx at cdf0659 [master] Implement subexpression.

Back to archive index

susumu.yata null+****@clear*****
Thu Sep 4 21:26:51 JST 2014


susumu.yata	2014-09-04 21:26:51 +0900 (Thu, 04 Sep 2014)

  New Revision: cdf06599ffe5c760e31f89cbc0ff95719a8541ce
  https://github.com/groonga/grnxx/commit/cdf06599ffe5c760e31f89cbc0ff95719a8541ce

  Message:
    Implement subexpression.

  Modified files:
    lib/grnxx/expression.cpp

  Modified: lib/grnxx/expression.cpp (+330 -4)
===================================================================
--- lib/grnxx/expression.cpp    2014-09-04 21:11:16 +0900 (e538b4a)
+++ lib/grnxx/expression.cpp    2014-09-04 21:26:51 +0900 (75bb1ff)
@@ -2455,6 +2455,202 @@ bool SubscriptNode<Float>::evaluate(Error *error,
   return true;
 }
 
+// ---- ReferenceNode ----
+
+template <typename T>
+class ReferenceNode : public BinaryNode<T, Int, T> {
+ public:
+  using Value = T;
+  using Arg1 = Int;
+  using Arg2 = T;
+
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) ReferenceNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  ReferenceNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)),
+        temp_records_() {}
+
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+
+ private:
+  Array<Record> temp_records_;
+};
+
+template <typename T>
+bool ReferenceNode<T>::evaluate(Error *error,
+                                ArrayCRef<Record> records,
+                                ArrayRef<Value> results) {
+  if (!this->fill_arg1_values(error, records)) {
+    return false;
+  }
+  if (!temp_records_.resize(error, records.size())) {
+    return false;
+  }
+  for (Int i = 0; i < records.size(); ++i) {
+    temp_records_.set_row_id(i, this->arg1_values_[i]);
+    temp_records_.set_score(i, records.get_score(i));
+  }
+  return this->arg2_->evaluate(error, temp_records_, results);
+}
+
+template <>
+class ReferenceNode<Bool> : public BinaryNode<Bool, Int, Bool> {
+ public:
+  using Value = Bool;
+  using Arg1 = Int;
+  using Arg2 = Bool;
+
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) ReferenceNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  ReferenceNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)),
+        temp_records_() {}
+
+  bool filter(Error *error,
+              ArrayCRef<Record> input_records,
+              ArrayRef<Record> *output_records);
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+
+ private:
+  Array<Record> temp_records_;
+};
+
+bool ReferenceNode<Bool>::filter(Error *error,
+                                 ArrayCRef<Record> input_records,
+                                 ArrayRef<Record> *output_records) {
+  if (!this->fill_arg1_values(error, input_records)) {
+    return false;
+  }
+  if (!temp_records_.resize(error, input_records.size())) {
+    return false;
+  }
+  for (Int i = 0; i < input_records.size(); ++i) {
+    temp_records_.set_row_id(i, this->arg1_values_[i]);
+    temp_records_.set_score(i, input_records.get_score(i));
+  }
+  auto ref = temp_records_.ref();
+  if (!this->arg2_->filter(error, ref, &ref)) {
+    return false;
+  }
+  Int count = 0;
+  for (Int i = 0; i < input_records.size(); ++i) {
+    if (this->arg1_values_[i] == ref.get_row_id(count)) {
+      output_records->set(count, input_records[i]);
+      ++count;
+    }
+  }
+  *output_records = output_records->ref(0, count);
+  return true;
+}
+
+bool ReferenceNode<Bool>::evaluate(Error *error,
+                                   ArrayCRef<Record> records,
+                                   ArrayRef<Value> results) {
+  if (!this->fill_arg1_values(error, records)) {
+    return false;
+  }
+  if (!temp_records_.resize(error, records.size())) {
+    return false;
+  }
+  for (Int i = 0; i < records.size(); ++i) {
+    temp_records_.set_row_id(i, this->arg1_values_[i]);
+    temp_records_.set_score(i, records.get_score(i));
+  }
+  return this->arg2_->evaluate(error, temp_records_, results);
+}
+
+template <>
+class ReferenceNode<Float> : public BinaryNode<Float, Int, Float> {
+ public:
+  using Value = Float;
+  using Arg1 = Int;
+  using Arg2 = Float;
+
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) ReferenceNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  ReferenceNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)),
+        temp_records_() {}
+
+  bool adjust(Error *error, ArrayRef<Record> records);
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+
+ private:
+  Array<Record> temp_records_;
+};
+
+bool ReferenceNode<Float>::adjust(Error *error,
+                                  ArrayRef<Record> records) {
+  if (!this->fill_arg1_values(error, records)) {
+    return false;
+  }
+  if (!temp_records_.resize(error, records.size())) {
+    return false;
+  }
+  for (Int i = 0; i < records.size(); ++i) {
+    temp_records_.set_row_id(i, this->arg1_values_[i]);
+    temp_records_.set_score(i, records.get_score(i));
+  }
+  if (!this->arg2_->adjust(error, temp_records_)) {
+    return false;
+  }
+  for (Int i = 0; i < records.size(); ++i) {
+    records.set_score(i, temp_records_.get_score(i));
+  }
+  return true;
+}
+
+bool ReferenceNode<Float>::evaluate(Error *error,
+                                    ArrayCRef<Record> records,
+                                    ArrayRef<Value> results) {
+  if (!this->fill_arg1_values(error, records)) {
+    return false;
+  }
+  if (!temp_records_.resize(error, records.size())) {
+    return false;
+  }
+  for (Int i = 0; i < records.size(); ++i) {
+    temp_records_.set_row_id(i, this->arg1_values_[i]);
+    temp_records_.set_score(i, records.get_score(i));
+  }
+  return this->arg2_->evaluate(error, temp_records_, results);
+}
+
+// -- Builder --
+
 class Builder {
  public:
   // Create an object for building an expression.
@@ -2470,6 +2666,10 @@ class Builder {
   const Table *table() const {
     return table_;
   }
+  // Return the latest node.
+  const Node *latest_node() const {
+    return (stack_.size() != 0) ? stack_.back().get() : nullptr;
+  }
 
   // Push a datum.
   //
@@ -2499,6 +2699,20 @@ class Builder {
   // "error" != nullptr.
   bool push_operator(Error *error, OperatorType operator_type);
 
+  // Push a node.
+  //
+  // On success, returns true.
+  // On failure, returns false and stores error information into "*error" if
+  // "error" != nullptr.
+  bool push_node(Error *error, unique_ptr<Node> &&node);
+
+  // Push a reference operator.
+  //
+  // On success, returns true.
+  // On failure, returns false and stores error information into "*error" if
+  // "error" != nullptr.
+  bool push_reference(Error *error);
+
   // Clear the internal stack.
   void clear();
 
@@ -2570,6 +2784,12 @@ class Builder {
       Error *error,
       unique_ptr<Node> &&arg1,
       unique_ptr<Node> &&arg2);
+
+  // Create a reference node.
+  unique_ptr<Node> create_reference_node(
+      Error *error,
+      unique_ptr<Node> &&arg1,
+      unique_ptr<Node> &&arg2);
 };
 
 
@@ -2647,6 +2867,27 @@ bool Builder::push_operator(Error *error, OperatorType operator_type) {
   }
 }
 
+bool Builder::push_node(Error *error, unique_ptr<Node> &&node) {
+  return stack_.push_back(error, std::move(node));
+}
+
+bool Builder::push_reference(Error *error) {
+  if (stack_.size() < 2) {
+    GRNXX_ERROR_SET(error, INVALID_OPERAND, "Not enough operands");
+    return false;
+  }
+  unique_ptr<Node> arg1 = std::move(stack_[stack_.size() - 2]);
+  unique_ptr<Node> arg2 = std::move(stack_[stack_.size() - 1]);
+  stack_.resize(nullptr, stack_.size() - 2);
+  unique_ptr<Node> node =
+      create_reference_node(error, std::move(arg1), std::move(arg2));
+  if (!node) {
+    return false;
+  }
+  stack_.push_back(nullptr, std::move(node));
+  return true;
+}
+
 void Builder::clear() {
   stack_.clear();
 }
@@ -3170,6 +3411,58 @@ unique_ptr<Node> Builder::create_subscript_node(
   }
 }
 
+unique_ptr<Node> Builder::create_reference_node(
+    Error *error,
+    unique_ptr<Node> &&arg1,
+    unique_ptr<Node> &&arg2) {
+  switch (arg2->data_type()) {
+    case BOOL_DATA: {
+      return ReferenceNode<Bool>::create(
+          error, std::move(arg1), std::move(arg2));
+    }
+    case INT_DATA: {
+      return ReferenceNode<Int>::create(
+          error, std::move(arg1), std::move(arg2));
+    }
+    case FLOAT_DATA: {
+      return ReferenceNode<Float>::create(
+          error, std::move(arg1), std::move(arg2));
+    }
+    case GEO_POINT_DATA: {
+      return ReferenceNode<GeoPoint>::create(
+          error, std::move(arg1), std::move(arg2));
+    }
+    case TEXT_DATA: {
+      return ReferenceNode<Text>::create(
+          error, std::move(arg1), std::move(arg2));
+    }
+    case BOOL_VECTOR_DATA: {
+      return ReferenceNode<Vector<Bool>>::create(
+          error, std::move(arg1), std::move(arg2));
+    }
+    case INT_VECTOR_DATA: {
+      return ReferenceNode<Vector<Int>>::create(
+          error, std::move(arg1), std::move(arg2));
+    }
+    case FLOAT_VECTOR_DATA: {
+      return ReferenceNode<Vector<Float>>::create(
+          error, std::move(arg1), std::move(arg2));
+    }
+    case GEO_POINT_VECTOR_DATA: {
+      return ReferenceNode<Vector<GeoPoint>>::create(
+          error, std::move(arg1), std::move(arg2));
+    }
+    case TEXT_VECTOR_DATA: {
+      return ReferenceNode<Vector<Text>>::create(
+          error, std::move(arg1), std::move(arg2));
+    }
+    default: {
+      GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
+      return nullptr;
+    }
+  }
+}
+
 }  // namespace expression
 
 using namespace expression;
@@ -3385,13 +3678,46 @@ bool ExpressionBuilder::push_operator(Error *error,
 }
 
 bool ExpressionBuilder::begin_subexpression(Error *error) {
-  GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-  return false;
+  const Node *latest_node = builders_.back()->latest_node();
+std::cerr << "LINE: " << __LINE__ << std::endl;
+  if (!latest_node) {
+    GRNXX_ERROR_SET(error, INVALID_OPERAND, "Not enough operands");
+    return false;
+  }
+std::cerr << "LINE: " << __LINE__ << std::endl;
+  if (!latest_node->ref_table()) {
+    GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
+    return false;
+  }
+std::cerr << "LINE: " << __LINE__ << std::endl;
+  unique_ptr<Builder> subexpression_builder =
+      Builder::create(error, latest_node->ref_table());
+std::cerr << "LINE: " << __LINE__ << std::endl;
+  if (!subexpression_builder) {
+    return false;
+  }
+std::cerr << "LINE: " << __LINE__ << std::endl;
+  if (!builders_.push_back(error, std::move(subexpression_builder))) {
+    return false;
+  }
+std::cerr << "LINE: " << __LINE__ << std::endl;
+  return true;
 }
 
 bool ExpressionBuilder::end_subexpression(Error *error) {
-  GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-  return false;
+  if (builders_.size() <= 1) {
+    GRNXX_ERROR_SET(error, INVALID_OPERATION, "Subexpression not found");
+    return false;
+  }
+  unique_ptr<Node> node = builders_.back()->release(error);
+  if (!node) {
+    return false;
+  }
+  builders_.pop_back();
+  if (!builders_.back()->push_node(error, std::move(node))) {
+    return false;
+  }
+  return builders_.back()->push_reference(error);
 }
 
 void ExpressionBuilder::clear() {
-------------- next part --------------
HTML����������������������������...
Download 



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