]> git.ipfire.org Git - thirdparty/kmod.git/commitdiff
strbuf: Add strbuf_reserve_extra()
authorLucas De Marchi <lucas.de.marchi@gmail.com>
Tue, 12 Nov 2024 18:07:39 +0000 (12:07 -0600)
committerLucas De Marchi <lucas.de.marchi@gmail.com>
Sun, 17 Nov 2024 21:35:13 +0000 (15:35 -0600)
To accomplish the same task as scratchbuf_alloc() does: make sure the
buffer has enough space for next operations. One difference is that
ensures **extra** space, not the total space. If needed in future,
a strbuf_reserve(), that resembles C++'s std::vector::reserve(), can be
added on top.

Signed-off-by: Lucas De Marchi <lucas.de.marchi@gmail.com>
Reviewed-by: Emil Velikov <emil.l.velikov@gmail.com>
Link: https://github.com/kmod-project/kmod/pull/239
shared/strbuf.c
shared/strbuf.h
testsuite/test-strbuf.c

index 836101c897cfc030b692d4ce3105df6c9662435f..5a25976c3b1408c71ec43230f5496b806f496312 100644 (file)
@@ -34,15 +34,18 @@ static bool buf_realloc(struct strbuf *buf, size_t sz)
        return true;
 }
 
-static bool buf_grow(struct strbuf *buf, size_t newsize)
+bool strbuf_reserve_extra(struct strbuf *buf, size_t n)
 {
-       if (newsize <= buf->size)
+       if (uaddsz_overflow(buf->used, n, &n))
+               return false;
+
+       if (n <= buf->size)
                return true;
 
-       if (newsize % BUF_STEP)
-               newsize = ((newsize / BUF_STEP) + 1) * BUF_STEP;
+       if (n % BUF_STEP)
+               n = ((n / BUF_STEP) + 1) * BUF_STEP;
 
-       return buf_realloc(buf, newsize);
+       return buf_realloc(buf, n);
 }
 
 void strbuf_init(struct strbuf *buf)
@@ -75,7 +78,7 @@ char *strbuf_steal(struct strbuf *buf)
 
 const char *strbuf_str(struct strbuf *buf)
 {
-       if (!buf_grow(buf, buf->used + 1))
+       if (!strbuf_reserve_extra(buf, 1))
                return NULL;
        buf->bytes[buf->used] = '\0';
        return buf->bytes;
@@ -83,7 +86,7 @@ const char *strbuf_str(struct strbuf *buf)
 
 bool strbuf_pushchar(struct strbuf *buf, char ch)
 {
-       if (!buf_grow(buf, buf->used + 1))
+       if (!strbuf_reserve_extra(buf, 1))
                return false;
        buf->bytes[buf->used] = ch;
        buf->used++;
@@ -99,7 +102,7 @@ size_t strbuf_pushchars(struct strbuf *buf, const char *str)
 
        len = strlen(str);
 
-       if (!buf_grow(buf, buf->used + len))
+       if (!strbuf_reserve_extra(buf, len))
                return 0;
 
        memcpy(buf->bytes + buf->used, str, len);
index b2aa946ef84ede790c461717d680e15495c4b0e4..d916d0af42e5055903d36f519c192d9c7c4f0318 100644 (file)
@@ -62,6 +62,11 @@ char *strbuf_steal(struct strbuf *buf);
  */
 const char *strbuf_str(struct strbuf *buf);
 
+/*
+ * Reserve enough space for @n bytes, ensuring additional pushes up to @n bytes
+ * don't cause re-allocations
+ */
+bool strbuf_reserve_extra(struct strbuf *buf, size_t n);
 bool strbuf_pushchar(struct strbuf *buf, char ch);
 size_t strbuf_pushchars(struct strbuf *buf, const char *str);
 
index 1c8f6040e54a6c79714d5f7764b6729d3fc931a6..45c9eec7ebdd23494b4bcc62892870e691003081 100644 (file)
@@ -163,4 +163,26 @@ static int test_strbuf_with_heap(const struct test *t)
 }
 DEFINE_TEST(test_strbuf_with_heap, .description = "test strbuf with heap only");
 
+static int test_strbuf_reserve_extra(const struct test *t)
+{
+       _cleanup_strbuf_ struct strbuf buf;
+       size_t size;
+
+       strbuf_init(&buf);
+       strbuf_reserve_extra(&buf, strlen(TEXT) + 1);
+       size = buf.size;
+       assert_return(size >= strlen(TEXT) + 1, EXIT_FAILURE);
+
+       strbuf_pushchars(&buf, TEXT);
+       strbuf_pushchar(&buf, '\0');
+       assert_return(size == buf.size, EXIT_FAILURE);
+
+       strbuf_clear(&buf);
+       strbuf_pushchars(&buf, TEXT);
+       assert_return(size == buf.size, EXIT_FAILURE);
+
+       return 0;
+}
+DEFINE_TEST(test_strbuf_reserve_extra, .description = "test strbuf_reserve_extra");
+
 TESTSUITE_MAIN();