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)
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;
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++;
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);
*/
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);
}
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();