Commit 72c8508d authored by Swann Perarnau's avatar Swann Perarnau

[feature] add generic vector type to library

Add a generic vector type to the library, with some special features:
- the elements are embedded in the vector, and not pointers
- each element must include an int field that is used as a "key"
- the element has a "null" value for its key, used to indicate that this
element of the vector is null.
- add/remove functions provide access to a new element/free it from the
vector, but don't "destroy" it.
- resize on add is exponential.

This patch includes implementation and unit test.
parent be88fe46
...@@ -23,7 +23,10 @@ DMA_CSOURCES = dma.c \ ...@@ -23,7 +23,10 @@ DMA_CSOURCES = dma.c \
SCRATCH_CSOURCES = scratch.c \ SCRATCH_CSOURCES = scratch.c \
scratch_seq.c scratch_seq.c
UTILS_CSOURCES = vector.c
LIBCSOURCES = aml.c area.c arena.c \ LIBCSOURCES = aml.c area.c arena.c \
$(UTILS_CSOURCES) \
$(ARENA_JEMALLOC_CSOURCES) \ $(ARENA_JEMALLOC_CSOURCES) \
$(AREA_LINUX_CSOURCES) \ $(AREA_LINUX_CSOURCES) \
$(AREA_POSIX_CSOURCES) \ $(AREA_POSIX_CSOURCES) \
......
...@@ -24,6 +24,38 @@ ...@@ -24,6 +24,38 @@
struct aml_area; struct aml_area;
struct aml_binding; struct aml_binding;
/*******************************************************************************
* Generic vector type:
* Vector of nbelems, each of size sz, with a comparison key at offset off
******************************************************************************/
#define AML_VECTOR_ELTKEY_P(v,e) ((int *)(((intptr_t) e) + v->off))
#define AML_VECTOR_KEY_P(v,i) ((int *)(((intptr_t) v->ptr) + i*v->sz + v->off))
#define AML_VECTOR_ELT_P(v,i) ((void *)(((intptr_t) v->ptr) + i*v->sz))
struct aml_vector {
int na;
size_t nbelems;
size_t sz;
size_t off;
void *ptr;
};
/* not needed, here for consistency */
#define AML_VECTOR_DECL(name) struct vector ##name;
#define AML_VECTOR_ALLOCSIZE (sizeof(struct vector))
size_t aml_vector_size(struct aml_vector *vec);
void *aml_vector_get(struct aml_vector *vec, int idx);
int aml_vector_find(struct aml_vector *vec, int key);
int aml_vector_resize(struct aml_vector *vec, size_t newsize);
void *aml_vector_add(struct aml_vector *vec);
void aml_vector_remove(struct aml_vector *vec, void *elem);
int aml_vector_init(struct aml_vector *vec, size_t num, size_t size,
size_t key, int na);
int aml_vector_destroy(struct aml_vector *vec);
/******************************************************************************* /*******************************************************************************
* Arenas: * Arenas:
* In-memory allocator implementation. Dispatches actual memory mappings back to * In-memory allocator implementation. Dispatches actual memory mappings back to
......
#include <aml.h>
#include <assert.h>
#include <errno.h>
/*******************************************************************************
* Vector type:
* generic vector of elements, with contiguous allocation: elements are part of
* the vector.
* This type supports one unusual feature: elements must contain an int key, at
* a static offset, and this key as configurable "null" value.
******************************************************************************/
int aml_vector_resize(struct aml_vector *vec, size_t newsize)
{
assert(vec != NULL);
/* we don't shrink */
if(vec->nbelems > newsize)
return 0;
vec->ptr = realloc(vec->ptr, newsize * vec->sz);
assert(vec->ptr != NULL);
for(int i = vec->nbelems; i < newsize; i++)
{
int *k = AML_VECTOR_KEY_P(vec, i);
*k = vec->na;
}
vec->nbelems = newsize;
return 0;
}
size_t aml_vector_size(struct aml_vector *vec)
{
assert(vec != NULL);
return vec->nbelems;
}
/* returns pointer to elements at index id */
void *aml_vector_get(struct aml_vector *vec, int id)
{
assert(vec != NULL);
if(id != vec->na && id < vec->nbelems)
return AML_VECTOR_ELT_P(vec, id);
else
return NULL;
}
/* return index of first element with key */
int aml_vector_find(struct aml_vector *vec, int key)
{
assert(vec != NULL);
for(int i = 0; i < vec->nbelems; i++)
{
int *k = AML_VECTOR_KEY_P(vec, i);
if(*k == key)
return i;
}
return vec->na;
}
void *aml_vector_add(struct aml_vector *vec)
{
assert(vec != NULL);
int idx = aml_vector_find(vec, vec->na);
if(idx == vec->na)
{
/* exponential growth, good to amortize cost */
idx = vec->nbelems;
aml_vector_resize(vec, vec->nbelems *2);
}
return AML_VECTOR_ELT_P(vec, idx);
}
void aml_vector_remove(struct aml_vector *vec, void *elem)
{
assert(vec != NULL);
assert(elem != NULL);
assert(elem >= vec->ptr && elem < AML_VECTOR_ELT_P(vec, vec->nbelems));
int *k = AML_VECTOR_ELTKEY_P(vec, elem);
*k = vec->na;
}
/*******************************************************************************
* Init/destroy:
******************************************************************************/
int aml_vector_init(struct aml_vector *vec, size_t reserve, size_t size,
size_t key, int na)
{
assert(vec != NULL);
vec->sz = size;
vec->off = key;
vec->na = na;
vec->nbelems = reserve;
vec->ptr = calloc(reserve, size);
assert(vec->ptr != NULL);
for(int i = 0; i < vec->nbelems; i++)
{
int *k = AML_VECTOR_KEY_P(vec, i);
*k = na;
}
return 0;
}
int aml_vector_destroy(struct aml_vector *vec)
{
assert(vec != NULL);
free(vec->ptr);
return 0;
}
...@@ -9,6 +9,8 @@ if TEST_VALGRIND ...@@ -9,6 +9,8 @@ if TEST_VALGRIND
TESTS_ENVIRONMENT= @LIBTOOL@ --mode=execute @VALGRIND@ --tool=memcheck -q --leak-check=full TESTS_ENVIRONMENT= @LIBTOOL@ --mode=execute @VALGRIND@ --tool=memcheck -q --leak-check=full
endif endif
UTILS_TESTS = vector
ARENA_JEMALLOC_TESTS = arena_jemalloc ARENA_JEMALLOC_TESTS = arena_jemalloc
AREA_LINUX_TESTS = linux_mbind \ AREA_LINUX_TESTS = linux_mbind \
...@@ -29,6 +31,7 @@ SCRATCH_TESTS = scratch_seq ...@@ -29,6 +31,7 @@ SCRATCH_TESTS = scratch_seq
# unit tests # unit tests
UNIT_TESTS = $(ARENA_JEMALLOC_TESTS) \ UNIT_TESTS = $(ARENA_JEMALLOC_TESTS) \
$(UTILS_TESTS) \
$(TILING_TESTS) \ $(TILING_TESTS) \
$(BINDING_TESTS) \ $(BINDING_TESTS) \
$(AREA_LINUX_TESTS) \ $(AREA_LINUX_TESTS) \
......
#include <aml.h>
#include <assert.h>
int main(int argc, char *argv[])
{
struct aml_vector v;
/* no need for library initialization */
;
/* struct to test the offsets */
struct test {
unsigned long unused;
int key;
};
assert(!aml_vector_init(&v, 1, sizeof(struct test),
offsetof(struct test, key), -1));
/* assert the size */
assert(aml_vector_size(&v) == 1);
/* add an element and look for some */
struct test *e = aml_vector_get(&v, 0);
assert(e != NULL);
e->unused = 42;
e->key = 24;
assert(aml_vector_find(&v, 24) == 0);
assert(aml_vector_find(&v, 42) == -1);
/* add a second element, trigger a resize, and check it */
struct test *f = aml_vector_add(&v);
assert(f != NULL && f->key == -1);
assert(aml_vector_find(&v, 42) == -1);
assert(aml_vector_find(&v, -1) == 1);
assert(aml_vector_size(&v) == 2);
aml_vector_destroy(&v);
return 0;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment