[gjs] Value: add Gjs::AutoGValue and use this to handle lifetime of GValues



commit e6950f8d6a1336d02aa348aa1391bf3db6924110
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date:   Fri May 14 18:06:01 2021 +0200

    Value: add Gjs::AutoGValue and use this to handle lifetime of GValues
    
    Add a simple structure that wraps GValue that allows us handling
    lifetime of GValue's in a nicer way and redefine AutoGValueVector
    with it transparently.
    
    In this way the allocated data keeps being structured as GValues but we
    handle its initializations without errors.

 gi/arg-cache.cpp |  3 +--
 gi/arg.cpp       |  3 +--
 gi/object.cpp    | 24 ++++++------------------
 gi/object.h      |  8 +-------
 gi/value.cpp     |  4 +---
 gi/value.h       | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 60 insertions(+), 32 deletions(-)
---
diff --git a/gi/arg-cache.cpp b/gi/arg-cache.cpp
index 53064b36..dfc76557 100644
--- a/gi/arg-cache.cpp
+++ b/gi/arg-cache.cpp
@@ -568,14 +568,13 @@ static bool gjs_marshal_gvalue_in_in(JSContext* cx, GjsArgumentCache*,
         }
     }
 
-    GValue gvalue = G_VALUE_INIT;
+    Gjs::AutoGValue gvalue;
 
     if (!gjs_value_to_g_value(cx, value, &gvalue))
         return false;
 
     gjs_arg_set(arg, g_boxed_copy(G_TYPE_VALUE, &gvalue));
 
-    g_value_unset(&gvalue);
     return true;
 }
 
diff --git a/gi/arg.cpp b/gi/arg.cpp
index 85edfc4d..2a82b07b 100644
--- a/gi/arg.cpp
+++ b/gi/arg.cpp
@@ -1221,14 +1221,13 @@ static bool value_to_interface_gi_argument(
             return true;
         }
 
-        GValue gvalue = G_VALUE_INIT;
+        Gjs::AutoGValue gvalue;
         if (!gjs_value_to_g_value(cx, value, &gvalue)) {
             gjs_arg_unset<void*>(arg);
             return false;
         }
 
         gjs_arg_set(arg, g_boxed_copy(G_TYPE_VALUE, &gvalue));
-        g_value_unset(&gvalue);
         return true;
 
     } else if (arg::is_gdk_atom(interface_info)) {
diff --git a/gi/object.cpp b/gi/object.cpp
index 5e27c64b..5eeb651a 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -367,8 +367,6 @@ bool ObjectInstance::prop_getter_impl(JSContext* cx, JS::HandleString name,
         return true;
     }
 
-    GValue gvalue = { 0, };
-
     ObjectPrototype* proto_priv = get_prototype();
     GParamSpec *param = proto_priv->find_param_spec_from_id(cx, name);
 
@@ -388,15 +386,10 @@ bool ObjectInstance::prop_getter_impl(JSContext* cx, JS::HandleString name,
     gjs_debug_jsprop(GJS_DEBUG_GOBJECT, "Accessing GObject property %s",
                      param->name);
 
-    g_value_init(&gvalue, G_PARAM_SPEC_VALUE_TYPE(param));
+    Gjs::AutoGValue gvalue(G_PARAM_SPEC_VALUE_TYPE(param));
     g_object_get_property(m_ptr, param->name, &gvalue);
-    if (!gjs_value_from_g_value(cx, rval, &gvalue)) {
-        g_value_unset(&gvalue);
-        return false;
-    }
-    g_value_unset(&gvalue);
 
-    return true;
+    return gjs_value_from_g_value(cx, rval, &gvalue);
 }
 
 [[nodiscard]] static GjsAutoFieldInfo lookup_field_info(GIObjectInfo* info,
@@ -531,15 +524,11 @@ bool ObjectInstance::prop_setter_impl(JSContext* cx, JS::HandleString name,
     gjs_debug_jsprop(GJS_DEBUG_GOBJECT, "Setting GObject prop %s",
                      param_spec->name);
 
-    GValue gvalue = G_VALUE_INIT;
-    g_value_init(&gvalue, G_PARAM_SPEC_VALUE_TYPE(param_spec));
-    if (!gjs_value_to_g_value(cx, value, &gvalue)) {
-        g_value_unset(&gvalue);
+    Gjs::AutoGValue gvalue(G_PARAM_SPEC_VALUE_TYPE(param_spec));
+    if (!gjs_value_to_g_value(cx, value, &gvalue))
         return false;
-    }
 
     g_object_set_property(m_ptr, param_spec->name, &gvalue);
-    g_value_unset(&gvalue);
 
     return true;
 }
@@ -1097,9 +1086,8 @@ bool ObjectPrototype::props_to_g_parameters(JSContext* context,
                                                     param_spec->name);
             /* prevent setting the prop even in JS */
 
-        GValue& gvalue = values->emplace_back();
-        gvalue = G_VALUE_INIT;
-        g_value_init(&gvalue, G_PARAM_SPEC_VALUE_TYPE(param_spec));
+        Gjs::AutoGValue& gvalue =
+            values->emplace_back(G_PARAM_SPEC_VALUE_TYPE(param_spec));
         if (!gjs_value_to_g_value(context, value, &gvalue))
             return false;
 
diff --git a/gi/object.h b/gi/object.h
index 980aff4a..1d5403bd 100644
--- a/gi/object.h
+++ b/gi/object.h
@@ -27,6 +27,7 @@
 #include <mozilla/HashFunctions.h>  // for HashGeneric, HashNumber
 #include <mozilla/Likely.h>         // for MOZ_LIKELY
 
+#include "gi/value.h"
 #include "gi/wrapperutils.h"
 #include "gjs/jsapi-util-root.h"
 #include "gjs/jsapi-util.h"
@@ -63,13 +64,6 @@ class GjsListLink {
     [[nodiscard]] size_t size() const;
 };
 
-struct AutoGValueVector : public std::vector<GValue> {
-    ~AutoGValueVector() {
-        for (GValue value : *this)
-            g_value_unset(&value);
-    }
-};
-
 /*
  * ObjectBase:
  *
diff --git a/gi/value.cpp b/gi/value.cpp
index f2f3bfc0..df427464 100644
--- a/gi/value.cpp
+++ b/gi/value.cpp
@@ -539,8 +539,6 @@ gjs_value_to_g_value_internal(JSContext      *context,
 
         /* special case GValue */
         if (g_type_is_a(gtype, G_TYPE_VALUE)) {
-            GValue nested_gvalue = G_VALUE_INIT;
-
             /* explicitly handle values that are already GValues
                to avoid infinite recursion */
             if (value.isObject()) {
@@ -557,11 +555,11 @@ gjs_value_to_g_value_internal(JSContext      *context,
                 }
             }
 
+            Gjs::AutoGValue nested_gvalue;
             if (!gjs_value_to_g_value(context, value, &nested_gvalue))
                 return false;
 
             g_value_set_boxed(gvalue, &nested_gvalue);
-            g_value_unset(&nested_gvalue);
             return true;
         }
 
diff --git a/gi/value.h b/gi/value.h
index 611cfb1a..8d05ee67 100644
--- a/gi/value.h
+++ b/gi/value.h
@@ -7,12 +7,62 @@
 
 #include <config.h>
 
+#include <utility>  // for move, swap
+#include <vector>   // for vector
+
 #include <glib-object.h>
 
 #include <js/TypeDecls.h>
 
 #include "gjs/macros.h"
 
+namespace Gjs {
+struct AutoGValue : GValue {
+    AutoGValue() {
+        static_assert(sizeof(AutoGValue) == sizeof(GValue));
+        *static_cast<GValue*>(this) = G_VALUE_INIT;
+    }
+    explicit AutoGValue(GType gtype) : AutoGValue() {
+        g_value_init(this, gtype);
+    }
+    AutoGValue(AutoGValue const& src) : AutoGValue(G_VALUE_TYPE(&src)) {
+        g_value_copy(&src, this);
+    }
+    AutoGValue& operator=(AutoGValue other) {
+        // We need to cast to GValue here not to make swap to recurse here
+        std::swap(*static_cast<GValue*>(this), *static_cast<GValue*>(&other));
+        return *this;
+    }
+    AutoGValue(AutoGValue&& src) {
+        switch (G_VALUE_TYPE(&src)) {
+            case G_TYPE_NONE:
+            case G_TYPE_CHAR:
+            case G_TYPE_UCHAR:
+            case G_TYPE_BOOLEAN:
+            case G_TYPE_INT:
+            case G_TYPE_UINT:
+            case G_TYPE_LONG:
+            case G_TYPE_ULONG:
+            case G_TYPE_INT64:
+            case G_TYPE_UINT64:
+            case G_TYPE_FLOAT:
+            case G_TYPE_DOUBLE:
+                *static_cast<GValue*>(this) =
+                    std::move(static_cast<GValue const&&>(src));
+                break;
+            default:
+                // We can't safely move in complex cases, so let's just copy
+                *static_cast<GValue*>(this) = G_VALUE_INIT;
+                *this = src;
+                g_value_unset(&src);
+        }
+    }
+    ~AutoGValue() { g_value_unset(this); }
+};
+}  // namespace Gjs
+
+using AutoGValueVector = std::vector<Gjs::AutoGValue>;
+
 GJS_JSAPI_RETURN_CONVENTION
 bool       gjs_value_to_g_value         (JSContext      *context,
                                          JS::HandleValue value,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]