Instead of a malloc(3)'d struct bvector having a pointer to a separately
malloc'd area for the bits in the normal case of the default initial
size, have non-malloc'd storage in the struct itself, and set the
pointer to that. It's two unsigned longs, which is less than the
previous default of 256 bits for struct bvector, but still double the
pre-bvector norm of one word on 32 and 64-bit architectures.
This halves the mallocs needed to create a struct bvector in the common
case, but does mean that embedded memory is wasted should it not be
enough. That's probably an unusual case. It also means derefencing the
pointer to the bits probably hits the same cache line.
Have separate initial sizes for string and int vectors.
#include <h/mh.h>
#include <h/utils.h>
#include <h/mh.h>
#include <h/utils.h>
-#define VEC_INIT_SIZE 256
+#define BVEC_INIT_SIZE (sizeof *(((bvector_t)NULL)->tiny) * CHAR_BIT)
+#define SVEC_INIT_SIZE 256
+#define IVEC_INIT_SIZE 256
/*
* These try to hide the type of the "bits" member of bvector. But if
/*
* These try to hide the type of the "bits" member of bvector. But if
struct bvector {
unsigned long *bits;
size_t maxsize;
struct bvector {
unsigned long *bits;
size_t maxsize;
};
static void bvector_resize (bvector_t, size_t);
};
static void bvector_resize (bvector_t, size_t);
assert (sizeof *vec->bits <= sizeof 1ul);
NEW(vec);
assert (sizeof *vec->bits <= sizeof 1ul);
NEW(vec);
- bytes = BVEC_BYTES(init_size ? init_size : VEC_INIT_SIZE);
+ if (init_size <= BVEC_INIT_SIZE) {
+ vec->bits = vec->tiny;
+ vec->maxsize = BVEC_INIT_SIZE;
+ memset(vec->tiny, 0, sizeof vec->tiny);
+ return vec;
+ }
+
+ bytes = BVEC_BYTES(init_size);
vec->bits = mh_xcalloc (1, bytes);
vec->maxsize = bytes * CHAR_BIT;
vec->bits = mh_xcalloc (1, bytes);
vec->maxsize = bytes * CHAR_BIT;
bvector_copy (bvector_t dest, bvector_t src) {
size_t bytes = BVEC_BYTES(src->maxsize);
bvector_copy (bvector_t dest, bvector_t src) {
size_t bytes = BVEC_BYTES(src->maxsize);
+ if (dest->bits != dest->tiny)
+ free(dest->bits);
dest->bits = mh_xmalloc (bytes);
memcpy (dest->bits, src->bits, bytes);
dest->maxsize = src->maxsize;
dest->bits = mh_xmalloc (bytes);
memcpy (dest->bits, src->bits, bytes);
dest->maxsize = src->maxsize;
void
bvector_free (bvector_t vec) {
void
bvector_free (bvector_t vec) {
+ if (vec->bits != vec->tiny)
+ free(vec->bits);
while ((vec->maxsize *= 2) < maxsize)
;
bytes = BVEC_BYTES(vec->maxsize);
while ((vec->maxsize *= 2) < maxsize)
;
bytes = BVEC_BYTES(vec->maxsize);
- vec->bits = mh_xrealloc (vec->bits, bytes);
+ if (vec->bits == vec->tiny) {
+ vec->bits = mh_xmalloc(bytes);
+ memcpy(vec->bits, vec->tiny, sizeof vec->tiny);
+ } else
+ vec->bits = mh_xrealloc(vec->bits, bytes);
for (i = old_maxsize; i < vec->maxsize; ++i)
bvector_clear (vec, i);
}
for (i = old_maxsize; i < vec->maxsize; ++i)
bvector_clear (vec, i);
}
- vec->maxsize = init_size ? init_size : VEC_INIT_SIZE;
+ vec->maxsize = init_size ? init_size : SVEC_INIT_SIZE;
bytes = vec->maxsize * sizeof (char *);
vec->strs = mh_xcalloc (1, bytes);
vec->size = 0;
bytes = vec->maxsize * sizeof (char *);
vec->strs = mh_xcalloc (1, bytes);
vec->size = 0;
- vec->maxsize = init_size ? init_size : VEC_INIT_SIZE;
+ vec->maxsize = init_size ? init_size : IVEC_INIT_SIZE;
bytes = vec->maxsize * sizeof (int);
vec->ints = mh_xcalloc (1, bytes);
vec->size = 0;
bytes = vec->maxsize * sizeof (int);
vec->ints = mh_xcalloc (1, bytes);
vec->size = 0;