From 07fbd1f0e0a68fb3b130fe9d0b0f5f338346746a Mon Sep 17 00:00:00 2001 From: Kjell Ahlstedt Date: Fri, 31 Mar 2023 19:00:02 +0200 Subject: Glib: value_custom: Use callback functions with C linkage * glib/glibmm/value_custom.[cc|h]: Add custom_boxed_type_cpp_register(). * tests/glibmm_value/main.cc: Add test of copying custom Value. Part of issue #1 --- glib/glibmm/value_custom.cc | 55 +++++++++++++++++++++++++++++++++++++++++++-- glib/glibmm/value_custom.h | 15 +++++++++++-- tests/glibmm_value/main.cc | 7 ++++++ 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/glib/glibmm/value_custom.cc b/glib/glibmm/value_custom.cc index 15260704..0deac7b3 100644 --- a/glib/glibmm/value_custom.cc +++ b/glib/glibmm/value_custom.cc @@ -17,16 +17,49 @@ #include #include #include +#include namespace { +std::map custom_init_funcmap; +std::map custom_free_funcmap; +std::map custom_copy_funcmap; + +extern "C" +{ +static void Value_custom_init_func(GValue* value) +{ + Glib::ValueInitCppFuncType init_func = custom_init_funcmap[G_VALUE_TYPE(value)]; + if (init_func) + init_func(value); + else + g_critical("Value_custom_init_func(): No init_func for GValue %s\n", G_VALUE_TYPE_NAME(value)); +} +static void Value_custom_free_func(GValue* value) +{ + Glib::ValueFreeCppFuncType free_func = custom_free_funcmap[G_VALUE_TYPE(value)]; + if (free_func) + free_func(value); + else + g_critical("Value_custom_free_func(): No free_func for GValue %s\n", G_VALUE_TYPE_NAME(value)); +} +static void Value_custom_copy_func(const GValue* src_value, GValue* dest_value) +{ + Glib::ValueCopyCppFuncType copy_func = custom_copy_funcmap[G_VALUE_TYPE(src_value)]; + if (copy_func) + copy_func(src_value, dest_value); + else + g_critical("Value_custom_copy_func(): No copy_func for GValue %s\n", G_VALUE_TYPE_NAME(src_value)); +} +} // extern "C" static void warn_already_registered(const char* location, const std::string& full_name) { g_warning("file %s: (%s): The type name `%s' has been registered already.\n" - "This is not supposed to happen -- please send a mail with detailed " - "information about your platform to gtkmm-list@gnome.org. Thanks.\n", + "This is not supposed to happen -- please create an issue with " + "detailed information about your platform\n" + "at https://gitlab.gnome.org/GNOME/glibmm/-/issues. Thanks.\n", __FILE__, location, full_name.c_str()); } @@ -35,6 +68,22 @@ warn_already_registered(const char* location, const std::string& full_name) namespace Glib { +GType +custom_boxed_type_cpp_register(const char* type_name, + ValueInitCppFuncType init_func, ValueFreeCppFuncType free_func, + ValueCopyCppFuncType copy_func) +{ + const GType custom_gtype = custom_boxed_type_register(type_name, + &Value_custom_init_func, &Value_custom_free_func, &Value_custom_copy_func); + custom_init_funcmap[custom_gtype] = init_func; + custom_free_funcmap[custom_gtype] = free_func; + custom_copy_funcmap[custom_gtype] = copy_func; + return custom_gtype; +} + +//TODO: When we can break ABI, move the contents of custom_boxed_type_register() +// (with small modifications) to custom_boxed_type_cpp_register() and +// remove custom_boxed_type_register(). GType custom_boxed_type_register( const char* type_name, ValueInitFunc init_func, ValueFreeFunc free_func, ValueCopyFunc copy_func) @@ -61,6 +110,8 @@ custom_boxed_type_register( // destroy, and copy arbitrary objects of the C++ type. const GTypeValueTable value_table = { + //TODO: When moved to custom_boxed_type_cpp_register(): + // &Value_custom_init_func, &Value_custom_free_func, &Value_custom_copy_func, init_func, free_func, copy_func, nullptr, // value_peek_pointer nullptr, // collect_format diff --git a/glib/glibmm/value_custom.h b/glib/glibmm/value_custom.h index 421fa28a..d8e486b5 100644 --- a/glib/glibmm/value_custom.h +++ b/glib/glibmm/value_custom.h @@ -33,20 +33,31 @@ namespace Glib #ifndef DOXYGEN_SHOULD_SKIP_THIS +//TODO: When we can break ABI, remove these extern "C" typedefs and +// custom_boxed_type_register(). extern "C" { typedef void (*ValueInitFunc)(GValue*); typedef void (*ValueFreeFunc)(GValue*); typedef void (*ValueCopyFunc)(const GValue*, GValue*); } +using ValueInitCppFuncType = void (*) (GValue*); +using ValueFreeCppFuncType = void (*) (GValue*); +using ValueCopyCppFuncType = void (*) (const GValue*, GValue*); /* When using Glib::Value with custom types, each T will be registered * as subtype of G_TYPE_BOXED, via this function. The type_name argument * should be the C++ RTTI name. */ +GLIBMM_API +GType custom_boxed_type_cpp_register( + const char* type_name, ValueInitCppFuncType init_func, + ValueFreeCppFuncType free_func, ValueCopyCppFuncType copy_func); + GLIBMM_API GType custom_boxed_type_register( - const char* type_name, ValueInitFunc init_func, ValueFreeFunc free_func, ValueCopyFunc copy_func); + const char* type_name, ValueInitFunc init_func, + ValueFreeFunc free_func, ValueCopyFunc copy_func); /* When using Glib::Value or Glib::Value with custom types, * each T* or const T* will be registered as a subtype of G_TYPE_POINTER, @@ -267,7 +278,7 @@ Value::value_type() { if (!custom_type_) { - custom_type_ = Glib::custom_boxed_type_register(typeid(CppType).name(), + custom_type_ = Glib::custom_boxed_type_cpp_register(typeid(CppType).name(), &Value::value_init_func, &Value::value_free_func, &Value::value_copy_func); } return custom_type_; diff --git a/tests/glibmm_value/main.cc b/tests/glibmm_value/main.cc index a824f948..4aea37cc 100644 --- a/tests/glibmm_value/main.cc +++ b/tests/glibmm_value/main.cc @@ -28,6 +28,13 @@ test() const auto v = value.get(); assert(v.bar == 1); + + // Make a copy + Glib::Value value2; + value2.init(Glib::Value::value_type()); // TODO: Avoid this step? + value2 = value; + const auto v2 = value2.get(); + assert(v2.bar == 1); } { -- cgit v1.2.1