--- a/src/buffer.c Sun Dec 15 15:23:29 2024 +0100 +++ b/src/buffer.c Wed Dec 18 15:35:42 2024 +0100 @@ -31,6 +31,19 @@ #include <stdio.h> #include <string.h> +static int buffer_copy_on_write(CxBuffer* buffer, size_t newcap) { + if (0 == (buffer->flags & CX_BUFFER_COPY_ON_WRITE)) return 0; + if (newcap == 0) newcap = buffer->capacity; + 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 &= ~CX_BUFFER_COPY_ON_WRITE; + buffer->flags |= CX_BUFFER_FREE_CONTENTS; + return 0; +} + int cxBufferInit( CxBuffer *buffer, void *space, @@ -46,7 +59,7 @@ if (!space) { buffer->bytes = cxMalloc(allocator, capacity); if (buffer->bytes == NULL) { - return 1; + return -1; } buffer->flags |= CX_BUFFER_FREE_CONTENTS; } else { @@ -66,7 +79,7 @@ } void cxBufferDestroy(CxBuffer *buffer) { - if ((buffer->flags & CX_BUFFER_FREE_CONTENTS) == CX_BUFFER_FREE_CONTENTS) { + if (buffer->flags & CX_BUFFER_FREE_CONTENTS) { cxFree(buffer->allocator, buffer->bytes); } } @@ -133,7 +146,9 @@ } void cxBufferClear(CxBuffer *buffer) { - memset(buffer->bytes, 0, buffer->size); + if (0 == (buffer->flags & CX_BUFFER_COPY_ON_WRITE)) { + memset(buffer->bytes, 0, buffer->size); + } buffer->size = 0; buffer->pos = 0; } @@ -155,7 +170,9 @@ return 0; } - if (cxReallocate(buffer->allocator, + if (buffer->flags & CX_BUFFER_COPY_ON_WRITE) { + return buffer_copy_on_write(buffer, newcap); + } else if (cxReallocate(buffer->allocator, (void **) &buffer->bytes, newcap) == 0) { buffer->capacity = newcap; return 0; @@ -207,6 +224,7 @@ ) { // optimize for easy case if (size == 1 && (buffer->capacity - buffer->pos) >= nitems) { + if (buffer_copy_on_write(buffer, 0)) return 0; memcpy(buffer->bytes + buffer->pos, ptr, nitems); buffer->pos += nitems; if (buffer->pos > buffer->size) { @@ -227,7 +245,7 @@ bool perform_flush = false; if (required > buffer->capacity) { - if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND && required) { + if (buffer->flags & CX_BUFFER_AUTO_EXTEND) { if (buffer->flush_blkmax > 0 && required > buffer->flush_threshold) { perform_flush = true; } else { @@ -293,6 +311,7 @@ return cxBufferWrite(ptr, size, nitems, buffer); } } else { + if (buffer_copy_on_write(buffer, 0)) return 0; memcpy(buffer->bytes + buffer->pos, ptr, len); buffer->pos += len; if (buffer->pos > buffer->size) { @@ -323,7 +342,7 @@ buffer->size--; return 0; } else { - return 1; + return -1; } } @@ -376,6 +395,7 @@ if (shift >= buffer->size) { buffer->pos = buffer->size = 0; } else { + if (buffer_copy_on_write(buffer, 0)) return -1; memmove(buffer->bytes, buffer->bytes + shift, buffer->size - shift); buffer->size -= shift; @@ -397,9 +417,9 @@ // auto extend buffer, if required and enabled if (buffer->capacity < req_capacity) { - if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) { + if (buffer->flags & CX_BUFFER_AUTO_EXTEND) { if (cxBufferMinimumCapacity(buffer, req_capacity)) { - return 1; + return -1; } movebytes = buffer->size; } else { @@ -409,8 +429,11 @@ movebytes = buffer->size; } - memmove(buffer->bytes + shift, buffer->bytes, movebytes); - buffer->size = shift + movebytes; + if (movebytes > 0) { + if (buffer_copy_on_write(buffer, 0)) return -1; + memmove(buffer->bytes + shift, buffer->bytes, movebytes); + buffer->size = shift + movebytes; + } buffer->pos += shift; if (buffer->pos > buffer->size) {