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