Rework allocation and oversizing of ByteBufs

Always round up capacity to next multiple of eight.

Don't call Memory_oversize, but oversize by custom amount of 25%.

Check for integer overflow. This should only matter on exotic platforms,
but it doesn't cost much.


Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/7165ca56
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/7165ca56
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/7165ca56

Branch: refs/heads/master
Commit: 7165ca565d24596191eb8c417d3af1523dcf1a1d
Parents: 8c4b290
Author: Nick Wellnhofer <wellnho...@aevum.de>
Authored: Wed Dec 9 14:55:53 2015 +0100
Committer: Nick Wellnhofer <wellnho...@aevum.de>
Committed: Wed Dec 9 15:04:01 2015 +0100

----------------------------------------------------------------------
 runtime/core/Clownfish/ByteBuf.c | 107 ++++++++++++++++++++++++----------
 1 file changed, 77 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/7165ca56/runtime/core/Clownfish/ByteBuf.c
----------------------------------------------------------------------
diff --git a/runtime/core/Clownfish/ByteBuf.c b/runtime/core/Clownfish/ByteBuf.c
index 3ab5ddd..14ede6f 100644
--- a/runtime/core/Clownfish/ByteBuf.c
+++ b/runtime/core/Clownfish/ByteBuf.c
@@ -29,8 +29,21 @@
 #include "Clownfish/String.h"
 #include "Clownfish/Util/Memory.h"
 
+// Ensure that the ByteBuf's capacity is at least (size + extra).
+// If the buffer must be grown, oversize the allocation.
+static CFISH_INLINE void
+SI_add_grow_and_oversize(ByteBuf *self, size_t size, size_t extra);
+
+// Compilers tend to inline this function although this is the unlikely
+// slow path. If we ever add cross-platform support for the noinline
+// attribute, it should be marked as such to reduce code size.
+static void
+S_grow_and_oversize(ByteBuf *self, size_t min_size);
+
+// Not inlining the THROW macro reduces code size and complexity of
+// SI_add_grow_and_oversize.
 static void
-S_grow(ByteBuf *self, size_t size);
+S_overflow_error();
 
 ByteBuf*
 BB_new(size_t capacity) {
@@ -39,12 +52,15 @@ BB_new(size_t capacity) {
 }
 
 ByteBuf*
-BB_init(ByteBuf *self, size_t capacity) {
-    size_t amount = capacity ? capacity : sizeof(int64_t);
-    self->buf   = NULL;
-    self->size  = 0;
-    self->cap   = 0;
-    S_grow(self, amount);
+BB_init(ByteBuf *self, size_t min_cap) {
+    // Round up to next multiple of eight.
+    size_t capacity = (min_cap + 7) & ~7;
+    // Check for overflow.
+    if (capacity < min_cap) { capacity = SIZE_MAX; }
+
+    self->buf  = (char*)MALLOCATE(capacity);
+    self->size = 0;
+    self->cap  = capacity;
     return self;
 }
 
@@ -56,9 +72,15 @@ BB_new_bytes(const void *bytes, size_t size) {
 
 ByteBuf*
 BB_init_bytes(ByteBuf *self, const void *bytes, size_t size) {
-    BB_init(self, size);
-    memcpy(self->buf, bytes, size);
+    // Round up to next multiple of eight.
+    size_t capacity = (size + 7) & ~7;
+    // Check for overflow.
+    if (capacity < size) { capacity = SIZE_MAX; }
+
+    self->buf  = (char*)MALLOCATE(capacity);
     self->size = size;
+    self->cap  = capacity;
+    memcpy(self->buf, bytes, size);
     return self;
 }
 
@@ -133,12 +155,9 @@ BB_Equals_Bytes_IMP(ByteBuf *self, const void *bytes, 
size_t size) {
 
 static CFISH_INLINE void
 SI_cat_bytes(ByteBuf *self, const void *bytes, size_t size) {
-    const size_t new_size = self->size + size;
-    if (new_size > self->cap) {
-        S_grow(self, Memory_oversize(new_size, sizeof(char)));
-    }
-    memcpy((self->buf + self->size), bytes, size);
-    self->size = new_size;
+    SI_add_grow_and_oversize(self, self->size, size);
+    memcpy(self->buf + self->size, bytes, size);
+    self->size += size;
 }
 
 void
@@ -151,23 +170,18 @@ BB_Cat_IMP(ByteBuf *self, Blob *blob) {
     SI_cat_bytes(self, Blob_Get_Buf(blob), Blob_Get_Size(blob));
 }
 
-static void
-S_grow(ByteBuf *self, size_t size) {
-    if (size > self->cap) {
-        size_t amount    = size;
-        size_t remainder = amount % sizeof(int64_t);
-        if (remainder) {
-            amount += sizeof(int64_t);
-            amount -= remainder;
-        }
-        self->buf = (char*)REALLOCATE(self->buf, amount);
-        self->cap = amount;
+char*
+BB_Grow_IMP(ByteBuf *self, size_t min_cap) {
+    if (min_cap > self->cap) {
+        // Round up to next multiple of eight.
+        size_t capacity = (min_cap + 7) & ~7;
+        // Check for overflow.
+        if (capacity < min_cap) { capacity = SIZE_MAX; }
+
+        self->buf = (char*)REALLOCATE(self->buf, capacity);
+        self->cap = capacity;
     }
-}
 
-char*
-BB_Grow_IMP(ByteBuf *self, size_t size) {
-    if (size > self->cap) { S_grow(self, size); }
     return self->buf;
 }
 
@@ -204,4 +218,37 @@ BB_Compare_To_IMP(ByteBuf *self, Obj *other) {
     return comparison;
 }
 
+static CFISH_INLINE void
+SI_add_grow_and_oversize(ByteBuf *self, size_t size, size_t extra) {
+    size_t min_size = size + extra;
+    if (min_size < size) {
+        S_overflow_error();
+        return;
+    }
+
+    if (min_size > self->cap) {
+        S_grow_and_oversize(self, min_size);
+    }
+}
+
+static void
+S_grow_and_oversize(ByteBuf *self, size_t min_size) {
+    // Oversize by 25%, but at least eight bytes.
+    size_t extra = min_size / 4;
+    // Round up to next multiple of eight.
+    extra = (extra + 7) & ~7;
+
+    size_t capacity = min_size + extra;
+    // Check for overflow.
+    if (capacity < min_size) { capacity = SIZE_MAX; }
+
+    self->buf = (char*)REALLOCATE(self->buf, capacity);
+    self->cap = capacity;
+}
+
+static void
+S_overflow_error() {
+    THROW(ERR, "ByteBuf buffer overflow");
+}
+
 

Reply via email to