diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2015-10-17 19:58:00 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2015-10-17 19:58:00 -0700 |
commit | fc450ffb9cc44781fa50b789dd5394e3f8937b36 (patch) | |
tree | 55387d188854f77f205b6439d1eb222e552a7b2d /lib.c | |
parent | 3d95abc9d28983a21215c6156dd9d57374cfed53 (diff) | |
download | txr-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.c | 49 |
1 files changed, 49 insertions, 0 deletions
@@ -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); |