diff options
-rw-r--r-- | src/NetworkManagerUtils.c | 124 | ||||
-rw-r--r-- | src/NetworkManagerUtils.h | 6 | ||||
-rw-r--r-- | src/tests/test-general-with-expect.c | 52 |
3 files changed, 182 insertions, 0 deletions
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index fdaa31cd77..7757643b29 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -2713,3 +2713,127 @@ nm_utils_setpgid (gpointer unused G_GNUC_UNUSED) pid = getpid (); setpgid (pid, pid); } + +/****************************************************************** + * 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_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); + } +} + +/******************************************************************/ + diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index 7624715264..c0ce323781 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -201,4 +201,10 @@ gboolean nm_utils_get_testing_initialized (void); NMUtilsTestFlags nm_utils_get_testing (void); void _nm_utils_set_testing (NMUtilsTestFlags flags); +typedef const char *NMRefString; +NMRefString nm_ref_string_new (const char *str); +NMRefString nm_ref_string_ref (NMRefString nmstr); +void nm_ref_string_unref (NMRefString nmstr); +NMRefString nm_ref_string_replace (NMRefString nmstr, const char *str); + #endif /* __NETWORKMANAGER_UTILS_H__ */ diff --git a/src/tests/test-general-with-expect.c b/src/tests/test-general-with-expect.c index 9491801d42..300ed2145d 100644 --- a/src/tests/test-general-with-expect.c +++ b/src/tests/test-general-with-expect.c @@ -35,6 +35,57 @@ /*******************************************/ static void +test_nm_ref_string (void) +{ + const char *nm_str, *s1, *s2; + + nm_str = nm_ref_string_new ("hallo"); + + g_assert_cmpstr (nm_str, ==, "hallo"); + + nm_ref_string_ref (nm_str); + g_assert_cmpstr (nm_str, ==, "hallo"); + + nm_ref_string_unref (nm_str); + g_assert_cmpstr (nm_str, ==, "hallo"); + + nm_str = nm_ref_string_replace (nm_str, "hallo"); + g_assert_cmpstr (nm_str, ==, "hallo"); + + nm_str = nm_ref_string_replace (nm_str, "hallo2"); + g_assert_cmpstr (nm_str, ==, "hallo2"); + + nm_ref_string_unref (nm_str); + + /* replace() reallocs old memory if ref-count is 1. */ + s1 = nm_ref_string_new ("abcdef"); + g_assert_cmpstr (s1, ==, "abcdef"); + s2 = nm_ref_string_replace (s1, "ABC"); + g_assert_cmpstr (s2, ==, "ABC"); + nm_ref_string_unref (s2); + + /* replace() reallocs old memory if ref-count is 1. */ + s1 = nm_ref_string_new ("ABC"); + g_assert_cmpstr (s1, ==, "ABC"); + s2 = nm_ref_string_replace (s1, "abcdef"); + g_assert_cmpstr (s2, ==, "abcdef"); + nm_ref_string_unref (s2); + + /* replace allocates new memory if ref-count larger 1. */ + s1 = nm_ref_string_new ("ABC"); + g_assert_cmpstr (s1, ==, "ABC"); + nm_ref_string_ref (s1); + s2 = nm_ref_string_replace (s1, "abcdef"); + g_assert_cmpstr (s2, ==, "abcdef"); + g_assert_cmpstr (s1, ==, "ABC"); + g_assert (s1 != s2); + nm_ref_string_unref (s2); + nm_ref_string_unref (s1); +} + +/*******************************************/ + +static void test_nm_utils_monotonic_timestamp_as_boottime (void) { gint64 timestamp_ns_per_tick, now, now_boottime, now_boottime_2, now_boottime_3; @@ -501,6 +552,7 @@ main (int argc, char **argv) { nmtst_init_assert_logging (&argc, &argv, "DEBUG", "DEFAULT"); + g_test_add_func ("/general/nm_ref_string", test_nm_ref_string); g_test_add_func ("/general/nm_utils_monotonic_timestamp_as_boottime", test_nm_utils_monotonic_timestamp_as_boottime); g_test_add_func ("/general/nm_utils_kill_child", test_nm_utils_kill_child); g_test_add_func ("/general/nm_utils_array_remove_at_indexes", test_nm_utils_array_remove_at_indexes); |