rice 4.5.0 → 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 +23 -0
- data/CMakeLists.txt +31 -0
- data/CMakePresets.json +75 -0
- data/COPYING +3 -2
- data/FindRuby.cmake +437 -0
- data/Rakefile +5 -4
- data/include/rice/rice.hpp +5436 -3201
- data/include/rice/stl.hpp +2355 -1269
- data/lib/make_rice_headers.rb +79 -0
- data/lib/mkmf-rice.rb +4 -0
- 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/Arg.hpp +7 -1
- data/rice/Arg.ipp +11 -2
- data/rice/Buffer.hpp +123 -0
- data/rice/Buffer.ipp +599 -0
- data/rice/Constructor.ipp +3 -3
- data/rice/Data_Object.hpp +2 -3
- data/rice/Data_Object.ipp +188 -188
- data/rice/Data_Type.hpp +4 -5
- data/rice/Data_Type.ipp +42 -26
- data/rice/Enum.hpp +0 -1
- data/rice/Enum.ipp +26 -23
- data/rice/Init.hpp +8 -0
- data/rice/Init.ipp +8 -0
- data/rice/MemoryView.ipp +1 -41
- data/rice/Return.hpp +1 -1
- data/rice/Return.ipp +6 -0
- 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/cpp_api/Identifier.hpp +46 -0
- data/rice/cpp_api/Identifier.ipp +31 -0
- 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/MethodInfo.hpp +1 -9
- data/rice/detail/MethodInfo.ipp +5 -72
- data/rice/detail/Native.hpp +3 -2
- data/rice/detail/Native.ipp +32 -4
- data/rice/detail/NativeAttributeGet.hpp +3 -2
- data/rice/detail/NativeAttributeGet.ipp +8 -2
- data/rice/detail/NativeAttributeSet.hpp +3 -2
- data/rice/detail/NativeAttributeSet.ipp +8 -2
- data/rice/detail/NativeCallbackFFI.ipp +1 -1
- data/rice/detail/NativeFunction.hpp +17 -6
- data/rice/detail/NativeFunction.ipp +168 -64
- data/rice/detail/NativeIterator.hpp +3 -2
- data/rice/detail/NativeIterator.ipp +8 -2
- data/rice/detail/RubyType.hpp +2 -5
- data/rice/detail/RubyType.ipp +50 -5
- data/rice/detail/Type.hpp +3 -1
- data/rice/detail/Type.ipp +61 -31
- data/rice/detail/Wrapper.hpp +68 -33
- data/rice/detail/Wrapper.ipp +103 -113
- data/rice/detail/from_ruby.hpp +5 -4
- data/rice/detail/from_ruby.ipp +737 -365
- data/rice/detail/to_ruby.ipp +1092 -186
- data/rice/global_function.ipp +1 -1
- data/rice/libc/file.hpp +11 -0
- data/rice/libc/file.ipp +32 -0
- data/rice/rice.hpp +23 -16
- 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 +7 -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 +3 -0
- data/test/ruby/test_multiple_extensions_same_class.rb +14 -14
- data/test/test_Array.cpp +6 -3
- data/test/test_Attribute.cpp +34 -1
- data/test/test_Buffer.cpp +285 -0
- data/test/test_Callback.cpp +2 -3
- data/test/test_Data_Object.cpp +88 -34
- data/test/test_Data_Type.cpp +106 -65
- data/test/test_Director.cpp +7 -3
- data/test/test_Enum.cpp +5 -2
- data/test/test_File.cpp +1 -1
- data/test/test_From_Ruby.cpp +181 -114
- data/test/test_Iterator.cpp +1 -1
- data/test/{test_JumpException.cpp → test_Jump_Exception.cpp} +1 -0
- data/test/test_Keep_Alive.cpp +7 -18
- data/test/test_Keep_Alive_No_Wrapper.cpp +0 -1
- data/test/test_Module.cpp +13 -6
- data/test/test_Native_Registry.cpp +0 -1
- data/test/test_Overloads.cpp +180 -5
- data/test/test_Ownership.cpp +100 -57
- data/test/test_Proc.cpp +0 -1
- data/test/test_Self.cpp +4 -4
- data/test/test_Stl_Map.cpp +37 -39
- data/test/test_Stl_Multimap.cpp +693 -0
- data/test/test_Stl_Pair.cpp +8 -8
- data/test/test_Stl_Reference_Wrapper.cpp +4 -2
- data/test/test_Stl_Set.cpp +790 -0
- data/test/{test_Stl_SmartPointer.cpp → test_Stl_SharedPtr.cpp} +97 -127
- data/test/test_Stl_Tuple.cpp +116 -0
- data/test/test_Stl_Type.cpp +1 -1
- data/test/test_Stl_UniquePtr.cpp +202 -0
- data/test/test_Stl_Unordered_Map.cpp +28 -34
- data/test/test_Stl_Variant.cpp +217 -89
- data/test/test_Stl_Vector.cpp +209 -83
- data/test/test_To_Ruby.cpp +373 -1
- data/test/test_Type.cpp +85 -14
- data/test/test_global_functions.cpp +17 -4
- metadata +94 -10
- data/rice/detail/TupleIterator.hpp +0 -14
@@ -21,7 +21,7 @@ namespace Rice::detail
|
|
21
21
|
}
|
22
22
|
|
23
23
|
template<typename Attribute_T>
|
24
|
-
inline Resolved NativeAttributeGet<Attribute_T>::matches(
|
24
|
+
inline Resolved NativeAttributeGet<Attribute_T>::matches(size_t argc, const VALUE* argv, VALUE self)
|
25
25
|
{
|
26
26
|
if (argc == 0)
|
27
27
|
return Resolved { Convertible::Exact, 1, this };
|
@@ -36,7 +36,7 @@ namespace Rice::detail
|
|
36
36
|
}
|
37
37
|
|
38
38
|
template<typename Attribute_T>
|
39
|
-
inline VALUE NativeAttributeGet<Attribute_T>::operator()(
|
39
|
+
inline VALUE NativeAttributeGet<Attribute_T>::operator()(size_t argc, const VALUE* argv, VALUE self)
|
40
40
|
{
|
41
41
|
if constexpr (std::is_member_object_pointer_v<Attribute_T>)
|
42
42
|
{
|
@@ -48,4 +48,10 @@ namespace Rice::detail
|
|
48
48
|
return To_Ruby<To_Ruby_T>().convert(*attribute_);
|
49
49
|
}
|
50
50
|
}
|
51
|
+
|
52
|
+
template<typename Attribute_T>
|
53
|
+
inline std::string NativeAttributeGet<Attribute_T>::toString()
|
54
|
+
{
|
55
|
+
return "";
|
56
|
+
}
|
51
57
|
} // Rice
|
@@ -26,8 +26,9 @@ namespace Rice
|
|
26
26
|
void operator=(const NativeAttribute_T&) = delete;
|
27
27
|
void operator=(NativeAttribute_T&&) = delete;
|
28
28
|
|
29
|
-
Resolved matches(
|
30
|
-
VALUE operator()(
|
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;
|
31
32
|
|
32
33
|
protected:
|
33
34
|
NativeAttributeSet(VALUE klass, std::string name, Attribute_T attr);
|
@@ -31,7 +31,7 @@ namespace Rice::detail
|
|
31
31
|
}
|
32
32
|
|
33
33
|
template<typename Attribute_T>
|
34
|
-
inline Resolved NativeAttributeSet<Attribute_T>::matches(
|
34
|
+
inline Resolved NativeAttributeSet<Attribute_T>::matches(size_t argc, const VALUE* argv, VALUE self)
|
35
35
|
{
|
36
36
|
if (argc == 1)
|
37
37
|
return Resolved{ Convertible::Exact, 1, this };
|
@@ -40,7 +40,7 @@ namespace Rice::detail
|
|
40
40
|
}
|
41
41
|
|
42
42
|
template<typename Attribute_T>
|
43
|
-
inline VALUE NativeAttributeSet<Attribute_T>::operator()(
|
43
|
+
inline VALUE NativeAttributeSet<Attribute_T>::operator()(size_t argc, const VALUE* argv, VALUE self)
|
44
44
|
{
|
45
45
|
if constexpr (std::is_fundamental_v<intrinsic_type<Attr_T>> && std::is_pointer_v<Attr_T>)
|
46
46
|
{
|
@@ -79,4 +79,10 @@ namespace Rice::detail
|
|
79
79
|
|
80
80
|
return value;
|
81
81
|
}
|
82
|
+
|
83
|
+
template<typename Attribute_T>
|
84
|
+
inline std::string NativeAttributeSet<Attribute_T>::toString()
|
85
|
+
{
|
86
|
+
return "";
|
87
|
+
}
|
82
88
|
} // Rice
|
@@ -118,7 +118,7 @@ namespace Rice::detail
|
|
118
118
|
|
119
119
|
// Create FFI closure
|
120
120
|
this->closure_ = (ffi_closure *)ffi_closure_alloc(sizeof(ffi_closure) + sizeof(void*), (void**)(&this->callback_));
|
121
|
-
|
121
|
+
ffi_prep_closure_loc(this->closure_, &cif_, ffiCallback, (void*)this, (void*)this->callback_);
|
122
122
|
}
|
123
123
|
|
124
124
|
template<typename Return_T, typename ...Arg_Ts>
|
@@ -64,14 +64,25 @@ namespace Rice::detail
|
|
64
64
|
void operator=(const NativeFunction_T&) = delete;
|
65
65
|
void operator=(NativeFunction_T&&) = delete;
|
66
66
|
|
67
|
-
Resolved matches(
|
68
|
-
VALUE operator()(
|
67
|
+
Resolved matches(size_t argc, const VALUE* argv, VALUE self) override;
|
68
|
+
VALUE operator()(size_t argc, const VALUE* argv, VALUE self) override;
|
69
|
+
std::string toString() override;
|
69
70
|
|
70
71
|
NativeFunction(Function_T function);
|
71
72
|
NativeFunction(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo);
|
73
|
+
|
72
74
|
protected:
|
73
75
|
|
74
76
|
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
|
+
template<std::size_t...I>
|
84
|
+
std::vector<std::string> argTypeNames(std::ostringstream& stream, std::index_sequence<I...>& indices);
|
85
|
+
|
75
86
|
template<typename T, std::size_t I>
|
76
87
|
From_Ruby<T> createFromRuby();
|
77
88
|
|
@@ -83,14 +94,14 @@ namespace Rice::detail
|
|
83
94
|
To_Ruby<To_Ruby_T> createToRuby();
|
84
95
|
|
85
96
|
// Convert Ruby argv pointer to Ruby values
|
86
|
-
std::vector<VALUE
|
97
|
+
std::vector<std::optional<VALUE>> getRubyValues(size_t argc, const VALUE* argv, bool validate);
|
87
98
|
|
88
99
|
template<typename Arg_T, int I>
|
89
|
-
Arg_T getNativeValue(std::vector<VALUE
|
100
|
+
Arg_T getNativeValue(std::vector<std::optional<VALUE>>& values);
|
90
101
|
|
91
102
|
// Convert Ruby values to C++ values
|
92
103
|
template<typename std::size_t...I>
|
93
|
-
Arg_Ts getNativeValues(std::vector<VALUE
|
104
|
+
Arg_Ts getNativeValues(std::vector<std::optional<VALUE>>& values, std::index_sequence<I...>& indices);
|
94
105
|
|
95
106
|
// Figure out what self is
|
96
107
|
Receiver_T getReceiver(VALUE self);
|
@@ -99,7 +110,7 @@ namespace Rice::detail
|
|
99
110
|
[[noreturn]] void noWrapper(const VALUE klass, const std::string& wrapper);
|
100
111
|
|
101
112
|
// Do we need to keep alive any arguments?
|
102
|
-
void checkKeepAlive(VALUE self, VALUE returnValue, std::vector<VALUE
|
113
|
+
void checkKeepAlive(VALUE self, VALUE returnValue, std::vector<std::optional<VALUE>>& rubyValues);
|
103
114
|
|
104
115
|
// Call the underlying C++ function
|
105
116
|
VALUE invokeNativeFunction(Arg_Ts&& nativeArgs);
|
@@ -1,9 +1,8 @@
|
|
1
|
-
#include <array>
|
2
1
|
#include <algorithm>
|
2
|
+
#include <array>
|
3
3
|
#include <stdexcept>
|
4
4
|
#include <sstream>
|
5
5
|
|
6
|
-
|
7
6
|
namespace Rice::detail
|
8
7
|
{
|
9
8
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
@@ -29,8 +28,11 @@ namespace Rice::detail
|
|
29
28
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
30
29
|
VALUE NativeFunction<Class_T, Function_T, IsMethod>::procEntry(VALUE yielded_arg, VALUE callback_arg, int argc, const VALUE* argv, VALUE blockarg)
|
31
30
|
{
|
32
|
-
|
33
|
-
|
31
|
+
return cpp_protect([&]
|
32
|
+
{
|
33
|
+
NativeFunction_T * native = (NativeFunction_T*)callback_arg;
|
34
|
+
return (*native)(argc, argv, Qnil);
|
35
|
+
});
|
34
36
|
}
|
35
37
|
|
36
38
|
// Ruby calls this method if an instance f a NativeFunction is owned by a Ruby proc. That happens when C++
|
@@ -43,7 +45,6 @@ namespace Rice::detail
|
|
43
45
|
return Qnil;
|
44
46
|
}
|
45
47
|
|
46
|
-
|
47
48
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
48
49
|
NativeFunction<Class_T, Function_T, IsMethod>::NativeFunction(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo)
|
49
50
|
: klass_(klass), method_name_(method_name), function_(function), methodInfo_(methodInfo)
|
@@ -64,6 +65,43 @@ namespace Rice::detail
|
|
64
65
|
{
|
65
66
|
}
|
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
|
+
|
67
105
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
68
106
|
To_Ruby<typename NativeFunction<Class_T, Function_T, IsMethod>::To_Ruby_T> NativeFunction<Class_T, Function_T, IsMethod>::createToRuby()
|
69
107
|
{
|
@@ -101,60 +139,100 @@ namespace Rice::detail
|
|
101
139
|
}
|
102
140
|
|
103
141
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
104
|
-
|
142
|
+
template<int I>
|
143
|
+
Convertible NativeFunction<Class_T, Function_T, IsMethod>::matchParameter(std::vector<std::optional<VALUE>>& values)
|
105
144
|
{
|
106
|
-
|
107
|
-
if (argc > arity)
|
108
|
-
return Resolved{ Convertible::None, 0, this };
|
109
|
-
|
110
|
-
Resolved result { Convertible::Exact, 1, this };
|
111
|
-
|
145
|
+
Convertible result = Convertible::None;
|
112
146
|
MethodInfo* methodInfo = this->methodInfo_.get();
|
113
|
-
|
114
|
-
|
115
|
-
std::vector<VALUE> rubyValues = this->getRubyValues(argc, argv, false);
|
147
|
+
const Arg* arg = methodInfo->arg(I);
|
148
|
+
std::optional<VALUE> value = values[I];
|
116
149
|
|
117
|
-
//
|
118
|
-
|
119
|
-
|
150
|
+
// Is a VALUE being passed directly to C++ ?
|
151
|
+
if (value.has_value())
|
152
|
+
{
|
153
|
+
if (arg->isValue())
|
120
154
|
{
|
121
|
-
|
122
|
-
|
123
|
-
|
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);
|
124
164
|
|
125
|
-
//
|
126
|
-
if (
|
127
|
-
{
|
128
|
-
convertible = Convertible::Exact;
|
129
|
-
}
|
130
|
-
// If index is less than argc then check with FromRuby if the VALUE is convertible
|
131
|
-
// to C++.
|
132
|
-
else if (index < rubyValues.size())
|
133
|
-
{
|
134
|
-
VALUE value = rubyValues[index];
|
135
|
-
convertible = fromRuby.is_convertible(value);
|
136
|
-
}
|
137
|
-
// Last check if a default value has been set
|
138
|
-
else if (arg->hasDefaultValue())
|
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)
|
139
167
|
{
|
140
|
-
|
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
|
+
}
|
141
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
|
+
}
|
142
204
|
|
143
|
-
|
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 };
|
144
211
|
|
145
|
-
|
146
|
-
|
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);
|
147
217
|
|
148
218
|
if constexpr (arity > 0)
|
149
|
-
|
219
|
+
{
|
220
|
+
int providedValues = std::count_if(rubyValues.begin(), rubyValues.end(), [](std::optional<VALUE>& value)
|
221
|
+
{
|
222
|
+
return value.has_value();
|
223
|
+
});
|
150
224
|
|
225
|
+
result.parameterMatch = providedValues / (double)arity;
|
226
|
+
}
|
151
227
|
return result;
|
152
228
|
}
|
153
229
|
|
154
230
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
155
|
-
std::vector<VALUE
|
231
|
+
std::vector<std::optional<VALUE>> NativeFunction<Class_T, Function_T, IsMethod>::getRubyValues(size_t argc, const VALUE* argv, bool validate)
|
156
232
|
{
|
157
|
-
|
233
|
+
#undef max
|
234
|
+
int size = std::max((size_t)arity, (size_t)argc);
|
235
|
+
std::vector<std::optional<VALUE>> result(size);
|
158
236
|
|
159
237
|
// Keyword handling
|
160
238
|
if (rb_keyword_given_p())
|
@@ -165,9 +243,7 @@ namespace Rice::detail
|
|
165
243
|
VALUE value = argv[actualArgc];
|
166
244
|
Hash keywords(value);
|
167
245
|
|
168
|
-
|
169
|
-
|
170
|
-
// Copy over leading arguments
|
246
|
+
// Copy over leading non-keyword arguments
|
171
247
|
for (int i = 0; i < actualArgc; i++)
|
172
248
|
{
|
173
249
|
result[i] = argv[i];
|
@@ -187,20 +263,39 @@ namespace Rice::detail
|
|
187
263
|
}
|
188
264
|
else
|
189
265
|
{
|
190
|
-
std::copy(argv, argv + argc,
|
266
|
+
std::copy(argv, argv + argc, result.begin());
|
191
267
|
}
|
192
268
|
|
193
269
|
// Block handling. If we find a block and the last parameter is missing then
|
194
270
|
// set it to the block
|
195
|
-
if (rb_block_given_p() && result.size()
|
271
|
+
if (rb_block_given_p() && result.size() > 0 && !result.back().has_value())
|
196
272
|
{
|
197
273
|
VALUE proc = rb_block_proc();
|
198
|
-
result.
|
274
|
+
result.back() = proc;
|
199
275
|
}
|
200
276
|
|
201
277
|
if (validate)
|
202
278
|
{
|
203
|
-
|
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
|
+
}
|
204
299
|
}
|
205
300
|
|
206
301
|
return result;
|
@@ -208,7 +303,7 @@ namespace Rice::detail
|
|
208
303
|
|
209
304
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
210
305
|
template<typename Arg_T, int I>
|
211
|
-
Arg_T NativeFunction<Class_T, Function_T, IsMethod>::getNativeValue(std::vector<VALUE
|
306
|
+
Arg_T NativeFunction<Class_T, Function_T, IsMethod>::getNativeValue(std::vector<std::optional<VALUE>>& values)
|
212
307
|
{
|
213
308
|
/* In general the compiler will convert T to const T, but that does not work for converting
|
214
309
|
T** to const T** (see see https://isocpp.org/wiki/faq/const-correctness#constptrptr-conversion)
|
@@ -218,22 +313,31 @@ namespace Rice::detail
|
|
218
313
|
the return type. That works but requires a lot more code changes for this one case and is not
|
219
314
|
backwards compatible. */
|
220
315
|
|
221
|
-
|
222
|
-
|
316
|
+
std::optional<VALUE> value = values[I];
|
317
|
+
Arg* arg = this->methodInfo_->arg(I);
|
223
318
|
|
224
319
|
if constexpr (is_pointer_pointer_v<Arg_T> && !std::is_convertible_v<remove_cv_recursive_t<Arg_T>, Arg_T>)
|
225
320
|
{
|
226
|
-
return (Arg_T)std::get<I>(this->fromRubys_).convert(value);
|
321
|
+
return (Arg_T)std::get<I>(this->fromRubys_).convert(value.value());
|
227
322
|
}
|
228
|
-
else
|
323
|
+
else if (value.has_value())
|
229
324
|
{
|
230
|
-
return std::get<I>(this->fromRubys_).convert(value);
|
325
|
+
return std::get<I>(this->fromRubys_).convert(value.value());
|
231
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");
|
232
336
|
}
|
233
337
|
|
234
338
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
235
339
|
template<std::size_t... I>
|
236
|
-
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,
|
237
341
|
std::index_sequence<I...>& indices)
|
238
342
|
{
|
239
343
|
/* Loop over each value returned from Ruby and convert it to the appropriate C++ type based
|
@@ -298,7 +402,7 @@ namespace Rice::detail
|
|
298
402
|
Return_T nativeResult = std::apply(this->function_, std::forward<Arg_Ts>(nativeArgs));
|
299
403
|
|
300
404
|
// Return the result
|
301
|
-
return this->toRuby_.convert(nativeResult);
|
405
|
+
return this->toRuby_.convert(std::forward<Return_T>(nativeResult));
|
302
406
|
}
|
303
407
|
}
|
304
408
|
|
@@ -343,7 +447,7 @@ namespace Rice::detail
|
|
343
447
|
}
|
344
448
|
}
|
345
449
|
|
346
|
-
return this->toRuby_.convert(nativeResult);
|
450
|
+
return this->toRuby_.convert(std::forward<Return_T>(nativeResult));
|
347
451
|
}
|
348
452
|
}
|
349
453
|
|
@@ -364,7 +468,7 @@ namespace Rice::detail
|
|
364
468
|
}
|
365
469
|
|
366
470
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
367
|
-
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)
|
368
472
|
{
|
369
473
|
// Self will be Qnil for wrapped procs
|
370
474
|
if (self == Qnil)
|
@@ -372,7 +476,7 @@ namespace Rice::detail
|
|
372
476
|
|
373
477
|
// selfWrapper will be nullptr if this(self) is a builtin type and not an external(wrapped) type
|
374
478
|
// it is highly unlikely that keepAlive is used in this case but we check anyway
|
375
|
-
|
479
|
+
WrapperBase* selfWrapper = getWrapper(self);
|
376
480
|
|
377
481
|
// Check function arguments
|
378
482
|
for (const Arg& arg : (*this->methodInfo_))
|
@@ -383,7 +487,7 @@ namespace Rice::detail
|
|
383
487
|
{
|
384
488
|
noWrapper(self, "self");
|
385
489
|
}
|
386
|
-
selfWrapper->addKeepAlive(rubyValues[arg.position]);
|
490
|
+
selfWrapper->addKeepAlive(rubyValues[arg.position].value());
|
387
491
|
}
|
388
492
|
}
|
389
493
|
|
@@ -396,7 +500,7 @@ namespace Rice::detail
|
|
396
500
|
}
|
397
501
|
|
398
502
|
// returnWrapper will be nullptr if returnValue is a built-in type and not an external(wrapped) type
|
399
|
-
|
503
|
+
WrapperBase* returnWrapper = getWrapper(returnValue);
|
400
504
|
if (returnWrapper == nullptr)
|
401
505
|
{
|
402
506
|
noWrapper(returnValue, "return");
|
@@ -406,10 +510,10 @@ namespace Rice::detail
|
|
406
510
|
}
|
407
511
|
|
408
512
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
409
|
-
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)
|
410
514
|
{
|
411
515
|
// Get the ruby values and make sure we have the correct number
|
412
|
-
std::vector<VALUE
|
516
|
+
std::vector<std::optional<VALUE>> rubyValues = this->getRubyValues(argc, argv, true);
|
413
517
|
|
414
518
|
auto indices = std::make_index_sequence<std::tuple_size_v<Arg_Ts>>{};
|
415
519
|
|
@@ -26,8 +26,9 @@ namespace Rice::detail
|
|
26
26
|
void operator=(const NativeIterator_T&) = delete;
|
27
27
|
void operator=(NativeIterator_T&&) = delete;
|
28
28
|
|
29
|
-
Resolved matches(
|
30
|
-
VALUE operator()(
|
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;
|
31
32
|
|
32
33
|
protected:
|
33
34
|
NativeIterator(VALUE klass, std::string method_name, Iterator_Func_T begin, Iterator_Func_T end);
|
@@ -26,7 +26,7 @@ namespace Rice::detail
|
|
26
26
|
}
|
27
27
|
|
28
28
|
template<typename T, typename Iterator_Func_T>
|
29
|
-
inline Resolved NativeIterator<T, Iterator_Func_T>::matches(
|
29
|
+
inline Resolved NativeIterator<T, Iterator_Func_T>::matches(size_t argc, const VALUE* argv, VALUE self)
|
30
30
|
{
|
31
31
|
return Resolved{ Convertible::Exact, 1.0, this };
|
32
32
|
}
|
@@ -72,7 +72,7 @@ namespace Rice::detail
|
|
72
72
|
}
|
73
73
|
|
74
74
|
template<typename T, typename Iterator_Func_T>
|
75
|
-
inline VALUE NativeIterator<T, Iterator_Func_T>::operator()(
|
75
|
+
inline VALUE NativeIterator<T, Iterator_Func_T>::operator()(size_t argc, const VALUE* argv, VALUE self)
|
76
76
|
{
|
77
77
|
if (!protect(rb_block_given_p))
|
78
78
|
{
|
@@ -95,4 +95,10 @@ namespace Rice::detail
|
|
95
95
|
return self;
|
96
96
|
}
|
97
97
|
}
|
98
|
+
|
99
|
+
template<typename T, typename Iterator_Func_T>
|
100
|
+
inline std::string NativeIterator<T, Iterator_Func_T>::toString()
|
101
|
+
{
|
102
|
+
return "";
|
103
|
+
}
|
98
104
|
}
|
data/rice/detail/RubyType.hpp
CHANGED
@@ -8,12 +8,9 @@ namespace Rice::detail
|
|
8
8
|
template <typename T>
|
9
9
|
class RubyType
|
10
10
|
{
|
11
|
-
public:
|
12
|
-
static std::set<ruby_value_type> types();
|
13
|
-
static std::set<ruby_value_type> convertibleFrom();
|
14
|
-
static T(*converter)(VALUE);
|
15
|
-
static std::string packTemplate;
|
16
11
|
};
|
12
|
+
|
13
|
+
void define_ruby_types();
|
17
14
|
}
|
18
15
|
|
19
16
|
#endif // Rice__detail__ruby__type__hpp_
|
data/rice/detail/RubyType.ipp
CHANGED
@@ -89,7 +89,9 @@ namespace Rice::detail
|
|
89
89
|
static inline FromRuby_T fromRuby = rb_num2int_inline;
|
90
90
|
static inline std::set<ruby_value_type> Exact = { RUBY_T_FIXNUM };
|
91
91
|
static inline std::set<ruby_value_type> Castable = { };
|
92
|
-
|
92
|
+
// We allow bignum to integer because Ruby switches to bignum at about 2 billion on 64 bit systems,
|
93
|
+
// while int can go up to 4 billion
|
94
|
+
static inline std::set<ruby_value_type> Narrowable = { RUBY_T_BIGNUM };
|
93
95
|
static inline std::string packTemplate = "i*";
|
94
96
|
};
|
95
97
|
|
@@ -102,7 +104,9 @@ namespace Rice::detail
|
|
102
104
|
static inline FromRuby_T fromRuby = RB_NUM2UINT;
|
103
105
|
static inline std::set<ruby_value_type> Exact = { RUBY_T_FIXNUM };
|
104
106
|
static inline std::set<ruby_value_type> Castable = { };
|
105
|
-
|
107
|
+
// We allow bignum to integer because Ruby switches to bignum at about 2 billion on 64 bit systems,
|
108
|
+
// while int can go up to 4 billion
|
109
|
+
static inline std::set<ruby_value_type> Narrowable = { RUBY_T_BIGNUM };
|
106
110
|
static inline std::string packTemplate = "I*";
|
107
111
|
};
|
108
112
|
|
@@ -115,7 +119,7 @@ namespace Rice::detail
|
|
115
119
|
static inline FromRuby_T fromRuby = rb_num2long_inline;
|
116
120
|
static inline std::set<ruby_value_type> Exact = { RUBY_T_FIXNUM };
|
117
121
|
static inline std::set<ruby_value_type> Castable = { };
|
118
|
-
static inline std::set<ruby_value_type> Narrowable = { };
|
122
|
+
static inline std::set<ruby_value_type> Narrowable = { RUBY_T_BIGNUM };
|
119
123
|
static inline std::string packTemplate = "l_*";
|
120
124
|
};
|
121
125
|
|
@@ -128,7 +132,7 @@ namespace Rice::detail
|
|
128
132
|
static inline FromRuby_T fromRuby = rb_num2ulong_inline;
|
129
133
|
static inline std::set<ruby_value_type> Exact = { RUBY_T_FIXNUM };
|
130
134
|
static inline std::set<ruby_value_type> Castable = { };
|
131
|
-
static inline std::set<ruby_value_type> Narrowable = { };
|
135
|
+
static inline std::set<ruby_value_type> Narrowable = { RUBY_T_BIGNUM};
|
132
136
|
static inline std::string packTemplate = "L_*";
|
133
137
|
};
|
134
138
|
|
@@ -158,7 +162,6 @@ namespace Rice::detail
|
|
158
162
|
static inline std::string packTemplate = "Q_*";
|
159
163
|
};
|
160
164
|
|
161
|
-
|
162
165
|
template<>
|
163
166
|
class RubyType<float>
|
164
167
|
{
|
@@ -184,4 +187,46 @@ namespace Rice::detail
|
|
184
187
|
static inline std::set<ruby_value_type> Narrowable = { };
|
185
188
|
static inline std::string packTemplate = "d*";
|
186
189
|
};
|
190
|
+
|
191
|
+
template<>
|
192
|
+
class RubyType<void>
|
193
|
+
{
|
194
|
+
public:
|
195
|
+
static inline std::set<ruby_value_type> Exact = { };
|
196
|
+
static inline std::set<ruby_value_type> Castable = { };
|
197
|
+
static inline std::set<ruby_value_type> Narrowable = { };
|
198
|
+
};
|
199
|
+
}
|
200
|
+
|
201
|
+
namespace Rice::detail
|
202
|
+
{
|
203
|
+
template<typename T>
|
204
|
+
inline Data_Type<T> define_ruby_type()
|
205
|
+
{
|
206
|
+
std::string name = detail::typeName(typeid(T*));
|
207
|
+
std::string klassName = detail::rubyClassName(name);
|
208
|
+
Identifier id(klassName);
|
209
|
+
|
210
|
+
Module rb_mRice = define_module("Rice");
|
211
|
+
return define_class_under<T>(rb_mRice, id);
|
212
|
+
}
|
213
|
+
|
214
|
+
inline void define_ruby_types()
|
215
|
+
{
|
216
|
+
define_ruby_type<bool>();
|
217
|
+
define_ruby_type<char>();
|
218
|
+
define_ruby_type<signed char>();
|
219
|
+
define_ruby_type<unsigned char>();
|
220
|
+
define_ruby_type<short>();
|
221
|
+
define_ruby_type<unsigned short>();
|
222
|
+
define_ruby_type<int>();
|
223
|
+
define_ruby_type<unsigned int>();
|
224
|
+
define_ruby_type<long>();
|
225
|
+
define_ruby_type<unsigned long>();
|
226
|
+
define_ruby_type<long long>();
|
227
|
+
define_ruby_type<unsigned long long>();
|
228
|
+
define_ruby_type<float>();
|
229
|
+
define_ruby_type<double>();
|
230
|
+
define_ruby_type<void>();
|
231
|
+
}
|
187
232
|
}
|