[gjs: 2/18] jsapi-util: Add back support for C++ objects and arrays to GjsAutoPointer




commit 84d1fc4669d8dffe7dc0f847e557e2c3f2f5f051
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date:   Tue Sep 29 21:35:50 2020 +0200

    jsapi-util: Add back support for C++ objects and arrays to GjsAutoPointer
    
    As per moving away from std::unique_ptr we lost support for C++ native
    objects, even this may be optional (as we can just use stl containers
    for that), it's still nice to have.
    
    So add it back and include tests.

 gjs/jsapi-util.h              | 47 +++++++++++++++++++++++++++++------
 test/gjs-test-jsapi-utils.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 95 insertions(+), 9 deletions(-)
---
diff --git a/gjs/jsapi-util.h b/gjs/jsapi-util.h
index 43d855ac..0f342283 100644
--- a/gjs/jsapi-util.h
+++ b/gjs/jsapi-util.h
@@ -39,11 +39,16 @@ struct GjsAutoTakeOwnership {};
 template <typename T, typename F = void, void (*free_func)(F*) = free,
           F* (*ref_func)(F*) = nullptr>
 struct GjsAutoPointer {
-    using Ptr = std::add_pointer_t<T>;
-    using ConstPtr = std::add_pointer_t<std::add_const_t<T>>;
+    using Tp =
+        std::conditional_t<std::is_array_v<T>, std::remove_extent_t<T>, T>;
+    using Ptr = std::add_pointer_t<Tp>;
+    using ConstPtr = std::add_pointer_t<std::add_const_t<Tp>>;
 
     constexpr GjsAutoPointer(Ptr ptr = nullptr)  // NOLINT(runtime/explicit)
         : m_ptr(ptr) {}
+    template <typename U = T,
+              typename std::enable_if_t<std::is_array_v<U>, int> = 0>
+    explicit constexpr GjsAutoPointer(Tp ptr[]) : m_ptr(ptr) {}
     constexpr GjsAutoPointer(Ptr ptr, const GjsAutoTakeOwnership&)
         : GjsAutoPointer(ptr) {
         // FIXME: should use if constexpr (...), but that doesn't work with
@@ -68,9 +73,18 @@ struct GjsAutoPointer {
         return *this;
     }
 
-    constexpr T operator*() const { return *m_ptr; }
-    constexpr Ptr operator->() { return m_ptr; }
-    constexpr ConstPtr operator->() const { return m_ptr; }
+    template <typename U = T>
+    constexpr std::enable_if_t<!std::is_array_v<U>, Ptr> operator->() {
+        return m_ptr;
+    }
+
+    template <typename U = T>
+    constexpr std::enable_if_t<!std::is_array_v<U>, ConstPtr> operator->()
+        const {
+        return m_ptr;
+    }
+
+    constexpr Tp operator*() const { return *m_ptr; }
     constexpr operator Ptr() { return m_ptr; }
     constexpr operator Ptr() const { return m_ptr; }
     constexpr operator ConstPtr() const { return m_ptr; }
@@ -90,8 +104,12 @@ struct GjsAutoPointer {
         auto ffunc = free_func;
         Ptr old_ptr = m_ptr;
         m_ptr = ptr;
-        if (old_ptr && ffunc)
-            ffunc(old_ptr);
+        if (old_ptr && ffunc) {
+            if constexpr (std::is_array_v<T>)
+                ffunc(reinterpret_cast<T*>(old_ptr));
+            else
+                ffunc(old_ptr);
+        }
     }
 
     constexpr void swap(GjsAutoPointer& other) {
@@ -102,7 +120,9 @@ struct GjsAutoPointer {
         reset();
     }
 
-    [[nodiscard]] constexpr Ptr copy() const {
+    template <typename U = T>
+    [[nodiscard]] constexpr std::enable_if_t<!std::is_array_v<U>, Ptr> copy()
+        const {
         // FIXME: Should use std::enable_if_t<ref_func != nullptr, Ptr>
         if (!m_ptr)
             return nullptr;
@@ -136,6 +156,17 @@ using GjsAutoStrv = GjsAutoPointer<char*, char*, g_strfreev>;
 template <typename T>
 using GjsAutoUnref = GjsAutoPointer<T, void, g_object_unref, g_object_ref>;
 
+template <typename V, typename T>
+constexpr void GjsAutoPointerDeleter(T v) {
+    if constexpr (std::is_array_v<V>)
+        delete[] v;
+    else
+        delete v;
+}
+
+template <typename T>
+using GjsAutoCppPointer = GjsAutoPointer<T, T, GjsAutoPointerDeleter<T>>;
+
 template <typename T = GTypeClass>
 struct GjsAutoTypeClass : GjsAutoPointer<T, void, &g_type_class_unref> {
     GjsAutoTypeClass(gpointer ptr = nullptr)  // NOLINT(runtime/explicit)
diff --git a/test/gjs-test-jsapi-utils.cpp b/test/gjs-test-jsapi-utils.cpp
index 8d8f51f1..3ba49a15 100644
--- a/test/gjs-test-jsapi-utils.cpp
+++ b/test/gjs-test-jsapi-utils.cpp
@@ -92,6 +92,58 @@ static void test_gjs_autopointer_dtor() {
     g_object_unref(ptr);
 }
 
+static void test_gjs_autopointer_dtor_cpp() {
+    bool deleted = false;
+    auto dtor_callback = [&deleted] { deleted = true; };
+
+    struct TestStruct {
+        explicit TestStruct(decltype(dtor_callback) cb) : _delete_cb(cb) {}
+        ~TestStruct() { _delete_cb(); }
+
+        decltype(dtor_callback) _delete_cb;
+    };
+
+    g_assert_false(deleted);
+
+    {
+        auto* ptr = new TestStruct(dtor_callback);
+        GjsAutoCppPointer<TestStruct> autoptr(ptr);
+        g_assert(ptr == autoptr);
+    }
+
+    g_assert_true(deleted);
+}
+
+static void test_gjs_autopointer_dtor_cpp_array() {
+    unsigned deleted = 0;
+    auto dtor_callback = [&deleted] { deleted++; };
+
+    struct TestStruct {
+        TestStruct(decltype(dtor_callback) cb)  // NOLINT(runtime/explicit)
+            : _delete_cb(cb) {}
+        ~TestStruct() { _delete_cb(); }
+
+        int val = 5;
+        decltype(dtor_callback) _delete_cb;
+    };
+
+    g_assert_cmpint(deleted, ==, 0);
+
+    {
+        // using GjsAutoCppPointer1 = GjsAutoPointer<TestStruct[], TestStruct[],
+        // GjsAutoPointerDeleter<TestStruct[]>>;
+
+        TestStruct* ptrs =
+            new TestStruct[3]{dtor_callback, dtor_callback, dtor_callback};
+        GjsAutoCppPointer<TestStruct[]> autoptr(ptrs);
+        g_assert_cmpint(autoptr[0].val, ==, 5);
+        g_assert_cmpint(autoptr[1].val, ==, 5);
+        g_assert_cmpint(autoptr[2].val, ==, 5);
+    }
+
+    g_assert_cmpuint(deleted, ==, 3);
+}
+
 static void test_gjs_autopointer_dtor_take_ownership() {
     auto* ptr = gjs_test_object_new();
     g_assert_nonnull(ptr);
@@ -406,7 +458,10 @@ void gjs_test_add_tests_for_jsapi_utils(void) {
     g_test_add_func(
         "/gjs/jsapi-utils/gjs-autopointer/destructor/take_ownership",
         test_gjs_autopointer_dtor_take_ownership);
-
+    g_test_add_func("/gjs/jsapi-utils/gjs-autopointer/destructor/c++",
+                    test_gjs_autopointer_dtor_cpp);
+    g_test_add_func("/gjs/jsapi-utils/gjs-autopointer/destructor/c++-array",
+                    test_gjs_autopointer_dtor_cpp_array);
     g_test_add_func("/gjs/jsapi-utils/gjs-autopointer/operator/assign",
                     test_gjs_autopointer_assign_operator);
     g_test_add_func(


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