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;
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;
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,
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;