rice 4.3.3 → 4.6.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 +86 -26
- data/CMakeLists.txt +31 -0
- data/CMakePresets.json +75 -0
- data/COPYING +3 -2
- data/FindRuby.cmake +437 -0
- data/README.md +7 -2
- data/Rakefile +12 -5
- data/include/rice/rice.hpp +9522 -4426
- data/include/rice/stl.hpp +2831 -1198
- data/lib/make_rice_headers.rb +79 -0
- data/lib/mkmf-rice.rb +40 -94
- data/lib/rice/version.rb +3 -0
- data/lib/rice.rb +1 -0
- data/lib/rubygems/builder.rb +11 -0
- data/lib/rubygems/cmake_builder.rb +113 -0
- data/lib/rubygems_plugin.rb +9 -0
- data/rice/Address_Registration_Guard.hpp +72 -3
- data/rice/Arg.hpp +26 -6
- data/rice/Arg.ipp +35 -2
- data/rice/Buffer.hpp +123 -0
- data/rice/Buffer.ipp +599 -0
- data/rice/Callback.hpp +21 -0
- data/rice/Callback.ipp +13 -0
- data/rice/Constructor.hpp +4 -27
- data/rice/Constructor.ipp +79 -0
- data/rice/Data_Object.hpp +73 -3
- data/rice/Data_Object.ipp +388 -96
- data/rice/Data_Type.hpp +214 -3
- data/rice/Data_Type.ipp +144 -67
- data/rice/Director.hpp +0 -2
- data/rice/Enum.hpp +4 -7
- data/rice/Enum.ipp +102 -55
- data/rice/Exception.hpp +62 -2
- data/rice/Exception.ipp +7 -12
- data/rice/Init.hpp +8 -0
- data/rice/Init.ipp +8 -0
- data/rice/JumpException.hpp +44 -0
- data/rice/JumpException.ipp +48 -0
- data/rice/MemoryView.hpp +11 -0
- data/rice/MemoryView.ipp +3 -0
- data/rice/Return.hpp +7 -27
- data/rice/Return.ipp +13 -13
- data/rice/cpp_api/Array.hpp +209 -0
- data/rice/cpp_api/Array.ipp +304 -0
- data/rice/cpp_api/Builtin_Object.hpp +31 -0
- data/rice/cpp_api/Builtin_Object.ipp +37 -0
- data/rice/cpp_api/Class.hpp +70 -0
- data/rice/cpp_api/Class.ipp +97 -0
- data/rice/cpp_api/Encoding.hpp +32 -0
- data/rice/cpp_api/Encoding.ipp +59 -0
- data/rice/cpp_api/Hash.hpp +194 -0
- data/rice/cpp_api/Hash.ipp +257 -0
- data/rice/{Identifier.hpp → cpp_api/Identifier.hpp} +2 -6
- data/rice/{Identifier.ipp → cpp_api/Identifier.ipp} +4 -2
- data/rice/cpp_api/Module.hpp +72 -0
- data/rice/cpp_api/Module.ipp +101 -0
- data/rice/cpp_api/Object.hpp +272 -0
- data/rice/cpp_api/Object.ipp +235 -0
- data/rice/cpp_api/String.hpp +74 -0
- data/rice/cpp_api/String.ipp +120 -0
- data/rice/cpp_api/Struct.hpp +113 -0
- data/rice/cpp_api/Struct.ipp +92 -0
- data/rice/cpp_api/Symbol.hpp +46 -0
- data/rice/cpp_api/Symbol.ipp +93 -0
- data/rice/cpp_api/shared_methods.hpp +134 -0
- data/rice/detail/DefaultHandler.hpp +12 -0
- data/rice/detail/DefaultHandler.ipp +8 -0
- data/rice/detail/HandlerRegistry.hpp +5 -35
- data/rice/detail/HandlerRegistry.ipp +7 -11
- data/rice/detail/InstanceRegistry.hpp +1 -4
- data/rice/detail/MethodInfo.hpp +12 -10
- data/rice/detail/MethodInfo.ipp +26 -21
- data/rice/detail/Native.hpp +33 -0
- data/rice/detail/Native.ipp +157 -0
- data/rice/detail/NativeAttributeGet.hpp +52 -0
- data/rice/detail/NativeAttributeGet.ipp +57 -0
- data/rice/detail/NativeAttributeSet.hpp +44 -0
- data/rice/detail/NativeAttributeSet.ipp +88 -0
- data/rice/detail/NativeCallbackFFI.hpp +55 -0
- data/rice/detail/NativeCallbackFFI.ipp +151 -0
- data/rice/detail/NativeCallbackSimple.hpp +30 -0
- data/rice/detail/NativeCallbackSimple.ipp +29 -0
- data/rice/detail/NativeFunction.hpp +33 -23
- data/rice/detail/NativeFunction.ipp +309 -70
- data/rice/detail/NativeIterator.hpp +9 -11
- data/rice/detail/NativeIterator.ipp +33 -31
- data/rice/detail/NativeRegistry.hpp +24 -15
- data/rice/detail/NativeRegistry.ipp +23 -48
- data/rice/detail/Proc.hpp +4 -0
- data/rice/detail/Proc.ipp +85 -0
- data/rice/detail/Registries.hpp +0 -7
- data/rice/detail/Registries.ipp +0 -18
- data/rice/detail/RubyFunction.hpp +0 -3
- data/rice/detail/RubyFunction.ipp +4 -8
- data/rice/detail/RubyType.hpp +16 -0
- data/rice/detail/RubyType.ipp +232 -0
- data/rice/detail/Type.hpp +7 -6
- data/rice/detail/Type.ipp +192 -45
- data/rice/detail/TypeRegistry.hpp +15 -7
- data/rice/detail/TypeRegistry.ipp +105 -12
- data/rice/detail/Wrapper.hpp +68 -32
- data/rice/detail/Wrapper.ipp +121 -109
- data/rice/detail/cpp_protect.hpp +5 -6
- data/rice/detail/default_allocation_func.ipp +0 -2
- data/rice/detail/from_ruby.hpp +38 -3
- data/rice/detail/from_ruby.ipp +1321 -492
- data/rice/detail/ruby.hpp +18 -0
- data/rice/detail/to_ruby.hpp +41 -3
- data/rice/detail/to_ruby.ipp +1424 -194
- data/rice/global_function.hpp +0 -4
- data/rice/global_function.ipp +0 -1
- data/rice/libc/file.hpp +11 -0
- data/rice/libc/file.ipp +32 -0
- data/rice/rice.hpp +116 -26
- data/rice/ruby_mark.hpp +4 -3
- data/rice/stl/complex.hpp +6 -0
- data/rice/stl/complex.ipp +93 -0
- data/rice/stl/exception.hpp +11 -0
- data/rice/stl/exception.ipp +29 -0
- data/rice/stl/exception_ptr.hpp +6 -0
- data/rice/stl/exception_ptr.ipp +27 -0
- data/rice/stl/map.hpp +12 -0
- data/rice/stl/map.ipp +469 -0
- data/rice/stl/monostate.hpp +6 -0
- data/rice/stl/monostate.ipp +80 -0
- data/rice/stl/multimap.hpp +14 -0
- data/rice/stl/multimap.ipp +448 -0
- data/rice/stl/optional.hpp +6 -0
- data/rice/stl/optional.ipp +118 -0
- data/rice/stl/pair.hpp +13 -0
- data/rice/stl/pair.ipp +155 -0
- data/rice/stl/reference_wrapper.hpp +6 -0
- data/rice/stl/reference_wrapper.ipp +41 -0
- data/rice/stl/set.hpp +12 -0
- data/rice/stl/set.ipp +495 -0
- data/rice/stl/shared_ptr.hpp +28 -0
- data/rice/stl/shared_ptr.ipp +224 -0
- data/rice/stl/string.hpp +6 -0
- data/rice/stl/string.ipp +158 -0
- data/rice/stl/string_view.hpp +6 -0
- data/rice/stl/string_view.ipp +65 -0
- data/rice/stl/tuple.hpp +6 -0
- data/rice/stl/tuple.ipp +128 -0
- data/rice/stl/type_index.hpp +6 -0
- data/rice/stl/type_index.ipp +30 -0
- data/rice/stl/type_info.hpp +6 -0
- data/rice/stl/type_info.ipp +29 -0
- data/rice/stl/unique_ptr.hpp +22 -0
- data/rice/stl/unique_ptr.ipp +139 -0
- data/rice/stl/unordered_map.hpp +12 -0
- data/rice/stl/unordered_map.ipp +469 -0
- data/rice/stl/variant.hpp +6 -0
- data/rice/stl/variant.ipp +242 -0
- data/rice/stl/vector.hpp +12 -0
- data/rice/stl/vector.ipp +590 -0
- data/rice/stl.hpp +11 -3
- data/rice/traits/attribute_traits.hpp +26 -0
- data/rice/traits/function_traits.hpp +95 -0
- data/rice/traits/method_traits.hpp +47 -0
- data/rice/traits/rice_traits.hpp +160 -0
- data/rice.gemspec +85 -0
- data/test/embed_ruby.cpp +7 -1
- data/test/extconf.rb +2 -0
- data/test/test_Address_Registration_Guard.cpp +5 -0
- data/test/test_Array.cpp +18 -4
- data/test/test_Attribute.cpp +136 -21
- data/test/test_Buffer.cpp +285 -0
- data/test/test_Builtin_Object.cpp +5 -0
- data/test/test_Callback.cpp +230 -0
- data/test/test_Class.cpp +5 -31
- data/test/test_Constructor.cpp +69 -6
- data/test/test_Data_Object.cpp +97 -38
- data/test/test_Data_Type.cpp +470 -65
- data/test/test_Director.cpp +17 -8
- data/test/test_Enum.cpp +155 -40
- data/test/test_Exception.cpp +235 -0
- data/test/test_File.cpp +70 -0
- data/test/test_From_Ruby.cpp +609 -0
- data/test/test_Hash.cpp +5 -0
- data/test/test_Identifier.cpp +5 -0
- data/test/test_Inheritance.cpp +6 -1
- data/test/test_Iterator.cpp +6 -1
- data/test/test_Jump_Exception.cpp +23 -0
- data/test/test_Keep_Alive.cpp +13 -19
- data/test/test_Keep_Alive_No_Wrapper.cpp +5 -1
- data/test/test_Memory_Management.cpp +5 -0
- data/test/test_Module.cpp +128 -67
- data/test/test_Native_Registry.cpp +2 -34
- data/test/test_Object.cpp +5 -0
- data/test/test_Overloads.cpp +806 -0
- data/test/test_Ownership.cpp +160 -54
- data/test/test_Proc.cpp +44 -0
- data/test/test_Self.cpp +9 -4
- data/test/test_Stl_Exception.cpp +109 -0
- data/test/test_Stl_Map.cpp +54 -42
- data/test/test_Stl_Multimap.cpp +693 -0
- data/test/test_Stl_Optional.cpp +5 -0
- data/test/test_Stl_Pair.cpp +14 -9
- data/test/test_Stl_Reference_Wrapper.cpp +9 -2
- data/test/test_Stl_Set.cpp +790 -0
- data/test/test_Stl_SharedPtr.cpp +458 -0
- data/test/test_Stl_String.cpp +5 -0
- data/test/test_Stl_String_View.cpp +5 -0
- data/test/test_Stl_Tuple.cpp +116 -0
- data/test/test_Stl_Type.cpp +147 -0
- data/test/test_Stl_UniquePtr.cpp +202 -0
- data/test/test_Stl_Unordered_Map.cpp +43 -38
- data/test/test_Stl_Variant.cpp +217 -84
- data/test/test_Stl_Vector.cpp +306 -58
- data/test/test_String.cpp +5 -0
- data/test/test_Struct.cpp +5 -0
- data/test/test_Symbol.cpp +5 -0
- data/test/test_Template.cpp +192 -0
- data/test/test_To_Ruby.cpp +524 -0
- data/test/test_Tracking.cpp +1 -0
- data/test/test_Type.cpp +171 -0
- data/test/test_global_functions.cpp +67 -7
- data/test/unittest.cpp +8 -0
- metadata +127 -26
- data/lib/version.rb +0 -3
- data/rice/Address_Registration_Guard_defn.hpp +0 -79
- data/rice/Data_Object_defn.hpp +0 -84
- data/rice/Data_Type_defn.hpp +0 -190
- data/rice/Exception_defn.hpp +0 -68
- data/rice/HandlerRegistration.hpp +0 -15
- data/rice/detail/ExceptionHandler.hpp +0 -8
- data/rice/detail/ExceptionHandler.ipp +0 -28
- data/rice/detail/ExceptionHandler_defn.hpp +0 -77
- data/rice/detail/Jump_Tag.hpp +0 -21
- data/rice/detail/NativeAttribute.hpp +0 -64
- data/rice/detail/NativeAttribute.ipp +0 -112
- data/rice/detail/from_ruby_defn.hpp +0 -38
- data/rice/detail/to_ruby_defn.hpp +0 -48
- data/test/test_Jump_Tag.cpp +0 -17
- data/test/test_Stl_SmartPointer.cpp +0 -283
- data/test/test_To_From_Ruby.cpp +0 -399
@@ -1,40 +1,50 @@
|
|
1
|
-
#include <array>
|
2
1
|
#include <algorithm>
|
2
|
+
#include <array>
|
3
3
|
#include <stdexcept>
|
4
4
|
#include <sstream>
|
5
5
|
|
6
|
-
#include "cpp_protect.hpp"
|
7
|
-
#include "to_ruby_defn.hpp"
|
8
|
-
#include "NativeRegistry.hpp"
|
9
|
-
|
10
6
|
namespace Rice::detail
|
11
7
|
{
|
12
8
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
13
9
|
void NativeFunction<Class_T, Function_T, IsMethod>::define(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo)
|
14
10
|
{
|
15
|
-
//
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
11
|
+
// Have we defined this method yet in Ruby?
|
12
|
+
Identifier identifier(method_name);
|
13
|
+
const std::vector<std::unique_ptr<Native>>& natives = Registries::instance.natives.lookup(klass, identifier.id());
|
14
|
+
if (natives.empty())
|
15
|
+
{
|
16
|
+
// Tell Ruby to invoke the static resolved method defined above
|
17
|
+
detail::protect(rb_define_method, klass, method_name.c_str(), (RUBY_METHOD_FUNC)&Native::resolve, -1);
|
18
|
+
}
|
19
|
+
|
20
|
+
// Create a NativeFunction instance and save it to the NativeRegistry. There may be multiple
|
21
|
+
// NativeFunction instances for a specific method because C++ supports method overloading.
|
22
|
+
NativeFunction_T* nativeFunction = new NativeFunction_T(klass, method_name, std::forward<Function_T>(function), methodInfo);
|
23
|
+
std::unique_ptr<Native> native(nativeFunction);
|
24
|
+
detail::Registries::instance.natives.add(klass, identifier.id(), native);
|
23
25
|
}
|
24
26
|
|
27
|
+
// Ruby calls this method when invoking a proc that was defined as a C++ function
|
25
28
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
26
|
-
VALUE NativeFunction<Class_T, Function_T, IsMethod>::
|
29
|
+
VALUE NativeFunction<Class_T, Function_T, IsMethod>::procEntry(VALUE yielded_arg, VALUE callback_arg, int argc, const VALUE* argv, VALUE blockarg)
|
27
30
|
{
|
28
|
-
// Look up the native function based on the Ruby klass and method id
|
29
|
-
NativeFunction_T* nativeFunction = detail::Registries::instance.natives.lookup<NativeFunction_T*>();
|
30
|
-
|
31
|
-
// Execute the function but make sure to catch any C++ exceptions!
|
32
31
|
return cpp_protect([&]
|
33
32
|
{
|
34
|
-
|
33
|
+
NativeFunction_T * native = (NativeFunction_T*)callback_arg;
|
34
|
+
return (*native)(argc, argv, Qnil);
|
35
35
|
});
|
36
36
|
}
|
37
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)
|
42
|
+
{
|
43
|
+
NativeFunction_T* native = (NativeFunction_T*)callback_arg;
|
44
|
+
delete native;
|
45
|
+
return Qnil;
|
46
|
+
}
|
47
|
+
|
38
48
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
39
49
|
NativeFunction<Class_T, Function_T, IsMethod>::NativeFunction(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo)
|
40
50
|
: klass_(klass), method_name_(method_name), function_(function), methodInfo_(methodInfo)
|
@@ -49,6 +59,63 @@ namespace Rice::detail
|
|
49
59
|
this->toRuby_ = this->createToRuby();
|
50
60
|
}
|
51
61
|
|
62
|
+
template<typename Class_T, typename Function_T, bool IsMethod>
|
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>
|
69
|
+
template<std::size_t... I>
|
70
|
+
std::vector<std::string> NativeFunction<Class_T, Function_T, IsMethod>::argTypeNames(std::ostringstream& stream, std::index_sequence<I...>& indices)
|
71
|
+
{
|
72
|
+
std::vector<std::string> typeNames;
|
73
|
+
(typeNames.push_back(cppClassName(typeName(typeid(typename std::tuple_element<I, Arg_Ts>::type)))), ...);
|
74
|
+
return typeNames;
|
75
|
+
}
|
76
|
+
|
77
|
+
template<typename Class_T, typename Function_T, bool IsMethod>
|
78
|
+
std::string NativeFunction<Class_T, Function_T, IsMethod>::toString()
|
79
|
+
{
|
80
|
+
std::ostringstream result;
|
81
|
+
|
82
|
+
result << cppClassName(typeName(typeid(Return_T))) << " ";
|
83
|
+
|
84
|
+
if (!std::is_null_pointer_v<Receiver_T>)
|
85
|
+
{
|
86
|
+
result << cppClassName(typeName(typeid(Receiver_T))) << "::";
|
87
|
+
}
|
88
|
+
|
89
|
+
result << this->method_name_;
|
90
|
+
|
91
|
+
result << "(";
|
92
|
+
|
93
|
+
auto indices = std::make_index_sequence<std::tuple_size_v<Arg_Ts>>{};
|
94
|
+
std::vector<std::string> argTypeNames = this->argTypeNames(result, indices);
|
95
|
+
for (size_t i = 0; i < argTypeNames.size(); i++)
|
96
|
+
{
|
97
|
+
result << argTypeNames[i];
|
98
|
+
if (i < argTypeNames.size() - 1)
|
99
|
+
result << ", ";
|
100
|
+
}
|
101
|
+
result << ")";
|
102
|
+
return result.str();
|
103
|
+
}
|
104
|
+
|
105
|
+
template<typename Class_T, typename Function_T, bool IsMethod>
|
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
|
+
|
52
119
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
53
120
|
template<typename T, std::size_t I>
|
54
121
|
From_Ruby<T> NativeFunction<Class_T, Function_T, IsMethod>::createFromRuby()
|
@@ -56,7 +123,7 @@ namespace Rice::detail
|
|
56
123
|
// Does the From_Ruby instantiation work with Arg?
|
57
124
|
if constexpr (std::is_constructible_v<From_Ruby<T>, Arg*>)
|
58
125
|
{
|
59
|
-
return From_Ruby<T>(
|
126
|
+
return From_Ruby<T>(this->methodInfo_->arg(I));
|
60
127
|
}
|
61
128
|
else
|
62
129
|
{
|
@@ -65,60 +132,220 @@ namespace Rice::detail
|
|
65
132
|
}
|
66
133
|
|
67
134
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
68
|
-
|
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)
|
69
137
|
{
|
70
|
-
|
71
|
-
|
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())
|
72
152
|
{
|
73
|
-
|
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
|
+
}
|
74
185
|
}
|
75
|
-
|
186
|
+
// Last check if a default value has been set
|
187
|
+
else if (arg->hasDefaultValue())
|
76
188
|
{
|
77
|
-
|
189
|
+
result = Convertible::Exact;
|
78
190
|
}
|
191
|
+
|
192
|
+
return result;
|
79
193
|
}
|
80
194
|
|
81
195
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
82
196
|
template<std::size_t... I>
|
83
|
-
|
197
|
+
Convertible NativeFunction<Class_T, Function_T, IsMethod>::matchParameters(std::vector<std::optional<VALUE>>& values,
|
198
|
+
std::index_sequence<I...>& indices)
|
84
199
|
{
|
85
|
-
|
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;
|
86
228
|
}
|
87
229
|
|
88
230
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
89
|
-
std::vector<VALUE
|
231
|
+
std::vector<std::optional<VALUE>> NativeFunction<Class_T, Function_T, IsMethod>::getRubyValues(size_t argc, const VALUE* argv, bool validate)
|
90
232
|
{
|
91
|
-
|
92
|
-
|
93
|
-
std::
|
94
|
-
|
95
|
-
//
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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++)
|
103
248
|
{
|
104
|
-
|
105
|
-
}
|
249
|
+
result[i] = argv[i];
|
250
|
+
}
|
106
251
|
|
107
|
-
|
108
|
-
|
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);
|
109
291
|
|
110
|
-
|
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");
|
111
336
|
}
|
112
337
|
|
113
338
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
114
339
|
template<std::size_t... I>
|
115
|
-
typename NativeFunction<Class_T, Function_T, IsMethod>::Arg_Ts NativeFunction<Class_T, Function_T, IsMethod>::getNativeValues(std::vector<VALUE
|
340
|
+
typename NativeFunction<Class_T, Function_T, IsMethod>::Arg_Ts NativeFunction<Class_T, Function_T, IsMethod>::getNativeValues(std::vector<std::optional<VALUE>>& values,
|
116
341
|
std::index_sequence<I...>& indices)
|
117
342
|
{
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
343
|
+
/* Loop over each value returned from Ruby and convert it to the appropriate C++ type based
|
344
|
+
on the arguments (Arg_Ts) required by the C++ function. Arg_T may have const/volatile while
|
345
|
+
the associated From_Ruby<T> template parameter will not. Thus From_Ruby produces non-const values
|
346
|
+
which we let the compiler convert to const values as needed. This works except for
|
347
|
+
T** -> const T**, see comment in getNativeValue method. */
|
348
|
+
return std::forward_as_tuple(this->getNativeValue<std::tuple_element_t<I, Arg_Ts>, I>(values)...);
|
122
349
|
}
|
123
350
|
|
124
351
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
@@ -140,11 +367,19 @@ namespace Rice::detail
|
|
140
367
|
that was wrapped so it can correctly extract the C++ object from
|
141
368
|
the Ruby object. */
|
142
369
|
else if constexpr (!std::is_same_v<intrinsic_type<Receiver_T>, Class_T> &&
|
143
|
-
std::is_base_of_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>)
|
144
372
|
{
|
145
373
|
Class_T* instance = From_Ruby<Class_T*>().convert(self);
|
146
374
|
return dynamic_cast<Receiver_T>(instance);
|
147
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
|
+
}
|
148
383
|
// Self parameter could be derived from Object or it is an C++ instance and
|
149
384
|
// needs to be unwrapped from Ruby
|
150
385
|
else
|
@@ -154,37 +389,37 @@ namespace Rice::detail
|
|
154
389
|
}
|
155
390
|
|
156
391
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
157
|
-
VALUE NativeFunction<Class_T, Function_T, IsMethod>::invokeNativeFunction(
|
392
|
+
VALUE NativeFunction<Class_T, Function_T, IsMethod>::invokeNativeFunction(Arg_Ts&& nativeArgs)
|
158
393
|
{
|
159
394
|
if constexpr (std::is_void_v<Return_T>)
|
160
395
|
{
|
161
|
-
std::apply(this->function_, nativeArgs);
|
396
|
+
std::apply(this->function_, std::forward<Arg_Ts>(nativeArgs));
|
162
397
|
return Qnil;
|
163
398
|
}
|
164
399
|
else
|
165
400
|
{
|
166
401
|
// Call the native method and get the result
|
167
|
-
Return_T nativeResult = std::apply(this->function_, nativeArgs);
|
402
|
+
Return_T nativeResult = std::apply(this->function_, std::forward<Arg_Ts>(nativeArgs));
|
168
403
|
|
169
404
|
// Return the result
|
170
|
-
return this->toRuby_.convert(nativeResult);
|
405
|
+
return this->toRuby_.convert(std::forward<Return_T>(nativeResult));
|
171
406
|
}
|
172
407
|
}
|
173
408
|
|
174
409
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
175
|
-
VALUE NativeFunction<Class_T, Function_T, IsMethod>::invokeNativeMethod(VALUE self,
|
410
|
+
VALUE NativeFunction<Class_T, Function_T, IsMethod>::invokeNativeMethod(VALUE self, Arg_Ts&& nativeArgs)
|
176
411
|
{
|
177
412
|
Receiver_T receiver = this->getReceiver(self);
|
178
|
-
auto selfAndNativeArgs = std::tuple_cat(std::forward_as_tuple(receiver), nativeArgs);
|
413
|
+
auto selfAndNativeArgs = std::tuple_cat(std::forward_as_tuple(receiver), std::forward<Arg_Ts>(nativeArgs));
|
179
414
|
|
180
415
|
if constexpr (std::is_void_v<Return_T>)
|
181
416
|
{
|
182
|
-
std::apply(this->function_, selfAndNativeArgs);
|
417
|
+
std::apply(this->function_, std::forward<decltype(selfAndNativeArgs)>(selfAndNativeArgs));
|
183
418
|
return Qnil;
|
184
419
|
}
|
185
420
|
else
|
186
421
|
{
|
187
|
-
Return_T nativeResult =
|
422
|
+
Return_T nativeResult = std::apply(this->function_, std::forward<decltype(selfAndNativeArgs)>(selfAndNativeArgs));
|
188
423
|
|
189
424
|
// Special handling if the method returns self. If so we do not want
|
190
425
|
// to create a new Ruby wrapper object and instead return self.
|
@@ -212,7 +447,7 @@ namespace Rice::detail
|
|
212
447
|
}
|
213
448
|
}
|
214
449
|
|
215
|
-
return this->toRuby_.convert(nativeResult);
|
450
|
+
return this->toRuby_.convert(std::forward<Return_T>(nativeResult));
|
216
451
|
}
|
217
452
|
}
|
218
453
|
|
@@ -233,11 +468,15 @@ namespace Rice::detail
|
|
233
468
|
}
|
234
469
|
|
235
470
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
236
|
-
void NativeFunction<Class_T, Function_T, IsMethod>::checkKeepAlive(VALUE self, VALUE returnValue, std::vector<VALUE
|
471
|
+
void NativeFunction<Class_T, Function_T, IsMethod>::checkKeepAlive(VALUE self, VALUE returnValue, std::vector<std::optional<VALUE>>& rubyValues)
|
237
472
|
{
|
473
|
+
// Self will be Qnil for wrapped procs
|
474
|
+
if (self == Qnil)
|
475
|
+
return;
|
476
|
+
|
238
477
|
// selfWrapper will be nullptr if this(self) is a builtin type and not an external(wrapped) type
|
239
478
|
// it is highly unlikely that keepAlive is used in this case but we check anyway
|
240
|
-
|
479
|
+
WrapperBase* selfWrapper = getWrapper(self);
|
241
480
|
|
242
481
|
// Check function arguments
|
243
482
|
for (const Arg& arg : (*this->methodInfo_))
|
@@ -248,7 +487,7 @@ namespace Rice::detail
|
|
248
487
|
{
|
249
488
|
noWrapper(self, "self");
|
250
489
|
}
|
251
|
-
selfWrapper->addKeepAlive(rubyValues[arg.position]);
|
490
|
+
selfWrapper->addKeepAlive(rubyValues[arg.position].value());
|
252
491
|
}
|
253
492
|
}
|
254
493
|
|
@@ -261,7 +500,7 @@ namespace Rice::detail
|
|
261
500
|
}
|
262
501
|
|
263
502
|
// returnWrapper will be nullptr if returnValue is a built-in type and not an external(wrapped) type
|
264
|
-
|
503
|
+
WrapperBase* returnWrapper = getWrapper(returnValue);
|
265
504
|
if (returnWrapper == nullptr)
|
266
505
|
{
|
267
506
|
noWrapper(returnValue, "return");
|
@@ -271,10 +510,10 @@ namespace Rice::detail
|
|
271
510
|
}
|
272
511
|
|
273
512
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
274
|
-
VALUE NativeFunction<Class_T, Function_T, IsMethod>::operator()(
|
513
|
+
VALUE NativeFunction<Class_T, Function_T, IsMethod>::operator()(size_t argc, const VALUE* argv, VALUE self)
|
275
514
|
{
|
276
|
-
// Get the ruby values
|
277
|
-
std::vector<VALUE
|
515
|
+
// Get the ruby values and make sure we have the correct number
|
516
|
+
std::vector<std::optional<VALUE>> rubyValues = this->getRubyValues(argc, argv, true);
|
278
517
|
|
279
518
|
auto indices = std::make_index_sequence<std::tuple_size_v<Arg_Ts>>{};
|
280
519
|
|
@@ -285,11 +524,11 @@ namespace Rice::detail
|
|
285
524
|
VALUE result = Qnil;
|
286
525
|
if constexpr (std::is_same_v<Receiver_T, std::nullptr_t>)
|
287
526
|
{
|
288
|
-
result = this->invokeNativeFunction(nativeValues);
|
527
|
+
result = this->invokeNativeFunction(std::forward<Arg_Ts>(nativeValues));
|
289
528
|
}
|
290
529
|
else
|
291
530
|
{
|
292
|
-
result = this->invokeNativeMethod(self, nativeValues);
|
531
|
+
result = this->invokeNativeMethod(self, std::forward<Arg_Ts>(nativeValues));
|
293
532
|
}
|
294
533
|
|
295
534
|
// Check if any function arguments or return values need to have their lifetimes tied to the receiver
|
@@ -1,26 +1,23 @@
|
|
1
|
-
#ifndef
|
2
|
-
#define
|
3
|
-
|
4
|
-
#include "../traits/function_traits.hpp"
|
1
|
+
#ifndef Rice__NativeIterator__hpp_
|
2
|
+
#define Rice__NativeIterator__hpp_
|
5
3
|
|
6
4
|
namespace Rice::detail
|
7
5
|
{
|
8
6
|
template<typename T, typename Iterator_Func_T>
|
9
|
-
class NativeIterator
|
7
|
+
class NativeIterator: Native
|
10
8
|
{
|
11
9
|
public:
|
12
10
|
using NativeIterator_T = NativeIterator<T, Iterator_Func_T>;
|
13
11
|
using Iterator_T = typename function_traits<Iterator_Func_T>::return_type;
|
14
12
|
using Value_T = typename std::iterator_traits<Iterator_T>::value_type;
|
13
|
+
using Reference_T = typename std::iterator_traits<Iterator_T>::reference;
|
15
14
|
using Difference_T = typename std::iterator_traits<Iterator_T>::difference_type;
|
15
|
+
using To_Ruby_T = remove_cv_recursive_t<Reference_T>;
|
16
16
|
|
17
17
|
public:
|
18
18
|
// Register function with Ruby
|
19
19
|
void static define(VALUE klass, std::string method_name, Iterator_Func_T begin, Iterator_Func_T end);
|
20
20
|
|
21
|
-
// Static member function that Ruby calls
|
22
|
-
static VALUE call(VALUE self);
|
23
|
-
|
24
21
|
public:
|
25
22
|
// Disallow creating/copying/moving
|
26
23
|
NativeIterator() = delete;
|
@@ -29,7 +26,9 @@ namespace Rice::detail
|
|
29
26
|
void operator=(const NativeIterator_T&) = delete;
|
30
27
|
void operator=(NativeIterator_T&&) = delete;
|
31
28
|
|
32
|
-
|
29
|
+
Resolved matches(size_t argc, const VALUE* argv, VALUE self) override;
|
30
|
+
VALUE operator()(size_t argc, const VALUE* argv, VALUE self) override;
|
31
|
+
std::string toString() override;
|
33
32
|
|
34
33
|
protected:
|
35
34
|
NativeIterator(VALUE klass, std::string method_name, Iterator_Func_T begin, Iterator_Func_T end);
|
@@ -44,6 +43,5 @@ namespace Rice::detail
|
|
44
43
|
Iterator_Func_T end_;
|
45
44
|
};
|
46
45
|
}
|
47
|
-
#include "NativeIterator.ipp"
|
48
46
|
|
49
|
-
#endif //
|
47
|
+
#endif // Rice__NativeIterator__hpp_
|