rice 4.6.0 → 4.7.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 +41 -0
- data/CMakeLists.txt +0 -4
- data/Rakefile +2 -8
- data/bin/rice-doc.rb +212 -0
- data/bin/rice-rbs.rb +93 -0
- data/include/rice/rice.hpp +5221 -4009
- data/include/rice/stl.hpp +822 -295
- data/lib/rice/doc/cpp_reference.rb +166 -0
- data/lib/rice/doc/doxygen.rb +294 -0
- data/lib/rice/doc/mkdocs.rb +298 -0
- data/lib/rice/doc/rice.rb +29 -0
- data/lib/rice/doc/ruby.rb +37 -0
- data/lib/rice/doc.rb +5 -0
- data/lib/{make_rice_headers.rb → rice/make_rice_headers.rb} +3 -0
- data/lib/rice/native.rb +18 -0
- data/lib/rice/native_registry.rb +21 -0
- data/lib/rice/parameter.rb +7 -0
- data/lib/rice/rbs.rb +104 -0
- data/lib/rice/version.rb +1 -1
- data/lib/rice.rb +4 -0
- data/lib/rubygems/cmake_builder.rb +24 -27
- data/rice/Arg.hpp +4 -4
- data/rice/Arg.ipp +4 -4
- data/rice/Buffer.hpp +77 -28
- data/rice/Buffer.ipp +500 -183
- data/rice/Data_Object.ipp +101 -82
- data/rice/Data_Type.hpp +7 -6
- data/rice/Data_Type.ipp +77 -47
- data/rice/Enum.ipp +15 -21
- data/rice/Function.hpp +17 -0
- data/rice/Function.ipp +13 -0
- data/rice/Pointer.hpp +15 -0
- data/rice/Pointer.ipp +49 -0
- data/rice/Return.hpp +1 -1
- data/rice/Return.ipp +2 -2
- data/rice/api.hpp +30 -0
- data/rice/cpp_api/Array.hpp +2 -2
- data/rice/cpp_api/Array.ipp +50 -5
- data/rice/cpp_api/Class.hpp +0 -5
- data/rice/cpp_api/Class.ipp +19 -0
- data/rice/cpp_api/Hash.ipp +20 -0
- data/rice/cpp_api/Module.hpp +6 -3
- data/rice/cpp_api/Module.ipp +49 -11
- data/rice/cpp_api/Object.ipp +31 -2
- data/rice/cpp_api/String.hpp +1 -2
- data/rice/cpp_api/String.ipp +21 -1
- data/rice/cpp_api/Struct.ipp +5 -0
- data/rice/cpp_api/Symbol.ipp +34 -0
- data/rice/cpp_api/shared_methods.hpp +12 -12
- data/rice/detail/MethodInfo.hpp +4 -2
- data/rice/detail/MethodInfo.ipp +19 -3
- data/rice/detail/ModuleRegistry.hpp +18 -0
- data/rice/detail/ModuleRegistry.ipp +25 -0
- data/rice/detail/Native.hpp +45 -2
- data/rice/detail/Native.ipp +196 -2
- data/rice/detail/NativeAttributeGet.hpp +9 -4
- data/rice/detail/NativeAttributeGet.ipp +73 -8
- data/rice/detail/NativeAttributeSet.hpp +4 -0
- data/rice/detail/NativeAttributeSet.ipp +33 -23
- data/rice/detail/NativeCallbackFFI.ipp +3 -2
- data/rice/detail/NativeCallbackSimple.ipp +1 -1
- data/rice/detail/NativeFunction.hpp +11 -49
- data/rice/detail/NativeFunction.ipp +83 -379
- data/rice/detail/NativeInvoker.hpp +74 -0
- data/rice/detail/NativeInvoker.ipp +197 -0
- data/rice/detail/NativeIterator.hpp +4 -0
- data/rice/detail/NativeIterator.ipp +19 -0
- data/rice/detail/NativeMethod.hpp +97 -0
- data/rice/detail/NativeMethod.ipp +332 -0
- data/rice/detail/NativeProc.hpp +51 -0
- data/rice/detail/NativeProc.ipp +133 -0
- data/rice/detail/NativeRegistry.hpp +8 -0
- data/rice/detail/NativeRegistry.ipp +27 -0
- data/rice/detail/Parameter.hpp +47 -0
- data/rice/detail/Parameter.ipp +105 -0
- data/rice/detail/Proc.ipp +14 -13
- data/rice/detail/Registries.hpp +1 -0
- data/rice/detail/RubyType.hpp +0 -2
- data/rice/detail/RubyType.ipp +15 -33
- data/rice/detail/Type.hpp +44 -8
- data/rice/detail/Type.ipp +150 -49
- data/rice/detail/TypeRegistry.hpp +3 -0
- data/rice/detail/TypeRegistry.ipp +17 -27
- data/rice/detail/Types.ipp +430 -0
- data/rice/detail/Wrapper.hpp +12 -0
- data/rice/detail/Wrapper.ipp +45 -2
- data/rice/detail/from_ruby.ipp +567 -1073
- data/rice/detail/ruby.hpp +1 -0
- data/rice/detail/to_ruby.ipp +4 -635
- data/rice/libc/file.ipp +3 -6
- data/rice/rice.hpp +22 -12
- data/rice/rice_api/Arg.hpp +7 -0
- data/rice/rice_api/Arg.ipp +9 -0
- data/rice/rice_api/ModuleRegistry.hpp +7 -0
- data/rice/rice_api/ModuleRegistry.ipp +10 -0
- data/rice/rice_api/Native.hpp +7 -0
- data/rice/rice_api/Native.ipp +52 -0
- data/rice/rice_api/NativeRegistry.hpp +7 -0
- data/rice/rice_api/NativeRegistry.ipp +21 -0
- data/rice/rice_api/Parameter.hpp +7 -0
- data/rice/rice_api/Parameter.ipp +11 -0
- data/rice/rice_api/Registries.hpp +6 -0
- data/rice/rice_api/Registries.ipp +12 -0
- data/rice/rice_api/TypeRegistry.hpp +7 -0
- data/rice/rice_api/TypeRegistry.ipp +10 -0
- data/rice/stl/complex.ipp +35 -0
- data/rice/stl/exception.ipp +20 -7
- data/rice/stl/filesystem.hpp +6 -0
- data/rice/stl/filesystem.ipp +34 -0
- data/rice/stl/map.ipp +13 -21
- data/rice/stl/monostate.ipp +37 -1
- data/rice/stl/multimap.ipp +17 -24
- data/rice/stl/optional.ipp +47 -2
- data/rice/stl/pair.ipp +23 -58
- data/rice/stl/reference_wrapper.ipp +22 -1
- data/rice/stl/set.ipp +17 -9
- data/rice/stl/shared_ptr.ipp +44 -17
- data/rice/stl/string.ipp +175 -7
- data/rice/stl/string_view.ipp +5 -0
- data/rice/stl/tuple.ipp +38 -9
- data/rice/stl/unique_ptr.ipp +46 -2
- data/rice/stl/unordered_map.ipp +13 -21
- data/rice/stl/variant.ipp +47 -11
- data/rice/stl/vector.ipp +182 -104
- data/rice/stl.hpp +1 -0
- data/rice/traits/attribute_traits.hpp +6 -6
- data/rice/traits/function_traits.hpp +2 -2
- data/rice/traits/method_traits.hpp +5 -16
- data/rice/traits/rice_traits.hpp +36 -4
- data/rice.gemspec +11 -22
- data/test/embed_ruby.cpp +0 -3
- data/test/test_Array.cpp +38 -38
- data/test/test_Attribute.cpp +244 -10
- data/test/test_Buffer.cpp +344 -13
- data/test/test_Callback.cpp +2 -3
- data/test/test_Class.cpp +5 -5
- data/test/test_Data_Object.cpp +0 -55
- data/test/test_Data_Type.cpp +19 -30
- data/test/test_Enum.cpp +4 -46
- data/test/test_From_Ruby.cpp +89 -82
- data/test/test_GVL.cpp +109 -0
- data/test/test_Iterator.cpp +1 -1
- data/test/test_Keep_Alive_No_Wrapper.cpp +5 -3
- data/test/test_Module.cpp +8 -9
- data/test/test_Object.cpp +1 -1
- data/test/test_Overloads.cpp +3 -3
- data/test/test_Stl_Map.cpp +8 -8
- data/test/test_Stl_Multimap.cpp +4 -4
- data/test/test_Stl_Pair.cpp +5 -3
- data/test/test_Stl_SharedPtr.cpp +24 -12
- data/test/test_Stl_Tuple.cpp +1 -1
- data/test/test_Stl_UniquePtr.cpp +8 -0
- data/test/test_Stl_Unordered_Map.cpp +9 -9
- data/test/test_Stl_Variant.cpp +9 -3
- data/test/test_Stl_Vector.cpp +118 -13
- data/test/test_To_Ruby.cpp +35 -28
- data/test/test_Type.cpp +256 -53
- data/test/unittest.hpp +35 -0
- metadata +66 -34
- data/rice/Init.hpp +0 -8
- data/rice/Init.ipp +0 -8
- data/rice/detail/RubyFunction.hpp +0 -31
- data/rice/detail/RubyFunction.ipp +0 -76
- data/sample/callbacks/extconf.rb +0 -5
- data/sample/callbacks/sample_callbacks.cpp +0 -35
- data/sample/callbacks/test.rb +0 -28
- data/sample/enum/extconf.rb +0 -5
- data/sample/enum/sample_enum.cpp +0 -40
- data/sample/enum/test.rb +0 -8
- data/sample/inheritance/animals.cpp +0 -82
- data/sample/inheritance/extconf.rb +0 -5
- data/sample/inheritance/test.rb +0 -7
- data/sample/map/extconf.rb +0 -5
- data/sample/map/map.cpp +0 -73
- data/sample/map/test.rb +0 -7
- data/test/ext/t1/Foo.hpp +0 -10
- data/test/ext/t1/extconf.rb +0 -4
- data/test/ext/t1/t1.cpp +0 -13
- data/test/ext/t2/extconf.rb +0 -4
- data/test/ext/t2/t2.cpp +0 -11
- data/test/ruby/test_callbacks_sample.rb +0 -28
- data/test/ruby/test_multiple_extensions.rb +0 -18
- data/test/ruby/test_multiple_extensions_same_class.rb +0 -14
- data/test/ruby/test_multiple_extensions_with_inheritance.rb +0 -20
- /data/test/{test_Stl_Type.cpp → test_Stl_Type_Info.cpp} +0 -0
|
@@ -2,12 +2,18 @@
|
|
|
2
2
|
#include <array>
|
|
3
3
|
#include <stdexcept>
|
|
4
4
|
#include <sstream>
|
|
5
|
+
#include <tuple>
|
|
5
6
|
|
|
6
7
|
namespace Rice::detail
|
|
7
8
|
{
|
|
8
|
-
template<typename
|
|
9
|
-
void NativeFunction<
|
|
9
|
+
template<typename Function_T>
|
|
10
|
+
void NativeFunction<Function_T>::define(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo)
|
|
10
11
|
{
|
|
12
|
+
// Verify return and argument types
|
|
13
|
+
Native::verify_type<Return_T>(methodInfo->returnInfo()->isBuffer());
|
|
14
|
+
auto indices = std::make_index_sequence<std::tuple_size_v<Arg_Ts>>{};
|
|
15
|
+
Native::verify_args<Arg_Ts>(methodInfo, indices);
|
|
16
|
+
|
|
11
17
|
// Have we defined this method yet in Ruby?
|
|
12
18
|
Identifier identifier(method_name);
|
|
13
19
|
const std::vector<std::unique_ptr<Native>>& natives = Registries::instance.natives.lookup(klass, identifier.id());
|
|
@@ -24,68 +30,33 @@ namespace Rice::detail
|
|
|
24
30
|
detail::Registries::instance.natives.add(klass, identifier.id(), native);
|
|
25
31
|
}
|
|
26
32
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
{
|
|
33
|
-
NativeFunction_T * native = (NativeFunction_T*)callback_arg;
|
|
34
|
-
return (*native)(argc, argv, Qnil);
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Ruby calls this method if an instance f a NativeFunction is owned by a Ruby proc. That happens when C++
|
|
39
|
-
// returns a function back to Ruby
|
|
40
|
-
template<typename Class_T, typename Function_T, bool IsMethod>
|
|
41
|
-
VALUE NativeFunction<Class_T, Function_T, IsMethod>::finalizerCallback(VALUE yielded_arg, VALUE callback_arg, int argc, const VALUE* argv, VALUE blockarg)
|
|
33
|
+
template<typename Function_T>
|
|
34
|
+
NativeFunction<Function_T>::NativeFunction(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo)
|
|
35
|
+
: Native(Native::create_parameters<Arg_Ts>(methodInfo)),
|
|
36
|
+
klass_(klass), method_name_(method_name), function_(function), methodInfo_(methodInfo),
|
|
37
|
+
toRuby_(methodInfo->returnInfo())
|
|
42
38
|
{
|
|
43
|
-
NativeFunction_T* native = (NativeFunction_T*)callback_arg;
|
|
44
|
-
delete native;
|
|
45
|
-
return Qnil;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
template<typename Class_T, typename Function_T, bool IsMethod>
|
|
49
|
-
NativeFunction<Class_T, Function_T, IsMethod>::NativeFunction(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo)
|
|
50
|
-
: klass_(klass), method_name_(method_name), function_(function), methodInfo_(methodInfo)
|
|
51
|
-
{
|
|
52
|
-
// Create a tuple of NativeArgs that will convert the Ruby values to native values. For
|
|
53
|
-
// builtin types NativeArgs will keep a copy of the native value so that it
|
|
54
|
-
// can be passed by reference or pointer to the native function. For non-builtin types
|
|
55
|
-
// it will just pass the value through.
|
|
56
|
-
auto indices = std::make_index_sequence<std::tuple_size_v<Arg_Ts>>{};
|
|
57
|
-
this->fromRubys_ = this->createFromRuby(indices);
|
|
58
|
-
|
|
59
|
-
this->toRuby_ = this->createToRuby();
|
|
60
39
|
}
|
|
61
40
|
|
|
62
|
-
template<typename
|
|
63
|
-
NativeFunction<Class_T, Function_T, IsMethod>::NativeFunction(Function_T function)
|
|
64
|
-
: NativeFunction(Qnil, "", function, new MethodInfo(arity))
|
|
65
|
-
{
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
template<typename Class_T, typename Function_T, bool IsMethod>
|
|
41
|
+
template<typename Function_T>
|
|
69
42
|
template<std::size_t... I>
|
|
70
|
-
std::vector<std::string> NativeFunction<
|
|
43
|
+
std::vector<std::string> NativeFunction<Function_T>::argTypeNames(std::ostringstream& stream, std::index_sequence<I...>& indices)
|
|
71
44
|
{
|
|
72
|
-
std::vector<std::string>
|
|
73
|
-
(
|
|
74
|
-
|
|
45
|
+
std::vector<std::string> result;
|
|
46
|
+
for (std::unique_ptr<ParameterAbstract>& parameter : this->parameters_)
|
|
47
|
+
{
|
|
48
|
+
result.push_back(parameter->cppTypeName());
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
75
51
|
}
|
|
76
52
|
|
|
77
|
-
template<typename
|
|
78
|
-
std::string NativeFunction<
|
|
53
|
+
template<typename Function_T>
|
|
54
|
+
std::string NativeFunction<Function_T>::toString()
|
|
79
55
|
{
|
|
80
56
|
std::ostringstream result;
|
|
81
57
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (!std::is_null_pointer_v<Receiver_T>)
|
|
85
|
-
{
|
|
86
|
-
result << cppClassName(typeName(typeid(Receiver_T))) << "::";
|
|
87
|
-
}
|
|
88
|
-
|
|
58
|
+
detail::TypeMapper<Return_T> typeMapper;
|
|
59
|
+
result << typeMapper.simplifiedName() << " ";
|
|
89
60
|
result << this->method_name_;
|
|
90
61
|
|
|
91
62
|
result << "(";
|
|
@@ -102,294 +73,24 @@ namespace Rice::detail
|
|
|
102
73
|
return result.str();
|
|
103
74
|
}
|
|
104
75
|
|
|
105
|
-
template<typename
|
|
106
|
-
To_Ruby<typename NativeFunction<Class_T, Function_T, IsMethod>::To_Ruby_T> NativeFunction<Class_T, Function_T, IsMethod>::createToRuby()
|
|
107
|
-
{
|
|
108
|
-
// Does the From_Ruby instantiation work with ReturnInfo?
|
|
109
|
-
if constexpr (std::is_constructible_v<To_Ruby<To_Ruby_T>, Return*>)
|
|
110
|
-
{
|
|
111
|
-
return To_Ruby<To_Ruby_T>(&this->methodInfo_->returnInfo);
|
|
112
|
-
}
|
|
113
|
-
else
|
|
114
|
-
{
|
|
115
|
-
return To_Ruby<To_Ruby_T>();
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
template<typename Class_T, typename Function_T, bool IsMethod>
|
|
120
|
-
template<typename T, std::size_t I>
|
|
121
|
-
From_Ruby<T> NativeFunction<Class_T, Function_T, IsMethod>::createFromRuby()
|
|
122
|
-
{
|
|
123
|
-
// Does the From_Ruby instantiation work with Arg?
|
|
124
|
-
if constexpr (std::is_constructible_v<From_Ruby<T>, Arg*>)
|
|
125
|
-
{
|
|
126
|
-
return From_Ruby<T>(this->methodInfo_->arg(I));
|
|
127
|
-
}
|
|
128
|
-
else
|
|
129
|
-
{
|
|
130
|
-
return From_Ruby<T>();
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
template<typename Class_T, typename Function_T, bool IsMethod>
|
|
135
|
-
template<std::size_t... I>
|
|
136
|
-
typename NativeFunction<Class_T, Function_T, IsMethod>::From_Ruby_Args_Ts NativeFunction<Class_T, Function_T, IsMethod>::createFromRuby(std::index_sequence<I...>& indices)
|
|
137
|
-
{
|
|
138
|
-
return std::make_tuple(createFromRuby<remove_cv_recursive_t<typename std::tuple_element<I, Arg_Ts>::type>, I>()...);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
template<typename Class_T, typename Function_T, bool IsMethod>
|
|
142
|
-
template<int I>
|
|
143
|
-
Convertible NativeFunction<Class_T, Function_T, IsMethod>::matchParameter(std::vector<std::optional<VALUE>>& values)
|
|
144
|
-
{
|
|
145
|
-
Convertible result = Convertible::None;
|
|
146
|
-
MethodInfo* methodInfo = this->methodInfo_.get();
|
|
147
|
-
const Arg* arg = methodInfo->arg(I);
|
|
148
|
-
std::optional<VALUE> value = values[I];
|
|
149
|
-
|
|
150
|
-
// Is a VALUE being passed directly to C++ ?
|
|
151
|
-
if (value.has_value())
|
|
152
|
-
{
|
|
153
|
-
if (arg->isValue())
|
|
154
|
-
{
|
|
155
|
-
result = Convertible::Exact;
|
|
156
|
-
}
|
|
157
|
-
// If index is less than argc then check with FromRuby if the VALUE is convertible
|
|
158
|
-
// to C++.
|
|
159
|
-
else
|
|
160
|
-
{
|
|
161
|
-
VALUE value = values[I].value();
|
|
162
|
-
auto fromRuby = std::get<I>(this->fromRubys_);
|
|
163
|
-
result = fromRuby.is_convertible(value);
|
|
164
|
-
|
|
165
|
-
// If this is an exact match check if the const-ness of the value and the parameter match
|
|
166
|
-
if (result == Convertible::Exact && rb_type(value) == RUBY_T_DATA)
|
|
167
|
-
{
|
|
168
|
-
// Check the constness of the Ruby wrapped value and the parameter
|
|
169
|
-
WrapperBase* wrapper = getWrapper(value);
|
|
170
|
-
using Parameter_T = std::tuple_element_t<I, Arg_Ts>;
|
|
171
|
-
|
|
172
|
-
// Do not send a const value to a non-const parameter
|
|
173
|
-
if (wrapper->isConst() && !is_const_any_v<Parameter_T>)
|
|
174
|
-
{
|
|
175
|
-
result = Convertible::None;
|
|
176
|
-
}
|
|
177
|
-
// It is ok to send a non-const value to a const parameter but
|
|
178
|
-
// prefer non-const to non-const by slighly decreasing the convertible value
|
|
179
|
-
else if (!wrapper->isConst() && is_const_any_v<Parameter_T>)
|
|
180
|
-
{
|
|
181
|
-
result = Convertible::Const;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
// Last check if a default value has been set
|
|
187
|
-
else if (arg->hasDefaultValue())
|
|
188
|
-
{
|
|
189
|
-
result = Convertible::Exact;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
return result;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
template<typename Class_T, typename Function_T, bool IsMethod>
|
|
196
|
-
template<std::size_t... I>
|
|
197
|
-
Convertible NativeFunction<Class_T, Function_T, IsMethod>::matchParameters(std::vector<std::optional<VALUE>>& values,
|
|
198
|
-
std::index_sequence<I...>& indices)
|
|
199
|
-
{
|
|
200
|
-
Convertible result = Convertible::Exact;
|
|
201
|
-
((result = result & this->matchParameter<I>(values)), ...);
|
|
202
|
-
return result;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
template<typename Class_T, typename Function_T, bool IsMethod>
|
|
206
|
-
Resolved NativeFunction<Class_T, Function_T, IsMethod>::matches(size_t argc, const VALUE* argv, VALUE self)
|
|
207
|
-
{
|
|
208
|
-
// Return false if Ruby provided more arguments than the C++ method takes
|
|
209
|
-
if (argc > arity)
|
|
210
|
-
return Resolved{ Convertible::None, 0, this };
|
|
211
|
-
|
|
212
|
-
Resolved result { Convertible::Exact, 1, this };
|
|
213
|
-
|
|
214
|
-
std::vector<std::optional<VALUE>> rubyValues = this->getRubyValues(argc, argv, false);
|
|
215
|
-
auto indices = std::make_index_sequence<std::tuple_size_v<Arg_Ts>>{};
|
|
216
|
-
result.convertible = this->matchParameters(rubyValues, indices);
|
|
217
|
-
|
|
218
|
-
if constexpr (arity > 0)
|
|
219
|
-
{
|
|
220
|
-
int providedValues = std::count_if(rubyValues.begin(), rubyValues.end(), [](std::optional<VALUE>& value)
|
|
221
|
-
{
|
|
222
|
-
return value.has_value();
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
result.parameterMatch = providedValues / (double)arity;
|
|
226
|
-
}
|
|
227
|
-
return result;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
template<typename Class_T, typename Function_T, bool IsMethod>
|
|
231
|
-
std::vector<std::optional<VALUE>> NativeFunction<Class_T, Function_T, IsMethod>::getRubyValues(size_t argc, const VALUE* argv, bool validate)
|
|
232
|
-
{
|
|
233
|
-
#undef max
|
|
234
|
-
int size = std::max((size_t)arity, (size_t)argc);
|
|
235
|
-
std::vector<std::optional<VALUE>> result(size);
|
|
236
|
-
|
|
237
|
-
// Keyword handling
|
|
238
|
-
if (rb_keyword_given_p())
|
|
239
|
-
{
|
|
240
|
-
// Keywords are stored in the last element in a hash
|
|
241
|
-
int actualArgc = argc - 1;
|
|
242
|
-
|
|
243
|
-
VALUE value = argv[actualArgc];
|
|
244
|
-
Hash keywords(value);
|
|
245
|
-
|
|
246
|
-
// Copy over leading non-keyword arguments
|
|
247
|
-
for (int i = 0; i < actualArgc; i++)
|
|
248
|
-
{
|
|
249
|
-
result[i] = argv[i];
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// Copy over keyword arguments
|
|
253
|
-
for (auto pair : keywords)
|
|
254
|
-
{
|
|
255
|
-
Symbol key(pair.first);
|
|
256
|
-
const Arg* arg = this->methodInfo_->arg(key.str());
|
|
257
|
-
if (!arg)
|
|
258
|
-
{
|
|
259
|
-
throw std::invalid_argument("Unknown keyword: " + key.str());
|
|
260
|
-
}
|
|
261
|
-
result[arg->position] = pair.second.value();
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
else
|
|
265
|
-
{
|
|
266
|
-
std::copy(argv, argv + argc, result.begin());
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// Block handling. If we find a block and the last parameter is missing then
|
|
270
|
-
// set it to the block
|
|
271
|
-
if (rb_block_given_p() && result.size() > 0 && !result.back().has_value())
|
|
272
|
-
{
|
|
273
|
-
VALUE proc = rb_block_proc();
|
|
274
|
-
result.back() = proc;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
if (validate)
|
|
278
|
-
{
|
|
279
|
-
// Protect against user sending too many arguments
|
|
280
|
-
if (argc > arity)
|
|
281
|
-
{
|
|
282
|
-
std::string message = "wrong number of arguments (given " +
|
|
283
|
-
std::to_string(argc) + ", expected " + std::to_string(arity) + ")";
|
|
284
|
-
throw std::invalid_argument(message);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
for (size_t i=0; i<result.size(); i++)
|
|
288
|
-
{
|
|
289
|
-
std::optional<VALUE> value = result[i];
|
|
290
|
-
Arg* arg = this->methodInfo_->arg(i);
|
|
291
|
-
|
|
292
|
-
if (!arg->hasDefaultValue() && !value.has_value())
|
|
293
|
-
{
|
|
294
|
-
std::string message;
|
|
295
|
-
message = "Missing argument. Name: " + arg->name + ". Index: " + std::to_string(arg->position) + ".";
|
|
296
|
-
throw std::invalid_argument(message);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
return result;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
template<typename Class_T, typename Function_T, bool IsMethod>
|
|
305
|
-
template<typename Arg_T, int I>
|
|
306
|
-
Arg_T NativeFunction<Class_T, Function_T, IsMethod>::getNativeValue(std::vector<std::optional<VALUE>>& values)
|
|
307
|
-
{
|
|
308
|
-
/* In general the compiler will convert T to const T, but that does not work for converting
|
|
309
|
-
T** to const T** (see see https://isocpp.org/wiki/faq/const-correctness#constptrptr-conversion)
|
|
310
|
-
which comes up in the OpenCV bindings.
|
|
311
|
-
|
|
312
|
-
An alternative solution is updating From_Ruby#convert to become a templated function that specifies
|
|
313
|
-
the return type. That works but requires a lot more code changes for this one case and is not
|
|
314
|
-
backwards compatible. */
|
|
315
|
-
|
|
316
|
-
std::optional<VALUE> value = values[I];
|
|
317
|
-
Arg* arg = this->methodInfo_->arg(I);
|
|
318
|
-
|
|
319
|
-
if constexpr (is_pointer_pointer_v<Arg_T> && !std::is_convertible_v<remove_cv_recursive_t<Arg_T>, Arg_T>)
|
|
320
|
-
{
|
|
321
|
-
return (Arg_T)std::get<I>(this->fromRubys_).convert(value.value());
|
|
322
|
-
}
|
|
323
|
-
else if (value.has_value())
|
|
324
|
-
{
|
|
325
|
-
return std::get<I>(this->fromRubys_).convert(value.value());
|
|
326
|
-
}
|
|
327
|
-
else if constexpr (std::is_constructible_v<std::remove_cv_t<Arg_T>, std::remove_cv_t<std::remove_reference_t<Arg_T>>&>)
|
|
328
|
-
{
|
|
329
|
-
if (arg->hasDefaultValue())
|
|
330
|
-
{
|
|
331
|
-
return arg->defaultValue<Arg_T>();
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
throw std::invalid_argument("Could not convert Rubyy value");
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
template<typename Class_T, typename Function_T, bool IsMethod>
|
|
76
|
+
template<typename Function_T>
|
|
339
77
|
template<std::size_t... I>
|
|
340
|
-
typename NativeFunction<
|
|
78
|
+
typename NativeFunction<Function_T>::Arg_Ts NativeFunction<Function_T>::getNativeValues(std::vector<std::optional<VALUE>>& values,
|
|
341
79
|
std::index_sequence<I...>& indices)
|
|
342
80
|
{
|
|
343
81
|
/* Loop over each value returned from Ruby and convert it to the appropriate C++ type based
|
|
344
82
|
on the arguments (Arg_Ts) required by the C++ function. Arg_T may have const/volatile while
|
|
345
83
|
the associated From_Ruby<T> template parameter will not. Thus From_Ruby produces non-const values
|
|
346
84
|
which we let the compiler convert to const values as needed. This works except for
|
|
347
|
-
T** -> const T**, see comment in
|
|
348
|
-
return std::forward_as_tuple(this->getNativeValue<std::tuple_element_t<I, Arg_Ts>, I>(values)...);
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
typename NativeFunction<Class_T, Function_T, IsMethod>::Receiver_T NativeFunction<Class_T, Function_T, IsMethod>::getReceiver(VALUE self)
|
|
353
|
-
{
|
|
354
|
-
// There is no self parameter
|
|
355
|
-
if constexpr (std::is_same_v<Receiver_T, std::nullptr_t>)
|
|
356
|
-
{
|
|
357
|
-
return nullptr;
|
|
358
|
-
}
|
|
359
|
-
// Self parameter is a Ruby VALUE so no conversion is needed
|
|
360
|
-
else if constexpr (std::is_same_v<Receiver_T, VALUE>)
|
|
361
|
-
{
|
|
362
|
-
return self;
|
|
363
|
-
}
|
|
364
|
-
/* This case happens when a class wrapped by Rice is calling a method
|
|
365
|
-
defined on an ancestor class. For example, the std::map size method
|
|
366
|
-
is defined on _Tree not map. Rice needs to know the actual type
|
|
367
|
-
that was wrapped so it can correctly extract the C++ object from
|
|
368
|
-
the Ruby object. */
|
|
369
|
-
else if constexpr (!std::is_same_v<intrinsic_type<Receiver_T>, Class_T> &&
|
|
370
|
-
std::is_base_of_v<intrinsic_type<Receiver_T>, Class_T> &&
|
|
371
|
-
std::is_pointer_v<Receiver_T>)
|
|
372
|
-
{
|
|
373
|
-
Class_T* instance = From_Ruby<Class_T*>().convert(self);
|
|
374
|
-
return dynamic_cast<Receiver_T>(instance);
|
|
375
|
-
}
|
|
376
|
-
else if constexpr (!std::is_same_v<intrinsic_type<Receiver_T>, Class_T> &&
|
|
377
|
-
std::is_base_of_v<intrinsic_type<Receiver_T>, Class_T> &&
|
|
378
|
-
std::is_reference_v<Receiver_T>)
|
|
379
|
-
{
|
|
380
|
-
Class_T& instance = From_Ruby<Class_T&>().convert(self);
|
|
381
|
-
return dynamic_cast<Receiver_T>(instance);
|
|
382
|
-
}
|
|
383
|
-
// Self parameter could be derived from Object or it is an C++ instance and
|
|
384
|
-
// needs to be unwrapped from Ruby
|
|
385
|
-
else
|
|
386
|
-
{
|
|
387
|
-
return From_Ruby<Receiver_T>().convert(self);
|
|
388
|
-
}
|
|
85
|
+
T** -> const T**, see comment in convertToNative method. */
|
|
86
|
+
//return std::forward_as_tuple(this->getNativeValue<std::tuple_element_t<I, Arg_Ts>, I>(values)...);
|
|
87
|
+
return std::forward_as_tuple(
|
|
88
|
+
(dynamic_cast<Parameter<std::tuple_element_t<I, Arg_Ts>>*>(this->parameters_[I].get()))->
|
|
89
|
+
convertToNative(values[I])...);
|
|
389
90
|
}
|
|
390
91
|
|
|
391
|
-
template<typename
|
|
392
|
-
VALUE NativeFunction<
|
|
92
|
+
template<typename Function_T>
|
|
93
|
+
VALUE NativeFunction<Function_T>::invoke(Arg_Ts&& nativeArgs)
|
|
393
94
|
{
|
|
394
95
|
if constexpr (std::is_void_v<Return_T>)
|
|
395
96
|
{
|
|
@@ -402,57 +103,30 @@ namespace Rice::detail
|
|
|
402
103
|
Return_T nativeResult = std::apply(this->function_, std::forward<Arg_Ts>(nativeArgs));
|
|
403
104
|
|
|
404
105
|
// Return the result
|
|
405
|
-
return this->toRuby_.convert(
|
|
106
|
+
return this->toRuby_.convert(nativeResult);
|
|
406
107
|
}
|
|
407
108
|
}
|
|
408
109
|
|
|
409
|
-
template<typename
|
|
410
|
-
VALUE NativeFunction<
|
|
110
|
+
template<typename Function_T>
|
|
111
|
+
VALUE NativeFunction<Function_T>::invokeNoGVL(Arg_Ts&& nativeArgs)
|
|
411
112
|
{
|
|
412
|
-
Receiver_T receiver = this->getReceiver(self);
|
|
413
|
-
auto selfAndNativeArgs = std::tuple_cat(std::forward_as_tuple(receiver), std::forward<Arg_Ts>(nativeArgs));
|
|
414
|
-
|
|
415
113
|
if constexpr (std::is_void_v<Return_T>)
|
|
416
114
|
{
|
|
417
|
-
|
|
115
|
+
no_gvl(this->function_, std::forward<Arg_Ts>(nativeArgs));
|
|
418
116
|
return Qnil;
|
|
419
117
|
}
|
|
420
118
|
else
|
|
421
119
|
{
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
// Special handling if the method returns self. If so we do not want
|
|
425
|
-
// to create a new Ruby wrapper object and instead return self.
|
|
426
|
-
if constexpr (std::is_same_v<intrinsic_type<Return_T>, intrinsic_type<Receiver_T>>)
|
|
427
|
-
{
|
|
428
|
-
if constexpr (std::is_pointer_v<Return_T> && std::is_pointer_v<Receiver_T>)
|
|
429
|
-
{
|
|
430
|
-
if (nativeResult == receiver)
|
|
431
|
-
return self;
|
|
432
|
-
}
|
|
433
|
-
else if constexpr (std::is_pointer_v<Return_T> && std::is_reference_v<Receiver_T>)
|
|
434
|
-
{
|
|
435
|
-
if (nativeResult == &receiver)
|
|
436
|
-
return self;
|
|
437
|
-
}
|
|
438
|
-
else if constexpr (std::is_reference_v<Return_T> && std::is_pointer_v<Receiver_T>)
|
|
439
|
-
{
|
|
440
|
-
if (&nativeResult == receiver)
|
|
441
|
-
return self;
|
|
442
|
-
}
|
|
443
|
-
else if constexpr (std::is_reference_v<Return_T> && std::is_reference_v<Receiver_T>)
|
|
444
|
-
{
|
|
445
|
-
if (&nativeResult == &receiver)
|
|
446
|
-
return self;
|
|
447
|
-
}
|
|
448
|
-
}
|
|
120
|
+
// Call the native method and get the result
|
|
121
|
+
Return_T nativeResult = no_gvl(this->function_, std::forward<Arg_Ts>(nativeArgs));
|
|
449
122
|
|
|
450
|
-
|
|
123
|
+
// Return the result
|
|
124
|
+
return this->toRuby_.convert(nativeResult);
|
|
451
125
|
}
|
|
452
126
|
}
|
|
453
127
|
|
|
454
|
-
template<typename
|
|
455
|
-
void NativeFunction<
|
|
128
|
+
template<typename Function_T>
|
|
129
|
+
void NativeFunction<Function_T>::noWrapper(const VALUE klass, const std::string& wrapper)
|
|
456
130
|
{
|
|
457
131
|
std::stringstream message;
|
|
458
132
|
|
|
@@ -467,8 +141,8 @@ namespace Rice::detail
|
|
|
467
141
|
throw std::runtime_error(message.str());
|
|
468
142
|
}
|
|
469
143
|
|
|
470
|
-
template<typename
|
|
471
|
-
void NativeFunction<
|
|
144
|
+
template<typename Function_T>
|
|
145
|
+
void NativeFunction<Function_T>::checkKeepAlive(VALUE self, VALUE returnValue, std::vector<std::optional<VALUE>>& rubyValues)
|
|
472
146
|
{
|
|
473
147
|
// Self will be Qnil for wrapped procs
|
|
474
148
|
if (self == Qnil)
|
|
@@ -492,7 +166,7 @@ namespace Rice::detail
|
|
|
492
166
|
}
|
|
493
167
|
|
|
494
168
|
// Check return value
|
|
495
|
-
if (this->methodInfo_->returnInfo
|
|
169
|
+
if (this->methodInfo_->returnInfo()->isKeepAlive())
|
|
496
170
|
{
|
|
497
171
|
if (selfWrapper == nullptr)
|
|
498
172
|
{
|
|
@@ -509,8 +183,8 @@ namespace Rice::detail
|
|
|
509
183
|
}
|
|
510
184
|
}
|
|
511
185
|
|
|
512
|
-
template<typename
|
|
513
|
-
VALUE NativeFunction<
|
|
186
|
+
template<typename Function_T>
|
|
187
|
+
VALUE NativeFunction<Function_T>::operator()(size_t argc, const VALUE* argv, VALUE self)
|
|
514
188
|
{
|
|
515
189
|
// Get the ruby values and make sure we have the correct number
|
|
516
190
|
std::vector<std::optional<VALUE>> rubyValues = this->getRubyValues(argc, argv, true);
|
|
@@ -520,15 +194,17 @@ namespace Rice::detail
|
|
|
520
194
|
// Convert the Ruby values to native values
|
|
521
195
|
Arg_Ts nativeValues = this->getNativeValues(rubyValues, indices);
|
|
522
196
|
|
|
523
|
-
|
|
197
|
+
bool noGvl = this->methodInfo_->function()->isNoGvl();
|
|
198
|
+
|
|
524
199
|
VALUE result = Qnil;
|
|
525
|
-
|
|
200
|
+
|
|
201
|
+
if (noGvl)
|
|
526
202
|
{
|
|
527
|
-
result = this->
|
|
203
|
+
result = this->invokeNoGVL(std::forward<Arg_Ts>(nativeValues));
|
|
528
204
|
}
|
|
529
205
|
else
|
|
530
206
|
{
|
|
531
|
-
result = this->
|
|
207
|
+
result = this->invoke(std::forward<Arg_Ts>(nativeValues));
|
|
532
208
|
}
|
|
533
209
|
|
|
534
210
|
// Check if any function arguments or return values need to have their lifetimes tied to the receiver
|
|
@@ -536,4 +212,32 @@ namespace Rice::detail
|
|
|
536
212
|
|
|
537
213
|
return result;
|
|
538
214
|
}
|
|
215
|
+
|
|
216
|
+
template<typename Function_T>
|
|
217
|
+
inline std::string NativeFunction<Function_T>::name()
|
|
218
|
+
{
|
|
219
|
+
return this->method_name_;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
template<typename Function_T>
|
|
223
|
+
inline NativeKind NativeFunction<Function_T>::kind()
|
|
224
|
+
{
|
|
225
|
+
return NativeKind::Function;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
template<typename Function_T>
|
|
229
|
+
inline VALUE NativeFunction<Function_T>::returnKlass()
|
|
230
|
+
{
|
|
231
|
+
// Check if an array is being returned
|
|
232
|
+
if (this->methodInfo_->returnInfo()->isBuffer())
|
|
233
|
+
{
|
|
234
|
+
TypeMapper<Pointer<Return_T>> typeMapper;
|
|
235
|
+
return typeMapper.rubyKlass();
|
|
236
|
+
}
|
|
237
|
+
else
|
|
238
|
+
{
|
|
239
|
+
TypeMapper<Return_T> typeMapper;
|
|
240
|
+
return typeMapper.rubyKlass();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
539
243
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#ifndef Rice__detail__native_invoker__hpp_
|
|
2
|
+
#define Rice__detail__native_invoker__hpp_
|
|
3
|
+
|
|
4
|
+
#include <optional>
|
|
5
|
+
|
|
6
|
+
namespace Rice::detail
|
|
7
|
+
{
|
|
8
|
+
template<typename Return_T>
|
|
9
|
+
class ResultWrapper
|
|
10
|
+
{
|
|
11
|
+
public:
|
|
12
|
+
std::exception_ptr exception;
|
|
13
|
+
Return_T getResult();
|
|
14
|
+
void setResult(Return_T&& value);
|
|
15
|
+
private:
|
|
16
|
+
std::optional<Return_T> result_;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
template<typename Return_T>
|
|
20
|
+
class ResultWrapper<Return_T&>
|
|
21
|
+
{
|
|
22
|
+
public:
|
|
23
|
+
std::exception_ptr exception;
|
|
24
|
+
Return_T& getResult();
|
|
25
|
+
void setResult(Return_T& value);
|
|
26
|
+
private:
|
|
27
|
+
std::optional<std::reference_wrapper<Return_T>> result_;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
template<typename Return_T>
|
|
31
|
+
class ResultWrapper<Return_T*>
|
|
32
|
+
{
|
|
33
|
+
public:
|
|
34
|
+
std::exception_ptr exception;
|
|
35
|
+
|
|
36
|
+
Return_T* getResult();
|
|
37
|
+
void setResult(Return_T* value);
|
|
38
|
+
private:
|
|
39
|
+
Return_T* result_;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
template<>
|
|
43
|
+
class ResultWrapper<void>
|
|
44
|
+
{
|
|
45
|
+
public:
|
|
46
|
+
std::exception_ptr exception;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
template<typename Return_T, typename Function_T, typename Tuple_T>
|
|
50
|
+
class NativeInvoker
|
|
51
|
+
{
|
|
52
|
+
public:
|
|
53
|
+
const Function_T func;
|
|
54
|
+
Tuple_T args;
|
|
55
|
+
public:
|
|
56
|
+
NativeInvoker(const Function_T func, Tuple_T&& args);
|
|
57
|
+
void invoke();
|
|
58
|
+
Return_T result();
|
|
59
|
+
std::exception_ptr exception();
|
|
60
|
+
private:
|
|
61
|
+
ResultWrapper<Return_T> resultWrapper;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
template<typename Function_T, typename ...Arg_Ts>
|
|
65
|
+
auto protect(Function_T func, Arg_Ts...args);
|
|
66
|
+
|
|
67
|
+
template<typename Function_T, typename ...Arg_Ts>
|
|
68
|
+
typename function_traits<Function_T>::return_type no_gvl(Function_T func, Arg_Ts...args);
|
|
69
|
+
|
|
70
|
+
template<typename Function_T, typename Tuple_T>
|
|
71
|
+
typename function_traits<Function_T>::return_type no_gvl(Function_T func, Tuple_T&& args);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
#endif // Rice__detail__native_invoker__hpp_
|