shared: add nm_utils_strv_dup_packed() util

This commit is contained in:
Thomas Haller
2020-08-24 19:09:53 +02:00
parent c25f4d947a
commit 2e0cd52474
3 changed files with 119 additions and 0 deletions

View File

@@ -3422,6 +3422,74 @@ _nm_utils_strv_dup (const char *const*strv,
return v;
}
const char **
_nm_utils_strv_dup_packed (const char *const*strv,
gssize len)
{
const char **result;
gsize mem_len;
gsize pre_len;
gsize len2;
char *sbuf;
gsize i;
nm_assert (len >= -1);
mem_len = 0;
if (G_LIKELY (len < 0)) {
if ( !strv
|| !strv[0]) {
/* This function never returns an empty strv array. If you need that, handle it
* yourself. */
return NULL;
}
for (i = 0; strv[i]; i++)
mem_len += strlen (strv[i]);
len2 = i;
} else {
if (len == 0)
return NULL;
len2 = len;
for (i = 0; i < len; i++) {
if (G_LIKELY (strv[i]))
mem_len += strlen (strv[i]);
}
}
mem_len += len2;
pre_len = sizeof (const char *) * (len2 + 1u);
result = g_malloc (pre_len + mem_len);
sbuf = &(((char *) result)[pre_len]);
for (i = 0; i < len2; i++) {
gsize l;
if (G_UNLIKELY (!strv[i])) {
/* Technically there is no problem with accepting NULL strings. But that
* does not really result in a strv array, and likely this only happens due
* to a bug. We want to catch such bugs by asserting.
*
* We clear the remainder of the buffer and fail with an assertion. */
len2++;
for (; i < len2; i++)
result[i] = NULL;
g_return_val_if_reached (result);;
}
result[i] = sbuf;
l = strlen (strv[i]) + 1u;
memcpy (sbuf, strv[i], l);
sbuf += l;
}
result[i] = NULL;
nm_assert (i == len2);
nm_assert (sbuf == (&((const char *) result)[pre_len]) + mem_len);
return result;
}
/*****************************************************************************/
gssize

View File

@@ -1533,6 +1533,11 @@ char **_nm_utils_strv_dup (const char *const*strv,
#define nm_utils_strv_dup(strv, len, deep_copied) _nm_utils_strv_dup (NM_CAST_STRV_CC (strv), (len), (deep_copied))
const char **_nm_utils_strv_dup_packed (const char *const*strv,
gssize len);
#define nm_utils_strv_dup_packed(strv, len) _nm_utils_strv_dup_packed (NM_CAST_STRV_CC (strv), (len))
/*****************************************************************************/
GSList *nm_utils_g_slist_find_str (const GSList *list,

View File

@@ -941,6 +941,51 @@ test_is_specific_hostname (void)
/*****************************************************************************/
static void
test_strv_dup_packed (void)
{
gs_unref_ptrarray GPtrArray *src = NULL;
int i_run;
src = g_ptr_array_new_with_free_func (g_free);
for (i_run = 0; i_run < 500; i_run++) {
const int strv_len = nmtst_get_rand_word_length (NULL);
gs_free const char **strv_cpy = NULL;
const char *const*strv_src;
int i, j;
g_ptr_array_set_size (src, 0);
for (i = 0; i < strv_len; i++) {
const int word_len = nmtst_get_rand_word_length (NULL);
NMStrBuf sbuf = NM_STR_BUF_INIT (0, nmtst_get_rand_bool ());
for (j = 0; j < word_len; j++)
nm_str_buf_append_c (&sbuf, 'a' + (nmtst_get_rand_uint32 () % 20));
g_ptr_array_add (src, nm_str_buf_finalize (&sbuf, NULL) ?: g_new0 (char, 1));
}
g_ptr_array_add (src, NULL);
strv_src = (const char *const*) src->pdata;
g_assert (strv_src);
g_assert (NM_PTRARRAY_LEN (strv_src) == strv_len);
strv_cpy = nm_utils_strv_dup_packed (strv_src,
nmtst_get_rand_bool () ? (gssize) strv_len : (gssize) -1);
if (strv_len == 0)
g_assert (!strv_cpy);
else
g_assert (strv_cpy);
g_assert (NM_PTRARRAY_LEN (strv_cpy) == strv_len);
if (strv_cpy)
g_assert (_nm_utils_strv_equal ((char **) strv_cpy, (char **) strv_src));
}
}
/*****************************************************************************/
NMTST_DEFINE ();
int main (int argc, char **argv)
@@ -965,6 +1010,7 @@ int main (int argc, char **argv)
g_test_add_func ("/general/test_nm_utils_parse_next_line", test_nm_utils_parse_next_line);
g_test_add_func ("/general/test_in_strset_ascii_case", test_in_strset_ascii_case);
g_test_add_func ("/general/test_is_specific_hostname", test_is_specific_hostname);
g_test_add_func ("/general/test_strv_dup_packed", test_strv_dup_packed);
return g_test_run ();
}