rice 4.7.0 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +36 -1
- data/CMakeLists.txt +14 -22
- data/CMakePresets.json +203 -75
- data/FindRuby.cmake +358 -123
- data/bin/rice-doc.rb +56 -142
- data/bin/rice-rbs.rb +1 -2
- data/include/rice/api.hpp +248 -0
- data/include/rice/rice.hpp +2281 -1668
- data/include/rice/stl.hpp +364 -443
- data/lib/rice/doc/config.rb +70 -0
- data/lib/rice/doc/cpp_reference.rb +1 -4
- data/lib/rice/doc/mkdocs.rb +58 -20
- data/lib/rice/doc/rice.rb +20 -0
- data/lib/rice/doc.rb +1 -0
- data/lib/rice/make_rice_headers.rb +7 -0
- data/lib/rice/native_registry.rb +2 -2
- data/lib/rice/rbs.rb +4 -4
- data/lib/rice/version.rb +1 -1
- data/lib/rubygems_plugin.rb +12 -9
- data/rice/Arg.hpp +12 -6
- data/rice/Arg.ipp +14 -7
- data/rice/Buffer.ipp +44 -40
- data/rice/Callback.hpp +1 -1
- data/rice/Callback.ipp +2 -7
- data/rice/Constructor.hpp +1 -1
- data/rice/Constructor.ipp +11 -11
- data/rice/Data_Object.ipp +59 -30
- data/rice/Data_Type.hpp +9 -10
- data/rice/Data_Type.ipp +22 -25
- data/rice/Director.hpp +1 -0
- data/rice/Enum.ipp +58 -39
- data/rice/Exception.hpp +4 -4
- data/rice/Exception.ipp +7 -7
- data/rice/NoGVL.hpp +13 -0
- data/rice/Reference.hpp +56 -0
- data/rice/Reference.ipp +96 -0
- data/rice/Return.hpp +4 -1
- data/rice/Return.ipp +0 -6
- data/rice/cpp_api/Array.hpp +44 -7
- data/rice/cpp_api/Array.ipp +105 -9
- data/rice/cpp_api/Class.hpp +2 -2
- data/rice/cpp_api/Class.ipp +4 -4
- data/rice/cpp_api/Hash.ipp +7 -4
- data/rice/cpp_api/Module.hpp +4 -4
- data/rice/cpp_api/Module.ipp +12 -10
- data/rice/cpp_api/Object.hpp +4 -4
- data/rice/cpp_api/Object.ipp +15 -12
- data/rice/cpp_api/String.hpp +2 -2
- data/rice/cpp_api/String.ipp +11 -8
- data/rice/cpp_api/Symbol.ipp +16 -7
- data/rice/cpp_api/shared_methods.hpp +5 -9
- data/rice/detail/InstanceRegistry.hpp +0 -2
- data/rice/detail/Native.hpp +31 -21
- data/rice/detail/Native.ipp +281 -133
- data/rice/detail/NativeAttributeGet.hpp +5 -7
- data/rice/detail/NativeAttributeGet.ipp +26 -26
- data/rice/detail/NativeAttributeSet.hpp +2 -4
- data/rice/detail/NativeAttributeSet.ipp +20 -16
- data/rice/detail/NativeCallback.hpp +77 -0
- data/rice/detail/NativeCallback.ipp +280 -0
- data/rice/detail/NativeFunction.hpp +11 -21
- data/rice/detail/NativeFunction.ipp +58 -119
- data/rice/detail/NativeInvoker.hpp +4 -4
- data/rice/detail/NativeInvoker.ipp +7 -7
- data/rice/detail/NativeIterator.hpp +2 -4
- data/rice/detail/NativeIterator.ipp +18 -14
- data/rice/detail/NativeMethod.hpp +10 -20
- data/rice/detail/NativeMethod.ipp +54 -114
- data/rice/detail/NativeProc.hpp +5 -7
- data/rice/detail/NativeProc.ipp +39 -28
- data/rice/detail/NativeRegistry.hpp +0 -1
- data/rice/detail/NativeRegistry.ipp +0 -1
- data/rice/detail/Parameter.hpp +15 -8
- data/rice/detail/Parameter.ipp +102 -43
- data/rice/detail/Proc.ipp +14 -28
- data/rice/detail/RubyType.ipp +2 -53
- data/rice/detail/Type.hpp +23 -7
- data/rice/detail/Type.ipp +73 -93
- data/rice/detail/TypeRegistry.ipp +5 -4
- data/rice/detail/Wrapper.hpp +1 -1
- data/rice/detail/Wrapper.ipp +18 -10
- data/rice/detail/from_ruby.hpp +8 -6
- data/rice/detail/from_ruby.ipp +306 -173
- data/rice/detail/ruby.hpp +23 -0
- data/rice/libc/file.hpp +4 -4
- data/rice/rice.hpp +6 -8
- data/rice/rice_api/Native.ipp +5 -1
- data/rice/rice_api/Parameter.ipp +1 -1
- data/rice/ruby_mark.hpp +2 -1
- data/rice/stl/complex.ipp +12 -8
- data/rice/stl/map.ipp +27 -22
- data/rice/stl/monostate.ipp +16 -12
- data/rice/stl/multimap.hpp +0 -2
- data/rice/stl/multimap.ipp +27 -22
- data/rice/stl/optional.ipp +27 -11
- data/rice/stl/pair.ipp +5 -5
- data/rice/stl/reference_wrapper.ipp +5 -4
- data/rice/stl/set.ipp +16 -16
- data/rice/stl/shared_ptr.hpp +0 -16
- data/rice/stl/shared_ptr.ipp +34 -190
- data/rice/stl/string.ipp +18 -18
- data/rice/stl/string_view.ipp +19 -1
- data/rice/stl/tuple.ipp +15 -36
- data/rice/stl/unique_ptr.ipp +18 -8
- data/rice/stl/unordered_map.ipp +20 -15
- data/rice/stl/variant.ipp +37 -21
- data/rice/stl/vector.ipp +41 -36
- data/rice/traits/function_traits.hpp +19 -19
- data/rice/traits/method_traits.hpp +4 -4
- data/rice/traits/rice_traits.hpp +162 -39
- data/rice.gemspec +1 -4
- data/test/test_Array.cpp +261 -3
- data/test/test_Attribute.cpp +6 -3
- data/test/test_Buffer.cpp +6 -42
- data/test/test_Callback.cpp +77 -23
- data/test/test_Data_Object.cpp +2 -2
- data/test/test_Data_Type.cpp +23 -23
- data/test/test_Director.cpp +2 -4
- data/test/test_Enum.cpp +34 -5
- data/test/test_File.cpp +9 -5
- data/test/test_From_Ruby.cpp +7 -6
- data/test/test_GVL.cpp +3 -3
- data/test/test_Hash.cpp +1 -1
- data/test/test_Iterator.cpp +54 -22
- data/test/test_Keep_Alive.cpp +1 -1
- data/test/test_Keep_Alive_No_Wrapper.cpp +1 -1
- data/test/test_Module.cpp +5 -5
- data/test/test_Overloads.cpp +395 -50
- data/test/test_Proc.cpp +54 -0
- data/test/test_Reference.cpp +181 -0
- data/test/test_Self.cpp +2 -2
- data/test/test_Stl_Set.cpp +6 -6
- data/test/test_Stl_SharedPtr.cpp +54 -30
- data/test/test_Stl_String_View.cpp +12 -0
- data/test/test_Stl_Tuple.cpp +1 -1
- data/test/test_Stl_Variant.cpp +6 -14
- data/test/test_Stl_Vector.cpp +61 -30
- data/test/test_String.cpp +4 -2
- data/test/test_Struct.cpp +1 -1
- data/test/test_Symbol.cpp +12 -0
- data/test/test_To_Ruby.cpp +1 -0
- data/test/test_Type.cpp +36 -35
- data/test/test_global_functions.cpp +1 -1
- data/test/unittest.cpp +1 -1
- data/test/unittest.hpp +5 -5
- metadata +10 -24
- data/rice/Function.hpp +0 -17
- data/rice/Function.ipp +0 -13
- data/rice/detail/MethodInfo.hpp +0 -48
- data/rice/detail/MethodInfo.ipp +0 -99
- data/rice/detail/NativeCallbackFFI.hpp +0 -55
- data/rice/detail/NativeCallbackFFI.ipp +0 -152
- data/rice/detail/NativeCallbackSimple.hpp +0 -30
- data/rice/detail/NativeCallbackSimple.ipp +0 -29
data/rice/detail/Native.hpp
CHANGED
|
@@ -11,8 +11,7 @@ namespace Rice::detail
|
|
|
11
11
|
inline bool operator<(Resolved other);
|
|
12
12
|
inline bool operator>(Resolved other);
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
double parameterMatch;
|
|
14
|
+
double score; // Combined score: minParameterScore * parameterMatch
|
|
16
15
|
Native* native;
|
|
17
16
|
};
|
|
18
17
|
|
|
@@ -23,7 +22,8 @@ namespace Rice::detail
|
|
|
23
22
|
Iterator,
|
|
24
23
|
AttributeReader,
|
|
25
24
|
AttributeWriter,
|
|
26
|
-
Proc
|
|
25
|
+
Proc,
|
|
26
|
+
Callback
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
class Native
|
|
@@ -31,8 +31,9 @@ namespace Rice::detail
|
|
|
31
31
|
public:
|
|
32
32
|
static VALUE resolve(int argc, VALUE* argv, VALUE self);
|
|
33
33
|
public:
|
|
34
|
-
Native()
|
|
35
|
-
Native(std::
|
|
34
|
+
Native(std::string name);
|
|
35
|
+
Native(std::string name, std::unique_ptr<Return>&& returnInfo);
|
|
36
|
+
Native(std::string name, std::unique_ptr<Return>&& returnInfo, std::vector<std::unique_ptr<ParameterAbstract>>&& parameters);
|
|
36
37
|
virtual ~Native() = default;
|
|
37
38
|
|
|
38
39
|
Native(const Native&) = delete;
|
|
@@ -40,36 +41,45 @@ namespace Rice::detail
|
|
|
40
41
|
void operator=(const Native&) = delete;
|
|
41
42
|
void operator=(Native&&) = delete;
|
|
42
43
|
|
|
43
|
-
virtual Resolved matches(
|
|
44
|
-
virtual VALUE operator()(
|
|
44
|
+
virtual Resolved matches(std::map<std::string, VALUE>& values);
|
|
45
|
+
virtual VALUE operator()(std::map<std::string, VALUE>& values, VALUE self) = 0;
|
|
45
46
|
virtual std::string toString() = 0;
|
|
46
47
|
|
|
47
48
|
// Ruby API access
|
|
48
|
-
|
|
49
|
+
std::string name();
|
|
50
|
+
std::vector<const ParameterAbstract*> parameters();
|
|
49
51
|
virtual NativeKind kind() = 0;
|
|
50
52
|
virtual VALUE returnKlass() = 0;
|
|
51
|
-
std::vector<const ParameterAbstract*> parameters();
|
|
52
53
|
|
|
53
54
|
protected:
|
|
54
|
-
template<typename T>
|
|
55
|
-
static void verify_type(
|
|
55
|
+
template<typename T, bool isBuffer>
|
|
56
|
+
static void verify_type();
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
std::vector<std::optional<VALUE>> getRubyValues(size_t argc, const VALUE* argv, bool validate);
|
|
58
|
+
static std::map<std::string, VALUE> readRubyArgs(size_t argc, const VALUE* argv);
|
|
59
|
+
std::vector<std::optional<VALUE>> getRubyValues(std::map<std::string, VALUE> values, bool validate);
|
|
61
60
|
ParameterAbstract* getParameterByName(std::string name);
|
|
62
|
-
|
|
61
|
+
double matchParameters(std::vector<std::optional<VALUE>>& values, size_t argc);
|
|
62
|
+
|
|
63
|
+
template<typename Parameter_Tuple, typename... Arg_Ts>
|
|
64
|
+
static std::vector<std::unique_ptr<ParameterAbstract>> create_parameters(Arg_Ts&& ...args);
|
|
63
65
|
|
|
64
|
-
template<typename
|
|
65
|
-
static std::
|
|
66
|
+
template<typename... Arg_Ts>
|
|
67
|
+
static std::unique_ptr<Return> create_return(Arg_Ts& ...args);
|
|
66
68
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
// Do we need to keep alive any arguments?
|
|
70
|
+
void checkKeepAlive(VALUE self, VALUE returnValue, std::vector<std::optional<VALUE>>& rubyValues);
|
|
71
|
+
|
|
72
|
+
private:
|
|
73
|
+
template<typename Parameter_Tuple, typename Arg_Tuple, std::size_t ...Indices>
|
|
74
|
+
static inline void create_parameters_impl(std::vector<std::unique_ptr<ParameterAbstract>>& parameters, std::index_sequence<Indices...> indices, std::vector<std::unique_ptr<Arg>>&& args);
|
|
75
|
+
|
|
76
|
+
template<typename Parameter_Tuple, typename Arg_Tuple, size_t I>
|
|
77
|
+
static void verify_parameter();
|
|
69
78
|
|
|
70
79
|
protected:
|
|
80
|
+
std::string name_;
|
|
81
|
+
std::unique_ptr<Return> returnInfo_;
|
|
71
82
|
std::vector<std::unique_ptr<ParameterAbstract>> parameters_;
|
|
72
|
-
|
|
73
83
|
};
|
|
74
84
|
}
|
|
75
85
|
|
data/rice/detail/Native.ipp
CHANGED
|
@@ -1,58 +1,41 @@
|
|
|
1
|
-
|
|
2
1
|
namespace Rice::detail
|
|
3
2
|
{
|
|
4
3
|
inline bool Resolved::operator<(Resolved other)
|
|
5
4
|
{
|
|
6
|
-
|
|
7
|
-
{
|
|
8
|
-
return this->convertible < other.convertible;
|
|
9
|
-
}
|
|
10
|
-
else
|
|
11
|
-
{
|
|
12
|
-
return this->parameterMatch < other.parameterMatch;
|
|
13
|
-
}
|
|
5
|
+
return this->score < other.score;
|
|
14
6
|
}
|
|
15
7
|
|
|
16
8
|
inline bool Resolved::operator>(Resolved other)
|
|
17
9
|
{
|
|
18
|
-
|
|
19
|
-
{
|
|
20
|
-
return this->convertible > other.convertible;
|
|
21
|
-
}
|
|
22
|
-
else
|
|
23
|
-
{
|
|
24
|
-
return this->parameterMatch > other.parameterMatch;
|
|
25
|
-
}
|
|
10
|
+
return this->score > other.score;
|
|
26
11
|
}
|
|
27
12
|
|
|
28
13
|
inline VALUE Native::resolve(int argc, VALUE* argv, VALUE self)
|
|
29
14
|
{
|
|
30
15
|
/* This method is called from Ruby and is responsible for determining the correct
|
|
31
|
-
Native object (ie, NativeFunction, NativeIterator, NativeAttributeGet and
|
|
32
|
-
NativeAttributeSet) that
|
|
16
|
+
Native object (ie, NativeFunction, NativeIterator, NativeAttributeGet and
|
|
17
|
+
NativeAttributeSet) that should be used to invoke the underlying C++ code.
|
|
33
18
|
Most of the time there will be a single Native object registered for a C++ function,
|
|
34
|
-
method, constructor, iterator or attribute. However, there can be multiple Natives
|
|
35
|
-
when a C++ function/method/
|
|
19
|
+
method, constructor, iterator or attribute. However, there can be multiple Natives
|
|
20
|
+
when a C++ function/method/constructor is overloaded.
|
|
36
21
|
|
|
37
22
|
In that case, the code iterates over each Native and calls its matches method. The matches
|
|
38
|
-
method returns a Resolved object
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
TypeCast (example Ruby into to C++ float) or None (cannot be converted).
|
|
23
|
+
method returns a Resolved object with a numeric score (0.0 to 1.0). The score is computed as:
|
|
24
|
+
|
|
25
|
+
score = minParameterScore * parameterMatch
|
|
42
26
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
parameters
|
|
27
|
+
where minParameterScore is the minimum score across all passed parameters (using precision-based
|
|
28
|
+
scoring for numeric types), and parameterMatch applies a small penalty (0.99) for each default
|
|
29
|
+
parameter used. If not enough arguments are provided and missing parameters don't have defaults,
|
|
30
|
+
the method returns 0 (not viable).
|
|
46
31
|
|
|
47
|
-
|
|
48
|
-
highest score (Convertible::Exact and 1.0 for parameterMatch). Thus given these two C++ functions:
|
|
32
|
+
The method sorts the Natives and picks the one with the highest score. Given these two C++ functions:
|
|
49
33
|
|
|
50
34
|
void some_method(int a);
|
|
51
|
-
void
|
|
35
|
+
void some_method(int a, float b = 2.0);
|
|
52
36
|
|
|
53
|
-
A call from ruby of some_method(1) will
|
|
54
|
-
will be chosen because
|
|
55
|
-
for the second. */
|
|
37
|
+
A call from ruby of some_method(1) will match both signatures, but the first one
|
|
38
|
+
will be chosen because parameterMatch = 1.0 for the first overload but 0.99 for the second. */
|
|
56
39
|
|
|
57
40
|
Native* native = nullptr;
|
|
58
41
|
|
|
@@ -64,11 +47,9 @@ namespace Rice::detail
|
|
|
64
47
|
}
|
|
65
48
|
|
|
66
49
|
// Execute the function but make sure to catch any C++ exceptions!
|
|
67
|
-
return cpp_protect([&]
|
|
50
|
+
return cpp_protect([&]()
|
|
68
51
|
{
|
|
69
|
-
|
|
70
|
-
std::string methodName = id.str();
|
|
71
|
-
std::string className = rb_class2name(klass);
|
|
52
|
+
std::map<std::string, VALUE> values = readRubyArgs(argc, argv);
|
|
72
53
|
|
|
73
54
|
const std::vector<std::unique_ptr<Native>>& natives = Registries::instance.natives.lookup(klass, methodId);
|
|
74
55
|
|
|
@@ -91,7 +72,7 @@ namespace Rice::detail
|
|
|
91
72
|
std::back_inserter(resolves),
|
|
92
73
|
[&](const std::unique_ptr<Native>& native)
|
|
93
74
|
{
|
|
94
|
-
return native->matches(
|
|
75
|
+
return native->matches(values);
|
|
95
76
|
});
|
|
96
77
|
|
|
97
78
|
// Now sort from best to worst
|
|
@@ -122,7 +103,7 @@ namespace Rice::detail
|
|
|
122
103
|
}*/
|
|
123
104
|
|
|
124
105
|
// Did it match?
|
|
125
|
-
if (resolved.
|
|
106
|
+
if (resolved.score > Convertible::None)
|
|
126
107
|
{
|
|
127
108
|
native = resolved.native;
|
|
128
109
|
}
|
|
@@ -151,19 +132,34 @@ namespace Rice::detail
|
|
|
151
132
|
}
|
|
152
133
|
|
|
153
134
|
// Call the C++ function
|
|
154
|
-
return (*native)(
|
|
135
|
+
return (*native)(values, self);
|
|
155
136
|
});
|
|
156
137
|
}
|
|
157
138
|
|
|
158
|
-
inline Native::Native(std::
|
|
139
|
+
inline Native::Native(std::string name) :
|
|
140
|
+
name_(name)
|
|
141
|
+
{
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
inline Native::Native(std::string name,std::unique_ptr<Return>&& returnInfo) :
|
|
145
|
+
name_(name), returnInfo_(std::move(returnInfo))
|
|
146
|
+
{
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
inline Native::Native(std::string name, std::unique_ptr<Return>&& returnInfo, std::vector<std::unique_ptr<ParameterAbstract>>&& parameters) :
|
|
150
|
+
name_(name), returnInfo_(std::move(returnInfo)), parameters_(std::move(parameters))
|
|
159
151
|
{
|
|
160
152
|
}
|
|
161
153
|
|
|
154
|
+
inline std::string Native::name()
|
|
155
|
+
{
|
|
156
|
+
return this->name_;
|
|
157
|
+
}
|
|
162
158
|
inline ParameterAbstract* Native::getParameterByName(std::string name)
|
|
163
159
|
{
|
|
164
160
|
for (std::unique_ptr<ParameterAbstract>& parameter : this->parameters_)
|
|
165
161
|
{
|
|
166
|
-
if (parameter->arg->name == name)
|
|
162
|
+
if (parameter->arg()->name == name)
|
|
167
163
|
{
|
|
168
164
|
return parameter.get();
|
|
169
165
|
}
|
|
@@ -172,168 +168,320 @@ namespace Rice::detail
|
|
|
172
168
|
return nullptr;
|
|
173
169
|
}
|
|
174
170
|
|
|
175
|
-
|
|
176
|
-
template<typename T>
|
|
177
|
-
inline void Native::verify_type(bool isBuffer)
|
|
171
|
+
inline void Native::checkKeepAlive(VALUE self, VALUE returnValue, std::vector<std::optional<VALUE>>& rubyValues)
|
|
178
172
|
{
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
detail::verifyType<T>();
|
|
182
|
-
|
|
183
|
-
if constexpr (std::is_pointer_v<T> && std::is_fundamental_v<std::remove_pointer_t<T>>)
|
|
173
|
+
// Check function arguments
|
|
174
|
+
for (size_t i = 0; i < this->parameters_.size(); i++)
|
|
184
175
|
{
|
|
185
|
-
|
|
186
|
-
|
|
176
|
+
Arg* arg = parameters_[i]->arg();
|
|
177
|
+
if (arg->isKeepAlive())
|
|
178
|
+
{
|
|
179
|
+
static WrapperBase* selfWrapper = getWrapper(self);
|
|
180
|
+
selfWrapper->addKeepAlive(rubyValues[i].value());
|
|
181
|
+
}
|
|
187
182
|
}
|
|
188
|
-
|
|
183
|
+
|
|
184
|
+
// Check return value
|
|
185
|
+
if (this->returnInfo_->isKeepAlive())
|
|
189
186
|
{
|
|
190
|
-
|
|
191
|
-
|
|
187
|
+
WrapperBase* returnWrapper = getWrapper(returnValue);
|
|
188
|
+
returnWrapper->addKeepAlive(self);
|
|
192
189
|
}
|
|
193
|
-
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// ----------- Type Checking ----------------
|
|
193
|
+
template<typename T, bool isBuffer>
|
|
194
|
+
inline void Native::verify_type()
|
|
195
|
+
{
|
|
196
|
+
detail::verifyType<T>();
|
|
197
|
+
|
|
198
|
+
if constexpr (std::is_pointer_v<T>)
|
|
194
199
|
{
|
|
195
|
-
|
|
200
|
+
using Base_T = std::remove_pointer_t<remove_cv_recursive_t<T>>;
|
|
201
|
+
|
|
202
|
+
if constexpr (std::is_fundamental_v<Base_T> || std::is_pointer_v<Base_T> || isBuffer)
|
|
196
203
|
{
|
|
197
204
|
Type<Pointer<Base_T>>::verify();
|
|
198
|
-
Type<Buffer<Base_T>>::verify();
|
|
199
205
|
}
|
|
200
|
-
|
|
206
|
+
}
|
|
207
|
+
else if constexpr (std::is_reference_v<T>)
|
|
208
|
+
{
|
|
209
|
+
using Base_T = std::remove_reference_t<remove_cv_recursive_t<T>>;
|
|
210
|
+
|
|
211
|
+
if constexpr (std::is_fundamental_v<Base_T>)
|
|
201
212
|
{
|
|
202
|
-
|
|
213
|
+
Type<Reference<Base_T>>::verify();
|
|
203
214
|
}
|
|
204
215
|
}
|
|
216
|
+
else if constexpr (std::is_array_v<T>)
|
|
217
|
+
{
|
|
218
|
+
using Base_T = std::remove_extent_t<remove_cv_recursive_t<T>>;
|
|
219
|
+
|
|
220
|
+
Type<Pointer<Base_T>>::verify();
|
|
221
|
+
}
|
|
205
222
|
}
|
|
206
223
|
|
|
207
|
-
template<typename
|
|
208
|
-
inline void Native::
|
|
224
|
+
template<typename Parameter_Tuple, typename Arg_Tuple, size_t I>
|
|
225
|
+
inline void Native::verify_parameter()
|
|
209
226
|
{
|
|
210
|
-
|
|
211
|
-
|
|
227
|
+
using Param_T = std::tuple_element_t<I, Parameter_Tuple>;
|
|
228
|
+
using Arg_T = std::tuple_element_t<I, Arg_Tuple>;
|
|
229
|
+
if constexpr (std::is_same_v<ArgBuffer, std::decay_t<Arg_T>>)
|
|
230
|
+
{
|
|
231
|
+
verify_type<Param_T, true>();
|
|
232
|
+
}
|
|
233
|
+
else
|
|
234
|
+
{
|
|
235
|
+
verify_type<Param_T, false>();
|
|
236
|
+
}
|
|
237
|
+
};
|
|
212
238
|
|
|
213
|
-
template<typename
|
|
214
|
-
inline void Native::create_parameters_impl(std::vector<std::unique_ptr<ParameterAbstract>>& parameters,
|
|
239
|
+
template<typename Parameter_Tuple, typename Arg_Tuple, std::size_t ...Indices>
|
|
240
|
+
inline void Native::create_parameters_impl(std::vector<std::unique_ptr<ParameterAbstract>>& parameters, std::index_sequence<Indices...>, std::vector<std::unique_ptr<Arg>>&& args)
|
|
215
241
|
{
|
|
216
|
-
|
|
242
|
+
// Verify parameter types
|
|
243
|
+
(verify_parameter<Parameter_Tuple, Arg_Tuple, Indices>(), ...);
|
|
244
|
+
|
|
245
|
+
// Create parameters
|
|
246
|
+
(parameters.push_back(std::move(std::make_unique<
|
|
247
|
+
Parameter<std::tuple_element_t<Indices, Parameter_Tuple>>>(std::move(args[Indices])))), ...);
|
|
217
248
|
}
|
|
218
249
|
|
|
219
|
-
template<typename
|
|
220
|
-
inline std::vector<std::unique_ptr<ParameterAbstract>> Native::create_parameters(
|
|
250
|
+
template<typename Parameter_Tuple, typename... Arg_Ts>
|
|
251
|
+
inline std::vector<std::unique_ptr<ParameterAbstract>> Native::create_parameters(Arg_Ts&& ...args)
|
|
221
252
|
{
|
|
222
253
|
std::vector<std::unique_ptr<ParameterAbstract>> result;
|
|
223
|
-
|
|
224
|
-
|
|
254
|
+
|
|
255
|
+
// Extract Arg and ArgBuffer from Arg_Ts and then pad Arg to match the size of Parameter_Tuple
|
|
256
|
+
using ArgsBaseTuple = tuple_filter_types_t<std::tuple<Arg_Ts...>, Arg, ArgBuffer>;
|
|
257
|
+
|
|
258
|
+
// Diff can be less than zero so it has to be signed! This happens when define_method is called with a self
|
|
259
|
+
// parameter and specifies one or more Args (usually to call Arg("self).setValue()).
|
|
260
|
+
// In that case the self parameter is considered Class_T and there are no arguments.
|
|
261
|
+
constexpr long diff = (long)std::tuple_size_v<Parameter_Tuple> - (long)std::tuple_size_v<ArgsBaseTuple>;
|
|
262
|
+
using ArgsTuple = tuple_pad_type_t<ArgsBaseTuple, Arg, diff < 0 ? 0 : diff>;
|
|
263
|
+
|
|
264
|
+
// Now play the same game but with the tuple values instead of types
|
|
265
|
+
std::vector<std::unique_ptr<Arg>> argsVector;
|
|
266
|
+
|
|
267
|
+
// Loop over each arg with an anonymous lambda
|
|
268
|
+
([&]
|
|
269
|
+
{
|
|
270
|
+
using Arg_T = std::decay_t<Arg_Ts>;
|
|
271
|
+
|
|
272
|
+
if constexpr (std::is_same_v<Arg, Arg_T> || std::is_same_v<ArgBuffer, Arg_T>)
|
|
273
|
+
{
|
|
274
|
+
argsVector.emplace_back(std::make_unique<Arg_T>(args));
|
|
275
|
+
}
|
|
276
|
+
}(), ...);
|
|
277
|
+
|
|
278
|
+
// Fill in missing args
|
|
279
|
+
for (size_t i = argsVector.size(); i < std::tuple_size_v<Parameter_Tuple>; i++)
|
|
280
|
+
{
|
|
281
|
+
std::string argName = "arg_" + std::to_string(i);
|
|
282
|
+
argsVector.emplace_back(std::make_unique<Arg>(argName));
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
auto indices = std::make_index_sequence<std::tuple_size_v<Parameter_Tuple>>{};
|
|
286
|
+
Native::create_parameters_impl<Parameter_Tuple, ArgsTuple>(result, indices, std::move(argsVector));
|
|
287
|
+
return result;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
template<typename... Arg_Ts>
|
|
291
|
+
inline std::unique_ptr<Return> Native::create_return(Arg_Ts& ...args)
|
|
292
|
+
{
|
|
293
|
+
using Arg_Tuple = std::tuple<Arg_Ts...>;
|
|
294
|
+
|
|
295
|
+
constexpr std::size_t index = tuple_element_index_v<Arg_Tuple, Return, ReturnBuffer>;
|
|
296
|
+
|
|
297
|
+
std::unique_ptr<Return> result;
|
|
298
|
+
|
|
299
|
+
if constexpr (index < std::tuple_size_v<Arg_Tuple>)
|
|
300
|
+
{
|
|
301
|
+
using Return_T_Local = std::decay_t<std::tuple_element_t<index, Arg_Tuple>>;
|
|
302
|
+
const Return_T_Local& returnInfo = std::get<index>(std::forward_as_tuple(std::forward<Arg_Ts>(args)...));
|
|
303
|
+
result = std::make_unique<Return_T_Local>(returnInfo);
|
|
304
|
+
}
|
|
305
|
+
else
|
|
306
|
+
{
|
|
307
|
+
result = std::make_unique<Return>();
|
|
308
|
+
}
|
|
309
|
+
|
|
225
310
|
return result;
|
|
226
311
|
}
|
|
227
312
|
|
|
228
|
-
inline std::
|
|
313
|
+
inline std::map<std::string, VALUE> Native::readRubyArgs(size_t argc, const VALUE* argv)
|
|
229
314
|
{
|
|
230
|
-
|
|
231
|
-
int size = std::max(this->parameters_.size(), argc);
|
|
232
|
-
std::vector<std::optional<VALUE>> result(size);
|
|
315
|
+
std::map<std::string, VALUE> result;
|
|
233
316
|
|
|
234
317
|
// Keyword handling
|
|
235
318
|
if (rb_keyword_given_p())
|
|
236
319
|
{
|
|
237
320
|
// Keywords are stored in the last element in a hash
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
VALUE value = argv[actualArgc];
|
|
241
|
-
Hash keywords(value);
|
|
321
|
+
size_t actualArgc = argc - 1;
|
|
242
322
|
|
|
243
323
|
// Copy over leading non-keyword arguments
|
|
244
|
-
for (
|
|
324
|
+
for (size_t i = 0; i < actualArgc; i++)
|
|
245
325
|
{
|
|
246
|
-
|
|
326
|
+
std::string key = "arg_" + std::to_string(i);
|
|
327
|
+
result[key] = argv[i];
|
|
247
328
|
}
|
|
248
329
|
|
|
330
|
+
VALUE value = argv[actualArgc];
|
|
331
|
+
Hash keywords(value);
|
|
332
|
+
|
|
249
333
|
// Copy over keyword arguments
|
|
250
334
|
for (auto pair : keywords)
|
|
251
335
|
{
|
|
252
|
-
|
|
253
|
-
ParameterAbstract* parameter = this->getParameterByName(key.str());
|
|
254
|
-
if (!parameter)
|
|
255
|
-
{
|
|
256
|
-
throw std::invalid_argument("Unknown keyword: " + key.str());
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
const Arg* arg = parameter->arg;
|
|
260
|
-
|
|
261
|
-
result[arg->position] = pair.second.value();
|
|
336
|
+
result[pair.first.to_s().str()] = pair.second.value();
|
|
262
337
|
}
|
|
263
338
|
}
|
|
264
339
|
else
|
|
265
340
|
{
|
|
266
|
-
|
|
341
|
+
// Copy over leading non-keyword arguments
|
|
342
|
+
for (size_t i = 0; i < argc; i++)
|
|
343
|
+
{
|
|
344
|
+
std::string key = "arg_" + std::to_string(i);
|
|
345
|
+
result[key] = argv[i];
|
|
346
|
+
}
|
|
267
347
|
}
|
|
268
348
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
349
|
+
return result;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
inline std::vector<std::optional<VALUE>> Native::getRubyValues(std::map<std::string, VALUE> values, bool validate)
|
|
353
|
+
{
|
|
354
|
+
// !!!NOTE!!! We copied the values parameter because we are going to modify it!
|
|
355
|
+
|
|
356
|
+
// Protect against user sending too many arguments
|
|
357
|
+
if (values.size() > this->parameters_.size())
|
|
272
358
|
{
|
|
273
|
-
|
|
274
|
-
|
|
359
|
+
std::string message = "wrong number of arguments (given " +
|
|
360
|
+
std::to_string(values.size()) + ", expected " + std::to_string(this->parameters_.size()) + ")";
|
|
361
|
+
throw std::invalid_argument(message);
|
|
275
362
|
}
|
|
276
363
|
|
|
277
|
-
|
|
364
|
+
std::vector<std::optional<VALUE>> result(this->parameters_.size());
|
|
365
|
+
|
|
366
|
+
for (size_t i=0; i< this->parameters_.size(); i++)
|
|
278
367
|
{
|
|
279
|
-
|
|
280
|
-
|
|
368
|
+
std::unique_ptr<ParameterAbstract>& parameter = this->parameters_[i];
|
|
369
|
+
Arg* arg = parameter->arg();
|
|
370
|
+
|
|
371
|
+
// If using keywords arguments, then the value key will be arg->name(). If using positional
|
|
372
|
+
// arguments then they key will be "arg_<position>"
|
|
373
|
+
std::string keywordKey = arg->name;
|
|
374
|
+
std::string positionKey = "arg_" + std::to_string(i);
|
|
375
|
+
|
|
376
|
+
auto iter = values.find(keywordKey);
|
|
377
|
+
if (iter == values.end() && keywordKey != positionKey)
|
|
281
378
|
{
|
|
282
|
-
|
|
283
|
-
std::to_string(argc) + ", expected " + std::to_string(this->parameters_.size()) + ")";
|
|
284
|
-
throw std::invalid_argument(message);
|
|
379
|
+
iter = values.find(positionKey);
|
|
285
380
|
}
|
|
286
381
|
|
|
287
|
-
|
|
382
|
+
if (iter != values.end())
|
|
383
|
+
{
|
|
384
|
+
result[i] = iter->second;
|
|
385
|
+
// Remove the value
|
|
386
|
+
values.erase(iter);
|
|
387
|
+
}
|
|
388
|
+
else if (arg->hasDefaultValue())
|
|
288
389
|
{
|
|
289
|
-
|
|
290
|
-
|
|
390
|
+
result[i] = parameter->defaultValueRuby();
|
|
391
|
+
}
|
|
392
|
+
else if (arg->isBlock() && rb_block_given_p())
|
|
393
|
+
{
|
|
394
|
+
result[i] = protect(rb_block_proc);
|
|
395
|
+
}
|
|
396
|
+
else if (validate)
|
|
397
|
+
{
|
|
398
|
+
std::string message = "Missing argument. Name: " + arg->name + ". Index: " + std::to_string(i) + ".";
|
|
399
|
+
throw std::invalid_argument(message);
|
|
400
|
+
}
|
|
401
|
+
else
|
|
402
|
+
{
|
|
403
|
+
// No point in continuing - this native is not going to match
|
|
404
|
+
return result;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
291
407
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
408
|
+
// Check for unknown arguments
|
|
409
|
+
if (validate && values.size() > 0)
|
|
410
|
+
{
|
|
411
|
+
// There are unknown arguments
|
|
412
|
+
std::ostringstream message;
|
|
413
|
+
message << "Unknown argument(s): ";
|
|
414
|
+
size_t count = 0;
|
|
415
|
+
for (const std::pair<const std::string, VALUE>& pair : values)
|
|
416
|
+
{
|
|
417
|
+
if (count > 0)
|
|
418
|
+
message << ", ";
|
|
419
|
+
message << pair.first;
|
|
420
|
+
count++;
|
|
298
421
|
}
|
|
422
|
+
throw std::invalid_argument(message.str());
|
|
299
423
|
}
|
|
300
424
|
|
|
301
425
|
return result;
|
|
302
426
|
}
|
|
303
427
|
|
|
304
|
-
inline
|
|
428
|
+
inline double Native::matchParameters(std::vector<std::optional<VALUE>>& values, size_t argc)
|
|
305
429
|
{
|
|
306
|
-
|
|
307
|
-
|
|
430
|
+
// Only score arguments actually passed (not defaults)
|
|
431
|
+
double minScore = Convertible::Exact;
|
|
432
|
+
|
|
433
|
+
for (size_t i = 0; i < argc && i < this->parameters_.size(); i++)
|
|
308
434
|
{
|
|
309
435
|
ParameterAbstract* parameter = this->parameters_[i].get();
|
|
310
436
|
std::optional<VALUE>& value = values[i];
|
|
311
|
-
|
|
437
|
+
double score = parameter->matches(value);
|
|
438
|
+
minScore = (std::min)(minScore, score);
|
|
312
439
|
}
|
|
313
|
-
|
|
440
|
+
|
|
441
|
+
return minScore;
|
|
314
442
|
}
|
|
315
443
|
|
|
316
|
-
inline Resolved Native::matches(
|
|
444
|
+
inline Resolved Native::matches(std::map<std::string, VALUE>& values)
|
|
317
445
|
{
|
|
318
|
-
// Return
|
|
319
|
-
if (
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
446
|
+
// Return Convertible::None if Ruby provided more arguments than the C++ method takes
|
|
447
|
+
if (values.size() > this->parameters_.size())
|
|
448
|
+
{
|
|
449
|
+
return Resolved{ Convertible::None, this };
|
|
450
|
+
}
|
|
323
451
|
|
|
324
|
-
|
|
325
|
-
|
|
452
|
+
// Get Ruby values for each parameter and see how they match
|
|
453
|
+
std::vector<std::optional<VALUE>> rubyValues = this->getRubyValues(values, false);
|
|
454
|
+
double minScore = this->matchParameters(rubyValues, values.size());
|
|
326
455
|
|
|
327
|
-
|
|
456
|
+
// If zero score return then stop
|
|
457
|
+
if (minScore == 0)
|
|
328
458
|
{
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
return value.has_value();
|
|
332
|
-
});
|
|
459
|
+
return Resolved{ Convertible::None, this };
|
|
460
|
+
}
|
|
333
461
|
|
|
334
|
-
|
|
462
|
+
// How many actual values do we have?
|
|
463
|
+
size_t actualValuesCount = std::count_if(rubyValues.begin(), rubyValues.end(),
|
|
464
|
+
[](std::optional<VALUE>& optional)
|
|
465
|
+
{
|
|
466
|
+
return optional.has_value();
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
// If we don't have enough parameters return
|
|
470
|
+
if (actualValuesCount < this->parameters_.size())
|
|
471
|
+
return Resolved{ Convertible::None, this };
|
|
472
|
+
|
|
473
|
+
// Penalize use of default parameters
|
|
474
|
+
double parameterMatch = Convertible::Exact;
|
|
475
|
+
size_t defaultParameterCount = actualValuesCount - values.size();
|
|
476
|
+
for (size_t i = 0; i < defaultParameterCount; i++)
|
|
477
|
+
{
|
|
478
|
+
parameterMatch *= 0.99; // Small penalty per default used
|
|
335
479
|
}
|
|
336
|
-
|
|
480
|
+
|
|
481
|
+
// Final score: minScore * parameterMatch
|
|
482
|
+
double finalScore = minScore * parameterMatch;
|
|
483
|
+
|
|
484
|
+
return Resolved{ finalScore, this };
|
|
337
485
|
}
|
|
338
486
|
|
|
339
487
|
inline std::vector<const ParameterAbstract*> Native::parameters()
|