rice 4.3.3 → 4.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +63 -26
- data/README.md +7 -2
- data/Rakefile +7 -1
- data/include/rice/rice.hpp +7291 -4430
- data/include/rice/stl.hpp +769 -222
- data/lib/mkmf-rice.rb +37 -95
- data/rice/Address_Registration_Guard.hpp +72 -3
- data/rice/Arg.hpp +19 -5
- data/rice/Arg.ipp +24 -0
- data/rice/Callback.hpp +21 -0
- data/rice/Callback.ipp +13 -0
- data/rice/Constructor.hpp +4 -27
- data/rice/Constructor.ipp +79 -0
- data/rice/Data_Object.hpp +74 -3
- data/rice/Data_Object.ipp +324 -32
- data/rice/Data_Type.hpp +215 -3
- data/rice/Data_Type.ipp +125 -64
- data/rice/Director.hpp +0 -2
- data/rice/Enum.hpp +4 -6
- data/rice/Enum.ipp +101 -57
- data/rice/Exception.hpp +62 -2
- data/rice/Exception.ipp +7 -12
- data/rice/JumpException.hpp +44 -0
- data/rice/JumpException.ipp +48 -0
- data/rice/MemoryView.hpp +11 -0
- data/rice/MemoryView.ipp +43 -0
- data/rice/Return.hpp +6 -26
- data/rice/Return.ipp +10 -16
- data/rice/detail/DefaultHandler.hpp +12 -0
- data/rice/detail/DefaultHandler.ipp +8 -0
- data/rice/detail/HandlerRegistry.hpp +5 -35
- data/rice/detail/HandlerRegistry.ipp +7 -11
- data/rice/detail/InstanceRegistry.hpp +1 -4
- data/rice/detail/MethodInfo.hpp +15 -5
- data/rice/detail/MethodInfo.ipp +78 -6
- data/rice/detail/Native.hpp +32 -0
- data/rice/detail/Native.ipp +129 -0
- data/rice/detail/NativeAttributeGet.hpp +51 -0
- data/rice/detail/NativeAttributeGet.ipp +51 -0
- data/rice/detail/NativeAttributeSet.hpp +43 -0
- data/rice/detail/NativeAttributeSet.ipp +82 -0
- data/rice/detail/NativeCallbackFFI.hpp +55 -0
- data/rice/detail/NativeCallbackFFI.ipp +151 -0
- data/rice/detail/NativeCallbackSimple.hpp +30 -0
- data/rice/detail/NativeCallbackSimple.ipp +29 -0
- data/rice/detail/NativeFunction.hpp +20 -21
- data/rice/detail/NativeFunction.ipp +199 -64
- data/rice/detail/NativeIterator.hpp +8 -11
- data/rice/detail/NativeIterator.ipp +27 -31
- data/rice/detail/NativeRegistry.hpp +24 -15
- data/rice/detail/NativeRegistry.ipp +23 -48
- data/rice/detail/Proc.hpp +4 -0
- data/rice/detail/Proc.ipp +85 -0
- data/rice/detail/Registries.hpp +0 -7
- data/rice/detail/Registries.ipp +0 -18
- data/rice/detail/RubyFunction.hpp +0 -3
- data/rice/detail/RubyFunction.ipp +4 -8
- data/rice/detail/RubyType.hpp +19 -0
- data/rice/detail/RubyType.ipp +187 -0
- data/rice/detail/TupleIterator.hpp +14 -0
- data/rice/detail/Type.hpp +5 -6
- data/rice/detail/Type.ipp +150 -33
- data/rice/detail/TypeRegistry.hpp +15 -7
- data/rice/detail/TypeRegistry.ipp +105 -12
- data/rice/detail/Wrapper.hpp +6 -5
- data/rice/detail/Wrapper.ipp +45 -23
- data/rice/detail/cpp_protect.hpp +5 -6
- data/rice/detail/default_allocation_func.ipp +0 -2
- data/rice/detail/from_ruby.hpp +37 -3
- data/rice/detail/from_ruby.ipp +911 -454
- data/rice/detail/ruby.hpp +18 -0
- data/rice/detail/to_ruby.hpp +41 -3
- data/rice/detail/to_ruby.ipp +437 -113
- data/rice/global_function.hpp +0 -4
- data/rice/global_function.ipp +1 -2
- data/rice/rice.hpp +105 -22
- data/rice/ruby_mark.hpp +4 -3
- data/rice/stl.hpp +4 -0
- data/test/embed_ruby.cpp +4 -1
- data/test/extconf.rb +2 -0
- data/test/ruby/test_multiple_extensions_same_class.rb +14 -14
- data/test/test_Address_Registration_Guard.cpp +5 -0
- data/test/test_Array.cpp +12 -1
- data/test/test_Attribute.cpp +103 -21
- data/test/test_Builtin_Object.cpp +5 -0
- data/test/test_Callback.cpp +231 -0
- data/test/test_Class.cpp +5 -31
- data/test/test_Constructor.cpp +69 -6
- data/test/test_Data_Object.cpp +9 -4
- data/test/test_Data_Type.cpp +428 -64
- data/test/test_Director.cpp +10 -5
- data/test/test_Enum.cpp +152 -40
- data/test/test_Exception.cpp +235 -0
- data/test/test_File.cpp +70 -0
- data/test/test_From_Ruby.cpp +542 -0
- data/test/test_Hash.cpp +5 -0
- data/test/test_Identifier.cpp +5 -0
- data/test/test_Inheritance.cpp +6 -1
- data/test/test_Iterator.cpp +5 -0
- data/test/test_JumpException.cpp +22 -0
- data/test/test_Keep_Alive.cpp +6 -1
- data/test/test_Keep_Alive_No_Wrapper.cpp +5 -0
- data/test/test_Memory_Management.cpp +5 -0
- data/test/test_Module.cpp +118 -64
- data/test/test_Native_Registry.cpp +2 -33
- data/test/test_Object.cpp +5 -0
- data/test/test_Overloads.cpp +631 -0
- data/test/test_Ownership.cpp +67 -4
- data/test/test_Proc.cpp +45 -0
- data/test/test_Self.cpp +5 -0
- data/test/test_Stl_Exception.cpp +109 -0
- data/test/test_Stl_Map.cpp +22 -8
- data/test/test_Stl_Optional.cpp +5 -0
- data/test/test_Stl_Pair.cpp +7 -2
- data/test/test_Stl_Reference_Wrapper.cpp +5 -0
- data/test/test_Stl_SmartPointer.cpp +210 -5
- data/test/test_Stl_String.cpp +5 -0
- data/test/test_Stl_String_View.cpp +5 -0
- data/test/test_Stl_Type.cpp +147 -0
- data/test/test_Stl_Unordered_Map.cpp +18 -7
- data/test/test_Stl_Variant.cpp +5 -0
- data/test/test_Stl_Vector.cpp +130 -8
- data/test/test_String.cpp +5 -0
- data/test/test_Struct.cpp +5 -0
- data/test/test_Symbol.cpp +5 -0
- data/test/test_Template.cpp +192 -0
- data/test/test_To_Ruby.cpp +152 -0
- data/test/test_Tracking.cpp +1 -0
- data/test/test_Type.cpp +100 -0
- data/test/test_global_functions.cpp +53 -6
- data/test/unittest.cpp +8 -0
- metadata +37 -20
- data/lib/version.rb +0 -3
- data/rice/Address_Registration_Guard_defn.hpp +0 -79
- data/rice/Data_Object_defn.hpp +0 -84
- data/rice/Data_Type_defn.hpp +0 -190
- data/rice/Exception_defn.hpp +0 -68
- data/rice/HandlerRegistration.hpp +0 -15
- data/rice/Identifier.hpp +0 -50
- data/rice/Identifier.ipp +0 -29
- data/rice/detail/ExceptionHandler.hpp +0 -8
- data/rice/detail/ExceptionHandler.ipp +0 -28
- data/rice/detail/ExceptionHandler_defn.hpp +0 -77
- data/rice/detail/Jump_Tag.hpp +0 -21
- data/rice/detail/NativeAttribute.hpp +0 -64
- data/rice/detail/NativeAttribute.ipp +0 -112
- data/rice/detail/from_ruby_defn.hpp +0 -38
- data/rice/detail/to_ruby_defn.hpp +0 -48
- data/test/test_Jump_Tag.cpp +0 -17
- data/test/test_To_From_Ruby.cpp +0 -399
@@ -0,0 +1,51 @@
|
|
1
|
+
#ifndef Rice__detail__Native_Attribute_Get__hpp_
|
2
|
+
#define Rice__detail__Native_Attribute_Get__hpp_
|
3
|
+
|
4
|
+
namespace Rice
|
5
|
+
{
|
6
|
+
enum class AttrAccess
|
7
|
+
{
|
8
|
+
ReadWrite,
|
9
|
+
Read,
|
10
|
+
Write
|
11
|
+
};
|
12
|
+
|
13
|
+
namespace detail
|
14
|
+
{
|
15
|
+
template<typename Attribute_T>
|
16
|
+
class NativeAttributeGet: Native
|
17
|
+
{
|
18
|
+
public:
|
19
|
+
using NativeAttribute_T = NativeAttributeGet<Attribute_T>;
|
20
|
+
|
21
|
+
using T = typename attribute_traits<Attribute_T>::attr_type;
|
22
|
+
using Receiver_T = typename attribute_traits<Attribute_T>::class_type;
|
23
|
+
using To_Ruby_T = remove_cv_recursive_t<T>;
|
24
|
+
|
25
|
+
public:
|
26
|
+
// Register attribute getter with Ruby
|
27
|
+
static void define(VALUE klass, std::string name, Attribute_T attribute);
|
28
|
+
|
29
|
+
public:
|
30
|
+
// Disallow creating/copying/moving
|
31
|
+
NativeAttributeGet() = delete;
|
32
|
+
NativeAttributeGet(const NativeAttribute_T&) = delete;
|
33
|
+
NativeAttributeGet(NativeAttribute_T&&) = delete;
|
34
|
+
void operator=(const NativeAttribute_T&) = delete;
|
35
|
+
void operator=(NativeAttribute_T&&) = delete;
|
36
|
+
|
37
|
+
Resolved matches(int argc, const VALUE* argv, VALUE self) override;
|
38
|
+
VALUE operator()(int argc, const VALUE* argv, VALUE self) override;
|
39
|
+
|
40
|
+
protected:
|
41
|
+
NativeAttributeGet(VALUE klass, std::string name, Attribute_T attr);
|
42
|
+
|
43
|
+
private:
|
44
|
+
VALUE klass_;
|
45
|
+
std::string name_;
|
46
|
+
Attribute_T attribute_;
|
47
|
+
};
|
48
|
+
} // detail
|
49
|
+
} // Rice
|
50
|
+
|
51
|
+
#endif // Rice__detail__Native_Attribute_Get__hpp_
|
@@ -0,0 +1,51 @@
|
|
1
|
+
#include <array>
|
2
|
+
#include <algorithm>
|
3
|
+
|
4
|
+
|
5
|
+
namespace Rice::detail
|
6
|
+
{
|
7
|
+
template<typename Attribute_T>
|
8
|
+
void NativeAttributeGet<Attribute_T>::define(VALUE klass, std::string name, Attribute_T attribute)
|
9
|
+
{
|
10
|
+
// Create a NativeAttributeGet that Ruby will call to read/write C++ variables
|
11
|
+
NativeAttribute_T* nativeAttribute = new NativeAttribute_T(klass, name, std::forward<Attribute_T>(attribute));
|
12
|
+
std::unique_ptr<Native> native(nativeAttribute);
|
13
|
+
|
14
|
+
detail::protect(rb_define_method, klass, name.c_str(), (RUBY_METHOD_FUNC)&Native::resolve, -1);
|
15
|
+
|
16
|
+
// Add to native registry. Since attributes cannot be overridden, there is no need to set the
|
17
|
+
// matches or calls function pointer. Instead Ruby can call the static call method defined on
|
18
|
+
// this class (&NativeAttribute_T::get).
|
19
|
+
Identifier identifier(name);
|
20
|
+
detail::Registries::instance.natives.add(klass, identifier.id(), native);
|
21
|
+
}
|
22
|
+
|
23
|
+
template<typename Attribute_T>
|
24
|
+
inline Resolved NativeAttributeGet<Attribute_T>::matches(int argc, const VALUE* argv, VALUE self)
|
25
|
+
{
|
26
|
+
if (argc == 0)
|
27
|
+
return Resolved { Convertible::Exact, 1, this };
|
28
|
+
else
|
29
|
+
return Resolved{ Convertible::None, 0, this };
|
30
|
+
}
|
31
|
+
|
32
|
+
template<typename Attribute_T>
|
33
|
+
NativeAttributeGet<Attribute_T>::NativeAttributeGet(VALUE klass, std::string name, Attribute_T attribute)
|
34
|
+
: klass_(klass), name_(name), attribute_(attribute)
|
35
|
+
{
|
36
|
+
}
|
37
|
+
|
38
|
+
template<typename Attribute_T>
|
39
|
+
inline VALUE NativeAttributeGet<Attribute_T>::operator()(int argc, const VALUE* argv, VALUE self)
|
40
|
+
{
|
41
|
+
if constexpr (std::is_member_object_pointer_v<Attribute_T>)
|
42
|
+
{
|
43
|
+
Receiver_T* nativeSelf = From_Ruby<Receiver_T*>().convert(self);
|
44
|
+
return To_Ruby<To_Ruby_T>().convert(nativeSelf->*attribute_);
|
45
|
+
}
|
46
|
+
else
|
47
|
+
{
|
48
|
+
return To_Ruby<To_Ruby_T>().convert(*attribute_);
|
49
|
+
}
|
50
|
+
}
|
51
|
+
} // Rice
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#ifndef Rice__detail__Native_Attribute_Set__hpp_
|
2
|
+
#define Rice__detail__Native_Attribute_Set__hpp_
|
3
|
+
|
4
|
+
namespace Rice
|
5
|
+
{
|
6
|
+
namespace detail
|
7
|
+
{
|
8
|
+
template<typename Attribute_T>
|
9
|
+
class NativeAttributeSet: Native
|
10
|
+
{
|
11
|
+
public:
|
12
|
+
using NativeAttribute_T = NativeAttributeSet<Attribute_T>;
|
13
|
+
using Attr_T = typename attribute_traits<Attribute_T>::attr_type;
|
14
|
+
using T_Unqualified = remove_cv_recursive_t<Attr_T>;
|
15
|
+
using Receiver_T = typename attribute_traits<Attribute_T>::class_type;
|
16
|
+
|
17
|
+
public:
|
18
|
+
// Register attribute getter/setter with Ruby
|
19
|
+
static void define(VALUE klass, std::string name, Attribute_T attribute);
|
20
|
+
|
21
|
+
public:
|
22
|
+
// Disallow creating/copying/moving
|
23
|
+
NativeAttributeSet() = delete;
|
24
|
+
NativeAttributeSet(const NativeAttribute_T&) = delete;
|
25
|
+
NativeAttributeSet(NativeAttribute_T&&) = delete;
|
26
|
+
void operator=(const NativeAttribute_T&) = delete;
|
27
|
+
void operator=(NativeAttribute_T&&) = delete;
|
28
|
+
|
29
|
+
Resolved matches(int argc, const VALUE* argv, VALUE self) override;
|
30
|
+
VALUE operator()(int argc, const VALUE* argv, VALUE self) override;
|
31
|
+
|
32
|
+
protected:
|
33
|
+
NativeAttributeSet(VALUE klass, std::string name, Attribute_T attr);
|
34
|
+
|
35
|
+
private:
|
36
|
+
VALUE klass_;
|
37
|
+
std::string name_;
|
38
|
+
Attribute_T attribute_;
|
39
|
+
};
|
40
|
+
} // detail
|
41
|
+
} // Rice
|
42
|
+
|
43
|
+
#endif // Rice__detail__Native_Attribute_Set__hpp_
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#include <array>
|
2
|
+
#include <algorithm>
|
3
|
+
|
4
|
+
|
5
|
+
namespace Rice::detail
|
6
|
+
{
|
7
|
+
template<typename Attribute_T>
|
8
|
+
void NativeAttributeSet<Attribute_T>::define(VALUE klass, std::string name, Attribute_T attribute)
|
9
|
+
{
|
10
|
+
// Create a NativeAttributeSet that Ruby will call to read/write C++ variables
|
11
|
+
NativeAttribute_T* nativeAttribute = new NativeAttribute_T(klass, name, std::forward<Attribute_T>(attribute));
|
12
|
+
std::unique_ptr<Native> native(nativeAttribute);
|
13
|
+
|
14
|
+
// Define the write method name
|
15
|
+
std::string setter = name + "=";
|
16
|
+
|
17
|
+
// Tell Ruby to invoke the static method write to get the attribute value
|
18
|
+
detail::protect(rb_define_method, klass, setter.c_str(), (RUBY_METHOD_FUNC)&Native::resolve, -1);
|
19
|
+
|
20
|
+
// Add to native registry. Since attributes cannot be overridden, there is no need to set the
|
21
|
+
// matches or calls function pointer. Instead Ruby can call the static call method defined on
|
22
|
+
// this class (&NativeAttribute_T::set).
|
23
|
+
Identifier identifier(setter);
|
24
|
+
detail::Registries::instance.natives.add(klass, identifier.id(), native);
|
25
|
+
}
|
26
|
+
|
27
|
+
template<typename Attribute_T>
|
28
|
+
NativeAttributeSet<Attribute_T>::NativeAttributeSet(VALUE klass, std::string name, Attribute_T attribute)
|
29
|
+
: klass_(klass), name_(name), attribute_(attribute)
|
30
|
+
{
|
31
|
+
}
|
32
|
+
|
33
|
+
template<typename Attribute_T>
|
34
|
+
inline Resolved NativeAttributeSet<Attribute_T>::matches(int argc, const VALUE* argv, VALUE self)
|
35
|
+
{
|
36
|
+
if (argc == 1)
|
37
|
+
return Resolved{ Convertible::Exact, 1, this };
|
38
|
+
else
|
39
|
+
return Resolved{ Convertible::None, 0, this };
|
40
|
+
}
|
41
|
+
|
42
|
+
template<typename Attribute_T>
|
43
|
+
inline VALUE NativeAttributeSet<Attribute_T>::operator()(int argc, const VALUE* argv, VALUE self)
|
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
|
+
if (argc != 1)
|
55
|
+
{
|
56
|
+
throw std::runtime_error("Incorrect number of parameters for setting attribute. Attribute: " + this->name_);
|
57
|
+
}
|
58
|
+
|
59
|
+
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>))
|
64
|
+
{
|
65
|
+
Receiver_T* nativeSelf = From_Ruby<Receiver_T*>().convert(self);
|
66
|
+
nativeSelf->*attribute_ = From_Ruby<T_Unqualified>().convert(value);
|
67
|
+
}
|
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
|
+
else
|
75
|
+
{
|
76
|
+
// Should never get here because define_attr won't compile this code, but just in case!
|
77
|
+
throw std::invalid_argument("Could not set attribute. Attribute: " + this->name_);
|
78
|
+
}
|
79
|
+
|
80
|
+
return value;
|
81
|
+
}
|
82
|
+
} // Rice
|
@@ -0,0 +1,55 @@
|
|
1
|
+
#ifndef Rice__detail__Native_Callback_Ffi_hpp_
|
2
|
+
#define Rice__detail__Native_Callback_Ffi_hpp_
|
3
|
+
|
4
|
+
#ifdef HAVE_LIBFFI
|
5
|
+
|
6
|
+
#include <ffi.h>
|
7
|
+
|
8
|
+
namespace Rice::detail
|
9
|
+
{
|
10
|
+
template<typename Callback_T>
|
11
|
+
class NativeCallbackFFI;
|
12
|
+
|
13
|
+
template<typename Return_T, typename ...Arg_Ts>
|
14
|
+
class NativeCallbackFFI<Return_T(*)(Arg_Ts...)>
|
15
|
+
{
|
16
|
+
public:
|
17
|
+
using Callback_T = Return_T(Arg_Ts...);
|
18
|
+
using Tuple_T = std::tuple<Arg_Ts...>;
|
19
|
+
static void ffiCallback(ffi_cif* cif, void* ret, void* args[], void* instance);
|
20
|
+
static VALUE finalizerCallback(VALUE yielded_arg, VALUE callback_arg, int argc, const VALUE* argv, VALUE blockarg);
|
21
|
+
static void setMethodInfo(MethodInfo* methodInfo);
|
22
|
+
|
23
|
+
public:
|
24
|
+
NativeCallbackFFI(VALUE proc);
|
25
|
+
~NativeCallbackFFI();
|
26
|
+
NativeCallbackFFI(const NativeCallbackFFI&) = delete;
|
27
|
+
NativeCallbackFFI(NativeCallbackFFI&&) = delete;
|
28
|
+
void operator=(const NativeCallbackFFI&) = delete;
|
29
|
+
void operator=(NativeCallbackFFI&&) = delete;
|
30
|
+
|
31
|
+
Return_T operator()(Arg_Ts...args);
|
32
|
+
Callback_T* callback();
|
33
|
+
|
34
|
+
private:
|
35
|
+
template <typename Arg_T>
|
36
|
+
static ffi_type* ffiType();
|
37
|
+
|
38
|
+
template<std::size_t... I>
|
39
|
+
static Tuple_T convertArgsToTuple(void* args[], std::index_sequence<I...>& indices);
|
40
|
+
|
41
|
+
static inline std::array<ffi_type*, sizeof...(Arg_Ts)> args_ = { ffiType<Arg_Ts>()... };
|
42
|
+
static inline ffi_cif cif_;
|
43
|
+
static inline ffi_closure* closure_ = nullptr;
|
44
|
+
static inline Callback_T* callback_ = nullptr;
|
45
|
+
static inline std::unique_ptr<MethodInfo> methodInfo_ = std::make_unique<MethodInfo>();
|
46
|
+
|
47
|
+
template<std::size_t... I>
|
48
|
+
Return_T callRuby(std::index_sequence<I...>& indices, Arg_Ts...args);
|
49
|
+
private:
|
50
|
+
VALUE proc_;
|
51
|
+
};
|
52
|
+
}
|
53
|
+
#endif // HAVE_LIBFFI
|
54
|
+
|
55
|
+
#endif // Rice__detail__Native_Callback_Ffi_hpp_
|
@@ -0,0 +1,151 @@
|
|
1
|
+
#ifdef HAVE_LIBFFI
|
2
|
+
#include <ffi.h>
|
3
|
+
|
4
|
+
namespace Rice::detail
|
5
|
+
{
|
6
|
+
template<typename Return_T, typename ...Arg_Ts>
|
7
|
+
template<typename Arg_T>
|
8
|
+
ffi_type* NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::ffiType()
|
9
|
+
{
|
10
|
+
std::map<std::type_index, ffi_type*> nativeToFfiMapping = {
|
11
|
+
{std::type_index(typeid(bool)), &ffi_type_uint8},
|
12
|
+
{std::type_index(typeid(bool)), &ffi_type_uint8},
|
13
|
+
{std::type_index(typeid(char)), &ffi_type_schar},
|
14
|
+
{std::type_index(typeid(unsigned char)), &ffi_type_uchar},
|
15
|
+
{std::type_index(typeid(signed char)), &ffi_type_schar},
|
16
|
+
{std::type_index(typeid(uint8_t)), &ffi_type_uint8},
|
17
|
+
{std::type_index(typeid(unsigned short)), &ffi_type_uint8},
|
18
|
+
{std::type_index(typeid(int8_t)), &ffi_type_sint8},
|
19
|
+
{std::type_index(typeid(short)), &ffi_type_sint8},
|
20
|
+
{std::type_index(typeid(uint16_t)), &ffi_type_uint16},
|
21
|
+
{std::type_index(typeid(int16_t)), &ffi_type_sint16},
|
22
|
+
{std::type_index(typeid(uint32_t)), &ffi_type_uint32},
|
23
|
+
{std::type_index(typeid(unsigned int)), &ffi_type_uint32},
|
24
|
+
{std::type_index(typeid(signed int)), &ffi_type_uint32},
|
25
|
+
{std::type_index(typeid(int32_t)), &ffi_type_sint32},
|
26
|
+
{std::type_index(typeid(uint64_t)), &ffi_type_uint64},
|
27
|
+
{std::type_index(typeid(unsigned long long)), &ffi_type_uint64},
|
28
|
+
{std::type_index(typeid(int64_t)), &ffi_type_sint64},
|
29
|
+
{std::type_index(typeid(signed long long)), &ffi_type_sint64},
|
30
|
+
{std::type_index(typeid(float)), &ffi_type_float},
|
31
|
+
{std::type_index(typeid(double)), &ffi_type_double},
|
32
|
+
{std::type_index(typeid(void)), &ffi_type_pointer},
|
33
|
+
{std::type_index(typeid(long double)), &ffi_type_longdouble}
|
34
|
+
};
|
35
|
+
|
36
|
+
if (sizeof(long) == 32)
|
37
|
+
{
|
38
|
+
nativeToFfiMapping[std::type_index(typeid(unsigned long))] = &ffi_type_uint32;
|
39
|
+
nativeToFfiMapping[std::type_index(typeid(long))] = &ffi_type_sint32;
|
40
|
+
}
|
41
|
+
else if (sizeof(long) == 64)
|
42
|
+
{
|
43
|
+
nativeToFfiMapping[std::type_index(typeid(unsigned long))] = &ffi_type_uint64;
|
44
|
+
nativeToFfiMapping[std::type_index(typeid(long))] = &ffi_type_sint64;
|
45
|
+
}
|
46
|
+
|
47
|
+
if (std::is_pointer_v<Arg_T>)
|
48
|
+
{
|
49
|
+
return &ffi_type_pointer;
|
50
|
+
}
|
51
|
+
else
|
52
|
+
{
|
53
|
+
const std::type_index& key = std::type_index(typeid(Arg_T));
|
54
|
+
return nativeToFfiMapping[key];
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
template<typename Return_T, typename ...Arg_Ts>
|
59
|
+
template<std::size_t... I>
|
60
|
+
typename NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::Tuple_T NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::convertArgsToTuple(void* args[], std::index_sequence<I...>& indices)
|
61
|
+
{
|
62
|
+
/* Loop over each value returned from Ruby and convert it to the appropriate C++ type based
|
63
|
+
on the arguments (Arg_Ts) required by the C++ function. Arg_T may have const/volatile while
|
64
|
+
the associated From_Ruby<T> template parameter will not. Thus From_Ruby produces non-const values
|
65
|
+
which we let the compiler convert to const values as needed. This works except for
|
66
|
+
T** -> const T**, see comment in getNativeValue method. */
|
67
|
+
return std::forward_as_tuple(*(std::tuple_element_t<I, Tuple_T>*)(args[I])...);
|
68
|
+
}
|
69
|
+
|
70
|
+
template<typename Return_T, typename ...Arg_Ts>
|
71
|
+
void NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::ffiCallback(ffi_cif* cif, void* ret, void* args[], void* instance)
|
72
|
+
{
|
73
|
+
using Self_T = NativeCallbackFFI<Return_T(*)(Arg_Ts...)>;
|
74
|
+
Self_T* self = (Self_T*)instance;
|
75
|
+
|
76
|
+
auto indices = std::make_index_sequence<sizeof...(Arg_Ts)>{};
|
77
|
+
|
78
|
+
if constexpr (sizeof...(Arg_Ts) == 0)
|
79
|
+
{
|
80
|
+
*(Return_T*)ret = self->operator()();
|
81
|
+
}
|
82
|
+
else
|
83
|
+
{
|
84
|
+
std::tuple<Arg_Ts...> tuple = convertArgsToTuple(args, indices);
|
85
|
+
*(Return_T*)ret = std::apply(*self, tuple);
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
template<typename Return_T, typename ...Arg_Ts>
|
90
|
+
void NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::setMethodInfo(MethodInfo* methodInfo)
|
91
|
+
{
|
92
|
+
methodInfo_.reset(methodInfo);
|
93
|
+
}
|
94
|
+
|
95
|
+
template<typename Return_T, typename ...Arg_Ts>
|
96
|
+
NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::~NativeCallbackFFI()
|
97
|
+
{
|
98
|
+
this->proc_ = Qnil;
|
99
|
+
}
|
100
|
+
|
101
|
+
template<typename Return_T, typename ...Arg_Ts>
|
102
|
+
VALUE NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::finalizerCallback(VALUE yielded_arg, VALUE callback_arg, int argc, const VALUE* argv, VALUE blockarg)
|
103
|
+
{
|
104
|
+
using NativeCallback_T = NativeCallbackFFI<Return_T(*)(Arg_Ts...)>;
|
105
|
+
NativeCallback_T* nativeCallback = (NativeCallback_T*)callback_arg;
|
106
|
+
delete nativeCallback;
|
107
|
+
return Qnil;
|
108
|
+
}
|
109
|
+
|
110
|
+
template<typename Return_T, typename ...Arg_Ts>
|
111
|
+
NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::NativeCallbackFFI(VALUE proc) : proc_(proc)
|
112
|
+
{
|
113
|
+
// First setup desccription of callback
|
114
|
+
if (cif_.bytes == 0)
|
115
|
+
{
|
116
|
+
ffi_prep_cif(&cif_, FFI_DEFAULT_ABI, sizeof...(Arg_Ts), &ffi_type_pointer, args_.data());
|
117
|
+
}
|
118
|
+
|
119
|
+
// Create FFI closure
|
120
|
+
this->closure_ = (ffi_closure *)ffi_closure_alloc(sizeof(ffi_closure) + sizeof(void*), (void**)(&this->callback_));
|
121
|
+
ffi_status status = ffi_prep_closure_loc(this->closure_, &cif_, ffiCallback, (void*)this, (void*)this->callback_);
|
122
|
+
}
|
123
|
+
|
124
|
+
template<typename Return_T, typename ...Arg_Ts>
|
125
|
+
typename NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::Callback_T* NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::callback()
|
126
|
+
{
|
127
|
+
return (Callback_T*)this->callback_;
|
128
|
+
}
|
129
|
+
|
130
|
+
template<typename Return_T, typename ...Arg_Ts>
|
131
|
+
template<std::size_t... I>
|
132
|
+
Return_T NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::callRuby(std::index_sequence<I...>& indices, Arg_Ts...args)
|
133
|
+
{
|
134
|
+
static Identifier id("call");
|
135
|
+
std::array<VALUE, sizeof...(Arg_Ts)> values = { detail::To_Ruby<detail::remove_cv_recursive_t<Arg_Ts>>(methodInfo_->arg(I)).convert(args)... };
|
136
|
+
VALUE result = detail::protect(rb_funcallv, this->proc_, id.id(), (int)sizeof...(Arg_Ts), values.data());
|
137
|
+
if constexpr (!std::is_void_v<Return_T>)
|
138
|
+
{
|
139
|
+
static From_Ruby<Return_T> fromRuby(dynamic_cast<Arg*>(&methodInfo_->returnInfo));
|
140
|
+
return fromRuby.convert(result);
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
template<typename Return_T, typename ...Arg_Ts>
|
145
|
+
Return_T NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::operator()(Arg_Ts...args)
|
146
|
+
{
|
147
|
+
auto indices = std::make_index_sequence<sizeof...(Arg_Ts)>{};
|
148
|
+
return NativeCallbackFFI<Return_T(*)(Arg_Ts...)>::callRuby(indices, args...);
|
149
|
+
}
|
150
|
+
}
|
151
|
+
#endif // HAVE_LIBFFI
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#ifndef Rice__detail__Native_Callback_Simple_hpp_
|
2
|
+
#define Rice__detail__Native_Callback_Simple_hpp_
|
3
|
+
|
4
|
+
namespace Rice::detail
|
5
|
+
{
|
6
|
+
template<typename Callback_T>
|
7
|
+
class NativeCallbackSimple;
|
8
|
+
|
9
|
+
template<typename Return_T, typename ...Arg_Ts>
|
10
|
+
class NativeCallbackSimple<Return_T(*)(Arg_Ts...)>
|
11
|
+
{
|
12
|
+
public:
|
13
|
+
static Return_T callback(Arg_Ts...args);
|
14
|
+
static inline VALUE proc = Qnil;
|
15
|
+
static void setMethodInfo(MethodInfo* methodInfo);
|
16
|
+
|
17
|
+
public:
|
18
|
+
NativeCallbackSimple() = delete;
|
19
|
+
NativeCallbackSimple(const NativeCallbackSimple&) = delete;
|
20
|
+
NativeCallbackSimple(NativeCallbackSimple&&) = delete;
|
21
|
+
void operator=(const NativeCallbackSimple&) = delete;
|
22
|
+
void operator=(NativeCallbackSimple&&) = delete;
|
23
|
+
|
24
|
+
private:
|
25
|
+
template<std::size_t... I>
|
26
|
+
static Return_T callRuby(std::index_sequence<I...>& indices, Arg_Ts...args);
|
27
|
+
static inline std::unique_ptr<MethodInfo> methodInfo_ = std::make_unique<MethodInfo>();
|
28
|
+
};
|
29
|
+
}
|
30
|
+
#endif // Rice__detail__Native_Callback_Simple_hpp_
|
@@ -0,0 +1,29 @@
|
|
1
|
+
namespace Rice::detail
|
2
|
+
{
|
3
|
+
template<typename Return_T, typename ...Arg_Ts>
|
4
|
+
void NativeCallbackSimple<Return_T(*)(Arg_Ts...)>::setMethodInfo(MethodInfo* methodInfo)
|
5
|
+
{
|
6
|
+
methodInfo_.reset(methodInfo);
|
7
|
+
}
|
8
|
+
|
9
|
+
template<typename Return_T, typename ...Arg_Ts>
|
10
|
+
template<std::size_t... I>
|
11
|
+
Return_T NativeCallbackSimple<Return_T(*)(Arg_Ts...)>::callRuby(std::index_sequence<I...>& indices, Arg_Ts...args)
|
12
|
+
{
|
13
|
+
static Identifier id("call");
|
14
|
+
std::array<VALUE, sizeof...(Arg_Ts)> values = { detail::To_Ruby<detail::remove_cv_recursive_t<Arg_Ts>>(methodInfo_->arg(I)).convert(args)... };
|
15
|
+
VALUE result = detail::protect(rb_funcallv, proc, id.id(), (int)sizeof...(Arg_Ts), values.data());
|
16
|
+
if constexpr (!std::is_void_v<Return_T>)
|
17
|
+
{
|
18
|
+
static From_Ruby<Return_T> fromRuby(dynamic_cast<Arg*>(&methodInfo_->returnInfo));
|
19
|
+
return fromRuby.convert(result);
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
template<typename Return_T, typename ...Arg_Ts>
|
24
|
+
Return_T NativeCallbackSimple<Return_T(*)(Arg_Ts...)>::callback(Arg_Ts...args)
|
25
|
+
{
|
26
|
+
auto indices = std::make_index_sequence<sizeof...(Arg_Ts)>{};
|
27
|
+
return NativeCallbackSimple<Return_T(*)(Arg_Ts...)>::callRuby(indices, args...);
|
28
|
+
}
|
29
|
+
}
|
@@ -1,13 +1,6 @@
|
|
1
1
|
#ifndef Rice__detail__Native_Function__hpp_
|
2
2
|
#define Rice__detail__Native_Function__hpp_
|
3
3
|
|
4
|
-
#include "ruby.hpp"
|
5
|
-
#include "ExceptionHandler_defn.hpp"
|
6
|
-
#include "MethodInfo.hpp"
|
7
|
-
#include "../traits/function_traits.hpp"
|
8
|
-
#include "../traits/method_traits.hpp"
|
9
|
-
#include "from_ruby.hpp"
|
10
|
-
|
11
4
|
namespace Rice::detail
|
12
5
|
{
|
13
6
|
//! The NativeFunction class calls C++ functions/methods/lambdas on behalf of Ruby
|
@@ -43,24 +36,26 @@ namespace Rice::detail
|
|
43
36
|
*/
|
44
37
|
|
45
38
|
template<typename Class_T, typename Function_T, bool IsMethod>
|
46
|
-
class NativeFunction
|
39
|
+
class NativeFunction: Native
|
47
40
|
{
|
48
41
|
public:
|
49
42
|
using NativeFunction_T = NativeFunction<Class_T, Function_T, IsMethod>;
|
50
43
|
|
51
44
|
// We remove const to avoid an explosion of To_Ruby specializations and Ruby doesn't
|
52
45
|
// have the concept of constants anyways
|
53
|
-
using Return_T =
|
46
|
+
using Return_T = typename function_traits<Function_T>::return_type;
|
54
47
|
using Receiver_T = typename method_traits<Function_T, IsMethod>::Class_T;
|
55
48
|
using Arg_Ts = typename method_traits<Function_T, IsMethod>::Arg_Ts;
|
49
|
+
static constexpr std::size_t arity = method_traits<Function_T, IsMethod>::arity;
|
56
50
|
using From_Ruby_Args_Ts = typename tuple_map<From_Ruby, Arg_Ts>::type;
|
51
|
+
using To_Ruby_T = remove_cv_recursive_t<Return_T>;
|
57
52
|
|
58
53
|
// Register function with Ruby
|
59
54
|
static void define(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo);
|
60
55
|
|
61
|
-
//
|
62
|
-
static VALUE
|
63
|
-
|
56
|
+
// Proc entry
|
57
|
+
static VALUE procEntry(VALUE yielded_arg, VALUE callback_arg, int argc, const VALUE* argv, VALUE blockarg);
|
58
|
+
static VALUE finalizerCallback(VALUE yielded_arg, VALUE callback_arg, int argc, const VALUE* argv, VALUE blockarg);
|
64
59
|
public:
|
65
60
|
// Disallow creating/copying/moving
|
66
61
|
NativeFunction() = delete;
|
@@ -69,11 +64,12 @@ namespace Rice::detail
|
|
69
64
|
void operator=(const NativeFunction_T&) = delete;
|
70
65
|
void operator=(NativeFunction_T&&) = delete;
|
71
66
|
|
72
|
-
|
73
|
-
VALUE operator()(int argc, VALUE* argv, VALUE self);
|
67
|
+
Resolved matches(int argc, const VALUE* argv, VALUE self) override;
|
68
|
+
VALUE operator()(int argc, const VALUE* argv, VALUE self) override;
|
74
69
|
|
75
|
-
|
70
|
+
NativeFunction(Function_T function);
|
76
71
|
NativeFunction(VALUE klass, std::string method_name, Function_T function, MethodInfo* methodInfo);
|
72
|
+
protected:
|
77
73
|
|
78
74
|
private:
|
79
75
|
template<typename T, std::size_t I>
|
@@ -83,10 +79,14 @@ namespace Rice::detail
|
|
83
79
|
template<std::size_t...I>
|
84
80
|
From_Ruby_Args_Ts createFromRuby(std::index_sequence<I...>& indices);
|
85
81
|
|
86
|
-
|
82
|
+
// Convert C++ value to Ruby
|
83
|
+
To_Ruby<To_Ruby_T> createToRuby();
|
87
84
|
|
88
85
|
// Convert Ruby argv pointer to Ruby values
|
89
|
-
std::vector<VALUE> getRubyValues(int argc, VALUE* argv);
|
86
|
+
std::vector<VALUE> getRubyValues(int argc, const VALUE* argv, bool validate);
|
87
|
+
|
88
|
+
template<typename Arg_T, int I>
|
89
|
+
Arg_T getNativeValue(std::vector<VALUE>& values);
|
90
90
|
|
91
91
|
// Convert Ruby values to C++ values
|
92
92
|
template<typename std::size_t...I>
|
@@ -102,18 +102,17 @@ namespace Rice::detail
|
|
102
102
|
void checkKeepAlive(VALUE self, VALUE returnValue, std::vector<VALUE>& rubyValues);
|
103
103
|
|
104
104
|
// Call the underlying C++ function
|
105
|
-
VALUE invokeNativeFunction(
|
106
|
-
VALUE invokeNativeMethod(VALUE self,
|
105
|
+
VALUE invokeNativeFunction(Arg_Ts&& nativeArgs);
|
106
|
+
VALUE invokeNativeMethod(VALUE self, Arg_Ts&& nativeArgs);
|
107
107
|
|
108
108
|
private:
|
109
109
|
VALUE klass_;
|
110
110
|
std::string method_name_;
|
111
111
|
Function_T function_;
|
112
112
|
From_Ruby_Args_Ts fromRubys_;
|
113
|
-
To_Ruby<
|
113
|
+
To_Ruby<To_Ruby_T> toRuby_;
|
114
114
|
std::unique_ptr<MethodInfo> methodInfo_;
|
115
115
|
};
|
116
116
|
}
|
117
|
-
#include "NativeFunction.ipp"
|
118
117
|
|
119
118
|
#endif // Rice__detail__Native_Function__hpp_
|