]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
basic/strv: introduce strv_extend_strv_consume()
authorMike Yuan <me@yhndnzj.com>
Thu, 19 Sep 2024 14:11:16 +0000 (16:11 +0200)
committerMike Yuan <me@yhndnzj.com>
Fri, 20 Sep 2024 22:53:49 +0000 (00:53 +0200)
src/basic/strv.c
src/basic/strv.h
src/test/test-strv.c

index 0c3733a02b1d6aacf9a56f66d36a7adf262be9bf..542883ea3ff51ebd9b3d837dd2f68e62688bc548 100644 (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;
 
index 1ef3ea5faf8092b0fc295374c450567520b5e2c8..b9580f7634e4bf3f1b69c5f41fe35e18d20b8fa2 100644 (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,
index f7b6ee2bb2d1306d32330dafe346fe3ac2cb0a95..a35a2b10dc6bcdf002be37a029cec037d69bc6a7 100644 (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;