After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 368686 - PATCH: GString overwriting functions
PATCH: GString overwriting functions
Status: RESOLVED FIXED
Product: glib
Classification: Platform
Component: general
2.12.x
Other All
: Normal enhancement
: ---
Assigned To: gtkdev
gtkdev
Depends on:
Blocks:
 
 
Reported: 2006-11-01 03:35 UTC by Samuel Cormier-Iijima
Modified: 2007-06-15 11:59 UTC
See Also:
GNOME target: ---
GNOME version: Unversioned Enhancement


Attachments
The aforementioned patch (4.57 KB, patch)
2006-11-01 03:36 UTC, Samuel Cormier-Iijima
needs-work Details | Review
Fixed patch (4.12 KB, patch)
2007-06-15 00:57 UTC, Samuel Cormier-Iijima
reviewed Details | Review
Reworked patch. (4.34 KB, patch)
2007-06-15 11:06 UTC, Mathias Hasselmann (IRC: tbf)
accepted-commit_now Details | Review

Description Samuel Cormier-Iijima 2006-11-01 03:35:42 UTC
I've written a short patch for adding overwriting support for GStrings. Don't know if this is needed or useful, but I'm using GStrings as buffers in my application and wanted a simple way to overwrite a part of it. This could also be done with a combination of g_string_erase and g_string_insert, but it's faster and simpler this way. I've added two new functions g_string_overwrite and g_string_overwrite_len which are quite obvious what they do. I also tried to follow coding convention and added docs and tests. This is my first time submitting a patch to such a highly visible project, so any suggestions are welcome. Thanks!
Comment 1 Samuel Cormier-Iijima 2006-11-01 03:36:20 UTC
Created attachment 75749 [details] [review]
The aforementioned patch
Comment 2 Havoc Pennington 2006-11-01 05:08:46 UTC
Something like this seems more similar to what other frameworks offer:
 g_string_replace(GString *str, int pos, int len, const char *replacement);
 g_string_replace_len(GString *str,
             int pos, int len, const char *replacement, int replacement_len);
Comment 3 Samuel Cormier-Iijima 2006-11-01 06:27:53 UTC
OK, replace is possibly a better name for these functions than overwrite. However, I don't get what the first len argument is in your examples... if I say
g_string_replace ("This is a sentence", 5, 8, "isnt"), what happens? Is "isnt" repeated until it fills 8 bytes becoming "This isntisnttence", or are the remaining 4 set to NULLs?
Comment 4 Havoc Pennington 2006-11-01 16:26:59 UTC
The idea is erase() followed by insert(), except if the erased len is the same as the inserted len, it can optimize by skipping the two memmove() calls.
(Which is what I thought you were getting at with overwrite())

Though, now that I look at Python and Java their replace() does a replace-by-value (replace all occurrences of a given substring), so maybe replace() is a bad name.


Comment 5 Behdad Esfahbod 2006-11-01 16:30:31 UTC
splice?
Comment 6 Tim Janik 2006-11-27 11:11:35 UTC
Comment on attachment 75749 [details] [review]
The aforementioned patch

>+GString *
>+g_string_overwrite (GString       *string,
>+		    gssize          pos,

the type for po should be gsize since negative values don't make sense here.

>+		    const gchar   *val)
>+{
>+  gsize len;
>+
>+  g_return_val_if_fail (string != NULL, NULL);
>+  g_return_val_if_fail (val != NULL, string);
>+  g_return_val_if_fail (pos >= 0, string);
>+  g_return_val_if_fail (pos <= string->len, string);
>+
>+  len = strlen (val);
>+
>+  g_string_maybe_expand (string, pos + len - string->len);

correct me if i'm wrong, but using an example calculation
pos=3, len=5, string->len=25:
  3 + 5 - 25 = 8 + (2^32 - 25) = 8 + 4294967271 = 4294967279
(adding 2^32 because len and string->len force unsigned evaluation)
does your test code check for this case btw?

to fix this, one could:
- use MAX (pos + len, string->len) - strig->len
- force signed evaluation by casting all 3 variables and change the
  the internal function g_string_maybe_expand() to accept gssize instead of gsize.

>+
>+  memcpy (string->str + pos, val, len);
>+
>+  if (pos + len > string->len)
>+    string->str[pos + len] = '\0';
>+
>+  string->len = MAX (string->len, pos + len);
>+
>+  return string;
>+}
>+
>+/**
>+ * g_string_overwrite_len:
>+ * @string: a #GString
>+ * @pos: the position at which to start overwriting
>+ * @val: the string that will overwrite the @string starting at @pos
>+ * @len: the number of bytes to write from @val
>+ * 
>+ * Overwrites part of a string, lengthening it if necessary. This function
>+ * will work with embedded NULLs.
>+ * 
>+ * Return value: @string
>+ **/
>+GString *
>+g_string_overwrite_len (GString       *string,
>+			gssize          pos,

use gsize, as above.

>+			const gchar   *val,
>+			gsize          len)

the below code expects a signed len, so you need gssize here.

>+{
>+  g_return_val_if_fail (string != NULL, NULL);
>+  g_return_val_if_fail (val != NULL, string);
>+  g_return_val_if_fail (pos >= 0, string);
>+  g_return_val_if_fail (pos <= string->len, string);
>+
>+  if (len < 0)
>+    len = strlen (val);
>+
>+  g_string_maybe_expand (string, pos + len - string->len);
>+
>+  memcpy (string->str + pos, val, len);
>+
>+  if (pos + len > string->len)
>+    string->str[pos + len] = '\0';
>+
>+  string->len = MAX (string->len, pos + len);
>+
>+  return string;
>+}
>+

the patch in general looks good, but the gsize vs. gssize issues definitely must be fixed.
Comment 7 Tim Janik 2006-11-27 11:15:15 UTC
(In reply to comment #4)
> The idea is erase() followed by insert(), except if the erased len is the same
> as the inserted len, it can optimize by skipping the two memmove() calls.
> (Which is what I thought you were getting at with overwrite())

overwrite makes perfect sense without memove. i don't think the suggested API needs any corrections.

> Though, now that I look at Python and Java their replace() does a
> replace-by-value (replace all occurrences of a given substring), so maybe
> replace() is a bad name.

for the overwriting that this patch implements you're probably right.
g_string_overwrite() is pretty closely naming i'd say, so i'm inclined to take the patch the way it is, provided it's technical issues get fixed.
Comment 8 Samuel Cormier-Iijima 2007-06-15 00:57:00 UTC
Created attachment 89982 [details] [review]
Fixed patch

Sorry about how long this took, been caught up in other things. Can this be commited?

Samuel
Comment 9 Tim Janik 2007-06-15 08:46:22 UTC
Comment on attachment 89982 [details] [review]
Fixed patch

>Index: glib/gstring.c
>===================================================================
>--- glib/gstring.c	(revision 5560)
>+++ glib/gstring.c	(working copy)
>@@ -1023,6 +1023,78 @@
> }
> 
> /**
>+ * g_string_overwrite:
>+ * @string: a #GString
>+ * @pos: the position at which to start overwriting
>+ * @val: the string that will overwrite the @string starting at @pos
>+ * 
>+ * Overwrites part of a string, lengthening it if necessary.

this needs: Since: 2.14.

>+ * 
>+ * Return value: @string
>+ **/
>+GString *
>+g_string_overwrite (GString     *string,
>+		    gsize        pos,
>+		    const gchar *val)
>+{
>+  gsize len;
>+
>+  g_return_val_if_fail (string != NULL, NULL);
>+  g_return_val_if_fail (val != NULL, string);
>+  g_return_val_if_fail (pos >= 0 && pos <= string->len, string);
>+
>+  len = strlen (val);
>+
>+  g_string_maybe_expand (string, MAX (pos + len, string->len) - string->len);
>+
>+  memcpy (string->str + pos, val, len);
>+
>+  if (pos + len > string->len)
>+    string->str[pos + len] = '\0';
>+
>+  string->len = MAX (string->len, pos + len);
>+
>+  return string;
>+}
>+
>+/**
>+ * g_string_overwrite_len:
>+ * @string: a #GString
>+ * @pos: the position at which to start overwriting
>+ * @val: the string that will overwrite the @string starting at @pos
>+ * @len: the number of bytes to write from @val
>+ * 
>+ * Overwrites part of a string, lengthening it if necessary. This function
>+ * will work with embedded NULLs.

Since: 2.14

>+ * 
>+ * Return value: @string
>+ **/
>+GString *
>+g_string_overwrite_len (GString       *string,
>+			gsize         pos,
>+			const gchar   *val,
>+			gsize          len)

len needs to be gssize to be negative.

>+{
>+  g_return_val_if_fail (string != NULL, NULL);
>+  g_return_val_if_fail (val != NULL, string);

this is missing if (!len) return string;
so that we allow val==NULL in case len=0.

>+  g_return_val_if_fail (pos >= 0 && pos <= string->len, string);
>+
>+  if (len < 0)
>+    len = strlen (val);

here you allow negative len...

>+
>+  g_string_maybe_expand (string, MAX (pos + len, string->len) - string->len);
>+
>+  memcpy (string->str + pos, val, len);
>+
>+  if (pos + len > string->len)
>+    string->str[pos + len] = '\0';
>+
>+  string->len = MAX (string->len, pos + len);
>+
>+  return string;
>+}
>+
>+/**
>  * g_string_erase:
>  * @string: a #GString
>  * @pos: the position of the content to remove
>Index: glib/gstring.h
>===================================================================
>--- glib/gstring.h	(revision 5560)
>+++ glib/gstring.h	(working copy)
>@@ -105,6 +105,13 @@
> GString*     g_string_insert_unichar    (GString	 *string,
> 					 gssize		  pos,    
> 					 gunichar	  wc);
>+GString*     g_string_overwrite         (GString	 *string,
>+					 gsize		  pos,    
>+					 const gchar	 *val);
>+GString*     g_string_overwrite_len     (GString	 *string,
>+					 gsize		  pos,    
>+					 const gchar	 *val,
>+					 gsize            len);

this needs gssize for len.

> GString*     g_string_erase	        (GString	 *string,
> 					 gssize		  pos,
> 					 gssize		  len);

apart from the above issues, the patch looks good.
tbf, bratsche, can you take care of fixing, testing and committing please?
Comment 10 Mathias Hasselmann (IRC: tbf) 2007-06-15 11:06:10 UTC
Created attachment 90005 [details] [review]
Reworked patch.

- Reworked the patch to include Tim's change requests (@Since tag, gssize len, early exit on !len)
- Avoid code duplication by calling g_string_overwrite_len from g_string_overwrite
- Made the unit-tests more pedantic.
Comment 11 Tim Janik 2007-06-15 11:24:42 UTC
rock, thanks, good patch, please test + commit.
Comment 12 Tim Janik 2007-06-15 11:59:30 UTC
2007-06-15  Mathias Hasselmann  <mathias.hasselmann@gmx.de>
       * build, tests/string-test.c, glib/glib.symbols, 
       glib/gstring.c, glib/gstring.h: Introduce g_string_overwrite(_len)?
       for overwriting parts of strings (#368686, Samuel Cormier-Iijima)