rice 4.7.1 → 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 +29 -1
- data/CMakeLists.txt +14 -22
- data/CMakePresets.json +203 -75
- data/FindRuby.cmake +358 -123
- data/bin/rice-doc.rb +56 -141
- data/include/rice/api.hpp +248 -0
- data/include/rice/rice.hpp +2237 -1657
- data/include/rice/stl.hpp +346 -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 +2 -2
- 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 +15 -15
- 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 +41 -4
- 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 +7 -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 +282 -130
- 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/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 +1 -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 -3
- 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 +1 -1
- data/test/test_Data_Type.cpp +21 -22
- 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 +4 -3
- 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 +345 -48
- 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 +4 -2
- 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 +1 -1
- 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 -10
- 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.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
|
-
The Convertible field is an enum that specifies if the types of the values supplied by Ruby
|
|
40
|
-
match the types of the C++ function parameters. Allowed values include can be Exact (example Ruby into to C++ int),
|
|
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:
|
|
42
24
|
|
|
43
|
-
|
|
44
|
-
number of arguments required by C++. These numbers can be different because C++ method
|
|
45
|
-
parameters can have default values.
|
|
25
|
+
score = minParameterScore * parameterMatch
|
|
46
26
|
|
|
47
|
-
|
|
48
|
-
|
|
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).
|
|
31
|
+
|
|
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,8 +47,10 @@ 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
|
{
|
|
52
|
+
std::map<std::string, VALUE> values = readRubyArgs(argc, argv);
|
|
53
|
+
|
|
69
54
|
const std::vector<std::unique_ptr<Native>>& natives = Registries::instance.natives.lookup(klass, methodId);
|
|
70
55
|
|
|
71
56
|
if (natives.size() == 1)
|
|
@@ -87,7 +72,7 @@ namespace Rice::detail
|
|
|
87
72
|
std::back_inserter(resolves),
|
|
88
73
|
[&](const std::unique_ptr<Native>& native)
|
|
89
74
|
{
|
|
90
|
-
return native->matches(
|
|
75
|
+
return native->matches(values);
|
|
91
76
|
});
|
|
92
77
|
|
|
93
78
|
// Now sort from best to worst
|
|
@@ -118,7 +103,7 @@ namespace Rice::detail
|
|
|
118
103
|
}*/
|
|
119
104
|
|
|
120
105
|
// Did it match?
|
|
121
|
-
if (resolved.
|
|
106
|
+
if (resolved.score > Convertible::None)
|
|
122
107
|
{
|
|
123
108
|
native = resolved.native;
|
|
124
109
|
}
|
|
@@ -147,19 +132,34 @@ namespace Rice::detail
|
|
|
147
132
|
}
|
|
148
133
|
|
|
149
134
|
// Call the C++ function
|
|
150
|
-
return (*native)(
|
|
135
|
+
return (*native)(values, self);
|
|
151
136
|
});
|
|
152
137
|
}
|
|
153
138
|
|
|
154
|
-
inline Native::Native(std::
|
|
139
|
+
inline Native::Native(std::string name) :
|
|
140
|
+
name_(name)
|
|
155
141
|
{
|
|
156
142
|
}
|
|
157
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))
|
|
151
|
+
{
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
inline std::string Native::name()
|
|
155
|
+
{
|
|
156
|
+
return this->name_;
|
|
157
|
+
}
|
|
158
158
|
inline ParameterAbstract* Native::getParameterByName(std::string name)
|
|
159
159
|
{
|
|
160
160
|
for (std::unique_ptr<ParameterAbstract>& parameter : this->parameters_)
|
|
161
161
|
{
|
|
162
|
-
if (parameter->arg->name == name)
|
|
162
|
+
if (parameter->arg()->name == name)
|
|
163
163
|
{
|
|
164
164
|
return parameter.get();
|
|
165
165
|
}
|
|
@@ -168,168 +168,320 @@ namespace Rice::detail
|
|
|
168
168
|
return nullptr;
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
|
|
172
|
-
template<typename T>
|
|
173
|
-
inline void Native::verify_type(bool isBuffer)
|
|
171
|
+
inline void Native::checkKeepAlive(VALUE self, VALUE returnValue, std::vector<std::optional<VALUE>>& rubyValues)
|
|
174
172
|
{
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
detail::verifyType<T>();
|
|
178
|
-
|
|
179
|
-
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++)
|
|
180
175
|
{
|
|
181
|
-
|
|
182
|
-
|
|
176
|
+
Arg* arg = parameters_[i]->arg();
|
|
177
|
+
if (arg->isKeepAlive())
|
|
178
|
+
{
|
|
179
|
+
static WrapperBase* selfWrapper = getWrapper(self);
|
|
180
|
+
selfWrapper->addKeepAlive(rubyValues[i].value());
|
|
181
|
+
}
|
|
183
182
|
}
|
|
184
|
-
|
|
183
|
+
|
|
184
|
+
// Check return value
|
|
185
|
+
if (this->returnInfo_->isKeepAlive())
|
|
185
186
|
{
|
|
186
|
-
|
|
187
|
-
|
|
187
|
+
WrapperBase* returnWrapper = getWrapper(returnValue);
|
|
188
|
+
returnWrapper->addKeepAlive(self);
|
|
188
189
|
}
|
|
189
|
-
|
|
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>)
|
|
190
199
|
{
|
|
191
|
-
|
|
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)
|
|
192
203
|
{
|
|
193
204
|
Type<Pointer<Base_T>>::verify();
|
|
194
|
-
Type<Buffer<Base_T>>::verify();
|
|
195
205
|
}
|
|
196
|
-
|
|
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>)
|
|
197
212
|
{
|
|
198
|
-
|
|
213
|
+
Type<Reference<Base_T>>::verify();
|
|
199
214
|
}
|
|
200
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
|
+
}
|
|
201
222
|
}
|
|
202
223
|
|
|
203
|
-
template<typename
|
|
204
|
-
inline void Native::
|
|
224
|
+
template<typename Parameter_Tuple, typename Arg_Tuple, size_t I>
|
|
225
|
+
inline void Native::verify_parameter()
|
|
205
226
|
{
|
|
206
|
-
|
|
207
|
-
|
|
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
|
+
};
|
|
208
238
|
|
|
209
|
-
template<typename
|
|
210
|
-
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)
|
|
211
241
|
{
|
|
212
|
-
|
|
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])))), ...);
|
|
213
248
|
}
|
|
214
249
|
|
|
215
|
-
template<typename
|
|
216
|
-
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)
|
|
217
252
|
{
|
|
218
253
|
std::vector<std::unique_ptr<ParameterAbstract>> result;
|
|
219
|
-
|
|
220
|
-
|
|
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));
|
|
221
287
|
return result;
|
|
222
288
|
}
|
|
223
289
|
|
|
224
|
-
|
|
290
|
+
template<typename... Arg_Ts>
|
|
291
|
+
inline std::unique_ptr<Return> Native::create_return(Arg_Ts& ...args)
|
|
225
292
|
{
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
std::
|
|
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
|
+
|
|
310
|
+
return result;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
inline std::map<std::string, VALUE> Native::readRubyArgs(size_t argc, const VALUE* argv)
|
|
314
|
+
{
|
|
315
|
+
std::map<std::string, VALUE> result;
|
|
229
316
|
|
|
230
317
|
// Keyword handling
|
|
231
318
|
if (rb_keyword_given_p())
|
|
232
319
|
{
|
|
233
320
|
// Keywords are stored in the last element in a hash
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
VALUE value = argv[actualArgc];
|
|
237
|
-
Hash keywords(value);
|
|
321
|
+
size_t actualArgc = argc - 1;
|
|
238
322
|
|
|
239
323
|
// Copy over leading non-keyword arguments
|
|
240
|
-
for (
|
|
324
|
+
for (size_t i = 0; i < actualArgc; i++)
|
|
241
325
|
{
|
|
242
|
-
|
|
326
|
+
std::string key = "arg_" + std::to_string(i);
|
|
327
|
+
result[key] = argv[i];
|
|
243
328
|
}
|
|
244
329
|
|
|
330
|
+
VALUE value = argv[actualArgc];
|
|
331
|
+
Hash keywords(value);
|
|
332
|
+
|
|
245
333
|
// Copy over keyword arguments
|
|
246
334
|
for (auto pair : keywords)
|
|
247
335
|
{
|
|
248
|
-
|
|
249
|
-
ParameterAbstract* parameter = this->getParameterByName(key.str());
|
|
250
|
-
if (!parameter)
|
|
251
|
-
{
|
|
252
|
-
throw std::invalid_argument("Unknown keyword: " + key.str());
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const Arg* arg = parameter->arg;
|
|
256
|
-
|
|
257
|
-
result[arg->position] = pair.second.value();
|
|
336
|
+
result[pair.first.to_s().str()] = pair.second.value();
|
|
258
337
|
}
|
|
259
338
|
}
|
|
260
339
|
else
|
|
261
340
|
{
|
|
262
|
-
|
|
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
|
+
}
|
|
263
347
|
}
|
|
264
348
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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())
|
|
268
358
|
{
|
|
269
|
-
|
|
270
|
-
|
|
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);
|
|
271
362
|
}
|
|
272
363
|
|
|
273
|
-
|
|
364
|
+
std::vector<std::optional<VALUE>> result(this->parameters_.size());
|
|
365
|
+
|
|
366
|
+
for (size_t i=0; i< this->parameters_.size(); i++)
|
|
274
367
|
{
|
|
275
|
-
|
|
276
|
-
|
|
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)
|
|
277
378
|
{
|
|
278
|
-
|
|
279
|
-
std::to_string(argc) + ", expected " + std::to_string(this->parameters_.size()) + ")";
|
|
280
|
-
throw std::invalid_argument(message);
|
|
379
|
+
iter = values.find(positionKey);
|
|
281
380
|
}
|
|
282
381
|
|
|
283
|
-
|
|
382
|
+
if (iter != values.end())
|
|
284
383
|
{
|
|
285
|
-
|
|
286
|
-
|
|
384
|
+
result[i] = iter->second;
|
|
385
|
+
// Remove the value
|
|
386
|
+
values.erase(iter);
|
|
387
|
+
}
|
|
388
|
+
else if (arg->hasDefaultValue())
|
|
389
|
+
{
|
|
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
|
+
}
|
|
287
407
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
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++;
|
|
294
421
|
}
|
|
422
|
+
throw std::invalid_argument(message.str());
|
|
295
423
|
}
|
|
296
424
|
|
|
297
425
|
return result;
|
|
298
426
|
}
|
|
299
427
|
|
|
300
|
-
inline
|
|
428
|
+
inline double Native::matchParameters(std::vector<std::optional<VALUE>>& values, size_t argc)
|
|
301
429
|
{
|
|
302
|
-
|
|
303
|
-
|
|
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++)
|
|
304
434
|
{
|
|
305
435
|
ParameterAbstract* parameter = this->parameters_[i].get();
|
|
306
436
|
std::optional<VALUE>& value = values[i];
|
|
307
|
-
|
|
437
|
+
double score = parameter->matches(value);
|
|
438
|
+
minScore = (std::min)(minScore, score);
|
|
308
439
|
}
|
|
309
|
-
|
|
440
|
+
|
|
441
|
+
return minScore;
|
|
310
442
|
}
|
|
311
443
|
|
|
312
|
-
inline Resolved Native::matches(
|
|
444
|
+
inline Resolved Native::matches(std::map<std::string, VALUE>& values)
|
|
313
445
|
{
|
|
314
|
-
// Return
|
|
315
|
-
if (
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
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
|
+
}
|
|
319
451
|
|
|
320
|
-
|
|
321
|
-
|
|
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());
|
|
322
455
|
|
|
323
|
-
|
|
456
|
+
// If zero score return then stop
|
|
457
|
+
if (minScore == 0)
|
|
324
458
|
{
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
return value.has_value();
|
|
328
|
-
});
|
|
459
|
+
return Resolved{ Convertible::None, this };
|
|
460
|
+
}
|
|
329
461
|
|
|
330
|
-
|
|
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
|
|
331
479
|
}
|
|
332
|
-
|
|
480
|
+
|
|
481
|
+
// Final score: minScore * parameterMatch
|
|
482
|
+
double finalScore = minScore * parameterMatch;
|
|
483
|
+
|
|
484
|
+
return Resolved{ finalScore, this };
|
|
333
485
|
}
|
|
334
486
|
|
|
335
487
|
inline std::vector<const ParameterAbstract*> Native::parameters()
|
|
@@ -24,7 +24,8 @@ namespace Rice
|
|
|
24
24
|
|
|
25
25
|
public:
|
|
26
26
|
// Register attribute getter with Ruby
|
|
27
|
-
|
|
27
|
+
template<typename...Arg_Ts>
|
|
28
|
+
static void define(VALUE klass, std::string name, Attribute_T attribute, Arg_Ts&...args);
|
|
28
29
|
|
|
29
30
|
public:
|
|
30
31
|
// Disallow creating/copying/moving
|
|
@@ -34,22 +35,19 @@ namespace Rice
|
|
|
34
35
|
void operator=(const NativeAttribute_T&) = delete;
|
|
35
36
|
void operator=(NativeAttribute_T&&) = delete;
|
|
36
37
|
|
|
37
|
-
Resolved matches(
|
|
38
|
-
VALUE operator()(
|
|
38
|
+
Resolved matches(std::map<std::string, VALUE>& values) override;
|
|
39
|
+
VALUE operator()(std::map<std::string, VALUE>& values, VALUE self) override;
|
|
39
40
|
std::string toString() override;
|
|
40
41
|
|
|
41
|
-
std::string name() override;
|
|
42
42
|
NativeKind kind() override;
|
|
43
43
|
VALUE returnKlass() override;
|
|
44
44
|
|
|
45
45
|
protected:
|
|
46
|
-
NativeAttributeGet(VALUE klass, std::string name, Attribute_T attr, Return returnInfo);
|
|
46
|
+
NativeAttributeGet(VALUE klass, std::string name, Attribute_T attr, std::unique_ptr<Return>&& returnInfo);
|
|
47
47
|
|
|
48
48
|
private:
|
|
49
49
|
VALUE klass_;
|
|
50
|
-
std::string name_;
|
|
51
50
|
Attribute_T attribute_;
|
|
52
|
-
Return return_;
|
|
53
51
|
};
|
|
54
52
|
} // detail
|
|
55
53
|
} // Rice
|