[Groonga-commit] groonga/grnxx at a170efc [master] Implement reference column.

Back to archive index

susumu.yata null+****@clear*****
Fri Mar 7 17:42:47 JST 2014


susumu.yata	2014-03-07 17:42:47 +0900 (Fri, 07 Mar 2014)

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

  Message:
    Implement reference column.

  Modified files:
    lib/grnxx/calc_impl.cpp
    lib/grnxx/calc_impl.hpp
    lib/grnxx/column.cpp
    lib/grnxx/column.hpp
    lib/grnxx/column_impl.cpp
    lib/grnxx/column_impl.hpp
    lib/grnxx/table.cpp
    lib/grnxx/table.hpp
    lib/grnxx/types.hpp
    test/test_grnxx.cpp

  Modified: lib/grnxx/calc_impl.cpp (+159 -15)
===================================================================
--- lib/grnxx/calc_impl.cpp    2014-03-05 15:05:43 +0900 (826f82a)
+++ lib/grnxx/calc_impl.cpp    2014-03-07 17:42:47 +0900 (d3a07dc)
@@ -88,6 +88,10 @@ class ColumnNode : public CalcNode {
   // ノードを破棄する.
   ~ColumnNode() {}
 
+  ColumnImpl<T> *column() const {
+    return column_;
+  }
+
   // 指定された値を返す.
   T get(Int64 i, RowID row_id) const {
     return column_->get(row_id);
@@ -760,6 +764,76 @@ class ArithmeticNodeHelper<T, InvalidResult> {
   }
 };
 
+// 参照と対応するノード.
+template <typename T>
+class ReferenceNode : public OperatorNode<T> {
+ public:
+  using Result = T;
+
+  // 指定されたノードに対する四則演算と対応するノードとして初期化する.
+  explicit ReferenceNode(CalcNode *lhs, CalcNode *rhs)
+      : OperatorNode<Result>(),
+        lhs_(static_cast<ColumnNode<Int64> *>(lhs)),
+        rhs_(static_cast<ColumnNode<T> *>(rhs)) {}
+  // ノードを破棄する.
+  ~ReferenceNode() {}
+
+  // 行の一覧を受け取り,演算結果が真になる行のみを残して,残った行の数を返す.
+  Int64 filter(RowID *row_ids, Int64 num_row_ids);
+
+  // 与えられた行の一覧について演算をおこない,その結果を取得できる状態にする.
+  void fill(const RowID *row_ids, Int64 num_row_ids);
+
+ private:
+  ColumnNode<Int64> *lhs_;
+  ColumnNode<T> *rhs_;
+  std::vector<RowID> local_row_ids_;
+};
+
+// 行の一覧を受け取り,演算結果が真になる行のみを残して,残った行の数を返す.
+template <typename T>
+Int64 ReferenceNode<T>::filter(RowID *row_ids, Int64 num_row_ids) {
+  // 参照先が真になる行だけを残す.
+  lhs_->fill(row_ids, num_row_ids);
+  // FIXME: lhs が行 ID の一覧を持っているのにコピーしなければならない.
+  local_row_ids_.resize(num_row_ids);
+  for (Int64 i = 0; i < num_row_ids; ++i) {
+    local_row_ids_[i] = lhs_->get(i, row_ids[i]);
+  }
+  rhs_->fill(&*local_row_ids_.begin(), num_row_ids);
+  Int64 count = 0;
+  for (Int64 i = 0; i < num_row_ids; ++i) {
+    if (rhs_->get(i, local_row_ids_[i])) {
+      row_ids[count++] = row_ids[i];
+    }
+  }
+  return count;
+}
+
+// 行の一覧を受け取り,演算結果が真になる行のみを残して,残った行の数を返す.
+template <>
+Int64 ReferenceNode<String>::filter(RowID *row_ids, Int64 num_row_ids) {
+  // FIXME: String から Boolean の変換は未定義.
+  return 0;
+}
+
+// 与えられた行の一覧について演算をおこない,その結果を取得できる状態にする.
+template <typename T>
+void ReferenceNode<T>::fill(const RowID *row_ids, Int64 num_row_ids) {
+  lhs_->fill(row_ids, num_row_ids);
+  // FIXME: lhs が行 ID の一覧を持っているのにコピーしなければならない.
+  local_row_ids_.resize(num_row_ids);
+  for (Int64 i = 0; i < num_row_ids; ++i) {
+    local_row_ids_[i] = lhs_->get(i, row_ids[i]);
+  }
+  // FIXME: わざわざコピーしなければならない.
+  rhs_->fill(&*local_row_ids_.begin(), num_row_ids);
+  this->data_.resize(num_row_ids);
+  for (Int64 i = 0; i < num_row_ids; ++i) {
+    this->data_[i] = rhs_->get(i, local_row_ids_[i]);
+  }
+}
+
 }  // namespace
 
 // 指定された種類のノードとして初期化する.
@@ -823,6 +897,9 @@ int CalcToken::get_binary_operator_priority(BinaryOperatorType operator_type) {
     case MODULUS_OPERATOR: {
       return 9;
     }
+    case REFERENCE_OPERATOR: {
+      return 10;
+    }
   }
   return 0;
 }
@@ -1017,15 +1094,16 @@ bool CalcImpl::tokenize_query(const String &query,
         if (end == left.npos) {
           end = left.size();
         }
-        // カラムもしくは Boolean, Int64, Float の定数に対応するノードを作成する.
+        // FIXME: アドホックに書き足したのでひどいことになっている.
+        // 最初に Boolean, Int64, Float の可能性を調べる.
         String token = left.prefix(end);
-        auto node = create_column_node(token);
-        if (!node) {
-          if (token == "TRUE") {
-            node = create_boolean_node(true);
-          } else if (token == "FALSE") {
-            node = create_boolean_node(false);
-          } else if (token.find_first_of('.') != token.npos) {
+        CalcNode *node = nullptr;
+        if (token == "TRUE") {
+          node = create_boolean_node(true);
+        } else if (token == "FALSE") {
+          node = create_boolean_node(false);
+        } else if (std::isdigit(static_cast<UInt8>(token[0]))) {
+          if (token.find_first_of('.') != token.npos) {
             node = create_float_node(static_cast<Float>(std::stod(
                 std::string(reinterpret_cast<const char *>(token.data()),
                             token.size()))));
@@ -1034,10 +1112,46 @@ bool CalcImpl::tokenize_query(const String &query,
                 std::string(reinterpret_cast<const char *>(token.data()),
                             token.size()))));
           }
-          if (!node) {
-            return false;
+        } else {
+          // カラムと参照演算子に対応するノードを作成する.
+          // 参照演算子は単項演算子より優先順位が高いため,以降の処理における面倒を
+          // なくすべく,最後に作成したノードのみをトークン化する.
+          const Table *current_table = table_;
+          ColumnNode<Int64> *src_node = nullptr;
+          for ( ; ; ) {
+            auto delim_pos = token.find_first_of('.');
+            auto column = current_table->get_column_by_name(
+                (delim_pos != token.npos) ? token.prefix(delim_pos) : token);
+            if (!column) {
+              return false;
+            }
+            node = create_column_node(column);
+            if (!node) {
+              return false;
+            }
+            if (src_node) {
+              node = create_binary_operator_node(REFERENCE_OPERATOR,
+                                                 src_node, node);
+              if (!node) {
+                return false;
+              }
+            }
+            if (delim_pos == token.npos) {
+              // 参照演算子がなければここで終わる.
+              break;
+            }
+
+            token = token.except_prefix(delim_pos + 1);
+            if (column->data_type() != INTEGER) {
+              return false;
+            }
+            src_node = static_cast<ColumnNode<Int64> *>(node);
+            current_table = src_node->column()->dest_table();
           }
         }
+        if (!node) {
+          return false;
+        }
         tokens->push_back(CalcToken(node));
         left = left.except_prefix(end);
         break;
@@ -1168,11 +1282,7 @@ bool CalcImpl::push_token(const CalcToken &token,
 }
 
 // 指定された名前のカラムと対応するノードを作成する.
-CalcNode *CalcImpl::create_column_node(const String &column_name) {
-  auto column = table_->get_column_by_name(column_name);
-  if (!column) {
-    return nullptr;
-  }
+CalcNode *CalcImpl::create_column_node(Column *column) {
   std::unique_ptr<CalcNode> node;
   switch (column->data_type()) {
     case BOOLEAN: {
@@ -1294,6 +1404,10 @@ CalcNode *CalcImpl::create_binary_operator_node(
       node.reset(create_arithmetic_node(binary_operator_type, lhs, rhs));
       break;
     }
+    case REFERENCE_OPERATOR: {
+      node.reset(create_reference_node(lhs, rhs));
+      break;
+    }
   }
   if (!node) {
     return nullptr;
@@ -1681,4 +1795,34 @@ CalcNode *CalcImpl::create_arithmetic_node_4(CalcNode *lhs, CalcNode *rhs) {
   return nullptr;
 }
 
+// 参照演算子と対応するノードを作成する.
+CalcNode *CalcImpl::create_reference_node(CalcNode *lhs, CalcNode *rhs) {
+  // 左の被演算子は参照型のカラムでなければならない.
+  if ((lhs->data_type() != INTEGER) ||
+      (lhs->type() != COLUMN_NODE) ||
+      !static_cast<ColumnNode<Int64> *>(lhs)->column()->dest_table()) {
+    return nullptr;
+  }
+  // 右の被演算子もカラムでなければならない.
+  if (rhs->type() != COLUMN_NODE) {
+    return nullptr;
+  }
+  // 右の被演算子の型に応じたノードを作成する.
+  switch (rhs->data_type()) {
+    case BOOLEAN: {
+      return new ReferenceNode<Boolean>(lhs, rhs);
+    }
+    case INTEGER: {
+      return new ReferenceNode<Int64>(lhs, rhs);
+    }
+    case FLOAT: {
+      return new ReferenceNode<Float>(lhs, rhs);
+    }
+    case STRING: {
+      return new ReferenceNode<String>(lhs, rhs);
+    }
+  }
+  return nullptr;
+}
+
 }  // namespace grnxx

  Modified: lib/grnxx/calc_impl.hpp (+7 -3)
===================================================================
--- lib/grnxx/calc_impl.hpp    2014-03-05 15:05:43 +0900 (e71e929)
+++ lib/grnxx/calc_impl.hpp    2014-03-07 17:42:47 +0900 (80390ae)
@@ -24,7 +24,8 @@ enum BinaryOperatorType {
   MINUS_OPERATOR,
   MULTIPLIES_OPERATOR,
   DIVIDES_OPERATOR,
-  MODULUS_OPERATOR
+  MODULUS_OPERATOR,
+  REFERENCE_OPERATOR
 };
 
 // 演算器を構成するノードの種類.
@@ -167,8 +168,8 @@ class CalcImpl : public Calc {
   // トークンをひとつずつ解釈する.
   bool push_token(const CalcToken &token, std::vector<CalcToken> *stack);
 
-  // 指定された名前のカラムと対応するノードを作成する.
-  CalcNode *create_column_node(const String &column_name);
+  // 指定されたカラムと対応するノードを作成する.
+  CalcNode *create_column_node(Column *column);
 
   // 指定された Boolean の定数と対応するノードを作成する.
   CalcNode *create_boolean_node(Boolean value);
@@ -226,6 +227,9 @@ class CalcImpl : public Calc {
   // T: 算術演算子.
   template <typename T>
   CalcNode *create_arithmetic_node_4(CalcNode *lhs, CalcNode *rhs);
+
+  // 参照演算子と対応するノードを作成する.
+  CalcNode *create_reference_node(CalcNode *lhs, CalcNode *rhs);
 };
 
 }  // namespace grnxx

  Modified: lib/grnxx/column.cpp (+9 -1)
===================================================================
--- lib/grnxx/column.cpp    2014-03-05 15:05:43 +0900 (a64ff4d)
+++ lib/grnxx/column.cpp    2014-03-07 17:42:47 +0900 (086d204)
@@ -76,7 +76,7 @@ std::ostream &operator<<(std::ostream &stream, const Column &column) {
 }
 
 // 指定されたカラムを作成して返す.
-Column *ColumnHelper::create(Table *table,
+Column *ColumnHelper::create_column(Table *table,
                              ColumnID column_id,
                              const String &column_name,
                              DataType data_type) {
@@ -97,4 +97,12 @@ Column *ColumnHelper::create(Table *table,
   return nullptr;
 }
 
+// 指定された参照型のカラムを作成して返す.
+Column *ColumnHelper::create_reference_column(Table *table,
+                                              ColumnID column_id,
+                                              const String &column_name,
+                                              Table *dest_table) {
+  return new ColumnImpl<Int64>(table, column_id, column_name, dest_table);
+}
+
 }  // namespace grnxx

  Modified: lib/grnxx/column.hpp (+9 -4)
===================================================================
--- lib/grnxx/column.hpp    2014-03-05 15:05:43 +0900 (66a0355)
+++ lib/grnxx/column.hpp    2014-03-07 17:42:47 +0900 (04111e7)
@@ -57,10 +57,15 @@ std::ostream &operator<<(std::ostream &stream, const Column &column);
 class ColumnHelper {
  public:
   // 指定されたカラムを作成して返す.
-  static Column *create(Table *table,
-                        ColumnID column_id,
-                        const String &column_name,
-                        DataType data_type);
+  static Column *create_column(Table *table,
+                               ColumnID column_id,
+                               const String &column_name,
+                               DataType data_type);
+  // 指定された参照型のカラムを作成して返す.
+  static Column *create_reference_column(Table *table,
+                                         ColumnID column_id,
+                                         const String &column_name,
+                                         Table *dest_table);
 };
 
 }  // namespace grnxx

  Modified: lib/grnxx/column_impl.cpp (+10 -1)
===================================================================
--- lib/grnxx/column_impl.cpp    2014-03-05 15:05:43 +0900 (151edfe)
+++ lib/grnxx/column_impl.cpp    2014-03-07 17:42:47 +0900 (d346e21)
@@ -1,6 +1,7 @@
 #include "grnxx/column_impl.hpp"
 
 #include "grnxx/index.hpp"
+#include "grnxx/table.hpp"
 
 //#include <iostream>
 
@@ -60,8 +61,10 @@ template class ColumnImpl<Float>;
 #ifdef GRNXX_ENABLE_VARIABLE_INTEGER_TYPE
 
 // カラムを初期化する.
-ColumnImpl<Int64>::ColumnImpl(Table *table, ColumnID id, const String &name)
+ColumnImpl<Int64>::ColumnImpl(Table *table, ColumnID id, const String &name,
+                              Table *dest_table)
     : Column(table, id, name, INTEGER),
+      dest_table_(dest_table),
       data_8_(MIN_ROW_ID, 0),
       data_16_(),
       data_32_(),
@@ -112,6 +115,12 @@ void ColumnImpl<Int64>::resize(RowID max_row_id) {
 
 // 指定された ID の値を更新する.
 void ColumnImpl<Int64>::set(RowID row_id, Int64 value) {
+  if (dest_table_) {
+    if ((value < dest_table_->min_row_id()) ||
+        (value > dest_table_->max_row_id())) {
+      throw "invalid reference";
+    }
+  }
   switch (internal_data_type_size_) {
     case 8: {
       if ((value < INT8_MIN) || (value > INT8_MAX)) {

  Modified: lib/grnxx/column_impl.hpp (+17 -1)
===================================================================
--- lib/grnxx/column_impl.hpp    2014-03-05 15:05:43 +0900 (a0a3fc1)
+++ lib/grnxx/column_impl.hpp    2014-03-07 17:42:47 +0900 (9100225)
@@ -9,6 +9,8 @@ namespace grnxx {
 template <typename T>
 class ColumnImpl : public Column {
  public:
+  using Value = T;
+
   // カラムを初期化する.
   ColumnImpl(Table *table, ColumnID id, const String &name);
   // カラムを破棄する.
@@ -42,8 +44,11 @@ class ColumnImpl : public Column {
 template <>
 class ColumnImpl<Int64> : public Column {
  public:
+  using Value = Int64;
+
   // カラムを初期化する.
-  ColumnImpl(Table *table, ColumnID id, const String &name);
+  ColumnImpl(Table *table, ColumnID id, const String &name,
+             Table *dest_table = nullptr);
   // カラムを破棄する.
   ~ColumnImpl();
 
@@ -59,6 +64,12 @@ class ColumnImpl<Int64> : public Column {
   // 指定された行 ID が使えるようにサイズを変更する.
   void resize(RowID max_row_id);
 
+  // 参照先のテーブルを返す.
+  // なければ nullptr を返す.
+  Table *dest_table() const {
+    return dest_table_;
+  }
+
   // 指定された ID の値を返す.
   Int64 get(RowID row_id) const {
     switch (internal_data_type_size_) {
@@ -80,6 +91,7 @@ class ColumnImpl<Int64> : public Column {
   void set(RowID row_id, Int64 value);
 
  private:
+  Table *dest_table_;
   std::vector<Int8> data_8_;
   std::vector<Int16> data_16_;
   std::vector<Int32> data_32_;
@@ -94,6 +106,8 @@ class ColumnImpl<Int64> : public Column {
 template <>
 class ColumnImpl<Int64> : public Column {
  public:
+  using Value = Int64;
+
   // カラムを初期化する.
   ColumnImpl(Table *table, ColumnID id, const String &name);
   // カラムを破棄する.
@@ -127,6 +141,8 @@ class ColumnImpl<Int64> : public Column {
 template <>
 class ColumnImpl<String> : public Column {
  public:
+  using Value = String;
+
   // カラムを初期化する.
   ColumnImpl(Table *table, ColumnID id, const String &name);
   // カラムを破棄する.

  Modified: lib/grnxx/table.cpp (+32 -1)
===================================================================
--- lib/grnxx/table.cpp    2014-03-05 15:05:43 +0900 (a9303b4)
+++ lib/grnxx/table.cpp    2014-03-07 17:42:47 +0900 (8b321ac)
@@ -2,6 +2,7 @@
 
 #include "grnxx/calc.hpp"
 #include "grnxx/column_impl.hpp"
+#include "grnxx/database.hpp"
 #include "grnxx/index.hpp"
 #include "grnxx/sorter.hpp"
 
@@ -86,7 +87,37 @@ Column *Table::create_column(const String &column_name, DataType data_type) {
     columns_.resize(column_id + 1);
   }
   std::unique_ptr<Column> new_column(
-      ColumnHelper::create(this, column_id, column_name, data_type));
+      ColumnHelper::create_column(this, column_id, column_name, data_type));
+  new_column->resize(max_row_id());
+  columns_map_.insert(it, std::make_pair(new_column->name(), column_id));
+  columns_[column_id] = std::move(new_column);
+  return columns_[column_id].get();
+}
+
+// 参照型のカラムを作成して返す.
+// 失敗すると nullptr を返す.
+Column *Table::create_reference_column(const String &column_name,
+                                       const String &table_name) {
+  Table *dest_table = database_->get_table_by_name(table_name);
+  if (!dest_table) {
+    return nullptr;
+  }
+  auto it = columns_map_.find(column_name);
+  if (it != columns_map_.end()) {
+    return nullptr;
+  }
+  ColumnID column_id = min_column_id();
+  for ( ; column_id <= max_column_id(); ++column_id) {
+    if (!columns_[column_id]) {
+      break;
+    }
+  }
+  if (column_id > max_column_id()) {
+    columns_.resize(column_id + 1);
+  }
+  std::unique_ptr<Column> new_column(
+      ColumnHelper::create_reference_column(this, column_id, column_name,
+                                            dest_table));
   new_column->resize(max_row_id());
   columns_map_.insert(it, std::make_pair(new_column->name(), column_id));
   columns_[column_id] = std::move(new_column);

  Modified: lib/grnxx/table.hpp (+4 -0)
===================================================================
--- lib/grnxx/table.hpp    2014-03-05 15:05:43 +0900 (8b019cd)
+++ lib/grnxx/table.hpp    2014-03-07 17:42:47 +0900 (8e51a8c)
@@ -32,6 +32,10 @@ class Table {
   // 指定された名前とデータ型のカラムを作成して返す.
   // 失敗すると nullptr を返す.
   Column *create_column(const String &column_name, DataType data_type);
+  // 参照型のカラムを作成して返す.
+  // 失敗すると nullptr を返す.
+  Column *create_reference_column(const String &column_name,
+                                  const String &table_name);
   // 指定された名前のカラムを破棄する.
   // 成功すれば true を返し,失敗すれば false を返す.
   bool drop_column(const String &column_name);

  Modified: lib/grnxx/types.hpp (+1 -0)
===================================================================
--- lib/grnxx/types.hpp    2014-03-05 15:05:43 +0900 (f8a1d78)
+++ lib/grnxx/types.hpp    2014-03-07 17:42:47 +0900 (3069069)
@@ -2,6 +2,7 @@
 #define GRNXX_TYPES_HPP
 
 #include <algorithm>
+#include <cctype>
 #include <cstdint>
 #include <cstring>
 #include <functional>

  Modified: test/test_grnxx.cpp (+147 -0)
===================================================================
--- test/test_grnxx.cpp    2014-03-05 15:05:43 +0900 (1b8d0a6)
+++ test/test_grnxx.cpp    2014-03-07 17:42:47 +0900 (b53abe4)
@@ -579,6 +579,152 @@ void test_calc() {
   }
 }
 
+void test_reference() {
+  grnxx::Database database;
+
+  grnxx::Table *src_table = database.create_table("Src");
+  assert(src_table);
+  grnxx::Table *dest_table = database.create_table("Dest");
+  assert(dest_table);
+
+  auto reference_column = dynamic_cast<grnxx::ColumnImpl<grnxx::Int64> *>(
+      src_table->create_reference_column("Reference", "Dest"));
+  assert(reference_column);
+
+  auto boolean_column = dynamic_cast<grnxx::ColumnImpl<grnxx::Boolean> *>(
+      dest_table->create_column("Boolean", grnxx::BOOLEAN));
+  assert(boolean_column);
+  auto integer_column = dynamic_cast<grnxx::ColumnImpl<grnxx::Int64> *>(
+      dest_table->create_column("Integer", grnxx::INTEGER));
+  assert(integer_column);
+  auto float_column = dynamic_cast<grnxx::ColumnImpl<grnxx::Float> *>(
+      dest_table->create_column("Float", grnxx::FLOAT));
+  assert(float_column);
+
+  std::mt19937_64 random;
+
+  std::vector<grnxx::Int64> boolean_data;
+  std::vector<grnxx::Int64> integer_data;
+  std::vector<grnxx::Int64> float_data;
+  for (grnxx::Int64 i = 0; i < 1000; ++i) {
+    boolean_data.push_back(random() & 1);
+    integer_data.push_back(random() % 100);
+    float_data.push_back(1.0 * random() / random.max());
+    grnxx::RowID row_id = dest_table->insert_row();
+    boolean_column->set(row_id, boolean_data[i]);
+    integer_column->set(row_id, integer_data[i]);
+    float_column->set(row_id, float_data[i]);
+  }
+
+  std::vector<grnxx::Int64> reference_data;
+  for (grnxx::Int64 i = 0; i < 1000; ++i) {
+    grnxx::RowID row_id = src_table->insert_row();
+    reference_data.push_back(random() % 1000);
+    reference_column->set(row_id, reference_data[i] + 1);
+  }
+
+  std::vector<grnxx::RowID> all_row_ids(1000);
+  std::unique_ptr<grnxx::RowIDCursor> cursor(src_table->create_cursor());
+  assert(cursor->get_next(&all_row_ids[0], 1000) == 1000);
+
+  // Boolean で絞り込む.
+  {
+    std::unique_ptr<grnxx::Calc> calc(
+        src_table->create_calc("Reference.Boolean"));
+    assert(calc);
+    std::vector<grnxx::RowID> row_ids(all_row_ids);
+    grnxx::Int64 num_row_ids = calc->filter(&*row_ids.begin(), row_ids.size());
+    assert(num_row_ids != 0);
+    grnxx::Int64 count = 0;
+    for (grnxx::Int64 i = 0; i < 1000; ++i) {
+      grnxx::RowID row_id = grnxx::MIN_ROW_ID + i;
+      if (boolean_data[reference_data[i]]) {
+        assert(row_ids[count] == row_id);
+        assert(++count <= num_row_ids);
+      }
+    }
+    assert(count == num_row_ids);
+  }
+
+  // Boolean で絞り込む.
+  {
+    std::unique_ptr<grnxx::Calc> calc(
+        src_table->create_calc("!Reference.Boolean"));
+    assert(calc);
+    std::vector<grnxx::RowID> row_ids(all_row_ids);
+    grnxx::Int64 num_row_ids = calc->filter(&*row_ids.begin(), row_ids.size());
+    assert(num_row_ids != 0);
+    grnxx::Int64 count = 0;
+    for (grnxx::Int64 i = 0; i < 1000; ++i) {
+      grnxx::RowID row_id = grnxx::MIN_ROW_ID + i;
+      if (!boolean_data[reference_data[i]]) {
+        assert(row_ids[count] == row_id);
+        assert(++count <= num_row_ids);
+      }
+    }
+    assert(count == num_row_ids);
+  }
+
+  // Integer で絞り込む.
+  {
+    std::unique_ptr<grnxx::Calc> calc(
+        src_table->create_calc("Reference.Integer < 50"));
+    assert(calc);
+    std::vector<grnxx::RowID> row_ids(all_row_ids);
+    grnxx::Int64 num_row_ids = calc->filter(&*row_ids.begin(), row_ids.size());
+    assert(num_row_ids != 0);
+    grnxx::Int64 count = 0;
+    for (grnxx::Int64 i = 0; i < 1000; ++i) {
+      grnxx::RowID row_id = grnxx::MIN_ROW_ID + i;
+      if (integer_data[reference_data[i]] < 50) {
+        assert(row_ids[count] == row_id);
+        assert(++count <= num_row_ids);
+      }
+    }
+    assert(count == num_row_ids);
+  }
+
+  // Float で絞り込む.
+  {
+    std::unique_ptr<grnxx::Calc> calc(
+        src_table->create_calc("Reference.Float <= 0.5"));
+    assert(calc);
+    std::vector<grnxx::RowID> row_ids(all_row_ids);
+    grnxx::Int64 num_row_ids = calc->filter(&*row_ids.begin(), row_ids.size());
+    assert(num_row_ids != 0);
+    grnxx::Int64 count = 0;
+    for (grnxx::Int64 i = 0; i < 1000; ++i) {
+      grnxx::RowID row_id = grnxx::MIN_ROW_ID + i;
+      if (float_data[reference_data[i]] <= 0.5) {
+        assert(row_ids[count] == row_id);
+        assert(++count <= num_row_ids);
+      }
+    }
+    assert(count == num_row_ids);
+  }
+
+  // Boolean と Integer と Float の範囲で絞り込む.
+  {
+    std::unique_ptr<grnxx::Calc> calc(src_table->create_calc(
+        "Reference.Boolean && Reference.Integer < 50 && Reference.Float < 0.5"));
+    assert(calc);
+    std::vector<grnxx::RowID> row_ids(all_row_ids);
+    grnxx::Int64 num_row_ids = calc->filter(&*row_ids.begin(), row_ids.size());
+    assert(num_row_ids != 0);
+    grnxx::Int64 count = 0;
+    for (grnxx::Int64 i = 0; i < 1000; ++i) {
+      grnxx::RowID row_id = grnxx::MIN_ROW_ID + i;
+      if (boolean_data[reference_data[i]] &&
+          (integer_data[reference_data[i]] < 50) &&
+          (float_data[reference_data[i]] < 0.5)) {
+        assert(row_ids[count] == row_id);
+        assert(++count <= num_row_ids);
+      }
+    }
+    assert(count == num_row_ids);
+  }
+}
+
 void test_sorter() {
   constexpr grnxx::Int64 DATA_SIZE = 1000;
 
@@ -1208,6 +1354,7 @@ int main() {
   test_table();
   test_column();
   test_calc();
+  test_reference();
   test_sorter();
   test_sorter_large();
   test_index();
-------------- next part --------------
HTML����������������������������...
Download 



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