summaryrefslogtreecommitdiffstats
path: root/lib.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2015-10-17 19:58:00 -0700
committerKaz Kylheku <kaz@kylheku.com>2015-10-17 19:58:00 -0700
commitfc450ffb9cc44781fa50b789dd5394e3f8937b36 (patch)
tree55387d188854f77f205b6439d1eb222e552a7b2d /lib.c
parent3d95abc9d28983a21215c6156dd9d57374cfed53 (diff)
downloadtxr-fc450ffb9cc44781fa50b789dd5394e3f8937b36.tar.gz
txr-fc450ffb9cc44781fa50b789dd5394e3f8937b36.tar.bz2
txr-fc450ffb9cc44781fa50b789dd5394e3f8937b36.zip
New function chk_manage_vec.
This function manages a dynamic array using only the filled size as input, while minimizing reallocations. The allocated size is implicitly always the next power of two at or above the filled size. * lib.c (next_pow_two): New static function. (chk_manage_vec): New function. * lib.h (chk_manage_vec): Declared.
Diffstat (limited to 'lib.c')
-rw-r--r--lib.c49
1 files changed, 49 insertions, 0 deletions
diff --git a/lib.c b/lib.c
index 7e1ad0e8..15986952 100644
--- a/lib.c
+++ b/lib.c
@@ -2029,6 +2029,55 @@ mem_t *chk_grow_vec(mem_t *old, size_t oldelems, size_t newelems,
return chk_realloc(old, bytes);
}
+static size_t bounding_pow_two(size_t s)
+{
+ s -= 1;
+
+ s |= (s >> 1);
+ s |= (s >> 2);
+ s |= (s >> 4);
+ s |= (s >> 8);
+ s |= (s >> 16);
+
+ if (sizeof (size_t) * CHAR_BIT > 32) {
+ size_t t = s >> 16; /* suppress warning about s >> 32 */
+ s |= (t >> 16);
+ }
+
+ return s ? s + 1 : s;
+}
+
+mem_t *chk_manage_vec(mem_t *old, size_t oldfilled, size_t newfilled,
+ size_t elsize, mem_t *fillval)
+{
+ if (newfilled == 0) {
+ free(old);
+ return 0;
+ } else {
+ static const size_t no_oflow = convert(size_t, -1) >> (CHAR_BIT * sizeof(size_t) / 2);
+ size_t oldbytes = oldfilled * elsize;
+ size_t newbytes = newfilled * elsize;
+ size_t oldsize = bounding_pow_two(oldbytes);
+ size_t newsize = bounding_pow_two(newbytes);
+
+ if (((newfilled > no_oflow || elsize > no_oflow) &&
+ newbytes / elsize != newfilled) ||
+ (newsize < newbytes))
+ uw_throw(error_s, lit("array size overflow"));
+
+ if (oldsize != newsize)
+ old = chk_realloc(old, newsize);
+
+ if (fillval)
+ while (oldbytes < newbytes) {
+ memcpy(old + oldbytes, fillval, elsize);
+ oldbytes += elsize;
+ }
+
+ return old;
+ }
+}
+
wchar_t *chk_wmalloc(size_t nwchar)
{
size_t size = nwchar * sizeof (wchar_t);