basic/strv: introduce strv_extend_strv_consume()

This commit is contained in:
Mike Yuan
2024-09-19 16:11:16 +02:00
parent 527b9e2437
commit 8a7ade7427
3 changed files with 104 additions and 5 deletions

View File

@@ -229,20 +229,18 @@ char** strv_new_internal(const char *x, ...) {
int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates) {
size_t p, q, i = 0;
char **t;
assert(a);
if (strv_isempty(b))
q = strv_length(b);
if (q == 0)
return 0;
p = strv_length(*a);
q = strv_length(b);
if (p >= SIZE_MAX - q)
return -ENOMEM;
t = reallocarray(*a, GREEDY_ALLOC_ROUND_UP(p + q + 1), sizeof(char *));
char **t = reallocarray(*a, GREEDY_ALLOC_ROUND_UP(p + q + 1), sizeof(char *));
if (!t)
return -ENOMEM;
@@ -271,9 +269,67 @@ rollback:
return -ENOMEM;
}
int strv_extend_strv_consume(char ***a, char **b, bool filter_duplicates) {
_cleanup_strv_free_ char **b_consume = b;
size_t p, q, i;
assert(a);
q = strv_length(b);
if (q == 0)
return 0;
p = strv_length(*a);
if (p == 0) {
strv_free_and_replace(*a, b_consume);
if (filter_duplicates)
strv_uniq(*a);
return strv_length(*a);
}
if (p >= SIZE_MAX - q)
return -ENOMEM;
char **t = reallocarray(*a, GREEDY_ALLOC_ROUND_UP(p + q + 1), sizeof(char *));
if (!t)
return -ENOMEM;
t[p] = NULL;
*a = t;
if (!filter_duplicates) {
*mempcpy_typesafe(t + p, b, q) = NULL;
i = q;
} else {
i = 0;
STRV_FOREACH(s, b) {
if (strv_contains(t, *s)) {
free(*s);
continue;
}
t[p+i] = *s;
i++;
t[p+i] = NULL;
}
}
assert(i <= q);
b_consume = mfree(b_consume);
return (int) i;
}
int strv_extend_strv_biconcat(char ***a, const char *prefix, const char* const *b, const char *suffix) {
int r;
assert(a);
STRV_FOREACH(s, b) {
char *v;

View File

@@ -44,10 +44,13 @@ int strv_copy_unless_empty(char * const *l, char ***ret);
size_t strv_length(char * const *l) _pure_;
int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates);
int strv_extend_strv_consume(char ***a, char **b, bool filter_duplicates);
int strv_extend_strv_biconcat(char ***a, const char *prefix, const char* const *b, const char *suffix);
static inline int strv_extend_strv_concat(char ***a, const char* const *b, const char *suffix) {
return strv_extend_strv_biconcat(a, NULL, b, suffix);
}
int strv_prepend(char ***l, const char *value);
/* _with_size() are lower-level functions where the size can be provided externally,

View File

@@ -660,6 +660,46 @@ TEST(strv_extend_strv) {
assert_se(strv_length(n) == 4);
}
TEST(strv_extend_strv_consume) {
_cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **n = NULL;
const char *s1, *s2, *s3;
ASSERT_NOT_NULL(a = strv_new("abc", "def", "ghi"));
ASSERT_NOT_NULL(b = strv_new("jkl", "mno", "abc", "pqr"));
s1 = b[0];
s2 = b[1];
s3 = b[3];
ASSERT_EQ(strv_extend_strv_consume(&a, TAKE_PTR(b), true), 3);
assert_se(s1 == a[3]);
assert_se(s2 == a[4]);
assert_se(s3 == a[5]);
ASSERT_STREQ(a[0], "abc");
ASSERT_STREQ(a[1], "def");
ASSERT_STREQ(a[2], "ghi");
ASSERT_STREQ(a[3], "jkl");
ASSERT_STREQ(a[4], "mno");
ASSERT_STREQ(a[5], "pqr");
ASSERT_EQ(strv_length(a), (size_t) 6);
ASSERT_NOT_NULL(c = strv_new("jkl", "mno"));
s1 = c[0];
s2 = c[1];
ASSERT_EQ(strv_extend_strv_consume(&n, TAKE_PTR(c), false), 2);
assert_se(s1 == n[0]);
assert_se(s2 == n[1]);
ASSERT_STREQ(n[0], "jkl");
ASSERT_STREQ(n[1], "mno");
ASSERT_EQ(strv_length(n), (size_t) 2);
}
TEST(strv_extend_with_size) {
_cleanup_strv_free_ char **a = NULL;
size_t n = SIZE_MAX;