shared: add nm_utils_strv_dup_packed() util

(cherry picked from commit 2e0cd52474)
This commit is contained in:
Thomas Haller 2020-08-24 19:09:53 +02:00 committed by Beniamino Galvani
parent 00e72048d6
commit c067e55205
3 changed files with 119 additions and 0 deletions

View file

@ -3371,6 +3371,74 @@ nm_utils_strv_dup (gpointer 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

@ -1530,6 +1530,11 @@ char **nm_utils_strv_dup (gpointer strv,
gssize len,
gboolean 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

@ -771,6 +771,51 @@ test_nm_str_buf (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)
@ -792,6 +837,7 @@ int main (int argc, char **argv)
g_test_add_func ("/general/test_string_table_lookup", test_string_table_lookup);
g_test_add_func ("/general/test_nm_utils_get_next_realloc_size", test_nm_utils_get_next_realloc_size);
g_test_add_func ("/general/test_nm_str_buf", test_nm_str_buf);
g_test_add_func ("/general/test_strv_dup_packed", test_strv_dup_packed);
return g_test_run ();
}