From e67f4c3a4d59bb65b44c88323d5c88b8f1c9d255 Mon Sep 17 00:00:00 2001 From: zekexiao Date: Tue, 9 Dec 2025 18:09:30 +0800 Subject: [PATCH] use mrb string to malloc method memory & add native init --- include/mrubypp/bind_class.h | 41 +++++++++++++++++++----------------- test/test_class.cpp | 32 +++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 20 deletions(-) diff --git a/include/mrubypp/bind_class.h b/include/mrubypp/bind_class.h index 0a27a97..e53e45a 100644 --- a/include/mrubypp/bind_class.h +++ b/include/mrubypp/bind_class.h @@ -37,11 +37,11 @@ template struct method_wrapper { using MethodType = Ret (T::*)(MethodArgs...); - // TODO, fix memory leak - static void *method_to_ptr(MethodType method) { - auto ptr = malloc(sizeof(MethodType)); + static mrb_value method_to_ptr(mrb_state* mrb, MethodType method) { + mrb_value bytes = mrb_str_new(mrb, NULL, sizeof(MethodType)); + void* ptr = (void*)RSTRING_PTR(bytes); memcpy(ptr, &method, sizeof(MethodType)); - return ptr; + return bytes; } static MethodType ptr_to_method(void *ptr) { @@ -57,7 +57,7 @@ struct method_wrapper { 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); if constexpr (std::is_same_v) { @@ -75,11 +75,11 @@ template struct 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 mrb_value method_to_ptr(mrb_state* mrb, MethodType method) { + mrb_value bytes = mrb_str_new(mrb, NULL, sizeof(MethodType)); + void* ptr = (void*)RSTRING_PTR(bytes); + memcpy(ptr, &method, sizeof(MethodType)); + return bytes; } static MethodType ptr_to_method(void *ptr) { @@ -95,7 +95,7 @@ struct const_method_wrapper { 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); if constexpr (std::is_same_v) { std::apply(method, std::tuple_cat(std::make_tuple(instance), args)); @@ -164,17 +164,20 @@ public: return *this; } + bind_class& def_constructor(mrb_func_t func, + mrb_aspec aspec = MRB_ARGS_ANY()) { + return def_native("initialize", func, aspec); + } + template bind_class &def_method(const std::string &name, Ret (T::*method)(MethodArgs...)) { mrb_sym method_sym = mrb_intern_cstr(mrb_, name.c_str()); using wrap = method_wrapper; - auto ptr = wrap::method_to_ptr(method); - - mrb_value env[] = { - mrb_cptr_value(mrb_, ptr), - }; + auto obj = wrap::method_to_ptr(mrb_, method); + mrb_gc_protect(mrb_, obj); + mrb_value env[] = { obj }; struct RProc *p = mrb_proc_new_cfunc_with_env(mrb_, &wrap::wrapper, 1, env); mrb_method_t m; MRB_METHOD_FROM_PROC(m, p); @@ -189,10 +192,10 @@ public: mrb_sym method_sym = mrb_intern_cstr(mrb_, name.c_str()); using wrap = const_method_wrapper; - auto ptr = wrap::method_to_ptr(method); - auto obj = mrb_cptr_value(mrb_, ptr); + auto obj = wrap::method_to_ptr(mrb_, method); + mrb_gc_protect(mrb_, obj); - mrb_value env[] = {obj}; + mrb_value env[] = { obj }; struct RProc *p = mrb_proc_new_cfunc_with_env(mrb_, &wrap::wrapper, 1, env); mrb_method_t m; diff --git a/test/test_class.cpp b/test/test_class.cpp index 529890b..ef7c883 100644 --- a/test/test_class.cpp +++ b/test/test_class.cpp @@ -36,6 +36,27 @@ private: 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::data_type; + return self; +} + static mrb_value point_native_div(mrb_state *mrb, mrb_value self) { auto point = mrubypp::bind_class::get_this(mrb, self); auto divisor = mrubypp::converter::from_mrb(mrb, mrb_get_arg1(mrb)); @@ -64,7 +85,7 @@ template <> struct mrubypp::converter { TEST_CASE("bind_class", "[class]") { mrubypp::engine engine; mrubypp::bind_class(engine.get_mrb(), "Point") - .def_constructor() + .def_constructor(point_native_init, MRB_ARGS_OPT(2)) .def_method("add", &Point::add) .def_class_method("none", &Point::none) .def_property("x", &Point::get_x, &Point::set_x) @@ -91,6 +112,9 @@ TEST_CASE("bind_class", "[class]") { def test_class_method() return Point::none() end + def test_class_init() + return Point.new(10) + end )"); SECTION("test_method") { @@ -115,4 +139,10 @@ TEST_CASE("bind_class", "[class]") { auto result = engine.call("test_class_method"); REQUIRE(result == 1); } + + SECTION("test_class_init") { + auto result = engine.call("test_class_init"); + REQUIRE(result.get_x() == 10); + REQUIRE(result.get_y() == 0); + } }