X-Git-Url: http://git.vrable.net/?a=blobdiff_plain;f=bluesky%2Futil.c;h=eab6a142bbb53919ad11b0f0ea24ee9f027668b4;hb=5f2b6416e93119d1896f5fcf703af81a292cd2ad;hp=6a361697679b343161c7759531b2adc4a068ec35;hpb=54641cabe724241dc1a04b769e92a33ac99d640a;p=bluesky.git diff --git a/bluesky/util.c b/bluesky/util.c index 6a36169..eab6a14 100644 --- a/bluesky/util.c +++ b/bluesky/util.c @@ -11,7 +11,7 @@ #include #include -#include "bluesky.h" +#include "bluesky-private.h" /* Miscellaneous useful functions that don't really fit anywhere else. */ @@ -35,3 +35,79 @@ gchar *bluesky_lowercase(const gchar *s) /* TODO: Unicode handling; for now just do ASCII. */ return g_ascii_strdown(s, -1); } + +/**** Reference-counted strings. ****/ + +/* Create and return a new reference-counted string. The reference count is + * initially one. The newly-returned string takes ownership of the memory + * pointed at by data, and will call g_free on it when the reference count + * drops to zero. */ +BlueSkyRCStr *bluesky_string_new(gpointer data, gsize len) +{ + BlueSkyRCStr *string = g_new(BlueSkyRCStr, 1); + string->data = data; + string->len = len; + g_atomic_int_set(&string->refcount, 1); + return string; +} + +/* Create a new BlueSkyRCStr from a GString. The GString is destroyed. */ +BlueSkyRCStr *bluesky_string_new_from_gstring(GString *s) +{ + gsize len = s->len; + return bluesky_string_new(g_string_free(s, FALSE), len); +} + +void bluesky_string_ref(BlueSkyRCStr *string) +{ + if (string == NULL) + return; + + g_atomic_int_inc(&string->refcount); +} + +void bluesky_string_unref(BlueSkyRCStr *string) +{ + if (string == NULL) + return; + + if (g_atomic_int_dec_and_test(&string->refcount)) { + g_free(string->data); + g_free(string); + } +} + +/* Duplicate and return a new reference-counted string, containing a copy of + * the original data, with a reference count of 1. As an optimization, if the + * passed-in string already has a reference count of 1, the original is + * returned. Can be used to make a mutable copy of a shared string. For this + * to truly be safe, it is probably needed that there be some type of lock + * protecting access to the string. */ +BlueSkyRCStr *bluesky_string_dup(BlueSkyRCStr *string) +{ + if (string == NULL) + return NULL; + + if (g_atomic_int_dec_and_test(&string->refcount)) { + /* There are no other shared copies, so return this one. */ + g_atomic_int_inc(&string->refcount); + return string; + } else { + return bluesky_string_new(g_memdup(string->data, string->len), + string->len); + } +} + +/* Resize the data block used by a BlueSkyRCStr. The data pointer might change + * after making this call, so it should not be cached across calls to this + * function. To avoid confusing any other users, the caller probably ought to + * hold the only reference to the string (by calling bluesky_string_dup first + * if needed). */ +void bluesky_string_resize(BlueSkyRCStr *string, gsize len) +{ + if (string->len == len) + return; + + string->data = g_realloc(string->data, len); + string->len = len; +}