[gjs: 8/9] js: Use strings and stringstreams instead of GString
- From: Philip Chimento <pchimento src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs: 8/9] js: Use strings and stringstreams instead of GString
- Date: Sat, 2 Jan 2021 20:52:41 +0000 (UTC)
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]