LCOV - code coverage report
Current view: top level - gjs - auto.h (source / functions) Coverage Total Hit
Test: gjs- Code Coverage Lines: 100.0 % 83 83
Test Date: 2025-02-15 06:20:10 Functions: 93.2 % 453 422
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 75.0 % 8 6

             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>  // IWYU pragma: keep
      15                 :             : // (https://github.com/include-what-you-use/include-what-you-use/issues/636)
      16                 :             : 
      17                 :             : #include <glib-object.h>
      18                 :             : #include <glib.h>
      19                 :             : 
      20                 :             : // For some reason, this needs to be here because otherwise
      21                 :             : // AutoPointer<char*>::swap() fails to link.
      22                 :             : #include <js/GCPolicyAPI.h>  // IWYU pragma: keep
      23                 :             : #include <js/Utility.h>      // for UniqueChars
      24                 :             : 
      25                 :             : // Auto pointers. We don't use GLib's g_autofree and friends because they only
      26                 :             : // work on GCC and Clang, and we try to support MSVC where possible. But this is
      27                 :             : // C++, so we use C++ classes.
      28                 :             : 
      29                 :             : namespace Gjs {
      30                 :             : 
      31                 :             : // A sentinel object used to pick the AutoPointer constructor that adds a
      32                 :             : // reference: AutoFoo foo{pointer, TakeOwnership{}};
      33                 :             : struct TakeOwnership {};
      34                 :             : 
      35                 :             : template <typename F = void>
      36                 :             : using AutoPointerRefFunction = F* (*)(F*);
      37                 :             : 
      38                 :             : template <typename F = void>
      39                 :             : using AutoPointerFreeFunction = void (*)(F*);
      40                 :             : 
      41                 :             : template <typename T, typename F = void,
      42                 :             :           AutoPointerFreeFunction<F> free_func = free,
      43                 :             :           AutoPointerRefFunction<F> ref_func = nullptr>
      44                 :             : struct AutoPointer {
      45                 :             :     using Tp =
      46                 :             :         std::conditional_t<std::is_array_v<T>, std::remove_extent_t<T>, T>;
      47                 :             :     using Ptr = std::add_pointer_t<Tp>;
      48                 :             :     using ConstPtr = std::add_pointer_t<std::add_const_t<Tp>>;
      49                 :             :     using RvalueRef = std::add_lvalue_reference_t<Tp>;
      50                 :             : 
      51                 :             :  protected:
      52                 :             :     using BaseType = AutoPointer<T, F, free_func, ref_func>;
      53                 :             : 
      54                 :             :  private:
      55                 :             :     template <typename FunctionType, FunctionType function>
      56                 :             :     static constexpr bool has_function() {
      57                 :             :         using NullType = std::integral_constant<FunctionType, nullptr>;
      58                 :             :         using ActualType = std::integral_constant<FunctionType, function>;
      59                 :             : 
      60                 :             :         return !std::is_same_v<ActualType, NullType>;
      61                 :             :     }
      62                 :             : 
      63                 :             :  public:
      64                 :             :     static constexpr bool has_free_function() {
      65                 :             :         return has_function<AutoPointerFreeFunction<F>, free_func>();
      66                 :             :     }
      67                 :             : 
      68                 :             :     static constexpr bool has_ref_function() {
      69                 :             :         return has_function<AutoPointerRefFunction<F>, ref_func>();
      70                 :             :     }
      71                 :             : 
      72                 :     1380676 :     constexpr AutoPointer(Ptr ptr = nullptr)  // NOLINT(runtime/explicit)
      73                 :     1380676 :         : m_ptr(ptr) {}
      74                 :             :     template <typename U, typename = std::enable_if_t<std::is_same_v<U, Tp> &&
      75                 :             :                                                       std::is_array_v<T>>>
      76                 :             :     explicit constexpr AutoPointer(U ptr[]) : m_ptr(ptr) {}
      77                 :             : 
      78                 :       19910 :     constexpr AutoPointer(Ptr ptr, const TakeOwnership&) : AutoPointer(ptr) {
      79                 :       19910 :         m_ptr = copy();
      80                 :       19910 :     }
      81                 :          15 :     constexpr AutoPointer(ConstPtr ptr, const TakeOwnership& o)
      82                 :          15 :         : AutoPointer(const_cast<Ptr>(ptr), o) {}
      83                 :         272 :     constexpr AutoPointer(AutoPointer&& other) : AutoPointer() {
      84                 :         272 :         this->swap(other);
      85                 :         272 :     }
      86                 :        1492 :     constexpr AutoPointer(AutoPointer const& other) : AutoPointer() {
      87                 :        1492 :         *this = other;
      88                 :        1492 :     }
      89                 :             : 
      90                 :      293474 :     constexpr AutoPointer& operator=(Ptr ptr) {
      91                 :      293474 :         reset(ptr);
      92                 :      293474 :         return *this;
      93                 :             :     }
      94                 :             : 
      95                 :       32437 :     constexpr AutoPointer& operator=(AutoPointer&& other) {
      96                 :       32437 :         this->swap(other);
      97                 :       32437 :         return *this;
      98                 :             :     }
      99                 :             : 
     100                 :        1518 :     constexpr AutoPointer& operator=(AutoPointer const& other) {
     101                 :        1518 :         AutoPointer dup{other.get(), TakeOwnership{}};
     102                 :        1518 :         this->swap(dup);
     103                 :        3036 :         return *this;
     104                 :        1518 :     }
     105                 :             : 
     106                 :             :     template <typename U = T>
     107                 :       17217 :     constexpr std::enable_if_t<!std::is_array_v<U>, Ptr> operator->() {
     108                 :       17217 :         return m_ptr;
     109                 :             :     }
     110                 :             : 
     111                 :             :     template <typename U = T>
     112                 :          20 :     constexpr std::enable_if_t<!std::is_array_v<U>, ConstPtr> operator->()
     113                 :             :         const {
     114                 :          20 :         return m_ptr;
     115                 :             :     }
     116                 :             : 
     117                 :             :     template <typename U = T>
     118                 :      266561 :     constexpr std::enable_if_t<std::is_array_v<U>, RvalueRef> operator[](
     119                 :             :         int index) {
     120                 :      266561 :         return m_ptr[index];
     121                 :             :     }
     122                 :             : 
     123                 :             :     template <typename U = T>
     124                 :             :     constexpr std::enable_if_t<std::is_array_v<U>, std::add_const_t<RvalueRef>>
     125                 :      874844 :     operator[](int index) const {
     126                 :      874844 :         return m_ptr[index];
     127                 :             :     }
     128                 :             : 
     129                 :           1 :     constexpr Tp operator*() const { return *m_ptr; }
     130                 :     1204565 :     constexpr operator Ptr() { return m_ptr; }
     131                 :      451915 :     constexpr operator Ptr() const { return m_ptr; }
     132                 :             :     constexpr operator ConstPtr() const { return m_ptr; }
     133                 :      430302 :     constexpr operator bool() const { return m_ptr != nullptr; }
     134                 :             : 
     135                 :      829750 :     constexpr Ptr get() const { return m_ptr; }
     136                 :      413994 :     constexpr Ptr* out() { return &m_ptr; }
     137                 :             :     constexpr ConstPtr* out() const { return const_cast<ConstPtr*>(&m_ptr); }
     138                 :             : 
     139                 :      243529 :     constexpr Ptr release() {
     140                 :      243529 :         auto* ptr = m_ptr;
     141                 :      243529 :         m_ptr = nullptr;
     142                 :      243529 :         return ptr;
     143                 :             :     }
     144                 :             : 
     145                 :     2028661 :     constexpr void reset(Ptr ptr = nullptr) {
     146                 :     2028661 :         Ptr old_ptr = m_ptr;
     147                 :     2028661 :         m_ptr = ptr;
     148                 :             : 
     149                 :             :         if constexpr (has_free_function()) {
     150         [ +  + ]:     1987959 :             if (old_ptr)
     151                 :             :                 free_func(reinterpret_cast<F*>(old_ptr));
     152                 :             :         }
     153                 :     2028661 :     }
     154                 :             : 
     155                 :       34230 :     constexpr void swap(AutoPointer& other) {
     156                 :       34230 :         std::swap(this->m_ptr, other.m_ptr);
     157                 :       34230 :     }
     158                 :             : 
     159                 :     1701888 :     /* constexpr */ ~AutoPointer() {  // one day, with -std=c++2a
     160                 :     1701888 :         reset();
     161                 :     1701888 :     }
     162                 :             : 
     163                 :             :     template <typename U = T>
     164                 :             :     [[nodiscard]]
     165                 :       19932 :     constexpr std::enable_if_t<!std::is_array_v<U>, Ptr> copy() const {
     166                 :             :         static_assert(has_ref_function(), "No ref function provided");
     167         [ +  + ]:       19932 :         return m_ptr ? reinterpret_cast<Ptr>(
     168                 :       19731 :                            ref_func(reinterpret_cast<F*>(m_ptr)))
     169                 :       19932 :                      : nullptr;
     170                 :             :     }
     171                 :             : 
     172                 :             :     template <typename C>
     173                 :             :     [[nodiscard]]
     174                 :       96790 :     constexpr C* as() const {
     175                 :       96790 :         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                 :          70 : using AutoFree = AutoPointer<T>;
     191                 :             : 
     192                 :             : struct AutoCharFuncs {
     193                 :         570 :     static char* dup(char* str) { return g_strdup(str); }
     194                 :      127236 :     static void free(char* str) { g_free(str); }
     195                 :             : };
     196                 :             : using AutoChar =
     197                 :      127236 :     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                 :        5213 : [[nodiscard]] inline AutoChar js_chars_to_glib(JS::UniqueChars&& js_chars) {
     205                 :        5213 :     return {js_chars.release()};
     206                 :             : }
     207                 :             : 
     208                 :       79423 : using AutoStrv = AutoPointer<char*, char*, g_strfreev, g_strdupv>;
     209                 :             : 
     210                 :             : template <typename T>
     211                 :       45534 : using AutoUnref = AutoPointer<T, void, g_object_unref, g_object_ref>;
     212                 :             : 
     213                 :             : using AutoGVariant =
     214                 :             :     AutoPointer<GVariant, GVariant, g_variant_unref, g_variant_ref>;
     215                 :             : 
     216                 :             : using AutoParam =
     217                 :         425 :     AutoPointer<GParamSpec, GParamSpec, g_param_spec_unref, g_param_spec_ref>;
     218                 :             : 
     219                 :             : using AutoGClosure =
     220                 :         287 :     AutoPointer<GClosure, GClosure, g_closure_unref, g_closure_ref>;
     221                 :             : 
     222                 :             : template <typename V, typename T>
     223                 :      267445 : constexpr void AutoPointerDeleter(T v) {
     224                 :             :     if constexpr (std::is_array_v<V>)
     225         [ +  - ]:      278932 :         delete[] reinterpret_cast<std::remove_extent_t<V>*>(v);
     226                 :             :     else
     227         [ +  - ]:       35407 :         delete v;
     228                 :      267445 : }
     229                 :             : 
     230                 :             : template <typename T>
     231                 :      267445 : using AutoCppPointer = AutoPointer<T, T, AutoPointerDeleter<T>>;
     232                 :             : 
     233                 :             : template <typename T = GTypeClass>
     234                 :        1755 : struct AutoTypeClass : AutoPointer<T, void, &g_type_class_unref> {
     235                 :        1755 :     AutoTypeClass(gpointer ptr = nullptr)  // NOLINT(runtime/explicit)
     236                 :        1755 :         : AutoPointer<T, void, g_type_class_unref>(static_cast<T*>(ptr)) {}
     237                 :        1755 :     explicit AutoTypeClass(GType gtype)
     238                 :        1755 :         : AutoTypeClass(g_type_class_ref(gtype)) {}
     239                 :             : };
     240                 :             : 
     241                 :             : template <typename T>
     242                 :             : struct SmartPointer : AutoPointer<T> {
     243                 :             :     using AutoPointer<T>::AutoPointer;
     244                 :             : };
     245                 :             : 
     246                 :             : template <>
     247                 :             : struct SmartPointer<char*> : AutoStrv {
     248                 :             :     using AutoStrv::AutoPointer;
     249                 :             : };
     250                 :             : 
     251                 :             : template <>
     252                 :             : struct SmartPointer<GStrv> : AutoStrv {
     253                 :             :     using AutoStrv::AutoPointer;
     254                 :             : };
     255                 :             : 
     256                 :             : template <>
     257                 :             : struct SmartPointer<GObject> : AutoUnref<GObject> {
     258                 :             :     using AutoUnref<GObject>::AutoPointer;
     259                 :             : };
     260                 :             : 
     261                 :             : template <>
     262                 :             : struct SmartPointer<GVariant> : AutoGVariant {
     263                 :             :     using AutoGVariant::AutoPointer;
     264                 :             : };
     265                 :             : 
     266                 :             : template <>
     267                 :          79 : struct SmartPointer<GList> : AutoPointer<GList, GList, g_list_free> {
     268                 :             :     using AutoPointer::AutoPointer;
     269                 :             : };
     270                 :             : 
     271                 :             : template <>
     272                 :          39 : struct SmartPointer<GSList> : AutoPointer<GSList, GSList, g_slist_free> {
     273                 :             :     using AutoPointer::AutoPointer;
     274                 :             : };
     275                 :             : 
     276                 :             : }  // namespace Gjs
        

Generated by: LCOV version 2.0-1