git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v3 09/27] strvec: introduce new `strvec_splice()` function

From
Patrick Steinhardt <ps@pks.im>
Date
Nov 20, 2024, 13:39 UTC
Message-ID
<20241120-b4-pks-leak-fixes-pt10-v3-9-d67f08f45c74@pks.im>
In-Reply-To
<20241120-b4-pks-leak-fixes-pt10-v3-0-d67f08f45c74@pks.im>

Introduce a new `strvec_splice()` function that can replace a range of strings in the vector with another array of strings. This function will be used in subsequent commits.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 strvec.c              | 19 +++++++++++++++
 strvec.h              |  9 +++++++
 t/unit-tests/strvec.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 93 insertions(+)
diff --git a/strvec.c b/strvec.c
index f712070f5745d5f998d0846ac4009441dddfa500..d1cf4e2496a564c878f4b81207efe275abed72cf 100644
--- a/strvec.c
+++ b/strvec.c
@@ -56,6 +56,25 @@ void strvec_pushv(struct strvec *array, const char **items)
 		strvec_push(array, *items);
 }
 
+void strvec_splice(struct strvec *array, size_t idx, size_t len,
+		   const char **replacement, size_t replacement_len)
+{
+	if (idx + len > array->nr)
+		BUG("range outside of array boundary");
+	if (replacement_len > len)
+		ALLOC_GROW(array->v, array->nr + (replacement_len - len) + 1,
+			   array->alloc);
+	for (size_t i = 0; i < len; i++)
+		free((char *)array->v[idx + i]);
+	if (replacement_len != len) {
+		memmove(array->v + idx + replacement_len, array->v + idx + len,
+			(array->nr - idx - len + 1) * sizeof(char *));
+		array->nr += (replacement_len - len);
+	}
+	for (size_t i = 0; i < replacement_len; i++)
+		array->v[idx + i] = xstrdup(replacement[i]);
+}
+
 const char *strvec_replace(struct strvec *array, size_t idx, const char *replacement)
 {
 	char *to_free;
diff --git a/strvec.h b/strvec.h
index 4b73c1f092e9b016ce3299035477713c6267cdae..f74e061e1419bce7c3f3730d4dfdf081c8db094e 100644
--- a/strvec.h
+++ b/strvec.h
@@ -67,6 +67,15 @@ void strvec_pushl(struct strvec *, ...);
 /* Push a null-terminated array of strings onto the end of the array. */
 void strvec_pushv(struct strvec *, const char **);
 
+/*
+ * Replace `len` values starting at `idx` with the provided replacement
+ * strings. If `len` is zero this is effectively an insert at the given `idx`.
+ * If `replacement_len` is zero this is effectively a delete of `len` items
+ * starting at `idx`.
+ */
+void strvec_splice(struct strvec *array, size_t idx, size_t len,
+		   const char **replacement, size_t replacement_len);
+
 /**
  * Replace the value at the given index with a new value. The index must be
  * valid. Returns a pointer to the inserted value.
diff --git a/t/unit-tests/strvec.c b/t/unit-tests/strvec.c
index bf4c0cb172e1f01c452b8744084cc45bf3aa86fa..855b602337169f6fffcadf91e0734db44ceccb16 100644
--- a/t/unit-tests/strvec.c
+++ b/t/unit-tests/strvec.c
@@ -88,6 +88,71 @@ void test_strvec__pushv(void)
 	strvec_clear(&vec);
 }
 
+void test_strvec__splice_with_same_size_replacement(void)
+{
+	struct strvec vec = STRVEC_INIT;
+	const char *replacement[] = { "1" };
+
+	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+	strvec_splice(&vec, 1, 1, replacement, ARRAY_SIZE(replacement));
+	check_strvec(&vec, "foo", "1", "baz", NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__splice_with_smaller_replacement(void)
+{
+	struct strvec vec = STRVEC_INIT;
+	const char *replacement[] = { "1" };
+
+	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+	strvec_splice(&vec, 1, 2, replacement, ARRAY_SIZE(replacement));
+	check_strvec(&vec, "foo", "1", NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__splice_with_bigger_replacement(void)
+{
+	struct strvec vec = STRVEC_INIT;
+	const char *replacement[] = { "1", "2", "3" };
+
+	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+	strvec_splice(&vec, 0, 2, replacement, ARRAY_SIZE(replacement));
+	check_strvec(&vec, "1", "2", "3", "baz", NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__splice_with_empty_replacement(void)
+{
+	struct strvec vec = STRVEC_INIT;
+
+	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+	strvec_splice(&vec, 0, 2, NULL, 0);
+	check_strvec(&vec, "baz", NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__splice_with_empty_original(void)
+{
+	struct strvec vec = STRVEC_INIT;
+	const char *replacement[] = { "1", "2" };
+
+	strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+	strvec_splice(&vec, 1, 0, replacement, ARRAY_SIZE(replacement));
+	check_strvec(&vec, "foo", "1", "2", "bar", "baz", NULL);
+	strvec_clear(&vec);
+}
+
+void test_strvec__splice_at_tail(void)
+{
+	struct strvec vec = STRVEC_INIT;
+	const char *replacement[] = { "1", "2" };
+
+	strvec_pushl(&vec, "foo", "bar", NULL);
+	strvec_splice(&vec, 2, 0, replacement, ARRAY_SIZE(replacement));
+	check_strvec(&vec, "foo", "bar", "1", "2", NULL);
+	strvec_clear(&vec);
+}
+
 void test_strvec__replace_at_head(void)
 {
 	struct strvec vec = STRVEC_INIT;
-- 
2.47.0.274.g962d0b743d.dirty
Previous: Patrick SteinhardtNext: Patrick Steinhardt
Message 14 of 33 in “Memory leak fixes (pt.10, final)”
  1. 00/27 Memory leak fixes (pt.10, final)Patrick Steinhardt, Nov 20, 2024
  2. 01/27 builtin/blame: fix leaking blame entries with `--incremental`Patrick Steinhardt, Nov 20, 2024
  3. 02/27 bisect: fix leaking good/bad terms when reading multipe timesPatrick Steinhardt, Nov 20, 2024
  4. 04/27 bisect: fix leaking `current_bad_oid`Patrick Steinhardt, Nov 20, 2024
  5. 03/27 bisect: fix leaking string in `handle_bad_merge_base()`Patrick Steinhardt, Nov 20, 2024
  6. 05/27 bisect: fix multiple leaks in `bisect_next_all()`Patrick Steinhardt, Nov 20, 2024
  7. 06/27 bisect: fix leaking commit list items in `check_merge_base()`Patrick Steinhardt, Nov 20, 2024
  8. 07/27 bisect: fix various cases where we leak commit list itemsPatrick Steinhardt, Nov 20, 2024
  9. Jeff KingNov 25, 2024
  10. Patrick SteinhardtNov 25, 2024
  11. Jeff KingNov 25, 2024
  12. Patrick SteinhardtNov 25, 2024
  13. 08/27 line-log: fix leak when rewriting commit parentsPatrick Steinhardt, Nov 20, 2024
  14. 09/27 strvec: introduce new `strvec_splice()` functionPatrick Steinhardt, Nov 20, 2024
  15. 10/27 git: refactor alias handling to use a `struct strvec`Patrick Steinhardt, Nov 20, 2024
  16. 11/27 git: refactor builtin handling to use a `struct strvec`Patrick Steinhardt, Nov 20, 2024
  17. 12/27 split-index: fix memory leak in `move_cache_to_base_index()`Patrick Steinhardt, Nov 20, 2024
  18. 13/27 builtin/sparse-checkout: fix leaking sanitized patternsPatrick Steinhardt, Nov 20, 2024
  19. 14/27 help: refactor to not use globals for reading configPatrick Steinhardt, Nov 20, 2024
  20. 15/27 help: fix leaking `struct cmdnames`Patrick Steinhardt, Nov 20, 2024
  21. 16/27 help: fix leaking return value from `help_unknown_cmd()`Patrick Steinhardt, Nov 20, 2024
  22. 17/27 builtin/help: fix leaks in `check_git_cmd()`Patrick Steinhardt, Nov 20, 2024
  23. 18/27 builtin/init-db: fix leaking directory pathsPatrick Steinhardt, Nov 20, 2024
  24. 20/27 t/helper: fix leaking commit graph in "read-graph" subcommandPatrick Steinhardt, Nov 20, 2024
  25. 19/27 builtin/branch: fix leaking sorting optionsPatrick Steinhardt, Nov 20, 2024
  26. 21/27 global: drop `UNLEAK()` annotationPatrick Steinhardt, Nov 20, 2024
  27. 22/27 git-compat-util: drop now-unused `UNLEAK()` macroPatrick Steinhardt, Nov 20, 2024
  28. 23/27 t5601: work around leak sanitizer issuePatrick Steinhardt, Nov 20, 2024
  29. 24/27 t: mark some tests as leak freePatrick Steinhardt, Nov 20, 2024
  30. 25/27 t: remove unneeded !SANITIZE_LEAK prerequisitesPatrick Steinhardt, Nov 20, 2024
  31. 26/27 test-lib: unconditionally enable leak checkingPatrick Steinhardt, Nov 20, 2024
  32. 27/27 t: remove TEST_PASSES_SANITIZE_LEAK annotationsPatrick Steinhardt, Nov 20, 2024
  33. Toon ClaesNov 21, 2024

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.