diff options
Diffstat (limited to 'src/nm-core-utils.c')
-rw-r--r-- | src/nm-core-utils.c | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index 6cdd00e0d7..3529839f35 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -3018,3 +3018,163 @@ nm_utils_lifetime_get (guint32 timestamp, return TRUE; } +/***************************************************************************** + * NMRefString + *****************************************************************************/ + +#ifdef NM_MORE_ASSERTS +#define NM_STRING_CANARY(s) (GPOINTER_TO_UINT (s) ^ ((guint) 30112031329)) +#endif + +typedef struct _NMString { +#ifdef NM_STRING_CANARY + guint _canary; +#endif + int ref_count; + char str[1]; +} _NMString; + +static inline _NMString * +_nm_ref_string_up_cast (NMRefString nmstr) +{ + _NMString *s; + + s = (_NMString *) (((char *) nmstr) - G_STRUCT_OFFSET (_NMString, str)); +#ifdef NM_STRING_CANARY + g_return_val_if_fail (s->_canary == NM_STRING_CANARY (s), NULL); +#endif + g_return_val_if_fail (s->ref_count > 0, NULL); + + nm_assert (s->str == nmstr); + + return s; +} + +NMRefString +nm_ref_string_new (const char *str) +{ + _NMString *s; + gsize len; + + if (!str) + return NULL; + + len = strlen (str) + 1; + + s = g_malloc (G_STRUCT_OFFSET (_NMString, str) + len); + s->ref_count = 1; +#ifdef NM_STRING_CANARY + s->_canary = NM_STRING_CANARY (s); +#endif + memcpy (s->str, str, len); + return s->str; +} + +NMRefString +nm_ref_string_ref (NMRefString nmstr) +{ + _NMString *s; + + if (!nmstr) + return NULL; + + s = _nm_ref_string_up_cast (nmstr); + g_return_val_if_fail (s, NULL); + + s->ref_count++; + return s->str; +} + +void +nm_ref_string_unref (NMRefString nmstr) +{ + _NMString *s; + + if (!nmstr) + return; + + s = _nm_ref_string_up_cast (nmstr); + g_return_if_fail (s); + + if (--s->ref_count <= 0) { +#ifdef NM_STRING_CANARY + s->_canary = 0; +#endif + g_free (s); + } +} + +NMRefString +nm_ref_string_dedup (NMRefString nmstr, const char *str) +{ + /* The difference between replace and dedup is, that + * replace in any case decrements the refcount on nmstr. Thus, + * with replace you hand ownership of nmstr over. + * + * with dedup, the caller keeps ownership, but if possible, + * the reference will be reused/shared. + **/ + + if (!nmstr) + return nm_ref_string_new (str); + if (!str) + return NULL; + + if (strcmp (nmstr, str) == 0) + return nm_ref_string_ref (nmstr); + return nm_ref_string_new (str); +} + +NMRefString +nm_ref_string_replace (NMRefString nmstr, const char *str) +{ + _NMString *s, *s2; + gsize len; + + if (!nmstr) + return nm_ref_string_new (str); + if (!str) { + nm_ref_string_unref (nmstr); + return NULL; + } + + s = _nm_ref_string_up_cast (nmstr); + g_return_val_if_fail (s, NULL); + + if (strcmp (s->str, str) == 0) + return nmstr; + + if (s->ref_count == 1) { + len = strlen (str) + 1; + + s2 = g_realloc (s, G_STRUCT_OFFSET (_NMString, str) + len); + +#ifdef NM_STRING_CANARY + s2->_canary = NM_STRING_CANARY (s2); +#endif + memcpy (s2->str, str, len); + return s2->str; + } else { + s->ref_count--; + return nm_ref_string_new (str); + } +} + +int +nm_ref_string_cmp (NMRefString nmstr1, NMRefString nmstr2) +{ + if (nmstr1 == nmstr2) + return 0; + if (!nmstr1) + return -1; + if (!nmstr2) + return 1; + return strcmp (nmstr1, nmstr2); +} + +gboolean +nm_ref_string_equal (NMRefString nmstr1, NMRefString nmstr2) +{ + return nm_ref_string_cmp (nmstr1, nmstr2) == 0; +} + |