[gjs: 8/9] js: Use strings and stringstreams instead of GString




commit fee940c0710f6bc3f9b08a1cef26ec4555cbb440
Author: Philip Chimento <philip chimento gmail com>
Date:   Tue Nov 24 19:27:55 2020 -0800

    js: Use strings and stringstreams instead of GString
    
    std::ostringstream is the C++ standard library version of GString. If we
    are not doing any formatting but only appending other strings, then we can
    even just use std::string and the + operator.
    
    This allows using RAII so we can get rid of a goto, and just generally be
    more memory-safe.
    
    We continue using GString in gjs_hyphen_from_camel() for performance
    reasons, because we would like a modifiable C buffer that we can pass to
    canonicalize_key(), and the only way to get a modifiable buffer out of
    std::string would be to copy it.
    
    Note: stream.str() _creates_ a std::string object, and copies the string
    data. string.c_str() returns a const char* _without_ copying.

 gi/repo.cpp         | 29 ++++++++++++++++-------------
 gi/wrapperutils.cpp | 36 +++++++++++++-----------------------
 gjs/jsapi-util.cpp  | 52 +++++++++++++++++++++-------------------------------
 gjs/jsapi-util.h    |  4 ++--
 modules/console.cpp | 28 +++++++++++-----------------
 modules/print.cpp   | 29 +++++++++++++----------------
 test/gjs-tests.cpp  | 22 ++++++----------------
 7 files changed, 82 insertions(+), 118 deletions(-)
---
diff --git a/gi/repo.cpp b/gi/repo.cpp
index d110d8d3..57938e6b 100644
--- a/gi/repo.cpp
+++ b/gi/repo.cpp
@@ -7,6 +7,10 @@
 #include <stdint.h>
 #include <string.h>  // for strlen
 
+#if GJS_VERBOSE_ENABLE_GI_USAGE
+#    include <string>
+#endif
+
 #include <girepository.h>
 #include <glib-object.h>
 #include <glib.h>
@@ -282,13 +286,11 @@ _gjs_log_info_usage(GIBaseInfo *info)
         info_type = g_base_info_get_type(info);
 
         if (info_type == GI_INFO_TYPE_FUNCTION) {
-            GString *args;
+            std::string args("{ ");
             int n_args;
             int i;
             GITransfer retval_transfer;
 
-            args = g_string_new("{ ");
-
             n_args = g_callable_info_get_n_args((GICallableInfo*) info);
             for (i = 0; i < n_args; ++i) {
                 GIArgInfo *arg;
@@ -299,23 +301,24 @@ _gjs_log_info_usage(GIBaseInfo *info)
                 direction = g_arg_info_get_direction(arg);
                 transfer = g_arg_info_get_ownership_transfer(arg);
 
-                g_string_append_printf(args,
-                                       "{ GI_DIRECTION_%s, GI_TRANSFER_%s }, ",
-                                       DIRECTION_STRING(direction),
-                                       TRANSFER_STRING(transfer));
+                if (i > 0)
+                    args += ", ";
+
+                args += std::string("{ GI_DIRECTION_") +
+                        DIRECTION_STRING(direction) + ", GI_TRANSFER_" +
+                        TRANSFER_STRING(transfer) + " }";
 
                 g_base_info_unref((GIBaseInfo*) arg);
             }
-            if (args->len > 2)
-                g_string_truncate(args, args->len - 2); /* chop comma */
 
-            g_string_append(args, " }");
+            args += " }";
 
             retval_transfer = g_callable_info_get_caller_owns((GICallableInfo*) info);
 
-            details = g_strdup_printf(".details = { .func = { .retval_transfer = GI_TRANSFER_%s, .n_args = 
%d, .args = %s } }",
-                                      TRANSFER_STRING(retval_transfer), n_args, args->str);
-            g_string_free(args, true);
+            details = g_strdup_printf(
+                ".details = { .func = { .retval_transfer = GI_TRANSFER_%s, "
+                ".n_args = %d, .args = %s } }",
+                TRANSFER_STRING(retval_transfer), n_args, args.c_str());
         } else {
             details = g_strdup_printf(".details = { .nothing = {} }");
         }
diff --git a/gi/wrapperutils.cpp b/gi/wrapperutils.cpp
index eae41020..c314ffd0 100644
--- a/gi/wrapperutils.cpp
+++ b/gi/wrapperutils.cpp
@@ -4,6 +4,8 @@
 
 #include <config.h>
 
+#include <sstream>
+
 #include <girepository.h>
 #include <glib-object.h>
 
@@ -26,39 +28,27 @@ bool gjs_wrapper_to_string_func(JSContext* context, JSObject* this_obj,
                                 const char* objtype, GIBaseInfo* info,
                                 GType gtype, const void* native_address,
                                 JS::MutableHandleValue rval) {
-    GString *buf;
-    bool ret = false;
-
-    buf = g_string_new("");
-    g_string_append_c(buf, '[');
-    g_string_append(buf, objtype);
+    std::ostringstream out;
+    out << '[' << objtype;
     if (!native_address)
-        g_string_append(buf, " prototype of");
+        out << " prototype of";
     else
-        g_string_append(buf, " instance wrapper");
+        out << " instance wrapper";
 
     if (info) {
-        g_string_append_printf(buf, " GIName:%s.%s",
-                               g_base_info_get_namespace(info),
-                               g_base_info_get_name(info));
+        out << " GIName:" << g_base_info_get_namespace(info) << "."
+            << g_base_info_get_name(info);
     } else {
-        g_string_append(buf, " GType:");
-        g_string_append(buf, g_type_name(gtype));
+        out << " GType:" << g_type_name(gtype);
     }
 
-    g_string_append_printf(buf, " jsobj@%p", this_obj);
+    out << " jsobj@0x" << uintptr_t(this_obj);
     if (native_address)
-        g_string_append_printf(buf, " native@%p", native_address);
-
-    g_string_append_c(buf, ']');
+        out << " native@0x" << uintptr_t(native_address);
 
-    if (!gjs_string_from_utf8(context, buf->str, rval))
-        goto out;
+    out << ']';
 
-    ret = true;
- out:
-    g_string_free(buf, true);
-    return ret;
+    return gjs_string_from_utf8(context, out.str().c_str(), rval);
 }
 
 bool gjs_wrapper_throw_nonexistent_field(JSContext* cx, GType gtype,
diff --git a/gjs/jsapi-util.cpp b/gjs/jsapi-util.cpp
index 945c9fb6..1e7d2aa8 100644
--- a/gjs/jsapi-util.cpp
+++ b/gjs/jsapi-util.cpp
@@ -244,11 +244,9 @@ JSObject* gjs_define_string_array(JSContext* context,
  * are \x escaped.
  *
  */
-[[nodiscard]] static char* gjs_string_readable(JSContext* context,
-                                               JS::HandleString string) {
-    GString *buf = g_string_new("");
-
-    g_string_append_c(buf, '"');
+[[nodiscard]] static std::string gjs_string_readable(JSContext* context,
+                                                     JS::HandleString string) {
+    std::string buf(1, '"');
 
     JS::UniqueChars chars(JS_EncodeStringToUTF8(context, string));
     if (!chars) {
@@ -262,52 +260,47 @@ JSObject* gjs_define_string_array(JSContext* context,
         char *escaped = g_new(char, len + 1);
 
         JS_PutEscapedString(context, escaped, len, string, '"');
-        g_string_append(buf, escaped);
+        buf += escaped;
         g_free(escaped);
     } else {
-        g_string_append(buf, chars.get());
+        buf += chars.get();
     }
 
-    g_string_append_c(buf, '"');
-
-    return g_string_free(buf, false);
+    return buf + '"';
 }
 
-[[nodiscard]] static char* _gjs_g_utf8_make_valid(const char* name) {
-    GString *string;
+[[nodiscard]] static std::string _gjs_g_utf8_make_valid(const char* name) {
     const char *remainder, *invalid;
     int remaining_bytes, valid_bytes;
 
     g_return_val_if_fail (name != NULL, NULL);
 
-    string = nullptr;
     remainder = name;
     remaining_bytes = strlen (name);
 
+    if (remaining_bytes == 0)
+        return std::string(name);
+
+    std::string buf;
+    buf.reserve(remaining_bytes);
     while (remaining_bytes != 0) {
         if (g_utf8_validate (remainder, remaining_bytes, &invalid))
             break;
         valid_bytes = invalid - remainder;
 
-        if (!string)
-            string = g_string_sized_new (remaining_bytes);
-
-        g_string_append_len (string, remainder, valid_bytes);
+        buf.append(remainder, valid_bytes);
         /* append U+FFFD REPLACEMENT CHARACTER */
-        g_string_append (string, "\357\277\275");
+        buf += "\357\277\275";
 
         remaining_bytes -= valid_bytes + 1;
         remainder = invalid + 1;
     }
 
-    if (!string)
-        return g_strdup (name);
-
-    g_string_append (string, remainder);
+    buf += remainder;
 
-    g_assert (g_utf8_validate (string->str, -1, NULL));
+    g_assert(g_utf8_validate(buf.c_str(), -1, nullptr));
 
-    return g_string_free (string, false);
+    return buf;
 }
 
 /**
@@ -317,10 +310,7 @@ JSObject* gjs_define_string_array(JSContext* context,
  *
  * Returns: A UTF-8 encoded string describing @value
  */
-char*
-gjs_value_debug_string(JSContext      *context,
-                       JS::HandleValue value)
-{
+std::string gjs_value_debug_string(JSContext* context, JS::HandleValue value) {
     /* Special case debug strings for strings */
     if (value.isString()) {
         JS::RootedString str(context, value.toString());
@@ -344,13 +334,13 @@ gjs_value_debug_string(JSContext      *context,
                 str = JS_NewStringCopyZ(context, klass->name);
                 JS_ClearPendingException(context);
                 if (!str)
-                    return g_strdup("[out of memory copying class name]");
+                    return "[out of memory copying class name]";
             } else {
                 gjs_log_exception(context);
-                return g_strdup("[unknown object]");
+                return "[unknown object]";
             }
         } else {
-            return g_strdup("[unknown non-object]");
+            return "[unknown non-object]";
         }
     }
 
diff --git a/gjs/jsapi-util.h b/gjs/jsapi-util.h
index 2d2aac87..273e9a29 100644
--- a/gjs/jsapi-util.h
+++ b/gjs/jsapi-util.h
@@ -421,8 +421,8 @@ bool gjs_log_exception_uncaught(JSContext* cx);
 bool gjs_log_exception_full(JSContext* cx, JS::HandleValue exc,
                             JS::HandleString message, GLogLevelFlags level);
 
-[[nodiscard]] char* gjs_value_debug_string(JSContext* cx,
-                                           JS::HandleValue value);
+[[nodiscard]] std::string gjs_value_debug_string(JSContext* cx,
+                                                 JS::HandleValue value);
 
 void gjs_warning_reporter(JSContext*, JSErrorReport* report);
 
diff --git a/modules/console.cpp b/modules/console.cpp
index 33678468..6eab0139 100644
--- a/modules/console.cpp
+++ b/modules/console.cpp
@@ -12,6 +12,8 @@
 #    include <readline/readline.h>
 #endif
 
+#include <string>
+
 #include <glib.h>
 #include <glib/gprintf.h>  // for g_fprintf
 
@@ -104,11 +106,11 @@ public:
  * invocation of this function.)
  */
 [[nodiscard]] static bool gjs_console_eval_and_print(JSContext* cx,
-                                                     const char* bytes,
-                                                     size_t length,
+                                                     const std::string& bytes,
                                                      int lineno) {
     JS::SourceText<mozilla::Utf8Unit> source;
-    if (!source.init(cx, bytes, length, JS::SourceOwnership::Borrowed))
+    if (!source.init(cx, bytes.c_str(), bytes.size(),
+                     JS::SourceOwnership::Borrowed))
         return false;
 
     JS::CompileOptions options(cx);
@@ -126,12 +128,7 @@ public:
     if (result.isUndefined())
         return true;
 
-    char *display_str;
-    display_str = gjs_value_debug_string(cx, result);
-    if (display_str) {
-        g_fprintf(stdout, "%s\n", display_str);
-        g_free(display_str);
-    }
+    g_fprintf(stdout, "%s\n", gjs_value_debug_string(cx, result).c_str());
     return true;
 }
 
@@ -144,7 +141,6 @@ gjs_console_interact(JSContext *context,
     JS::CallArgs argv = JS::CallArgsFromVp(argc, vp);
     bool eof = false;
     JS::RootedObject global(context, gjs_get_import_global(context));
-    GString *buffer = NULL;
     char *temp_buf = NULL;
     int lineno;
     int startline;
@@ -161,26 +157,24 @@ gjs_console_interact(JSContext *context,
          * coincides with the end of a line.
          */
         startline = lineno;
-        buffer = g_string_new("");
+        std::string buffer;
         do {
             if (!gjs_console_readline(
                     &temp_buf, startline == lineno ? "gjs> " : ".... ")) {
                 eof = true;
                 break;
             }
-            g_string_append(buffer, temp_buf);
+            buffer += temp_buf;
             g_free(temp_buf);
             lineno++;
-        } while (!JS_Utf8BufferIsCompilableUnit(context, global, buffer->str,
-                                                buffer->len));
+        } while (!JS_Utf8BufferIsCompilableUnit(context, global, buffer.c_str(),
+                                                buffer.size()));
 
         bool ok;
         {
             AutoReportException are(context);
-            ok = gjs_console_eval_and_print(context, buffer->str, buffer->len,
-                                            startline);
+            ok = gjs_console_eval_and_print(context, buffer, startline);
         }
-        g_string_free(buffer, true);
 
         GjsContextPrivate* gjs = GjsContextPrivate::from_cx(context);
         ok = gjs->run_jobs_fallible() && ok;
diff --git a/modules/print.cpp b/modules/print.cpp
index e73a35af..cb0f1e3b 100644
--- a/modules/print.cpp
+++ b/modules/print.cpp
@@ -5,6 +5,8 @@
 
 #include <config.h>
 
+#include <string>
+
 #include <glib.h>
 
 #include <js/CallArgs.h>
@@ -85,8 +87,9 @@ static bool gjs_log_error(JSContext* cx, unsigned argc, JS::Value* vp) {
 
 GJS_JSAPI_RETURN_CONVENTION
 static bool gjs_print_parse_args(JSContext* cx, const JS::CallArgs& argv,
-                                 GjsAutoChar* buffer) {
-    GString* str = g_string_new("");
+                                 std::string* buffer) {
+    g_assert(buffer && "forgot out parameter");
+    buffer->clear();
     for (unsigned n = 0; n < argv.length(); ++n) {
         /* JS::ToString might throw, in which case we will only log that the
          * value could not be converted to string */
@@ -96,23 +99,17 @@ static bool gjs_print_parse_args(JSContext* cx, const JS::CallArgs& argv,
 
         if (jstr) {
             JS::UniqueChars s(JS_EncodeStringToUTF8(cx, jstr));
-            if (!s) {
-                g_string_free(str, true);
+            if (!s)
                 return false;
-            }
 
-            g_string_append(str, s.get());
+            *buffer += s.get();
             if (n < (argv.length() - 1))
-                g_string_append_c(str, ' ');
+                *buffer += ' ';
         } else {
-            *buffer = g_string_free(str, true);
-            if (!*buffer)
-                *buffer = g_strdup("<invalid string>");
+            *buffer = "<invalid string>";
             return true;
         }
     }
-    *buffer = g_string_free(str, false);
-
     return true;
 }
 
@@ -120,11 +117,11 @@ GJS_JSAPI_RETURN_CONVENTION
 static bool gjs_print(JSContext* context, unsigned argc, JS::Value* vp) {
     JS::CallArgs argv = JS::CallArgsFromVp(argc, vp);
 
-    GjsAutoChar buffer;
+    std::string buffer;
     if (!gjs_print_parse_args(context, argv, &buffer))
         return false;
 
-    g_print("%s\n", buffer.get());
+    g_print("%s\n", buffer.c_str());
 
     argv.rval().setUndefined();
     return true;
@@ -134,11 +131,11 @@ GJS_JSAPI_RETURN_CONVENTION
 static bool gjs_printerr(JSContext* context, unsigned argc, JS::Value* vp) {
     JS::CallArgs argv = JS::CallArgsFromVp(argc, vp);
 
-    GjsAutoChar buffer;
+    std::string buffer;
     if (!gjs_print_parse_args(context, argv, &buffer))
         return false;
 
-    g_printerr("%s\n", buffer.get());
+    g_printerr("%s\n", buffer.c_str());
 
     argv.rval().setUndefined();
     return true;
diff --git a/test/gjs-tests.cpp b/test/gjs-tests.cpp
index 4bf7b78e..c7555013 100644
--- a/test/gjs-tests.cpp
+++ b/test/gjs-tests.cpp
@@ -317,12 +317,9 @@ static void test_jsapi_util_debug_string_valid_utf8(GjsUnitTestFixture* fx,
     JS::RootedValue v_string(fx->cx);
     g_assert_true(gjs_string_from_utf8(fx->cx, VALID_UTF8_STRING, &v_string));
 
-    char *debug_output = gjs_value_debug_string(fx->cx, v_string);
+    std::string debug_output = gjs_value_debug_string(fx->cx, v_string);
 
-    g_assert_nonnull(debug_output);
-    g_assert_cmpstr("\"" VALID_UTF8_STRING "\"", ==, debug_output);
-
-    g_free(debug_output);
+    g_assert_cmpstr("\"" VALID_UTF8_STRING "\"", ==, debug_output.c_str());
 }
 
 static void test_jsapi_util_debug_string_invalid_utf8(GjsUnitTestFixture* fx,
@@ -333,12 +330,8 @@ static void test_jsapi_util_debug_string_invalid_utf8(GjsUnitTestFixture* fx,
     const char16_t invalid_unicode[] = { 0xffff, 0xffff };
     v_string.setString(JS_NewUCStringCopyN(fx->cx, invalid_unicode, 2));
 
-    char *debug_output = gjs_value_debug_string(fx->cx, v_string);
-
-    g_assert_nonnull(debug_output);
-    /* g_assert_cmpstr("\"\\xff\\xff\\xff\\xff\"", ==, debug_output); */
-
-    g_free(debug_output);
+    std::string debug_output = gjs_value_debug_string(fx->cx, v_string);
+    // g_assert_cmpstr("\"\\xff\\xff\\xff\\xff\"", ==, debug_output.c_str());
 }
 
 static void test_jsapi_util_debug_string_object_with_complicated_to_string(
@@ -352,12 +345,9 @@ static void test_jsapi_util_debug_string_object_with_complicated_to_string(
     contents[1].setString(JS_NewUCStringCopyN(fx->cx, desserts + 2, 2));
     JS::RootedObject array(fx->cx, JS::NewArrayObject(fx->cx, contents));
     JS::RootedValue v_array(fx->cx, JS::ObjectValue(*array));
-    char *debug_output = gjs_value_debug_string(fx->cx, v_array);
-
-    g_assert_nonnull(debug_output);
-    g_assert_cmpstr(u8"🍪,🍩", ==, debug_output);
+    std::string debug_output = gjs_value_debug_string(fx->cx, v_array);
 
-    g_free(debug_output);
+    g_assert_cmpstr(u8"🍪,🍩", ==, debug_output.c_str());
 }
 
 static void


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