VapourSynth-llvmexpr
Loading...
Searching...
No Matches
OverloadResolution.hpp
Go to the documentation of this file.
1
19
20#ifndef LLVMEXPR_FRONTEND_INFIX2POSTFIX_OVERLOADRESOLUTION_HPP
21#define LLVMEXPR_FRONTEND_INFIX2POSTFIX_OVERLOADRESOLUTION_HPP
22
23#include "types.hpp"
24
25#include <algorithm>
26#include <optional>
27#include <vector>
28
29namespace infix2postfix {
30
31inline bool is_convertible(Type from, Type to, Mode mode) {
32 if (from == Type::Void) {
33 return false;
34 }
35 return from == to || (to == Type::Value && from != Type::LiteralString &&
36 from != Type::Array &&
37 (mode != Mode::Single || from != Type::Clip));
38}
39
40template <typename T> struct OverloadCandidate {
41 const T* item;
44};
45
46template <typename T>
49 if (candidates.empty()) {
50 return nullptr;
51 }
52
53 OverloadCandidate<T>* best = candidates.data();
54 for (size_t i = 1; i < candidates.size(); ++i) {
55 if (candidates[i].conversion_count < best->conversion_count) {
56 best = &candidates[i];
57 } else if (candidates[i].conversion_count == best->conversion_count) {
58 if (candidates[i].first_conversion_index >
60 best = &candidates[i];
61 }
62 }
63 }
64 return best;
65}
66
67template <typename T>
68bool is_ambiguous(const std::vector<OverloadCandidate<T>>& candidates,
69 const OverloadCandidate<T>* best) {
70 if (!best || candidates.size() <= 1) {
71 return false;
72 }
73
74 int count = 0;
75 count = std::ranges::count_if(candidates, [best](const auto& cand) {
76 return cand.conversion_count == best->conversion_count &&
77 cand.first_conversion_index == best->first_conversion_index;
78 });
79 return count > 1;
80}
81
82template <typename T, typename ArgTypeGetter, typename ParamTypeGetter>
83std::vector<OverloadCandidate<T>>
84compute_candidates(const std::vector<T>& overloads, size_t arg_count,
85 ArgTypeGetter get_arg_type, ParamTypeGetter get_param_type,
86 Mode mode) {
87 std::vector<OverloadCandidate<T>> candidates;
88
89 for (const auto& item : overloads) {
90 int conversion_count = 0;
91 int first_conversion_index = -1;
92 bool possible = true;
93
94 for (size_t j = 0; j < arg_count; ++j) {
95 std::optional<Type> arg_type_opt = get_arg_type(item, j);
96 std::optional<Type> param_type_opt = get_param_type(item, j);
97
98 if (!arg_type_opt.has_value() || !param_type_opt.has_value()) {
99 possible = false;
100 break;
101 }
102
103 Type arg_type = arg_type_opt.value();
104 Type param_type = param_type_opt.value();
105
106 if (arg_type != param_type) {
107 if (is_convertible(arg_type, param_type, mode)) {
108 conversion_count++;
109 if (first_conversion_index == -1) {
110 first_conversion_index = static_cast<int>(j);
111 }
112 } else {
113 possible = false;
114 break;
115 }
116 }
117 }
118
119 if (possible) {
120 candidates.push_back(
121 {&item, conversion_count, first_conversion_index});
122 }
123 }
124
125 return candidates;
126}
127
128} // namespace infix2postfix
129
130#endif // LLVMEXPR_FRONTEND_INFIX2POSTFIX_OVERLOADRESOLUTION_HPP
bool is_ambiguous(const std::vector< OverloadCandidate< T > > &candidates, const OverloadCandidate< T > *best)
std::vector< OverloadCandidate< T > > compute_candidates(const std::vector< T > &overloads, size_t arg_count, ArgTypeGetter get_arg_type, ParamTypeGetter get_param_type, Mode mode)
bool is_convertible(Type from, Type to, Mode mode)
const OverloadCandidate< T > * select_best_candidate(std::vector< OverloadCandidate< T > > &candidates)