From 5f91247d9590aa7ce8d754bff1ba3cb69bdc7cc6 Mon Sep 17 00:00:00 2001 From: "susumu.yata" Date: Thu, 27 Nov 2014 22:58:44 +0900 Subject: [PATCH] Remove the old implementation of Expression. --- lib/grnxx/expression-old.cpp | 4090 ---------------------------------- 1 file changed, 4090 deletions(-) delete mode 100644 lib/grnxx/expression-old.cpp diff --git a/lib/grnxx/expression-old.cpp b/lib/grnxx/expression-old.cpp deleted file mode 100644 index ed88cca..0000000 --- a/lib/grnxx/expression-old.cpp +++ /dev/null @@ -1,4090 +0,0 @@ -#include "grnxx/expression.hpp" - -#include "grnxx/impl/column.hpp" -#include "grnxx/table.hpp" - -#include // For debugging. - -namespace grnxx { -namespace expression { - -// TODO: Only CONSTANT_NODE and VARIABLE_NODE are required? -enum NodeType { - CONSTANT_NODE, - ROW_ID_NODE, - SCORE_NODE, - COLUMN_NODE, - OPERATOR_NODE -}; - -// -- Node -- - -class Node { - public: - Node() {} - virtual ~Node() {} - - // Return the node type. - virtual NodeType node_type() const = 0; - // Return the result data type. - virtual DataType data_type() const = 0; - // Return the reference table. - virtual const Table *ref_table() const { - return nullptr; - } - - // Extract true records. - // - // Evaluates the expression for "input_records" and appends records - // whose evaluation results are true into "*output_records". - // "*output_records" is truncated to the number of true records. - // - // On success, returns true. - // On failure, returns false and stores error information into "*error" if - // "error" != nullptr. - virtual bool filter(Error *error, - ArrayCRef input_records, - ArrayRef *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 records) = 0; -}; - -// -- TypedNode -- - -template -class TypedNode : public Node { - public: - using Value = T; - - TypedNode() : Node() {} - virtual ~TypedNode() {} - - DataType data_type() const { - return TypeTraits::data_type(); - } - - bool filter(Error *error, - ArrayCRef, - ArrayRef *) { - // Other than TypedNode don't support filter(). - GRNXX_ERROR_SET(error, INVALID_OPERATION, "Invalid operation"); - return false; - } - - bool adjust(Error *error, ArrayRef) { - // Other than TypedNode 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 records, - ArrayRef results) = 0; -}; - -template <> -class TypedNode : public Node { - public: - using Value = Bool; - - TypedNode() : Node() {} - virtual ~TypedNode() {} - - DataType data_type() const { - return TypeTraits::data_type(); - } - - // Derived classes must override this member function. - virtual bool filter(Error *error, - ArrayCRef input_records, - ArrayRef *output_records) = 0; - - bool adjust(Error *error, ArrayRef) { - // Other than TypedNode don't support adjust(). - GRNXX_ERROR_SET(error, INVALID_OPERATION, "Invalid operation"); - return false; - } - - virtual bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results) = 0; -}; - -//template <> -//bool TypedNode::filter(Error *error, -// ArrayCRef input_records, -// ArrayRef *output_records) { -// // TODO: This implementation should be overridden by derived classes. -// Array 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 : public Node { - public: - using Value = Float; - - TypedNode() : Node(), scores_() {} - virtual ~TypedNode() {} - - DataType data_type() const { - return TypeTraits::data_type(); - } - - bool filter(Error *error, - ArrayCRef, - ArrayRef *) { - // Other than TypedNode 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 records); - - virtual bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results) = 0; - - private: - Array scores_; -}; - -bool TypedNode::adjust(Error *error, ArrayRef 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 -class ConstantNode : public TypedNode { - public: - using Value = T; - - static unique_ptr create(Error *error, Value datum) { - unique_ptr node(new (nothrow) ConstantNode(datum)); - if (!node) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - } - return node; - } - - explicit ConstantNode(Value datum) - : TypedNode(), - datum_(datum) {} - - NodeType node_type() const { - return CONSTANT_NODE; - } - - bool evaluate(Error *, - ArrayCRef records, - ArrayRef results) { - for (Int i = 0; i < records.size(); ++i) { - results[i] = datum_; - } - return true; - } - - private: - T datum_; -}; - -template <> -class ConstantNode : public TypedNode { - public: - using Value = Bool; - - static unique_ptr create(Error *error, Value datum) { - unique_ptr node(new (nothrow) ConstantNode(datum)); - if (!node) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - } - return node; - } - - explicit ConstantNode(Value datum) - : TypedNode(), - datum_(datum) {} - - NodeType node_type() const { - return CONSTANT_NODE; - } - - bool filter(Error *error, - ArrayCRef input_records, - ArrayRef *output_records); - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); - - private: - Value datum_; -}; - -bool ConstantNode::filter(Error *, - ArrayCRef input_records, - ArrayRef *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::evaluate(Error *, - ArrayCRef records, - ArrayRef results) { - // TODO: Fill results per 64 bits. - for (Int i = 0; i < records.size(); ++i) { - results.set(i, datum_); - } - return true; -} - -template <> -class ConstantNode : public TypedNode { - public: - using Value = Float; - - static unique_ptr create(Error *error, Value datum) { - unique_ptr node(new (nothrow) ConstantNode(datum)); - if (!node) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - } - return node; - } - - explicit ConstantNode(Value datum) - : TypedNode(), - datum_(datum) {} - - NodeType node_type() const { - return CONSTANT_NODE; - } - - bool adjust(Error *, ArrayRef records) { - for (Int i = 0; i < records.size(); ++i) { - records.set_score(i, datum_); - } - return true; - } - bool evaluate(Error *, - ArrayCRef records, - ArrayRef results) { - for (Int i = 0; i < records.size(); ++i) { - results[i] = datum_; - } - return true; - } - - private: - Float datum_; -}; - -template <> -class ConstantNode : public TypedNode { - public: - using Value = Text; - - static unique_ptr create(Error *error, Value datum) { - unique_ptr 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.release()); - } - - explicit ConstantNode() - : TypedNode(), - datum_() {} - - NodeType node_type() const { - return CONSTANT_NODE; - } - - bool evaluate(Error *, - ArrayCRef records, - ArrayRef results) { - for (Int i = 0; i < records.size(); ++i) { - results[i] = datum_; - } - return true; - } - - private: - String datum_; -}; - -template <> -class ConstantNode> : public TypedNode> { - public: - using Value = Vector; - - static unique_ptr create(Error *error, Value value) { - unique_ptr 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.release()); - } - - explicit ConstantNode() - : TypedNode(), - value_() {} - - NodeType node_type() const { - return CONSTANT_NODE; - } - - bool evaluate(Error *, - ArrayCRef records, - ArrayRef results) { - Value value(value_.data(), value_.size()); - for (Int i = 0; i < records.size(); ++i) { - results[i] = value; - } - return true; - } - - private: - Array value_; -}; - -template <> -class ConstantNode> : public TypedNode> { - public: - using Value = Vector; - - static unique_ptr create(Error *error, Value value) { - unique_ptr 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.release()); - } - - explicit ConstantNode() - : TypedNode(), - value_() {} - - NodeType node_type() const { - return CONSTANT_NODE; - } - - bool evaluate(Error *, - ArrayCRef records, - ArrayRef results) { - Value value(value_.data(), value_.size()); - for (Int i = 0; i < records.size(); ++i) { - results[i] = value; - } - return true; - } - - private: - Array value_; -}; - -template <> -class ConstantNode> : public TypedNode> { - public: - using Value = Vector; - - static unique_ptr create(Error *error, Value value) { - unique_ptr 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.release()); - } - - explicit ConstantNode() - : TypedNode(), - value_() {} - - NodeType node_type() const { - return CONSTANT_NODE; - } - - bool evaluate(Error *, - ArrayCRef records, - ArrayRef results) { - Value value(value_.data(), value_.size()); - for (Int i = 0; i < records.size(); ++i) { - results[i] = value; - } - return true; - } - - private: - Array value_; -}; - -template <> -class ConstantNode> : public TypedNode> { - public: - using Value = Vector; - - static unique_ptr create(Error *error, Value value) { - unique_ptr 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.release()); - } - - explicit ConstantNode() - : TypedNode(), - value_(), - bodies_() {} - - NodeType node_type() const { - return CONSTANT_NODE; - } - - bool evaluate(Error *, - ArrayCRef records, - ArrayRef results) { - Value value(value_.data(), value_.size()); - for (Int i = 0; i < records.size(); ++i) { - results[i] = value; - } - return true; - } - - private: - Array value_; - Array bodies_; -}; - -// -- RowIDNode -- - -class RowIDNode : public TypedNode { - public: - using Value = Int; - - static unique_ptr create(Error *error) { - unique_ptr node(new (nothrow) RowIDNode); - if (!node) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - } - return node; - } - - RowIDNode() : TypedNode() {} - - NodeType node_type() const { - return ROW_ID_NODE; - } - - bool evaluate(Error *, - ArrayCRef records, - ArrayRef results) { - for (Int i = 0; i < records.size(); ++i) { - results[i] = records.get_row_id(i); - } - return true; - } -}; - -// -- ScoreNode -- - -class ScoreNode : public TypedNode { - public: - using Value = Float; - - static unique_ptr create(Error *error) { - unique_ptr node(new (nothrow) ScoreNode); - if (!node) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - } - return node; - } - - ScoreNode() : TypedNode() {} - - NodeType node_type() const { - return SCORE_NODE; - } - - bool adjust(Error *, ArrayRef) { - // Nothing to do. - return true; - } - bool evaluate(Error *, - ArrayCRef records, - ArrayRef results) { - for (Int i = 0; i < records.size(); ++i) { - results[i] = records.get_score(i); - } - return true; - } -}; - -// -- ColumnNode -- - -template -class ColumnNode : public TypedNode { - public: - using Value = T; - - static unique_ptr create(Error *error, const Column *column) { - unique_ptr node(new (nothrow) ColumnNode(column)); - if (!node) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - } - return node; - } - - explicit ColumnNode(const Column *column) - : TypedNode(), - column_(static_cast *>(column)) {} - - NodeType node_type() const { - return COLUMN_NODE; - } - const Table *ref_table() const { - return column_->ref_table(); - } - - bool evaluate(Error *, - ArrayCRef records, - ArrayRef results) { - column_->read(records, results); - return true; - } - - private: - const impl::Column *column_; -}; - -template <> -class ColumnNode : public TypedNode { - public: - using Value = Bool; - - static unique_ptr create(Error *error, const Column *column) { - unique_ptr node(new (nothrow) ColumnNode(column)); - if (!node) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - } - return node; - } - - explicit ColumnNode(const Column *column) - : TypedNode(), - column_(static_cast *>(column)) {} - - NodeType node_type() const { - return COLUMN_NODE; - } - - bool filter(Error *error, - ArrayCRef input_records, - ArrayRef *output_records); - bool evaluate(Error *, - ArrayCRef records, - ArrayRef results) { - column_->read(records, results); - return true; - } - - private: - const impl::Column *column_; -}; - -bool ColumnNode::filter(Error *, - ArrayCRef input_records, - ArrayRef *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 : public TypedNode { - public: - using Value = Float; - - static unique_ptr create(Error *error, const Column *column) { - unique_ptr node(new (nothrow) ColumnNode(column)); - if (!node) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - } - return node; - } - - explicit ColumnNode(const Column *column) - : TypedNode(), - column_(static_cast *>(column)) {} - - NodeType node_type() const { - return COLUMN_NODE; - } - - bool adjust(Error *, ArrayRef 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 records, - ArrayRef results) { - column_->read(records, results); - return true; - } - - private: - const impl::Column *column_; -}; - -// -- OperatorNode -- - -template -class OperatorNode : public TypedNode { - public: - using Value = T; - - OperatorNode() : TypedNode() {} - 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 -bool fill_node_arg_values(Error *error, ArrayCRef records, - TypedNode *arg, Array *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 -class UnaryNode : public OperatorNode { - public: - using Value = T; - using Arg = U; - - explicit UnaryNode(unique_ptr &&arg) - : OperatorNode(), - arg_(static_cast *>(arg.release())), - arg_values_() {} - virtual ~UnaryNode() {} - - protected: - unique_ptr> arg_; - Array arg_values_; - - bool fill_arg_values(Error *error, ArrayCRef records) { - return fill_node_arg_values(error, records, arg_.get(), &arg_values_); - } -}; - -// ---- LogicalNotNode ---- - -class LogicalNotNode : public UnaryNode { - public: - using Value = Bool; - using Arg = Bool; - - static unique_ptr create(Error *error, unique_ptr &&arg) { - unique_ptr node(new (nothrow) LogicalNotNode(std::move(arg))); - if (!node) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - } - return node; - } - - explicit LogicalNotNode(unique_ptr &&arg) - : UnaryNode(std::move(arg)), - temp_records_() {} - - bool filter(Error *error, - ArrayCRef input_records, - ArrayRef *output_records); - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); - - private: - Array temp_records_; -}; - -bool LogicalNotNode::filter(Error *error, - ArrayCRef input_records, - ArrayRef *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 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 records, - ArrayRef 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 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 class BitwiseNotNode; - -template <> -class BitwiseNotNode : public UnaryNode { - public: - using Value = Bool; - using Arg = Bool; - - static unique_ptr create(Error *error, unique_ptr &&arg) { - unique_ptr node(new (nothrow) BitwiseNotNode(std::move(arg))); - if (!node) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - } - return node; - } - - explicit BitwiseNotNode(unique_ptr &&arg) - : UnaryNode(std::move(arg)) {} - - bool filter(Error *error, - ArrayCRef input_records, - ArrayRef *output_records); - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool BitwiseNotNode::filter(Error *error, - ArrayCRef input_records, - ArrayRef *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::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 : public UnaryNode { - public: - using Value = Int; - using Arg = Int; - - static unique_ptr create(Error *error, unique_ptr &&arg) { - unique_ptr node( - new (nothrow) BitwiseNotNode(std::move(arg))); - if (!node) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - } - return node; - } - - explicit BitwiseNotNode(unique_ptr &&arg) - : UnaryNode(std::move(arg)) {} - - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool BitwiseNotNode::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 class NegativeNode; - -template <> -class NegativeNode : public UnaryNode { - public: - using Value = Int; - using Arg = Int; - - static unique_ptr create(Error *error, unique_ptr &&arg) { - unique_ptr node(new (nothrow) NegativeNode(std::move(arg))); - if (!node) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - } - return node; - } - - explicit NegativeNode(unique_ptr &&arg) - : UnaryNode(std::move(arg)) {} - - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool NegativeNode::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 : public UnaryNode { - public: - using Value = Float; - using Arg = Float; - - static unique_ptr create(Error *error, unique_ptr &&arg) { - unique_ptr node(new (nothrow) NegativeNode(std::move(arg))); - if (!node) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - } - return node; - } - - explicit NegativeNode(unique_ptr &&arg) - : UnaryNode(std::move(arg)) {} - - bool adjust(Error *error, ArrayRef records); - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool NegativeNode::adjust(Error *error, ArrayRef 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::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 { - public: - using Value = Int; - using Arg = Float; - - static unique_ptr create(Error *error, unique_ptr &&arg) { - unique_ptr node(new (nothrow) ToIntNode(std::move(arg))); - if (!node) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - } - return node; - } - - explicit ToIntNode(unique_ptr &&arg) - : UnaryNode(std::move(arg)) {} - - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool ToIntNode::evaluate(Error *error, - ArrayCRef records, - ArrayRef results) { - if (!fill_arg_values(error, records)) { - return false; - } - for (Int i = 0; i < records.size(); ++i) { - results.set(i, static_cast(arg_values_[i])); - } - return true; -} - -// ---- ToFloatNode ---- - -class ToFloatNode : public UnaryNode { - public: - using Value = Float; - using Arg = Int; - - static unique_ptr create(Error *error, unique_ptr &&arg) { - unique_ptr node(new (nothrow) ToFloatNode(std::move(arg))); - if (!node) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - } - return node; - } - - explicit ToFloatNode(unique_ptr &&arg) - : UnaryNode(std::move(arg)) {} - - bool adjust(Error *error, ArrayRef records); - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool ToFloatNode::adjust(Error *error, ArrayRef records) { - if (!fill_arg_values(error, records)) { - return false; - } - for (Int i = 0; i < records.size(); ++i) { - records.set_score(i, static_cast(arg_values_[i])); - } - return true; -} - -bool ToFloatNode::evaluate(Error *error, - ArrayCRef records, - ArrayRef results) { - if (!fill_arg_values(error, records)) { - return false; - } - for (Int i = 0; i < records.size(); ++i) { - results.set(i, static_cast(arg_values_[i])); - } - return true; -} - -// --- BinaryNode --- - -template -class BinaryNode : public OperatorNode { - public: - using Value = T; - using Arg1 = U; - using Arg2 = V; - - BinaryNode(unique_ptr &&arg1, unique_ptr &&arg2) - : OperatorNode(), - arg1_(static_cast *>(arg1.release())), - arg2_(static_cast *>(arg2.release())), - arg1_values_(), - arg2_values_() {} - virtual ~BinaryNode() {} - - protected: - unique_ptr> arg1_; - unique_ptr> arg2_; - Array arg1_values_; - Array arg2_values_; - - bool fill_arg1_values(Error *error, ArrayCRef records) { - return fill_node_arg_values(error, records, arg1_.get(), &arg1_values_); - } - bool fill_arg2_values(Error *error, ArrayCRef records) { - return fill_node_arg_values(error, records, arg2_.get(), &arg2_values_); - } -}; - -// ---- LogicalAndNode ---- - -class LogicalAndNode : public BinaryNode { - public: - using Value = Bool; - using Arg1 = Bool; - using Arg2 = Bool; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)), - temp_records_() {} - - bool filter(Error *error, - ArrayCRef input_records, - ArrayRef *output_records) { - return arg1_->filter(error, input_records, output_records) && - arg2_->filter(error, *output_records, output_records); - } - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); - - private: - Array temp_records_; -}; - -bool LogicalAndNode::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 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 { - public: - using Value = Bool; - using Arg1 = Bool; - using Arg2 = Bool; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)), - temp_records_() {} - - bool filter(Error *error, - ArrayCRef input_records, - ArrayRef *output_records); - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); - - private: - Array temp_records_; -}; - -bool LogicalOrNode::filter(Error *error, - ArrayCRef input_records, - ArrayRef *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 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 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 records, - ArrayRef 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 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 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 -class ComparisonNode - : public BinaryNode { - public: - using Comparer = T; - using Value = Bool; - using Arg1 = typename T::Arg; - using Arg2 = typename T::Arg; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)), - comparer_() {} - - bool filter(Error *error, - ArrayCRef input_records, - ArrayRef *output_records); - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); - - protected: - Comparer comparer_; -}; - -template -bool ComparisonNode::filter(Error *error, - ArrayCRef input_records, - ArrayRef *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 -bool ComparisonNode::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 - struct Comparer { - using Arg = T; - Bool operator()(Arg arg1, Arg arg2) const { - return arg1 == arg2; - } - }; -}; - -template -using EqualNode = ComparisonNode>; - -// ----- NotEqualNode ----- - -// TODO: NotEqualNode for Bool should be specialized. - -struct NotEqual { - template - struct Comparer { - using Arg = T; - Bool operator()(Arg arg1, Arg arg2) const { - return arg1 != arg2; - } - }; -}; - -template -using NotEqualNode = ComparisonNode>; - -// ----- LessNode ----- - -struct Less { - template - struct Comparer { - using Arg = T; - Bool operator()(Arg arg1, Arg arg2) const { - return arg1 < arg2; - } - }; -}; - -template -using LessNode = ComparisonNode>; - -// ----- LessEqualNode ----- - -struct LessEqual { - template - struct Comparer { - using Arg = T; - Bool operator()(Arg arg1, Arg arg2) const { - return arg1 <= arg2; - } - }; -}; - -template -using LessEqualNode = ComparisonNode>; - -// ----- GreaterNode ----- - -struct Greater { - template - struct Comparer { - using Arg = T; - Bool operator()(Arg arg1, Arg arg2) const { - return arg1 > arg2; - } - }; -}; - -template -using GreaterNode = ComparisonNode>; - -// ----- GreaterEqualNode ----- - -struct GreaterEqual { - template - struct Comparer { - using Arg = T; - Bool operator()(Arg arg1, Arg arg2) const { - return arg1 >= arg2; - } - }; -}; - -template -using GreaterEqualNode = ComparisonNode>; - -// ---- BitwiseAndNode ---- - -// TODO: BitwiseAnd/Or/XorNode should be implemented on the same base class? - -template class BitwiseAndNode; - -template <> -class BitwiseAndNode : public BinaryNode { - public: - using Value = Bool; - using Arg1 = Bool; - using Arg2 = Bool; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)) {} - - bool filter(Error *error, - ArrayCRef input_records, - ArrayRef *output_records); - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool BitwiseAndNode::filter(Error *error, - ArrayCRef input_records, - ArrayRef *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::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 : public BinaryNode { - public: - using Value = Int; - using Arg1 = Int; - using Arg2 = Int; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)) {} - - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool BitwiseAndNode::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 class BitwiseOrNode; - -template <> -class BitwiseOrNode : public BinaryNode { - public: - using Value = Bool; - using Arg1 = Bool; - using Arg2 = Bool; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)) {} - - bool filter(Error *error, - ArrayCRef input_records, - ArrayRef *output_records); - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool BitwiseOrNode::filter(Error *error, - ArrayCRef input_records, - ArrayRef *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::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 : public BinaryNode { - public: - using Value = Int; - using Arg1 = Int; - using Arg2 = Int; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)) {} - - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool BitwiseOrNode::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 class BitwiseXorNode; - -template <> -class BitwiseXorNode : public BinaryNode { - public: - using Value = Bool; - using Arg1 = Bool; - using Arg2 = Bool; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)) {} - - bool filter(Error *error, - ArrayCRef input_records, - ArrayRef *output_records); - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool BitwiseXorNode::filter(Error *error, - ArrayCRef input_records, - ArrayRef *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::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 : public BinaryNode { - public: - using Value = Int; - using Arg1 = Int; - using Arg2 = Int; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)) {} - - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool BitwiseXorNode::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 class PlusNode; - -template <> -class PlusNode : public BinaryNode { - public: - using Value = Int; - using Arg1 = Int; - using Arg2 = Int; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)) {} - - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool PlusNode::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 : public BinaryNode { - public: - using Value = Float; - using Arg1 = Float; - using Arg2 = Float; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)) {} - - bool adjust(Error *error, ArrayRef records); - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool PlusNode::adjust(Error *error, ArrayRef 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::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 class MinusNode; - -template <> -class MinusNode : public BinaryNode { - public: - using Value = Int; - using Arg1 = Int; - using Arg2 = Int; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)) {} - - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool MinusNode::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 : public BinaryNode { - public: - using Value = Float; - using Arg1 = Float; - using Arg2 = Float; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)) {} - - bool adjust(Error *error, ArrayRef records); - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool MinusNode::adjust(Error *error, ArrayRef 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::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 class MultiplicationNode; - -template <> -class MultiplicationNode : public BinaryNode { - public: - using Value = Int; - using Arg1 = Int; - using Arg2 = Int; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)) {} - - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool MultiplicationNode::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 : public BinaryNode { - public: - using Value = Float; - using Arg1 = Float; - using Arg2 = Float; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)) {} - - bool adjust(Error *error, ArrayRef records); - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool MultiplicationNode::adjust(Error *error, - ArrayRef 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::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 class DivisionNode; - -template <> -class DivisionNode : public BinaryNode { - public: - using Value = Int; - using Arg1 = Int; - using Arg2 = Int; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)) {} - - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool DivisionNode::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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::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 : public BinaryNode { - public: - using Value = Float; - using Arg1 = Float; - using Arg2 = Float; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)) {} - - bool adjust(Error *error, ArrayRef records); - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool DivisionNode::adjust(Error *error, - ArrayRef 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::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 class ModulusNode; - -template <> -class ModulusNode : public BinaryNode { - public: - using Value = Int; - using Arg1 = Int; - using Arg2 = Int; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)) {} - - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool ModulusNode::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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::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 -class SubscriptNode : public BinaryNode, Int> { - public: - using Value = T; - using Arg1 = Vector; - using Arg2 = Int; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)) {} - - const Table *ref_table() const { - return this->arg1_->ref_table(); - } - - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -template -bool SubscriptNode::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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::default_value()); - } - } - return true; -} - -template <> -class SubscriptNode : public BinaryNode, Int> { - public: - using Value = Bool; - using Arg1 = Vector; - using Arg2 = Int; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)) {} - - bool filter(Error *error, - ArrayCRef input_records, - ArrayRef *output_records); - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool SubscriptNode::filter(Error *error, - ArrayCRef input_records, - ArrayRef *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::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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::default_value()); - } - } - return true; -} - -template <> -class SubscriptNode : public BinaryNode, Int> { - public: - using Value = Float; - using Arg1 = Vector; - using Arg2 = Int; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)) {} - - bool adjust(Error *error, ArrayRef records); - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); -}; - -bool SubscriptNode::adjust(Error *error, - ArrayRef 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::default_value()); - } - } - return true; -} - -bool SubscriptNode::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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::default_value()); - } - } - return true; -} - -// ---- ReferenceNode ---- - -template -class ReferenceNode : public BinaryNode { - public: - using Value = T; - using Arg1 = Int; - using Arg2 = T; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2, - const ExpressionOptions &) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)), - temp_records_() {} - - const Table *ref_table() const { - return this->arg2_->ref_table(); - } - - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); - - private: - Array temp_records_; -}; - -template -bool ReferenceNode::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 : public BinaryNode { - public: - using Value = Bool; - using Arg1 = Int; - using Arg2 = Bool; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2, - const ExpressionOptions &) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)), - temp_records_() {} - - bool filter(Error *error, - ArrayCRef input_records, - ArrayRef *output_records); - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); - - private: - Array temp_records_; -}; - -bool ReferenceNode::filter(Error *error, - ArrayCRef input_records, - ArrayRef *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::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 : public BinaryNode { - public: - using Value = Float; - using Arg1 = Int; - using Arg2 = Float; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2, - const ExpressionOptions &) { - unique_ptr 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 &&arg1, unique_ptr &&arg2) - : BinaryNode(std::move(arg1), std::move(arg2)), - temp_records_() {} - - bool adjust(Error *error, ArrayRef records); - bool evaluate(Error *error, - ArrayCRef records, - ArrayRef results); - - private: - Array temp_records_; -}; - -bool ReferenceNode::adjust(Error *error, - ArrayRef 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::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 -class ReferenceVectorNode - : public BinaryNode, Vector, T> { - public: - using Value = Vector; - using Arg1 = Vector; - using Arg2 = T; - - static unique_ptr create(Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2, - const ExpressionOptions &options) { - unique_ptr 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 &&arg1, - unique_ptr &&arg2, - Int block_size) - : BinaryNode(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 records, - ArrayRef results); - - private: - Array temp_records_; - Array> result_pools_; - Int block_size_; -}; - -template -bool ReferenceVectorNode::evaluate(Error *error, - ArrayCRef records, - ArrayRef 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 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 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); - - // 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 release(Error *error); - - private: - const Table *table_; - Array> stack_; - - Builder(const Table *table) : table_(table), stack_() {} - - // Create a node associated with a constant. - unique_ptr create_constant_node(Error *error, const Datum &datum); - // Create a node associated with a column. - unique_ptr 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 create_unary_node( - Error *error, - OperatorType operator_type, - unique_ptr &&arg); - // Create a node associated with a binary operator. - unique_ptr create_binary_node( - Error *error, - OperatorType operator_type, - unique_ptr &&arg1, - unique_ptr &&arg2); - - // Create a equality test node. - template - unique_ptr create_equality_test_node( - Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2); - // Create a comparison node. - template - unique_ptr create_comparison_node( - Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2); - // Create a bitwise node. - template - unique_ptr create_bitwise_node( - Error *error, - OperatorType operator_type, - unique_ptr &&arg1, - unique_ptr &&arg2); - // Create an arithmetic node. - template - unique_ptr create_arithmetic_node( - Error *error, - OperatorType operator_type, - unique_ptr &&arg1, - unique_ptr &&arg2); - // Create a subscript node. - unique_ptr create_subscript_node( - Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2); - - // Create a reference node. - unique_ptr create_reference_node( - Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2, - const ExpressionOptions &options); -}; - -unique_ptr Builder::create(Error *error, const Table *table) { - unique_ptr 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 = 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(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(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 = 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) { - 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 arg1 = std::move(stack_[stack_.size() - 2]); - unique_ptr arg2 = std::move(stack_[stack_.size() - 1]); - stack_.resize(nullptr, stack_.size() - 2); - unique_ptr 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 Builder::release(Error *error) { - if (stack_.size() != 1) { - GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Incomplete expression"); - return nullptr; - } - unique_ptr root = std::move(stack_[0]); - stack_.clear(); - return root; -} - -unique_ptr Builder::create_constant_node( - Error *error, - const Datum &datum) { - switch (datum.type()) { - case BOOL_DATA: { - return ConstantNode::create(error, datum.force_bool()); - } - case INT_DATA: { - return ConstantNode::create(error, datum.force_int()); - } - case FLOAT_DATA: { - return ConstantNode::create(error, datum.force_float()); - } - case GEO_POINT_DATA: { - return ConstantNode::create(error, datum.force_geo_point()); - } - case TEXT_DATA: { - return ConstantNode::create(error, datum.force_text()); - } - case BOOL_VECTOR_DATA: { - return ConstantNode>::create(error, - datum.force_bool_vector()); - } - case INT_VECTOR_DATA: { - return ConstantNode>::create(error, - datum.force_int_vector()); - } - case FLOAT_VECTOR_DATA: { - return ConstantNode>::create(error, - datum.force_float_vector()); - } - case TEXT_VECTOR_DATA: { - return ConstantNode>::create(error, - datum.force_text_vector()); - } - case GEO_POINT_VECTOR_DATA: { - return ConstantNode>::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 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::create(error, column); - } - case INT_DATA: { - return ColumnNode::create(error, column); - } - case FLOAT_DATA: { - return ColumnNode::create(error, column); - } - case GEO_POINT_DATA: { - return ColumnNode::create(error, column); - } - case TEXT_DATA: { - return ColumnNode::create(error, column); - } - case BOOL_VECTOR_DATA: { - return ColumnNode>::create(error, column); - } - case INT_VECTOR_DATA: { - return ColumnNode>::create(error, column); - } - case FLOAT_VECTOR_DATA: { - return ColumnNode>::create(error, column); - } - case GEO_POINT_VECTOR_DATA: { - return ColumnNode>::create(error, column); - } - case TEXT_VECTOR_DATA: { - return ColumnNode>::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 arg = std::move(stack_[stack_.size() - 1]); - stack_.resize(nullptr, stack_.size() - 1); - unique_ptr 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 arg1 = std::move(stack_[stack_.size() - 2]); - unique_ptr arg2 = std::move(stack_[stack_.size() - 1]); - stack_.resize(nullptr, stack_.size() - 2); - unique_ptr 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 Builder::create_unary_node( - Error *error, - OperatorType operator_type, - unique_ptr &&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::create(error, std::move(arg)); - } - case INT_DATA: { - return BitwiseNotNode::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::create(error, std::move(arg)); - } - case FLOAT_DATA: { - return NegativeNode::create(error, std::move(arg)); - } - default: { - GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type"); - return nullptr; - } - } - } - case TO_INT_OPERATOR: { - if (arg->data_type() != FLOAT_DATA) { - GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type"); - return nullptr; - } - return ToIntNode::create(error, std::move(arg)); - } - case TO_FLOAT_OPERATOR: { - if (arg->data_type() != INT_DATA) { - GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type"); - return nullptr; - } - return ToFloatNode::create(error, std::move(arg)); - } - default: { - // TODO: Not supported yet. - GRNXX_ERROR_SET(error, NOT_SUPPORTED_YET, "Not supported yet"); - return nullptr; - } - } -} - -unique_ptr Builder::create_binary_node( - Error *error, - OperatorType operator_type, - unique_ptr &&arg1, - unique_ptr &&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( - error, std::move(arg1), std::move(arg2)); - } - case NOT_EQUAL_OPERATOR: { - return create_equality_test_node( - error, std::move(arg1), std::move(arg2)); - } - case LESS_OPERATOR: { - return create_comparison_node( - error, std::move(arg1), std::move(arg2)); - } - case LESS_EQUAL_OPERATOR: { - return create_comparison_node( - error, std::move(arg1), std::move(arg2)); - } - case GREATER_OPERATOR: { - return create_comparison_node( - error, std::move(arg1), std::move(arg2)); - } - case GREATER_EQUAL_OPERATOR: { - return create_comparison_node( - 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( - error, operator_type, std::move(arg1), std::move(arg2)); - } - case INT_DATA: { - return create_bitwise_node( - 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( - error, operator_type, std::move(arg1), std::move(arg2)); - } - case FLOAT_DATA: { - return create_arithmetic_node( - 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::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 -unique_ptr Builder::create_equality_test_node( - Error *error, - unique_ptr &&arg1, - unique_ptr &&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>::create( - error, std::move(arg1), std::move(arg2)); - } - case INT_DATA: { - return ComparisonNode>::create( - error, std::move(arg1), std::move(arg2)); - } - case FLOAT_DATA: { - return ComparisonNode>::create( - error, std::move(arg1), std::move(arg2)); - } - case GEO_POINT_DATA: { - return ComparisonNode>::create( - error, std::move(arg1), std::move(arg2)); - } - case TEXT_DATA: { - return ComparisonNode>::create( - error, std::move(arg1), std::move(arg2)); - } - case BOOL_VECTOR_DATA: { - typedef typename T:: template Comparer> Functor; - return ComparisonNode::create( - error, std::move(arg1), std::move(arg2)); - } - case INT_VECTOR_DATA: { - typedef typename T:: template Comparer> Functor; - return ComparisonNode::create( - error, std::move(arg1), std::move(arg2)); - } - case FLOAT_VECTOR_DATA: { - typedef typename T:: template Comparer> Functor; - return ComparisonNode::create( - error, std::move(arg1), std::move(arg2)); - } - case GEO_POINT_VECTOR_DATA: { - typedef typename T:: template Comparer> Functor; - return ComparisonNode::create( - error, std::move(arg1), std::move(arg2)); - } - case TEXT_VECTOR_DATA: { - typedef typename T:: template Comparer> Functor; - return ComparisonNode::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 -unique_ptr Builder::create_comparison_node( - Error *error, - unique_ptr &&arg1, - unique_ptr &&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>::create( - error, std::move(arg1), std::move(arg2)); - } - case FLOAT_DATA: { - return ComparisonNode>::create( - error, std::move(arg1), std::move(arg2)); - } - case TEXT_DATA: { - return ComparisonNode>::create( - error, std::move(arg1), std::move(arg2)); - } - default: { - GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type"); - return nullptr; - } - } -} - -template -unique_ptr Builder::create_bitwise_node( - Error *error, - OperatorType operator_type, - unique_ptr &&arg1, - unique_ptr &&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::create( - error, std::move(arg1), std::move(arg2)); - } - case BITWISE_OR_OPERATOR: { - return BitwiseOrNode::create( - error, std::move(arg1), std::move(arg2)); - } - case BITWISE_XOR_OPERATOR: { - return BitwiseXorNode::create( - error, std::move(arg1), std::move(arg2)); - } - default: { - GRNXX_ERROR_SET(error, INVALID_ARGUMENT, "Invalid operator"); - return nullptr; - } - } -} - -template -unique_ptr Builder::create_arithmetic_node( - Error *error, - OperatorType operator_type, - unique_ptr &&arg1, - unique_ptr &&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::create( - error, std::move(arg1), std::move(arg2)); - } - case MINUS_OPERATOR: { - return MinusNode::create( - error, std::move(arg1), std::move(arg2)); - } - case MULTIPLICATION_OPERATOR: { - return MultiplicationNode::create( - error, std::move(arg1), std::move(arg2)); - } - case DIVISION_OPERATOR: { - return DivisionNode::create( - error, std::move(arg1), std::move(arg2)); - } - default: { - GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type"); - return nullptr; - } - } -} - -unique_ptr Builder::create_subscript_node( - Error *error, - unique_ptr &&arg1, - unique_ptr &&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::create( - error, std::move(arg1), std::move(arg2)); - } - case INT_VECTOR_DATA: { - return SubscriptNode::create( - error, std::move(arg1), std::move(arg2)); - } - case FLOAT_VECTOR_DATA: { - return SubscriptNode::create( - error, std::move(arg1), std::move(arg2)); - } - case GEO_POINT_VECTOR_DATA: { - return SubscriptNode::create( - error, std::move(arg1), std::move(arg2)); - } - case TEXT_VECTOR_DATA: { - return SubscriptNode::create( - error, std::move(arg1), std::move(arg2)); - } - default: { - GRNXX_ERROR_SET(error, INVALID_OPERAND, "Invalid data type"); - return nullptr; - } - } -} - -unique_ptr Builder::create_reference_node( - Error *error, - unique_ptr &&arg1, - unique_ptr &&arg2, - const ExpressionOptions &options) { - switch (arg1->data_type()) { - case INT_DATA: { - switch (arg2->data_type()) { - case BOOL_DATA: { - return ReferenceNode::create( - error, std::move(arg1), std::move(arg2), options); - } - case INT_DATA: { - return ReferenceNode::create( - error, std::move(arg1), std::move(arg2), options); - } - case FLOAT_DATA: { - return ReferenceNode::create( - error, std::move(arg1), std::move(arg2), options); - } - case GEO_POINT_DATA: { - return ReferenceNode::create( - error, std::move(arg1), std::move(arg2), options); - } - case TEXT_DATA: { - return ReferenceNode::create( - error, std::move(arg1), std::move(arg2), options); - } - case BOOL_VECTOR_DATA: { - return ReferenceNode>::create( - error, std::move(arg1), std::move(arg2), options); - } - case INT_VECTOR_DATA: { - return ReferenceNode>::create( - error, std::move(arg1), std::move(arg2), options); - } - case FLOAT_VECTOR_DATA: { - return ReferenceNode>::create( - error, std::move(arg1), std::move(arg2), options); - } - case GEO_POINT_VECTOR_DATA: { - return ReferenceNode>::create( - error, std::move(arg1), std::move(arg2), options); - } - case TEXT_VECTOR_DATA: { - return ReferenceNode>::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::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::create( - error, std::move(arg1), std::move(arg2), options); - } - case FLOAT_DATA: { - return ReferenceVectorNode::create( - error, std::move(arg1), std::move(arg2), options); - } - case GEO_POINT_DATA: { - return ReferenceVectorNode::create( - error, std::move(arg1), std::move(arg2), options); - } - case TEXT_DATA: { - return ReferenceVectorNode::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 *records, Int offset) { -// ArrayRef 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 *records, - Int input_offset, - Int output_offset, - Int output_limit) { - ArrayCRef input = records->ref(input_offset); - ArrayRef 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 next_input = input.ref(0, next_size); - ArrayRef 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 input_records, - ArrayRef *output_records) { - ArrayCRef input = input_records; - ArrayRef output = *output_records; - Int count = 0; - while (input.size() > block_size_) { - ArrayCRef input_block = input.ref(0, block_size_); - ArrayRef 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 *records, Int offset) { - return adjust(error, records->ref(offset)); -} - -bool Expression::adjust(Error *error, ArrayRef 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 -bool Expression::evaluate(Error *error, - ArrayCRef records, - Array *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 records, \ - Array *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); -GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Vector); -GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Vector); -GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Vector); -GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Vector); -#undef GRNXX_INSTANTIATE_EXPRESSION_EVALUATE - -template -bool Expression::evaluate(Error *error, - ArrayCRef records, - ArrayRef results) { - if (TypeTraits::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 *>(root_.get()); - while (records.size() > block_size_) { - ArrayCRef input = records.ref(0, block_size_); - ArrayRef 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 records, \ - ArrayRef 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); -GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Vector); -GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Vector); -GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Vector); -GRNXX_INSTANTIATE_EXPRESSION_EVALUATE(Vector); -#undef GRNXX_INSTANTIATE_EXPRESSION_EVALUATE - -unique_ptr Expression::create(Error *error, - const Table *table, - unique_ptr &&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( - 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 &&root, - Int block_size) - : table_(table), - root_(std::move(root)), - block_size_(block_size) {} - -// -- ExpressionBuilder -- - -unique_ptr ExpressionBuilder::create(Error *error, - const Table *table) { - unique_ptr builder( - new (nothrow) ExpressionBuilder(table)); - if (!builder) { - GRNXX_ERROR_SET(error, NO_MEMORY, "Memory allocation failed"); - return nullptr; - } - unique_ptr 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 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 = 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 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 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