Rework oversizing of CharBufs

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/6e1d5fd1
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/6e1d5fd1
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/6e1d5fd1

Branch: refs/heads/master
Commit: 6e1d5fd1a687eae61dc0609806c5269ba1e045fb
Parents: 641250d
Author: Nick Wellnhofer <wellnho...@aevum.de>
Authored: Thu Nov 12 15:35:33 2015 +0100
Committer: Nick Wellnhofer <wellnho...@aevum.de>
Committed: Thu Nov 12 16:09:44 2015 +0100

----------------------------------------------------------------------
 runtime/core/Clownfish/CharBuf.c | 69 +++++++++++++++++++++++++++++------
 1 file changed, 57 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/6e1d5fd1/runtime/core/Clownfish/CharBuf.c
----------------------------------------------------------------------
diff --git a/runtime/core/Clownfish/CharBuf.c b/runtime/core/Clownfish/CharBuf.c
index 0f1b7c3..fa7a2b3 100644
--- a/runtime/core/Clownfish/CharBuf.c
+++ b/runtime/core/Clownfish/CharBuf.c
@@ -33,6 +33,22 @@
 #include "Clownfish/Util/StringHelper.h"
 #include "Clownfish/Class.h"
 
+// Ensure that the CharBuf'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(CharBuf *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(CharBuf *self, size_t min_size);
+
+// Not inlining the THROW macro reduces code size and complexity of
+// SI_add_grow_and_oversize.
+static void
+S_overflow_error();
+
 // Helper function for throwing invalid UTF-8 error. Since THROW uses
 // a String internally, calling THROW with invalid UTF-8 would create an
 // infinite loop -- so we fwrite some of the bogus text to stderr and
@@ -261,11 +277,9 @@ CB_Yield_String_IMP(CharBuf *self) {
 void
 CB_Cat_Char_IMP(CharBuf *self, int32_t code_point) {
     const size_t MAX_UTF8_BYTES = 4;
-    if (self->size + MAX_UTF8_BYTES > self->cap) {
-        CB_Grow(self, Memory_oversize(self->size + MAX_UTF8_BYTES,
-                                     sizeof(char)));
-    }
-    char *end = self->ptr + self->size;
+    size_t old_size = self->size;
+    SI_add_grow_and_oversize(self, old_size, MAX_UTF8_BYTES);
+    char *end = self->ptr + old_size;
     size_t count = StrHelp_encode_utf8_char(code_point, (uint8_t*)end);
     self->size += count;
 }
@@ -283,13 +297,10 @@ CB_Clone_IMP(CharBuf *self) {
 
 static CFISH_INLINE void
 SI_cat_utf8(CharBuf *self, const char* ptr, size_t size) {
-    const size_t new_size = self->size + size;
-    if (new_size > self->cap) {
-        size_t amount = Memory_oversize(new_size, sizeof(char));
-        CB_Grow(self, amount);
-    }
-    memcpy(self->ptr + self->size, ptr, size);
-    self->size = new_size;
+    size_t old_size = self->size;
+    SI_add_grow_and_oversize(self, old_size, size);
+    memcpy(self->ptr + old_size, ptr, size);
+    self->size = old_size + size;
 }
 
 void
@@ -320,4 +331,38 @@ CB_Get_Size_IMP(CharBuf *self) {
     return self->size;
 }
 
+static CFISH_INLINE void
+SI_add_grow_and_oversize(CharBuf *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(CharBuf *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;
+    if (capacity < min_size) {
+        capacity = SIZE_MAX;
+    }
+
+    self->cap = capacity;
+    self->ptr = (char*)REALLOCATE(self->ptr, capacity);
+}
+
+static void
+S_overflow_error() {
+    THROW(ERR, "CharBuf buffer overflow");
+}
+
 

Reply via email to