LCOV - code coverage report
Current view: top level - gjs - auto.h (source / functions) Coverage Total Hit
Test: gjs-1.88.0 Code Coverage Lines: 100.0 % 83 83
Test Date: 2026-06-07 00:56:06 Functions: 93.4 % 441 412
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 70.0 % 10 7

             Branch data     Line data    Source code
       1                 :             : /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
       2                 :             : // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
       3                 :             : // SPDX-FileCopyrightText: 2017 Chun-wei Fan <fanchunwei@src.gnome.org>
       4                 :             : // SPDX-FileCopyrightText: 2018-2020  Canonical, Ltd
       5                 :             : // SPDX-FileCopyrightText: 2018, 2024 Philip Chimento <philip.chimento@gmail.com>
       6                 :             : 
       7                 :             : #pragma once
       8                 :             : 
       9                 :             : #include <config.h>
      10                 :             : 
      11                 :             : #include <stdlib.h>
      12                 :             : 
      13                 :             : #include <type_traits>
      14                 :             : #include <utility>
      15                 :             : 
      16                 :             : #include <glib-object.h>
      17                 :             : #include <glib.h>
      18                 :             : // IWYU pragma: no_forward_declare _GVariant
      19                 :             : 
      20                 :             : #include <js/Utility.h>  // for UniqueChars
      21                 :             : 
      22                 :             : // Auto pointers. We don't use GLib's g_autofree and friends because they only
      23                 :             : // work on GCC and Clang, and we try to support MSVC where possible. But this is
      24                 :             : // C++, so we use C++ classes.
      25                 :             : 
      26                 :             : namespace Gjs {
      27                 :             : 
      28                 :             : // A sentinel object used to pick the AutoPointer constructor that adds a
      29                 :             : // reference: AutoFoo foo{pointer, TakeOwnership{}};
      30                 :             : struct TakeOwnership {};
      31                 :             : 
      32                 :             : template <typename F = void>
      33                 :             : using AutoPointerRefFunction = F* (*)(F*);
      34                 :             : 
      35                 :             : template <typename F = void>
      36                 :             : using AutoPointerFreeFunction = void (*)(F*);
      37                 :             : 
      38                 :             : template <typename T, typename F = void,
      39                 :             :           AutoPointerFreeFunction<F> free_func = free,
      40                 :             :           AutoPointerRefFunction<F> ref_func = nullptr>
      41                 :             : struct AutoPointer {
      42                 :             :     using Tp =
      43                 :             :         std::conditional_t<std::is_array_v<T>, std::remove_extent_t<T>, T>;
      44                 :             :     using Ptr = std::add_pointer_t<Tp>;
      45                 :             :     using ConstPtr = std::add_pointer_t<std::add_const_t<Tp>>;
      46                 :             :     using RvalueRef = std::add_lvalue_reference_t<Tp>;
      47                 :             : 
      48                 :             :  protected:
      49                 :             :     using BaseType = AutoPointer<T, F, free_func, ref_func>;
      50                 :             : 
      51                 :             :  private:
      52                 :             :     template <typename FunctionType, FunctionType function>
      53                 :             :     static constexpr bool has_function() {
      54                 :             :         using NullType = std::integral_constant<FunctionType, nullptr>;
      55                 :             :         using ActualType = std::integral_constant<FunctionType, function>;
      56                 :             : 
      57                 :             :         return !std::is_same_v<ActualType, NullType>;
      58                 :             :     }
      59                 :             : 
      60                 :             :  public:
      61                 :             :     static constexpr bool has_free_function() {
      62                 :             :         return has_function<AutoPointerFreeFunction<F>, free_func>();
      63                 :             :     }
      64                 :             : 
      65                 :             :     static constexpr bool has_ref_function() {
      66                 :             :         return has_function<AutoPointerRefFunction<F>, ref_func>();
      67                 :             :     }
      68                 :             : 
      69                 :     1227437 :     constexpr AutoPointer(Ptr ptr = nullptr)  // NOLINT(runtime/explicit)
      70                 :     1227437 :         : m_ptr(ptr) {}
      71                 :             :     template <typename U, typename = std::enable_if_t<std::is_same_v<U, Tp> &&
      72                 :             :                                                       std::is_array_v<T>>>
      73                 :             :     explicit constexpr AutoPointer(U ptr[]) : m_ptr(ptr) {}
      74                 :             : 
      75                 :        3206 :     constexpr AutoPointer(Ptr ptr, const TakeOwnership&) : AutoPointer(ptr) {
      76                 :        3206 :         m_ptr = copy();
      77                 :        3206 :     }
      78                 :          15 :     constexpr AutoPointer(ConstPtr ptr, const TakeOwnership& o)
      79                 :          15 :         : AutoPointer(const_cast<Ptr>(ptr), o) {}
      80                 :         229 :     constexpr AutoPointer(AutoPointer&& other) : AutoPointer() {
      81                 :         229 :         this->swap(other);
      82                 :         229 :     }
      83                 :         235 :     constexpr AutoPointer(AutoPointer const& other) : AutoPointer() {
      84                 :         235 :         *this = other;
      85                 :         235 :     }
      86                 :             : 
      87                 :      321262 :     constexpr AutoPointer& operator=(Ptr ptr) {
      88                 :      321262 :         reset(ptr);
      89                 :      321262 :         return *this;
      90                 :             :     }
      91                 :             : 
      92                 :       24206 :     constexpr AutoPointer& operator=(AutoPointer&& other) {
      93                 :       24206 :         this->swap(other);
      94                 :       24206 :         return *this;
      95                 :             :     }
      96                 :             : 
      97                 :         261 :     constexpr AutoPointer& operator=(AutoPointer const& other) {
      98                 :         261 :         AutoPointer dup{other.get(), TakeOwnership{}};
      99                 :         261 :         this->swap(dup);
     100                 :         522 :         return *this;
     101                 :         261 :     }
     102                 :             : 
     103                 :             :     template <typename U = T>
     104                 :       20211 :     constexpr std::enable_if_t<!std::is_array_v<U>, Ptr> operator->() {
     105                 :       20211 :         return m_ptr;
     106                 :             :     }
     107                 :             : 
     108                 :             :     template <typename U = T>
     109                 :          25 :     constexpr std::enable_if_t<!std::is_array_v<U>, ConstPtr> operator->()
     110                 :             :         const {
     111                 :          25 :         return m_ptr;
     112                 :             :     }
     113                 :             : 
     114                 :             :     template <typename U = T>
     115                 :      287240 :     constexpr std::enable_if_t<std::is_array_v<U>, RvalueRef> operator[](
     116                 :             :         int index) {
     117                 :      287240 :         return m_ptr[index];
     118                 :             :     }
     119                 :             : 
     120                 :             :     template <typename U = T>
     121                 :             :     constexpr std::enable_if_t<std::is_array_v<U>, std::add_const_t<RvalueRef>>
     122                 :      951383 :     operator[](int index) const {
     123                 :      951383 :         return m_ptr[index];
     124                 :             :     }
     125                 :             : 
     126                 :           1 :     constexpr Tp operator*() const { return *m_ptr; }
     127                 :      725233 :     constexpr operator Ptr() { return m_ptr; }
     128                 :      101148 :     constexpr operator Ptr() const { return m_ptr; }
     129                 :             :     constexpr operator ConstPtr() const { return m_ptr; }
     130                 :      734533 :     constexpr operator bool() const { return m_ptr != nullptr; }
     131                 :             : 
     132                 :      885283 :     [[nodiscard]] constexpr Ptr get() const { return m_ptr; }
     133                 :      431877 :     [[nodiscard]] constexpr Ptr* out() { return &m_ptr; }
     134                 :             :     [[nodiscard]]
     135                 :             :     constexpr ConstPtr* out() const {
     136                 :             :         return const_cast<ConstPtr*>(&m_ptr);
     137                 :             :     }
     138                 :             : 
     139                 :      265108 :     constexpr Ptr release() {
     140                 :      265108 :         auto* ptr = m_ptr;
     141                 :      265108 :         m_ptr = nullptr;
     142                 :      265108 :         return ptr;
     143                 :             :     }
     144                 :             : 
     145                 :     1906112 :     constexpr void reset(Ptr ptr = nullptr) {
     146                 :     1906112 :         Ptr old_ptr = m_ptr;
     147                 :     1906112 :         m_ptr = ptr;
     148                 :             : 
     149                 :             :         if constexpr (has_free_function()) {
     150         [ +  + ]:     1862159 :             if (old_ptr)
     151                 :             :                 free_func(reinterpret_cast<F*>(old_ptr));
     152                 :             :         }
     153                 :     1906112 :     }
     154                 :             : 
     155                 :       24699 :     constexpr void swap(AutoPointer& other) {
     156                 :       24699 :         std::swap(this->m_ptr, other.m_ptr);
     157                 :       24699 :     }
     158                 :             : 
     159                 :     1560590 :     /* constexpr */ ~AutoPointer() {  // one day, with -std=c++2a
     160                 :     1560590 :         reset();
     161                 :     1560590 :     }
     162                 :             : 
     163                 :             :     template <typename U = T>
     164                 :             :     [[nodiscard]]
     165                 :        3230 :     constexpr std::enable_if_t<!std::is_array_v<U>, Ptr> copy() const {
     166                 :             :         static_assert(has_ref_function(), "No ref function provided");
     167         [ +  + ]:        3230 :         return m_ptr ? reinterpret_cast<Ptr>(
     168                 :        3226 :                            ref_func(reinterpret_cast<F*>(m_ptr)))
     169                 :           4 :                      : nullptr;
     170                 :             :     }
     171                 :             : 
     172                 :             :     template <typename C>
     173                 :             :     [[nodiscard]]
     174                 :        4174 :     constexpr C* as() const {
     175                 :        4174 :         return const_cast<C*>(reinterpret_cast<const C*>(m_ptr));
     176                 :             :     }
     177                 :             : 
     178                 :             :  private:
     179                 :             :     Ptr m_ptr;
     180                 :             : };
     181                 :             : 
     182                 :             : template <typename T, typename F, AutoPointerFreeFunction<F> free_func,
     183                 :             :           AutoPointerRefFunction<F> ref_func>
     184                 :           1 : constexpr bool operator==(AutoPointer<T, F, free_func, ref_func> const& lhs,
     185                 :             :                           AutoPointer<T, F, free_func, ref_func> const& rhs) {
     186                 :           1 :     return lhs.get() == rhs.get();
     187                 :             : }
     188                 :             : 
     189                 :             : template <typename T>
     190                 :         313 : using AutoFree = AutoPointer<T>;
     191                 :             : 
     192                 :             : struct AutoCharFuncs {
     193                 :         389 :     static char* dup(char* str) { return g_strdup(str); }
     194         [ -  + ]:      162679 :     static void free(char* str) { g_free(str); }
     195                 :             : };
     196                 :             : using AutoChar =
     197                 :      162679 :     AutoPointer<char, char, AutoCharFuncs::free, AutoCharFuncs::dup>;
     198                 :             : 
     199                 :             : // This moves a string owned by the JS runtime into the GLib domain. This is
     200                 :             : // only possible because currently, js_free() and g_free() both ultimately call
     201                 :             : // free(). It would cause crashes if SpiderMonkey were to stop supporting
     202                 :             : // embedders using the system allocator in the future. In that case, this
     203                 :             : // function would have to copy the string.
     204                 :             : [[nodiscard]]
     205                 :        5788 : inline AutoChar js_chars_to_glib(JS::UniqueChars&& js_chars) {
     206                 :        5788 :     return {js_chars.release()};
     207                 :             : }
     208                 :             : 
     209                 :       77593 : using AutoStrv = AutoPointer<char*, char*, g_strfreev, g_strdupv>;
     210                 :             : 
     211                 :             : template <typename T>
     212                 :       80339 : using AutoUnref = AutoPointer<T, void, g_object_unref, g_object_ref>;
     213                 :             : 
     214                 :             : using AutoGVariant =
     215                 :             :     AutoPointer<GVariant, GVariant, g_variant_unref, g_variant_ref>;
     216                 :             : 
     217                 :             : using AutoParam =
     218                 :         425 :     AutoPointer<GParamSpec, GParamSpec, g_param_spec_unref, g_param_spec_ref>;
     219                 :             : 
     220                 :             : using AutoGClosure =
     221                 :         293 :     AutoPointer<GClosure, GClosure, g_closure_unref, g_closure_ref>;
     222                 :             : 
     223                 :             : template <typename V, typename T>
     224                 :      294023 : constexpr void AutoPointerDeleter(T v) {
     225                 :             :     if constexpr (std::is_array_v<V>)
     226         [ +  - ]:      308003 :         delete[] reinterpret_cast<std::remove_extent_t<V>*>(v);
     227                 :             :     else
     228         [ +  - ]:       42193 :         delete v;
     229                 :      294023 : }
     230                 :             : 
     231                 :             : template <typename T>
     232                 :      294023 : using AutoCppPointer = AutoPointer<T, T, AutoPointerDeleter<T>>;
     233                 :             : 
     234                 :             : template <typename T = GTypeClass>
     235                 :        1095 : class AutoTypeClass : public AutoPointer<T, void, &g_type_class_unref> {
     236                 :        1095 :     explicit AutoTypeClass(void* ptr = nullptr)
     237                 :        1095 :         : AutoPointer<T, void, g_type_class_unref>(static_cast<T*>(ptr)) {}
     238                 :             : 
     239                 :             :  public:
     240                 :        1095 :     explicit AutoTypeClass(GType gtype)
     241                 :        1095 :         : AutoTypeClass(g_type_class_ref(gtype)) {}
     242                 :             : };
     243                 :             : 
     244                 :             : template <typename T>
     245                 :             : struct SmartPointer : AutoPointer<T> {
     246                 :             :     using AutoPointer<T>::AutoPointer;
     247                 :             : };
     248                 :             : 
     249                 :             : template <>
     250                 :             : struct SmartPointer<char*> : AutoStrv {
     251                 :             :     using AutoStrv::AutoPointer;
     252                 :             : };
     253                 :             : 
     254                 :             : template <>
     255                 :             : struct SmartPointer<GStrv> : AutoStrv {
     256                 :             :     using AutoStrv::AutoPointer;
     257                 :             : };
     258                 :             : 
     259                 :             : template <>
     260                 :             : struct SmartPointer<GObject> : AutoUnref<GObject> {
     261                 :             :     using AutoUnref<GObject>::AutoPointer;
     262                 :             : };
     263                 :             : 
     264                 :             : template <>
     265                 :             : struct SmartPointer<GVariant> : AutoGVariant {
     266                 :             :     using AutoGVariant::AutoPointer;
     267                 :             : };
     268                 :             : 
     269                 :             : template <>
     270                 :          82 : struct SmartPointer<GList> : AutoPointer<GList, GList, g_list_free> {
     271                 :             :     using AutoPointer::AutoPointer;
     272                 :             : };
     273                 :             : 
     274                 :             : template <>
     275                 :          46 : struct SmartPointer<GSList> : AutoPointer<GSList, GSList, g_slist_free> {
     276                 :             :     using AutoPointer::AutoPointer;
     277                 :             : };
     278                 :             : 
     279                 :             : }  // namespace Gjs
        

Generated by: LCOV version 2.0-1