[Groonga-commit] groonga/grnxx at d71ea2b [master] Add a part of Expression implementations.

Back to archive index

susumu.yata null+****@clear*****
Wed Jul 9 16:27:15 JST 2014


susumu.yata	2014-07-09 16:27:15 +0900 (Wed, 09 Jul 2014)

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

  Message:
    Add a part of Expression implementations.

  Modified files:
    include/grnxx/expression.hpp
    include/grnxx/types.hpp
    lib/grnxx/expression.cpp

  Modified: include/grnxx/expression.hpp (+31 -10)
===================================================================
--- include/grnxx/expression.hpp    2014-07-08 16:11:24 +0900 (5d635f9)
+++ include/grnxx/expression.hpp    2014-07-09 16:27:15 +0900 (00cdb12)
@@ -1,28 +1,46 @@
 #ifndef GRNXX_EXPRESSION_HPP
 #define GRNXX_EXPRESSION_HPP
 
+#include <vector>
+
 #include "grnxx/types.hpp"
 
 namespace grnxx {
 
 enum OperatorType {
-  // TODO
+  // -- Unary operators --
+
+  // -- Binary operators --
+
+  EQUAL_OPERATOR,
+  NOT_EQUAL_OPERATOR
 };
 
 class Expression {
  public:
+  // Create an expression.
+  //
+  // Returns a poitner to the builder on success.
+  // On failure, returns nullptr and stores error information into "*error" if
+  // "error" != nullptr.
+  static unique_ptr<Expression> create(Error *error,
+                                       unique_ptr<ExpressionNode> &&root);
+
+  ~Expression();
+
   Table *table() const {
     return table_;
   }
-  DataType data_type() const {
-    return data_type_;
-  }
+  DataType data_type() const;
 
-  friend class ExpressionBuilder;
+  bool filter(Error *error, RecordSet *record_set);
 
  private:
   Table *table_;
-  DataType data_type_;
+  unique_ptr<ExpressionNode> root_;
+
+  Expression(Table *table,
+             unique_ptr<ExpressionNode> &&root);
 };
 
 class ExpressionBuilder {
@@ -37,7 +55,7 @@ class ExpressionBuilder {
 
   ~ExpressionBuilder();
 
-  Table *table() const {
+  const Table *table() const {
     return table_;
   }
 
@@ -69,20 +87,23 @@ class ExpressionBuilder {
   // "error" != nullptr.
   bool push_operator(Error *error, OperatorType operator_type);
 
-  // Clear the builder.
+  // Clear the stack.
   void clear();
 
   // Complete building an expression and clear the builder.
   //
+  // Fails if the stack is empty or contains more than one nodes.
+  //
   // Returns a poitner to the expression on success.
   // On failure, returns nullptr and stores error information into "*error" if
   // "error" != nullptr.
   unique_ptr<Expression> release(Error *error);
 
  private:
-  Table *table_;
+  const Table *table_;
+  std::vector<unique_ptr<ExpressionNode>> stack_;
 
-  explicit ExpressionBuilder(Table *table);
+  explicit ExpressionBuilder(const Table *table);
 };
 
 }  // namespace grnxx

  Modified: include/grnxx/types.hpp (+1 -0)
===================================================================
--- include/grnxx/types.hpp    2014-07-08 16:11:24 +0900 (e0d5b73)
+++ include/grnxx/types.hpp    2014-07-09 16:27:15 +0900 (30997fd)
@@ -317,6 +317,7 @@ class Datum;
 class Cursor;
 class RecordSet;
 class Expression;
+class ExpressionNode;
 class ExpressionBuilder;
 
 // Database temporary object option types.

  Modified: lib/grnxx/expression.cpp (+420 -16)
===================================================================
--- lib/grnxx/expression.cpp    2014-07-08 16:11:24 +0900 (7bd70f6)
+++ lib/grnxx/expression.cpp    2014-07-09 16:27:15 +0900 (88830bc)
@@ -1,47 +1,451 @@
 #include "grnxx/expression.hpp"
 
+#include "grnxx/column_impl.hpp"
+#include "grnxx/datum.hpp"
 #include "grnxx/error.hpp"
+#include "grnxx/record.hpp"
+#include "grnxx/table.hpp"
 
 namespace grnxx {
 
-unique_ptr<ExpressionBuilder> ExpressionBuilder::create(Error *error,
-                                                        const Table *table) {
+enum ExpressionNodeType {
+  EXPRESSION_DATUM_NODE,
+  EXPRESSION_ROW_ID_NODE,
+  EXPRESSION_SCORE_NODE,
+  EXPRESSION_COLUMN_NODE,
+  EXPRESSION_OPERATOR_NODE
+};
+
+class ExpressionNode {
+ public:
+  ExpressionNode() {}
+  virtual ~ExpressionNode() {}
+
+  virtual ExpressionNodeType node_type() const = 0;
+  virtual DataType data_type() const = 0;
+
+  virtual bool filter(Error *error, RecordSet *record_set) {
+    // TODO: Set an "This type is not supported" error.
+    GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
+    return false;
+  }
+  virtual bool evaluate(Error *error, const RecordSet &record_set) {
+    // TODO: This should be a pure virtual function.
+    GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
+    return false;
+  }
+};
+
+// -- ExpressionDatumNode --
+
+class ExpressionDatumNode : public ExpressionNode {
+ public:
+  ExpressionDatumNode() : ExpressionNode() {}
+  virtual ~ExpressionDatumNode() {}
+
+  ExpressionNodeType node_type() const {
+    return EXPRESSION_DATUM_NODE;
+  }
+};
+
+class ExpressionBoolDatumNode : public ExpressionDatumNode {
+ public:
+  ExpressionBoolDatumNode(Bool datum)
+      : ExpressionDatumNode(),
+        datum_(datum) {}
+  ~ExpressionBoolDatumNode() {}
+
+  DataType data_type() const {
+    return BOOL_DATA;
+  }
+
+  bool filter(Error *error, RecordSet *record_set) {
+    if (!datum_) {
+      record_set->clear();
+    }
+    return true;
+  }
+
+  bool evaluate(Error *error, const RecordSet &record_set) {
+    return true;
+  }
+
+  Bool get(Int i) const {
+    return datum_;
+  }
+
+ private:
+  Bool datum_;
+};
+
+class ExpressionIntDatumNode : public ExpressionDatumNode {
+ public:
+  ExpressionIntDatumNode(Int datum)
+      : ExpressionDatumNode(),
+        datum_(datum) {}
+  ~ExpressionIntDatumNode() {}
+
+  DataType data_type() const {
+    return INT_DATA;
+  }
+
+  bool evaluate(Error *error, const RecordSet &record_set) {
+    return true;
+  }
+
+  Int get(Int i) const {
+    return datum_;
+  }
+
+ private:
+  Int datum_;
+};
+
+// -- ExpressionRowIDNode --
+
+class ExpressionRowIDNode : public ExpressionNode {
+ public:
+  ExpressionRowIDNode()
+      : ExpressionNode(),
+        record_set_(nullptr) {}
+  ~ExpressionRowIDNode() {}
+
+  ExpressionNodeType node_type() const {
+    return EXPRESSION_ROW_ID_NODE;
+  }
+  DataType data_type() const {
+    return INT_DATA;
+  }
+
+  bool evaluate(Error *error, const RecordSet &record_set) {
+    record_set_ = &record_set;
+    return true;
+  }
+
+  Int get(Int i) const {
+    return record_set_->get(i).row_id;
+  }
+
+ private:
+  const RecordSet *record_set_;
+};
+
+// -- ExpressionScoreNode --
+
+class ExpressionScoreNode : public ExpressionNode {
+ public:
+  ExpressionScoreNode() : ExpressionNode() {}
+  ~ExpressionScoreNode() {}
+
+  ExpressionNodeType node_type() const {
+    return EXPRESSION_SCORE_NODE;
+  }
+  DataType data_type() const {
+    return FLOAT_DATA;
+  }
+
+  bool evaluate(Error *error, const RecordSet &record_set) {
+    record_set_ = &record_set;
+    return true;
+  }
+
+  Float get(Int i) const {
+    return record_set_->get(i).score;
+  }
+
+ private:
+  const RecordSet *record_set_;
+};
+
+// -- ExpressionColumnNode --
+
+class ExpressionColumnNode : public ExpressionNode {
+ public:
+  ExpressionColumnNode() : ExpressionNode() {}
+  virtual ~ExpressionColumnNode() {}
+
+  ExpressionNodeType node_type() const {
+    return EXPRESSION_COLUMN_NODE;
+  }
+};
+
+class ExpressionBoolColumnNode : public ExpressionColumnNode {
+ public:
+  ExpressionBoolColumnNode(const BoolColumn *column)
+      : ExpressionColumnNode(),
+        column_(column),
+        record_set_(nullptr) {}
+  ~ExpressionBoolColumnNode() {}
+
+  DataType data_type() const {
+    return column_->data_type();
+  }
+
+//  bool filter(Error *error, RecordSet *record_set) {
+//    return false;
+//  }
+
+  bool evaluate(Error *error, const RecordSet &record_set) {
+    record_set_ = &record_set;
+    return true;
+  }
+
+  Bool get(Int i) const {
+    return column_->get(record_set_->get(i).row_id);
+  }
+
+ private:
+  const BoolColumn *column_;
+  const RecordSet *record_set_;
+};
+
+class ExpressionIntColumnNode : public ExpressionColumnNode {
+ public:
+  ExpressionIntColumnNode(const IntColumn *column)
+      : ExpressionColumnNode(),
+        column_(column),
+        record_set_(nullptr) {}
+  ~ExpressionIntColumnNode() {}
+
+  DataType data_type() const {
+    return column_->data_type();
+  }
+
+  bool evaluate(Error *error, const RecordSet &record_set) {
+    record_set_ = &record_set;
+    return true;
+  }
+
+  Int get(Int i) const {
+    return column_->get(record_set_->get(i).row_id);
+  }
+
+ private:
+  const IntColumn *column_;
+  const RecordSet *record_set_;
+};
+
+// -- ExpressionOperatorNode --
+
+// TODO: 演算子の実装はどうしても長くなるので,別ファイルに移行すべきかもしれません.
+
+// TODO: ExpressionOperatorNode<T> (T: 評価結果のデータ型)に data_type と
+//       バッファを持たせてインタフェースを統一しないと,再帰的な組み合わせが発生します.
+
+class ExpressionOperatorNode : public ExpressionNode {
+ public:
+  ExpressionOperatorNode() : ExpressionNode() {}
+  virtual ~ExpressionOperatorNode() {}
+
+  ExpressionNodeType node_type() const {
+    return EXPRESSION_OPERATOR_NODE;
+  }
+
+  virtual OperatorType operator_type() const = 0;
+};
+
+template <typename T, typename U>
+class ExpressionEqualOperatorNode : public ExpressionOperatorNode {
+ public:
+  ExpressionEqualOperatorNode() : ExpressionOperatorNode() {}
+  virtual ~ExpressionEqualOperatorNode() {}
+
+  DataType data_type() const {
+    return BOOL_DATA;
+  }
+  OperatorType operator_type() const {
+    return EQUAL_OPERATOR;
+  }
+
+  bool evaluate(Error *error, const RecordSet &record_set) {
+    // TODO: Not supported yet.
+    GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
+    return false;
+  }
+
+  Int get(Int i) const {
+    return values_[i];
+  }
+
+ private:
+  unique_ptr<T> lhs_;
+  unique_ptr<U> rhs_;
+  std::vector<Bool> values_;
+};
+
+// -- Expression --
+
+unique_ptr<Expression> Expression::create(Error *error,
+                                          unique_ptr<ExpressionNode> &&root) {
   // TODO: Not supported yet.
   GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
   return nullptr;
 }
 
-ExpressionBuilder::~ExpressionBuilder() {}
+Expression::~Expression() {}
 
-bool ExpressionBuilder::push_datum(Error *error, const Datum &datum) {
-  // TODO: Not supported yet.
+DataType Expression::data_type() const {
+  return root_->data_type();
+}
+
+bool Expression::filter(Error *error, RecordSet *record_set) {
+  // TODO
   GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
   return false;
 }
 
+Expression::Expression(Table *table,
+                       unique_ptr<ExpressionNode> &&root)
+    : table_(table),
+      root_(std::move(root)) {}
+
+// -- 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;
+  }
+  return builder;
+}
+
+ExpressionBuilder::~ExpressionBuilder() {}
+
+bool ExpressionBuilder::push_datum(Error *error, const Datum &datum) {
+  try {
+    stack_.reserve(stack_.size() + 1);
+  } catch (...) {
+    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    return false;
+  }
+  // TODO: ExpressionDatumNode::create() should be provided to get error
+  //       information.
+  unique_ptr<ExpressionDatumNode> node;
+  switch (datum.type()) {
+    case BOOL_DATA: {
+      node.reset(new (nothrow) ExpressionBoolDatumNode(
+          static_cast<Bool>(datum)));
+      break;
+    }
+    case INT_DATA: {
+      node.reset(new (nothrow) ExpressionIntDatumNode(
+          static_cast<Int>(datum)));
+      break;
+    }
+    default: {
+      // TODO: Other types are not supported yet.
+      GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
+      return false;
+    }
+  }
+  if (!node) {
+    GRNXX_ERROR_SET(error, NO_MEMORY, "Not supported yet");
+    return false;
+  }
+  stack_.push_back(std::move(node));
+  return true;
+}
+
 bool ExpressionBuilder::push_column(Error *error, String name) {
-  // TODO: Not supported yet.
-  GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-  return false;
+  try {
+    stack_.reserve(stack_.size() + 1);
+  } catch (...) {
+    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    return false;
+  }
+  unique_ptr<ExpressionNode> node;
+  if (name == "_id") {
+    node.reset(new (nothrow) ExpressionRowIDNode());
+  } else if (name == "_score") {
+    node.reset(new (nothrow) ExpressionScoreNode());
+  } else {
+    Column *column = table_->find_column(error, name);
+    if (!column) {
+      return false;
+    }
+    // TODO: The following switch should be done in
+    //       ExpressionColumnNode::create().
+    switch (column->data_type()) {
+      case BOOL_DATA: {
+        node.reset(new (nothrow) ExpressionBoolColumnNode(
+            static_cast<BoolColumn *>(column)));
+        break;
+      }
+      case INT_DATA: {
+        node.reset(new (nothrow) ExpressionIntColumnNode(
+            static_cast<IntColumn *>(column)));
+        break;
+      }
+      default: {
+        // TODO: Not supported yet.
+        GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
+        return false;
+      }
+    }
+  }
+  if (!node) {
+    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    return false;
+  }
+  return true;
 }
 
 bool ExpressionBuilder::push_operator(Error *error,
                                       OperatorType operator_type) {
-  // TODO: Not supported yet.
-  GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-  return false;
+  unique_ptr<ExpressionNode> node;
+  switch (operator_type) {
+    case EQUAL_OPERATOR: {
+      if (stack_.size() != 2) {
+        // TODO: Define a better error code.
+        GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Not enough operands");
+        return false;
+      }
+      if (stack_[stack_.size() - 1]->data_type() !=
+          stack_[stack_.size() - 2]->data_type()) {
+        // TODO: Define a better error code.
+        GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Type conflict");
+        return false;
+      }
+      // TODO: Not supported yet.
+      GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
+      return false;
+    }
+    case NOT_EQUAL_OPERATOR: {
+      // TODO: Not supported yet.
+      GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
+      return false;
+    }
+    default: {
+      // TODO: Not supported yet.
+      GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
+      return false;
+    }
+  }
+  if (!node) {
+    // TODO: Error information should be set in the above switch.
+    GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed");
+    return false;
+  }
+  return true;
 }
 
 void ExpressionBuilder::clear() {
-  // TODO: Not supported yet.
+  stack_.clear();
 }
 
 unique_ptr<Expression> ExpressionBuilder::release(Error *error) {
-  // TODO: Not supported yet.
-  GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet");
-  return nullptr;
+  if (stack_.size() != 1) {
+    GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Incomplete expression");
+    return nullptr;
+  }
+  unique_ptr<ExpressionNode> root_node = std::move(stack_[0]);
+  stack_.clear();
+  return Expression::create(error, std::move(root_node));
 }
 
-ExpressionBuilder::ExpressionBuilder(Table *table) : table_(table) {}
+ExpressionBuilder::ExpressionBuilder(const Table *table) : table_(table) {}
 
 }  // namespace grnxx
-------------- next part --------------
HTML����������������������������...
Download 



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