ucx/buffer.c

changeset 888
af685cc9d623
parent 854
1c8401ece69e
--- a/ucx/buffer.c	Sun Aug 31 14:39:13 2025 +0200
+++ b/ucx/buffer.c	Sat Nov 08 23:06:11 2025 +0100
@@ -32,6 +32,24 @@
 #include <string.h>
 #include <errno.h>
 
+#ifdef _WIN32
+#include <Windows.h>
+#include <sysinfoapi.h>
+static unsigned long system_page_size() {
+    static unsigned long ps = 0;
+    if (ps == 0) {
+        SYSTEM_INFO sysinfo;
+        GetSystemInfo(&sysinfo);
+        ps = sysinfo.dwPageSize;
+    }
+    return ps;
+}
+#define SYSTEM_PAGE_SIZE system_page_size()
+#else
+#include <unistd.h>
+#define SYSTEM_PAGE_SIZE sysconf(_SC_PAGESIZE)
+#endif
+
 static int buffer_copy_on_write(CxBuffer* buffer) {
     if (0 == (buffer->flags & CX_BUFFER_COPY_ON_WRITE)) return 0;
     void *newspace = cxMalloc(buffer->allocator, buffer->capacity);
@@ -80,7 +98,7 @@
     CxBuffer *buffer,
     CxBufferFlushConfig config
 ) {
-    buffer->flush = malloc(sizeof(CxBufferFlushConfig));
+    buffer->flush = cxMallocDefault(sizeof(CxBufferFlushConfig));
     if (buffer->flush == NULL) return -1; // LCOV_EXCL_LINE
     memcpy(buffer->flush, &config, sizeof(CxBufferFlushConfig));
     return 0;
@@ -90,7 +108,7 @@
     if (buffer->flags & CX_BUFFER_FREE_CONTENTS) {
         cxFree(buffer->allocator, buffer->bytes);
     }
-    free(buffer->flush);
+    cxFreeDefault(buffer->flush);
     memset(buffer, 0, sizeof(CxBuffer));
 }
 
@@ -139,6 +157,7 @@
             npos = 0;
             break;
         default:
+            errno = EINVAL;
             return -1;
     }
 
@@ -146,11 +165,16 @@
     npos += offset;
 
     if ((offset > 0 && npos < opos) || (offset < 0 && npos > opos)) {
-        errno = EOVERFLOW;
+        // to be compliant with fseek() specification
+        // we return EINVAL on underflow
+        errno = EINVAL;
         return -1;
     }
 
     if (npos > buffer->size) {
+        // not compliant with fseek() specification
+        // but this is the better behavior for CxBuffer
+        errno = EINVAL;
         return -1;
     } else {
         buffer->pos = npos;
@@ -184,6 +208,28 @@
         return 0;
     }
 
+    unsigned long pagesize = SYSTEM_PAGE_SIZE;
+    // if page size is larger than 64 KB - for some reason - truncate to 64 KB
+    if (pagesize > 65536) pagesize = 65536;
+    if (newcap < pagesize) {
+        // when smaller as one page, map to the next power of two
+        newcap--;
+        newcap |= newcap >> 1;
+        newcap |= newcap >> 2;
+        newcap |= newcap >> 4;
+        // last operation only needed for pages larger 4096 bytes
+        // but if/else would be more expensive than just doing this
+        newcap |= newcap >> 8;
+        newcap++;
+    } else {
+        // otherwise, map to a multiple of the page size
+        newcap -= newcap % pagesize;
+        newcap += pagesize;
+        // note: if newcap is already page aligned,
+        // 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);
@@ -203,6 +249,28 @@
     }
 }
 
+void cxBufferShrink(
+        CxBuffer *buffer,
+        size_t reserve
+) {
+    // Ensure buffer is in a reallocatable state
+    const int force_copy_flags = CX_BUFFER_COPY_ON_WRITE | CX_BUFFER_COPY_ON_EXTEND;
+    if (buffer->flags & force_copy_flags) {
+        // do nothing when we are not allowed to reallocate
+        return;
+    }
+
+    // calculate new capacity
+    size_t newCapacity = buffer->size + reserve;
+
+    // If new capacity is smaller than current capacity, resize the buffer
+    if (newCapacity < buffer->capacity) {
+        if (0 == cxReallocate(buffer->allocator, &buffer->bytes, newCapacity)) {
+            buffer->capacity = newCapacity;
+        }
+    }
+}
+
 static size_t cx_buffer_flush_helper(
         const CxBuffer *buffer,
         const unsigned char *src,
@@ -399,10 +467,8 @@
 }
 
 int cxBufferTerminate(CxBuffer *buffer) {
-    bool success = 0 == cxBufferPut(buffer, 0);
-    if (success) {
-        buffer->pos--;
-        buffer->size--;
+    if (0 == cxBufferPut(buffer, 0)) {
+        buffer->size = buffer->pos - 1;
         return 0;
     } else {
         return -1;

mercurial