mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-22 10:12:10 +01:00
GString: Support on-stack use
Move the preallocation into the GString struct, and add g_string_init and g_string_clear to enable on-stack use of GString.
This commit is contained in:
parent
1aa5304109
commit
1e38e6f53f
@ -2652,6 +2652,8 @@ g_string_truncate
|
||||
g_string_set_size
|
||||
g_string_free
|
||||
g_string_free_to_bytes
|
||||
g_string_init
|
||||
g_string_free
|
||||
|
||||
<SUBSECTION>
|
||||
g_string_up
|
||||
|
@ -59,6 +59,10 @@
|
||||
* characters in the data. Conceptually then, #GString is like a
|
||||
* #GByteArray with the addition of many convenience methods for text,
|
||||
* and a guaranteed nul terminator.
|
||||
*
|
||||
* GString can be used as a heap-allocated object, using g_string_new()
|
||||
* and g_string_free(), or as a stack-allocated struct, using g_string_init()
|
||||
* and g_string_clear().
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -70,6 +74,7 @@
|
||||
* terminating nul byte.
|
||||
* @allocated_len: the number of bytes that can be stored in the
|
||||
* string before it needs to be reallocated. May be larger than @len.
|
||||
* @buf: preallocated memory for @str
|
||||
*
|
||||
* The GString struct contains the public fields of a GString.
|
||||
*/
|
||||
@ -82,6 +87,9 @@ g_string_expand (GString *string,
|
||||
if G_UNLIKELY ((G_MAXSIZE - string->len - 1) < len)
|
||||
g_error ("adding %" G_GSIZE_FORMAT " to string would overflow", len);
|
||||
|
||||
if (string->str == NULL)
|
||||
g_string_init (string);
|
||||
|
||||
string->allocated_len = g_nearest_pow (string->len + len + 1);
|
||||
/* If the new size is bigger than G_MAXSIZE / 2, only allocate enough
|
||||
* memory for this string and don't over-allocate.
|
||||
@ -89,7 +97,14 @@ g_string_expand (GString *string,
|
||||
if (string->allocated_len == 0)
|
||||
string->allocated_len = string->len + len + 1;
|
||||
|
||||
string->str = g_realloc (string->str, string->allocated_len);
|
||||
if (string->str != string->buf)
|
||||
string->str = g_realloc (string->str, string->allocated_len);
|
||||
else
|
||||
{
|
||||
string->str = g_malloc (string->allocated_len);
|
||||
memcpy (string->str, string->buf, string->len);
|
||||
string->str[string->len] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -100,6 +115,23 @@ g_string_maybe_expand (GString *string,
|
||||
g_string_expand (string, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_string_init:
|
||||
* @string: an uninitialized #GString
|
||||
*
|
||||
* Initializes @string.
|
||||
*
|
||||
* This function should be used to initialize a stack-allocated
|
||||
* GString struct.
|
||||
*
|
||||
* Since: 2.76
|
||||
*/
|
||||
void
|
||||
(g_string_init) (GString *string)
|
||||
{
|
||||
g_string_init_inline (string);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_string_sized_new: (constructor)
|
||||
* @dfl_size: the default size of the space allocated to hold the string
|
||||
@ -116,12 +148,8 @@ g_string_sized_new (gsize dfl_size)
|
||||
{
|
||||
GString *string = g_slice_new (GString);
|
||||
|
||||
string->allocated_len = 0;
|
||||
string->len = 0;
|
||||
string->str = NULL;
|
||||
|
||||
g_string_expand (string, MAX (dfl_size, 64));
|
||||
string->str[0] = 0;
|
||||
g_string_init (string);
|
||||
g_string_maybe_expand (string, dfl_size);
|
||||
|
||||
return string;
|
||||
}
|
||||
@ -189,6 +217,29 @@ g_string_new_len (const gchar *init,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* g_string_clear:
|
||||
* @string: (transfer full): a #GString
|
||||
* @free_segment: if %TRUE, the actual character data is freed as well
|
||||
*
|
||||
* Clears a stack-allocated GString struct.
|
||||
*
|
||||
* If @free_segment is %TRUE it also frees the character data.
|
||||
* If it's %FALSE, the caller gains ownership of the buffer and
|
||||
* must free it after use with g_free().
|
||||
*
|
||||
* Returns: (nullable): the character data of @string
|
||||
* (i.e. %NULL if @free_segment is %TRUE)
|
||||
*
|
||||
* Since: 2.76
|
||||
*/
|
||||
char *
|
||||
(g_string_clear) (GString *string,
|
||||
gboolean free_segment)
|
||||
{
|
||||
return g_string_clear_inline (string, free_segment);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_string_free:
|
||||
* @string: (transfer full): a #GString
|
||||
@ -210,13 +261,7 @@ g_string_free (GString *string,
|
||||
|
||||
g_return_val_if_fail (string != NULL, NULL);
|
||||
|
||||
if (free_segment)
|
||||
{
|
||||
g_free (string->str);
|
||||
segment = NULL;
|
||||
}
|
||||
else
|
||||
segment = string->str;
|
||||
segment = g_string_clear (string, free_segment);
|
||||
|
||||
g_slice_free (GString, string);
|
||||
|
||||
|
@ -35,10 +35,13 @@
|
||||
#include <glib/gunicode.h>
|
||||
#include <glib/gbytes.h>
|
||||
#include <glib/gutils.h> /* for G_CAN_INLINE */
|
||||
#include <glib/gstrfuncs.h>
|
||||
#include <string.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define G_STRING_PREALLOC 64
|
||||
|
||||
typedef struct _GString GString;
|
||||
|
||||
struct _GString
|
||||
@ -46,6 +49,7 @@ struct _GString
|
||||
gchar *str;
|
||||
gsize len;
|
||||
gsize allocated_len;
|
||||
char buf[G_STRING_PREALLOC];
|
||||
};
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
@ -163,9 +167,54 @@ GString* g_string_append_uri_escaped (GString *string,
|
||||
const gchar *reserved_chars_allowed,
|
||||
gboolean allow_utf8);
|
||||
|
||||
GLIB_AVAILABLE_IN_2_76
|
||||
void g_string_init (GString *string);
|
||||
|
||||
GLIB_AVAILABLE_IN_2_76
|
||||
char * g_string_clear (GString *string,
|
||||
gboolean free_segment);
|
||||
|
||||
#ifndef __GTK_DOC_IGNORE__
|
||||
|
||||
#ifdef G_CAN_INLINE
|
||||
G_ALWAYS_INLINE
|
||||
static inline void
|
||||
g_string_init_inline (GString *string)
|
||||
{
|
||||
string->str = string->buf;
|
||||
string->len = 0;
|
||||
string->allocated_len = G_STRING_PREALLOC;
|
||||
string->str[0] = 0;
|
||||
}
|
||||
#define g_string_init(gstr) g_string_init_inline (gstr)
|
||||
|
||||
G_ALWAYS_INLINE
|
||||
static inline char *
|
||||
g_string_clear_inline (GString *string,
|
||||
gboolean free_segment)
|
||||
{
|
||||
char *segment;
|
||||
|
||||
if (free_segment)
|
||||
{
|
||||
if (string->str != string->buf)
|
||||
g_free (string->str);
|
||||
segment = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string->str != string->buf)
|
||||
segment = string->str;
|
||||
else
|
||||
segment = (char *) g_memdup2 (string->str, string->len + 1);
|
||||
}
|
||||
|
||||
g_string_init (string);
|
||||
|
||||
return segment;
|
||||
}
|
||||
#define g_string_clear(gstr, free_segment) g_string_clear_inline (gstr, free_segment)
|
||||
|
||||
G_ALWAYS_INLINE
|
||||
static inline GString*
|
||||
g_string_append_c_inline (GString *gstring,
|
||||
@ -216,7 +265,6 @@ g_string_truncate_inline (GString *gstring,
|
||||
gstring->str[gstring->len] = '\0';
|
||||
return gstring;
|
||||
}
|
||||
|
||||
#define g_string_truncate(gstr,len) g_string_truncate_inline (gstr, len)
|
||||
|
||||
#if G_GNUC_CHECK_VERSION (2, 0)
|
||||
|
@ -629,6 +629,44 @@ test_string_replace (void)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_string_on_stack (void)
|
||||
{
|
||||
GString string;
|
||||
char *s;
|
||||
|
||||
g_string_init (&string);
|
||||
|
||||
g_assert_cmpstr (string.str, ==, "");
|
||||
g_assert_cmpint (string.len, ==, 0);
|
||||
g_assert_true (string.str == string.buf);
|
||||
|
||||
g_string_append_printf (&string, "Three %s", "cheese");
|
||||
g_assert_cmpstr (string.str, ==, "Three cheese");
|
||||
g_string_append (&string, " and a big banana");
|
||||
g_assert_cmpstr (string.str, ==, "Three cheese and a big banana");
|
||||
|
||||
g_string_assign (&string, "On a hot summer night, would you offer your throat to the wolf with red roses?");
|
||||
g_assert_cmpstr (string.str, ==, "On a hot summer night, would you offer your throat to the wolf with red roses?");
|
||||
|
||||
g_string_clear (&string, TRUE);
|
||||
|
||||
g_assert_cmpstr (string.str, ==, "");
|
||||
g_assert_cmpint (string.len, ==, 0);
|
||||
g_assert_true (string.str == string.buf);
|
||||
|
||||
g_string_append_printf (&string, "Three %s", "cheese");
|
||||
g_assert_cmpstr (string.str, ==, "Three cheese");
|
||||
g_string_append (&string, " and a big banana");
|
||||
g_assert_cmpstr (string.str, ==, "Three cheese and a big banana");
|
||||
|
||||
s = (g_string_clear) (&string, FALSE);
|
||||
|
||||
g_assert_cmpstr (s, ==, "Three cheese and a big banana");
|
||||
|
||||
g_free (s);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
@ -655,6 +693,7 @@ main (int argc,
|
||||
g_test_add_func ("/string/test-string-set-size", test_string_set_size);
|
||||
g_test_add_func ("/string/test-string-to-bytes", test_string_to_bytes);
|
||||
g_test_add_func ("/string/test-string-replace", test_string_replace);
|
||||
g_test_add_func ("/string/test-string-on-stack", test_string_on_stack);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user