rice 4.3.3 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +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,48 @@
|
|
1
|
+
namespace Rice
|
2
|
+
{
|
3
|
+
inline JumpException::JumpException(ruby_tag_type tag) : tag(tag)
|
4
|
+
{
|
5
|
+
this->createMessage();
|
6
|
+
}
|
7
|
+
|
8
|
+
inline const char* JumpException::what() const noexcept
|
9
|
+
{
|
10
|
+
return this->message_.c_str();
|
11
|
+
}
|
12
|
+
|
13
|
+
inline void JumpException::createMessage()
|
14
|
+
{
|
15
|
+
switch (this->tag)
|
16
|
+
{
|
17
|
+
case RUBY_TAG_NONE:
|
18
|
+
this->message_ = "No error";
|
19
|
+
break;
|
20
|
+
case RUBY_TAG_RETURN:
|
21
|
+
this->message_ = "Unexpected return";
|
22
|
+
break;
|
23
|
+
case RUBY_TAG_NEXT:
|
24
|
+
this->message_ = "Unexpected next";
|
25
|
+
break;
|
26
|
+
case RUBY_TAG_BREAK:
|
27
|
+
this->message_ = "Unexpected break";
|
28
|
+
break;
|
29
|
+
case RUBY_TAG_REDO:
|
30
|
+
this->message_ = "Unexpected redo";
|
31
|
+
break;
|
32
|
+
case RUBY_TAG_RETRY:
|
33
|
+
this->message_ = "Retry outside of rescue clause";
|
34
|
+
break;
|
35
|
+
case RUBY_TAG_THROW:
|
36
|
+
this->message_ = "Unexpected throw";
|
37
|
+
case RUBY_TAG_RAISE:
|
38
|
+
this->message_ = "Ruby exception was thrown";
|
39
|
+
break;
|
40
|
+
case RUBY_TAG_FATAL:
|
41
|
+
this->message_ = "Fatal error";
|
42
|
+
break;
|
43
|
+
case RUBY_TAG_MASK:
|
44
|
+
this->message_ = "Mask error";
|
45
|
+
break;
|
46
|
+
}
|
47
|
+
}
|
48
|
+
} // namespace Rice
|
data/rice/MemoryView.hpp
ADDED
data/rice/MemoryView.ipp
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
namespace Rice
|
2
|
+
{
|
3
|
+
}
|
4
|
+
|
5
|
+
namespace Rice::detail
|
6
|
+
{
|
7
|
+
template<>
|
8
|
+
class To_Ruby<unsigned char**>
|
9
|
+
{
|
10
|
+
public:
|
11
|
+
VALUE convert(unsigned char** x)
|
12
|
+
{
|
13
|
+
std::runtime_error("To_Ruby unsigned char** is not implemented yet");
|
14
|
+
return Qnil;
|
15
|
+
}
|
16
|
+
};
|
17
|
+
|
18
|
+
template<>
|
19
|
+
class From_Ruby<unsigned char**>
|
20
|
+
{
|
21
|
+
public:
|
22
|
+
From_Ruby() = default;
|
23
|
+
|
24
|
+
explicit From_Ruby(Arg* arg) : arg_(arg)
|
25
|
+
{
|
26
|
+
}
|
27
|
+
|
28
|
+
Convertible is_convertible(VALUE value)
|
29
|
+
{
|
30
|
+
std::runtime_error("From_Ruby unsigned char** is not implemented yet");
|
31
|
+
return Convertible::None;
|
32
|
+
}
|
33
|
+
|
34
|
+
unsigned char** convert(VALUE value)
|
35
|
+
{
|
36
|
+
std::runtime_error("From_Ruby unsigned char** is not implemented yet");
|
37
|
+
return nullptr;
|
38
|
+
}
|
39
|
+
|
40
|
+
private:
|
41
|
+
Arg* arg_ = nullptr;
|
42
|
+
};
|
43
|
+
}
|
data/rice/Return.hpp
CHANGED
@@ -1,40 +1,20 @@
|
|
1
1
|
#ifndef Rice__Return__hpp_
|
2
2
|
#define Rice__Return__hpp_
|
3
3
|
|
4
|
-
#include <any>
|
5
|
-
|
6
4
|
namespace Rice
|
7
5
|
{
|
8
6
|
//! Helper for defining Return argument of a method
|
9
7
|
|
10
|
-
class Return
|
8
|
+
class Return: public Arg
|
11
9
|
{
|
12
10
|
public:
|
13
|
-
|
14
|
-
Return&
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
//! Specifies the returned value is a Ruby value
|
20
|
-
Return& setValue();
|
21
|
-
|
22
|
-
//! Is the returned value a Ruby value?
|
23
|
-
bool isValue() const;
|
11
|
+
Return();
|
12
|
+
Return& keepAlive() override;
|
13
|
+
Return& setValue() override;
|
14
|
+
Return& setOpaque() override;
|
15
|
+
Return& takeOwnership() override;
|
24
16
|
|
25
|
-
//! Tell the returned object to keep alive the receving object
|
26
|
-
Return& keepAlive();
|
27
|
-
|
28
|
-
//! Is the returned value being kept alive?
|
29
|
-
bool isKeepAlive() const;
|
30
|
-
|
31
|
-
private:
|
32
|
-
bool isKeepAlive_ = false;
|
33
|
-
bool isOwner_ = false;
|
34
|
-
bool isValue_ = false;
|
35
17
|
};
|
36
18
|
} // Rice
|
37
19
|
|
38
|
-
#include "Return.ipp"
|
39
|
-
|
40
20
|
#endif // Rice__Return__hpp_
|
data/rice/Return.ipp
CHANGED
@@ -1,38 +1,32 @@
|
|
1
1
|
#include <any>
|
2
|
-
#include <string>
|
3
2
|
|
4
3
|
namespace Rice
|
5
4
|
{
|
6
|
-
inline Return
|
5
|
+
inline Return::Return(): Arg("Return")
|
7
6
|
{
|
8
|
-
this->isOwner_ = true;
|
9
|
-
return *this;
|
10
7
|
}
|
11
8
|
|
12
|
-
inline
|
9
|
+
inline Return& Return::keepAlive()
|
13
10
|
{
|
14
|
-
|
11
|
+
Arg::keepAlive();
|
12
|
+
return *this;
|
15
13
|
}
|
16
14
|
|
17
15
|
inline Return& Return::setValue()
|
18
16
|
{
|
19
|
-
|
17
|
+
Arg::setValue();
|
20
18
|
return *this;
|
21
19
|
}
|
22
20
|
|
23
|
-
inline
|
24
|
-
{
|
25
|
-
return this->isValue_;
|
26
|
-
}
|
27
|
-
|
28
|
-
inline Return& Return::keepAlive()
|
21
|
+
inline Return& Return::setOpaque()
|
29
22
|
{
|
30
|
-
|
23
|
+
Arg::setOpaque();
|
31
24
|
return *this;
|
32
25
|
}
|
33
26
|
|
34
|
-
inline
|
27
|
+
inline Return& Return::takeOwnership()
|
35
28
|
{
|
36
|
-
|
29
|
+
Arg::takeOwnership();
|
30
|
+
return *this;
|
37
31
|
}
|
38
32
|
} // Rice
|
@@ -1,51 +1,21 @@
|
|
1
1
|
#ifndef Rice__detail__HandlerRegistry__hpp_
|
2
2
|
#define Rice__detail__HandlerRegistry__hpp_
|
3
3
|
|
4
|
-
#include
|
4
|
+
#include <functional>
|
5
5
|
|
6
6
|
namespace Rice::detail
|
7
7
|
{
|
8
8
|
class HandlerRegistry
|
9
9
|
{
|
10
10
|
public:
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
* translate the exception into a ruby exception.
|
15
|
-
* \param Exception_T a template parameter indicating the type of
|
16
|
-
* exception to be translated.
|
17
|
-
* \param functor a functor to be called to translate the exception
|
18
|
-
* into a ruby exception. This functor should re-throw the exception
|
19
|
-
* as an Exception.
|
20
|
-
* Example:
|
21
|
-
* \code
|
22
|
-
* Class rb_cFoo;
|
23
|
-
*
|
24
|
-
* void translate_my_exception(MyException const& ex)
|
25
|
-
* {
|
26
|
-
* throw Rice::Exception(rb_eRuntimeError, ex.what_without_backtrace());
|
27
|
-
* }
|
28
|
-
*
|
29
|
-
* extern "C"
|
30
|
-
* void Init_MyExtension()
|
31
|
-
* {
|
32
|
-
* rb_cFoo = define_class("Foo");
|
33
|
-
* register_handler<MyException>(translate_my_exception);
|
34
|
-
* }
|
35
|
-
* \endcode
|
36
|
-
*/
|
37
|
-
template<typename Exception_T, typename Functor_T>
|
38
|
-
HandlerRegistry& add(Functor_T functor);
|
39
|
-
|
40
|
-
std::shared_ptr<detail::ExceptionHandler> handler() const;
|
11
|
+
HandlerRegistry();
|
12
|
+
void set(std::function<void()> handler);
|
13
|
+
std::function<void()> handler() const;
|
41
14
|
|
42
15
|
private:
|
43
|
-
|
44
|
-
|
16
|
+
std::function<void()> handler_;
|
45
17
|
};
|
46
18
|
} // namespace Rice::detail
|
47
19
|
|
48
|
-
#include "HandlerRegistry.ipp"
|
49
|
-
|
50
20
|
#endif // Rice__detail__HandlerRegistry__hpp_
|
51
21
|
|
@@ -1,20 +1,16 @@
|
|
1
|
-
#include <memory>
|
2
|
-
|
3
1
|
namespace Rice::detail
|
4
2
|
{
|
5
|
-
|
6
|
-
inline HandlerRegistry& HandlerRegistry::add(Functor_T functor)
|
3
|
+
inline HandlerRegistry::HandlerRegistry() : handler_(DefaultHandler())
|
7
4
|
{
|
8
|
-
|
9
|
-
// get chained together). Then take ownership of the new handler.
|
10
|
-
this->handler_ = std::make_shared<detail::CustomExceptionHandler<Exception_T, Functor_T>>(
|
11
|
-
functor, std::move(this->handler_));
|
5
|
+
}
|
12
6
|
|
13
|
-
|
7
|
+
inline void HandlerRegistry::set(std::function<void()> handler)
|
8
|
+
{
|
9
|
+
this->handler_ = handler;
|
14
10
|
}
|
15
11
|
|
16
|
-
inline std::
|
12
|
+
inline std::function<void()> HandlerRegistry::handler() const
|
17
13
|
{
|
18
14
|
return this->handler_;
|
19
15
|
}
|
20
|
-
}
|
16
|
+
}
|
@@ -2,7 +2,6 @@
|
|
2
2
|
#define Rice__detail__InstanceRegistry__hpp_
|
3
3
|
|
4
4
|
#include <map>
|
5
|
-
#include "ruby.hpp"
|
6
5
|
|
7
6
|
namespace Rice::detail
|
8
7
|
{
|
@@ -14,6 +13,7 @@ namespace Rice::detail
|
|
14
13
|
|
15
14
|
template <typename T>
|
16
15
|
VALUE lookup(T* cppInstance);
|
16
|
+
VALUE lookup(void* cppInstance);
|
17
17
|
|
18
18
|
void add(void* cppInstance, VALUE rubyInstance);
|
19
19
|
void remove(void* cppInstance);
|
@@ -23,12 +23,9 @@ namespace Rice::detail
|
|
23
23
|
bool isEnabled = false;
|
24
24
|
|
25
25
|
private:
|
26
|
-
VALUE lookup(void* cppInstance);
|
27
26
|
std::map<void*, VALUE> objectMap_;
|
28
27
|
};
|
29
28
|
} // namespace Rice::detail
|
30
29
|
|
31
|
-
#include "InstanceRegistry.ipp"
|
32
|
-
|
33
30
|
#endif // Rice__detail__InstanceRegistry__hpp_
|
34
31
|
|
data/rice/detail/MethodInfo.hpp
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
#define Rice__MethodInfo__hpp_
|
3
3
|
|
4
4
|
#include <vector>
|
5
|
-
#include "../Arg.hpp"
|
6
|
-
#include "../Return.hpp"
|
7
5
|
|
8
6
|
namespace Rice
|
9
7
|
{
|
10
8
|
class MethodInfo
|
11
9
|
{
|
12
10
|
public:
|
11
|
+
MethodInfo() = default;
|
12
|
+
|
13
13
|
template <typename...Arg_Ts>
|
14
14
|
MethodInfo(size_t argCount, const Arg_Ts&...args);
|
15
15
|
|
@@ -24,7 +24,19 @@ namespace Rice
|
|
24
24
|
*/
|
25
25
|
void addArg(const Arg& arg);
|
26
26
|
|
27
|
-
|
27
|
+
/**
|
28
|
+
* Get argument by position
|
29
|
+
*/
|
30
|
+
Arg* arg(size_t pos);
|
31
|
+
|
32
|
+
/**
|
33
|
+
* Get argument by name
|
34
|
+
*/
|
35
|
+
Arg* arg(std::string name);
|
36
|
+
|
37
|
+
int requiredArgCount();
|
38
|
+
int optionalArgCount();
|
39
|
+
void verifyArgCount(int argc);
|
28
40
|
|
29
41
|
// Iterator support
|
30
42
|
std::vector<Arg>::iterator begin();
|
@@ -39,6 +51,4 @@ namespace Rice
|
|
39
51
|
std::vector<Arg> args_;
|
40
52
|
};
|
41
53
|
}
|
42
|
-
#include "MethodInfo.ipp"
|
43
|
-
|
44
54
|
#endif // Rice__MethodInfo__hpp_
|
data/rice/detail/MethodInfo.ipp
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
#include <sstream>
|
2
|
-
#include "from_ruby_defn.hpp"
|
3
2
|
|
4
3
|
namespace Rice
|
5
4
|
{
|
@@ -26,13 +25,13 @@ namespace Rice
|
|
26
25
|
template <typename Arg_T>
|
27
26
|
inline void MethodInfo::processArg(const Arg_T& arg)
|
28
27
|
{
|
29
|
-
if constexpr (std::is_same_v<Arg_T,
|
28
|
+
if constexpr (std::is_same_v<Arg_T, Return>)
|
30
29
|
{
|
31
|
-
this->
|
30
|
+
this->returnInfo = arg;
|
32
31
|
}
|
33
32
|
else
|
34
33
|
{
|
35
|
-
this->
|
34
|
+
this->addArg(arg);
|
36
35
|
}
|
37
36
|
}
|
38
37
|
|
@@ -41,6 +40,60 @@ namespace Rice
|
|
41
40
|
this->args_.push_back(arg);
|
42
41
|
}
|
43
42
|
|
43
|
+
inline int MethodInfo::requiredArgCount()
|
44
|
+
{
|
45
|
+
int result = 0;
|
46
|
+
|
47
|
+
for (const Arg& arg : this->args_)
|
48
|
+
{
|
49
|
+
if (!arg.hasDefaultValue())
|
50
|
+
{
|
51
|
+
result++;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
return result;
|
56
|
+
}
|
57
|
+
|
58
|
+
inline int MethodInfo::optionalArgCount()
|
59
|
+
{
|
60
|
+
int result = 0;
|
61
|
+
|
62
|
+
for (const Arg& arg : this->args_)
|
63
|
+
{
|
64
|
+
if (arg.hasDefaultValue())
|
65
|
+
{
|
66
|
+
result++;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
return result;
|
71
|
+
}
|
72
|
+
|
73
|
+
inline void MethodInfo::verifyArgCount(int argc)
|
74
|
+
{
|
75
|
+
int requiredArgCount = this->requiredArgCount();
|
76
|
+
int optionalArgCount = this->optionalArgCount();
|
77
|
+
|
78
|
+
if (argc < requiredArgCount || argc > requiredArgCount + optionalArgCount)
|
79
|
+
{
|
80
|
+
std::string message;
|
81
|
+
|
82
|
+
if (optionalArgCount > 0)
|
83
|
+
{
|
84
|
+
message = "wrong number of arguments (given " +
|
85
|
+
std::to_string(argc) + ", expected " +
|
86
|
+
std::to_string(requiredArgCount) + ".." + std::to_string(requiredArgCount + optionalArgCount) + ")";
|
87
|
+
}
|
88
|
+
else
|
89
|
+
{
|
90
|
+
message = "wrong number of arguments (given " +
|
91
|
+
std::to_string(argc) + ", expected " + std::to_string(requiredArgCount) + ")";
|
92
|
+
}
|
93
|
+
throw std::invalid_argument(message);
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
44
97
|
inline std::string MethodInfo::formatString()
|
45
98
|
{
|
46
99
|
size_t required = 0;
|
@@ -61,9 +114,28 @@ namespace Rice
|
|
61
114
|
return std::to_string(required) + std::to_string(optional);
|
62
115
|
}
|
63
116
|
|
64
|
-
inline Arg
|
117
|
+
inline Arg* MethodInfo::arg(size_t pos)
|
65
118
|
{
|
66
|
-
|
119
|
+
if (pos < this->args_.size())
|
120
|
+
{
|
121
|
+
return &this->args_[pos];
|
122
|
+
}
|
123
|
+
else
|
124
|
+
{
|
125
|
+
return nullptr;
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
inline Arg* MethodInfo::arg(std::string name)
|
130
|
+
{
|
131
|
+
for (Arg& arg : this->args_)
|
132
|
+
{
|
133
|
+
if (arg.name == name)
|
134
|
+
{
|
135
|
+
return &arg;
|
136
|
+
}
|
137
|
+
}
|
138
|
+
return nullptr;
|
67
139
|
}
|
68
140
|
|
69
141
|
inline std::vector<Arg>::iterator MethodInfo::begin()
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#ifndef Rice__detail__Native__hpp_
|
2
|
+
#define Rice__detail__Native__hpp_
|
3
|
+
|
4
|
+
namespace Rice::detail
|
5
|
+
{
|
6
|
+
class Native;
|
7
|
+
|
8
|
+
class Resolved
|
9
|
+
{
|
10
|
+
public:
|
11
|
+
inline bool operator<(Resolved other);
|
12
|
+
inline bool operator>(Resolved other);
|
13
|
+
|
14
|
+
Convertible convertible;
|
15
|
+
double parameterMatch;
|
16
|
+
Native* native;
|
17
|
+
};
|
18
|
+
|
19
|
+
class Native
|
20
|
+
{
|
21
|
+
public:
|
22
|
+
static VALUE resolve(int argc, VALUE* argv, VALUE self);
|
23
|
+
public:
|
24
|
+
virtual ~Native() = default;
|
25
|
+
VALUE call(int argc, VALUE* argv, VALUE self);
|
26
|
+
|
27
|
+
virtual Resolved matches(int argc, const VALUE* argv, VALUE self) = 0;
|
28
|
+
virtual VALUE operator()(int argc, const VALUE* argv, VALUE self) = 0;
|
29
|
+
};
|
30
|
+
}
|
31
|
+
|
32
|
+
#endif // Rice__detail__Native__hpp_
|
@@ -0,0 +1,129 @@
|
|
1
|
+
|
2
|
+
namespace Rice::detail
|
3
|
+
{
|
4
|
+
inline bool Resolved::operator<(Resolved other)
|
5
|
+
{
|
6
|
+
if (this->convertible != other.convertible)
|
7
|
+
{
|
8
|
+
return this->convertible < other.convertible;
|
9
|
+
}
|
10
|
+
else
|
11
|
+
{
|
12
|
+
return this->parameterMatch < other.parameterMatch;
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
inline bool Resolved::operator>(Resolved other)
|
17
|
+
{
|
18
|
+
if (this->convertible != other.convertible)
|
19
|
+
{
|
20
|
+
return this->convertible > other.convertible;
|
21
|
+
}
|
22
|
+
else
|
23
|
+
{
|
24
|
+
return this->parameterMatch > other.parameterMatch;
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
inline VALUE Native::resolve(int argc, VALUE* argv, VALUE self)
|
29
|
+
{
|
30
|
+
/* This method is called from Ruby and is responsible for determining the correct
|
31
|
+
Native object (ie, NativeFunction, NativeIterator, NativeAttributeGet and
|
32
|
+
NativeAttributeSet) that shoudl be used to invoke the underlying C++ code.
|
33
|
+
Most of the time there will be a single Native object registered for a C++ function,
|
34
|
+
method, constructor, iterator or attribute. However, there can be multiple Natives
|
35
|
+
when a C++ function/method/construtor is overloaded.
|
36
|
+
|
37
|
+
In that case, the code iterates over each Native and calls its matches method. The matches
|
38
|
+
method returns a Resolved object which includes a Convertible field and parameterMatch field.
|
39
|
+
The Convertible field is an enum that specifies if the types of the values supplied by Ruby
|
40
|
+
match the types of the C++ function parameters. Allowed values include can be Exact (example Ruby into to C++ int),
|
41
|
+
TypeCast (example Ruby into to C++ float) or None (cannot be converted).
|
42
|
+
|
43
|
+
The parameterMatch field is simply the number or arguments provided by Ruby divided by the
|
44
|
+
number of arguments required by C++. These numbers can be different because C++ method
|
45
|
+
parameters can have default values.
|
46
|
+
|
47
|
+
Taking these two values into account, the method sorts the Natives and picks the one with the
|
48
|
+
highest score (Convertible::Exact and 1.0 for parameterMatch). Thus given these two C++ functions:
|
49
|
+
|
50
|
+
void some_method(int a);
|
51
|
+
void some_mtehod(int a, float b = 2.0).
|
52
|
+
|
53
|
+
A call from ruby of some_method(1) will exactly match both signatures, but the first one
|
54
|
+
will be chosen because the parameterMatch will be 1.0 for the first overload but 0.5
|
55
|
+
for the second. */
|
56
|
+
|
57
|
+
Native* native = nullptr;
|
58
|
+
|
59
|
+
ID methodId;
|
60
|
+
VALUE klass;
|
61
|
+
if (!rb_frame_method_id_and_class(&methodId, &klass))
|
62
|
+
{
|
63
|
+
rb_raise(rb_eRuntimeError, "Cannot get method id and class for function");
|
64
|
+
}
|
65
|
+
|
66
|
+
// Execute the function but make sure to catch any C++ exceptions!
|
67
|
+
return cpp_protect([&]
|
68
|
+
{
|
69
|
+
Identifier id(methodId);
|
70
|
+
std::string methodName = id.str();
|
71
|
+
std::string className = rb_class2name(klass);
|
72
|
+
|
73
|
+
const std::vector<std::unique_ptr<Native>>& natives = Registries::instance.natives.lookup(klass, methodId);
|
74
|
+
|
75
|
+
if (natives.size() == 1)
|
76
|
+
{
|
77
|
+
native = natives.front().get();
|
78
|
+
}
|
79
|
+
else if (natives.size() == 0)
|
80
|
+
{
|
81
|
+
Identifier identifier(methodId);
|
82
|
+
rb_raise(rb_eArgError, "Could not find method call for %s#%s", rb_class2name(klass), identifier.c_str());
|
83
|
+
}
|
84
|
+
else
|
85
|
+
{
|
86
|
+
// Loop over every native to see how well they match the Ruby parameters
|
87
|
+
std::vector<Resolved> resolves;
|
88
|
+
std::transform(natives.begin(), natives.end(),
|
89
|
+
std::back_inserter(resolves),
|
90
|
+
[&](const std::unique_ptr<Native>& native)
|
91
|
+
{
|
92
|
+
return native->matches(argc, argv, self);
|
93
|
+
});
|
94
|
+
|
95
|
+
// Now sort from best to worst
|
96
|
+
std::sort(resolves.begin(), resolves.end(), std::greater{});
|
97
|
+
|
98
|
+
// Get the best one
|
99
|
+
Resolved resolved = resolves.front();
|
100
|
+
|
101
|
+
// Did it match?
|
102
|
+
if (resolved.convertible != Convertible::None)
|
103
|
+
{
|
104
|
+
native = resolved.native;
|
105
|
+
}
|
106
|
+
else
|
107
|
+
{
|
108
|
+
// Special case == to make the RubyMine debugger work. It calls == with a Module as
|
109
|
+
// the other argument, thus breaking if C++ operator== is implemented.
|
110
|
+
Identifier identifier(methodId);
|
111
|
+
if (identifier.str() == "==")
|
112
|
+
{
|
113
|
+
return detail::protect(rb_call_super, argc, argv);
|
114
|
+
}
|
115
|
+
else
|
116
|
+
{
|
117
|
+
std::ostringstream message;
|
118
|
+
message << "Could not resolve method call for %s#%s" << "\n"
|
119
|
+
<< " %d overload(s) were evaluated based on the types of Ruby parameters provided.";
|
120
|
+
rb_raise(rb_eArgError, message.str().c_str(), rb_class2name(klass), identifier.c_str(), natives.size());
|
121
|
+
}
|
122
|
+
}
|
123
|
+
}
|
124
|
+
|
125
|
+
// Call the C++ function
|
126
|
+
return (*native)(argc, argv, self);
|
127
|
+
});
|
128
|
+
}
|
129
|
+
}
|