[gjs] arg: Add function to handle big numbers warning on rounding



commit 25d5db5392bd1c80721d7edae4773cf96f85b9c0
Author: Marco Trevisan (TreviƱo) <mail 3v1n0 net>
Date:   Mon May 11 03:33:52 2020 +0200

    arg: Add function to handle big numbers warning on rounding

 gi/arg-inl.h | 40 ++++++++++++++++++++++++++++++++++++++++
 gi/arg.cpp   | 19 ++-----------------
 2 files changed, 42 insertions(+), 17 deletions(-)
---
diff --git a/gi/arg-inl.h b/gi/arg-inl.h
index 996092c2..4e9afb8a 100644
--- a/gi/arg-inl.h
+++ b/gi/arg-inl.h
@@ -10,6 +10,8 @@
 #include <stdint.h>
 
 #include <cstddef>  // for nullptr_t
+#include <limits>
+#include <string>  // for to_string
 #include <type_traits>
 
 #include <girepository.h>
@@ -220,3 +222,41 @@ template <typename T, GITypeTag TAG = GI_TYPE_TAG_VOID>
 inline std::enable_if_t<std::is_pointer_v<T>> gjs_arg_unset(GIArgument* arg) {
     gjs_arg_set<T, TAG>(arg, nullptr);
 }
+
+// Implementation to store rounded (u)int64_t numbers into double
+
+template <typename BigT>
+[[nodiscard]] inline BigT max_safe_big_number() {
+    return BigT(1) << std::numeric_limits<double>::digits;
+}
+
+template <typename BigT>
+[[nodiscard]] inline std::enable_if_t<std::is_signed_v<BigT>, BigT>
+min_safe_big_number() {
+    return -(max_safe_big_number<BigT>()) + 1;
+}
+
+template <typename BigT>
+[[nodiscard]] inline std::enable_if_t<std::is_unsigned_v<BigT>, BigT>
+min_safe_big_number() {
+    return std::numeric_limits<BigT>::lowest();
+}
+
+template <typename BigT>
+[[nodiscard]] inline std::enable_if_t<std::is_integral_v<BigT> &&
+                                          (std::numeric_limits<BigT>::max() >
+                                           std::numeric_limits<int32_t>::max()),
+                                      double>
+gjs_arg_get_maybe_rounded(GIArgument* arg) {
+    BigT val = gjs_arg_get<BigT>(arg);
+
+    if (val < min_safe_big_number<BigT>() ||
+        val > max_safe_big_number<BigT>()) {
+        g_warning(
+            "Value %s cannot be safely stored in a JS Number "
+            "and may be rounded",
+            std::to_string(val).c_str());
+    }
+
+    return static_cast<double>(val);
+}
diff --git a/gi/arg.cpp b/gi/arg.cpp
index d02d37d0..2d4fa012 100644
--- a/gi/arg.cpp
+++ b/gi/arg.cpp
@@ -26,7 +26,6 @@
 
 #include <string.h>  // for strcmp, strlen, memcpy
 
-#include <cmath>   // for std::abs
 #include <limits>  // for numeric_limits
 #include <string>
 #include <type_traits>
@@ -2836,9 +2835,6 @@ gjs_object_from_g_hash (JSContext             *context,
     return true;
 }
 
-static const int64_t MAX_SAFE_INT64 =
-    int64_t(1) << std::numeric_limits<double>::digits;
-
 bool
 gjs_value_from_g_argument (JSContext             *context,
                            JS::MutableHandleValue value_p,
@@ -2874,22 +2870,11 @@ gjs_value_from_g_argument (JSContext             *context,
         break;
 
     case GI_TYPE_TAG_INT64:
-        if (gjs_arg_get<int64_t>(arg) == G_MININT64 ||
-            std::abs(gjs_arg_get<int64_t>(arg)) > MAX_SAFE_INT64)
-            g_warning("Value %" G_GINT64_FORMAT
-                      " cannot be safely stored in a JS Number and may be "
-                      "rounded",
-                      gjs_arg_get<int64_t>(arg));
-        value_p.setNumber(static_cast<double>(gjs_arg_get<int64_t>(arg)));
+        value_p.setNumber(gjs_arg_get_maybe_rounded<int64_t>(arg));
         break;
 
     case GI_TYPE_TAG_UINT64:
-        if (gjs_arg_get<uint64_t>(arg) > MAX_SAFE_INT64)
-            g_warning("Value %" G_GUINT64_FORMAT
-                      " cannot be safely stored in a JS Number and may be "
-                      "rounded",
-                      gjs_arg_get<uint64_t>(arg));
-        value_p.setNumber(static_cast<double>(gjs_arg_get<uint64_t>(arg)));
+        value_p.setNumber(gjs_arg_get_maybe_rounded<uint64_t>(arg));
         break;
 
     case GI_TYPE_TAG_UINT16:


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