[vlc-devel] [PATCH v3] include: add C++ wrapper for C shared resources

Romain Vimont rom1v at videolabs.io
Wed Sep 12 10:59:35 CEST 2018


Add a helper to create RAII wrappers for C shared resources, which
automatically call the Hold() and Release() functions associated to the
raw pointer.

Just declare a new shared resource wrapper type:

    using InputItemPtr = vlc_shared_data_ptr_type(input_item_t,
                                                  input_item_Hold,
                                                  input_item_Release);

Then use this new type directly:

    input_item_t *ptr = /* ... */;
    InputItemPtr item(ptr);
    QString name = item->psz_name;
    InputItemPtr other = item; /* hold automatically */
---
Changes from v2:
 - fix constness: smart pointers must provide const access to their non-const
   data

 include/vlc_cxx_helpers.hpp | 107 ++++++++++++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)

diff --git a/include/vlc_cxx_helpers.hpp b/include/vlc_cxx_helpers.hpp
index 832a964e53..5d76c3c841 100644
--- a/include/vlc_cxx_helpers.hpp
+++ b/include/vlc_cxx_helpers.hpp
@@ -122,6 +122,113 @@ inline std::unique_ptr<T[], void (*)(void*)> wrap_carray( T* ptr ) noexcept
 
 } // anonymous namespace
 
+///
+/// Wraps a C shared resource having associated Hold() and Release() functions
+//
+/// This is a RAII wrapper for C shared resources (which are manually managed by
+/// calling explicitly their Hold() and Release() functions).
+///
+/// The Hold() and Release() functions must accept exactly one parameter having
+/// type T* (the raw pointer type). Their return type is irrelevant.
+///
+/// To create a new shared resource wrapper type for my_type_t, simply declare:
+///
+///     using MyTypePtr =
+///         vlc_shared_data_ptr_type(my_type_t, my_type_Hold, my_type_Release);
+///
+/// Then use it to wrap a raw C pointer:
+///
+///     my_type_t *raw_ptr = /* ... */;
+///     MyTypePtr ptr(raw_ptr);
+
+// In C++17, the template declaration could be replaced by:
+//     template<typename T, auto HOLD, auto RELEASE>
+template <typename T, typename H, typename R, H HOLD, R RELEASE>
+class vlc_shared_data_ptr {
+    T *ptr;
+
+public:
+    explicit vlc_shared_data_ptr(T *ptr = nullptr)
+        : ptr(ptr)
+    {
+        if (ptr)
+            HOLD(ptr);
+    }
+
+    vlc_shared_data_ptr(const vlc_shared_data_ptr &other)
+        : vlc_shared_data_ptr(other.ptr) {}
+
+    vlc_shared_data_ptr(vlc_shared_data_ptr &&other) noexcept
+        : ptr(other.ptr)
+    {
+        other.ptr = nullptr;
+    }
+
+    ~vlc_shared_data_ptr()
+    {
+        if (ptr)
+            RELEASE(ptr);
+    }
+
+    vlc_shared_data_ptr &operator=(const vlc_shared_data_ptr &other)
+    {
+        reset(other.ptr);
+        return *this;
+    }
+
+    vlc_shared_data_ptr &operator=(vlc_shared_data_ptr &&other) noexcept
+    {
+        ptr = other.ptr;
+        other.ptr = nullptr;
+        return *this;
+    }
+
+    bool operator==(const vlc_shared_data_ptr &other) const
+    {
+        return ptr == other.ptr;
+    }
+
+    bool operator!=(const vlc_shared_data_ptr &other) const
+    {
+        return !(*this == other);
+    }
+
+    operator bool() const
+    {
+        return ptr;
+    }
+
+    T &operator*() const
+    {
+        return *ptr;
+    }
+
+    T *operator->() const
+    {
+        return ptr;
+    }
+
+    T *get() const
+    {
+        return ptr;
+    }
+
+    void reset(T *newptr)
+    {
+        if (newptr)
+            /* hold before in case ptr == newptr */
+            HOLD(newptr);
+        if (ptr)
+            RELEASE(ptr);
+        ptr = newptr;
+    }
+};
+
+// useful due to the unnecessarily complex template declaration before C++17
+#define vlc_shared_data_ptr_type(type, hold, release) \
+    vlc_shared_data_ptr<type, decltype(&hold), decltype(&release), \
+                        &hold, &release>
+
 #ifdef VLC_THREADS_H_
 
 namespace threads
-- 
2.19.0.rc2



More information about the vlc-devel mailing list