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,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
|
+
}
|