[gjs: 1/6] jsapi-util: add GjsAutoPointer to simply generate c++ smart pointers



commit dab3c7d06b7e80ec778bf5a326e2588c8553a09c
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date:   Wed Oct 10 03:11:38 2018 +0200

    jsapi-util: add GjsAutoPointer to simply generate c++ smart pointers
    
    A wrapper on std::unique_ptr that adds facility functions to unref and in case
    take ownership of pointers handling the memory management in a smart way.
    
    Keep just few specializations for specific objects

 gi/object.cpp    |   4 +-
 gjs/jsapi-util.h | 137 ++++++++++++++++++++++++-------------------------------
 2 files changed, 61 insertions(+), 80 deletions(-)
---
diff --git a/gi/object.cpp b/gi/object.cpp
index 3626c2d6..1c3b7c33 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -286,7 +286,7 @@ GParamSpec* ObjectPrototype::find_param_spec_from_id(JSContext* cx,
     GjsAutoChar gname = gjs_hyphen_from_camel(js_prop_name.get());
     GjsAutoTypeClass<GObjectClass> gobj_class(m_gtype);
     GParamSpec* pspec = g_object_class_find_property(gobj_class, gname);
-    GjsAutoParam param_spec(pspec, GjsAutoParam::TakeOwnership());
+    GjsAutoParam param_spec(pspec, GjsAutoTakeOwnership());
 
     if (!param_spec) {
         _gjs_proxy_throw_nonexistent_field(cx, m_gtype, js_prop_name.get());
@@ -2386,7 +2386,7 @@ static bool find_vfunc_info(JSContext* context, GType implementor_gtype,
 
     is_interface = g_base_info_get_type(ancestor_info) == GI_INFO_TYPE_INTERFACE;
 
-    GjsAutoTypeClass<void> implementor_class(implementor_gtype);
+    GjsAutoTypeClass<GTypeClass> implementor_class(implementor_gtype);
     if (is_interface) {
         GTypeInstance *implementor_iface_class;
         implementor_iface_class = (GTypeInstance*) g_type_interface_peek(implementor_class,
diff --git a/gjs/jsapi-util.h b/gjs/jsapi-util.h
index bfd1d079..b9f9053d 100644
--- a/gjs/jsapi-util.h
+++ b/gjs/jsapi-util.h
@@ -39,74 +39,66 @@
 #define GJS_ALWAYS_INLINE
 #endif
 
-class GjsAutoChar : public std::unique_ptr<char, decltype(&g_free)> {
-public:
-    GjsAutoChar(char *str = nullptr) : unique_ptr(str, g_free) {}
-
-    operator const char *() const {
-        return get();
+struct GjsAutoTakeOwnership {};
+
+template <typename T, typename F,
+          void (*free_func)(F*) = nullptr, F* (*ref_func)(F*) = nullptr>
+struct GjsAutoPointer : std::unique_ptr<T, decltype(free_func)> {
+    GjsAutoPointer(T* ptr = nullptr)  // NOLINT(runtime/explicit)
+        : GjsAutoPointer::unique_ptr(ptr, *free_func) {}
+    GjsAutoPointer(T* ptr, const GjsAutoTakeOwnership&)
+        : GjsAutoPointer(nullptr) {
+        auto ref = ref_func;  // use if constexpr ... once we're on C++17
+        this->reset(ptr && ref ? reinterpret_cast<T*>(ref(ptr)) : ptr);
     }
 
-    void operator= (char *str) {
-        reset(str);
-    }
+    operator T*() const { return this->get(); }
+    T& operator[](size_t i) const { return static_cast<T*>(*this)[i]; }
 
-    void operator= (const char *str) {
-        reset(g_strdup(str));
+    T* copy() const { return reinterpret_cast<T*>(ref_func(this->get())); }
+
+    template <typename C>
+    C* as() const {
+        return const_cast<C*>(reinterpret_cast<const C*>(this->get()));
     }
 };
 
-template <typename T>
-class GjsAutoUnref : public std::unique_ptr<T, decltype(&g_object_unref)> {
-public:
-    GjsAutoUnref(T *ptr = nullptr) : GjsAutoUnref::unique_ptr(ptr, g_object_unref) {}
-
-    operator T *() const {
-        return GjsAutoUnref::unique_ptr::get();
-    }
+struct GjsAutoCharFuncs {
+    static char* dup(char* str) { return g_strdup(str); }
+    static void free(char* str) { g_free(str); }
 };
+using GjsAutoChar =
+    GjsAutoPointer<char, char, GjsAutoCharFuncs::free, GjsAutoCharFuncs::dup>;
+
+template <typename T>
+using GjsAutoUnref = GjsAutoPointer<T, void, g_object_unref, g_object_ref>;
 
-template<typename T = GTypeClass>
-class GjsAutoTypeClass : public std::unique_ptr<T, decltype(&g_type_class_unref)> {
-public:
-    GjsAutoTypeClass(gpointer ptr = nullptr)
-        : GjsAutoTypeClass::unique_ptr(static_cast<T*>(ptr), g_type_class_unref) {}
+template <typename T = GTypeClass>
+struct GjsAutoTypeClass : GjsAutoPointer<T, void, &g_type_class_unref> {
+    GjsAutoTypeClass(gpointer ptr = nullptr)  // NOLINT(runtime/explicit)
+        : GjsAutoPointer<T, void, g_type_class_unref>(static_cast<T*>(ptr)) {}
     explicit GjsAutoTypeClass(GType gtype)
         : GjsAutoTypeClass(g_type_class_ref(gtype)) {}
-
-    operator T *() const { return GjsAutoTypeClass::unique_ptr::get(); }
-
-    template<typename C>
-    C *as() const { return reinterpret_cast<C*>(operator T *()); }
 };
 
 // Use this class for owning a GIBaseInfo* of indeterminate type. Any type (e.g.
 // GIFunctionInfo*, GIObjectInfo*) will fit. If you know that the info is of a
 // certain type (e.g. you are storing the return value of a function that
 // returns GIFunctionInfo*,) use one of the derived classes below.
-class GjsAutoBaseInfo
-    : public std::unique_ptr<GIBaseInfo, decltype(&g_base_info_unref)> {
- public:
-    GjsAutoBaseInfo(GIBaseInfo* ptr = nullptr)
-        : GjsAutoBaseInfo::unique_ptr(ptr, g_base_info_unref) {}
-
-    operator GIBaseInfo*() const { return get(); }
-
-    const char* name(void) const { return g_base_info_get_name(get()); }
-    const char* ns(void) const { return g_base_info_get_namespace(get()); }
-    GIInfoType type(void) const { return g_base_info_get_type(get()); }
+struct GjsAutoBaseInfo : GjsAutoPointer<GIBaseInfo, GIBaseInfo,
+                                        g_base_info_unref, g_base_info_ref> {
+    GjsAutoBaseInfo(GIBaseInfo* ptr = nullptr)  // NOLINT(runtime/explicit)
+        : GjsAutoPointer(ptr) {}
+
+    const char* name() const { return g_base_info_get_name(*this); }
+    const char* ns() const { return g_base_info_get_namespace(*this); }
+    GIInfoType type() const { return g_base_info_get_type(*this); }
 };
 
 // Use GjsAutoInfo, preferably its typedefs below, when you know for sure that
 // the info is either of a certain type or null.
 template <GIInfoType TAG>
-class GjsAutoInfo : public GjsAutoBaseInfo {
-    void validate(void) const {
-        if (*this)
-            g_assert(g_base_info_get_type(get()) == TAG);
-    }
-
- public:
+struct GjsAutoInfo : GjsAutoBaseInfo {
     // Normally one-argument constructors should be explicit, but we are trying
     // to conform to the interface of std::unique_ptr here.
     GjsAutoInfo(GIBaseInfo* ptr = nullptr)  // NOLINT(runtime/explicit)
@@ -115,12 +107,18 @@ class GjsAutoInfo : public GjsAutoBaseInfo {
     }
 
     void reset(GIBaseInfo* other = nullptr) {
-        GjsAutoInfo::unique_ptr::reset(other);
+        GjsAutoBaseInfo::reset(other);
         validate();
     }
 
     // You should not need this method, because you already know the answer.
-    GIInfoType type(void) = delete;
+    GIInfoType type() = delete;
+
+ private:
+    void validate() const {
+        if (GIBaseInfo* base = *this)
+            g_assert(g_base_info_get_type(base) == TAG);
+    }
 };
 
 using GjsAutoEnumInfo = GjsAutoInfo<GI_INFO_TYPE_ENUM>;
@@ -135,56 +133,39 @@ using GjsAutoVFuncInfo = GjsAutoInfo<GI_INFO_TYPE_VFUNC>;
 
 // GICallableInfo can be one of several tags, so we have to have a separate
 // class, and use GI_IS_CALLABLE_INFO() to validate.
-class GjsAutoCallableInfo : public GjsAutoBaseInfo {
-    void validate(void) const {
-        if (*this)
-            g_assert(GI_IS_CALLABLE_INFO(get()));
-    }
-
- public:
+struct GjsAutoCallableInfo : GjsAutoBaseInfo {
     GjsAutoCallableInfo(GIBaseInfo* ptr = nullptr)  // NOLINT(runtime/explicit)
         : GjsAutoBaseInfo(ptr) {
         validate();
     }
 
     void reset(GIBaseInfo* other = nullptr) {
-        GjsAutoCallableInfo::unique_ptr::reset(other);
+        GjsAutoBaseInfo::reset(other);
         validate();
     }
+
+ private:
+    void validate() const {
+        if (GIBaseInfo* base = *this)
+            g_assert(GI_IS_CALLABLE_INFO(base));
+    }
 };
 
 /* For use of GjsAutoInfo<TAG> in GC hash maps */
 namespace JS {
 template <GIInfoType TAG>
 struct GCPolicy<GjsAutoInfo<TAG>> : public IgnoreGCPolicy<GjsAutoInfo<TAG>> {};
-}
-
-class GjsAutoParam
-    : public std::unique_ptr<GParamSpec, decltype(&g_param_spec_unref)> {
-    public:
-    struct TakeOwnership {};
-
-    GjsAutoParam(GParamSpec* ptr = nullptr)
-        : unique_ptr(ptr, g_param_spec_unref) {}
-
-    GjsAutoParam(GParamSpec* ptr, const TakeOwnership&)
-        : GjsAutoParam(ptr ? g_param_spec_ref(ptr) : nullptr) {}
+}  // namespace JS
 
-    operator GParamSpec*() const { return get(); }
-};
+using GjsAutoParam = GjsAutoPointer<GParamSpec, GParamSpec, g_param_spec_unref,
+                                    g_param_spec_ref>;
 
 /* For use of GjsAutoParam in GC hash maps */
 namespace JS {
-template<>
+template <>
 struct GCPolicy<GjsAutoParam> : public IgnoreGCPolicy<GjsAutoParam> {};
 }  // namespace JS
 
-struct GjsJSFreeArgs {
-    void operator() (char *str) {
-        JS_free(nullptr, str);
-    }
-};
-
 G_BEGIN_DECLS
 
 #define GJS_UTIL_ERROR gjs_util_error_quark ()


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