I'm working on my own generic-type dynamic array in C99 and I would like to hear your input, suggestions, ideas, anything!
What I most care about is: 1) correctness and 2) performance.
So far, I've tested both with standard malloc
and mimalloc, although with the standard implementation it seems to be running 50% faster.
I've also ran benchmarks against libsrt, vec and Nim's implementation of dynamic sequences and my code seems to be beating them all.
Also, of major importance is to note that this code is not meant to be used as a library, but as part of a bytecode VM/intepreter that I've been working on - which means I am the one who is going to use it.
Here's the source:
#ifndef __VARRAY_H__
#define __VARRAY_H__
/**************************************
Type definitions
**************************************/
#define Array(TYPE) \
struct { \
size_t size; \
size_t cap; \
size_t typeSize; \
TYPE *data; \
}
/**************************************
Macros
**************************************/
#define aInit(DEST,TYPE,CAP) { \
int k=0; \
while (powerOfTwo[++k]<CAP); \
\
DEST = malloc(sizeof(Array(TYPE))); \
DEST->size = 0; \
DEST->typeSize = sizeof(TYPE); \
DEST->cap = powerOfTwo[k]; \
DEST->data = calloc(DEST->cap, DEST->typeSize); \
}
#define aNew(NAME,TYPE,CAP) \
Array(TYPE)* NAME; \
aInit(NAME,TYPE,CAP);
#define aResize(DEST) { \
DEST->cap *= 2; \
DEST->data = realloc(DEST->data, DEST->cap * DEST->typeSize); \
}
#define aAdd(DEST,X) \
if (++(DEST->size) >= DEST->cap) aResize(DEST); \
DEST->data[DEST->size-1] = X
#define aAppend(DEST,X) \
DEST->cap += X->cap; \
DEST->data = realloc(DEST->data, DEST->cap * DEST->typeSize); \
memcpy(DEST->data + DEST->size, X->data, X->size * X->typeSize); \
DEST->size += X->size
#define aEach(DEST,INDEX) \
for (int INDEX=0; INDEX<DEST->size; INDEX++)
#define aFree(DEST) \
free(DEST->data); \
free(DEST)
#endif
The powerOfTwo
lookup constant:
/**************************************
Constants
**************************************/
static size_t powerOfTwo[] = {
0,
1, 2, 4, 8, 16, 32, 64, 128,
256, 512, 1024, 2048, 4096, 8192, 16384, 32768,
65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608,
16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648,
4294967296, 8589934592, 17179869184, 34359738368, 68719476736, 137438953472, 274877906944, 549755813888
};
And a little usage example:
Array(int)* arr;
aInit(arr,int,0);
aAdd(arr,0);
aAdd(arr,1);
aEach(fastArr,i) {
printf("item @ %d = %d\n",i,arr->data[i]);
}
aFree(arr);