[Groonga-commit] groonga/grnxx at 5f91247 [master] Remove the old implementation of Expression.

Back to archive index

susumu.yata null+****@clear*****
Tue Dec 16 10:47:16 JST 2014


susumu.yata	2014-11-27 22:58:44 +0900 (Thu, 27 Nov 2014)

  New Revision: 5f91247d9590aa7ce8d754bff1ba3cb69bdc7cc6
  https://github.com/groonga/grnxx/commit/5f91247d9590aa7ce8d754bff1ba3cb69bdc7cc6

  Message:
    Remove the old implementation of Expression.

  Removed files:
    lib/grnxx/expression-old.cpp

  Deleted: lib/grnxx/expression-old.cpp (+0 -4090) 100644
===================================================================
--- lib/grnxx/expression-old.cpp    2014-11-27 21:30:15 +0900 (ed88cca)
+++ /dev/null
@@ -1,4090 +0,0 @@
-#include "grnxx/expression.hpp"
-
-#include "grnxx/impl/column.hpp"
-#include "grnxx/table.hpp"
-
-#include <iostream>  // For debugging.
-
-namespace grnxx {
-namespace expression {
-
-// TODO: Only CONSTANT_NODE and VARIABLE_NODE are required?
-enum NodeType {
-  CONSTANT_NODE,
-  ROW_ID_NODE,
-  SCORE_NODE,
-  COLUMN_NODE,
-  OPERATOR_NODE
-};
-
-// -- Node --
-
-class Node {
- public:
-  Node() {}
-  virtual ~Node() {}
-
-  // Return the node type.
-  virtual NodeType node_type() const = 0;
-  // Return the result data type.
-  virtual DataType data_type() const = 0;
-  // Return the reference table.
-  virtual const Table *ref_table() const {
-    return nullptr;
-  }
-
-  // Extract true records.
-  //
-  // Evaluates the expression for "input_records" and appends records
-  // whose evaluation results are true into "*output_records".
-  // "*output_records" is truncated to the number of true records.
-  //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool filter(Error *error,
-                      ArrayCRef<Record> input_records,
-                      ArrayRef<Record> *output_records) = 0;
-
-  // Adjust scores of records.
-  //
-  // Evaluates the expression for the given record set and replaces their
-  // scores with the evaluation results.
-  //
-  // Returns true on success.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool adjust(Error *error, ArrayRef<Record> records) = 0;
-};
-
-// -- TypedNode --
-
-template <typename T>
-class TypedNode : public Node {
- public:
-  using Value = T;
-
-  TypedNode() : Node() {}
-  virtual ~TypedNode() {}
-
-  DataType data_type() const {
-    return TypeTraits<Value>::data_type();
-  }
-
-  bool filter(Error *error,
-              ArrayCRef<Record>,
-              ArrayRef<Record> *) {
-    // Other than TypedNode<Bool> don't support filter().
-    GRNXX_ERROR_SET(error, INVALID_OPERATION, "Invalid operation");
-    return false;
-  }
-
-  bool adjust(Error *error, ArrayRef<Record>) {
-    // Other than TypedNode<Float> don't support adjust().
-    GRNXX_ERROR_SET(error, INVALID_OPERATION, "Invalid operation");
-    return false;
-  }
-
-  // Evaluate the expression subtree.
-  //
-  // The evaluation results are stored into "*results".
-  //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  virtual bool evaluate(Error *error,
-                        ArrayCRef<Record> records,
-                        ArrayRef<Value> results) = 0;
-};
-
-template <>
-class TypedNode<Bool> : public Node {
- public:
-  using Value = Bool;
-
-  TypedNode() : Node() {}
-  virtual ~TypedNode() {}
-
-  DataType data_type() const {
-    return TypeTraits<Value>::data_type();
-  }
-
-  // Derived classes must override this member function.
-  virtual bool filter(Error *error,
-                      ArrayCRef<Record> input_records,
-                      ArrayRef<Record> *output_records) = 0;
-
-  bool adjust(Error *error, ArrayRef<Record>) {
-    // Other than TypedNode<Float> don't support adjust().
-    GRNXX_ERROR_SET(error, INVALID_OPERATION, "Invalid operation");
-    return false;
-  }
-
-  virtual bool evaluate(Error *error,
-                        ArrayCRef<Record> records,
-                        ArrayRef<Value> results) = 0;
-};
-
-//template <>
-//bool TypedNode<Bool>::filter(Error *error,
-//                             ArrayCRef<Record> input_records,
-//                             ArrayRef<Record> *output_records) {
-//  // TODO: This implementation should be overridden by derived classes.
-//  Array<Bool> results;
-//  if (!results.resize(error, input_records.size())) {
-//    return false;
-//  }
-//  if (!evaluate(error, input_records, results)) {
-//    return false;
-//  }
-//  Int count = 0;
-//  for (Int i = 0; i < input_records.size(); ++i) {
-//    if (results[i]) {
-//      output_records->set(count, input_records.get(i));
-//      ++count;
-//    }
-//  }
-//  *output_records = output_records->ref(0, count);
-//  return true;
-//}
-
-template <>
-class TypedNode<Float> : public Node {
- public:
-  using Value = Float;
-
-  TypedNode() : Node(), scores_() {}
-  virtual ~TypedNode() {}
-
-  DataType data_type() const {
-    return TypeTraits<Value>::data_type();
-  }
-
-  bool filter(Error *error,
-              ArrayCRef<Record>,
-              ArrayRef<Record> *) {
-    // Other than TypedNode<Bool> don't support filter().
-    GRNXX_ERROR_SET(error, INVALID_OPERATION, "Invalid operation");
-    return false;
-  }
-
-  // Derived classes must override this member function.
-  virtual bool adjust(Error *error, ArrayRef<Record> records);
-
-  virtual bool evaluate(Error *error,
-                        ArrayCRef<Record> records,
-                        ArrayRef<Value> results) = 0;
-
- private:
-  Array<Float> scores_;
-};
-
-bool TypedNode<Float>::adjust(Error *error, ArrayRef<Record> records) {
-  // TODO: This implementation should be overridden by derived classes.
-  if (!scores_.resize(error, records.size())) {
-    return false;
-  }
-  if (!evaluate(error, records, scores_.ref())) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    records.set_score(i, scores_[i]);
-  }
-  return true;
-}
-
-// -- ConstantNode --
-
-template <typename T>
-class ConstantNode : public TypedNode<T> {
- public:
-  using Value = T;
-
-  static unique_ptr<Node> create(Error *error, Value datum) {
-    unique_ptr<Node> node(new (nothrow) ConstantNode(datum));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit ConstantNode(Value datum)
-      : TypedNode<Value>(),
-        datum_(datum) {}
-
-  NodeType node_type() const {
-    return CONSTANT_NODE;
-  }
-
-  bool evaluate(Error *,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    for (Int i = 0; i < records.size(); ++i) {
-      results[i] = datum_;
-    }
-    return true;
-  }
-
- private:
-  T datum_;
-};
-
-template <>
-class ConstantNode<Bool> : public TypedNode<Bool> {
- public:
-  using Value = Bool;
-
-  static unique_ptr<Node> create(Error *error, Value datum) {
-    unique_ptr<Node> node(new (nothrow) ConstantNode(datum));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit ConstantNode(Value datum)
-      : TypedNode<Value>(),
-        datum_(datum) {}
-
-  NodeType node_type() const {
-    return CONSTANT_NODE;
-  }
-
-  bool filter(Error *error,
-              ArrayCRef<Record> input_records,
-              ArrayRef<Record> *output_records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-
- private:
-  Value datum_;
-};
-
-bool ConstantNode<Bool>::filter(Error *,
-                                ArrayCRef<Record> input_records,
-                                ArrayRef<Record> *output_records) {
-  if (datum_) {
-    if (input_records != *output_records) {
-      for (Int i = 0; i < input_records.size(); ++i) {
-        output_records->set(i, input_records.get(i));
-      }
-    }
-  } else {
-    *output_records = output_records->ref(0, 0);
-  }
-  return true;
-}
-
-bool ConstantNode<Bool>::evaluate(Error *,
-                                  ArrayCRef<Record> records,
-                                  ArrayRef<Value> results) {
-  // TODO: Fill results per 64 bits.
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, datum_);
-  }
-  return true;
-}
-
-template <>
-class ConstantNode<Float> : public TypedNode<Float> {
- public:
-  using Value = Float;
-
-  static unique_ptr<Node> create(Error *error, Value datum) {
-    unique_ptr<Node> node(new (nothrow) ConstantNode(datum));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit ConstantNode(Value datum)
-      : TypedNode<Float>(),
-        datum_(datum) {}
-
-  NodeType node_type() const {
-    return CONSTANT_NODE;
-  }
-
-  bool adjust(Error *, ArrayRef<Record> records) {
-    for (Int i = 0; i < records.size(); ++i) {
-      records.set_score(i, datum_);
-    }
-    return true;
-  }
-  bool evaluate(Error *,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    for (Int i = 0; i < records.size(); ++i) {
-      results[i] = datum_;
-    }
-    return true;
-  }
-
- private:
-  Float datum_;
-};
-
-template <>
-class ConstantNode<Text> : public TypedNode<Text> {
- public:
-  using Value = Text;
-
-  static unique_ptr<Node> create(Error *error, Value datum) {
-    unique_ptr<ConstantNode> node(new (nothrow) ConstantNode);
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-      return nullptr;
-    }
-    if (!node->datum_.assign(error, datum)) {
-      return nullptr;
-    }
-    return unique_ptr<Node>(node.release());
-  }
-
-  explicit ConstantNode()
-      : TypedNode<Value>(),
-        datum_() {}
-
-  NodeType node_type() const {
-    return CONSTANT_NODE;
-  }
-
-  bool evaluate(Error *,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    for (Int i = 0; i < records.size(); ++i) {
-      results[i] = datum_;
-    }
-    return true;
-  }
-
- private:
-  String datum_;
-};
-
-template <>
-class ConstantNode<Vector<Int>> : public TypedNode<Vector<Int>> {
- public:
-  using Value = Vector<Int>;
-
-  static unique_ptr<Node> create(Error *error, Value value) {
-    unique_ptr<ConstantNode> node(new (nothrow) ConstantNode);
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-      return nullptr;
-    }
-    if (!node->value_.resize(error, value.size())) {
-      return nullptr;
-    }
-    for (Int i = 0; i < value.size(); ++i) {
-      node->value_[i] = value[i];
-    }
-    return unique_ptr<Node>(node.release());
-  }
-
-  explicit ConstantNode()
-      : TypedNode<Value>(),
-        value_() {}
-
-  NodeType node_type() const {
-    return CONSTANT_NODE;
-  }
-
-  bool evaluate(Error *,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    Value value(value_.data(), value_.size());
-    for (Int i = 0; i < records.size(); ++i) {
-      results[i] = value;
-    }
-    return true;
-  }
-
- private:
-  Array<Int> value_;
-};
-
-template <>
-class ConstantNode<Vector<Float>> : public TypedNode<Vector<Float>> {
- public:
-  using Value = Vector<Float>;
-
-  static unique_ptr<Node> create(Error *error, Value value) {
-    unique_ptr<ConstantNode> node(new (nothrow) ConstantNode);
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-      return nullptr;
-    }
-    if (!node->value_.resize(error, value.size())) {
-      return nullptr;
-    }
-    for (Int i = 0; i < value.size(); ++i) {
-      node->value_[i] = value[i];
-    }
-    return unique_ptr<Node>(node.release());
-  }
-
-  explicit ConstantNode()
-      : TypedNode<Value>(),
-        value_() {}
-
-  NodeType node_type() const {
-    return CONSTANT_NODE;
-  }
-
-  bool evaluate(Error *,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    Value value(value_.data(), value_.size());
-    for (Int i = 0; i < records.size(); ++i) {
-      results[i] = value;
-    }
-    return true;
-  }
-
- private:
-  Array<Float> value_;
-};
-
-template <>
-class ConstantNode<Vector<GeoPoint>> : public TypedNode<Vector<GeoPoint>> {
- public:
-  using Value = Vector<GeoPoint>;
-
-  static unique_ptr<Node> create(Error *error, Value value) {
-    unique_ptr<ConstantNode> node(new (nothrow) ConstantNode);
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-      return nullptr;
-    }
-    if (!node->value_.resize(error, value.size())) {
-      return nullptr;
-    }
-    for (Int i = 0; i < value.size(); ++i) {
-      node->value_[i] = value[i];
-    }
-    return unique_ptr<Node>(node.release());
-  }
-
-  explicit ConstantNode()
-      : TypedNode<Value>(),
-        value_() {}
-
-  NodeType node_type() const {
-    return CONSTANT_NODE;
-  }
-
-  bool evaluate(Error *,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    Value value(value_.data(), value_.size());
-    for (Int i = 0; i < records.size(); ++i) {
-      results[i] = value;
-    }
-    return true;
-  }
-
- private:
-  Array<GeoPoint> value_;
-};
-
-template <>
-class ConstantNode<Vector<Text>> : public TypedNode<Vector<Text>> {
- public:
-  using Value = Vector<Text>;
-
-  static unique_ptr<Node> create(Error *error, Value value) {
-    unique_ptr<ConstantNode> node(new (nothrow) ConstantNode);
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-      return nullptr;
-    }
-    Int total_size = 0;
-    for (Int i = 0; i < value.size(); ++i) {
-      total_size += value[i].size();
-    }
-    if (!node->value_.resize(error, value.size()) ||
-        !node->bodies_.resize(error, total_size)) {
-      return nullptr;
-    }
-    char *body = node->bodies_.data();
-    for (Int i = 0; i < value.size(); ++i) {
-      node->value_[i] = Text(body, value[i].size());
-      for (Int j = 0; j < value[i].size(); ++j) {
-        body[j] = value[i][j];
-      }
-      body += value[i].size();
-    }
-    return unique_ptr<Node>(node.release());
-  }
-
-  explicit ConstantNode()
-      : TypedNode<Value>(),
-        value_(),
-        bodies_() {}
-
-  NodeType node_type() const {
-    return CONSTANT_NODE;
-  }
-
-  bool evaluate(Error *,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    Value value(value_.data(), value_.size());
-    for (Int i = 0; i < records.size(); ++i) {
-      results[i] = value;
-    }
-    return true;
-  }
-
- private:
-  Array<Text> value_;
-  Array<char> bodies_;
-};
-
-// -- RowIDNode --
-
-class RowIDNode : public TypedNode<Int> {
- public:
-  using Value = Int;
-
-  static unique_ptr<Node> create(Error *error) {
-    unique_ptr<Node> node(new (nothrow) RowIDNode);
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  RowIDNode() : TypedNode<Value>() {}
-
-  NodeType node_type() const {
-    return ROW_ID_NODE;
-  }
-
-  bool evaluate(Error *,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    for (Int i = 0; i < records.size(); ++i) {
-      results[i] = records.get_row_id(i);
-    }
-    return true;
-  }
-};
-
-// -- ScoreNode --
-
-class ScoreNode : public TypedNode<Float> {
- public:
-  using Value = Float;
-
-  static unique_ptr<Node> create(Error *error) {
-    unique_ptr<Node> node(new (nothrow) ScoreNode);
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  ScoreNode() : TypedNode<Value>() {}
-
-  NodeType node_type() const {
-    return SCORE_NODE;
-  }
-
-  bool adjust(Error *, ArrayRef<Record>) {
-    // Nothing to do.
-    return true;
-  }
-  bool evaluate(Error *,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    for (Int i = 0; i < records.size(); ++i) {
-      results[i] = records.get_score(i);
-    }
-    return true;
-  }
-};
-
-// -- ColumnNode --
-
-template <typename T>
-class ColumnNode : public TypedNode<T> {
- public:
-  using Value = T;
-
-  static unique_ptr<Node> create(Error *error, const Column *column) {
-    unique_ptr<Node> node(new (nothrow) ColumnNode(column));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit ColumnNode(const Column *column)
-      : TypedNode<Value>(),
-        column_(static_cast<const impl::Column<Value> *>(column)) {}
-
-  NodeType node_type() const {
-    return COLUMN_NODE;
-  }
-  const Table *ref_table() const {
-    return column_->ref_table();
-  }
-
-  bool evaluate(Error *,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    column_->read(records, results);
-    return true;
-  }
-
- private:
-  const impl::Column<T> *column_;
-};
-
-template <>
-class ColumnNode<Bool> : public TypedNode<Bool> {
- public:
-  using Value = Bool;
-
-  static unique_ptr<Node> create(Error *error, const Column *column) {
-    unique_ptr<Node> node(new (nothrow) ColumnNode(column));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit ColumnNode(const Column *column)
-      : TypedNode<Value>(),
-        column_(static_cast<const impl::Column<Value> *>(column)) {}
-
-  NodeType node_type() const {
-    return COLUMN_NODE;
-  }
-
-  bool filter(Error *error,
-              ArrayCRef<Record> input_records,
-              ArrayRef<Record> *output_records);
-  bool evaluate(Error *,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    column_->read(records, results);
-    return true;
-  }
-
- private:
-  const impl::Column<Value> *column_;
-};
-
-bool ColumnNode<Bool>::filter(Error *,
-                              ArrayCRef<Record> input_records,
-                              ArrayRef<Record> *output_records) {
-  Int dest = 0;
-  for (Int i = 0; i < input_records.size(); ++i) {
-    if (column_->get(input_records.get_row_id(i))) {
-      output_records->set(dest, input_records.get(i));
-      ++dest;
-    }
-  }
-  *output_records = output_records->ref(0, dest);
-  return true;
-}
-
-template <>
-class ColumnNode<Float> : public TypedNode<Float> {
- public:
-  using Value = Float;
-
-  static unique_ptr<Node> create(Error *error, const Column *column) {
-    unique_ptr<Node> node(new (nothrow) ColumnNode(column));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit ColumnNode(const Column *column)
-      : TypedNode<Value>(),
-        column_(static_cast<const impl::Column<Value> *>(column)) {}
-
-  NodeType node_type() const {
-    return COLUMN_NODE;
-  }
-
-  bool adjust(Error *, ArrayRef<Record> records) {
-    for (Int i = 0; i < records.size(); ++i) {
-      records.set_score(i, column_->get(records.get_row_id(i)));
-    }
-    return true;
-  }
-  bool evaluate(Error *,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results) {
-    column_->read(records, results);
-    return true;
-  }
-
- private:
-  const impl::Column<Value> *column_;
-};
-
-// -- OperatorNode --
-
-template <typename T>
-class OperatorNode : public TypedNode<T> {
- public:
-  using Value = T;
-
-  OperatorNode() : TypedNode<Value>() {}
-  virtual ~OperatorNode() {}
-
-  NodeType node_type() const {
-    return OPERATOR_NODE;
-  }
-};
-
-// Evaluate "*arg" for "records".
-//
-// The evaluation results are stored into "*arg_values".
-//
-// On success, returns true.
-// On failure, returns false and stores error information into "*error" if
-// "error" != nullptr.
-template <typename T>
-bool fill_node_arg_values(Error *error, ArrayCRef<Record> records,
-                          TypedNode<T> *arg, Array<T> *arg_values) {
-  Int old_size = arg_values->size();
-  if (old_size < records.size()) {
-    if (!arg_values->resize(error, records.size())) {
-      return false;
-    }
-  }
-  switch (arg->node_type()) {
-    case CONSTANT_NODE: {
-      if (old_size < records.size()) {
-        if (!arg->evaluate(error, records.ref(old_size),
-                           arg_values->ref(old_size))) {
-          return false;
-        }
-      }
-      break;
-    }
-    default: {
-      if (!arg->evaluate(error, records, arg_values->ref(0, records.size()))) {
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-// --- UnaryNode ---
-
-template <typename T, typename U>
-class UnaryNode : public OperatorNode<T> {
- public:
-  using Value = T;
-  using Arg = U;
-
-  explicit UnaryNode(unique_ptr<Node> &&arg)
-      : OperatorNode<Value>(),
-        arg_(static_cast<TypedNode<Arg> *>(arg.release())),
-        arg_values_() {}
-  virtual ~UnaryNode() {}
-
- protected:
-  unique_ptr<TypedNode<Arg>> arg_;
-  Array<Arg> arg_values_;
-
-  bool fill_arg_values(Error *error, ArrayCRef<Record> records) {
-    return fill_node_arg_values(error, records, arg_.get(), &arg_values_);
-  }
-};
-
-// ---- LogicalNotNode ----
-
-class LogicalNotNode : public UnaryNode<Bool, Bool> {
- public:
-  using Value = Bool;
-  using Arg = Bool;
-
-  static unique_ptr<Node> create(Error *error, unique_ptr<Node> &&arg) {
-    unique_ptr<Node> node(new (nothrow) LogicalNotNode(std::move(arg)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit LogicalNotNode(unique_ptr<Node> &&arg)
-      : UnaryNode<Value, Arg>(std::move(arg)),
-        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 LogicalNotNode::filter(Error *error,
-                            ArrayCRef<Record> input_records,
-                            ArrayRef<Record> *output_records) {
-  // Apply an argument filter to "input_records" and store the result to
-  // "temp_records_". Then, appends a sentinel to the end.
-  if (!temp_records_.resize(error, input_records.size() + 1)) {
-    return false;
-  }
-  ArrayRef<Record> ref = temp_records_.ref();
-  if (!arg_->filter(error, input_records, &ref)) {
-    return false;
-  }
-  temp_records_.set_row_id(ref.size(), NULL_ROW_ID);
-
-  // Extract records which appear in "input_records" and don't appear in "ref".
-  Int count = 0;
-  for (Int i = 0, j = 0; i < input_records.size(); ++i) {
-    if (input_records.get_row_id(i) == ref.get_row_id(j)) {
-      ++j;
-      continue;
-    }
-    output_records->set(count, input_records.get(i));
-    ++count;
-  }
-  *output_records = output_records->ref(0, count);
-  return true;
-}
-
-bool LogicalNotNode::evaluate(Error *error,
-                              ArrayCRef<Record> records,
-                              ArrayRef<Value> results) {
-  // Apply an argument filter to "records" and store the result to
-  // "temp_records_". Then, appends a sentinel to the end.
-  if (!temp_records_.resize(error, records.size() + 1)) {
-    return false;
-  }
-  ArrayRef<Record> ref = temp_records_.ref();
-  if (!arg_->filter(error, records, &ref)) {
-    return false;
-  }
-  temp_records_.set_row_id(ref.size(), NULL_ROW_ID);
-
-  // Compare records in "records" and "ref".
-  Int count = 0;
-  for (Int i = 0; i < records.size(); ++i) {
-    if (records.get_row_id(i) == ref.get_row_id(count)) {
-      results.set(i, false);
-      ++count;
-    } else {
-      results.set(i, true);
-    }
-  }
-  return true;
-}
-
-// ---- BitwiseNotNode ----
-
-template <typename T> class BitwiseNotNode;
-
-template <>
-class BitwiseNotNode<Bool> : public UnaryNode<Bool, Bool> {
- public:
-  using Value = Bool;
-  using Arg = Bool;
-
-  static unique_ptr<Node> create(Error *error, unique_ptr<Node> &&arg) {
-    unique_ptr<Node> node(new (nothrow) BitwiseNotNode(std::move(arg)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit BitwiseNotNode(unique_ptr<Node> &&arg)
-      : UnaryNode<Value, Arg>(std::move(arg)) {}
-
-  bool filter(Error *error,
-              ArrayCRef<Record> input_records,
-              ArrayRef<Record> *output_records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool BitwiseNotNode<Bool>::filter(Error *error,
-                                  ArrayCRef<Record> input_records,
-                                  ArrayRef<Record> *output_records) {
-  if (!fill_arg_values(error, input_records)) {
-    return false;
-  }
-  Int count = 0;
-  for (Int i = 0; i < input_records.size(); ++i) {
-    if (!arg_values_[i]) {
-      output_records->set(count, input_records.get(i));
-      ++count;
-    }
-  }
-  *output_records = output_records->ref(0, count);
-  return true;
-}
-
-bool BitwiseNotNode<Bool>::evaluate(Error *error,
-                                    ArrayCRef<Record> records,
-                                    ArrayRef<Value> results) {
-  if (!arg_->evaluate(error, records, results)) {
-    return false;
-  }
-  // TODO: Should be processed per 64 bits.
-  //       Check the 64-bit boundary and do it!
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, !results.get(i));
-  }
-  return true;
-}
-
-template <>
-class BitwiseNotNode<Int> : public UnaryNode<Int, Int> {
- public:
-  using Value = Int;
-  using Arg = Int;
-
-  static unique_ptr<Node> create(Error *error, unique_ptr<Node> &&arg) {
-    unique_ptr<Node> node(
-        new (nothrow) BitwiseNotNode(std::move(arg)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit BitwiseNotNode(unique_ptr<Node> &&arg)
-      : UnaryNode<Value, Arg>(std::move(arg)) {}
-
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool BitwiseNotNode<Int>::evaluate(Error *error,
-                                   ArrayCRef<Record> records,
-                                   ArrayRef<Value> results) {
-  if (!arg_->evaluate(error, records, results)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, ~results.get(i));
-  }
-  return true;
-}
-
-// ---- PositiveNode ----
-
-// Nothing to do.
-
-// ---- NegativeNode ----
-
-template <typename T> class NegativeNode;
-
-template <>
-class NegativeNode<Int> : public UnaryNode<Int, Int> {
- public:
-  using Value = Int;
-  using Arg = Int;
-
-  static unique_ptr<Node> create(Error *error, unique_ptr<Node> &&arg) {
-    unique_ptr<Node> node(new (nothrow) NegativeNode(std::move(arg)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit NegativeNode(unique_ptr<Node> &&arg)
-      : UnaryNode<Value, Arg>(std::move(arg)) {}
-
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool NegativeNode<Int>::evaluate(Error *error,
-                                 ArrayCRef<Record> records,
-                                 ArrayRef<Value> results) {
-  if (!arg_->evaluate(error, records, results)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, -results.get(i));
-  }
-  return true;
-}
-
-template <>
-class NegativeNode<Float> : public UnaryNode<Float, Float> {
- public:
-  using Value = Float;
-  using Arg = Float;
-
-  static unique_ptr<Node> create(Error *error, unique_ptr<Node> &&arg) {
-    unique_ptr<Node> node(new (nothrow) NegativeNode(std::move(arg)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit NegativeNode(unique_ptr<Node> &&arg)
-      : UnaryNode<Value, Arg>(std::move(arg)) {}
-
-  bool adjust(Error *error, ArrayRef<Record> records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool NegativeNode<Float>::adjust(Error *error, ArrayRef<Record> records) {
-  if (!arg_->adjust(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    records.set_score(i, -records.get_score(i));
-  }
-  return true;
-}
-
-bool NegativeNode<Float>::evaluate(Error *error,
-                                   ArrayCRef<Record> records,
-                                   ArrayRef<Value> results) {
-  if (!arg_->evaluate(error, records, results)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, -results.get(i));
-  }
-  return true;
-}
-
-// ---- ToIntNode ----
-
-class ToIntNode : public UnaryNode<Int, Float> {
- public:
-  using Value = Int;
-  using Arg = Float;
-
-  static unique_ptr<Node> create(Error *error, unique_ptr<Node> &&arg) {
-    unique_ptr<Node> node(new (nothrow) ToIntNode(std::move(arg)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit ToIntNode(unique_ptr<Node> &&arg)
-      : UnaryNode<Value, Arg>(std::move(arg)) {}
-
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool ToIntNode::evaluate(Error *error,
-                         ArrayCRef<Record> records,
-                         ArrayRef<Value> results) {
-  if (!fill_arg_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, static_cast<Value>(arg_values_[i]));
-  }
-  return true;
-}
-
-// ---- ToFloatNode ----
-
-class ToFloatNode : public UnaryNode<Float, Int> {
- public:
-  using Value = Float;
-  using Arg = Int;
-
-  static unique_ptr<Node> create(Error *error, unique_ptr<Node> &&arg) {
-    unique_ptr<Node> node(new (nothrow) ToFloatNode(std::move(arg)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  explicit ToFloatNode(unique_ptr<Node> &&arg)
-      : UnaryNode<Value, Arg>(std::move(arg)) {}
-
-  bool adjust(Error *error, ArrayRef<Record> records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool ToFloatNode::adjust(Error *error, ArrayRef<Record> records) {
-  if (!fill_arg_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    records.set_score(i, static_cast<Value>(arg_values_[i]));
-  }
-  return true;
-}
-
-bool ToFloatNode::evaluate(Error *error,
-                           ArrayCRef<Record> records,
-                           ArrayRef<Value> results) {
-  if (!fill_arg_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, static_cast<Value>(arg_values_[i]));
-  }
-  return true;
-}
-
-// --- BinaryNode ---
-
-template <typename T, typename U, typename V>
-class BinaryNode : public OperatorNode<T> {
- public:
-  using Value = T;
-  using Arg1 = U;
-  using Arg2 = V;
-
-  BinaryNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : OperatorNode<Value>(),
-        arg1_(static_cast<TypedNode<Arg1> *>(arg1.release())),
-        arg2_(static_cast<TypedNode<Arg2> *>(arg2.release())),
-        arg1_values_(),
-        arg2_values_() {}
-  virtual ~BinaryNode() {}
-
- protected:
-  unique_ptr<TypedNode<Arg1>> arg1_;
-  unique_ptr<TypedNode<Arg2>> arg2_;
-  Array<Arg1> arg1_values_;
-  Array<Arg2> arg2_values_;
-
-  bool fill_arg1_values(Error *error, ArrayCRef<Record> records) {
-    return fill_node_arg_values(error, records, arg1_.get(), &arg1_values_);
-  }
-  bool fill_arg2_values(Error *error, ArrayCRef<Record> records) {
-    return fill_node_arg_values(error, records, arg2_.get(), &arg2_values_);
-  }
-};
-
-// ---- LogicalAndNode ----
-
-class LogicalAndNode : public BinaryNode<Bool, Bool, Bool> {
- public:
-  using Value = Bool;
-  using Arg1 = Bool;
-  using Arg2 = Bool;
-
-  static unique_ptr<Node> create(Error *error,
-                                 unique_ptr<Node> &&arg1,
-                                 unique_ptr<Node> &&arg2) {
-    unique_ptr<Node> node(
-        new (nothrow) LogicalAndNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  LogicalAndNode(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) {
-    return arg1_->filter(error, input_records, output_records) &&
-           arg2_->filter(error, *output_records, output_records);
-  }
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-
- private:
-  Array<Record> temp_records_;
-};
-
-bool LogicalAndNode::evaluate(Error *error,
-                              ArrayCRef<Record> records,
-                              ArrayRef<Value> results) {
-  // Apply argument filters to "records" and store the result to
-  // "temp_records_". Then, appends a sentinel to the end.
-  if (!temp_records_.resize(error, records.size() + 1)) {
-    return false;
-  }
-  ArrayRef<Record> ref = temp_records_.ref();
-  if (!arg1_->filter(error, records, &ref) ||
-      !arg2_->filter(error, ref, &ref)) {
-    return false;
-  }
-  temp_records_.set_row_id(ref.size(), NULL_ROW_ID);
-
-  // Compare records in "records" and "ref".
-  Int count = 0;
-  for (Int i = 0; i < records.size(); ++i) {
-    if (records.get_row_id(i) == ref.get_row_id(count)) {
-      results.set(i, true);
-      ++count;
-    } else {
-      results.set(i, false);
-    }
-  }
-  return true;
-}
-
-// ---- LogicalOrNode ----
-
-class LogicalOrNode : public BinaryNode<Bool, Bool, Bool> {
- public:
-  using Value = Bool;
-  using Arg1 = Bool;
-  using Arg2 = Bool;
-
-  static unique_ptr<Node> create(Error *error,
-                                 unique_ptr<Node> &&arg1,
-                                 unique_ptr<Node> &&arg2) {
-    unique_ptr<Node> node(
-        new (nothrow) LogicalOrNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  LogicalOrNode(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 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_.ref();
-  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<Value> 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_.ref();
-  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;
-}
-
-// ---- ComparisonNode ----
-
-template <typename T>
-class ComparisonNode
-    : public BinaryNode<Bool, typename T::Arg, typename T::Arg> {
- public:
-  using Comparer = T;
-  using Value = Bool;
-  using Arg1 = typename T::Arg;
-  using Arg2 = typename T::Arg;
-
-  static unique_ptr<Node> create(Error *error,
-                                 unique_ptr<Node> &&arg1,
-                                 unique_ptr<Node> &&arg2) {
-    unique_ptr<Node> node(
-        new (nothrow) ComparisonNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  ComparisonNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)),
-        comparer_() {}
-
-  bool filter(Error *error,
-              ArrayCRef<Record> input_records,
-              ArrayRef<Record> *output_records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-
- protected:
-  Comparer comparer_;
-};
-
-template <typename T>
-bool ComparisonNode<T>::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 (comparer_(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;
-}
-
-template <typename T>
-bool ComparisonNode<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, comparer_(this->arg1_values_[i], this->arg2_values_[i]));
-  }
-  return true;
-}
-
-// ----- EqualNode -----
-
-// TODO: EqualNode for Bool should be specialized.
-
-struct Equal {
-  template <typename T>
-  struct Comparer {
-    using Arg = T;
-    Bool operator()(Arg arg1, Arg arg2) const {
-      return arg1 == arg2;
-    }
-  };
-};
-
-template <typename T>
-using EqualNode = ComparisonNode<Equal::Comparer<T>>;
-
-// ----- NotEqualNode -----
-
-// TODO: NotEqualNode for Bool should be specialized.
-
-struct NotEqual {
-  template <typename T>
-  struct Comparer {
-    using Arg = T;
-    Bool operator()(Arg arg1, Arg arg2) const {
-      return arg1 != arg2;
-    }
-  };
-};
-
-template <typename T>
-using NotEqualNode = ComparisonNode<NotEqual::Comparer<T>>;
-
-// ----- LessNode -----
-
-struct Less {
-  template <typename T>
-  struct Comparer {
-    using Arg = T;
-    Bool operator()(Arg arg1, Arg arg2) const {
-      return arg1 < arg2;
-    }
-  };
-};
-
-template <typename T>
-using LessNode = ComparisonNode<Less::Comparer<T>>;
-
-// ----- LessEqualNode -----
-
-struct LessEqual {
-  template <typename T>
-  struct Comparer {
-    using Arg = T;
-    Bool operator()(Arg arg1, Arg arg2) const {
-      return arg1 <= arg2;
-    }
-  };
-};
-
-template <typename T>
-using LessEqualNode = ComparisonNode<LessEqual::Comparer<T>>;
-
-// ----- GreaterNode -----
-
-struct Greater {
-  template <typename T>
-  struct Comparer {
-    using Arg = T;
-    Bool operator()(Arg arg1, Arg arg2) const {
-      return arg1 > arg2;
-    }
-  };
-};
-
-template <typename T>
-using GreaterNode = ComparisonNode<Greater::Comparer<T>>;
-
-// ----- GreaterEqualNode -----
-
-struct GreaterEqual {
-  template <typename T>
-  struct Comparer {
-    using Arg = T;
-    Bool operator()(Arg arg1, Arg arg2) const {
-      return arg1 >= arg2;
-    }
-  };
-};
-
-template <typename T>
-using GreaterEqualNode = ComparisonNode<GreaterEqual::Comparer<T>>;
-
-// ---- BitwiseAndNode ----
-
-// TODO: BitwiseAnd/Or/XorNode should be implemented on the same base class?
-
-template <typename T> class BitwiseAndNode;
-
-template <>
-class BitwiseAndNode<Bool> : public BinaryNode<Bool, Bool, Bool> {
- public:
-  using Value = Bool;
-  using Arg1 = Bool;
-  using Arg2 = Bool;
-
-  static unique_ptr<Node> create(Error *error,
-                                 unique_ptr<Node> &&arg1,
-                                 unique_ptr<Node> &&arg2) {
-    unique_ptr<Node> node(
-        new (nothrow) BitwiseAndNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  BitwiseAndNode(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 BitwiseAndNode<Bool>::filter(Error *error,
-                                  ArrayCRef<Record> input_records,
-                                  ArrayRef<Record> *output_records) {
-  if (!fill_arg1_values(error, input_records) ||
-      !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 BitwiseAndNode<Bool>::evaluate(Error *error,
-                                    ArrayCRef<Record> records,
-                                    ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  // TODO: Should be processed per 64 bits.
-  //       Check the 64-bit boundary and do it!
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, this->arg1_values_[i] & this->arg2_values_[i]);
-  }
-  return true;
-}
-
-template <>
-class BitwiseAndNode<Int> : public BinaryNode<Int, Int, Int> {
- public:
-  using Value = Int;
-  using Arg1 = Int;
-  using Arg2 = Int;
-
-  static unique_ptr<Node> create(Error *error,
-                                 unique_ptr<Node> &&arg1,
-                                 unique_ptr<Node> &&arg2) {
-    unique_ptr<Node> node(
-        new (nothrow) BitwiseAndNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  BitwiseAndNode(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);
-};
-
-bool BitwiseAndNode<Int>::evaluate(Error *error,
-                                   ArrayCRef<Record> records,
-                                   ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  // TODO: Should be processed per 64 bits.
-  //       Check the 64-bit boundary and do it!
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, this->arg1_values_[i] & this->arg2_values_[i]);
-  }
-  return true;
-}
-
-// ---- BitwiseOrNode ----
-
-template <typename T> class BitwiseOrNode;
-
-template <>
-class BitwiseOrNode<Bool> : public BinaryNode<Bool, Bool, Bool> {
- public:
-  using Value = Bool;
-  using Arg1 = Bool;
-  using Arg2 = Bool;
-
-  static unique_ptr<Node> create(Error *error,
-                                 unique_ptr<Node> &&arg1,
-                                 unique_ptr<Node> &&arg2) {
-    unique_ptr<Node> node(
-        new (nothrow) BitwiseOrNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  BitwiseOrNode(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 BitwiseOrNode<Bool>::filter(Error *error,
-                                 ArrayCRef<Record> input_records,
-                                 ArrayRef<Record> *output_records) {
-  if (!fill_arg1_values(error, input_records) ||
-      !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 BitwiseOrNode<Bool>::evaluate(Error *error,
-                                   ArrayCRef<Record> records,
-                                   ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  // TODO: Should be processed per 64 bits.
-  //       Check the 64-bit boundary and do it!
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, this->arg1_values_[i] | this->arg2_values_[i]);
-  }
-  return true;
-}
-
-template <>
-class BitwiseOrNode<Int> : public BinaryNode<Int, Int, Int> {
- public:
-  using Value = Int;
-  using Arg1 = Int;
-  using Arg2 = Int;
-
-  static unique_ptr<Node> create(Error *error,
-                                 unique_ptr<Node> &&arg1,
-                                 unique_ptr<Node> &&arg2) {
-    unique_ptr<Node> node(
-        new (nothrow) BitwiseOrNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  BitwiseOrNode(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);
-};
-
-bool BitwiseOrNode<Int>::evaluate(Error *error,
-                                  ArrayCRef<Record> records,
-                                  ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  // TODO: Should be processed per 64 bits.
-  //       Check the 64-bit boundary and do it!
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, this->arg1_values_[i] | this->arg2_values_[i]);
-  }
-  return true;
-}
-
-// ---- BitwiseXorNode ----
-
-template <typename T> class BitwiseXorNode;
-
-template <>
-class BitwiseXorNode<Bool> : public BinaryNode<Bool, Bool, Bool> {
- public:
-  using Value = Bool;
-  using Arg1 = Bool;
-  using Arg2 = Bool;
-
-  static unique_ptr<Node> create(Error *error,
-                                 unique_ptr<Node> &&arg1,
-                                 unique_ptr<Node> &&arg2) {
-    unique_ptr<Node> node(
-        new (nothrow) BitwiseXorNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  BitwiseXorNode(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 BitwiseXorNode<Bool>::filter(Error *error,
-                                  ArrayCRef<Record> input_records,
-                                  ArrayRef<Record> *output_records) {
-  if (!fill_arg1_values(error, input_records) ||
-      !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 BitwiseXorNode<Bool>::evaluate(Error *error,
-                                    ArrayCRef<Record> records,
-                                    ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  // TODO: Should be processed per 64 bits.
-  //       Check the 64-bit boundary and do it!
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, this->arg1_values_[i] ^ this->arg2_values_[i]);
-  }
-  return true;
-}
-
-template <>
-class BitwiseXorNode<Int> : public BinaryNode<Int, Int, Int> {
- public:
-  using Value = Int;
-  using Arg1 = Int;
-  using Arg2 = Int;
-
-  static unique_ptr<Node> create(Error *error,
-                                 unique_ptr<Node> &&arg1,
-                                 unique_ptr<Node> &&arg2) {
-    unique_ptr<Node> node(
-        new (nothrow) BitwiseXorNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  BitwiseXorNode(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);
-};
-
-bool BitwiseXorNode<Int>::evaluate(Error *error,
-                                   ArrayCRef<Record> records,
-                                   ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  // TODO: Should be processed per 64 bits.
-  //       Check the 64-bit boundary and do it!
-  for (Int i = 0; i < records.size(); ++i) {
-    results.set(i, this->arg1_values_[i] ^ this->arg2_values_[i]);
-  }
-  return true;
-}
-
-// ---- PlusOperator ----
-
-template <typename T> class PlusNode;
-
-template <>
-class PlusNode<Int> : public BinaryNode<Int, Int, Int> {
- public:
-  using Value = Int;
-  using Arg1 = Int;
-  using Arg2 = Int;
-
-  static unique_ptr<Node> create(Error *error,
-                                 unique_ptr<Node> &&arg1,
-                                 unique_ptr<Node> &&arg2) {
-    unique_ptr<Node> node(
-        new (nothrow) PlusNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  PlusNode(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);
-};
-
-bool PlusNode<Int>::evaluate(Error *error,
-                             ArrayCRef<Record> records,
-                             ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !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 PlusNode<Float> : public BinaryNode<Float, Float, Float> {
- public:
-  using Value = Float;
-  using Arg1 = Float;
-  using Arg2 = Float;
-
-  static unique_ptr<Node> create(Error *error,
-                                 unique_ptr<Node> &&arg1,
-                                 unique_ptr<Node> &&arg2) {
-    unique_ptr<Node> node(
-        new (nothrow) PlusNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  PlusNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
-
-  bool adjust(Error *error, ArrayRef<Record> records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool PlusNode<Float>::adjust(Error *error, ArrayRef<Record> records) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    records.set_score(i, this->arg1_values_[i] + this->arg2_values_[i]);
-  }
-  return true;
-}
-
-bool PlusNode<Float>::evaluate(Error *error,
-                               ArrayCRef<Record> records,
-                               ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !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;
-}
-
-// ---- MinusOperator ----
-
-template <typename T> class MinusNode;
-
-template <>
-class MinusNode<Int> : public BinaryNode<Int, Int, Int> {
- public:
-  using Value = Int;
-  using Arg1 = Int;
-  using Arg2 = Int;
-
-  static unique_ptr<Node> create(Error *error,
-                                 unique_ptr<Node> &&arg1,
-                                 unique_ptr<Node> &&arg2) {
-    unique_ptr<Node> node(
-        new (nothrow) MinusNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  MinusNode(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);
-};
-
-bool MinusNode<Int>::evaluate(Error *error,
-                              ArrayCRef<Record> records,
-                              ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !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 MinusNode<Float> : public BinaryNode<Float, Float, Float> {
- public:
-  using Value = Float;
-  using Arg1 = Float;
-  using Arg2 = Float;
-
-  static unique_ptr<Node> create(Error *error,
-                                 unique_ptr<Node> &&arg1,
-                                 unique_ptr<Node> &&arg2) {
-    unique_ptr<Node> node(
-        new (nothrow) MinusNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  MinusNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
-
-  bool adjust(Error *error, ArrayRef<Record> records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool MinusNode<Float>::adjust(Error *error, ArrayRef<Record> records) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    records.set_score(i, this->arg1_values_[i] - this->arg2_values_[i]);
-  }
-  return true;
-}
-
-bool MinusNode<Float>::evaluate(Error *error,
-                                ArrayCRef<Record> records,
-                                ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !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;
-}
-
-// ---- MultiplicationOperator ----
-
-template <typename T> class MultiplicationNode;
-
-template <>
-class MultiplicationNode<Int> : public BinaryNode<Int, Int, Int> {
- public:
-  using Value = Int;
-  using Arg1 = Int;
-  using Arg2 = Int;
-
-  static unique_ptr<Node> create(Error *error,
-                                 unique_ptr<Node> &&arg1,
-                                 unique_ptr<Node> &&arg2) {
-    unique_ptr<Node> node(
-        new (nothrow) MultiplicationNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  MultiplicationNode(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);
-};
-
-bool MultiplicationNode<Int>::evaluate(Error *error,
-                                       ArrayCRef<Record> records,
-                                       ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !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 MultiplicationNode<Float> : public BinaryNode<Float, Float, Float> {
- public:
-  using Value = Float;
-  using Arg1 = Float;
-  using Arg2 = Float;
-
-  static unique_ptr<Node> create(Error *error,
-                                 unique_ptr<Node> &&arg1,
-                                 unique_ptr<Node> &&arg2) {
-    unique_ptr<Node> node(
-        new (nothrow) MultiplicationNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  MultiplicationNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
-
-  bool adjust(Error *error, ArrayRef<Record> records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool MultiplicationNode<Float>::adjust(Error *error,
-                                       ArrayRef<Record> records) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    records.set_score(i, this->arg1_values_[i] * this->arg2_values_[i]);
-  }
-  return true;
-}
-
-bool MultiplicationNode<Float>::evaluate(Error *error,
-                                         ArrayCRef<Record> records,
-                                         ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !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;
-}
-
-// ---- DivisionOperator ----
-
-template <typename T> class DivisionNode;
-
-template <>
-class DivisionNode<Int> : public BinaryNode<Int, Int, Int> {
- public:
-  using Value = Int;
-  using Arg1 = Int;
-  using Arg2 = Int;
-
-  static unique_ptr<Node> create(Error *error,
-                                 unique_ptr<Node> &&arg1,
-                                 unique_ptr<Node> &&arg2) {
-    unique_ptr<Node> node(
-        new (nothrow) DivisionNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  DivisionNode(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);
-};
-
-bool DivisionNode<Int>::evaluate(Error *error,
-                                 ArrayCRef<Record> records,
-                                 ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    if (this->arg2_values_[i] == 0) {
-      GRNXX_ERROR_SET(error, DIVISION_BY_ZERO, "Division by zero");
-      return false;
-    } else if ((this->arg2_values_[i] == -1) &&
-               (this->arg1_values_[i] == numeric_limits<Int>::min())) {
-      GRNXX_ERROR_SET(error, DIVISION_OVERFLOW, "Division overflow");
-      return false;
-    }
-    results.set(i, this->arg1_values_[i] / this->arg2_values_[i]);
-  }
-  return true;
-}
-
-template <>
-class DivisionNode<Float> : public BinaryNode<Float, Float, Float> {
- public:
-  using Value = Float;
-  using Arg1 = Float;
-  using Arg2 = Float;
-
-  static unique_ptr<Node> create(Error *error,
-                                 unique_ptr<Node> &&arg1,
-                                 unique_ptr<Node> &&arg2) {
-    unique_ptr<Node> node(
-        new (nothrow) DivisionNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  DivisionNode(unique_ptr<Node> &&arg1, unique_ptr<Node> &&arg2)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)) {}
-
-  bool adjust(Error *error, ArrayRef<Record> records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool DivisionNode<Float>::adjust(Error *error,
-                                 ArrayRef<Record> records) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    records.set_score(i, this->arg1_values_[i] / this->arg2_values_[i]);
-  }
-  return true;
-}
-
-bool DivisionNode<Float>::evaluate(Error *error,
-                                   ArrayCRef<Record> records,
-                                   ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !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;
-}
-
-// ---- ModulusOperator ----
-
-template <typename T> class ModulusNode;
-
-template <>
-class ModulusNode<Int> : public BinaryNode<Int, Int, Int> {
- public:
-  using Value = Int;
-  using Arg1 = Int;
-  using Arg2 = Int;
-
-  static unique_ptr<Node> create(Error *error,
-                                 unique_ptr<Node> &&arg1,
-                                 unique_ptr<Node> &&arg2) {
-    unique_ptr<Node> node(
-        new (nothrow) ModulusNode(std::move(arg1), std::move(arg2)));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  ModulusNode(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);
-};
-
-bool ModulusNode<Int>::evaluate(Error *error,
-                                ArrayCRef<Record> records,
-                                ArrayRef<Value> results) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    if (this->arg2_values_[i] == 0) {
-      GRNXX_ERROR_SET(error, DIVISION_BY_ZERO, "Division by zero");
-      return false;
-    } else if ((this->arg2_values_[i] == -1) &&
-               (this->arg1_values_[i] == numeric_limits<Int>::min())) {
-      GRNXX_ERROR_SET(error, DIVISION_OVERFLOW, "Division overflow");
-      return false;
-    }
-    results.set(i, this->arg1_values_[i] % this->arg2_values_[i]);
-  }
-  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)) {}
-
-  const Table *ref_table() const {
-    return this->arg1_->ref_table();
-  }
-
-  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) {
-    auto arg1_value = this->arg1_values_[i];
-    auto arg2_value = this->arg2_values_[i];
-    if (arg2_value < arg1_value.size()) {
-      results.set(i, arg1_value[arg2_value]);
-    } else {
-      results.set(i, TypeTraits<T>::default_value());
-    }
-  }
-  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) {
-    auto arg1_value = this->arg1_values_[i];
-    auto arg2_value = this->arg2_values_[i];
-    if (arg2_value < arg1_value.size()) {
-      if (arg1_value[arg2_value]) {
-        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) {
-    auto arg1_value = this->arg1_values_[i];
-    auto arg2_value = this->arg2_values_[i];
-    if (arg2_value < arg1_value.size()) {
-      results.set(i, arg1_value[arg2_value]);
-    } else {
-      results.set(i, TypeTraits<Bool>::default_value());
-    }
-  }
-  return true;
-}
-
-template <>
-class SubscriptNode<Float> : public BinaryNode<Float, Vector<Float>, Int> {
- public:
-  using Value = Float;
-  using Arg1 = Vector<Float>;
-  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 adjust(Error *error, ArrayRef<Record> records);
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-};
-
-bool SubscriptNode<Float>::adjust(Error *error,
-                                  ArrayRef<Record> records) {
-  if (!fill_arg1_values(error, records) ||
-      !fill_arg2_values(error, records)) {
-    return false;
-  }
-  for (Int i = 0; i < records.size(); ++i) {
-    auto arg1_value = this->arg1_values_[i];
-    auto arg2_value = this->arg2_values_[i];
-    if (arg2_value < arg1_value.size()) {
-      records.set_score(i, arg1_value[arg2_value]);
-    } else {
-      records.set_score(i, TypeTraits<Float>::default_value());
-    }
-  }
-  return true;
-}
-
-bool SubscriptNode<Float>::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) {
-    auto arg1_value = this->arg1_values_[i];
-    auto arg2_value = this->arg2_values_[i];
-    if (arg2_value < arg1_value.size()) {
-      results.set(i, arg1_value[arg2_value]);
-    } else {
-      results.set(i, TypeTraits<Float>::default_value());
-    }
-  }
-  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,
-                                 const ExpressionOptions &) {
-    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_() {}
-
-  const Table *ref_table() const {
-    return this->arg2_->ref_table();
-  }
-
-  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,
-                                 const ExpressionOptions &) {
-    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,
-                                 const ExpressionOptions &) {
-    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_.ref())) {
-    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);
-}
-
-// ---- ReferenceVectorNode ----
-
-template <typename T>
-class ReferenceVectorNode
-    : public BinaryNode<Vector<T>, Vector<Int>, T> {
- public:
-  using Value = Vector<T>;
-  using Arg1 = Vector<Int>;
-  using Arg2 = T;
-
-  static unique_ptr<Node> create(Error *error,
-                                 unique_ptr<Node> &&arg1,
-                                 unique_ptr<Node> &&arg2,
-                                 const ExpressionOptions &options) {
-    unique_ptr<Node> node(
-        new (nothrow) ReferenceVectorNode(std::move(arg1),
-                                          std::move(arg2),
-                                          options.block_size));
-    if (!node) {
-      GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    }
-    return node;
-  }
-
-  ReferenceVectorNode(unique_ptr<Node> &&arg1,
-                      unique_ptr<Node> &&arg2,
-                      Int block_size)
-      : BinaryNode<Value, Arg1, Arg2>(std::move(arg1), std::move(arg2)),
-        temp_records_(),
-        result_pools_(),
-        block_size_(block_size) {}
-
-  const Table *ref_table() const {
-    return this->arg2_->ref_table();
-  }
-
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<Value> results);
-
- private:
-  Array<Record> temp_records_;
-  Array<Array<Arg2>> result_pools_;
-  Int block_size_;
-};
-
-template <typename T>
-bool ReferenceVectorNode<T>::evaluate(Error *error,
-                                      ArrayCRef<Record> records,
-                                      ArrayRef<Value> results) {
-  if (!this->fill_arg1_values(error, records)) {
-    return false;
-  }
-  Int total_size = 0;
-  for (Int i = 0; i < records.size(); ++i) {
-    total_size += this->arg1_values_[i].size();
-  }
-  if (!temp_records_.resize(error, block_size_)) {
-    return false;
-  }
-  Array<Arg2> result_pool;
-  if (!result_pool.resize(error, total_size)) {
-    return false;
-  }
-  Int offset = 0;
-  Int count = 0;
-  for (Int i = 0; i < records.size(); ++i) {
-    Float score = records.get_score(i);
-    for (Int j = 0; j < this->arg1_values_[i].size(); ++j) {
-      temp_records_.set(count, Record(this->arg1_values_[i][j], score));
-      ++count;
-      if (count >= block_size_) {
-        if (!this->arg2_->evaluate(error, temp_records_,
-                                   result_pool.ref(offset, count))) {
-          return false;
-        }
-        offset += count;
-        count = 0;
-      }
-    }
-  }
-  if (count != 0) {
-    if (!this->arg2_->evaluate(error, temp_records_.ref(0, count),
-                               result_pool.ref(offset, count))) {
-      return false;
-    }
-  }
-  offset = 0;
-  for (Int i = 0; i < records.size(); ++i) {
-    Int size = this->arg1_values_[i].size();
-    results[i] = Value(&result_pool[offset], size);
-    offset += size;
-  }
-  if (!result_pools_.push_back(error, std::move(result_pool))) {
-    return false;
-  }
-  return true;
-}
-
-// -- Builder --
-
-class Builder {
- public:
-  // Create an object for building an expression.
-  //
-  // On success, returns a poitner to the builder.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
-  static unique_ptr<Builder> create(Error *error, const Table *table);
-
-  ~Builder() {}
-
-  // Return the target table.
-  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.
-  //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  bool push_constant(Error *error, const Datum &datum);
-
-  // Push a node associated with row IDs of Records.
-  //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  bool push_row_id(Error *error);
-
-  // Push a node associated with scores of Records.
-  //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  bool push_score(Error *error);
-
-  // Push a column.
-  //
-  // If "name" == "_id", pushes a pseudo column associated with row IDs.
-  // If "name" == "_score", pushes a pseudo column associated with scores.
-  //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  bool push_column(Error *error, const StringCRef &name);
-
-  // Push an operator.
-  //
-  // Pops operands and pushes an operator.
-  // Fails if there are not enough operands.
-  // Fails if the combination of operands is invalid.
-  //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "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, const ExpressionOptions &options);
-
-  // Clear the internal stack.
-  void clear();
-
-  // Complete building an expression and clear the internal stack.
-  //
-  // Fails if the stack is empty or contains more than one nodes.
-  //
-  // On success, returns a pointer to the expression root node.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
-  unique_ptr<Node> release(Error *error);
-
- private:
-  const Table *table_;
-  Array<unique_ptr<Node>> stack_;
-
-  Builder(const Table *table) : table_(table), stack_() {}
-
-  // Create a node associated with a constant.
-  unique_ptr<Node> create_constant_node(Error *error, const Datum &datum);
-  // Create a node associated with a column.
-  unique_ptr<Node> create_column_node(Error *error, const StringCRef &name);
-
-  // Push a unary operator.
-  bool push_unary_operator(Error *error, OperatorType operator_type);
-  // Push a binary operator.
-  bool push_binary_operator(Error *error, OperatorType operator_type);
-
-  // Create a node associated with a unary operator.
-  unique_ptr<Node> create_unary_node(
-      Error *error,
-      OperatorType operator_type,
-      unique_ptr<Node> &&arg);
-  // Create a node associated with a binary operator.
-  unique_ptr<Node> create_binary_node(
-      Error *error,
-      OperatorType operator_type,
-      unique_ptr<Node> &&arg1,
-      unique_ptr<Node> &&arg2);
-
-  // Create a equality test node.
-  template <typename T>
-  unique_ptr<Node> create_equality_test_node(
-      Error *error,
-      unique_ptr<Node> &&arg1,
-      unique_ptr<Node> &&arg2);
-  // Create a comparison node.
-  template <typename T>
-  unique_ptr<Node> create_comparison_node(
-      Error *error,
-      unique_ptr<Node> &&arg1,
-      unique_ptr<Node> &&arg2);
-  // Create a bitwise node.
-  template <typename T>
-  unique_ptr<Node> create_bitwise_node(
-      Error *error,
-      OperatorType operator_type,
-      unique_ptr<Node> &&arg1,
-      unique_ptr<Node> &&arg2);
-  // Create an arithmetic node.
-  template <typename T>
-  unique_ptr<Node> create_arithmetic_node(
-      Error *error,
-      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);
-
-  // Create a reference node.
-  unique_ptr<Node> create_reference_node(
-      Error *error,
-      unique_ptr<Node> &&arg1,
-      unique_ptr<Node> &&arg2,
-      const ExpressionOptions &options);
-};
-
-unique_ptr<Builder> Builder::create(Error *error, const Table *table) {
-  unique_ptr<Builder> builder(new (nothrow) Builder(table));
-  if (!builder) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return nullptr;
-  }
-  return builder;
-}
-
-bool Builder::push_constant(Error *error, const Datum &datum) {
-  // Reserve a space for a new node.
-  if (!stack_.reserve(error, stack_.size() + 1)) {
-    return false;
-  }
-  unique_ptr<Node> node = create_constant_node(error, datum);
-  if (!node) {
-    return false;
-  }
-  // This push_back() must not fail because a space is already reserved.
-  stack_.push_back(nullptr, std::move(node));
-  return true;
-}
-
-bool Builder::push_row_id(Error *error) {
-  // Reserve a space for a new node.
-  if (!stack_.reserve(error, stack_.size() + 1)) {
-    return false;
-  }
-  unique_ptr<Node> node(RowIDNode::create(error));
-  if (!node) {
-    return false;
-  }
-  // This push_back() must not fail because a space is already reserved.
-  stack_.push_back(nullptr, std::move(node));
-  return true;
-}
-
-bool Builder::push_score(Error *error) {
-  // Reserve a space for a new node.
-  if (!stack_.reserve(error, stack_.size() + 1)) {
-    return false;
-  }
-  unique_ptr<Node> node(ScoreNode::create(error));
-  if (!node) {
-    return false;
-  }
-  // This push_back() must not fail because a space is already reserved.
-  stack_.push_back(nullptr, std::move(node));
-  return true;
-}
-
-bool Builder::push_column(Error *error, const StringCRef &name) {
-  // Reserve a space for a new node.
-  if (!stack_.reserve(error, stack_.size() + 1)) {
-    return false;
-  }
-  unique_ptr<Node> node = create_column_node(error, name);
-  if (!node) {
-    return false;
-  }
-  // This push_back() must not fail because a space is already reserved.
-  stack_.push_back(nullptr, std::move(node));
-  return true;
-}
-
-bool Builder::push_operator(Error *error, OperatorType operator_type) {
-  switch (operator_type) {
-    case LOGICAL_NOT_OPERATOR:
-    case BITWISE_NOT_OPERATOR:
-    case POSITIVE_OPERATOR:
-    case NEGATIVE_OPERATOR:
-    case TO_INT_OPERATOR:
-    case TO_FLOAT_OPERATOR: {
-      return push_unary_operator(error, operator_type);
-    }
-    case LOGICAL_AND_OPERATOR:
-    case LOGICAL_OR_OPERATOR:
-    case EQUAL_OPERATOR:
-    case NOT_EQUAL_OPERATOR:
-    case LESS_OPERATOR:
-    case LESS_EQUAL_OPERATOR:
-    case GREATER_OPERATOR:
-    case GREATER_EQUAL_OPERATOR:
-    case BITWISE_AND_OPERATOR:
-    case BITWISE_OR_OPERATOR:
-    case BITWISE_XOR_OPERATOR:
-    case PLUS_OPERATOR:
-    case MINUS_OPERATOR:
-    case MULTIPLICATION_OPERATOR:
-    case DIVISION_OPERATOR:
-    case MODULUS_OPERATOR:
-    case SUBSCRIPT_OPERATOR: {
-      return push_binary_operator(error, operator_type);
-    }
-    default: {
-      // TODO: Not supported yet.
-      GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-      return false;
-    }
-  }
-}
-
-bool Builder::push_node(Error *error, unique_ptr<Node> &&node) {
-  return stack_.push_back(error, std::move(node));
-}
-
-bool Builder::push_reference(Error *error, const ExpressionOptions &options) {
-  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), options);
-  if (!node) {
-    return false;
-  }
-  stack_.push_back(nullptr, std::move(node));
-  return true;
-}
-
-void Builder::clear() {
-  stack_.clear();
-}
-
-unique_ptr<Node> Builder::release(Error *error) {
-  if (stack_.size() != 1) {
-    GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Incomplete expression");
-    return nullptr;
-  }
-  unique_ptr<Node> root = std::move(stack_[0]);
-  stack_.clear();
-  return root;
-}
-
-unique_ptr<Node> Builder::create_constant_node(
-    Error *error,
-    const Datum &datum) {
-  switch (datum.type()) {
-    case BOOL_DATA: {
-      return ConstantNode<Bool>::create(error, datum.force_bool());
-    }
-    case INT_DATA: {
-      return ConstantNode<Int>::create(error, datum.force_int());
-    }
-    case FLOAT_DATA: {
-      return ConstantNode<Float>::create(error, datum.force_float());
-    }
-    case GEO_POINT_DATA: {
-      return ConstantNode<GeoPoint>::create(error, datum.force_geo_point());
-    }
-    case TEXT_DATA: {
-      return ConstantNode<Text>::create(error, datum.force_text());
-    }
-    case BOOL_VECTOR_DATA: {
-      return ConstantNode<Vector<Bool>>::create(error,
-                                                datum.force_bool_vector());
-    }
-    case INT_VECTOR_DATA: {
-      return ConstantNode<Vector<Int>>::create(error,
-                                               datum.force_int_vector());
-    }
-    case FLOAT_VECTOR_DATA: {
-      return ConstantNode<Vector<Float>>::create(error,
-                                                 datum.force_float_vector());
-    }
-    case TEXT_VECTOR_DATA: {
-      return ConstantNode<Vector<Text>>::create(error,
-                                                datum.force_text_vector());
-    }
-    case GEO_POINT_VECTOR_DATA: {
-      return ConstantNode<Vector<GeoPoint>>::create(
-          error, datum.force_geo_point_vector());
-    }
-    default: {
-      // TODO: Other types are not supported yet.
-      GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-      return nullptr;
-    }
-  }
-}
-
-unique_ptr<Node> Builder::create_column_node(
-    Error *error,
-    const StringCRef &name) {
-  Column *column = table_->find_column(error, name);
-  if (!column) {
-    return nullptr;
-  }
-  switch (column->data_type()) {
-    case BOOL_DATA: {
-      return ColumnNode<Bool>::create(error, column);
-    }
-    case INT_DATA: {
-      return ColumnNode<Int>::create(error, column);
-    }
-    case FLOAT_DATA: {
-      return ColumnNode<Float>::create(error, column);
-    }
-    case GEO_POINT_DATA: {
-      return ColumnNode<GeoPoint>::create(error, column);
-    }
-    case TEXT_DATA: {
-      return ColumnNode<Text>::create(error, column);
-    }
-    case BOOL_VECTOR_DATA: {
-      return ColumnNode<Vector<Bool>>::create(error, column);
-    }
-    case INT_VECTOR_DATA: {
-      return ColumnNode<Vector<Int>>::create(error, column);
-    }
-    case FLOAT_VECTOR_DATA: {
-      return ColumnNode<Vector<Float>>::create(error, column);
-    }
-    case GEO_POINT_VECTOR_DATA: {
-      return ColumnNode<Vector<GeoPoint>>::create(error, column);
-    }
-    case TEXT_VECTOR_DATA: {
-      return ColumnNode<Vector<Text>>::create(error, column);
-    }
-    default: {
-      // TODO: Other types are not supported yet.
-      GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-      return nullptr;
-    }
-  }
-}
-
-bool Builder::push_unary_operator(Error *error, OperatorType operator_type) {
-  if (stack_.size() < 1) {
-    GRNXX_ERROR_SET(error, INVALID_OPERAND, "Not enough operands");
-    return false;
-  }
-  unique_ptr<Node> arg = std::move(stack_[stack_.size() - 1]);
-  stack_.resize(nullptr, stack_.size() - 1);
-  unique_ptr<Node> node =
-      create_unary_node(error, operator_type, std::move(arg));
-  if (!node) {
-    return false;
-  }
-  stack_.push_back(error, std::move(node));
-  return true;
-}
-
-bool Builder::push_binary_operator(Error *error, OperatorType operator_type) {
-  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_binary_node(error, operator_type,
-                                             std::move(arg1), std::move(arg2));
-  if (!node) {
-    return false;
-  }
-  stack_.push_back(nullptr, std::move(node));
-  return true;
-}
-
-unique_ptr<Node> Builder::create_unary_node(
-    Error *error,
-    OperatorType operator_type,
-    unique_ptr<Node> &&arg) {
-  switch (operator_type) {
-    case LOGICAL_NOT_OPERATOR: {
-      if (arg->data_type() != BOOL_DATA) {
-        GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-        return nullptr;
-      }
-      return LogicalNotNode::create(error, std::move(arg));
-    }
-    case BITWISE_NOT_OPERATOR: {
-      switch (arg->data_type()) {
-        case BOOL_DATA: {
-          return BitwiseNotNode<Bool>::create(error, std::move(arg));
-        }
-        case INT_DATA: {
-          return BitwiseNotNode<Int>::create(error, std::move(arg));
-        }
-        default: {
-          GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-          return nullptr;
-        }
-      }
-    }
-    case POSITIVE_OPERATOR: {
-      if ((arg->data_type() != INT_DATA) && (arg->data_type() != FLOAT_DATA)) {
-        GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-        return nullptr;
-      }
-      // Positive operator does nothing.
-      return std::move(arg);
-    }
-    case NEGATIVE_OPERATOR: {
-      switch (arg->data_type()) {
-        case INT_DATA: {
-          return NegativeNode<Int>::create(error, std::move(arg));
-        }
-        case FLOAT_DATA: {
-          return NegativeNode<Float>::create(error, std::move(arg));
-        }
-        default: {
-          GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-          return nullptr;
-        }
-      }
-    }
-    case TO_INT_OPERATOR: {
-      if (arg->data_type() != FLOAT_DATA) {
-        GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-        return nullptr;
-      }
-      return ToIntNode::create(error, std::move(arg));
-    }
-    case TO_FLOAT_OPERATOR: {
-      if (arg->data_type() != INT_DATA) {
-        GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-        return nullptr;
-      }
-      return ToFloatNode::create(error, std::move(arg));
-    }
-    default: {
-      // TODO: Not supported yet.
-      GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-      return nullptr;
-    }
-  }
-}
-
-unique_ptr<Node> Builder::create_binary_node(
-    Error *error,
-    OperatorType operator_type,
-    unique_ptr<Node> &&arg1,
-    unique_ptr<Node> &&arg2) {
-  switch (operator_type) {
-    case LOGICAL_AND_OPERATOR: {
-      if ((arg1->data_type() != BOOL_DATA) ||
-          (arg2->data_type() != BOOL_DATA)) {
-        GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-        return nullptr;
-      }
-      return LogicalAndNode::create(error, std::move(arg1), std::move(arg2));
-    }
-    case LOGICAL_OR_OPERATOR: {
-      if ((arg1->data_type() != BOOL_DATA) ||
-          (arg2->data_type() != BOOL_DATA)) {
-        GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-        return nullptr;
-      }
-      return LogicalOrNode::create(error, std::move(arg1), std::move(arg2));
-    }
-    case EQUAL_OPERATOR: {
-      return create_equality_test_node<Equal>(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case NOT_EQUAL_OPERATOR: {
-      return create_equality_test_node<NotEqual>(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case LESS_OPERATOR: {
-      return create_comparison_node<Less>(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case LESS_EQUAL_OPERATOR: {
-      return create_comparison_node<LessEqual>(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case GREATER_OPERATOR: {
-      return create_comparison_node<Greater>(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case GREATER_EQUAL_OPERATOR: {
-      return create_comparison_node<GreaterEqual>(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case BITWISE_AND_OPERATOR:
-    case BITWISE_OR_OPERATOR:
-    case BITWISE_XOR_OPERATOR: {
-      switch (arg1->data_type()) {
-        case BOOL_DATA: {
-          return create_bitwise_node<Bool>(
-              error, operator_type, std::move(arg1), std::move(arg2));
-        }
-        case INT_DATA: {
-          return create_bitwise_node<Int>(
-              error, operator_type, std::move(arg1), std::move(arg2));
-        }
-        default: {
-          GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-          return nullptr;
-        }
-      }
-    }
-    case PLUS_OPERATOR:
-    case MINUS_OPERATOR:
-    case MULTIPLICATION_OPERATOR:
-    case DIVISION_OPERATOR: {
-      switch (arg1->data_type()) {
-        case INT_DATA: {
-          return create_arithmetic_node<Int>(
-              error, operator_type, std::move(arg1), std::move(arg2));
-        }
-        case FLOAT_DATA: {
-          return create_arithmetic_node<Float>(
-              error, operator_type, std::move(arg1), std::move(arg2));
-        }
-        default: {
-          GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-          return nullptr;
-        }
-      }
-    }
-    case MODULUS_OPERATOR: {
-      if ((arg1->data_type() != INT_DATA) ||
-          (arg2->data_type() != INT_DATA)) {
-        GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-        return nullptr;
-      }
-      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");
-      return nullptr;
-    }
-  }
-}
-
-template <typename T>
-unique_ptr<Node> Builder::create_equality_test_node(
-    Error *error,
-    unique_ptr<Node> &&arg1,
-    unique_ptr<Node> &&arg2) {
-  if (arg1->data_type() != arg2->data_type()) {
-    GRNXX_ERROR_SET(error, INVALID_OPERAND, "Data type conflict");
-    return nullptr;
-  }
-  switch (arg1->data_type()) {
-    case BOOL_DATA: {
-      return ComparisonNode<typename T:: template Comparer<Bool>>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case INT_DATA: {
-      return ComparisonNode<typename T:: template Comparer<Int>>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case FLOAT_DATA: {
-      return ComparisonNode<typename T:: template Comparer<Float>>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case GEO_POINT_DATA: {
-      return ComparisonNode<typename T:: template Comparer<GeoPoint>>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case TEXT_DATA: {
-      return ComparisonNode<typename T:: template Comparer<Text>>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case BOOL_VECTOR_DATA: {
-      typedef typename T:: template Comparer<Vector<Bool>> Functor;
-      return ComparisonNode<Functor>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case INT_VECTOR_DATA: {
-      typedef typename T:: template Comparer<Vector<Int>> Functor;
-      return ComparisonNode<Functor>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case FLOAT_VECTOR_DATA: {
-      typedef typename T:: template Comparer<Vector<Float>> Functor;
-      return ComparisonNode<Functor>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case GEO_POINT_VECTOR_DATA: {
-      typedef typename T:: template Comparer<Vector<GeoPoint>> Functor;
-      return ComparisonNode<Functor>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case TEXT_VECTOR_DATA: {
-      typedef typename T:: template Comparer<Vector<Text>> Functor;
-      return ComparisonNode<Functor>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    // TODO: Support other types.
-    default: {
-      GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-      return nullptr;
-    }
-  }
-}
-
-template <typename T>
-unique_ptr<Node> Builder::create_comparison_node(
-    Error *error,
-    unique_ptr<Node> &&arg1,
-    unique_ptr<Node> &&arg2) {
-  if (arg1->data_type() != arg2->data_type()) {
-    GRNXX_ERROR_SET(error, INVALID_OPERAND, "Data type conflict");
-    return nullptr;
-  }
-  switch (arg1->data_type()) {
-    case INT_DATA: {
-      return ComparisonNode<typename T:: template Comparer<Int>>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case FLOAT_DATA: {
-      return ComparisonNode<typename T:: template Comparer<Float>>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case TEXT_DATA: {
-      return ComparisonNode<typename T:: template Comparer<Text>>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    default: {
-      GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-      return nullptr;
-    }
-  }
-}
-
-template <typename T>
-unique_ptr<Node> Builder::create_bitwise_node(
-    Error *error,
-    OperatorType operator_type,
-    unique_ptr<Node> &&arg1,
-    unique_ptr<Node> &&arg2) {
-  if (arg1->data_type() != arg2->data_type()) {
-    GRNXX_ERROR_SET(error, INVALID_OPERAND, "Data type conflict");
-    return nullptr;
-  }
-  switch (operator_type) {
-    case BITWISE_AND_OPERATOR: {
-      return BitwiseAndNode<T>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case BITWISE_OR_OPERATOR: {
-      return BitwiseOrNode<T>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case BITWISE_XOR_OPERATOR: {
-      return BitwiseXorNode<T>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    default: {
-      GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Invalid operator");
-      return nullptr;
-    }
-  }
-}
-
-template <typename T>
-unique_ptr<Node> Builder::create_arithmetic_node(
-    Error *error,
-    OperatorType operator_type,
-    unique_ptr<Node> &&arg1,
-    unique_ptr<Node> &&arg2) {
-  if (arg1->data_type() != arg2->data_type()) {
-    GRNXX_ERROR_SET(error, INVALID_OPERAND, "Data type conflict");
-    return nullptr;
-  }
-  switch (operator_type) {
-    case PLUS_OPERATOR: {
-      return PlusNode<T>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case MINUS_OPERATOR: {
-      return MinusNode<T>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case MULTIPLICATION_OPERATOR: {
-      return MultiplicationNode<T>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case DIVISION_OPERATOR: {
-      return DivisionNode<T>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    default: {
-      GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-      return nullptr;
-    }
-  }
-}
-
-unique_ptr<Node> Builder::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));
-    }
-    case INT_VECTOR_DATA: {
-      return SubscriptNode<Int>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case FLOAT_VECTOR_DATA: {
-      return SubscriptNode<Float>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case GEO_POINT_VECTOR_DATA: {
-      return SubscriptNode<GeoPoint>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    case TEXT_VECTOR_DATA: {
-      return SubscriptNode<Text>::create(
-          error, std::move(arg1), std::move(arg2));
-    }
-    default: {
-      GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-      return nullptr;
-    }
-  }
-}
-
-unique_ptr<Node> Builder::create_reference_node(
-    Error *error,
-    unique_ptr<Node> &&arg1,
-    unique_ptr<Node> &&arg2,
-    const ExpressionOptions &options) {
-  switch (arg1->data_type()) {
-    case INT_DATA: {
-      switch (arg2->data_type()) {
-        case BOOL_DATA: {
-          return ReferenceNode<Bool>::create(
-              error, std::move(arg1), std::move(arg2), options);
-        }
-        case INT_DATA: {
-          return ReferenceNode<Int>::create(
-              error, std::move(arg1), std::move(arg2), options);
-        }
-        case FLOAT_DATA: {
-          return ReferenceNode<Float>::create(
-              error, std::move(arg1), std::move(arg2), options);
-        }
-        case GEO_POINT_DATA: {
-          return ReferenceNode<GeoPoint>::create(
-              error, std::move(arg1), std::move(arg2), options);
-        }
-        case TEXT_DATA: {
-          return ReferenceNode<Text>::create(
-              error, std::move(arg1), std::move(arg2), options);
-        }
-        case BOOL_VECTOR_DATA: {
-          return ReferenceNode<Vector<Bool>>::create(
-              error, std::move(arg1), std::move(arg2), options);
-        }
-        case INT_VECTOR_DATA: {
-          return ReferenceNode<Vector<Int>>::create(
-              error, std::move(arg1), std::move(arg2), options);
-        }
-        case FLOAT_VECTOR_DATA: {
-          return ReferenceNode<Vector<Float>>::create(
-              error, std::move(arg1), std::move(arg2), options);
-        }
-        case GEO_POINT_VECTOR_DATA: {
-          return ReferenceNode<Vector<GeoPoint>>::create(
-              error, std::move(arg1), std::move(arg2), options);
-        }
-        case TEXT_VECTOR_DATA: {
-          return ReferenceNode<Vector<Text>>::create(
-              error, std::move(arg1), std::move(arg2), options);
-        }
-        default: {
-          GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-          return nullptr;
-        }
-      }
-    }
-    case INT_VECTOR_DATA: {
-      switch (arg2->data_type()) {
-        case BOOL_DATA: {
-          // TODO: Not supported yet.
-//          return ReferenceVectorNode<Bool>::create(
-//              error, std::move(arg1), std::move(arg2));
-          GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-          return nullptr;
-        }
-        case INT_DATA: {
-          return ReferenceVectorNode<Int>::create(
-              error, std::move(arg1), std::move(arg2), options);
-        }
-        case FLOAT_DATA: {
-          return ReferenceVectorNode<Float>::create(
-              error, std::move(arg1), std::move(arg2), options);
-        }
-        case GEO_POINT_DATA: {
-          return ReferenceVectorNode<GeoPoint>::create(
-              error, std::move(arg1), std::move(arg2), options);
-        }
-        case TEXT_DATA: {
-          return ReferenceVectorNode<Text>::create(
-              error, std::move(arg1), std::move(arg2), options);
-        }
-        default: {
-          GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-          return nullptr;
-        }
-      }
-    }
-    default: {
-      GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-      return nullptr;
-    }
-  }
-}
-
-}  // namespace expression
-
-using namespace expression;
-
-// -- Expression --
-
-Expression::~Expression() {}
-
-DataType Expression::data_type() const {
-  return root_->data_type();
-}
-
-//bool Expression::filter(Error *error, Array<Record> *records, Int offset) {
-//  ArrayRef<Record> output_records = records->ref();
-//  if (!filter(error, *records, &output_records)) {
-//    return false;
-//  }
-//  return records->resize(error, output_records.size());
-//}
-
-bool Expression::filter(Error *error,
-                        Array<Record> *records,
-                        Int input_offset,
-                        Int output_offset,
-                        Int output_limit) {
-  ArrayCRef<Record> input = records->ref(input_offset);
-  ArrayRef<Record> output = records->ref(input_offset);
-  Int count = 0;
-  while ((input.size() > 0) && (output_limit > 0)) {
-    Int next_size = (input.size() < block_size_) ? input.size() : block_size_;
-    ArrayCRef<Record> next_input = input.ref(0, next_size);
-    ArrayRef<Record> next_output = output.ref(0, next_size);
-    if (!root_->filter(error, next_input, &next_output)) {
-      return false;
-    }
-    input = input.ref(next_size);
-
-    if (output_offset > 0) {
-      if (output_offset >= next_output.size()) {
-        output_offset -= next_output.size();
-        next_output = next_output.ref(0, 0);
-      } else {
-        for (Int i = output_offset; i < next_output.size(); ++i) {
-          next_output.set(i - output_offset, next_output[i]);
-        }
-        next_output = next_output.ref(0, next_output.size() - output_offset);
-        output_offset = 0;
-      }
-    }
-    if (next_output.size() > output_limit) {
-      next_output = next_output.ref(0, output_limit);
-    }
-    output_limit -= next_output.size();
-
-    output = output.ref(next_output.size());
-    count += next_output.size();
-  }
-  records->resize(nullptr, input_offset + count);
-  return true;
-
-}
-
-bool Expression::filter(Error *error,
-                        ArrayCRef<Record> input_records,
-                        ArrayRef<Record> *output_records) {
-  ArrayCRef<Record> input = input_records;
-  ArrayRef<Record> output = *output_records;
-  Int count = 0;
-  while (input.size() > block_size_) {
-    ArrayCRef<Record> input_block = input.ref(0, block_size_);
-    ArrayRef<Record> output_block = output.ref(0, block_size_);
-    if (!root_->filter(error, input_block, &output_block)) {
-      return false;
-    }
-    input = input.ref(block_size_);
-    output = output.ref(output_block.size());
-    count += output_block.size();
-  }
-  if (!root_->filter(error, input, &output)) {
-    return false;
-  }
-  count += output.size();
-  *output_records = output_records->ref(0, count);
-  return true;
-}
-
-bool Expression::adjust(Error *error, Array<Record> *records, Int offset) {
-  return adjust(error, records->ref(offset));
-}
-
-bool Expression::adjust(Error *error, ArrayRef<Record> records) {
-  while (records.size() > block_size_) {
-    if (!root_->adjust(error, records.ref(0, block_size_))) {
-      return false;
-    }
-    records = records.ref(block_size_);
-  }
-  return root_->adjust(error, records);
-}
-
-template <typename T>
-bool Expression::evaluate(Error *error,
-                          ArrayCRef<Record> records,
-                          Array<T> *results) {
-  if (!results->resize(error, records.size())) {
-    return false;
-  }
-  return evaluate(error, records, results->ref());
-}
-
-#define GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(type) \
-  template bool Expression::evaluate(Error *error, \
-                                     ArrayCRef<Record> records, \
-                                     Array<type> *results)
-GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Bool);
-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>);
-GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Vector<Int>);
-GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Vector<Float>);
-GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Vector<GeoPoint>);
-GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Vector<Text>);
-#undef GRNXX_INSTANTIATE_EXPRESSION_EVALUATE
-
-template <typename T>
-bool Expression::evaluate(Error *error,
-                          ArrayCRef<Record> records,
-                          ArrayRef<T> results) {
-  if (TypeTraits<T>::data_type() != data_type()) {
-    GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Invalid data type");
-    return false;
-  }
-  if (records.size() != results.size()) {
-    GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Size conflict: "
-                    "#records = %" PRIi64 ", #results = %" PRIi64,
-                    records.size(), results.size());
-    return false;
-  }
-  auto typed_root = static_cast<TypedNode<T> *>(root_.get());
-  while (records.size() > block_size_) {
-    ArrayCRef<Record> input = records.ref(0, block_size_);
-    ArrayRef<T> output = results.ref(0, block_size_);
-    if (!typed_root->evaluate(error, input, output)) {
-      return false;
-    }
-    records = records.ref(block_size_);
-    results = results.ref(block_size_);
-  }
-  return typed_root->evaluate(error, records, results);
-}
-
-#define GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(type) \
-  template bool Expression::evaluate(Error *error, \
-                                     ArrayCRef<Record> records, \
-                                     ArrayRef<type> results)
-GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Bool);
-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>);
-GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Vector<Int>);
-GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Vector<Float>);
-GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Vector<GeoPoint>);
-GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Vector<Text>);
-#undef GRNXX_INSTANTIATE_EXPRESSION_EVALUATE
-
-unique_ptr<Expression> Expression::create(Error *error,
-                                          const Table *table,
-                                          unique_ptr<Node> &&root,
-                                          const ExpressionOptions &options) {
-  if (options.block_size <= 0) {
-    GRNXX_ERROR_SET(error, INVALID_ARGUMENT,
-                    "Invalid argument: block_size = %" PRIi64,
-                    options.block_size);
-    return nullptr;
-  }
-  unique_ptr<Expression> expression(
-      new (nothrow) Expression(table, std::move(root), options.block_size));
-  if (!expression) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return nullptr;
-  }
-  return expression;
-}
-
-Expression::Expression(const Table *table,
-                       unique_ptr<Node> &&root,
-                       Int block_size)
-    : table_(table),
-      root_(std::move(root)),
-      block_size_(block_size) {}
-
-// -- ExpressionBuilder --
-
-unique_ptr<ExpressionBuilder> ExpressionBuilder::create(Error *error,
-                                                        const Table *table) {
-  unique_ptr<ExpressionBuilder> builder(
-      new (nothrow) ExpressionBuilder(table));
-  if (!builder) {
-    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
-    return nullptr;
-  }
-  unique_ptr<Builder> internal_builder = Builder::create(error, table);
-  if (!internal_builder) {
-    return nullptr;
-  }
-  if (!builder->builders_.push_back(error, std::move(internal_builder))) {
-    return nullptr;
-  }
-  return builder;
-}
-
-ExpressionBuilder::~ExpressionBuilder() {}
-
-bool ExpressionBuilder::push_constant(Error *error, const Datum &datum) {
-  if (!is_ok_) {
-    GRNXX_ERROR_SET(error, BROKEN, "Broken builder");
-    return false;
-  }
-  is_ok_ = builders_.back()->push_constant(error, datum);
-  return is_ok_;
-}
-
-bool ExpressionBuilder::push_row_id(Error *error) {
-  if (!is_ok_) {
-    GRNXX_ERROR_SET(error, BROKEN, "Broken builder");
-    return false;
-  }
-  is_ok_ = builders_.back()->push_row_id(error);
-  return is_ok_;
-}
-
-bool ExpressionBuilder::push_score(Error *error) {
-  if (!is_ok_) {
-    GRNXX_ERROR_SET(error, BROKEN, "Broken builder");
-    return false;
-  }
-  is_ok_ = builders_.back()->push_score(error);
-  return is_ok_;
-}
-
-bool ExpressionBuilder::push_column(Error *error, const StringCRef &name) {
-  if (!is_ok_) {
-    GRNXX_ERROR_SET(error, BROKEN, "Broken builder");
-    return false;
-  }
-  is_ok_ = builders_.back()->push_column(error, name);
-  return is_ok_;
-}
-
-bool ExpressionBuilder::push_operator(Error *error,
-                                      OperatorType operator_type) {
-  if (!is_ok_) {
-    GRNXX_ERROR_SET(error, BROKEN, "Broken builder");
-    return false;
-  }
-  is_ok_ = builders_.back()->push_operator(error, operator_type);
-  return is_ok_;
-}
-
-bool ExpressionBuilder::begin_subexpression(Error *error) {
-  if (!is_ok_) {
-    GRNXX_ERROR_SET(error, BROKEN, "Broken builder");
-    return false;
-  }
-  const Node *latest_node = builders_.back()->latest_node();
-  if (!latest_node) {
-    GRNXX_ERROR_SET(error, INVALID_OPERAND, "Not enough operands");
-    is_ok_ = false;
-    return false;
-  }
-  if (!latest_node->ref_table()) {
-    GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type");
-    is_ok_ = false;
-    return false;
-  }
-  unique_ptr<Builder> subexpression_builder =
-      Builder::create(error, latest_node->ref_table());
-  if (!subexpression_builder) {
-    is_ok_ = false;
-    return false;
-  }
-  if (!builders_.push_back(error, std::move(subexpression_builder))) {
-    is_ok_ = false;
-    return false;
-  }
-  return true;
-}
-
-bool ExpressionBuilder::end_subexpression(
-    Error *error,
-    const ExpressionOptions &options) {
-  if (!is_ok_) {
-    GRNXX_ERROR_SET(error, BROKEN, "Broken builder");
-    return false;
-  }
-  if (builders_.size() <= 1) {
-    GRNXX_ERROR_SET(error, INVALID_OPERATION, "Subexpression not found");
-    is_ok_ = false;
-    return false;
-  }
-  unique_ptr<Node> node = builders_.back()->release(error);
-  if (!node) {
-    is_ok_ = false;
-    return false;
-  }
-  builders_.pop_back();
-  if (!builders_.back()->push_node(error, std::move(node))) {
-    is_ok_ = false;
-    return false;
-  }
-  if (!builders_.back()->push_reference(error, options)) {
-    is_ok_ = false;
-    return false;
-  }
-  return true;
-}
-
-void ExpressionBuilder::clear() {
-  builders_.resize(nullptr, 1);
-  builders_[0]->clear();
-  is_ok_ = true;
-}
-
-unique_ptr<Expression> ExpressionBuilder::release(
-    Error *error,
-    const ExpressionOptions &options) {
-  if (!is_ok_) {
-    GRNXX_ERROR_SET(error, BROKEN, "Broken builder");
-    return nullptr;
-  }
-  if (builders_.size() != 1) {
-    GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Incomplete expression");
-    is_ok_ = false;
-    return nullptr;
-  }
-  unique_ptr<Node> root = builders_[0]->release(error);
-  if (!root) {
-    is_ok_ = false;
-    return nullptr;
-  }
-  auto expression = Expression::create(error, table_, std::move(root),
-                                       options);
-  if (!expression) {
-    is_ok_ = false;
-    return nullptr;
-  }
-  return expression;
-}
-
-ExpressionBuilder::ExpressionBuilder(const Table *table)
-    : table_(table),
-      builders_(),
-      is_ok_(true) {}
-
-}  // namespace grnxx




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