use mrb string to malloc method memory & add native init

This commit is contained in:
2025-12-09 18:09:30 +08:00
parent ef4ada6035
commit e67f4c3a4d
2 changed files with 53 additions and 20 deletions

View File

@@ -37,11 +37,11 @@ template <typename T, typename Ret, typename... MethodArgs>
struct method_wrapper { struct method_wrapper {
using MethodType = Ret (T::*)(MethodArgs...); using MethodType = Ret (T::*)(MethodArgs...);
// TODO, fix memory leak static mrb_value method_to_ptr(mrb_state* mrb, MethodType method) {
static void *method_to_ptr(MethodType method) { mrb_value bytes = mrb_str_new(mrb, NULL, sizeof(MethodType));
auto ptr = malloc(sizeof(MethodType)); void* ptr = (void*)RSTRING_PTR(bytes);
memcpy(ptr, &method, sizeof(MethodType)); memcpy(ptr, &method, sizeof(MethodType));
return ptr; return bytes;
} }
static MethodType ptr_to_method(void *ptr) { static MethodType ptr_to_method(void *ptr) {
@@ -57,7 +57,7 @@ struct method_wrapper {
mrb_raise(mrb, E_RUNTIME_ERROR, "invalid instance"); mrb_raise(mrb, E_RUNTIME_ERROR, "invalid instance");
} }
void *method_ptr = mrb_cptr(mrb_cfunc_env_get(mrb, 0)); void *method_ptr = (void*)RSTRING_PTR(mrb_cfunc_env_get(mrb, 0));
auto method = ptr_to_method(method_ptr); auto method = ptr_to_method(method_ptr);
if constexpr (std::is_same_v<Ret, void>) { if constexpr (std::is_same_v<Ret, void>) {
@@ -75,11 +75,11 @@ template <typename T, typename Ret, typename... MethodArgs>
struct const_method_wrapper { struct const_method_wrapper {
using MethodType = Ret (T::*)(MethodArgs...) const; using MethodType = Ret (T::*)(MethodArgs...) const;
// TODO, fix memory leak static mrb_value method_to_ptr(mrb_state* mrb, MethodType method) {
static void *method_to_ptr(MethodType method) { mrb_value bytes = mrb_str_new(mrb, NULL, sizeof(MethodType));
auto ptr = malloc(sizeof(MethodType)); void* ptr = (void*)RSTRING_PTR(bytes);
memcpy(ptr, &method, sizeof(MethodType)); memcpy(ptr, &method, sizeof(MethodType));
return ptr; return bytes;
} }
static MethodType ptr_to_method(void *ptr) { static MethodType ptr_to_method(void *ptr) {
@@ -95,7 +95,7 @@ struct const_method_wrapper {
mrb_raise(mrb, E_RUNTIME_ERROR, "invalid instance"); mrb_raise(mrb, E_RUNTIME_ERROR, "invalid instance");
} }
void *method_ptr = mrb_cptr(mrb_cfunc_env_get(mrb, 0)); void *method_ptr = (void*)RSTRING_PTR(mrb_cfunc_env_get(mrb, 0));
auto method = ptr_to_method(method_ptr); 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));
@@ -164,17 +164,20 @@ public:
return *this; return *this;
} }
bind_class& def_constructor(mrb_func_t func,
mrb_aspec aspec = MRB_ARGS_ANY()) {
return def_native("initialize", func, aspec);
}
template <typename Ret, typename... MethodArgs> template <typename Ret, typename... MethodArgs>
bind_class &def_method(const std::string &name, bind_class &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());
using wrap = method_wrapper<T, Ret, MethodArgs...>; using wrap = method_wrapper<T, Ret, MethodArgs...>;
auto ptr = wrap::method_to_ptr(method); auto obj = wrap::method_to_ptr(mrb_, method);
mrb_gc_protect(mrb_, obj);
mrb_value env[] = { mrb_value env[] = { obj };
mrb_cptr_value(mrb_, ptr),
};
struct RProc *p = mrb_proc_new_cfunc_with_env(mrb_, &wrap::wrapper, 1, env); struct RProc *p = mrb_proc_new_cfunc_with_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);
@@ -189,8 +192,8 @@ public:
mrb_sym method_sym = mrb_intern_cstr(mrb_, name.c_str()); mrb_sym method_sym = mrb_intern_cstr(mrb_, name.c_str());
using wrap = const_method_wrapper<T, Ret, MethodArgs...>; using wrap = const_method_wrapper<T, Ret, MethodArgs...>;
auto ptr = wrap::method_to_ptr(method); auto obj = wrap::method_to_ptr(mrb_, method);
auto obj = mrb_cptr_value(mrb_, ptr);
mrb_gc_protect(mrb_, obj); mrb_gc_protect(mrb_, obj);
mrb_value env[] = { obj }; mrb_value env[] = { obj };

View File

@@ -36,6 +36,27 @@ private:
int y_; int y_;
}; };
static mrb_value point_native_init(mrb_state* mrb, mrb_value self) {
auto count = mrb_get_argc(mrb);
Point* p = nullptr;
if (count == 0)
{
p = new Point(0, 0);
} else if (count == 1) {
auto argv = mrb_get_argv(mrb);
p = new Point(mrb_as_float(mrb, argv[0]), 0);
} else if (count == 2) {
auto argv = mrb_get_argv(mrb);
p = new Point(mrb_as_float(mrb, argv[0]), mrb_as_float(mrb, argv[1]));
} else {
mrb_raise(mrb, E_ARGUMENT_ERROR, "Point wrong number of arguments");
}
DATA_PTR(self) = p;
DATA_TYPE(self) = &mrubypp::bind_class<Point>::data_type;
return self;
}
static mrb_value point_native_div(mrb_state *mrb, mrb_value self) { static mrb_value point_native_div(mrb_state *mrb, mrb_value self) {
auto point = mrubypp::bind_class<Point>::get_this(mrb, self); auto point = mrubypp::bind_class<Point>::get_this(mrb, self);
auto divisor = mrubypp::converter<int>::from_mrb(mrb, mrb_get_arg1(mrb)); auto divisor = mrubypp::converter<int>::from_mrb(mrb, mrb_get_arg1(mrb));
@@ -64,7 +85,7 @@ template <> struct mrubypp::converter<Point> {
TEST_CASE("bind_class", "[class]") { TEST_CASE("bind_class", "[class]") {
mrubypp::engine engine; mrubypp::engine engine;
mrubypp::bind_class<Point>(engine.get_mrb(), "Point") mrubypp::bind_class<Point>(engine.get_mrb(), "Point")
.def_constructor<int, int>() .def_constructor(point_native_init, MRB_ARGS_OPT(2))
.def_method("add", &Point::add) .def_method("add", &Point::add)
.def_class_method("none", &Point::none) .def_class_method("none", &Point::none)
.def_property("x", &Point::get_x, &Point::set_x) .def_property("x", &Point::get_x, &Point::set_x)
@@ -91,6 +112,9 @@ TEST_CASE("bind_class", "[class]") {
def test_class_method() def test_class_method()
return Point::none() return Point::none()
end end
def test_class_init()
return Point.new(10)
end
)"); )");
SECTION("test_method") { SECTION("test_method") {
@@ -115,4 +139,10 @@ TEST_CASE("bind_class", "[class]") {
auto result = engine.call<int>("test_class_method"); auto result = engine.call<int>("test_class_method");
REQUIRE(result == 1); REQUIRE(result == 1);
} }
SECTION("test_class_init") {
auto result = engine.call<Point>("test_class_init");
REQUIRE(result.get_x() == 10);
REQUIRE(result.get_y() == 0);
}
} }