[Groonga-commit] groonga/grnxx at 05790de [new_data_types] Implement a part of Expression. (#104)

Back to archive index

susumu.yata null+****@clear*****
Wed Nov 12 16:10:55 JST 2014


susumu.yata	2014-11-12 16:10:55 +0900 (Wed, 12 Nov 2014)

  New Revision: 05790dee637455ac32d1b3259cb16a7aa2928588
  https://github.com/groonga/grnxx/commit/05790dee637455ac32d1b3259cb16a7aa2928588

  Message:
    Implement a part of Expression. (#104)
    
    ConstantNode, RowIDNode, ScoreNode, and ColumnNode.

  Added files:
    lib/grnxx/impl/expression.cpp
    lib/grnxx/impl/expression.hpp
  Copied files:
    lib/grnxx/expression-old.cpp
      (from lib/grnxx/expression.cpp)
  Modified files:
    include/grnxx/Makefile.am
    include/grnxx/array.hpp
    include/grnxx/expression.hpp
    lib/grnxx/Makefile.am
    lib/grnxx/expression.cpp
    lib/grnxx/impl/Makefile.am

  Modified: include/grnxx/Makefile.am (+1 -1)
===================================================================
--- include/grnxx/Makefile.am    2014-11-11 08:38:14 +0900 (0ddf15b)
+++ include/grnxx/Makefile.am    2014-11-12 16:10:55 +0900 (b1cc5d8)
@@ -9,13 +9,13 @@ pkginclude_HEADERS =	\
 	data_types.hpp	\
 	db.hpp		\
 	error.hpp	\
+	expression.hpp	\
 	features.hpp	\
 	index.hpp	\
 	library.hpp	\
 	string.hpp	\
 	table.hpp
 
-#	expression.hpp	\
 #	merger.hpp	\
 #	pipeline.hpp	\
 #	sorter.hpp

  Modified: include/grnxx/array.hpp (+10 -0)
===================================================================
--- include/grnxx/array.hpp    2014-11-11 08:38:14 +0900 (e6b42f2)
+++ include/grnxx/array.hpp    2014-11-12 16:10:55 +0900 (abd51a9)
@@ -40,6 +40,11 @@ class ArrayCRef {
     return values_[i];
   }
 
+  // Return a pointer to the contents.
+  const Value *data() const {
+    return values_;
+  }
+
   // Return whether the array is empty or not.
   bool is_empty() const {
     return size_ == 0;
@@ -113,6 +118,11 @@ class ArrayRef {
     return values_[i];
   }
 
+  // Return a pointer to the contents.
+  const Value *data() const {
+    return values_;
+  }
+
   // Return whether the array is empty or not.
   bool is_empty() const {
     return size_ == 0;

  Modified: include/grnxx/expression.hpp (+103 -152)
===================================================================
--- include/grnxx/expression.hpp    2014-11-11 08:38:14 +0900 (58d143f)
+++ include/grnxx/expression.hpp    2014-11-12 16:10:55 +0900 (bb26685)
@@ -1,15 +1,14 @@
 #ifndef GRNXX_EXPRESSION_HPP
 #define GRNXX_EXPRESSION_HPP
 
-#include "grnxx/types.hpp"
+#include <memory>
 
-namespace grnxx {
-namespace expression {
-
-class Node;
-class Builder;
+#include "grnxx/array.hpp"
+#include "grnxx/column.hpp"
+#include "grnxx/data_types.hpp"
+#include "grnxx/table.hpp"
 
-}  // namespace expression
+namespace grnxx {
 
 enum OperatorType {
   // -- Unary operators --
@@ -23,8 +22,8 @@ enum OperatorType {
 
   // Typecast operators.
 //  TO_BOOL_OPERATOR,
-  TO_INT_OPERATOR,
-  TO_FLOAT_OPERATOR,
+  TO_INT_OPERATOR,    // For Float.
+  TO_FLOAT_OPERATOR,  // For Int.
 //  TO_GEO_POINT_OPERATOR,
 //  TO_TEXT_OPERATOR,
 
@@ -62,229 +61,181 @@ enum OperatorType {
   // -- Ternary operators --
 };
 
+struct ExpressionOptions {
+  // Records are evaluated per block.
+  size_t block_size;
+
+  ExpressionOptions() : block_size(1024) {}
+};
+
 class Expression {
  public:
-  using Node = expression::Node;
-
-  ~Expression();
+  Expression() = default;
+  virtual ~Expression() = default;
 
   // Return the associated table.
-  const Table *table() const {
-    return table_;
-  }
+  virtual const Table *table() const = 0;
   // Return the result data type.
-  DataType data_type() const;
+  virtual DataType data_type() const = 0;
   // Return the evaluation block size.
-  Int block_size() const {
-    return block_size_;
-  }
+  virtual size_t block_size() const = 0;
 
-  // Filter out false records.
+  // Extract true records.
   //
   // Evaluates the expression for "*records" and removes records whose
-  // evaluation results are false.
+  // evaluation results are not true.
   //
-  // Note that the first "input_offset" records in "*records" are left as is
-  // without evaluation.
-  // Also note that the first "output_offset" true records are removed and
-  // the number of output records is at most "output_limit".
+  // The first "input_offset" records in "*records" are left as is without
+  // evaluation.
+  // The first "output_offset" true records are removed.
+  // The number of output records is at most "output_limit".
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  bool filter(Error *error, Array<Record> *records,
-              Int input_offset = 0,
-              Int output_offset = 0,
-              Int output_limit = numeric_limits<Int>::max());
+  // On failure, throws an exception.
+  virtual void filter(
+      Array<Record> *records,
+      size_t input_offset = 0,
+      size_t output_offset = 0,
+      size_t output_limit = std::numeric_limits<size_t>::max()) = 0;
 
   // Extract true records.
   //
-  // Evaluates the expression for "input_records" and copies records whose
-  // evaluation results are true into "*output_records".
+  // Evaluates the expression for "input_records" and stores true records
+  // into "*output_records".
   // "*output_records" is truncated to fit the number of extracted records.
   //
   // Fails if "output_records->size()" is less than "input_records.size()".
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  bool filter(Error *error,
-              ArrayCRef<Record> input_records,
-              ArrayRef<Record> *output_records);
+  // On failure, throws an exception.
+  virtual void filter(ArrayCRef<Record> input_records,
+                      ArrayRef<Record> *output_records) = 0;
 
   // Adjust scores of records.
   //
   // Evaluates the expression for "*records" and replaces the scores with
   // the evaluation results.
-  // Note that the first "offset" records are not modified.
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  bool adjust(Error *error, Array<Record> *records, Int offset = 0);
+  // The first "offset" records are not modified.
+  //
+  // On failure, throws an exception.
+  virtual void adjust(Array<Record> *records, size_t offset = 0) = 0;
 
   // Adjust scores of records.
   //
   // Evaluates the expression for "records" and replaces the scores with
   // the evaluation results.
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  bool adjust(Error *error, ArrayRef<Record> records);
+  // On failure, throws an exception.
+  virtual void adjust(ArrayRef<Record> records) = 0;
 
   // Evaluate the expression.
   //
   // Evaluates the expression for "records" and stores the results into
   // "*results".
   //
-  // Fails if "T" is different from the result data type.
+  // Fails if "T" differs from the result data type.
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  template <typename T>
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                Array<T> *results);
+  // On failure, throws an exception.
+  virtual void evaluate(ArrayCRef<Record> records,
+                        Array<Bool> *results) = 0;
+  virtual void evaluate(ArrayCRef<Record> records,
+                        Array<Int> *results) = 0;
+  virtual void evaluate(ArrayCRef<Record> records,
+                        Array<Float> *results) = 0;
+  virtual void evaluate(ArrayCRef<Record> records,
+                        Array<GeoPoint> *results) = 0;
+  virtual void evaluate(ArrayCRef<Record> records,
+                        Array<Text> *results) = 0;
 
   // Evaluate the expression.
   //
   // Evaluates the expression for "records" and stores the results into
-  // "*results".
-  //
-  // Fails if "T" is different from the result data type.
-  // Fails if "results.size()" != "records.size()".
-  //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  template <typename T>
-  bool evaluate(Error *error,
-                ArrayCRef<Record> records,
-                ArrayRef<T> results);
-
- private:
-  const Table *table_;
-  unique_ptr<Node> root_;
-  Int block_size_;
-
-  // Create an expression.
-  //
-  // On success, returns a poitner to the expression.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
-  static unique_ptr<Expression> create(Error *error,
-                                       const Table *table,
-                                       unique_ptr<Node> &&root,
-                                       const ExpressionOptions &options);
-
-  Expression(const Table *table,
-             unique_ptr<Node> &&root,
-             Int block_size);
-
-  friend ExpressionBuilder;
+  // "results".
+  //
+  // Fails if the data type of "records" differs from the result data type.
+  // Fails if "records.size()" != "results.size()".
+  //
+  // On failure, throws an exception.
+  virtual void evaluate(ArrayCRef<Record> records,
+                        ArrayRef<Bool> results) = 0;
+  virtual void evaluate(ArrayCRef<Record> records,
+                        ArrayRef<Int> results) = 0;
+  virtual void evaluate(ArrayCRef<Record> records,
+                        ArrayRef<Float> results) = 0;
+  virtual void evaluate(ArrayCRef<Record> records,
+                        ArrayRef<GeoPoint> results) = 0;
+  virtual void evaluate(ArrayCRef<Record> records,
+                        ArrayRef<Text> results) = 0;
 };
 
 class ExpressionBuilder {
  public:
-  using Node = expression::Node;
-  using Builder = expression::Builder;
-
   // Create an object for building expressions.
   //
-  // On success, returns a poitner to the builder.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
-  static unique_ptr<ExpressionBuilder> create(Error *error,
-                                              const Table *table);
+  // On success, returns the builder.
+  // On failure, throws an exception.
+  static std::unique_ptr<ExpressionBuilder> create(const Table *table);
 
-  ~ExpressionBuilder();
+  ExpressionBuilder() = default;
+  virtual ~ExpressionBuilder() = default;
 
   // Return the target table.
-  const Table *table() const {
-    return table_;
-  }
-  // Return the builder is OK or broken.
-  bool is_ok() const {
-    return is_ok_;
-  }
+  virtual const Table *table() const = 0;
 
   // Push a node associated with a constant.
   //
-  // 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);
+  // On failure, throws an exception.
+  virtual void push_constant(const Datum &datum) = 0;
 
   // 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);
+  // On failure, throws an exception.
+  virtual void push_row_id() = 0;
 
   // 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);
+  // On failure, throws an exception.
+  virtual void push_score() = 0;
 
   // Push a node associated with a column.
   //
-  // 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);
+  // On failure, throws an exception.
+  virtual void push_column(const String &name) = 0;
 
   // Push a node associated with an operator.
   //
   // Pops operands and pushes an operator.
   // Fails if there are not enough operands.
-  // Fails if the combination of operands is invalid.
+  // Fails if the combination of the operator and its 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);
+  // On failure, throws an exception.
+  virtual void push_operator(OperatorType operator_type) = 0;
 
   // Begin a subexpression.
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  bool begin_subexpression(Error *error);
+  // On failure, throws an exception.
+  virtual void begin_subexpression() = 0;
 
   // End a subexpression.
   //
-  // On success, returns true.
-  // On failure, returns false and stores error information into "*error" if
-  // "error" != nullptr.
-  bool end_subexpression(
-      Error *error,
-      const ExpressionOptions &options = ExpressionOptions());
+  // Fails if the stack for the subexpression is empty or contains more than
+  // one nodes.
+  //
+  // On failure, throws an exception.
+  virtual void end_subexpression(
+      const ExpressionOptions &options = ExpressionOptions()) = 0;
 
   // Clear the internal stack.
-  void clear();
+  virtual void clear() = 0;
 
   // Complete building an expression and clear the internal stack.
   //
-  // Fails if the stack is empty or contains more than one nodes.
+  // Fails if the node stack is empty or contains more than one nodes.
+  // Fails if there is an incomplete subexpression.
   //
-  // On success, returns a pointer to the expression.
-  // On failure, returns nullptr and stores error information into "*error" if
-  // "error" != nullptr.
-  unique_ptr<Expression> release(
-      Error *error,
-      const ExpressionOptions &options = ExpressionOptions());
-
- private:
-  const Table *table_;
-  Array<unique_ptr<Builder>> builders_;
-  bool is_ok_;
-
-  explicit ExpressionBuilder(const Table *table);
+  // On success, returns the expression.
+  // On failure, throws an exception.
+  virtual std::unique_ptr<Expression> release(
+      const ExpressionOptions &options = ExpressionOptions()) = 0;
 };
 
 }  // namespace grnxx

  Modified: lib/grnxx/Makefile.am (+1 -1)
===================================================================
--- lib/grnxx/Makefile.am    2014-11-11 08:38:14 +0900 (c0d825e)
+++ lib/grnxx/Makefile.am    2014-11-12 16:10:55 +0900 (9ff3252)
@@ -11,10 +11,10 @@ libgrnxx_la_LDFLAGS = @AM_LTLDFLAGS@
 libgrnxx_la_SOURCES =			\
 	cursor.cpp			\
 	db.cpp				\
+	expression.cpp			\
 	library.cpp			\
 	string.cpp
 
-#	expression.cpp			\
 #	index.cpp			\
 #	merger.cpp			\
 #	pipeline.cpp			\

  Copied: lib/grnxx/expression-old.cpp (+0 -0) 100%
===================================================================

  Modified: lib/grnxx/expression.cpp (+8 -4081)
===================================================================
--- lib/grnxx/expression.cpp    2014-11-11 08:38:14 +0900 (ed88cca)
+++ lib/grnxx/expression.cpp    2014-11-12 16:10:55 +0900 (e14c841)
@@ -1,4090 +1,17 @@
 #include "grnxx/expression.hpp"
 
-#include "grnxx/impl/column.hpp"
-#include "grnxx/table.hpp"
+#include <new>
 
-#include <iostream>  // For debugging.
+#include "grnxx/impl/expression.hpp"
 
 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;
-    }
-  }
+std::unique_ptr<ExpressionBuilder> ExpressionBuilder::create(
+    const Table *table) try {
+  return std::unique_ptr<ExpressionBuilder>(
+      new impl::ExpressionBuilder(static_cast<const impl::Table *>(table)));
+} catch (const std::bad_alloc &) {
+  throw "Memory allocation failed";  // TODO
 }
 
-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

  Modified: lib/grnxx/impl/Makefile.am (+2 -0)
===================================================================
--- lib/grnxx/impl/Makefile.am    2014-11-11 08:38:14 +0900 (bf5f11d)
+++ lib/grnxx/impl/Makefile.am    2014-11-12 16:10:55 +0900 (789fca8)
@@ -10,6 +10,7 @@ libgrnxx_impl_la_LDFLAGS = @AM_LTLDFLAGS@
 
 libgrnxx_impl_la_SOURCES =		\
 	db.cpp				\
+	expression.cpp			\
 	table.cpp
 
 libgrnxx_impl_includedir = ${includedir}/grnxx/impl
@@ -17,5 +18,6 @@ libgrnxx_impl_include_HEADERS =		\
 	column.hpp			\
 	cursor.hpp			\
 	db.hpp				\
+	expression.hpp			\
 	index.hpp			\
 	table.hpp

  Added: lib/grnxx/impl/expression.cpp (+792 -0) 100644
===================================================================
--- /dev/null
+++ lib/grnxx/impl/expression.cpp    2014-11-12 16:10:55 +0900 (a461aca)
@@ -0,0 +1,792 @@
+#include "grnxx/impl/expression.hpp"
+
+#include <new>
+
+#include "grnxx/impl/column.hpp"
+
+namespace grnxx {
+namespace impl {
+namespace expression {
+
+enum NodeType {
+  CONSTANT_NODE,
+  ROW_ID_NODE,
+  SCORE_NODE,
+  COLUMN_NODE,
+  OPERATOR_NODE
+};
+
+// -- Node --
+
+class Node {
+ public:
+  Node() = default;
+  virtual ~Node() = default;
+
+  // 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 *reference_table() const {
+    return nullptr;
+  }
+
+  // -- Public API (grnxx/expression.hpp) --
+
+  virtual void filter(ArrayCRef<Record>, ArrayRef<Record> *) {
+    // Other than TypedNode<Bool> don't support filter().
+    throw "Not supported";  // TODO
+  }
+  virtual void adjust(ArrayRef<Record>) {
+    // Other than TypedNode<Float> don't support adjust().
+    throw "Not supported";
+  }
+};
+
+
+// -- TypedNode --
+
+template <typename T>
+class TypedNode : public Node {
+ public:
+  using Value = T;
+
+  TypedNode() = default;
+  virtual ~TypedNode() = default;
+
+  DataType data_type() const {
+    return T::type();
+  }
+
+//  void filter(ArrayCRef<Record>, ArrayRef<Record> *) {
+//    // Other than TypedNode<Bool> don't support filter().
+//    throw "Not supported";
+//  }
+
+//  void adjust(ArrayRef<Record>) {
+//    // Other than TypedNode<Float> don't support adjust().
+//    throw "Not supported";
+//  }
+
+  // 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 void evaluate(ArrayCRef<Record> records,
+                        ArrayRef<Value> results) = 0;
+};
+
+template <>
+class TypedNode<Bool> : public Node {
+ public:
+  using Value = Bool;
+
+  TypedNode() = default;
+  virtual ~TypedNode() = default;
+
+  DataType data_type() const {
+    return Value::type();
+  }
+
+  // NOTE: Derived classes should provide better implementations.
+  virtual void filter(ArrayCRef<Record> input_records,
+                      ArrayRef<Record> *output_records);
+
+//  void adjust(ArrayRef<Record>) {
+//    // Other than TypedNode<Float> don't support adjust().
+//    GRNXX_ERROR_SET(error, INVALID_OPERATION, "Invalid operation");
+//    return false;
+//  }
+
+  virtual void evaluate(ArrayCRef<Record> records,
+                        ArrayRef<Value> results) = 0;
+
+ private:
+  Array<Value> values_for_filter_;
+};
+
+void TypedNode<Bool>::filter(ArrayCRef<Record> input_records,
+                             ArrayRef<Record> *output_records) {
+  if (values_for_filter_.size() < input_records.size()) {
+    values_for_filter_.resize(input_records.size());
+  }
+  evaluate(input_records, values_for_filter_.ref(0, input_records.size()));
+  size_t count = 0;
+  for (size_t i = 0; i < input_records.size(); ++i) {
+    if (values_for_filter_[i]) {
+      (*output_records)[count] = input_records[i];
+      ++count;
+    }
+  }
+  *output_records = output_records->ref(0, count);
+}
+
+template <>
+class TypedNode<Float> : public Node {
+ public:
+  using Value = Float;
+
+  TypedNode() = default;
+  virtual ~TypedNode() = default;
+
+  DataType data_type() const {
+    return Value::type();
+  }
+
+//  void filter(ArrayCRef<Record>, ArrayRef<Record> *) {
+//    // Other than TypedNode<Bool> don't support filter().
+//    GRNXX_ERROR_SET(error, INVALID_OPERATION, "Invalid operation");
+//    return false;
+//  }
+
+  // NOTE: Derived classes should provide better implementations.
+  virtual void adjust(ArrayRef<Record> records);
+
+  virtual void evaluate(ArrayCRef<Record> records,
+                        ArrayRef<Value> results) = 0;
+
+ private:
+  Array<Float> values_for_adjust_;
+};
+
+void TypedNode<Float>::adjust(ArrayRef<Record> records) {
+  if (values_for_adjust_.size() < records.size()) {
+    values_for_adjust_.resize(records.size());
+  }
+  evaluate(records, values_for_adjust_.ref(0, records.size()));
+  for (size_t i = 0; i < records.size(); ++i) {
+    records[i].score = values_for_adjust_[i];
+  }
+}
+
+// -- ConstantNode --
+
+template <typename T>
+class ConstantNode : public TypedNode<T> {
+ public:
+  using Value = T;
+
+  explicit ConstantNode(const Value &value)
+      : TypedNode<Value>(),
+        value_(value) {}
+  ~ConstantNode() = default;
+
+  NodeType node_type() const {
+    return CONSTANT_NODE;
+  }
+
+  void evaluate(ArrayCRef<Record> records, ArrayRef<Value> results) {
+    for (size_t i = 0; i < records.size(); ++i) {
+      results[i] = value_;
+    }
+  }
+
+ private:
+  Value value_;
+};
+
+template <>
+class ConstantNode<Bool> : public TypedNode<Bool> {
+ public:
+  using Value = Bool;
+
+  explicit ConstantNode(Value value) : TypedNode<Value>(), value_(value) {}
+  ~ConstantNode() = default;
+
+  NodeType node_type() const {
+    return CONSTANT_NODE;
+  }
+
+  void filter(ArrayCRef<Record> input_records,
+              ArrayRef<Record> *output_records);
+  void evaluate(ArrayCRef<Record> records, ArrayRef<Value> results);
+
+ private:
+  Value value_;
+};
+
+void ConstantNode<Bool>::filter(ArrayCRef<Record> input_records,
+                                ArrayRef<Record> *output_records) {
+  if (value_) {
+    // Don't copy records if the input/output addresses are the same.
+    if (input_records.data() != output_records->data()) {
+      for (size_t i = 0; i < input_records.size(); ++i) {
+        (*output_records)[i] = input_records[i];
+      }
+    }
+  } else {
+    *output_records = output_records->ref(0, 0);
+  }
+}
+
+void ConstantNode<Bool>::evaluate(ArrayCRef<Record> records,
+                                  ArrayRef<Value> results) {
+  for (size_t i = 0; i < records.size(); ++i) {
+    results[i] = value_;
+  }
+}
+
+template <>
+class ConstantNode<Float> : public TypedNode<Float> {
+ public:
+  using Value = Float;
+
+  explicit ConstantNode(Value value) : TypedNode<Float>(), value_(value) {}
+  ~ConstantNode() = default;
+
+  NodeType node_type() const {
+    return CONSTANT_NODE;
+  }
+
+  void adjust(ArrayRef<Record> records) {
+    for (size_t i = 0; i < records.size(); ++i) {
+      records[i].score = value_;
+    }
+  }
+  void evaluate(ArrayCRef<Record> records, ArrayRef<Value> results) {
+    for (size_t i = 0; i < records.size(); ++i) {
+      results[i] = value_;
+    }
+  }
+
+ private:
+  Float value_;
+};
+
+//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_;
+//};
+
+// -- RowIDNode --
+
+class RowIDNode : public TypedNode<Int> {
+ public:
+  using Value = Int;
+
+  RowIDNode() = default;
+  ~RowIDNode() = default;
+
+  NodeType node_type() const {
+    return ROW_ID_NODE;
+  }
+
+  void evaluate(ArrayCRef<Record> records, ArrayRef<Value> results) {
+    for (size_t i = 0; i < records.size(); ++i) {
+      results[i] = records[i].row_id;
+    }
+  }
+};
+
+// -- ScoreNode --
+
+class ScoreNode : public TypedNode<Float> {
+ public:
+  using Value = Float;
+
+  ScoreNode() = default;
+  ~ScoreNode() = default;
+
+  NodeType node_type() const {
+    return SCORE_NODE;
+  }
+
+  void adjust(ArrayRef<Record>) {
+    // Nothing to do.
+  }
+  void evaluate(ArrayCRef<Record> records, ArrayRef<Value> results) {
+    for (size_t i = 0; i < records.size(); ++i) {
+      results[i] = records[i].score;
+    }
+  }
+};
+
+// -- ColumnNode --
+
+template <typename T>
+class ColumnNode : public TypedNode<T> {
+ public:
+  using Value = T;
+
+  explicit ColumnNode(const ColumnBase *column)
+      : TypedNode<Value>(),
+        column_(static_cast<const impl::Column<Value> *>(column)) {}
+  ~ColumnNode() = default;
+
+  NodeType node_type() const {
+    return COLUMN_NODE;
+  }
+  const Table *reference_table() const {
+    return column_->_reference_table();
+  }
+
+  void evaluate(ArrayCRef<Record> records, ArrayRef<Value> results) {
+    column_->read(records, results);
+  }
+
+ private:
+  const impl::Column<Value> *column_;
+};
+
+template <>
+class ColumnNode<Bool> : public TypedNode<Bool> {
+ public:
+  using Value = Bool;
+
+  explicit ColumnNode(const ColumnBase *column)
+      : TypedNode<Value>(),
+        column_(static_cast<const impl::Column<Value> *>(column)) {}
+  ~ColumnNode() = default;
+
+  NodeType node_type() const {
+    return COLUMN_NODE;
+  }
+
+  void filter(ArrayCRef<Record> input_records,
+              ArrayRef<Record> *output_records);
+  void evaluate(ArrayCRef<Record> records, ArrayRef<Value> results) {
+    column_->read(records, results);
+  }
+
+ private:
+  const impl::Column<Value> *column_;
+};
+
+void ColumnNode<Bool>::filter(ArrayCRef<Record> input_records,
+                              ArrayRef<Record> *output_records) {
+  size_t count = 0;
+  for (size_t i = 0; i < input_records.size(); ++i) {
+    if (column_->get(input_records[i].row_id)) {
+      (*output_records)[count] = input_records[i];
+      ++count;
+    }
+  }
+  *output_records = output_records->ref(0, count);
+}
+
+template <>
+class ColumnNode<Float> : public TypedNode<Float> {
+ public:
+  using Value = Float;
+
+  explicit ColumnNode(const ColumnBase *column)
+      : TypedNode<Value>(),
+        column_(static_cast<const impl::Column<Value> *>(column)) {}
+  ~ColumnNode() = default;
+
+  NodeType node_type() const {
+    return COLUMN_NODE;
+  }
+
+  void adjust(ArrayRef<Record> records) {
+    for (size_t i = 0; i < records.size(); ++i) {
+      records[i].score = column_->get(records[i].row_id);
+    }
+  }
+  void evaluate(ArrayCRef<Record> records, ArrayRef<Value> results) {
+    column_->read(records, results);
+  }
+
+ private:
+  const impl::Column<Value> *column_;
+};
+
+}  // namespace expression
+
+using namespace expression;
+
+// -- Expression --
+
+Expression::Expression(const Table *table,
+                       std::unique_ptr<Node> &&root,
+                       const ExpressionOptions &options)
+    : table_(table),
+      root_(std::move(root)),
+      block_size_(options.block_size) {}
+
+Expression::~Expression() {}
+
+DataType Expression::data_type() const {
+  // TODO: Node has the data type.
+  throw "Not supported yet";  // TODO
+}
+
+void Expression::filter(Array<Record> *records,
+                        size_t input_offset,
+                        size_t output_offset,
+                        size_t output_limit) {
+  ArrayCRef<Record> input = records->cref(input_offset);
+  ArrayRef<Record> output = records->ref(input_offset);
+  size_t count = 0;
+  while ((input.size() > 0) && (output_limit > 0)) {
+    size_t next_size = (input.size() < block_size_) ?
+                       input.size() : block_size_;
+    ArrayCRef<Record> next_input = input.cref(0, next_size);
+    ArrayRef<Record> next_output = output.ref(0, next_size);
+    root_->filter(next_input, &next_output);
+    input = input.cref(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 (size_t 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(input_offset + count);
+}
+
+void Expression::filter(ArrayCRef<Record> input_records,
+                        ArrayRef<Record> *output_records) {
+  ArrayCRef<Record> input = input_records;
+  ArrayRef<Record> output = *output_records;
+  size_t count = 0;
+  while (input.size() > block_size_) {
+    ArrayCRef<Record> input_block = input.cref(0, block_size_);
+    ArrayRef<Record> output_block = output.ref(0, block_size_);
+    root_->filter(input_block, &output_block);
+    input = input.cref(block_size_);
+    output = output.ref(output_block.size());
+    count += output_block.size();
+  }
+  root_->filter(input, &output);
+  count += output.size();
+  *output_records = output_records->ref(0, count);
+}
+
+void Expression::adjust(Array<Record> *records, size_t offset) {
+  adjust(records->ref(offset));
+}
+
+void Expression::adjust(ArrayRef<Record> records) {
+  while (records.size() > block_size_) {
+    root_->adjust(records.ref(0, block_size_));
+    records = records.ref(block_size_);
+  }
+  root_->adjust(records);
+}
+
+void Expression::evaluate(ArrayCRef<Record> records,
+                          Array<Bool> *results) {
+  _evaluate(records, results);
+}
+
+void Expression::evaluate(ArrayCRef<Record> records,
+                          Array<Int> *results) {
+  _evaluate(records, results);
+}
+
+void Expression::evaluate(ArrayCRef<Record> records,
+                          Array<Float> *results) {
+  _evaluate(records, results);
+}
+
+void Expression::evaluate(ArrayCRef<Record> records,
+                          Array<GeoPoint> *results) {
+  _evaluate(records, results);
+}
+
+void Expression::evaluate(ArrayCRef<Record> records,
+                          Array<Text> *results) {
+  _evaluate(records, results);
+}
+
+void Expression::evaluate(ArrayCRef<Record> records,
+                          ArrayRef<Bool> results) {
+  _evaluate(records, results);
+}
+
+void Expression::evaluate(ArrayCRef<Record> records,
+                          ArrayRef<Int> results) {
+  _evaluate(records, results);
+}
+
+void Expression::evaluate(ArrayCRef<Record> records,
+                          ArrayRef<Float> results) {
+  _evaluate(records, results);
+}
+
+void Expression::evaluate(ArrayCRef<Record> records,
+                          ArrayRef<GeoPoint> results) {
+  _evaluate(records, results);
+}
+
+void Expression::evaluate(ArrayCRef<Record> records,
+                          ArrayRef<Text> results) {
+  _evaluate(records, results);
+}
+
+template <typename T>
+void Expression::_evaluate(ArrayCRef<Record> records, Array<T> *results) {
+  results->resize(records.size());
+  _evaluate(records, results->ref());
+}
+
+template <typename T>
+void Expression::_evaluate(ArrayCRef<Record> records, ArrayRef<T> results) {
+  if (T::type() != data_type()) {
+    throw "Data type conflict";  // TODO
+  }
+  if (records.size() != results.size()) {
+    throw "Size conflict";  // TODO
+  }
+  TypedNode<T> *typed_root = static_cast<TypedNode<T> *>(root_.get());
+  while (records.size() > block_size_) {
+    ArrayCRef<Record> input = records.cref(0, block_size_);
+    ArrayRef<T> output = results.ref(0, block_size_);
+    typed_root->evaluate(input, output);
+    records = records.cref(block_size_);
+    results = results.ref(block_size_);
+  }
+  typed_root->evaluate(records, results);
+}
+
+// -- ExpressionBuilder --
+
+ExpressionBuilder::ExpressionBuilder(const Table *table)
+    : table_(table),
+      node_stack_(),
+      subexpression_builder_() {}
+
+ExpressionBuilder::~ExpressionBuilder() {}
+
+void ExpressionBuilder::push_constant(const Datum &datum) {
+  if (subexpression_builder_) {
+    subexpression_builder_->push_constant(datum);
+  } else {
+    node_stack_.push_back(std::unique_ptr<Node>(create_constant_node(datum)));
+  }
+}
+
+void ExpressionBuilder::push_row_id() try {
+  if (subexpression_builder_) {
+    subexpression_builder_->push_row_id();
+  } else {
+    node_stack_.push_back(std::unique_ptr<Node>(new RowIDNode()));
+  }
+} catch (const std::bad_alloc &) {
+  throw "Memory allocation failed";  // TODO
+}
+
+void ExpressionBuilder::push_score() try {
+  if (subexpression_builder_) {
+    subexpression_builder_->push_score();
+  } else {
+    node_stack_.push_back(std::unique_ptr<Node>(new ScoreNode()));
+  }
+} catch (const std::bad_alloc &) {
+  throw "Memory allocation failed";  // TODO
+}
+
+void ExpressionBuilder::push_column(const String &name) {
+  if (subexpression_builder_) {
+    subexpression_builder_->push_column(name);
+  } else {
+    node_stack_.push_back(std::unique_ptr<Node>(create_column_node(name)));
+  }
+}
+
+void ExpressionBuilder::push_operator(OperatorType operator_type) {
+  if (subexpression_builder_) {
+    subexpression_builder_->push_operator(operator_type);
+  } else {
+    // TODO
+  }
+}
+
+void ExpressionBuilder::begin_subexpression() try {
+  if (subexpression_builder_) {
+    subexpression_builder_->begin_subexpression();
+  } else if (node_stack_.is_empty()) {
+    throw "No operand";  // TODO
+  } else {
+    std::unique_ptr<Node> &latest_node = node_stack_.back();
+    if (!latest_node->reference_table()) {
+      throw "Reference not available";  // TODO
+    }
+    subexpression_builder_.reset(
+        new ExpressionBuilder(latest_node->reference_table()));
+  }
+} catch (const std::bad_alloc &) {
+  throw "Memory allocation failed";  // TODO
+}
+
+void ExpressionBuilder::end_subexpression(const ExpressionOptions &options) {
+  if (!subexpression_builder_) {
+    throw "No subexpression";  // TODO
+  }
+  if (subexpression_builder_->subexpression_builder_) {
+    subexpression_builder_->end_subexpression(options);
+  } else {
+    if (subexpression_builder_->node_stack_.size() != 1) {
+      throw "Incomplete subexpression";  // TODO
+    }
+    node_stack_.push_back(std::move(subexpression_builder_->node_stack_[0]));
+    push_dereference(options);
+    subexpression_builder_.reset();
+  }
+}
+
+void ExpressionBuilder::clear() {
+  node_stack_.clear();
+  subexpression_builder_.reset();
+}
+
+std::unique_ptr<ExpressionInterface> ExpressionBuilder::release(
+    const ExpressionOptions &options) try {
+  if (subexpression_builder_) {
+    throw "Incomplete subexpression";  // TODO
+  }
+  if (node_stack_.size() != 1) {
+    throw "Incomplete expression";  // TODO
+  }
+  std::unique_ptr<Node> root = std::move(node_stack_[0]);
+  node_stack_.clear();
+  return std::unique_ptr<ExpressionInterface>(
+      new Expression(table_, std::move(root), options));
+} catch (const std::bad_alloc &) {
+  throw "Memory allocation failed";  // TODO
+}
+
+void ExpressionBuilder::push_dereference(const ExpressionOptions &options) {
+  throw "Not supported yet";  // TODO
+}
+
+Node *ExpressionBuilder::create_constant_node(
+    const Datum &datum) try {
+  switch (datum.type()) {
+    case BOOL_DATA: {
+      return new ConstantNode<Bool>(datum.as_bool());
+    }
+    case INT_DATA: {
+      return new ConstantNode<Int>(datum.as_int());
+    }
+    case FLOAT_DATA: {
+      return new ConstantNode<Float>(datum.as_float());
+    }
+    case GEO_POINT_DATA: {
+      return new ConstantNode<GeoPoint>(datum.as_geo_point());
+    }
+    case TEXT_DATA: {
+      return new ConstantNode<Text>(datum.as_text());
+    }
+//    case BOOL_VECTOR_DATA: {
+//      return new ConstantNode<Vector<Bool>>(datum.as_bool_vector());
+//    }
+//    case INT_VECTOR_DATA: {
+//      return new ConstantNode<Vector<Int>>(datum.as_int_vector());
+//    }
+//    case FLOAT_VECTOR_DATA: {
+//      return new ConstantNode<Vector<Float>>(datum.as_float_vector());
+//    }
+//    case GEO_POINT_VECTOR_DATA: {
+//      return new ConstantNode<Vector<GeoPoint>>(datum.as_geo_point_vector());
+//    }
+//    case TEXT_VECTOR_DATA: {
+//      return new ConstantNode<Vector<Text>>(datum.as_text_vector());
+//    }
+    default: {
+      throw "Not supported yet";  // TODO
+    }
+  }
+} catch (const std::bad_alloc &) {
+  throw "Memory allocation failed";  // TODO
+}
+
+Node *ExpressionBuilder::create_column_node(
+    const String &name) try {
+  ColumnBase *column = table_->find_column(name);
+  if (!column) {
+    throw "Column not found";  // TODO
+  }
+  switch (column->data_type()) {
+    case BOOL_DATA: {
+      return new ColumnNode<Bool>(column);
+    }
+    case INT_DATA: {
+      return new ColumnNode<Int>(column);
+    }
+    case FLOAT_DATA: {
+      return new ColumnNode<Float>(column);
+    }
+    case GEO_POINT_DATA: {
+      return new ColumnNode<GeoPoint>(column);
+    }
+    case TEXT_DATA: {
+      return new ColumnNode<Text>(column);
+    }
+//    case BOOL_VECTOR_DATA: {
+//      return new ColumnNode<Vector<Bool>>(column);
+//    }
+//    case INT_VECTOR_DATA: {
+//      return new ColumnNode<Vector<Int>>(column);
+//    }
+//    case FLOAT_VECTOR_DATA: {
+//      return new ColumnNode<Vector<Float>>(column);
+//    }
+//    case GEO_POINT_VECTOR_DATA: {
+//      return new ColumnNode<Vector<GeoPoint>>(column);
+//    }
+//    case TEXT_VECTOR_DATA: {
+//      return new ColumnNode<Vector<Text>>(column);
+//    }
+    default: {
+      throw "Not supported yet";  // TODO
+    }
+  }
+} catch (const std::bad_alloc &) {
+  throw "Memory allocation failed";  // TODO
+}
+
+}  // namespace impl
+}  // namespace grnxx

  Added: lib/grnxx/impl/expression.hpp (+123 -0) 100644
===================================================================
--- /dev/null
+++ lib/grnxx/impl/expression.hpp    2014-11-12 16:10:55 +0900 (82f222e)
@@ -0,0 +1,123 @@
+#ifndef GRNXX_IMPL_EXPRESSION_HPP
+#define GRNXX_IMPL_EXPRESSION_HPP
+
+#include "grnxx/expression.hpp"
+#include "grnxx/impl/table.hpp"
+
+namespace grnxx {
+namespace impl {
+namespace expression {
+
+class Node;
+class Builder;
+
+}  // namespace expression
+
+using ExpressionInterface = grnxx::Expression;
+using ExpressionBuilderInterface = grnxx::ExpressionBuilder;
+
+class Expression : public ExpressionInterface {
+ public:
+  using Node = expression::Node;
+
+  // -- Public API (grnxx/expression.hpp) --
+
+  Expression(const Table *table,
+             std::unique_ptr<Node> &&root,
+             const ExpressionOptions &options);
+  ~Expression();
+
+  const Table *table() const {
+    return table_;
+  }
+  DataType data_type() const;
+  size_t block_size() const {
+    return block_size_;
+  }
+
+  void filter(Array<Record> *records,
+              size_t input_offset,
+              size_t output_offset,
+              size_t output_limit);
+  void filter(ArrayCRef<Record> input_records,
+              ArrayRef<Record> *output_records);
+
+  void adjust(Array<Record> *records, size_t offset);
+  void adjust(ArrayRef<Record> records);
+
+  void evaluate(ArrayCRef<Record> records, Array<Bool> *results);
+  void evaluate(ArrayCRef<Record> records, Array<Int> *results);
+  void evaluate(ArrayCRef<Record> records, Array<Float> *results);
+  void evaluate(ArrayCRef<Record> records, Array<GeoPoint> *results);
+  void evaluate(ArrayCRef<Record> records, Array<Text> *results);
+
+  void evaluate(ArrayCRef<Record> records, ArrayRef<Bool> results);
+  void evaluate(ArrayCRef<Record> records, ArrayRef<Int> results);
+  void evaluate(ArrayCRef<Record> records, ArrayRef<Float> results);
+  void evaluate(ArrayCRef<Record> records, ArrayRef<GeoPoint> results);
+  void evaluate(ArrayCRef<Record> records, ArrayRef<Text> results);
+
+ private:
+  const Table *table_;
+  std::unique_ptr<Node> root_;
+  size_t block_size_;
+
+  template <typename T>
+  void _evaluate(ArrayCRef<Record> records, Array<T> *results);
+  template <typename T>
+  void _evaluate(ArrayCRef<Record> records, ArrayRef<T> results);
+};
+
+class ExpressionBuilder : public ExpressionBuilderInterface {
+ public:
+  using Node = expression::Node;
+
+  // -- Public API (grnxx/expression.hpp) --
+
+  explicit ExpressionBuilder(const Table *table);
+  ~ExpressionBuilder();
+
+  const Table *table() const {
+    return table_;
+  }
+
+  void push_constant(const Datum &datum);
+  void push_row_id();
+  void push_score();
+  void push_column(const String &name);
+  void push_operator(OperatorType operator_type);
+
+  void begin_subexpression();
+  void end_subexpression(const ExpressionOptions &options);
+
+  void clear();
+
+  std::unique_ptr<ExpressionInterface> release(
+      const ExpressionOptions &options);
+
+ private:
+  const Table *table_;
+  Array<std::unique_ptr<Node>> node_stack_;
+  std::unique_ptr<ExpressionBuilder> subexpression_builder_;
+
+  // Push a node associated with the dereference operator.
+  //
+  // On failure, throws an exception.
+  void push_dereference(const ExpressionOptions &options);
+
+  // Create a node associated with a constant.
+  //
+  // On failure, throws an exception.
+  Node *create_constant_node(const Datum &datum);
+
+  // Create a node associated with a column.
+  //
+  // On failure, throws an exception.
+  Node *create_column_node(const String &name);
+
+};
+
+}  // namespace impl
+}  // namespace grnxx
+
+#endif  // GRNXX_IMPL_EXPRESSION_HPP




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