rice 4.7.1 → 4.8.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.
Files changed (153) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -1
  3. data/CMakeLists.txt +14 -22
  4. data/CMakePresets.json +203 -75
  5. data/FindRuby.cmake +358 -123
  6. data/bin/rice-doc.rb +56 -141
  7. data/include/rice/api.hpp +248 -0
  8. data/include/rice/rice.hpp +2237 -1657
  9. data/include/rice/stl.hpp +346 -443
  10. data/lib/rice/doc/config.rb +70 -0
  11. data/lib/rice/doc/cpp_reference.rb +1 -4
  12. data/lib/rice/doc/mkdocs.rb +58 -20
  13. data/lib/rice/doc/rice.rb +20 -0
  14. data/lib/rice/doc.rb +1 -0
  15. data/lib/rice/make_rice_headers.rb +7 -0
  16. data/lib/rice/native_registry.rb +2 -2
  17. data/lib/rice/rbs.rb +2 -2
  18. data/lib/rice/version.rb +1 -1
  19. data/lib/rubygems_plugin.rb +12 -9
  20. data/rice/Arg.hpp +12 -6
  21. data/rice/Arg.ipp +14 -7
  22. data/rice/Buffer.ipp +44 -40
  23. data/rice/Callback.hpp +1 -1
  24. data/rice/Callback.ipp +2 -7
  25. data/rice/Constructor.hpp +1 -1
  26. data/rice/Constructor.ipp +11 -11
  27. data/rice/Data_Object.ipp +15 -15
  28. data/rice/Data_Type.hpp +9 -10
  29. data/rice/Data_Type.ipp +22 -25
  30. data/rice/Director.hpp +1 -0
  31. data/rice/Enum.ipp +58 -39
  32. data/rice/Exception.hpp +4 -4
  33. data/rice/Exception.ipp +7 -7
  34. data/rice/NoGVL.hpp +13 -0
  35. data/rice/Reference.hpp +56 -0
  36. data/rice/Reference.ipp +96 -0
  37. data/rice/Return.hpp +4 -1
  38. data/rice/Return.ipp +0 -6
  39. data/rice/cpp_api/Array.hpp +41 -4
  40. data/rice/cpp_api/Array.ipp +105 -9
  41. data/rice/cpp_api/Class.hpp +2 -2
  42. data/rice/cpp_api/Class.ipp +4 -4
  43. data/rice/cpp_api/Hash.ipp +7 -4
  44. data/rice/cpp_api/Module.hpp +4 -4
  45. data/rice/cpp_api/Module.ipp +12 -10
  46. data/rice/cpp_api/Object.hpp +4 -4
  47. data/rice/cpp_api/Object.ipp +15 -12
  48. data/rice/cpp_api/String.hpp +2 -2
  49. data/rice/cpp_api/String.ipp +11 -8
  50. data/rice/cpp_api/Symbol.ipp +7 -7
  51. data/rice/cpp_api/shared_methods.hpp +5 -9
  52. data/rice/detail/InstanceRegistry.hpp +0 -2
  53. data/rice/detail/Native.hpp +31 -21
  54. data/rice/detail/Native.ipp +282 -130
  55. data/rice/detail/NativeAttributeGet.hpp +5 -7
  56. data/rice/detail/NativeAttributeGet.ipp +26 -26
  57. data/rice/detail/NativeAttributeSet.hpp +2 -4
  58. data/rice/detail/NativeAttributeSet.ipp +20 -16
  59. data/rice/detail/NativeCallback.hpp +77 -0
  60. data/rice/detail/NativeCallback.ipp +280 -0
  61. data/rice/detail/NativeFunction.hpp +11 -21
  62. data/rice/detail/NativeFunction.ipp +58 -119
  63. data/rice/detail/NativeInvoker.hpp +4 -4
  64. data/rice/detail/NativeInvoker.ipp +7 -7
  65. data/rice/detail/NativeIterator.hpp +2 -4
  66. data/rice/detail/NativeIterator.ipp +18 -14
  67. data/rice/detail/NativeMethod.hpp +10 -20
  68. data/rice/detail/NativeMethod.ipp +54 -114
  69. data/rice/detail/NativeProc.hpp +5 -7
  70. data/rice/detail/NativeProc.ipp +39 -28
  71. data/rice/detail/NativeRegistry.hpp +0 -1
  72. data/rice/detail/Parameter.hpp +15 -8
  73. data/rice/detail/Parameter.ipp +102 -43
  74. data/rice/detail/Proc.ipp +14 -28
  75. data/rice/detail/RubyType.ipp +2 -53
  76. data/rice/detail/Type.hpp +23 -7
  77. data/rice/detail/Type.ipp +73 -93
  78. data/rice/detail/TypeRegistry.ipp +5 -4
  79. data/rice/detail/Wrapper.hpp +1 -1
  80. data/rice/detail/Wrapper.ipp +18 -10
  81. data/rice/detail/from_ruby.hpp +8 -6
  82. data/rice/detail/from_ruby.ipp +306 -173
  83. data/rice/detail/ruby.hpp +23 -0
  84. data/rice/libc/file.hpp +4 -4
  85. data/rice/rice.hpp +6 -8
  86. data/rice/rice_api/Native.ipp +5 -1
  87. data/rice/rice_api/Parameter.ipp +1 -1
  88. data/rice/ruby_mark.hpp +2 -1
  89. data/rice/stl/complex.ipp +12 -8
  90. data/rice/stl/map.ipp +27 -22
  91. data/rice/stl/monostate.ipp +16 -12
  92. data/rice/stl/multimap.hpp +0 -2
  93. data/rice/stl/multimap.ipp +27 -22
  94. data/rice/stl/optional.ipp +27 -11
  95. data/rice/stl/pair.ipp +5 -5
  96. data/rice/stl/reference_wrapper.ipp +5 -4
  97. data/rice/stl/set.ipp +16 -16
  98. data/rice/stl/shared_ptr.hpp +0 -16
  99. data/rice/stl/shared_ptr.ipp +34 -190
  100. data/rice/stl/string.ipp +18 -18
  101. data/rice/stl/string_view.ipp +1 -1
  102. data/rice/stl/tuple.ipp +15 -36
  103. data/rice/stl/unique_ptr.ipp +18 -8
  104. data/rice/stl/unordered_map.ipp +20 -15
  105. data/rice/stl/variant.ipp +37 -21
  106. data/rice/stl/vector.ipp +41 -36
  107. data/rice/traits/function_traits.hpp +19 -19
  108. data/rice/traits/method_traits.hpp +4 -4
  109. data/rice/traits/rice_traits.hpp +162 -39
  110. data/rice.gemspec +1 -3
  111. data/test/test_Array.cpp +261 -3
  112. data/test/test_Attribute.cpp +6 -3
  113. data/test/test_Buffer.cpp +6 -42
  114. data/test/test_Callback.cpp +77 -23
  115. data/test/test_Data_Object.cpp +1 -1
  116. data/test/test_Data_Type.cpp +21 -22
  117. data/test/test_Director.cpp +2 -4
  118. data/test/test_Enum.cpp +34 -5
  119. data/test/test_File.cpp +9 -5
  120. data/test/test_From_Ruby.cpp +4 -3
  121. data/test/test_GVL.cpp +3 -3
  122. data/test/test_Hash.cpp +1 -1
  123. data/test/test_Iterator.cpp +54 -22
  124. data/test/test_Keep_Alive.cpp +1 -1
  125. data/test/test_Keep_Alive_No_Wrapper.cpp +1 -1
  126. data/test/test_Module.cpp +5 -5
  127. data/test/test_Overloads.cpp +345 -48
  128. data/test/test_Proc.cpp +54 -0
  129. data/test/test_Reference.cpp +181 -0
  130. data/test/test_Self.cpp +2 -2
  131. data/test/test_Stl_Set.cpp +6 -6
  132. data/test/test_Stl_SharedPtr.cpp +54 -30
  133. data/test/test_Stl_String_View.cpp +4 -2
  134. data/test/test_Stl_Tuple.cpp +1 -1
  135. data/test/test_Stl_Variant.cpp +6 -14
  136. data/test/test_Stl_Vector.cpp +61 -30
  137. data/test/test_String.cpp +4 -2
  138. data/test/test_Struct.cpp +1 -1
  139. data/test/test_Symbol.cpp +1 -1
  140. data/test/test_To_Ruby.cpp +1 -0
  141. data/test/test_Type.cpp +36 -35
  142. data/test/test_global_functions.cpp +1 -1
  143. data/test/unittest.cpp +1 -1
  144. data/test/unittest.hpp +5 -5
  145. metadata +10 -10
  146. data/rice/Function.hpp +0 -17
  147. data/rice/Function.ipp +0 -13
  148. data/rice/detail/MethodInfo.hpp +0 -48
  149. data/rice/detail/MethodInfo.ipp +0 -99
  150. data/rice/detail/NativeCallbackFFI.hpp +0 -55
  151. data/rice/detail/NativeCallbackFFI.ipp +0 -152
  152. data/rice/detail/NativeCallbackSimple.hpp +0 -30
  153. data/rice/detail/NativeCallbackSimple.ipp +0 -29
@@ -4,13 +4,17 @@
4
4
  namespace Rice::detail
5
5
  {
6
6
  template<typename Attribute_T>
7
- void NativeAttributeGet<Attribute_T>::define(VALUE klass, std::string name, Attribute_T attribute, Return returnInfo)
7
+ template<typename...Arg_Ts>
8
+ void NativeAttributeGet<Attribute_T>::define(VALUE klass, std::string name, Attribute_T attribute, Arg_Ts&...args)
8
9
  {
9
10
  // Verify attribute type
10
- Native::verify_type<Attr_T>(returnInfo.isBuffer());
11
+ Native::verify_type<Attr_T, is_one_of_v<ReturnBuffer, Arg_Ts...>>();
12
+
13
+ // Create return info
14
+ std::unique_ptr<Return> returnInfo = Native::create_return<Arg_Ts...>(args...);
11
15
 
12
16
  // Create a NativeAttributeGet that Ruby will call to read/write C++ variables
13
- NativeAttribute_T* nativeAttribute = new NativeAttribute_T(klass, name, std::forward<Attribute_T>(attribute), returnInfo);
17
+ NativeAttribute_T* nativeAttribute = new NativeAttribute_T(klass, name, std::forward<Attribute_T>(attribute), std::move(returnInfo));
14
18
  std::unique_ptr<Native> native(nativeAttribute);
15
19
 
16
20
  detail::protect(rb_define_method, klass, name.c_str(), (RUBY_METHOD_FUNC)&Native::resolve, -1);
@@ -23,22 +27,23 @@ namespace Rice::detail
23
27
  }
24
28
 
25
29
  template<typename Attribute_T>
26
- inline Resolved NativeAttributeGet<Attribute_T>::matches(size_t argc, const VALUE* argv, VALUE self)
30
+ inline Resolved NativeAttributeGet<Attribute_T>::matches(std::map<std::string, VALUE>& values)
27
31
  {
28
- if (argc == 0)
29
- return Resolved { Convertible::Exact, 1, this };
32
+ if (values.size() == 0)
33
+ return Resolved{ Convertible::Exact, this };
30
34
  else
31
- return Resolved{ Convertible::None, 0, this };
35
+ return Resolved{ Convertible::None, this };
32
36
  }
33
37
 
34
38
  template<typename Attribute_T>
35
- NativeAttributeGet<Attribute_T>::NativeAttributeGet(VALUE klass, std::string name, Attribute_T attribute, Return returnInfo)
36
- : klass_(klass), name_(name), attribute_(attribute), return_(returnInfo)
39
+ NativeAttributeGet<Attribute_T>::NativeAttributeGet(VALUE klass, std::string name, Attribute_T attribute, std::unique_ptr<Return>&& returnInfo)
40
+ : Native(name, std::move(returnInfo)),
41
+ klass_(klass), attribute_(attribute)
37
42
  {
38
43
  }
39
44
 
40
45
  template<typename Attribute_T>
41
- inline VALUE NativeAttributeGet<Attribute_T>::operator()(size_t argc, const VALUE* argv, VALUE self)
46
+ inline VALUE NativeAttributeGet<Attribute_T>::operator()(std::map<std::string, VALUE>&, VALUE self)
42
47
  {
43
48
  if constexpr (std::is_member_object_pointer_v<Attribute_T>)
44
49
  {
@@ -46,42 +51,42 @@ namespace Rice::detail
46
51
 
47
52
  if constexpr (std::is_fundamental_v<detail::intrinsic_type<To_Ruby_T>>)
48
53
  {
49
- return To_Ruby<To_Ruby_T>(&this->return_).convert(nativeSelf->*attribute_);
54
+ return To_Ruby<To_Ruby_T>(this->returnInfo_.get()).convert(nativeSelf->*attribute_);
50
55
  }
51
56
  else if constexpr (std::is_array_v<To_Ruby_T>)
52
57
  {
53
- return To_Ruby<To_Ruby_T>(&this->return_).convert(nativeSelf->*attribute_);
58
+ return To_Ruby<To_Ruby_T>(this->returnInfo_.get()).convert(nativeSelf->*attribute_);
54
59
  }
55
60
  else if constexpr (std::is_pointer_v<To_Ruby_T>)
56
61
  {
57
- return To_Ruby<To_Ruby_T>(&this->return_).convert(nativeSelf->*attribute_);
62
+ return To_Ruby<To_Ruby_T>(this->returnInfo_.get()).convert(nativeSelf->*attribute_);
58
63
  }
59
64
  else
60
65
  {
61
66
  // If the attribute is an object return a reference to avoid a copy (and avoid issues with
62
67
  // attributes that are not assignable, copy constructible or move constructible)
63
- return To_Ruby<To_Ruby_T&>(&this->return_).convert(nativeSelf->*attribute_);
68
+ return To_Ruby<To_Ruby_T&>(this->returnInfo_.get()).convert(nativeSelf->*attribute_);
64
69
  }
65
70
  }
66
71
  else
67
72
  {
68
73
  if constexpr (std::is_fundamental_v<detail::intrinsic_type<To_Ruby_T>>)
69
74
  {
70
- return To_Ruby<To_Ruby_T>(&this->return_).convert(*attribute_);
75
+ return To_Ruby<To_Ruby_T>(this->returnInfo_.get()).convert(*attribute_);
71
76
  }
72
77
  else if constexpr (std::is_array_v<To_Ruby_T>)
73
78
  {
74
- return To_Ruby<To_Ruby_T>(&this->return_).convert(*attribute_);
79
+ return To_Ruby<To_Ruby_T>(this->returnInfo_.get()).convert(*attribute_);
75
80
  }
76
81
  else if constexpr (std::is_pointer_v<To_Ruby_T>)
77
82
  {
78
- return To_Ruby<To_Ruby_T>(&this->return_).convert(*attribute_);
83
+ return To_Ruby<To_Ruby_T>(this->returnInfo_.get()).convert(*attribute_);
79
84
  }
80
85
  else
81
86
  {
82
87
  // If the attribute is an object return a reference to avoid a copy (and avoid issues with
83
88
  // attributes that are not assignable, copy constructible or move constructible)
84
- return To_Ruby<To_Ruby_T&>(&this->return_).convert(*attribute_);
89
+ return To_Ruby<To_Ruby_T&>(this->returnInfo_.get()).convert(*attribute_);
85
90
  }
86
91
  }
87
92
  }
@@ -92,12 +97,6 @@ namespace Rice::detail
92
97
  return "";
93
98
  }
94
99
 
95
- template<typename Attribute_T>
96
- inline std::string NativeAttributeGet<Attribute_T>::name()
97
- {
98
- return this->name_;
99
- }
100
-
101
100
  template<typename Attribute_T>
102
101
  inline NativeKind NativeAttributeGet<Attribute_T>::kind()
103
102
  {
@@ -108,9 +107,10 @@ namespace Rice::detail
108
107
  inline VALUE NativeAttributeGet<Attribute_T>::returnKlass()
109
108
  {
110
109
  // Check if an array is being returned
111
- if (this->return_.isBuffer())
110
+ bool isBuffer = dynamic_cast<ReturnBuffer*>(this->returnInfo_.get()) ? true : false;
111
+ if (isBuffer)
112
112
  {
113
- TypeMapper<Pointer<Attr_T>> typeMapper;
113
+ TypeMapper<Pointer<detail::remove_cv_recursive_t<std::remove_pointer_t<Attr_T>>>> typeMapper;
114
114
  return typeMapper.rubyKlass();
115
115
  }
116
116
  else
@@ -26,11 +26,10 @@ namespace Rice
26
26
  void operator=(const NativeAttribute_T&) = delete;
27
27
  void operator=(NativeAttribute_T&&) = delete;
28
28
 
29
- Resolved matches(size_t argc, const VALUE* argv, VALUE self) override;
30
- VALUE operator()(size_t argc, const VALUE* argv, VALUE self) override;
29
+ Resolved matches(std::map<std::string, VALUE>& values) override;
30
+ VALUE operator()(std::map<std::string, VALUE>& values, VALUE self) override;
31
31
  std::string toString() override;
32
32
 
33
- std::string name() override;
34
33
  NativeKind kind() override;
35
34
  VALUE returnKlass() override;
36
35
 
@@ -39,7 +38,6 @@ namespace Rice
39
38
 
40
39
  private:
41
40
  VALUE klass_;
42
- std::string name_;
43
41
  Attribute_T attribute_;
44
42
  };
45
43
  } // detail
@@ -26,28 +26,28 @@ namespace Rice::detail
26
26
 
27
27
  template<typename Attribute_T>
28
28
  NativeAttributeSet<Attribute_T>::NativeAttributeSet(VALUE klass, std::string name, Attribute_T attribute)
29
- : klass_(klass), name_(name), attribute_(attribute)
29
+ : Native(name), klass_(klass), attribute_(attribute)
30
30
  {
31
31
  }
32
32
 
33
33
  template<typename Attribute_T>
34
- inline Resolved NativeAttributeSet<Attribute_T>::matches(size_t argc, const VALUE* argv, VALUE self)
34
+ inline Resolved NativeAttributeSet<Attribute_T>::matches(std::map<std::string, VALUE>& values)
35
35
  {
36
- if (argc == 1)
37
- return Resolved{ Convertible::Exact, 1, this };
36
+ if (values.size() == 1)
37
+ return Resolved{ Convertible::Exact, this };
38
38
  else
39
- return Resolved{ Convertible::None, 0, this };
39
+ return Resolved{ Convertible::None, this };
40
40
  }
41
41
 
42
42
  template<typename Attribute_T>
43
- inline VALUE NativeAttributeSet<Attribute_T>::operator()(size_t argc, const VALUE* argv, VALUE self)
43
+ inline VALUE NativeAttributeSet<Attribute_T>::operator()(std::map<std::string, VALUE>& values, VALUE self)
44
44
  {
45
- if (argc != 1)
45
+ if (values.size() != 1)
46
46
  {
47
47
  throw std::runtime_error("Incorrect number of parameters for setting attribute. Attribute: " + this->name_);
48
48
  }
49
49
 
50
- VALUE value = argv[0];
50
+ VALUE value = values.begin()->second;
51
51
 
52
52
  if constexpr (!std::is_null_pointer_v<Receiver_T>)
53
53
  {
@@ -77,12 +77,6 @@ namespace Rice::detail
77
77
  return "";
78
78
  }
79
79
 
80
- template<typename Attribute_T>
81
- inline std::string NativeAttributeSet<Attribute_T>::name()
82
- {
83
- return this->name_;
84
- }
85
-
86
80
  template<typename Attribute_T>
87
81
  inline NativeKind NativeAttributeSet<Attribute_T>::kind()
88
82
  {
@@ -92,7 +86,17 @@ namespace Rice::detail
92
86
  template<typename Attribute_T>
93
87
  inline VALUE NativeAttributeSet<Attribute_T>::returnKlass()
94
88
  {
95
- TypeMapper<Attr_T> typeMapper;
96
- return typeMapper.rubyKlass();
89
+ // Check if an array is being returned
90
+ bool isBuffer = dynamic_cast<ReturnBuffer*>(this->returnInfo_.get()) ? true : false;
91
+ if (isBuffer)
92
+ {
93
+ TypeMapper<Pointer<detail::remove_cv_recursive_t<std::remove_pointer_t<Attr_T>>>> typeMapper;
94
+ return typeMapper.rubyKlass();
95
+ }
96
+ else
97
+ {
98
+ TypeMapper<Attr_T> typeMapper;
99
+ return typeMapper.rubyKlass();
100
+ }
97
101
  }
98
102
  }
@@ -0,0 +1,77 @@
1
+ #ifndef Rice__detail__Native_Callback_Ffi_hpp_
2
+ #define Rice__detail__Native_Callback_Ffi_hpp_
3
+
4
+ #ifdef HAVE_LIBFFI
5
+ #include <ffi.h>
6
+ #endif //HAVE_LIBFFI
7
+
8
+ namespace Rice::detail
9
+ {
10
+ template<typename Callback_T>
11
+ class NativeCallback;
12
+
13
+ template<typename Return_T, typename ...Parameter_Ts>
14
+ class NativeCallback<Return_T(*)(Parameter_Ts...)> : public Native
15
+ {
16
+ public:
17
+ using Callback_T = Return_T(*)(Parameter_Ts...);
18
+ using NativeCallback_T = NativeCallback<Callback_T>;
19
+ using Tuple_T = std::tuple<Parameter_Ts...>;
20
+
21
+ static VALUE finalizerCallback(VALUE yielded_arg, VALUE callback_arg, int argc, const VALUE* argv, VALUE blockarg);
22
+
23
+ template<typename ...Arg_Ts>
24
+ static void define(Arg_Ts&& ...args);
25
+
26
+ static Return_T invoke(Parameter_Ts...args);
27
+ public:
28
+ NativeCallback(VALUE proc);
29
+ ~NativeCallback();
30
+ NativeCallback(const NativeCallback&) = delete;
31
+ NativeCallback(NativeCallback&&) = delete;
32
+ void operator=(const NativeCallback&) = delete;
33
+ void operator=(NativeCallback&&) = delete;
34
+
35
+ Callback_T callback();
36
+ private:
37
+ template<typename Parameter_T>
38
+ static Parameter_T extractArg(void* arg);
39
+
40
+ template<std::size_t... I>
41
+ static Tuple_T convertArgsToTuple(void* args[], std::index_sequence<I...>& indices);
42
+ Callback_T callback_ = nullptr;
43
+
44
+ template<std::size_t... I>
45
+ static void copyParametersImpl(std::vector<std::unique_ptr<ParameterAbstract>>& result, std::index_sequence<I...> indices);
46
+ static std::vector<std::unique_ptr<ParameterAbstract>> copyParameters();
47
+ static std::unique_ptr<Return> copyReturnInfo();
48
+
49
+ static inline std::vector<std::unique_ptr<ParameterAbstract>> parameters_;
50
+ static inline std::unique_ptr<Return> returnInfo_;
51
+ static inline NativeCallback_T* native_;
52
+
53
+ private:
54
+ VALUE operator()(std::map<std::string, VALUE>& values, VALUE self) override;
55
+ std::string toString() override;
56
+ NativeKind kind() override;
57
+ VALUE returnKlass() override;
58
+
59
+ template<std::size_t... I>
60
+ Return_T callRuby(std::index_sequence<I...>& indices, Parameter_Ts...args);
61
+
62
+ VALUE proc_;
63
+ From_Ruby<Return_T> fromRuby_;
64
+
65
+ #ifdef HAVE_LIBFFI
66
+ template <typename Arg_T>
67
+ static ffi_type* ffiType();
68
+
69
+ static void invokeFFI(ffi_cif* cif, void* ret, void* args[], void* instance);
70
+
71
+ static inline std::array<ffi_type*, sizeof...(Parameter_Ts)> args_ = { ffiType<Parameter_Ts>()... };
72
+ static inline ffi_cif cif_;
73
+ ffi_closure* closure_ = nullptr;
74
+ #endif //HAVE_LIBFFI
75
+ };
76
+ }
77
+ #endif // Rice__detail__Native_Callback_Ffi_hpp_
@@ -0,0 +1,280 @@
1
+ namespace Rice::detail
2
+ {
3
+ #ifdef HAVE_LIBFFI
4
+ template<typename Return_T, typename ...Parameter_Ts>
5
+ template<typename Arg_T>
6
+ ffi_type* NativeCallback<Return_T(*)(Parameter_Ts...)>::ffiType()
7
+ {
8
+ std::map<std::type_index, ffi_type*> nativeToFfiMapping = {
9
+ {std::type_index(typeid(bool)), &ffi_type_uint8},
10
+ {std::type_index(typeid(bool)), &ffi_type_uint8},
11
+ {std::type_index(typeid(char)), &ffi_type_schar},
12
+ {std::type_index(typeid(unsigned char)), &ffi_type_uchar},
13
+ {std::type_index(typeid(signed char)), &ffi_type_schar},
14
+ {std::type_index(typeid(uint8_t)), &ffi_type_uint8},
15
+ {std::type_index(typeid(unsigned short)), &ffi_type_uint8},
16
+ {std::type_index(typeid(int8_t)), &ffi_type_sint8},
17
+ {std::type_index(typeid(short)), &ffi_type_sint8},
18
+ {std::type_index(typeid(uint16_t)), &ffi_type_uint16},
19
+ {std::type_index(typeid(int16_t)), &ffi_type_sint16},
20
+ {std::type_index(typeid(uint32_t)), &ffi_type_uint32},
21
+ {std::type_index(typeid(unsigned int)), &ffi_type_uint32},
22
+ {std::type_index(typeid(signed int)), &ffi_type_uint32},
23
+ {std::type_index(typeid(int32_t)), &ffi_type_sint32},
24
+ {std::type_index(typeid(uint64_t)), &ffi_type_uint64},
25
+ {std::type_index(typeid(unsigned long long)), &ffi_type_uint64},
26
+ {std::type_index(typeid(int64_t)), &ffi_type_sint64},
27
+ {std::type_index(typeid(signed long long)), &ffi_type_sint64},
28
+ {std::type_index(typeid(float)), &ffi_type_float},
29
+ {std::type_index(typeid(double)), &ffi_type_double},
30
+ {std::type_index(typeid(void)), &ffi_type_pointer},
31
+ {std::type_index(typeid(long double)), &ffi_type_longdouble}
32
+ };
33
+
34
+ if (sizeof(long) == 32)
35
+ {
36
+ nativeToFfiMapping[std::type_index(typeid(unsigned long))] = &ffi_type_uint32;
37
+ nativeToFfiMapping[std::type_index(typeid(long))] = &ffi_type_sint32;
38
+ }
39
+ else if (sizeof(long) == 64)
40
+ {
41
+ nativeToFfiMapping[std::type_index(typeid(unsigned long))] = &ffi_type_uint64;
42
+ nativeToFfiMapping[std::type_index(typeid(long))] = &ffi_type_sint64;
43
+ }
44
+
45
+ if constexpr (std::is_pointer_v<Arg_T> || std::is_reference_v<Arg_T>)
46
+ {
47
+ return &ffi_type_pointer;
48
+ }
49
+ else
50
+ {
51
+ const std::type_index& key = std::type_index(typeid(Arg_T));
52
+ return nativeToFfiMapping[key];
53
+ }
54
+ }
55
+
56
+ // This is the function provided to the C++ callback with FFI
57
+ template<typename Return_T, typename ...Parameter_Ts>
58
+ void NativeCallback<Return_T(*)(Parameter_Ts...)>::invokeFFI(ffi_cif*, void* ret, void* args[], void* instance)
59
+ {
60
+ NativeCallback_T* self = (NativeCallback_T*)instance;
61
+
62
+ // Define a helper lambda to invoke callRuby with unpacked args
63
+ auto indices = std::make_index_sequence<sizeof...(Parameter_Ts)>{};
64
+ auto helper = [&](auto&&... args)
65
+ {
66
+ if constexpr (!std::is_void_v<Return_T>)
67
+ {
68
+ *(Return_T*)ret = self->callRuby(indices, std::forward<Parameter_Ts>(args)...);
69
+ }
70
+ else
71
+ {
72
+ self->callRuby(indices, std::forward<Parameter_Ts>(args)...);
73
+ }
74
+ };
75
+
76
+ // Convert the C style array to a tuple
77
+ Tuple_T argsTuple = convertArgsToTuple(args, indices);
78
+
79
+ // Now use std::apply to unpack the tuple and call the lamba helper
80
+ std::apply(helper, std::forward<Tuple_T>(argsTuple));
81
+ }
82
+ #endif //HAVE_LIBFFI
83
+
84
+ // This is the function provided to the C++ callback without FFI
85
+ template<typename Return_T, typename ...Parameter_Ts>
86
+ inline Return_T NativeCallback<Return_T(*)(Parameter_Ts...)>::invoke(Parameter_Ts...args)
87
+ {
88
+ auto indices = std::make_index_sequence<sizeof...(Parameter_Ts)>{};
89
+
90
+ if constexpr (std::is_void_v<Return_T>)
91
+ {
92
+ NativeCallback::native_->callRuby(indices, args...);
93
+ }
94
+ else
95
+ {
96
+ return NativeCallback::native_->callRuby(indices, args...);
97
+ }
98
+ }
99
+
100
+ template<typename Return_T, typename ...Parameter_Ts>
101
+ std::vector<std::unique_ptr<ParameterAbstract>> NativeCallback<Return_T(*)(Parameter_Ts...)>::copyParameters()
102
+ {
103
+ std::vector<std::unique_ptr<ParameterAbstract>> result;
104
+
105
+ if (sizeof...(Parameter_Ts) > 0 && parameters_.empty())
106
+ {
107
+ NativeCallback_T::define();
108
+ }
109
+
110
+ if (parameters_.size() > 0)
111
+ {
112
+ auto indices = std::make_index_sequence<sizeof...(Parameter_Ts)>{};
113
+ copyParametersImpl(result, indices);
114
+ }
115
+ return result;
116
+ }
117
+
118
+ template<typename Return_T, typename ...Parameter_Ts>
119
+ template<std::size_t... I>
120
+ void NativeCallback<Return_T(*)(Parameter_Ts...)>::copyParametersImpl(std::vector<std::unique_ptr<ParameterAbstract>>& result, std::index_sequence<I...>)
121
+ {
122
+ (result.push_back(std::make_unique<Parameter<Parameter_Ts>>(*(Parameter<Parameter_Ts>*)parameters_[I].get())), ...);
123
+ }
124
+
125
+ template<typename Return_T, typename ...Parameter_Ts>
126
+ std::unique_ptr<Return> NativeCallback<Return_T(*)(Parameter_Ts...)>::copyReturnInfo()
127
+ {
128
+ if (!returnInfo_)
129
+ {
130
+ NativeCallback_T::define();
131
+ }
132
+
133
+ return std::make_unique<Return>(*returnInfo_);
134
+ }
135
+
136
+ template<typename Return_T, typename ...Parameter_Ts>
137
+ template<typename Parameter_T>
138
+ Parameter_T NativeCallback<Return_T(*)(Parameter_Ts...)>::extractArg(void* arg)
139
+ {
140
+ if constexpr (std::is_reference_v<Parameter_T>)
141
+ {
142
+ // We told libffi to pass references as pointers, so arg points to the pointer
143
+ return static_cast<Parameter_T>(**reinterpret_cast<std::remove_reference_t<Parameter_T>**>(arg));
144
+ }
145
+ else
146
+ {
147
+ return *reinterpret_cast<Parameter_T*>(arg);
148
+ }
149
+ }
150
+
151
+ template<typename Return_T, typename ...Parameter_Ts>
152
+ template<std::size_t... I>
153
+ typename NativeCallback<Return_T(*)(Parameter_Ts...)>::Tuple_T NativeCallback<Return_T(*)(Parameter_Ts...)>::convertArgsToTuple(void* args[], std::index_sequence<I...>&)
154
+ {
155
+ /* Loop over each value returned from Ruby and convert it to the appropriate C++ type based
156
+ on the arguments (Parameter_Ts) required by the C++ function. Arg_T may have const/volatile while
157
+ the associated From_Ruby<T> template parameter will not. Thus From_Ruby produces non-const values
158
+ which we let the compiler convert to const values as needed. This works except for
159
+ T** -> const T**, see comment in convertToNative method. */
160
+ return std::forward_as_tuple(extractArg<Parameter_Ts>(args[I])...);
161
+ }
162
+
163
+ template<typename Return_T, typename ...Parameter_Ts>
164
+ VALUE NativeCallback<Return_T(*)(Parameter_Ts...)>::finalizerCallback(VALUE, VALUE callback_arg, int, const VALUE*, VALUE)
165
+ {
166
+ NativeCallback_T* nativeCallback = (NativeCallback_T*)callback_arg;
167
+ delete nativeCallback;
168
+ return Qnil;
169
+ }
170
+
171
+ template<typename Return_T, typename...Parameter_Ts>
172
+ template<typename ...Arg_Ts>
173
+ inline void NativeCallback<Return_T(*)(Parameter_Ts...)>::define(Arg_Ts&& ...args)
174
+ {
175
+ // Create parameters and save them in static member so we can use them later when constructing an instance
176
+ using Parameter_Tuple = std::tuple<Parameter_Ts...>;
177
+ NativeCallback_T::parameters_ = Native::create_parameters<Parameter_Tuple>(std::forward<Arg_Ts>(args)...);
178
+
179
+ // Create Return and save it in static member so we can use them later when constructing an instance
180
+ NativeCallback_T::returnInfo_ = Native::create_return<Arg_Ts...>(args...);
181
+ }
182
+
183
+ template<typename Return_T, typename ...Parameter_Ts>
184
+ NativeCallback<Return_T(*)(Parameter_Ts...)>::NativeCallback(VALUE proc) :
185
+ Native("callback", copyReturnInfo(), copyParameters()),
186
+ proc_(proc), fromRuby_(returnInfo_.get())
187
+ {
188
+ // Tie the lifetime of the NativeCallback C++ instance to the lifetime of the Ruby proc object
189
+ VALUE finalizer = rb_proc_new(NativeCallback_T::finalizerCallback, (VALUE)this);
190
+ rb_define_finalizer(proc, finalizer);
191
+
192
+ #ifdef HAVE_LIBFFI
193
+ // First setup description of callback
194
+ if (cif_.bytes == 0)
195
+ {
196
+ ffi_prep_cif(&cif_, FFI_DEFAULT_ABI, sizeof...(Parameter_Ts), ffiType<Return_T>(), args_.data());
197
+ }
198
+
199
+ // Now allocate memory
200
+ this->closure_ = (ffi_closure *)ffi_closure_alloc(sizeof(ffi_closure) + sizeof(void*), (void**)(&this->callback_));
201
+ // Now create the closure which will create a C++ callback
202
+ ffi_prep_closure_loc(this->closure_, &cif_, invokeFFI, (void*)this, (void*)this->callback_);
203
+ #else
204
+ NativeCallback_T::callback_ = &NativeCallback_T::invoke;
205
+ NativeCallback_T::native_ = this;
206
+ #endif
207
+ }
208
+
209
+ template<typename Return_T, typename ...Parameter_Ts>
210
+ NativeCallback<Return_T(*)(Parameter_Ts...)>::~NativeCallback()
211
+ {
212
+ #ifdef HAVE_LIBFFI
213
+ ffi_closure_free(this->closure_);
214
+ #endif
215
+
216
+ NativeCallback_T::callback_ = nullptr;
217
+ NativeCallback_T::native_ = nullptr;
218
+
219
+ this->proc_ = Qnil;
220
+ }
221
+
222
+ template<typename Return_T, typename ...Parameter_Ts>
223
+ typename NativeCallback<Return_T(*)(Parameter_Ts...)>::Callback_T NativeCallback<Return_T(*)(Parameter_Ts...)>::callback()
224
+ {
225
+ return this->callback_;
226
+ }
227
+
228
+ template<typename Return_T, typename ...Parameter_Ts>
229
+ template<std::size_t... I>
230
+ Return_T NativeCallback<Return_T(*)(Parameter_Ts...)>::callRuby(std::index_sequence<I...>&, Parameter_Ts...args)
231
+ {
232
+ // Convert the C++ arguments to Ruby VALUEs
233
+ std::array<VALUE, sizeof...(Parameter_Ts)> values = {
234
+ dynamic_cast<Parameter<Parameter_Ts>*>(this->parameters_[I].get())->
235
+ convertToRuby(args)... };
236
+
237
+ static Identifier id("call");
238
+ VALUE result = detail::protect(rb_funcallv, this->proc_, id.id(), (int)sizeof...(Parameter_Ts), values.data());
239
+ if constexpr (!std::is_void_v<Return_T>)
240
+ {
241
+ return this->fromRuby_.convert(result);
242
+ }
243
+ }
244
+
245
+ template<typename Return_T, typename ...Parameter_Ts>
246
+ inline VALUE NativeCallback<Return_T(*)(Parameter_Ts...)>::operator()(std::map<std::string, VALUE>&, VALUE)
247
+ {
248
+ return Qnil;
249
+ }
250
+
251
+ template<typename Return_T, typename ...Parameter_Ts>
252
+ inline std::string NativeCallback<Return_T(*)(Parameter_Ts...)>::toString()
253
+ {
254
+ return "";
255
+ }
256
+
257
+ //NativeKind kind() override;
258
+ template<typename Return_T, typename ...Parameter_Ts>
259
+ inline NativeKind NativeCallback<Return_T(*)(Parameter_Ts...)>::kind()
260
+ {
261
+ return NativeKind::Callback;
262
+ }
263
+
264
+ template<typename Return_T, typename ...Parameter_Ts>
265
+ inline VALUE NativeCallback<Return_T(*)(Parameter_Ts...)>::returnKlass()
266
+ {
267
+ // Check if an array is being returned
268
+ bool isBuffer = dynamic_cast<ReturnBuffer*>(this->returnInfo_.get()) ? true : false;
269
+ if (isBuffer)
270
+ {
271
+ TypeMapper<Pointer<detail::remove_cv_recursive_t<std::remove_pointer_t<Return_T>>>> typeMapper;
272
+ return typeMapper.rubyKlass();
273
+ }
274
+ else
275
+ {
276
+ TypeMapper<Return_T> typeMapper;
277
+ return typeMapper.rubyKlass();
278
+ }
279
+ }
280
+ }
@@ -35,55 +35,45 @@ namespace Rice::detail
35
35
  * calling them methods (self) or functions (no self).
36
36
  */
37
37
 
38
- template<typename Function_T>
38
+ template<typename Function_T, bool NoGVL = false>
39
39
  class NativeFunction: Native
40
40
  {
41
41
  public:
42
- using NativeFunction_T = NativeFunction<Function_T>;
42
+ using NativeFunction_T = NativeFunction<Function_T, NoGVL>;
43
43
 
44
44
  // We remove const to avoid an explosion of To_Ruby specializations and Ruby doesn't
45
45
  // have the concept of constants anyways
46
46
  using Return_T = typename function_traits<Function_T>::return_type;
47
47
  using Class_T = typename function_traits<Function_T>::class_type;
48
- using Arg_Ts = typename function_traits<Function_T>::arg_types;
48
+ using Parameter_Ts = typename function_traits<Function_T>::arg_types;
49
49
  using To_Ruby_T = remove_cv_recursive_t<Return_T>;
50
50
 
51
- // Register function with Ruby
52
- static void define(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo);
51
+ template<typename ...Arg_Ts>
52
+ static void define(VALUE klass, std::string function_name, Function_T function, Arg_Ts&& ...args);
53
53
 
54
54
  public:
55
- NativeFunction(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo);
55
+ NativeFunction(VALUE klass, std::string method_name, Function_T function, std::unique_ptr<Return>&& returnInfo, std::vector<std::unique_ptr<ParameterAbstract>>&& parameters);
56
56
 
57
- VALUE operator()(size_t argc, const VALUE* argv, VALUE self) override;
57
+ VALUE operator()(std::map<std::string, VALUE>& values, VALUE self) override;
58
58
  std::string toString() override;
59
59
 
60
- std::string name() override;
61
60
  NativeKind kind() override;
62
61
  VALUE returnKlass() override;
63
62
 
64
63
  private:
65
- template<std::size_t...I>
66
- std::vector<std::string> argTypeNames(std::ostringstream& stream, std::index_sequence<I...>& indices);
64
+ std::vector<std::string> argTypeNames();
67
65
 
68
66
  // Convert Ruby values to C++ values
69
67
  template<typename std::size_t...I>
70
- Arg_Ts getNativeValues(std::vector<std::optional<VALUE>>& values, std::index_sequence<I...>& indices);
71
-
72
- // Throw an exception when wrapper cannot be extracted
73
- [[noreturn]] void noWrapper(const VALUE klass, const std::string& wrapper);
74
-
75
- // Do we need to keep alive any arguments?
76
- void checkKeepAlive(VALUE self, VALUE returnValue, std::vector<std::optional<VALUE>>& rubyValues);
68
+ Parameter_Ts getNativeValues(std::vector<std::optional<VALUE>>& values, std::index_sequence<I...>& indices);
77
69
 
78
70
  // Call the underlying C++ function
79
- VALUE invoke(Arg_Ts&& nativeArgs);
80
- VALUE invokeNoGVL(Arg_Ts&& nativeArgs);
71
+ VALUE invoke(Parameter_Ts&& nativeArgs);
72
+ VALUE invokeNoGVL(Parameter_Ts&& nativeArgs);
81
73
 
82
74
  private:
83
75
  VALUE klass_;
84
- std::string method_name_;
85
76
  Function_T function_;
86
- std::unique_ptr<MethodInfo> methodInfo_;
87
77
  To_Ruby<To_Ruby_T> toRuby_;
88
78
  };
89
79
  }