LCOV - code coverage report
Current view: top level - gi - arg-inl.h (source / functions) Coverage Total Hit
Test: gjs- Code Coverage Lines: 80.5 % 82 66
Test Date: 2024-11-09 06:56:44 Functions: 82.9 % 187 155
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 68.4 % 19 13

             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: 2020 Marco Trevisan <marco.trevisan@canonical.com>
       4                 :             : 
       5                 :             : #pragma once
       6                 :             : 
       7                 :             : #include <config.h>
       8                 :             : 
       9                 :             : #include <stdint.h>
      10                 :             : 
      11                 :             : #include <cstddef>  // for nullptr_t
      12                 :             : #include <limits>
      13                 :             : #include <string>  // for to_string
      14                 :             : #include <type_traits>
      15                 :             : 
      16                 :             : #include <girepository.h>
      17                 :             : #include <glib-object.h>  // for GType
      18                 :             : #include <glib.h>         // for gboolean
      19                 :             : #include <js/TypeDecls.h>  // for HandleValue
      20                 :             : 
      21                 :             : #include "gi/js-value-inl.h"
      22                 :             : #include "gi/utils-inl.h"
      23                 :             : #include "gjs/macros.h"
      24                 :             : 
      25                 :             : // GIArgument accessor templates
      26                 :             : //
      27                 :             : // These are intended to make access to the GIArgument union more type-safe and
      28                 :             : // reduce bugs that occur from assigning to one member and reading from another.
      29                 :             : // (These bugs often work fine on one processor architecture but crash on
      30                 :             : // another.)
      31                 :             : //
      32                 :             : // gjs_arg_member<T>(GIArgument*) - returns a reference to the appropriate union
      33                 :             : //   member that would hold the type T. Rarely used, unless as a pointer to a
      34                 :             : //   return location.
      35                 :             : // gjs_arg_get<T>(GIArgument*) - returns the value of type T from the
      36                 :             : //   appropriate union member.
      37                 :             : // gjs_arg_set(GIArgument*, T) - sets the appropriate union member for type T.
      38                 :             : // gjs_arg_unset<T>(GIArgument*) - sets the appropriate zero value in the
      39                 :             : //   appropriate union member for type T.
      40                 :             : // gjs_arg_steal<T>(GIArgument*) - sets the appropriate zero value in the
      41                 :             : //   appropriate union member for type T and returns the replaced value.
      42                 :             : 
      43                 :             : template <auto GIArgument::*member>
      44                 :      271108 : [[nodiscard]] constexpr inline decltype(auto) gjs_arg_member(GIArgument* arg) {
      45                 :      271108 :     return (arg->*member);
      46                 :             : }
      47                 :             : 
      48                 :             : /* The tag is needed to disambiguate types such as gboolean and GType
      49                 :             :  * which are in fact typedef's of other generic types.
      50                 :             :  * Setting a tag for a type allows to perform proper specialization. */
      51                 :             : template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
      52                 :      271108 : [[nodiscard]] constexpr inline decltype(auto) gjs_arg_member(GIArgument* arg) {
      53                 :             :     if constexpr (TAG == GI_TYPE_TAG_VOID) {
      54                 :             :         if constexpr (std::is_same_v<T, bool>)
      55                 :         441 :             return gjs_arg_member<&GIArgument::v_boolean>(arg);
      56                 :             :         if constexpr (std::is_same_v<T, int8_t>)
      57                 :          42 :             return gjs_arg_member<&GIArgument::v_int8>(arg);
      58                 :             :         if constexpr (std::is_same_v<T, uint8_t>)
      59                 :          47 :             return gjs_arg_member<&GIArgument::v_uint8>(arg);
      60                 :             :         if constexpr (std::is_same_v<T, int16_t>)
      61                 :          36 :             return gjs_arg_member<&GIArgument::v_int16>(arg);
      62                 :             :         if constexpr (std::is_same_v<T, uint16_t>)
      63                 :          16 :             return gjs_arg_member<&GIArgument::v_uint16>(arg);
      64                 :             :         if constexpr (std::is_same_v<T, int32_t>)
      65                 :       15642 :             return gjs_arg_member<&GIArgument::v_int32>(arg);
      66                 :             :         if constexpr (std::is_same_v<T, uint32_t>)
      67                 :       26531 :             return gjs_arg_member<&GIArgument::v_uint32>(arg);
      68                 :             :         if constexpr (std::is_same_v<T, int64_t>)
      69                 :         304 :             return gjs_arg_member<&GIArgument::v_int64>(arg);
      70                 :             :         if constexpr (std::is_same_v<T, uint64_t>)
      71                 :        3518 :             return gjs_arg_member<&GIArgument::v_uint64>(arg);
      72                 :             : 
      73                 :             :         // gunichar is stored in v_uint32
      74                 :             :         if constexpr (std::is_same_v<T, char32_t>)
      75                 :           2 :             return gjs_arg_member<&GIArgument::v_uint32>(arg);
      76                 :             : 
      77                 :             :         if constexpr (std::is_same_v<T, float>)
      78                 :          48 :             return gjs_arg_member<&GIArgument::v_float>(arg);
      79                 :             : 
      80                 :             :         if constexpr (std::is_same_v<T, double>)
      81                 :          38 :             return gjs_arg_member<&GIArgument::v_double>(arg);
      82                 :             : 
      83                 :             :         if constexpr (std::is_same_v<T, char*>)
      84                 :        5302 :             return gjs_arg_member<&GIArgument::v_string>(arg);
      85                 :             : 
      86                 :             :         if constexpr (std::is_same_v<T, void*>)
      87                 :      190656 :             return gjs_arg_member<&GIArgument::v_pointer>(arg);
      88                 :             : 
      89                 :             :         if constexpr (std::is_same_v<T, std::nullptr_t>)
      90                 :           0 :             return gjs_arg_member<&GIArgument::v_pointer>(arg);
      91                 :             : 
      92                 :             :         if constexpr (std::is_pointer<T>()) {
      93                 :             :             using NonconstPtrT = std::add_pointer_t<
      94                 :             :                 std::remove_const_t<std::remove_pointer_t<T>>>;
      95                 :             :             return reinterpret_cast<NonconstPtrT&>(
      96                 :       20318 :                 gjs_arg_member<&GIArgument::v_pointer>(arg));
      97                 :             :         }
      98                 :             :     }
      99                 :             : 
     100                 :             :     if constexpr (TAG == GI_TYPE_TAG_BOOLEAN && std::is_same_v<T, gboolean>)
     101                 :        1205 :         return gjs_arg_member<&GIArgument::v_boolean>(arg);
     102                 :             : 
     103                 :             :     if constexpr (TAG == GI_TYPE_TAG_GTYPE && std::is_same_v<T, GType>) {
     104                 :             :         // GType is defined differently on 32-bit vs. 64-bit architectures.
     105                 :             :         if constexpr (std::is_same_v<GType, gsize>)
     106                 :        1482 :             return gjs_arg_member<&GIArgument::v_size>(arg);
     107                 :             :         else if constexpr (std::is_same_v<GType, gulong>)
     108                 :             :             return gjs_arg_member<&GIArgument::v_ulong>(arg);
     109                 :             :     }
     110                 :             : 
     111                 :             :     if constexpr (TAG == GI_TYPE_TAG_INTERFACE && std::is_integral_v<T>) {
     112                 :             :         if constexpr (std::is_signed_v<T>)
     113                 :        5478 :             return gjs_arg_member<&GIArgument::v_int>(arg);
     114                 :             :         else
     115                 :           2 :             return gjs_arg_member<&GIArgument::v_uint>(arg);
     116                 :             :     }
     117                 :             : }
     118                 :             : 
     119                 :             : typedef enum {
     120                 :             :     GJS_TYPE_TAG_LONG = 0,
     121                 :             : } ExtraTag;
     122                 :             : 
     123                 :             : template <typename T, ExtraTag TAG>
     124                 :           0 : [[nodiscard]] constexpr inline decltype(auto) gjs_arg_member(GIArgument* arg) {
     125                 :             :     if constexpr (TAG == GJS_TYPE_TAG_LONG &&
     126                 :             :                   std::is_same_v<T, long>)  // NOLINT(runtime/int)
     127                 :           0 :         return gjs_arg_member<&GIArgument::v_long>(arg);
     128                 :             :     else if constexpr (TAG == GJS_TYPE_TAG_LONG &&
     129                 :             :                        std::is_same_v<T, unsigned long>)  // NOLINT(runtime/int)
     130                 :           0 :         return gjs_arg_member<&GIArgument::v_ulong>(arg);
     131                 :             : }
     132                 :             : 
     133                 :             : template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
     134                 :       87930 : constexpr inline void gjs_arg_set(GIArgument* arg, T v) {
     135                 :             :     if constexpr (std::is_pointer_v<T>) {
     136                 :             :         using NonconstPtrT =
     137                 :             :             std::add_pointer_t<std::remove_const_t<std::remove_pointer_t<T>>>;
     138                 :       76010 :         gjs_arg_member<NonconstPtrT, TAG>(arg) = const_cast<NonconstPtrT>(v);
     139                 :             :     } else {
     140                 :             :         if constexpr (std::is_same_v<T, bool> || (std::is_same_v<T, gboolean> &&
     141                 :             :                                                   TAG == GI_TYPE_TAG_BOOLEAN))
     142                 :         399 :             v = !!v;
     143                 :             : 
     144                 :       11920 :         gjs_arg_member<T, TAG>(arg) = v;
     145                 :             :     }
     146                 :       87930 : }
     147                 :             : 
     148                 :             : template <typename T, ExtraTag TAG>
     149                 :           0 : constexpr inline void gjs_arg_set(GIArgument* arg, T v) {
     150                 :           0 :     gjs_arg_member<T, TAG>(arg) = v;
     151                 :           0 : }
     152                 :             : 
     153                 :             : // Store function pointers as void*. It is a requirement of GLib that your
     154                 :             : // compiler can do this
     155                 :             : template <typename ReturnT, typename... Args>
     156                 :          88 : constexpr inline void gjs_arg_set(GIArgument* arg, ReturnT (*v)(Args...)) {
     157                 :          88 :     gjs_arg_member<void*>(arg) = reinterpret_cast<void*>(v);
     158                 :          88 : }
     159                 :             : 
     160                 :             : template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
     161                 :             : constexpr inline std::enable_if_t<std::is_integral_v<T>> gjs_arg_set(
     162                 :             :     GIArgument* arg, void* v) {
     163                 :             :     gjs_arg_set<T, TAG>(arg, gjs_pointer_to_int<T>(v));
     164                 :             : }
     165                 :             : 
     166                 :             : template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
     167                 :      141967 : [[nodiscard]] constexpr inline T gjs_arg_get(GIArgument* arg) {
     168                 :             :     if constexpr (std::is_same_v<T, bool> ||
     169                 :             :                   (std::is_same_v<T, gboolean> && TAG == GI_TYPE_TAG_BOOLEAN))
     170                 :         221 :         return T(!!gjs_arg_member<T, TAG>(arg));
     171                 :             : 
     172                 :      141746 :     return gjs_arg_member<T, TAG>(arg);
     173                 :             : }
     174                 :             : 
     175                 :             : template <typename T, ExtraTag TAG>
     176                 :             : [[nodiscard]] constexpr inline T gjs_arg_get(GIArgument* arg) {
     177                 :             :     return gjs_arg_member<T, TAG>(arg);
     178                 :             : }
     179                 :             : 
     180                 :             : template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
     181                 :             : [[nodiscard]] constexpr inline void* gjs_arg_get_as_pointer(GIArgument* arg) {
     182                 :             :     return gjs_int_to_pointer(gjs_arg_get<T, TAG>(arg));
     183                 :             : }
     184                 :             : 
     185                 :             : template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
     186                 :       20740 : constexpr inline void gjs_arg_unset(GIArgument* arg) {
     187                 :             :     if constexpr (std::is_pointer_v<T>)
     188                 :       20492 :         gjs_arg_set<T, TAG>(arg, nullptr);
     189                 :             :     else
     190                 :         248 :         gjs_arg_set<T, TAG>(arg, static_cast<T>(0));
     191                 :       20740 : }
     192                 :             : 
     193                 :             : template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
     194                 :       10732 : [[nodiscard]] constexpr inline T gjs_arg_steal(GIArgument* arg) {
     195                 :       10732 :     auto val = gjs_arg_get<T, TAG>(arg);
     196                 :       10732 :     gjs_arg_unset<T, TAG>(arg);
     197                 :       10732 :     return val;
     198                 :             : }
     199                 :             : 
     200                 :             : // Implementation to store rounded (u)int64_t numbers into double
     201                 :             : 
     202                 :             : template <typename BigT>
     203                 :             : [[nodiscard]] inline constexpr std::enable_if_t<
     204                 :             :     std::is_integral_v<BigT> && (std::numeric_limits<BigT>::max() >
     205                 :             :                                  std::numeric_limits<int32_t>::max()),
     206                 :             :     double>
     207                 :          34 : gjs_arg_get_maybe_rounded(GIArgument* arg) {
     208                 :          34 :     BigT val = gjs_arg_get<BigT>(arg);
     209                 :             : 
     210   [ +  +  +  +  :          66 :     if (val < Gjs::min_safe_big_number<BigT>() ||
                   +  + ]
     211                 :          32 :         val > Gjs::max_safe_big_number<BigT>()) {
     212                 :           7 :         g_warning(
     213                 :             :             "Value %s cannot be safely stored in a JS Number "
     214                 :             :             "and may be rounded",
     215                 :             :             std::to_string(val).c_str());
     216                 :             :     }
     217                 :             : 
     218                 :          34 :     return static_cast<double>(val);
     219                 :             : }
     220                 :             : 
     221                 :             : template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
     222                 :       19749 : GJS_JSAPI_RETURN_CONVENTION inline bool gjs_arg_set_from_js_value(
     223                 :             :     JSContext* cx, const JS::HandleValue& value, GIArgument* arg,
     224                 :             :     bool* out_of_range) {
     225                 :             :     if constexpr (Gjs::type_has_js_getter<T>())
     226                 :        9338 :         return Gjs::js_value_to_c<TAG>(cx, value, &gjs_arg_member<T, TAG>(arg));
     227                 :             : 
     228                 :       10411 :     Gjs::JsValueHolder::Relaxed<T> val{};
     229                 :             : 
     230         [ -  + ]:       10411 :     if (!Gjs::js_value_to_c_checked<T, TAG>(cx, value, &val, out_of_range))
     231                 :           0 :         return false;
     232                 :             : 
     233         [ -  + ]:       10411 :     if (*out_of_range)
     234                 :           0 :         return false;
     235                 :             : 
     236                 :       10411 :     gjs_arg_set<T, TAG>(arg, val);
     237                 :             : 
     238                 :       10411 :     return true;
     239                 :             : }
     240                 :             : 
     241                 :             : // A helper function to retrieve array lengths from a GIArgument (letting the
     242                 :             : // compiler generate good instructions in case of big endian machines)
     243                 :         353 : [[nodiscard]] constexpr size_t gjs_gi_argument_get_array_length(
     244                 :             :     GITypeTag tag, GIArgument* arg) {
     245   [ -  +  -  -  :         353 :     switch (tag) {
             +  +  +  +  
                      - ]
     246                 :           0 :         case GI_TYPE_TAG_INT8:
     247                 :           0 :             return gjs_arg_get<int8_t>(arg);
     248                 :           1 :         case GI_TYPE_TAG_UINT8:
     249                 :           1 :             return gjs_arg_get<uint8_t>(arg);
     250                 :           0 :         case GI_TYPE_TAG_INT16:
     251                 :           0 :             return gjs_arg_get<int16_t>(arg);
     252                 :           0 :         case GI_TYPE_TAG_UINT16:
     253                 :           0 :             return gjs_arg_get<uint16_t>(arg);
     254                 :          88 :         case GI_TYPE_TAG_INT32:
     255                 :          88 :             return gjs_arg_get<int32_t>(arg);
     256                 :           5 :         case GI_TYPE_TAG_UINT32:
     257                 :           5 :             return gjs_arg_get<uint32_t>(arg);
     258                 :          17 :         case GI_TYPE_TAG_INT64:
     259                 :          17 :             return gjs_arg_get<int64_t>(arg);
     260                 :         242 :         case GI_TYPE_TAG_UINT64:
     261                 :         242 :             return gjs_arg_get<uint64_t>(arg);
     262                 :           0 :         default:
     263                 :             :             g_assert_not_reached();
     264                 :             :     }
     265                 :             : }
        

Generated by: LCOV version 2.0-1