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