[Groonga-commit] groonga/grnxx at f888788 [master] Support expressions for BoolVector and add tests.

Back to archive index

susumu.yata null+****@clear*****
Wed Aug 27 16:49:17 JST 2014


susumu.yata	2014-08-27 16:49:17 +0900 (Wed, 27 Aug 2014)

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

  Message:
    Support expressions for BoolVector and add tests.

  Modified files:
    include/grnxx/datum.hpp
    include/grnxx/expression.hpp
    include/grnxx/types.hpp
    lib/grnxx/column.cpp
    lib/grnxx/expression.cpp
    test/test_column.cpp
    test/test_expression.cpp

  Modified: include/grnxx/datum.hpp (+6 -6)
===================================================================
--- include/grnxx/datum.hpp    2014-08-27 14:57:10 +0900 (10e2d2f)
+++ include/grnxx/datum.hpp    2014-08-27 16:49:17 +0900 (c3d703d)
@@ -26,8 +26,8 @@ class Datum {
       : type_(TEXT_DATA),
         text_(value) {}
   Datum(Vector<Bool> value)
-      : type_(VECTOR_BOOL_DATA),
-        vector_bool_(value) {}
+      : type_(BOOL_VECTOR_DATA),
+        bool_vector_(value) {}
 
   // Return the data type.
   DataType type() const {
@@ -50,8 +50,8 @@ class Datum {
   Text force_text() const {
     return text_;
   }
-  Vector<Bool> force_vector_bool() const {
-    return vector_bool_;
+  Vector<Bool> force_bool_vector() const {
+    return bool_vector_;
   }
 
   // Force the specified interpretation.
@@ -71,7 +71,7 @@ class Datum {
     *value = text_;
   }
   void force(Vector<Bool> *value) const {
-    *value = vector_bool_;
+    *value = bool_vector_;
   }
 
  private:
@@ -82,7 +82,7 @@ class Datum {
     Float float_;
     GeoPoint geo_point_;
     String text_;
-    Vector<Bool> vector_bool_;
+    Vector<Bool> bool_vector_;
   };
 };
 

  Modified: include/grnxx/expression.hpp (+6 -1)
===================================================================
--- include/grnxx/expression.hpp    2014-08-27 14:57:10 +0900 (b4f8802)
+++ include/grnxx/expression.hpp    2014-08-27 16:49:17 +0900 (3e5f9c2)
@@ -57,7 +57,7 @@ enum OperatorType {
   MODULUS_OPERATOR,         // For Int.
 
   // Array operators.
-//  SUBSCRIPT_OPERATOR,
+  SUBSCRIPT_OPERATOR,
 
   // -- Ternary operators --
 };
@@ -314,6 +314,11 @@ class ExpressionBuilder {
       OperatorType operator_type,
       unique_ptr<Node> &&arg1,
       unique_ptr<Node> &&arg2);
+  // Create a subscript node.
+  unique_ptr<Node> create_subscript_node(
+      Error *error,
+      unique_ptr<Node> &&arg1,
+      unique_ptr<Node> &&arg2);
 };
 
 }  // namespace grnxx

  Modified: include/grnxx/types.hpp (+9 -7)
===================================================================
--- include/grnxx/types.hpp    2014-08-27 14:57:10 +0900 (3866034)
+++ include/grnxx/types.hpp    2014-08-27 16:49:17 +0900 (c9669cf)
@@ -83,12 +83,12 @@ enum DataType {
   // Type: Vector.
   // Value: Vector of above data types.
   // Default: {}.
-  VECTOR_BOOL_DATA,
-  VECTOR_INT_DATA,
-  VECTOR_FLOAT_DATA,
-  VECTOR_GEO_POINT_DATA,
-  VECTOR_TEXT_DATA,
-  VECTOR_ROW_REF_DATA
+  BOOL_VECTOR_DATA,
+  INT_VECTOR_DATA,
+  FLOAT_VECTOR_DATA,
+  GEO_POINT_VECTOR_DATA,
+  TEXT_VECTOR_DATA,
+  ROW_REF_VECTOR_DATA
 };
 
 using Bool  = bool;
@@ -289,6 +289,8 @@ inline Bool operator!=(Vector<Bool> lhs, Vector<Bool> rhs) {
          ((lhs.bits() ^ rhs.bits()) != 0);
 }
 
+using BoolVector = Vector<Bool>;
+
 // Type information.
 template <typename T> struct TypeTraits;
 template <> struct TypeTraits <Bool> {
@@ -333,7 +335,7 @@ template <> struct TypeTraits <Text> {
 };
 template <> struct TypeTraits <Vector<Bool>> {
   static DataType data_type() {
-    return VECTOR_BOOL_DATA;
+    return BOOL_VECTOR_DATA;
   }
   static Vector<Bool> default_value() {
     return Vector<Bool>(0, 0);

  Modified: lib/grnxx/column.cpp (+1 -1)
===================================================================
--- lib/grnxx/column.cpp    2014-08-27 14:57:10 +0900 (fd3c573)
+++ lib/grnxx/column.cpp    2014-08-27 16:49:17 +0900 (d8cab38)
@@ -88,7 +88,7 @@ unique_ptr<Column> Column::create(Error *error,
     case TEXT_DATA: {
       return ColumnImpl<Text>::create(error, table, name, options);
     }
-    case VECTOR_BOOL_DATA: {
+    case BOOL_VECTOR_DATA: {
       return ColumnImpl<Vector<Bool>>::create(error, table, name, options);
     }
     default: {

  Modified: lib/grnxx/expression.cpp (+137 -0)
===================================================================
--- lib/grnxx/expression.cpp    2014-08-27 14:57:10 +0900 (ec83b15)
+++ lib/grnxx/expression.cpp    2014-08-27 16:49:17 +0900 (44db766)
@@ -2182,6 +2182,108 @@ bool ModulusNode<Int>::evaluate(Error *error,
   return true;
 }
 
+// ---- SubscriptOperator ----
+
+template <typename T>
+class SubscriptNode : public BinaryNode<T, Vector<T>, Int> {
+ public:
+  using Value = T;
+  using Arg1 = Vector<T>;
+  using Arg2 = Int;
+
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) SubscriptNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  SubscriptNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
+
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+};
+
+template <typename T>
+bool SubscriptNode<T>::evaluate(Error *error,
+                                ArrayCRef<Record> records,
+                                ArrayRef<Value> results) {
+  if (!this->fill_arg1_values(error, records) ||
+      !this->fill_arg2_values(error, records)) {
+    return false;
+  }
+  for (Int i = 0; i < records.size(); ++i) {
+    results.set(i, this->arg1_values_[i][this->arg2_values_[i]]);
+  }
+  return true;
+}
+
+template <>
+class SubscriptNode<Bool> : public BinaryNode<Bool, Vector<Bool>, Int> {
+ public:
+  using Value = Bool;
+  using Arg1 = Vector<Bool>;
+  using Arg2 = Int;
+
+  static unique_ptr<Node> create(Error *error,
+                                 unique_ptr<Node> &&arg1,
+                                 unique_ptr<Node> &&arg2) {
+    unique_ptr<Node> node(
+        new (nothrow) SubscriptNode(std::move(arg1), std::move(arg2)));
+    if (!node) {
+      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    }
+    return node;
+  }
+
+  SubscriptNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
+      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
+
+  bool filter(Error *error,
+              ArrayCRef<Record> input_records,
+              ArrayRef<Record> *output_records);
+  bool evaluate(Error *error,
+                ArrayCRef<Record> records,
+                ArrayRef<Value> results);
+};
+
+bool SubscriptNode<Bool>::filter(Error *error,
+                                 ArrayCRef<Record> input_records,
+                                 ArrayRef<Record> *output_records) {
+  if (!this->fill_arg1_values(error, input_records) ||
+      !this->fill_arg2_values(error, input_records)) {
+    return false;
+  }
+  Int count = 0;
+  for (Int i = 0; i < input_records.size(); ++i) {
+    if (this->arg1_values_[i][this->arg2_values_[i]]) {
+      output_records->set(count, input_records.get(i));
+      ++count;
+    }
+  }
+  *output_records = output_records->ref(0, count);
+  return true;
+}
+
+bool SubscriptNode<Bool>::evaluate(Error *error,
+                                   ArrayCRef<Record> records,
+                                   ArrayRef<Value> results) {
+  if (!this->fill_arg1_values(error, records) ||
+      !this->fill_arg2_values(error, records)) {
+    return false;
+  }
+  for (Int i = 0; i < records.size(); ++i) {
+    results.set(i, this->arg1_values_[i][this->arg2_values_[i]]);
+  }
+  return true;
+}
+
 }  // namespace expression
 
 using namespace expression;
@@ -2301,6 +2403,7 @@ GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Int);
 GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Float);
 GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(GeoPoint);
 GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Text);
+GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Vector<Bool>);
 #undef GRNXX_INSTANTIATE_EXPRESSION_EVALUATE
 
 template <typename T>
@@ -2475,6 +2578,9 @@ unique_ptr<Node> ExpressionBuilder::create_datum_node(
     case TEXT_DATA: {
       return DatumNode<Text>::create(error, datum.force_text());
     }
+    case BOOL_VECTOR_DATA: {
+      return DatumNode<Vector<Bool>>::create(error, datum.force_bool_vector());
+    }
     default: {
       // TODO: Other types are not supported yet.
       GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
@@ -2527,6 +2633,9 @@ unique_ptr<Node> ExpressionBuilder::create_column_node(
     case TEXT_DATA: {
       return ColumnNode<Text>::create(error, column);
     }
+    case BOOL_VECTOR_DATA: {
+      return ColumnNode<Vector<Bool>>::create(error, column);
+    }
     default: {
       // TODO: Other types are not supported yet.
       GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
@@ -2731,6 +2840,10 @@ unique_ptr<Node> ExpressionBuilder::create_binary_node(
       }
       return ModulusNode<Int>::create(error, std::move(arg1), std::move(arg2));
     }
+    case SUBSCRIPT_OPERATOR: {
+      return create_subscript_node(
+          error, std::move(arg1), std::move(arg2));
+    }
     default: {
       // TODO: Not supported yet.
       GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
@@ -2769,6 +2882,10 @@ unique_ptr<Node> ExpressionBuilder::create_equality_test_node(
       return ComparisonNode<typename T:: template Comparer<Text>>::create(
           error, std::move(arg1), std::move(arg2));
     }
+    case BOOL_VECTOR_DATA: {
+      return ComparisonNode<typename T:: template Comparer<Vector<Bool>>>::create(
+          error, std::move(arg1), std::move(arg2));
+    }
     // TODO: Support other types.
     default: {
       GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
@@ -2870,4 +2987,24 @@ unique_ptr<Node> ExpressionBuilder::create_arithmetic_node(
   }
 }
 
+unique_ptr<Node> ExpressionBuilder::create_subscript_node(
+    Error *error,
+    unique_ptr<Node> &&arg1,
+    unique_ptr<Node> &&arg2) {
+  if (arg2->data_type() != INT_DATA) {
+    GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
+    return nullptr;
+  }
+  switch (arg1->data_type()) {
+    case BOOL_VECTOR_DATA: {
+      return SubscriptNode<Bool>::create(
+          error, std::move(arg1), std::move(arg2));
+    }
+    default: {
+      GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
+      return nullptr;
+    }
+  }
+}
+
 }  // namespace grnxx

  Modified: test/test_column.cpp (+15 -15)
===================================================================
--- test/test_column.cpp    2014-08-27 14:57:10 +0900 (1c970f9)
+++ test/test_column.cpp    2014-08-27 16:49:17 +0900 (862ea70)
@@ -87,14 +87,14 @@ void test_column() {
 
   // Create a column named "VectorBoolColumn".
   // The column stores Text values.
-  auto vector_bool_column = table->create_column(&error, "VectorBoolColumn",
-                                                 grnxx::VECTOR_BOOL_DATA);
-  assert(vector_bool_column);
-  assert(vector_bool_column->table() == table);
-  assert(vector_bool_column->name() == "VectorBoolColumn");
-  assert(vector_bool_column->data_type() == grnxx::VECTOR_BOOL_DATA);
-  assert(!vector_bool_column->has_key_attribute());
-  assert(vector_bool_column->num_indexes() == 0);
+  auto bool_vector_column = table->create_column(&error, "VectorBoolColumn",
+                                                 grnxx::BOOL_VECTOR_DATA);
+  assert(bool_vector_column);
+  assert(bool_vector_column->table() == table);
+  assert(bool_vector_column->name() == "VectorBoolColumn");
+  assert(bool_vector_column->data_type() == grnxx::BOOL_VECTOR_DATA);
+  assert(!bool_vector_column->has_key_attribute());
+  assert(bool_vector_column->num_indexes() == 0);
 
   grnxx::Datum datum;
 
@@ -115,16 +115,16 @@ void test_column() {
   assert(datum.type() == grnxx::TEXT_DATA);
   assert(datum.force_text() == "");
 
-  assert(vector_bool_column->get(&error, 1, &datum));
-  assert(datum.type() == grnxx::VECTOR_BOOL_DATA);
-  assert(datum.force_vector_bool() == grnxx::Vector<grnxx::Bool>{});
+  assert(bool_vector_column->get(&error, 1, &datum));
+  assert(datum.type() == grnxx::BOOL_VECTOR_DATA);
+  assert(datum.force_bool_vector() == grnxx::Vector<grnxx::Bool>{});
 
   // Set and get values.
   assert(bool_column->set(&error, 1, grnxx::Bool(true)));
   assert(int_column->set(&error, 1, grnxx::Int(123)));
   assert(float_column->set(&error, 1, grnxx::Float(0.25)));
   assert(text_column->set(&error, 1, grnxx::Text("Hello, world!")));
-  assert(vector_bool_column->set(&error, 1,
+  assert(bool_vector_column->set(&error, 1,
          grnxx::Vector<grnxx::Bool>{ true, false, true }));
 
   assert(bool_column->get(&error, 1, &datum));
@@ -143,9 +143,9 @@ void test_column() {
   assert(datum.type() == grnxx::TEXT_DATA);
   assert(datum.force_text() == "Hello, world!");
 
-  assert(vector_bool_column->get(&error, 1, &datum));
-  assert(datum.type() == grnxx::VECTOR_BOOL_DATA);
-  assert((datum.force_vector_bool() ==
+  assert(bool_vector_column->get(&error, 1, &datum));
+  assert(datum.type() == grnxx::BOOL_VECTOR_DATA);
+  assert((datum.force_bool_vector() ==
           grnxx::Vector<grnxx::Bool>{ true, false, true }));
 }
 

  Modified: test/test_expression.cpp (+117 -0)
===================================================================
--- test/test_expression.cpp    2014-08-27 14:57:10 +0900 (e00eefc)
+++ test/test_expression.cpp    2014-08-27 16:49:17 +0900 (e3b1b32)
@@ -40,6 +40,8 @@ struct {
   grnxx::Array<grnxx::Text> text2_values;
   grnxx::Array<std::string> text_bodies;
   grnxx::Array<std::string> text2_bodies;
+  grnxx::Array<grnxx::Vector<grnxx::Bool>> bool_vector_values;
+  grnxx::Array<grnxx::Vector<grnxx::Bool>> bool_vector2_values;
 } test;
 
 void init_test() {
@@ -78,6 +80,14 @@ void init_test() {
   assert(text_column);
   assert(text2_column);
 
+  data_type = grnxx::BOOL_VECTOR_DATA;
+  auto bool_vector_column =
+      test.table->create_column(&error, "BoolVector", data_type);
+  auto bool_vector2_column =
+      test.table->create_column(&error, "BoolVector2", data_type);
+  assert(bool_vector_column);
+  assert(bool_vector2_column);
+
   // Generate random values.
   // Bool: true or false.
   // Int: [0, 100).
@@ -97,6 +107,8 @@ void init_test() {
   assert(test.text2_values.resize(&error, NUM_ROWS + 1));
   assert(test.text_bodies.resize(&error, NUM_ROWS + 1));
   assert(test.text2_bodies.resize(&error, NUM_ROWS + 1));
+  assert(test.bool_vector_values.resize(&error, NUM_ROWS + 1));
+  assert(test.bool_vector2_values.resize(&error, NUM_ROWS + 1));
   for (grnxx::Int i = 1; i <= NUM_ROWS; ++i) {
     test.bool_values.set(i, (mersenne_twister() & 1) != 0);
     test.bool2_values.set(i, (mersenne_twister() & 1) != 0);
@@ -122,6 +134,13 @@ void init_test() {
       test.text2_bodies[i][j] = '0' + (mersenne_twister() % 10);
     }
     test.text2_values.set(i, grnxx::Text(test.text2_bodies[i].data(), length));
+
+    grnxx::uint64_t bits = mersenne_twister();
+    grnxx::Int size = mersenne_twister() % 59;
+    test.bool_vector_values.set(i, grnxx::Vector<grnxx::Bool>(bits, size));
+    bits = mersenne_twister();
+    size = mersenne_twister() % 59;
+    test.bool_vector2_values.set(i, grnxx::Vector<grnxx::Bool>(bits, size));
   }
 
   // Store generated values into columns.
@@ -137,6 +156,10 @@ void init_test() {
     assert(float2_column->set(&error, row_id, test.float2_values[i]));
     assert(text_column->set(&error, row_id, test.text_values[i]));
     assert(text2_column->set(&error, row_id, test.text2_values[i]));
+    assert(bool_vector_column->set(&error, row_id,
+                                   test.bool_vector_values[i]));
+    assert(bool_vector2_column->set(&error, row_id,
+                                    test.bool_vector2_values[i]));
   }
 }
 
@@ -227,6 +250,20 @@ void test_constant() {
   for (grnxx::Int i = 0; i < text_results.size(); ++i) {
     assert(text_results[i] == "ABC");
   }
+
+  // Test an expression ({ true, false, true }).
+  assert(builder->push_datum(
+      &error, grnxx::Vector<grnxx::Bool>({ true, false, true })));
+  expression = builder->release(&error);
+  assert(expression);
+
+  grnxx::Array<grnxx::Vector<grnxx::Bool>> bool_vector_results;
+  assert(expression->evaluate(&error, records, &bool_vector_results));
+  assert(bool_vector_results.size() == test.table->num_rows());
+  for (grnxx::Int i = 0; i < bool_vector_results.size(); ++i) {
+    assert(bool_vector_results[i] ==
+           grnxx::Vector<grnxx::Bool>({ true, false, true }));
+  }
 }
 
 void test_column() {
@@ -320,6 +357,24 @@ void test_column() {
     assert(text_results[i] == test.text_values[row_id]);
   }
 
+  // Test an expression (BoolVector).
+  assert(builder->push_column(&error, "BoolVector"));
+  expression = builder->release(&error);
+  assert(expression);
+
+  records.clear();
+  cursor = test.table->create_cursor(&error);
+  assert(cursor);
+  assert(cursor->read_all(&error, &records) == test.table->num_rows());
+
+  grnxx::Array<grnxx::Vector<grnxx::Bool>> bool_vector_results;
+  assert(expression->evaluate(&error, records, &bool_vector_results));
+  assert(bool_vector_results.size() == test.table->num_rows());
+  for (grnxx::Int i = 0; i < bool_vector_results.size(); ++i) {
+    grnxx::Int row_id = records.get_row_id(i);
+    assert(bool_vector_results[i] == test.bool_vector_values[row_id]);
+  }
+
   // Test and expression (_id).
   assert(builder->push_column(&error, "_id"));
   expression = builder->release(&error);
@@ -822,6 +877,37 @@ void test_equal() {
     }
   }
   assert(records.size() == count);
+
+  // Test an expression (BoolVector == BoolVector2).
+  assert(builder->push_column(&error, "BoolVector"));
+  assert(builder->push_column(&error, "BoolVector2"));
+  assert(builder->push_operator(&error, grnxx::EQUAL_OPERATOR));
+  expression = builder->release(&error);
+  assert(expression);
+
+  records.clear();
+  cursor = test.table->create_cursor(&error);
+  assert(cursor);
+  assert(cursor->read_all(&error, &records) == test.table->num_rows());
+
+  results.clear();
+  assert(expression->evaluate(&error, records, &results));
+  assert(results.size() == test.table->num_rows());
+  for (grnxx::Int i = 0; i < results.size(); ++i) {
+    grnxx::Int row_id = records.get_row_id(i);
+    assert(results[i] == (test.bool_vector_values[row_id] ==
+                          test.bool_vector2_values[row_id]));
+  }
+
+  assert(expression->filter(&error, &records));
+  count = 0;
+  for (grnxx::Int i = 1; i < test.bool_vector_values.size(); ++i) {
+    if (test.bool_vector_values[i] == test.bool_vector2_values[i]) {
+      assert(records.get_row_id(count) == i);
+      ++count;
+    }
+  }
+  assert(records.size() == count);
 }
 
 void test_not_equal() {
@@ -954,6 +1040,37 @@ void test_not_equal() {
     }
   }
   assert(records.size() == count);
+
+  // Test an expression (BoolVector != BoolVector2).
+  assert(builder->push_column(&error, "BoolVector"));
+  assert(builder->push_column(&error, "BoolVector2"));
+  assert(builder->push_operator(&error, grnxx::NOT_EQUAL_OPERATOR));
+  expression = builder->release(&error);
+  assert(expression);
+
+  records.clear();
+  cursor = test.table->create_cursor(&error);
+  assert(cursor);
+  assert(cursor->read_all(&error, &records) == test.table->num_rows());
+
+  results.clear();
+  assert(expression->evaluate(&error, records, &results));
+  assert(results.size() == test.table->num_rows());
+  for (grnxx::Int i = 0; i < results.size(); ++i) {
+    grnxx::Int row_id = records.get_row_id(i);
+    assert(results[i] == (test.bool_vector_values[row_id] !=
+                          test.bool_vector2_values[row_id]));
+  }
+
+  assert(expression->filter(&error, &records));
+  count = 0;
+  for (grnxx::Int i = 1; i < test.bool_vector_values.size(); ++i) {
+    if (test.bool_vector_values[i] != test.bool_vector2_values[i]) {
+      assert(records.get_row_id(count) == i);
+      ++count;
+    }
+  }
+  assert(records.size() == count);
 }
 
 void test_less() {
-------------- next part --------------
HTML����������������������������...
Download 



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