rice 4.5.0 → 4.6.1
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 +33 -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 +5619 -3129
- data/include/rice/stl.hpp +2319 -1234
- 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 +168 -0
- data/rice/Buffer.ipp +788 -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 +7 -5
- data/rice/Data_Type.ipp +79 -52
- 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 +20 -3
- data/rice/detail/NativeAttributeSet.hpp +3 -2
- data/rice/detail/NativeAttributeSet.ipp +11 -23
- data/rice/detail/NativeCallbackFFI.ipp +2 -1
- data/rice/detail/NativeFunction.hpp +17 -6
- data/rice/detail/NativeFunction.ipp +169 -64
- data/rice/detail/NativeIterator.hpp +3 -2
- data/rice/detail/NativeIterator.ipp +8 -2
- data/rice/detail/RubyFunction.ipp +1 -0
- 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 +60 -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 +589 -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 +172 -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 +91 -9
- data/test/test_Buffer.cpp +340 -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 +180 -113
- 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,16 +36,33 @@ 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
|
{
|
43
43
|
Receiver_T* nativeSelf = From_Ruby<Receiver_T*>().convert(self);
|
44
|
-
|
44
|
+
|
45
|
+
if constexpr (std::is_fundamental_v<detail::intrinsic_type<To_Ruby_T>> ||
|
46
|
+
(std::is_array_v<To_Ruby_T> && std::is_fundamental_v<std::remove_extent_t<To_Ruby_T>>))
|
47
|
+
{
|
48
|
+
return To_Ruby<To_Ruby_T>().convert(nativeSelf->*attribute_);
|
49
|
+
}
|
50
|
+
else
|
51
|
+
{
|
52
|
+
// If the attribute is an object return a reference to avoid a copy (and avoid issues with
|
53
|
+
// attributes that are not assignable, copy constructible or move constructible)
|
54
|
+
return To_Ruby<To_Ruby_T&>().convert(nativeSelf->*attribute_);
|
55
|
+
}
|
45
56
|
}
|
46
57
|
else
|
47
58
|
{
|
48
59
|
return To_Ruby<To_Ruby_T>().convert(*attribute_);
|
49
60
|
}
|
50
61
|
}
|
62
|
+
|
63
|
+
template<typename Attribute_T>
|
64
|
+
inline std::string NativeAttributeGet<Attribute_T>::toString()
|
65
|
+
{
|
66
|
+
return "";
|
67
|
+
}
|
51
68
|
} // 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,43 +40,31 @@ 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
|
-
if constexpr (std::is_fundamental_v<intrinsic_type<Attr_T>> && std::is_pointer_v<Attr_T>)
|
46
|
-
{
|
47
|
-
static_assert(true, "An fundamental value, such as an integer, cannot be assigned to an attribute that is a pointer.");
|
48
|
-
}
|
49
|
-
else if constexpr (std::is_same_v<intrinsic_type<Attr_T>, std::string> && std::is_pointer_v<Attr_T>)
|
50
|
-
{
|
51
|
-
static_assert(true, "An string cannot be assigned to an attribute that is a pointer.");
|
52
|
-
}
|
53
|
-
|
54
45
|
if (argc != 1)
|
55
46
|
{
|
56
47
|
throw std::runtime_error("Incorrect number of parameters for setting attribute. Attribute: " + this->name_);
|
57
48
|
}
|
58
49
|
|
59
50
|
VALUE value = argv[0];
|
60
|
-
|
61
|
-
if constexpr (!std::is_null_pointer_v<Receiver_T>
|
62
|
-
!std::is_const_v<Attr_T> &&
|
63
|
-
(std::is_fundamental_v<Attr_T> || std::is_assignable_v<Attr_T, Attr_T>))
|
51
|
+
|
52
|
+
if constexpr (!std::is_null_pointer_v<Receiver_T>)
|
64
53
|
{
|
65
54
|
Receiver_T* nativeSelf = From_Ruby<Receiver_T*>().convert(self);
|
66
55
|
nativeSelf->*attribute_ = From_Ruby<T_Unqualified>().convert(value);
|
67
56
|
}
|
68
|
-
else if constexpr (std::is_null_pointer_v<Receiver_T> &&
|
69
|
-
!std::is_const_v<Attr_T> &&
|
70
|
-
(std::is_fundamental_v<Attr_T> || std::is_assignable_v<Attr_T, Attr_T>))
|
71
|
-
{
|
72
|
-
*attribute_ = From_Ruby<T_Unqualified>().convert(value);
|
73
|
-
}
|
74
57
|
else
|
75
58
|
{
|
76
|
-
|
77
|
-
throw std::invalid_argument("Could not set attribute. Attribute: " + this->name_);
|
59
|
+
*attribute_ = From_Ruby<T_Unqualified>().convert(value);
|
78
60
|
}
|
79
61
|
|
80
62
|
return value;
|
81
63
|
}
|
64
|
+
|
65
|
+
template<typename Attribute_T>
|
66
|
+
inline std::string NativeAttributeSet<Attribute_T>::toString()
|
67
|
+
{
|
68
|
+
return "";
|
69
|
+
}
|
82
70
|
} // Rice
|
@@ -1,4 +1,5 @@
|
|
1
1
|
#ifdef HAVE_LIBFFI
|
2
|
+
#include <tuple>
|
2
3
|
#include <ffi.h>
|
3
4
|
|
4
5
|
namespace Rice::detail
|
@@ -118,7 +119,7 @@ namespace Rice::detail
|
|
118
119
|
|
119
120
|
// Create FFI closure
|
120
121
|
this->closure_ = (ffi_closure *)ffi_closure_alloc(sizeof(ffi_closure) + sizeof(void*), (void**)(&this->callback_));
|
121
|
-
|
122
|
+
ffi_prep_closure_loc(this->closure_, &cif_, ffiCallback, (void*)this, (void*)this->callback_);
|
122
123
|
}
|
123
124
|
|
124
125
|
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,8 +1,8 @@
|
|
1
|
-
#include <array>
|
2
1
|
#include <algorithm>
|
2
|
+
#include <array>
|
3
3
|
#include <stdexcept>
|
4
4
|
#include <sstream>
|
5
|
-
|
5
|
+
#include <tuple>
|
6
6
|
|
7
7
|
namespace Rice::detail
|
8
8
|
{
|
@@ -29,8 +29,11 @@ namespace Rice::detail
|
|
29
29
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
30
30
|
VALUE NativeFunction<Class_T, Function_T, IsMethod>::procEntry(VALUE yielded_arg, VALUE callback_arg, int argc, const VALUE* argv, VALUE blockarg)
|
31
31
|
{
|
32
|
-
|
33
|
-
|
32
|
+
return cpp_protect([&]
|
33
|
+
{
|
34
|
+
NativeFunction_T * native = (NativeFunction_T*)callback_arg;
|
35
|
+
return (*native)(argc, argv, Qnil);
|
36
|
+
});
|
34
37
|
}
|
35
38
|
|
36
39
|
// Ruby calls this method if an instance f a NativeFunction is owned by a Ruby proc. That happens when C++
|
@@ -43,7 +46,6 @@ namespace Rice::detail
|
|
43
46
|
return Qnil;
|
44
47
|
}
|
45
48
|
|
46
|
-
|
47
49
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
48
50
|
NativeFunction<Class_T, Function_T, IsMethod>::NativeFunction(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo)
|
49
51
|
: klass_(klass), method_name_(method_name), function_(function), methodInfo_(methodInfo)
|
@@ -64,6 +66,43 @@ namespace Rice::detail
|
|
64
66
|
{
|
65
67
|
}
|
66
68
|
|
69
|
+
template<typename Class_T, typename Function_T, bool IsMethod>
|
70
|
+
template<std::size_t... I>
|
71
|
+
std::vector<std::string> NativeFunction<Class_T, Function_T, IsMethod>::argTypeNames(std::ostringstream& stream, std::index_sequence<I...>& indices)
|
72
|
+
{
|
73
|
+
std::vector<std::string> typeNames;
|
74
|
+
(typeNames.push_back(cppClassName(typeName(typeid(typename std::tuple_element<I, Arg_Ts>::type)))), ...);
|
75
|
+
return typeNames;
|
76
|
+
}
|
77
|
+
|
78
|
+
template<typename Class_T, typename Function_T, bool IsMethod>
|
79
|
+
std::string NativeFunction<Class_T, Function_T, IsMethod>::toString()
|
80
|
+
{
|
81
|
+
std::ostringstream result;
|
82
|
+
|
83
|
+
result << cppClassName(typeName(typeid(Return_T))) << " ";
|
84
|
+
|
85
|
+
if (!std::is_null_pointer_v<Receiver_T>)
|
86
|
+
{
|
87
|
+
result << cppClassName(typeName(typeid(Receiver_T))) << "::";
|
88
|
+
}
|
89
|
+
|
90
|
+
result << this->method_name_;
|
91
|
+
|
92
|
+
result << "(";
|
93
|
+
|
94
|
+
auto indices = std::make_index_sequence<std::tuple_size_v<Arg_Ts>>{};
|
95
|
+
std::vector<std::string> argTypeNames = this->argTypeNames(result, indices);
|
96
|
+
for (size_t i = 0; i < argTypeNames.size(); i++)
|
97
|
+
{
|
98
|
+
result << argTypeNames[i];
|
99
|
+
if (i < argTypeNames.size() - 1)
|
100
|
+
result << ", ";
|
101
|
+
}
|
102
|
+
result << ")";
|
103
|
+
return result.str();
|
104
|
+
}
|
105
|
+
|
67
106
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
68
107
|
To_Ruby<typename NativeFunction<Class_T, Function_T, IsMethod>::To_Ruby_T> NativeFunction<Class_T, Function_T, IsMethod>::createToRuby()
|
69
108
|
{
|
@@ -101,60 +140,100 @@ namespace Rice::detail
|
|
101
140
|
}
|
102
141
|
|
103
142
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
104
|
-
|
143
|
+
template<int I>
|
144
|
+
Convertible NativeFunction<Class_T, Function_T, IsMethod>::matchParameter(std::vector<std::optional<VALUE>>& values)
|
105
145
|
{
|
106
|
-
|
107
|
-
if (argc > arity)
|
108
|
-
return Resolved{ Convertible::None, 0, this };
|
109
|
-
|
110
|
-
Resolved result { Convertible::Exact, 1, this };
|
111
|
-
|
146
|
+
Convertible result = Convertible::None;
|
112
147
|
MethodInfo* methodInfo = this->methodInfo_.get();
|
113
|
-
|
114
|
-
|
115
|
-
std::vector<VALUE> rubyValues = this->getRubyValues(argc, argv, false);
|
148
|
+
const Arg* arg = methodInfo->arg(I);
|
149
|
+
std::optional<VALUE> value = values[I];
|
116
150
|
|
117
|
-
//
|
118
|
-
|
119
|
-
|
151
|
+
// Is a VALUE being passed directly to C++ ?
|
152
|
+
if (value.has_value())
|
153
|
+
{
|
154
|
+
if (arg->isValue())
|
120
155
|
{
|
121
|
-
|
122
|
-
|
123
|
-
|
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);
|
124
165
|
|
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())
|
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)
|
139
168
|
{
|
140
|
-
|
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
|
+
}
|
141
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
|
+
}
|
142
205
|
|
143
|
-
|
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 };
|
144
212
|
|
145
|
-
|
146
|
-
|
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);
|
147
218
|
|
148
219
|
if constexpr (arity > 0)
|
149
|
-
|
220
|
+
{
|
221
|
+
int providedValues = std::count_if(rubyValues.begin(), rubyValues.end(), [](std::optional<VALUE>& value)
|
222
|
+
{
|
223
|
+
return value.has_value();
|
224
|
+
});
|
150
225
|
|
226
|
+
result.parameterMatch = providedValues / (double)arity;
|
227
|
+
}
|
151
228
|
return result;
|
152
229
|
}
|
153
230
|
|
154
231
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
155
|
-
std::vector<VALUE
|
232
|
+
std::vector<std::optional<VALUE>> NativeFunction<Class_T, Function_T, IsMethod>::getRubyValues(size_t argc, const VALUE* argv, bool validate)
|
156
233
|
{
|
157
|
-
|
234
|
+
#undef max
|
235
|
+
int size = std::max((size_t)arity, (size_t)argc);
|
236
|
+
std::vector<std::optional<VALUE>> result(size);
|
158
237
|
|
159
238
|
// Keyword handling
|
160
239
|
if (rb_keyword_given_p())
|
@@ -165,9 +244,7 @@ namespace Rice::detail
|
|
165
244
|
VALUE value = argv[actualArgc];
|
166
245
|
Hash keywords(value);
|
167
246
|
|
168
|
-
|
169
|
-
|
170
|
-
// Copy over leading arguments
|
247
|
+
// Copy over leading non-keyword arguments
|
171
248
|
for (int i = 0; i < actualArgc; i++)
|
172
249
|
{
|
173
250
|
result[i] = argv[i];
|
@@ -187,20 +264,39 @@ namespace Rice::detail
|
|
187
264
|
}
|
188
265
|
else
|
189
266
|
{
|
190
|
-
std::copy(argv, argv + argc,
|
267
|
+
std::copy(argv, argv + argc, result.begin());
|
191
268
|
}
|
192
269
|
|
193
270
|
// Block handling. If we find a block and the last parameter is missing then
|
194
271
|
// set it to the block
|
195
|
-
if (rb_block_given_p() && result.size()
|
272
|
+
if (rb_block_given_p() && result.size() > 0 && !result.back().has_value())
|
196
273
|
{
|
197
274
|
VALUE proc = rb_block_proc();
|
198
|
-
result.
|
275
|
+
result.back() = proc;
|
199
276
|
}
|
200
277
|
|
201
278
|
if (validate)
|
202
279
|
{
|
203
|
-
|
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
|
+
}
|
204
300
|
}
|
205
301
|
|
206
302
|
return result;
|
@@ -208,7 +304,7 @@ namespace Rice::detail
|
|
208
304
|
|
209
305
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
210
306
|
template<typename Arg_T, int I>
|
211
|
-
Arg_T NativeFunction<Class_T, Function_T, IsMethod>::getNativeValue(std::vector<VALUE
|
307
|
+
Arg_T NativeFunction<Class_T, Function_T, IsMethod>::getNativeValue(std::vector<std::optional<VALUE>>& values)
|
212
308
|
{
|
213
309
|
/* In general the compiler will convert T to const T, but that does not work for converting
|
214
310
|
T** to const T** (see see https://isocpp.org/wiki/faq/const-correctness#constptrptr-conversion)
|
@@ -218,22 +314,31 @@ namespace Rice::detail
|
|
218
314
|
the return type. That works but requires a lot more code changes for this one case and is not
|
219
315
|
backwards compatible. */
|
220
316
|
|
221
|
-
|
222
|
-
|
317
|
+
std::optional<VALUE> value = values[I];
|
318
|
+
Arg* arg = this->methodInfo_->arg(I);
|
223
319
|
|
224
320
|
if constexpr (is_pointer_pointer_v<Arg_T> && !std::is_convertible_v<remove_cv_recursive_t<Arg_T>, Arg_T>)
|
225
321
|
{
|
226
|
-
return (Arg_T)std::get<I>(this->fromRubys_).convert(value);
|
322
|
+
return (Arg_T)std::get<I>(this->fromRubys_).convert(value.value());
|
227
323
|
}
|
228
|
-
else
|
324
|
+
else if (value.has_value())
|
229
325
|
{
|
230
|
-
return std::get<I>(this->fromRubys_).convert(value);
|
326
|
+
return std::get<I>(this->fromRubys_).convert(value.value());
|
231
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");
|
232
337
|
}
|
233
338
|
|
234
339
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
235
340
|
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
|
341
|
+
typename NativeFunction<Class_T, Function_T, IsMethod>::Arg_Ts NativeFunction<Class_T, Function_T, IsMethod>::getNativeValues(std::vector<std::optional<VALUE>>& values,
|
237
342
|
std::index_sequence<I...>& indices)
|
238
343
|
{
|
239
344
|
/* Loop over each value returned from Ruby and convert it to the appropriate C++ type based
|
@@ -298,7 +403,7 @@ namespace Rice::detail
|
|
298
403
|
Return_T nativeResult = std::apply(this->function_, std::forward<Arg_Ts>(nativeArgs));
|
299
404
|
|
300
405
|
// Return the result
|
301
|
-
return this->toRuby_.convert(nativeResult);
|
406
|
+
return this->toRuby_.convert(std::forward<Return_T>(nativeResult));
|
302
407
|
}
|
303
408
|
}
|
304
409
|
|
@@ -343,7 +448,7 @@ namespace Rice::detail
|
|
343
448
|
}
|
344
449
|
}
|
345
450
|
|
346
|
-
return this->toRuby_.convert(nativeResult);
|
451
|
+
return this->toRuby_.convert(std::forward<Return_T>(nativeResult));
|
347
452
|
}
|
348
453
|
}
|
349
454
|
|
@@ -364,7 +469,7 @@ namespace Rice::detail
|
|
364
469
|
}
|
365
470
|
|
366
471
|
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
|
472
|
+
void NativeFunction<Class_T, Function_T, IsMethod>::checkKeepAlive(VALUE self, VALUE returnValue, std::vector<std::optional<VALUE>>& rubyValues)
|
368
473
|
{
|
369
474
|
// Self will be Qnil for wrapped procs
|
370
475
|
if (self == Qnil)
|
@@ -372,7 +477,7 @@ namespace Rice::detail
|
|
372
477
|
|
373
478
|
// selfWrapper will be nullptr if this(self) is a builtin type and not an external(wrapped) type
|
374
479
|
// it is highly unlikely that keepAlive is used in this case but we check anyway
|
375
|
-
|
480
|
+
WrapperBase* selfWrapper = getWrapper(self);
|
376
481
|
|
377
482
|
// Check function arguments
|
378
483
|
for (const Arg& arg : (*this->methodInfo_))
|
@@ -383,7 +488,7 @@ namespace Rice::detail
|
|
383
488
|
{
|
384
489
|
noWrapper(self, "self");
|
385
490
|
}
|
386
|
-
selfWrapper->addKeepAlive(rubyValues[arg.position]);
|
491
|
+
selfWrapper->addKeepAlive(rubyValues[arg.position].value());
|
387
492
|
}
|
388
493
|
}
|
389
494
|
|
@@ -396,7 +501,7 @@ namespace Rice::detail
|
|
396
501
|
}
|
397
502
|
|
398
503
|
// returnWrapper will be nullptr if returnValue is a built-in type and not an external(wrapped) type
|
399
|
-
|
504
|
+
WrapperBase* returnWrapper = getWrapper(returnValue);
|
400
505
|
if (returnWrapper == nullptr)
|
401
506
|
{
|
402
507
|
noWrapper(returnValue, "return");
|
@@ -406,10 +511,10 @@ namespace Rice::detail
|
|
406
511
|
}
|
407
512
|
|
408
513
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
409
|
-
VALUE NativeFunction<Class_T, Function_T, IsMethod>::operator()(
|
514
|
+
VALUE NativeFunction<Class_T, Function_T, IsMethod>::operator()(size_t argc, const VALUE* argv, VALUE self)
|
410
515
|
{
|
411
516
|
// Get the ruby values and make sure we have the correct number
|
412
|
-
std::vector<VALUE
|
517
|
+
std::vector<std::optional<VALUE>> rubyValues = this->getRubyValues(argc, argv, true);
|
413
518
|
|
414
519
|
auto indices = std::make_index_sequence<std::tuple_size_v<Arg_Ts>>{};
|
415
520
|
|
@@ -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_
|