Repository: incubator-quickstep Updated Branches: refs/heads/refactor-type 4bf0857c5 -> 8c3996c68
Updates to implicit casts Project: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/commit/8c3996c6 Tree: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/tree/8c3996c6 Diff: http://git-wip-us.apache.org/repos/asf/incubator-quickstep/diff/8c3996c6 Branch: refs/heads/refactor-type Commit: 8c3996c686ac22d19e01d5e4e1f7bfb415f8321c Parents: 4bf0857 Author: Jianqiao Zhu <[email protected]> Authored: Wed Oct 11 03:38:40 2017 -0500 Committer: Jianqiao Zhu <[email protected]> Committed: Wed Oct 11 03:38:40 2017 -0500 ---------------------------------------------------------------------- query_optimizer/expressions/Cast.cpp | 16 ++ query_optimizer/expressions/Cast.hpp | 19 +- query_optimizer/expressions/Expression.hpp | 5 + query_optimizer/expressions/ScalarLiteral.hpp | 8 +- query_optimizer/resolver/Resolver.cpp | 27 ++- types/TextType.cpp | 9 + types/TextType.hpp | 2 + types/TypeUtil.hpp | 27 +++ types/operations/OperationFactory.cpp | 218 ++++++++++++++------- types/operations/OperationFactory.hpp | 56 ++++-- 10 files changed, 285 insertions(+), 102 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/query_optimizer/expressions/Cast.cpp ---------------------------------------------------------------------- diff --git a/query_optimizer/expressions/Cast.cpp b/query_optimizer/expressions/Cast.cpp index 2315f92..7df4159 100644 --- a/query_optimizer/expressions/Cast.cpp +++ b/query_optimizer/expressions/Cast.cpp @@ -73,6 +73,22 @@ ExpressionPtr Cast::copyWithNewChildren( std::make_shared<const std::vector<TypedValue>>(std::move(meta_type_value))); } +TypedValue Cast::getConstantValue() const { + DCHECK(isConstant()); + const Type &source_type = operand_->getValueType(); + const UnaryOperationPtr cast_operation = + OperationFactory::GetCastOperation(source_type.getTypeID()); + + std::vector<TypedValue> meta_type_value = + { GenericValue::CreateWithLiteral( + MetaType::InstanceNonNullable(), &target_type_).toTypedValue() }; + DCHECK(cast_operation->canApplyTo(source_type, meta_type_value)); + + std::unique_ptr<UncheckedUnaryOperator> cast_op( + cast_operation->makeUncheckedUnaryOperator(source_type, meta_type_value)); + return cast_op->applyToTypedValue(operand_->getConstantValue()); +} + std::size_t Cast::computeHash() const { return CombineHashes( CombineHashes(static_cast<std::size_t>(ExpressionType::kCast), http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/query_optimizer/expressions/Cast.hpp ---------------------------------------------------------------------- diff --git a/query_optimizer/expressions/Cast.hpp b/query_optimizer/expressions/Cast.hpp index 11be775..5da0e8c 100644 --- a/query_optimizer/expressions/Cast.hpp +++ b/query_optimizer/expressions/Cast.hpp @@ -55,13 +55,23 @@ typedef std::shared_ptr<const Cast> CastPtr; */ class Cast : public Scalar { public: - ExpressionType getExpressionType() const override { return ExpressionType::kCast; } + ExpressionType getExpressionType() const override { + return ExpressionType::kCast; + } + + std::string getName() const override { + return "Cast"; + } - std::string getName() const override { return "Cast"; } + const Type& getValueType() const override { + return target_type_; + } - const Type& getValueType() const override { return target_type_; } + bool isConstant() const override { + return operand_->isConstant(); + } - bool isConstant() const override { return operand_->isConstant(); } + TypedValue getConstantValue() const override; /** * @return The expression to be coerced. @@ -78,6 +88,7 @@ class Cast : public Scalar { ::quickstep::Scalar* concretize( const std::unordered_map<ExprId, const CatalogAttribute*> &substitution_map) const override; + bool equals(const ScalarPtr &other) const override; /** http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/query_optimizer/expressions/Expression.hpp ---------------------------------------------------------------------- diff --git a/query_optimizer/expressions/Expression.hpp b/query_optimizer/expressions/Expression.hpp index 7127047..fc6fc53 100644 --- a/query_optimizer/expressions/Expression.hpp +++ b/query_optimizer/expressions/Expression.hpp @@ -80,6 +80,11 @@ class Expression : public OptimizerTree<Expression> { */ virtual bool isConstant() const = 0; + virtual TypedValue getConstantValue() const { + LOG(FATAL) << "Not implemented"; + } + + protected: Expression() {} http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/query_optimizer/expressions/ScalarLiteral.hpp ---------------------------------------------------------------------- diff --git a/query_optimizer/expressions/ScalarLiteral.hpp b/query_optimizer/expressions/ScalarLiteral.hpp index f6a14f4..fc9f69a 100644 --- a/query_optimizer/expressions/ScalarLiteral.hpp +++ b/query_optimizer/expressions/ScalarLiteral.hpp @@ -65,7 +65,13 @@ class ScalarLiteral : public Scalar { const Type& getValueType() const override; - bool isConstant() const override { return true; } + bool isConstant() const override { + return true; + } + + TypedValue getConstantValue() const override { + return value_.toTypedValue(); + } /** * @return The literal value. http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/query_optimizer/resolver/Resolver.cpp ---------------------------------------------------------------------- diff --git a/query_optimizer/resolver/Resolver.cpp b/query_optimizer/resolver/Resolver.cpp index b3e8c2c..f06679d 100644 --- a/query_optimizer/resolver/Resolver.cpp +++ b/query_optimizer/resolver/Resolver.cpp @@ -2928,24 +2928,37 @@ E::ScalarPtr Resolver::resolveScalarFunction( } } - // TODO: add cast if neccessary. - (void)coerced_argument_types; + // Add cast if neccessary. + std::vector<E::ScalarPtr> coerced_arguments; + for (std::size_t i = 0; i < op_signature->getNonStaticArity(); ++i) { + const auto &argument = resolved_arguments[i]; + const Type &target_type = *(*coerced_argument_types)[i]; + if (argument->getValueType().equals(target_type)) { + coerced_arguments.emplace_back(argument); + } else { + coerced_arguments.emplace_back(E::Cast::Create(argument, target_type)); + } + } const OperationPtr operation = OperationFactory::GetOperation(op_signature); switch (operation->getOperationSuperTypeID()) { - case Operation::kUnaryOperation: + case Operation::kUnaryOperation: { + DCHECK_EQ(1u, coerced_arguments.size()); return E::UnaryExpression::Create( op_signature, std::static_pointer_cast<const UnaryOperation>(operation), - resolved_arguments[0], + coerced_arguments[0], coerced_static_arguments); - case Operation::kBinaryOperation: + } + case Operation::kBinaryOperation: { + DCHECK_EQ(2u, coerced_arguments.size()); return E::BinaryExpression::Create( op_signature, std::static_pointer_cast<const BinaryOperation>(operation), - resolved_arguments[0], - resolved_arguments[1], + coerced_arguments[0], + coerced_arguments[1], coerced_static_arguments); + } default: { const auto operation_id = static_cast<std::underlying_type_t<Operation::OperationSuperTypeID>>( http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/types/TextType.cpp ---------------------------------------------------------------------- diff --git a/types/TextType.cpp b/types/TextType.cpp index ce5c3a5..b806ea8 100644 --- a/types/TextType.cpp +++ b/types/TextType.cpp @@ -22,8 +22,17 @@ #include <cstddef> #include <string> +#include "types/Type.hpp" +#include "types/TypeID.hpp" +#include "utility/EqualsAnyConstant.hpp" + namespace quickstep { +bool TextType::isSafelyCoercibleFrom(const Type &original_type) const { + return QUICKSTEP_EQUALS_ANY_CONSTANT(original_type.getTypeID(), + kChar, kVarChar, kText); +} + bool TextType::checkValuesEqual(const UntypedLiteral *lhs, const UntypedLiteral *rhs, const Type &rhs_type) const { http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/types/TextType.hpp ---------------------------------------------------------------------- diff --git a/types/TextType.hpp b/types/TextType.hpp index a1fc04e..620420e 100644 --- a/types/TextType.hpp +++ b/types/TextType.hpp @@ -42,6 +42,8 @@ class TextType final : public TypeSynthesizer<kText> { return 32; } + bool isSafelyCoercibleFrom(const Type &original_type) const override; + bool checkValuesEqual(const UntypedLiteral *lhs, const UntypedLiteral *rhs, const Type &rhs_type) const override; http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/types/TypeUtil.hpp ---------------------------------------------------------------------- diff --git a/types/TypeUtil.hpp b/types/TypeUtil.hpp index ca88456..496844f 100644 --- a/types/TypeUtil.hpp +++ b/types/TypeUtil.hpp @@ -41,6 +41,7 @@ #include "types/VarCharType.hpp" #include "types/YearMonthIntervalType.hpp" #include "utility/Macros.hpp" +#include "utility/meta/TypeList.hpp" #include "glog/logging.h" @@ -50,8 +51,29 @@ namespace quickstep { * @{ */ +namespace internal { + +// TODO(refactor-type): Organize selector predicates, refactor the old design. +template <MemoryLayout layout> +struct MemoryLayoutSelector { + template <typename TypeIDConstant> + struct type { + static constexpr bool value = + TypeIDTrait<TypeIDConstant::value>::kMemoryLayout == layout; + }; +}; + +} // namespace internal + + class TypeUtil { public: + template <MemoryLayout layout> + using TypeIDSequenceMemoryLayout = + TypeIDSequenceAll::bind_to<meta::TypeList> + ::filter<internal::MemoryLayoutSelector<kCxxInlinePod>::type> + ::as_sequence<TypeID>; + static MemoryLayout GetMemoryLayout(const TypeID type_id) { return InvokeOnTypeID( type_id, @@ -60,6 +82,11 @@ class TypeUtil { }); } + template <MemoryLayout layout> + static std::vector<TypeID> GetTypeIDVectorOfMemoryLayout(){ + return TypeIDSequenceMemoryLayout<layout>::Instantiate<std::vector<TypeID>>(); + } + static bool IsParameterizedPod(const TypeID type_id) { return InvokeOnTypeID( type_id, http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/types/operations/OperationFactory.cpp ---------------------------------------------------------------------- diff --git a/types/operations/OperationFactory.cpp b/types/operations/OperationFactory.cpp index df536ed..af0ddc9 100644 --- a/types/operations/OperationFactory.cpp +++ b/types/operations/OperationFactory.cpp @@ -94,6 +94,8 @@ OperationFactory::OperationFactory() { registerFunctorPack<ArithmeticBinaryFunctorPack>(); registerFunctorPack<AsciiStringBinaryFunctorPack>(); registerFunctorPack<CMathBinaryFunctorPack>(); + + initializeTypeIDSafeCoercibility(); } bool OperationFactory::HasOperation(const std::string &operation_name, @@ -207,7 +209,6 @@ OperationSignaturePtr OperationFactory::resolveOperation( ResolveStatus status; OperationSignaturePtr op_signature = nullptr; - const auto &secondary_index = indices_it->second; std::vector<TypeID> argument_type_ids; for (const auto *type : *argument_types) { @@ -215,7 +216,7 @@ OperationSignaturePtr OperationFactory::resolveOperation( } // First, try full exact matching. - status = resolveOperationWithFullTypeMatch(secondary_index, + status = resolveOperationWithFullTypeMatch(indices_it->second.partial_signature_index, argument_type_ids, *argument_types, *static_arguments, @@ -231,7 +232,7 @@ OperationSignaturePtr OperationFactory::resolveOperation( } // Otherwise, try partial (non-static arguments) exact matching. - status = resolveOperationWithPartialTypeMatch(secondary_index, + status = resolveOperationWithPartialTypeMatch(indices_it->second.static_arity_index, argument_type_ids, *argument_types, *static_arguments, @@ -246,13 +247,13 @@ OperationSignaturePtr OperationFactory::resolveOperation( return nullptr; } - // TODO + // TODO(refactor-type): More informative error message. *message = "Unexpected argument types for function " + operation_name; return nullptr; } OperationFactory::ResolveStatus OperationFactory::resolveOperationWithFullTypeMatch( - const PartialSignatureIndex &secondary_index, + const PartialSignatureIndex &partial_signature_index, const std::vector<TypeID> &argument_type_ids, const std::vector<const Type*> &argument_types, const std::vector<GenericValue> &static_arguments, @@ -260,10 +261,11 @@ OperationFactory::ResolveStatus OperationFactory::resolveOperationWithFullTypeMa OperationSignaturePtr *resolved_op_signature, std::string *message) const { const std::size_t max_num_static_arguments = static_arguments.size(); - auto it = secondary_index.lower_bound( - std::make_pair(&argument_type_ids, max_num_static_arguments)); + auto it = partial_signature_index.lower_bound( + PartialSignature(&argument_type_ids, max_num_static_arguments)); - if (it != secondary_index.end() && *it->first.first == argument_type_ids) { + if (it != partial_signature_index.end() && + *it->first.argument_type_ids == argument_type_ids) { const OperationSignaturePtr op_signature = it->second; const OperationPtr operation = operations_.at(op_signature); @@ -288,7 +290,7 @@ OperationFactory::ResolveStatus OperationFactory::resolveOperationWithFullTypeMa } OperationFactory::ResolveStatus OperationFactory::resolveOperationWithPartialTypeMatch( - const PartialSignatureIndex &secondary_index, + const StaticArityIndex &static_arity_index, const std::vector<TypeID> &argument_type_ids, const std::vector<const Type*> &argument_types, const std::vector<GenericValue> &static_arguments, @@ -300,84 +302,154 @@ OperationFactory::ResolveStatus OperationFactory::resolveOperationWithPartialTyp const std::size_t max_num_static_arguments = static_arguments.size(); const std::size_t first_static_argument_position = arity - max_num_static_arguments; - auto it = secondary_index.lower_bound( - std::make_pair(&argument_type_ids, max_num_static_arguments)); - while (it != secondary_index.end()) { - const std::vector<TypeID> &expected_type_ids = *it->first.first; - DCHECK_GE(expected_type_ids.size(), it->first.second); - const std::size_t num_non_static_arguments = - expected_type_ids.size() - it->first.second; - - if (!std::equal(expected_type_ids.begin(), - expected_type_ids.begin() + num_non_static_arguments, - argument_type_ids.begin())) { - break; - } + const OperationSignaturePtr *best_match_op_sig = nullptr; + const std::vector<TypeID> *best_match_type_ids = nullptr; + std::size_t best_match_num_static_arguments = max_num_static_arguments; - // Coerce static arguments - std::vector<GenericValue> coerced_static_args; + auto it = static_arity_index.lower_bound(max_num_static_arguments); + while (it != static_arity_index.end()) { + if (it->first != best_match_num_static_arguments) { + if (best_match_op_sig != nullptr) { + break; + } else { + best_match_num_static_arguments = it->first; + } + } - bool is_coercible = true; - for (std::size_t i = num_non_static_arguments; i < arity; ++i) { - const Type &arg_type = *argument_types.at(i); - const GenericValue &arg_value = - static_arguments.at(i - first_static_argument_position); - const TypeID &expected_type_id = expected_type_ids.at(i); + const auto ¤t_type_ids = it->second->getArgumentTypeIDs(); - if (arg_type.getTypeID() == expected_type_id) { - coerced_static_args.emplace_back(arg_value); + if (canSafelyCoerceTypes(argument_type_ids, current_type_ids)) { + if (best_match_type_ids == nullptr) { + DCHECK(best_match_op_sig == nullptr); + best_match_op_sig = &it->second; + best_match_type_ids = ¤t_type_ids; } else { - const Type *expected_type = nullptr; - if (TypeFactory::TypeRequiresLengthParameter(expected_type_id)) { - // TODO: refactor type system to make this coercion extensible. - if (expected_type_id == kChar && arg_type.getTypeID() == kVarChar) { - expected_type = &TypeFactory::GetType( - expected_type_id, arg_type.maximumByteLength() - 1); - } else if (expected_type_id == kVarChar && arg_type.getTypeID() == kChar) { - expected_type = &TypeFactory::GetType( - expected_type_id, arg_type.maximumByteLength() + 1); - } - } else { - expected_type = &TypeFactory::GetType(expected_type_id); + const bool cur_to_best_safe = + canSafelyCoerceTypes(current_type_ids, *best_match_type_ids); + const bool best_to_cur_safe = + canSafelyCoerceTypes(*best_match_type_ids, current_type_ids); + if (cur_to_best_safe == best_to_cur_safe) { + *message = "Ambiguous call to overloaded function " + + it->second->getName() + ", candidates: " + + (*best_match_op_sig)->toString() + " v.s. " + + it->second->toString(); + return ResolveStatus::kError; } - - if (expected_type != nullptr && expected_type->isSafelyCoercibleFrom(arg_type)) { - coerced_static_args.emplace_back(arg_value.coerce(*expected_type)); - } else { - is_coercible = false; - break; + if (cur_to_best_safe) { + best_match_op_sig = &it->second; + best_match_type_ids = ¤t_type_ids; } } } - if (is_coercible) { - std::vector<const Type*> coerced_arg_types( - argument_types.begin(), - argument_types.begin() + num_non_static_arguments); - for (const auto &value : coerced_static_args) { - coerced_arg_types.emplace_back(&value.getType()); - } + ++it; + } - const OperationPtr operation = operations_.at(it->second); - if (canApplyOperationTo(operation, - coerced_arg_types, - coerced_static_args, - message)) { - *coerced_argument_types = - std::make_shared<const std::vector<const Type*>>(std::move(coerced_arg_types)); - *coerced_static_arguments = - std::make_shared<const std::vector<GenericValue>>(std::move(coerced_static_args)); - *resolved_op_signature = it->second; - return ResolveStatus::kSuccess; - } + if (best_match_op_sig == nullptr) { + return ResolveStatus::kNotFound; + } + + DCHECK(best_match_type_ids != nullptr); + DCHECK_EQ(arity, best_match_type_ids->size()); + std::vector<const Type*> coerced_arg_types; + for (std::size_t i = 0; i < arity; ++i) { + const Type &source_type = *argument_types[i]; + const TypeID target_type_id = (*best_match_type_ids)[i]; + // TODO(refactor-type): Figure out how to better handle this. + if (source_type.getTypeID() == target_type_id) { + coerced_arg_types.emplace_back(&source_type); + } else if (TypeUtil::GetMemoryLayout(target_type_id) == kCxxInlinePod) { + coerced_arg_types.emplace_back( + &TypeFactory::GetType(target_type_id, source_type.isNullable())); + } else if (target_type_id == kChar && source_type.getTypeID() == kVarChar) { + coerced_arg_types.emplace_back( + &CharType::Instance(source_type.isNullable(), + source_type.maximumByteLength() - 1)); + } else if (target_type_id == kVarChar && source_type.getTypeID() == kChar) { + coerced_arg_types.emplace_back( + &VarCharType::Instance(source_type.isNullable(), + source_type.maximumByteLength() + 1)); + } else if (target_type_id == kText) { + coerced_arg_types.emplace_back( + &TextType::Instance(source_type.isNullable())); + } else { + LOG(FATAL) << "Unexpected casting"; } + } - ++it; + std::vector<GenericValue> coerced_static_args; + for (std::size_t i = arity - best_match_num_static_arguments; i < arity; ++i) { + const auto &value = static_arguments[i - first_static_argument_position]; + if (coerced_arg_types[i]->equals(*argument_types[i])) { + coerced_static_args.emplace_back(value); + } else { + coerced_static_args.emplace_back(value.coerce(*coerced_arg_types[i])); + } + } + + const OperationPtr operation = operations_.at(*best_match_op_sig); + // TODO(refactor-type): Fix. + if (canApplyOperationTo(operation, + coerced_arg_types, + coerced_static_args, + message)) { + *coerced_argument_types = + std::make_shared<const std::vector<const Type*>>(std::move(coerced_arg_types)); + *coerced_static_arguments = + std::make_shared<const std::vector<GenericValue>>(std::move(coerced_static_args)); + *resolved_op_signature = *best_match_op_sig; + return ResolveStatus::kSuccess; } return ResolveStatus::kNotFound; } +bool OperationFactory::canSafelyCoerceTypes(const std::vector<TypeID> &source_type_ids, + const std::vector<TypeID> &target_type_ids) const { + if (source_type_ids.size() != target_type_ids.size()) { + return false; + } + for (std::size_t i = 0; i < source_type_ids.size(); ++i) { + const TypeID source_id = source_type_ids[i]; + const TypeID target_id = target_type_ids[i]; + if (source_id != target_id) { + const auto it = type_id_safe_coercibility_.find( + std::make_pair(source_id, target_id)); + if (it == type_id_safe_coercibility_.end()) { + return false; + } + } + } + return true; +} + +void OperationFactory::initializeTypeIDSafeCoercibility() { + // TODO(refactor-type): Figure out how to better handle this. + const std::vector<TypeID> cxx_inline_pod_type_ids = + TypeUtil::GetTypeIDVectorOfMemoryLayout<kCxxInlinePod>(); + + std::vector<const Type*> cxx_line_pod_types; + for (const TypeID tid : cxx_inline_pod_type_ids) { + cxx_line_pod_types.emplace_back(&TypeFactory::GetType(tid, true)); + } + + for (const Type *source_type : cxx_line_pod_types) { + for (const Type *target_type : cxx_line_pod_types) { + if (target_type->isSafelyCoercibleFrom(*source_type)) { + type_id_safe_coercibility_.emplace( + std::make_pair(source_type->getTypeID(), target_type->getTypeID())); + } + } + } + + for (const TypeID source_id : std::vector<TypeID>({kChar, kVarChar})) { + for (const TypeID target_id : std::vector<TypeID>({kChar, kVarChar, kText})) { + type_id_safe_coercibility_.emplace(std::make_pair(source_id, target_id)); + } + } + type_id_safe_coercibility_.emplace(std::make_pair(kText, kText)); +} + bool OperationFactory::canApplyOperationTo( const OperationPtr operation, const std::vector<const Type*> &argument_types, @@ -444,12 +516,8 @@ void OperationFactory::registerOperationInternal(const OperationPtr &operation) // TODO: print error message for collision operations_.emplace(op_sig, operation); - - const PartialSignature sig_ref = - std::make_pair(&op_sig->getArgumentTypeIDs(), - op_sig->getNumStaticArguments()); primary_index_[std::make_pair(op_sig->getName(), - op_sig->getArity())].emplace(sig_ref, op_sig); + op_sig->getArity())].addSignature(op_sig); } } http://git-wip-us.apache.org/repos/asf/incubator-quickstep/blob/8c3996c6/types/operations/OperationFactory.hpp ---------------------------------------------------------------------- diff --git a/types/operations/OperationFactory.hpp b/types/operations/OperationFactory.hpp index 7fccbc5..f124e9a 100644 --- a/types/operations/OperationFactory.hpp +++ b/types/operations/OperationFactory.hpp @@ -134,30 +134,49 @@ class OperationFactory { void registerOperationInternal(const OperationPtr &operation); - using PartialSignature = std::pair<const std::vector<TypeID>*, std::size_t>; - - struct PartialSignatureLess { - inline bool operator()(const PartialSignature &lhs, - const PartialSignature &rhs) const { - int cmp_code = static_cast<int>(lhs.first->size()) - - static_cast<int>(lhs.first->size()); + struct PartialSignature { + PartialSignature(const std::vector<TypeID> *argument_type_ids_in, + const std::size_t num_static_arguments_in) + : argument_type_ids(argument_type_ids_in), + num_static_arguments(num_static_arguments_in) { + } + inline bool operator<(const PartialSignature &rhs) const { + const PartialSignature &lhs = *this; + const std::vector<TypeID> &lhs_ids = *lhs.argument_type_ids; + const std::vector<TypeID> &rhs_ids = *rhs.argument_type_ids; + int cmp_code = static_cast<int>(lhs_ids.size()) - static_cast<int>(rhs_ids.size()); if (cmp_code != 0) { return cmp_code < 0; } - for (std::size_t i = 0; i < lhs.first->size(); ++i) { - cmp_code = static_cast<int>(lhs.first->at(i)) - - static_cast<int>(rhs.first->at(i)); + for (std::size_t i = 0; i < lhs.argument_type_ids->size(); ++i) { + cmp_code = static_cast<int>(lhs_ids[i]) - static_cast<int>(rhs_ids[i]); if (cmp_code != 0) { return cmp_code < 0; } } - return lhs.second > rhs.second; + return lhs.num_static_arguments > rhs.num_static_arguments; } + const std::vector<TypeID> *argument_type_ids; + const std::size_t num_static_arguments; }; using PartialSignatureIndex = std::map<PartialSignature, + OperationSignaturePtr>; + using StaticArityIndex = std::multimap<std::size_t, OperationSignaturePtr, - PartialSignatureLess>; + std::greater<std::size_t>>; + + struct SecondaryIndex { + inline void addSignature(const OperationSignaturePtr &op_sig) { + partial_signature_index.emplace( + PartialSignature(&op_sig->getArgumentTypeIDs(), + op_sig->getNumStaticArguments()), + op_sig); + static_arity_index.emplace(op_sig->getNumStaticArguments(), op_sig); + } + PartialSignatureIndex partial_signature_index; + StaticArityIndex static_arity_index; + }; enum class ResolveStatus { kSuccess = 0, @@ -174,7 +193,7 @@ class OperationFactory { std::string *message) const; ResolveStatus resolveOperationWithFullTypeMatch( - const PartialSignatureIndex &secondary_index, + const PartialSignatureIndex &partial_signature_index, const std::vector<TypeID> &argument_type_ids, const std::vector<const Type*> &argument_types, const std::vector<GenericValue> &static_arguments, @@ -183,7 +202,7 @@ class OperationFactory { std::string *message) const; ResolveStatus resolveOperationWithPartialTypeMatch( - const PartialSignatureIndex &secondary_index, + const StaticArityIndex &static_arity_index, const std::vector<TypeID> &argument_type_ids, const std::vector<const Type*> &argument_types, const std::vector<GenericValue> &static_arguments, @@ -192,6 +211,11 @@ class OperationFactory { OperationSignaturePtr *resolved_op_signature, std::string *message) const; + bool canSafelyCoerceTypes(const std::vector<TypeID> &source_type_ids, + const std::vector<TypeID> &target_type_ids) const; + + void initializeTypeIDSafeCoercibility(); + bool canApplyOperationTo(const OperationPtr operation, const std::vector<const Type*> &argument_types, const std::vector<GenericValue> &static_arguments, @@ -203,7 +227,9 @@ class OperationFactory { OperationSignatureEqual> operations_; std::unordered_map<std::pair<std::string, std::size_t>, - PartialSignatureIndex> primary_index_; + SecondaryIndex> primary_index_; + + std::unordered_set<std::pair<TypeID, TypeID>> type_id_safe_coercibility_; DISALLOW_COPY_AND_ASSIGN(OperationFactory); };
