# HG changeset patch # User Mike Becker # Date 1764195723 -3600 # Node ID f024313c08f1c172bea97e3f867b9af346305b6e # Parent ee5d668a71e4bee416594007e9ab347d3b2a078b add cxBufferReserve() diff -r ee5d668a71e4 -r f024313c08f1 docs/Writerside/topics/buffer.h.md --- a/docs/Writerside/topics/buffer.h.md Wed Nov 26 23:06:12 2025 +0100 +++ b/docs/Writerside/topics/buffer.h.md Wed Nov 26 23:22:03 2025 +0100 @@ -122,16 +122,22 @@ ```C #include +int cxBufferReserve(CxBuffer *buffer, size_t capacity); + int cxBufferMinimumCapacity(CxBuffer *buffer, size_t capacity); void cxBufferShrink(CxBuffer *buffer, size_t reserve); ``` -The function `cxBufferMinimumCapacity()` guarantees a buffer capacity of _at least_ `capacity`. -The actual capacity will be a power of two until the system's page size is reached. +The functions `cxBufferReserve()` and `cxBufferMinimumCapacity()` guarantee a buffer capacity of _at least_ `capacity`. +The difference is, that `cxBufferReserve()` will not increase the capacity beyond the specified `capacity`, +while `cxBufferMinimumCapacity()` will grow the capacity in powers of two until the system's page size is reached. Then, the new capacity will be a multiple of the page size. The function returns non-zero if increasing the capacity was attempted unsuccessfully. +You should use `cxBufferReserve()` when you know precisely the required capacity beforehand +and `cxBufferMinimumCapacity()` when it is likely that the buffer needs to regrow soon. + The function `cxBufferShrink()` can be used to shrink the capacity of the buffer to its current size plus a number of `reserve` bytes. If the current capacity is not larger than the size plus the reserve bytes, the function will do nothing. diff -r ee5d668a71e4 -r f024313c08f1 src/buffer.c --- a/src/buffer.c Wed Nov 26 23:06:12 2025 +0100 +++ b/src/buffer.c Wed Nov 26 23:22:03 2025 +0100 @@ -238,10 +238,30 @@ return buffer->pos >= buffer->size; } -int cxBufferMinimumCapacity( - CxBuffer *buffer, - size_t newcap -) { +int cxBufferReserve(CxBuffer *buffer, size_t newcap) { + if (newcap <= buffer->capacity) { + return 0; + } + const int force_copy_flags = CX_BUFFER_COPY_ON_WRITE | CX_BUFFER_COPY_ON_EXTEND; + if (buffer->flags & force_copy_flags) { + void *newspace = cxMalloc(buffer->allocator, newcap); + if (NULL == newspace) return -1; + memcpy(newspace, buffer->space, buffer->size); + buffer->space = newspace; + buffer->capacity = newcap; + buffer->flags &= ~force_copy_flags; + buffer->flags |= CX_BUFFER_FREE_CONTENTS; + return 0; + } else if (cxReallocate(buffer->allocator, + (void **) &buffer->bytes, newcap) == 0) { + buffer->capacity = newcap; + return 0; + } else { + return -1; // LCOV_EXCL_LINE + } +} + +int cxBufferMinimumCapacity(CxBuffer *buffer, size_t newcap) { if (newcap <= buffer->capacity) { return 0; } @@ -267,24 +287,7 @@ // this gives a full additional page (which is good) } - - const int force_copy_flags = CX_BUFFER_COPY_ON_WRITE | CX_BUFFER_COPY_ON_EXTEND; - if (buffer->flags & force_copy_flags) { - void *newspace = cxMalloc(buffer->allocator, newcap); - if (NULL == newspace) return -1; - memcpy(newspace, buffer->space, buffer->size); - buffer->space = newspace; - buffer->capacity = newcap; - buffer->flags &= ~force_copy_flags; - buffer->flags |= CX_BUFFER_FREE_CONTENTS; - return 0; - } else if (cxReallocate(buffer->allocator, - (void **) &buffer->bytes, newcap) == 0) { - buffer->capacity = newcap; - return 0; - } else { - return -1; // LCOV_EXCL_LINE - } + return cxBufferReserve(buffer, newcap); } void cxBufferShrink( diff -r ee5d668a71e4 -r f024313c08f1 src/cx/buffer.h --- a/src/cx/buffer.h Wed Nov 26 23:06:12 2025 +0100 +++ b/src/cx/buffer.h Wed Nov 26 23:22:03 2025 +0100 @@ -439,11 +439,30 @@ cx_attr_nonnull cx_attr_nodiscard CX_EXPORT bool cxBufferEof(const CxBuffer *buffer); +/** + * Ensures that the buffer has the required capacity. + * + * If the current capacity is not sufficient, the buffer will be extended. + * + * This function will reserve no more bytes than requested, in contrast to + * cxBufferMinimumCapacity(), which may reserve more bytes to improve the + * number of future necessary reallocations. + * + * @param buffer the buffer + * @param capacity the required capacity for this buffer + * @retval zero the capacity was already sufficient or successfully increased + * @retval non-zero on allocation failure + * @see cxBufferShrink() + * @see cxBufferMinimumCapacity() + */ +cx_attr_nonnull +CX_EXPORT int cxBufferReserve(CxBuffer *buffer, size_t capacity); /** * Ensures that the buffer has a minimum capacity. * - * If the current capacity is not sufficient, the buffer will be extended. + * If the current capacity is not sufficient, the buffer will be generously + * extended. * * The new capacity will be a power of two until the system's page size is reached. * Then, the new capacity will be a multiple of the page size. @@ -452,6 +471,7 @@ * @param capacity the minimum required capacity for this buffer * @retval zero the capacity was already sufficient or successfully increased * @retval non-zero on allocation failure + * @see cxBufferReserve() * @see cxBufferShrink() */ cx_attr_nonnull @@ -471,6 +491,7 @@ * * @param buffer the buffer * @param reserve the number of bytes that shall remain reserved + * @see cxBufferReserve() * @see cxBufferMinimumCapacity() */ cx_attr_nonnull