fix failed bind method in gcc/clang
All checks were successful
ubuntu / Explore-Gitea-Actions (push) Successful in 1m39s

This commit is contained in:
2025-10-22 22:11:58 +08:00
parent 4cc759347f
commit 72db94928c
4 changed files with 102 additions and 80 deletions

View File

@@ -4,6 +4,7 @@ project(mrubypp LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(mruby_ROOT "/mnt/d/Sources/mruby/build/host")
option(MRUBYPP_BUILD_TEST "Build Catch2 Test" OFF) option(MRUBYPP_BUILD_TEST "Build Catch2 Test" OFF)

View File

@@ -15,16 +15,16 @@
#include <mruby/data.h> #include <mruby/data.h>
#include <mruby/proc.h> #include <mruby/proc.h>
template <typename... Args, size_t... Is> template<typename... Args, size_t... Is>
std::tuple<Args...> mrubypp_get_args_helper_impl(mrb_state *mrb, std::tuple<Args...> mrubypp_get_args_helper_impl(mrb_state *mrb,
const mrb_value *argv, const mrb_value *argv,
std::index_sequence<Is...>) { std::index_sequence<Is...>) {
return std::make_tuple( return std::make_tuple(
mrubypp_converter<typename std::decay<Args>::type>::from_mrb( mrubypp_converter<typename std::decay<Args>::type>::from_mrb(
mrb, argv[Is])...); mrb, argv[Is])...);
} }
template <typename... Args> template<typename... Args>
std::tuple<typename std::decay<Args>::type...> std::tuple<typename std::decay<Args>::type...>
mrubypp_get_args_helper(mrb_state *mrb) { mrubypp_get_args_helper(mrb_state *mrb) {
mrubypp_arena_guard guard(mrb); mrubypp_arena_guard guard(mrb);
@@ -36,24 +36,37 @@ mrubypp_get_args_helper(mrb_state *mrb) {
} }
return mrubypp_get_args_helper_impl<typename std::decay<Args>::type...>( return mrubypp_get_args_helper_impl<typename std::decay<Args>::type...>(
mrb, argv, std::index_sequence_for<Args...>{}); mrb, argv, std::index_sequence_for<Args...>{});
} }
template <typename T, typename Ret, typename... MethodArgs> template<typename T, typename Ret, typename... MethodArgs>
struct mrubypp_method_wrapper { struct mrubypp_method_wrapper {
using MethodType = Ret (T::*)(MethodArgs...);
// TODO, fix memory leak
static void *method_to_ptr(MethodType method) {
auto ptr = malloc(sizeof(MethodType));
memcpy(ptr, &method, sizeof(MethodType));
return ptr;
}
static MethodType ptr_to_method(void *ptr) {
MethodType method;
memcpy(&method, ptr, sizeof(MethodType));
return method;
}
static mrb_value wrapper(mrb_state *mrb, mrb_value self) { static mrb_value wrapper(mrb_state *mrb, mrb_value self) {
auto args = mrubypp_get_args_helper<MethodArgs...>(mrb); auto args = mrubypp_get_args_helper<MethodArgs...>(mrb);
T *instance = static_cast<T *>(DATA_PTR(self)); T *instance = static_cast<T *>(DATA_PTR(self));
if (!instance) { if (!instance) {
mrb_raise(mrb, E_RUNTIME_ERROR, "invalid instance"); mrb_raise(mrb, E_RUNTIME_ERROR, "invalid instance");
} }
union {
Ret (T::*method)(MethodArgs...);
void *ptr;
} converter;
converter.ptr = mrb_cptr(mrb_cfunc_env_get(mrb, 0));
auto method = converter.method; void *method_ptr = mrb_cptr(mrb_cfunc_env_get(mrb, 0));
auto method = ptr_to_method(method_ptr);
if constexpr (std::is_same_v<Ret, void>) { if constexpr (std::is_same_v<Ret, void>) {
std::apply(method, std::tuple_cat(std::make_tuple(instance), args)); std::apply(method, std::tuple_cat(std::make_tuple(instance), args));
return mrb_nil_value(); return mrb_nil_value();
@@ -65,25 +78,36 @@ struct mrubypp_method_wrapper {
} }
}; };
template <typename T, typename Ret, typename... MethodArgs> template<typename T, typename Ret, typename... MethodArgs>
struct mrubypp_const_method_wrapper { struct mrubypp_const_method_wrapper {
using MethodType = Ret (T::*)(MethodArgs...) const;
// TODO, fix memory leak
static void *method_to_ptr(MethodType method) {
auto ptr = malloc(sizeof(MethodType));
memcpy(ptr, &method, sizeof(MethodType));
return ptr;
}
static MethodType ptr_to_method(void *ptr) {
MethodType method;
memcpy(&method, ptr, sizeof(MethodType));
return method;
}
static mrb_value wrapper(mrb_state *mrb, mrb_value self) { static mrb_value wrapper(mrb_state *mrb, mrb_value self) {
auto args = mrubypp_get_args_helper<MethodArgs...>(mrb); auto args = mrubypp_get_args_helper<MethodArgs...>(mrb);
T *instance = static_cast<T *>(DATA_PTR(self)); T *instance = static_cast<T *>(DATA_PTR(self));
if (!instance) { if (!instance) {
mrb_raise(mrb, E_RUNTIME_ERROR, "invalid instance"); mrb_raise(mrb, E_RUNTIME_ERROR, "invalid instance");
} }
union {
Ret (T::*method)(MethodArgs...) const;
void *ptr;
} converter;
converter.ptr = mrb_cptr(mrb_cfunc_env_get(mrb, 0));
auto method = converter.method;
void *method_ptr = mrb_cptr(mrb_cfunc_env_get(mrb, 0));
auto method = ptr_to_method(method_ptr);
if constexpr (std::is_same_v<Ret, void>) { if constexpr (std::is_same_v<Ret, void>) {
std::apply(method, std::tuple_cat(std::make_tuple(instance), args)); std::apply(method, std::tuple_cat(std::make_tuple(instance), args));
return mrb_nil_value();
} else { } else {
Ret result = Ret result =
std::apply(method, std::tuple_cat(std::make_tuple(instance), args)); std::apply(method, std::tuple_cat(std::make_tuple(instance), args));
@@ -92,16 +116,12 @@ struct mrubypp_const_method_wrapper {
} }
}; };
template <typename T, typename Ret, typename... FuncArgs> template<typename T, typename Ret, typename... FuncArgs>
struct mrubypp_function_wrapper { struct mrubypp_function_wrapper {
static mrb_value wrapper(mrb_state *mrb, mrb_value self) { using FunctionType = Ret (*)(FuncArgs...);
union {
Ret (*func)(FuncArgs...);
void *ptr;
} converter;
converter.ptr = mrb_cptr(mrb_cfunc_env_get(mrb, 0)); static mrb_value wrapper(mrb_state *mrb, mrb_value self) {
auto func = converter.func; auto func = (FunctionType) mrb_cptr(mrb_cfunc_env_get(mrb, 0));
auto args = mrubypp_get_args_helper<FuncArgs...>(mrb); auto args = mrubypp_get_args_helper<FuncArgs...>(mrb);
if constexpr (std::is_same_v<Ret, void>) { if constexpr (std::is_same_v<Ret, void>) {
std::apply(func, args); std::apply(func, args);
@@ -113,9 +133,11 @@ struct mrubypp_function_wrapper {
} }
}; };
template <typename T> class mrubypp_class_builder; template<typename T>
class mrubypp_class_builder;
template <typename T, typename... Args> struct mrubypp_constructor_wrapper { template<typename T, typename... Args>
struct mrubypp_constructor_wrapper {
static mrb_value wrapper(mrb_state *mrb, mrb_value self) { static mrb_value wrapper(mrb_state *mrb, mrb_value self) {
auto args = mrubypp_get_args_helper<Args...>(mrb); auto args = mrubypp_get_args_helper<Args...>(mrb);
T *instance = std::apply([](Args... args) { return new T(args...); }, args); T *instance = std::apply([](Args... args) { return new T(args...); }, args);
@@ -126,49 +148,47 @@ template <typename T, typename... Args> struct mrubypp_constructor_wrapper {
} }
}; };
template <typename T> class mrubypp_class_builder { template<typename T>
class mrubypp_class_builder {
public: public:
static const struct mrb_data_type data_type; static const struct mrb_data_type data_type;
mrubypp_class_builder(mrb_state *mrb, std::string name) mrubypp_class_builder(mrb_state *mrb, std::string name)
: mrb_(mrb), name_(std::move(name)) { : mrb_(mrb), name_(std::move(name)) {
rclass_ = mrb_define_class(mrb_, name_.c_str(), mrb_->object_class); rclass_ = mrb_define_class(mrb_, name_.c_str(), mrb_->object_class);
MRB_SET_INSTANCE_TT(rclass_, MRB_TT_DATA); MRB_SET_INSTANCE_TT(rclass_, MRB_TT_DATA);
mrb_define_method( mrb_define_method(
mrb_, rclass_, "initialize", mrb_, rclass_, "initialize",
[](mrb_state *mrb, mrb_value self) -> mrb_value { [](mrb_state *mrb, mrb_value self) -> mrb_value {
mrb_raise(mrb, E_NOTIMP_ERROR, mrb_raise(mrb, E_NOTIMP_ERROR,
"initialize must be defined explicitly"); "initialize must be defined explicitly");
return self; return self;
}, },
MRB_ARGS_ANY()); MRB_ARGS_ANY());
} }
template <typename... Args> mrubypp_class_builder &def_constructor() { template<typename... Args>
mrubypp_class_builder &def_constructor() {
mrb_define_method(mrb_, rclass_, "initialize", mrb_define_method(mrb_, rclass_, "initialize",
&mrubypp_constructor_wrapper<T, Args...>::wrapper, &mrubypp_constructor_wrapper<T, Args...>::wrapper,
MRB_ARGS_REQ(sizeof...(Args))); MRB_ARGS_REQ(sizeof...(Args)));
return *this; return *this;
} }
template <typename Ret, typename... MethodArgs> template<typename Ret, typename... MethodArgs>
mrubypp_class_builder &def_method(const std::string &name, mrubypp_class_builder &def_method(const std::string &name,
Ret (T::*method)(MethodArgs...)) { Ret (T::*method)(MethodArgs...)) {
mrb_sym method_sym = mrb_intern_cstr(mrb_, name.c_str()); mrb_sym method_sym = mrb_intern_cstr(mrb_, name.c_str());
union {
Ret (T::*method_ptr)(MethodArgs...);
void *ptr;
} converter;
converter.method_ptr = method; using wrap = mrubypp_method_wrapper<T, Ret, MethodArgs...>;
auto ptr = wrap::method_to_ptr(method);
mrb_value env[] = { mrb_value env[] = {
mrb_cptr_value(mrb_, converter.ptr), mrb_cptr_value(mrb_, ptr),
}; };
struct RProc *p = mrb_proc_new_cfunc_with_env( struct RProc *p = mrb_proc_new_cfunc_with_env(
mrb_, &mrubypp_method_wrapper<T, Ret, MethodArgs...>::wrapper, 1, env); mrb_, &wrap::wrapper, 1, env);
mrb_method_t m; mrb_method_t m;
MRB_METHOD_FROM_PROC(m, p); MRB_METHOD_FROM_PROC(m, p);
mrb_define_method_raw(mrb_, rclass_, method_sym, m); mrb_define_method_raw(mrb_, rclass_, method_sym, m);
@@ -176,45 +196,39 @@ public:
return *this; return *this;
} }
template <typename Ret, typename... MethodArgs> template<typename Ret, typename... MethodArgs>
mrubypp_class_builder &def_method(const std::string &name, mrubypp_class_builder &def_method(const std::string &name,
Ret (T::*method)(MethodArgs...) const) { Ret (T::*method)(MethodArgs...) const) {
mrb_sym method_sym = mrb_intern_cstr(mrb_, name.c_str()); mrb_sym method_sym = mrb_intern_cstr(mrb_, name.c_str());
union { using wrap = mrubypp_const_method_wrapper<T, Ret, MethodArgs...>;
Ret (T::*method_ptr)(MethodArgs...) const;
void *ptr;
} converter;
converter.method_ptr = method; auto ptr = wrap::method_to_ptr(method);
auto obj = mrb_cptr_value(mrb_, ptr);
mrb_gc_protect(mrb_, obj);
mrb_value env[] = { mrb_value env[] = {
mrb_cptr_value(mrb_, converter.ptr), obj
}; };
struct RProc *p = mrb_proc_new_cfunc_with_env( struct RProc *p = mrb_proc_new_cfunc_with_env(
mrb_, &mrubypp_const_method_wrapper<T, Ret, MethodArgs...>::wrapper, 1, mrb_, &wrap::wrapper, 1,
env); env);
mrb_method_t m; mrb_method_t m;
MRB_METHOD_FROM_PROC(m, p); MRB_METHOD_FROM_PROC(m, p);
mrb_define_method_raw(mrb_, rclass_, method_sym, m); mrb_define_method_raw(mrb_, rclass_, method_sym, m);
return *this; return *this;
} }
template <typename Ret, typename... FuncArgs> template<typename Ret, typename... FuncArgs>
mrubypp_class_builder &def_class_method(const std::string &name, mrubypp_class_builder &def_class_method(const std::string &name,
Ret (*func)(FuncArgs...)) { Ret (*func)(FuncArgs...)) {
using wrap = mrubypp_function_wrapper<T, Ret, FuncArgs...>;
union {
Ret (*funcPtr)(FuncArgs...);
void *ptr;
} converter;
converter.funcPtr = func;
mrb_value env[] = { mrb_value env[] = {
mrb_cptr_value(mrb_, converter.ptr), mrb_cptr_value(mrb_, (void *) func),
}; };
mrb_sym func_sym = mrb_intern_cstr(mrb_, name.c_str()); mrb_sym func_sym = mrb_intern_cstr(mrb_, name.c_str());
struct RProc *p = mrb_proc_new_cfunc_with_env( struct RProc *p = mrb_proc_new_cfunc_with_env(
mrb_, &mrubypp_function_wrapper<T, Ret, FuncArgs...>::wrapper, 1, env); mrb_, &wrap::wrapper, 1, env);
mrb_method_t m; mrb_method_t m;
MRB_METHOD_FROM_PROC(m, p); MRB_METHOD_FROM_PROC(m, p);
@@ -225,11 +239,10 @@ public:
} }
// get set // get set
template <typename Ret> template<typename Ret>
mrubypp_class_builder &def_property(const std::string &name, mrubypp_class_builder &def_property(const std::string &name,
Ret (T::*getter)() const, Ret (T::*getter)() const,
void (T::*setter)(Ret)) { void (T::*setter)(Ret)) {
def_method(name, getter); def_method(name, getter);
def_method(name + "=", setter); def_method(name + "=", setter);
return *this; return *this;
@@ -258,14 +271,14 @@ private:
delete instance; delete instance;
} }
} }
static std::map<std::string, mrb_method_t> method_map;
mrb_state *mrb_; mrb_state *mrb_;
struct RClass *rclass_; struct RClass *rclass_;
std::string name_; std::string name_;
}; };
template <typename T> template<typename T>
const struct mrb_data_type mrubypp_class_builder<T>::data_type = { const struct mrb_data_type mrubypp_class_builder<T>::data_type = {
typeid(T).name(), mrubypp_class_builder<T>::free_instance typeid(T).name(), mrubypp_class_builder<T>::free_instance
}; };

View File

@@ -8,7 +8,8 @@
class Point { class Point {
public: public:
Point(int x, int y) : x_(x), y_(y) {} Point(int x, int y) : x_(x), y_(y) {
}
void set_values(int x, int y) { void set_values(int x, int y) {
x_ = x; x_ = x;
@@ -16,10 +17,16 @@ public:
} }
int get_x() const { return x_; } int get_x() const { return x_; }
void set_x(int x) { x_ = x; }
void set_x(int x) {
x_ = x;
}
int get_y() const { return y_; } int get_y() const { return y_; }
void set_y(int y) { y_ = y; }
void set_y(int y) {
y_ = y;
}
void add(const Point &other) { void add(const Point &other) {
this->x_ += other.x_; this->x_ += other.x_;
@@ -41,11 +48,12 @@ static mrb_value point_native_div(mrb_state *mrb, mrb_value self) {
return self; return self;
} }
template <> struct mrubypp_converter<Point> { template<>
struct mrubypp_converter<Point> {
static mrb_value to_mrb(mrb_state *mrb, const Point &var) { static mrb_value to_mrb(mrb_state *mrb, const Point &var) {
mrb_value obj = mrb_obj_value( mrb_value obj = mrb_obj_value(
mrb_data_object_alloc(mrb, mrb->object_class, new Point(var), mrb_data_object_alloc(mrb, mrb->object_class, new Point(var),
&mrubypp_class_builder<Point>::data_type)); &mrubypp_class_builder<Point>::data_type));
return obj; return obj;
} }
@@ -112,4 +120,4 @@ TEST_CASE("Point", "[class]") {
auto result = engine.call<int>("test_class_method"); auto result = engine.call<int>("test_class_method");
REQUIRE(result == 1); REQUIRE(result == 1);
} }
} }

View File

@@ -47,4 +47,4 @@ TEST_CASE("call benchmark", "[!benchmark]") {
auto b = engine.call<int>("get_same", 1); auto b = engine.call<int>("get_same", 1);
REQUIRE(b == 1); REQUIRE(b == 1);
}; };
} }