[Groonga-commit] groonga/grnxx at 151fcd1 [master] Add LogicalOrNode.

アーカイブの一覧に戻る

susumu.yata null+****@clear*****
Mon Aug 11 17:46:01 JST 2014


susumu.yata	2014-08-11 17:46:01 +0900 (Mon, 11 Aug 2014)

  New Revision: 151fcd1bc403be4dee434e4ac15b062680deba5d
  https://github.com/groonga/grnxx/commit/151fcd1bc403be4dee434e4ac15b062680deba5d

  Message:
    Add LogicalOrNode.

  Modified files:
    lib/grnxx/expression2.cpp

  Modified: lib/grnxx/expression2.cpp (+182 -3)
===================================================================
--- lib/grnxx/expression2.cpp    2014-08-11 13:11:12 +0900 (eaafcf4)
+++ lib/grnxx/expression2.cpp    2014-08-11 17:46:01 +0900 (81c2b61)
@@ -906,10 +906,189 @@ bool LogicalAndNode::evaluate(Error *error,
   return true;
 }
 
-// TODO: Other binary operators.
-//  // Logical operators.
-//  LOGICAL_OR_OPERATOR,   // For Bool.
+// ---- LogicalOrNode ----
+
+class LogicalOrNode : public BinaryNode<Bool, Bool, Bool> {
+ public:
+  using Value = Bool;
+  using Arg1 = Bool;
+  using Arg2 = Bool;
+
+  LogicalOrNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Bool, Bool, Bool>(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<Bool> results);
+
+ private:
+  Array<Record> temp_records_;
+};
+
+bool LogicalOrNode::filter(Error *error,
+                            ArrayCRef<Record> input_records,
+                            ArrayRef<Record> *output_records) {
+  // Apply the 1st argument filter to "input_records" and store the result into
+  // "temp_records_", Then, appends a sentinel to the end.
+  if (!temp_records_.resize(error, input_records.size() + 2)) {
+    return false;
+  }
+  ArrayRef<Record> ref1 = temp_records_;
+  if (!arg1_->filter(error, input_records, &ref1)) {
+    return false;
+  }
+  if (ref1.size() == 0) {
+    // There are no arg1-true records.
+    return arg2_->filter(error, input_records, output_records);
+  } else if (ref1.size() == temp_records_.size()) {
+    // There are no arg1-false records.
+    if (input_records != *output_records) {
+      for (Int i = 0; i < input_records.size(); ++i) {
+        output_records->set(i, input_records.get(i));
+      }
+    }
+    return true;
+  }
+  temp_records_.set_row_id(ref1.size(), NULL_ROW_ID);
+
+  // Append arg1-false records to the end of "temp_records_".
+  // Then, applies the 2nd argument filter to it and appends a sentinel.
+  ArrayRef<Record> ref2 =
+      temp_records_.ref(ref1.size() + 1, input_records.size() - ref1.size());
+  Int arg1_count = 0;
+  Int arg2_count = 0;
+  for (Int i = 0; i < input_records.size(); ++i) {
+    if (input_records.get_row_id(i) == ref1.get_row_id(arg1_count)) {
+      ++arg1_count;
+    } else {
+      ref2.set(arg2_count, input_records.get(i));
+      ++arg2_count;
+    }
+  }
+  if (!arg2_->filter(error, ref2, &ref2)) {
+    return false;
+  }
+  if (ref2.size() == 0) {
+    // There are no arg2-true records.
+    for (Int i = 0; i < ref1.size(); ++i) {
+      output_records->set(i, ref1.get(i));
+    }
+    *output_records = output_records->ref(0, ref1.size());
+    return true;
+  } else if (ref2.size() == arg2_count) {
+    // There are no arg2-false records.
+    if (input_records != *output_records) {
+      for (Int i = 0; i < input_records.size(); ++i) {
+        output_records->set(i, input_records.get(i));
+      }
+      *output_records = output_records->ref(0, input_records.size());
+    }
+    return true;
+  }
+  temp_records_.set_row_id(ref1.size() + 1 + ref2.size(), NULL_ROW_ID);
+
+  // Merge the arg1-true records and the arg2-true records.
+  arg1_count = 0;
+  arg2_count = 0;
+  for (Int i = 0; i < input_records.size(); ++i) {
+    if (input_records.get_row_id(i) == ref1.get_row_id(arg1_count)) {
+      output_records->set(arg1_count + arg2_count, input_records.get(i));
+      ++arg1_count;
+    } else if (input_records.get_row_id(i) == ref2.get_row_id(arg2_count)) {
+      output_records->set(arg1_count + arg2_count, input_records.get(i));
+      ++arg2_count;
+    }
+  }
+  *output_records = output_records->ref(0, arg1_count + arg2_count);
+  return true;
+}
+
+bool LogicalOrNode::evaluate(Error *error,
+                              ArrayCRef<Record> records,
+                              ArrayRef<Bool> results) {
+  // Apply the 1st argument filter to "records" and store the result into
+  // "temp_records_", Then, appends a sentinel to the end.
+  if (!temp_records_.resize(error, records.size() + 2)) {
+    return false;
+  }
+  ArrayRef<Record> ref1 = temp_records_;
+  if (!arg1_->filter(error, records, &ref1)) {
+    return false;
+  }
+  if (ref1.size() == 0) {
+    // There are no arg1-true records.
+    return arg2_->evaluate(error, records, results);
+  } else if (ref1.size() == temp_records_.size()) {
+    // There are no arg1-false records.
+    // TODO: Fill the array per 64 bits.
+    for (Int i = 0; i < records.size(); ++i) {
+      results.set(i, true);
+    }
+    return true;
+  }
+  temp_records_.set_row_id(ref1.size(), NULL_ROW_ID);
+
+  // Append arg1-false records to the end of "temp_records_".
+  // Then, applies the 2nd argument filter to it and appends a sentinel.
+  ArrayRef<Record> ref2 =
+      temp_records_.ref(ref1.size() + 1, records.size() - ref1.size());
+  Int arg1_count = 0;
+  Int arg2_count = 0;
+  for (Int i = 0; i < records.size(); ++i) {
+    if (records.get_row_id(i) == ref1.get_row_id(arg1_count)) {
+      ++arg1_count;
+    } else {
+      ref2.set(arg2_count, records.get(i));
+      ++arg2_count;
+    }
+  }
+  if (!arg2_->filter(error, ref2, &ref2)) {
+    return false;
+  }
+  if (ref2.size() == 0) {
+    // There are no arg2-true records.
+    arg1_count = 0;
+    for (Int i = 0; i < records.size(); ++i) {
+      if (records.get_row_id(i) == ref1.get_row_id(arg1_count)) {
+        results.set(i, true);
+        ++arg1_count;
+      } else {
+        results.set(i, false);
+      }
+    }
+    return true;
+  } else if (ref2.size() == arg2_count) {
+    // There are no arg2-false records.
+    // TODO: Fill the array per 64 bits.
+    for (Int i = 0; i < records.size(); ++i) {
+      results.set(i, true);
+    }
+    return true;
+  }
+  temp_records_.set_row_id(ref1.size() + 1 + ref2.size(), NULL_ROW_ID);
 
+  // Merge the arg1-true records and the arg2-true records.
+  arg1_count = 0;
+  arg2_count = 0;
+  for (Int i = 0; i < records.size(); ++i) {
+    if (records.get_row_id(i) == ref1.get_row_id(arg1_count)) {
+      results.set(i, true);
+      ++arg1_count;
+    } else if (records.get_row_id(i) == ref2.get_row_id(arg2_count)) {
+      results.set(i, true);
+      ++arg2_count;
+    } else {
+      results.set(i, false);
+    }
+  }
+  return true;
+}
+
+// TODO: Other binary operators.
 //  // Equality operators.
 //  EQUAL_OPERATOR,      // For any types.
 //  NOT_EQUAL_OPERATOR,  // For any types.
-------------- next part --------------
HTML����������������������������...
ダウンロード 



More information about the Groonga-commit mailing list
アーカイブの一覧に戻る