mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-22 18:22:11 +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_set_size
|
||||||
g_string_free
|
g_string_free
|
||||||
g_string_free_to_bytes
|
g_string_free_to_bytes
|
||||||
|
g_string_init
|
||||||
|
g_string_free
|
||||||
|
|
||||||
<SUBSECTION>
|
<SUBSECTION>
|
||||||
g_string_up
|
g_string_up
|
||||||
|
@ -59,6 +59,10 @@
|
|||||||
* characters in the data. Conceptually then, #GString is like a
|
* characters in the data. Conceptually then, #GString is like a
|
||||||
* #GByteArray with the addition of many convenience methods for text,
|
* #GByteArray with the addition of many convenience methods for text,
|
||||||
* and a guaranteed nul terminator.
|
* 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.
|
* terminating nul byte.
|
||||||
* @allocated_len: the number of bytes that can be stored in the
|
* @allocated_len: the number of bytes that can be stored in the
|
||||||
* string before it needs to be reallocated. May be larger than @len.
|
* 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.
|
* 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)
|
if G_UNLIKELY ((G_MAXSIZE - string->len - 1) < len)
|
||||||
g_error ("adding %" G_GSIZE_FORMAT " to string would overflow", 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);
|
string->allocated_len = g_nearest_pow (string->len + len + 1);
|
||||||
/* If the new size is bigger than G_MAXSIZE / 2, only allocate enough
|
/* If the new size is bigger than G_MAXSIZE / 2, only allocate enough
|
||||||
* memory for this string and don't over-allocate.
|
* memory for this string and don't over-allocate.
|
||||||
@ -89,7 +97,14 @@ g_string_expand (GString *string,
|
|||||||
if (string->allocated_len == 0)
|
if (string->allocated_len == 0)
|
||||||
string->allocated_len = string->len + len + 1;
|
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
|
static inline void
|
||||||
@ -100,6 +115,23 @@ g_string_maybe_expand (GString *string,
|
|||||||
g_string_expand (string, len);
|
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)
|
* g_string_sized_new: (constructor)
|
||||||
* @dfl_size: the default size of the space allocated to hold the string
|
* @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);
|
GString *string = g_slice_new (GString);
|
||||||
|
|
||||||
string->allocated_len = 0;
|
g_string_init (string);
|
||||||
string->len = 0;
|
g_string_maybe_expand (string, dfl_size);
|
||||||
string->str = NULL;
|
|
||||||
|
|
||||||
g_string_expand (string, MAX (dfl_size, 64));
|
|
||||||
string->str[0] = 0;
|
|
||||||
|
|
||||||
return string;
|
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:
|
* g_string_free:
|
||||||
* @string: (transfer full): a #GString
|
* @string: (transfer full): a #GString
|
||||||
@ -210,13 +261,7 @@ g_string_free (GString *string,
|
|||||||
|
|
||||||
g_return_val_if_fail (string != NULL, NULL);
|
g_return_val_if_fail (string != NULL, NULL);
|
||||||
|
|
||||||
if (free_segment)
|
segment = g_string_clear (string, free_segment);
|
||||||
{
|
|
||||||
g_free (string->str);
|
|
||||||
segment = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
segment = string->str;
|
|
||||||
|
|
||||||
g_slice_free (GString, string);
|
g_slice_free (GString, string);
|
||||||
|
|
||||||
|
@ -35,10 +35,13 @@
|
|||||||
#include <glib/gunicode.h>
|
#include <glib/gunicode.h>
|
||||||
#include <glib/gbytes.h>
|
#include <glib/gbytes.h>
|
||||||
#include <glib/gutils.h> /* for G_CAN_INLINE */
|
#include <glib/gutils.h> /* for G_CAN_INLINE */
|
||||||
|
#include <glib/gstrfuncs.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define G_STRING_PREALLOC 64
|
||||||
|
|
||||||
typedef struct _GString GString;
|
typedef struct _GString GString;
|
||||||
|
|
||||||
struct _GString
|
struct _GString
|
||||||
@ -46,6 +49,7 @@ struct _GString
|
|||||||
gchar *str;
|
gchar *str;
|
||||||
gsize len;
|
gsize len;
|
||||||
gsize allocated_len;
|
gsize allocated_len;
|
||||||
|
char buf[G_STRING_PREALLOC];
|
||||||
};
|
};
|
||||||
|
|
||||||
GLIB_AVAILABLE_IN_ALL
|
GLIB_AVAILABLE_IN_ALL
|
||||||
@ -163,9 +167,54 @@ GString* g_string_append_uri_escaped (GString *string,
|
|||||||
const gchar *reserved_chars_allowed,
|
const gchar *reserved_chars_allowed,
|
||||||
gboolean allow_utf8);
|
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__
|
#ifndef __GTK_DOC_IGNORE__
|
||||||
|
|
||||||
#ifdef G_CAN_INLINE
|
#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
|
G_ALWAYS_INLINE
|
||||||
static inline GString*
|
static inline GString*
|
||||||
g_string_append_c_inline (GString *gstring,
|
g_string_append_c_inline (GString *gstring,
|
||||||
@ -216,7 +265,6 @@ g_string_truncate_inline (GString *gstring,
|
|||||||
gstring->str[gstring->len] = '\0';
|
gstring->str[gstring->len] = '\0';
|
||||||
return gstring;
|
return gstring;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define g_string_truncate(gstr,len) g_string_truncate_inline (gstr, len)
|
#define g_string_truncate(gstr,len) g_string_truncate_inline (gstr, len)
|
||||||
|
|
||||||
#if G_GNUC_CHECK_VERSION (2, 0)
|
#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
|
int
|
||||||
main (int argc,
|
main (int argc,
|
||||||
char *argv[])
|
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-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-to-bytes", test_string_to_bytes);
|
||||||
g_test_add_func ("/string/test-string-replace", test_string_replace);
|
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();
|
return g_test_run();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user