142 lines
9.6 KiB
C
142 lines
9.6 KiB
C
#ifndef VESSEL_ARRAY_H_
|
|
#define VESSEL_ARRAY_H_
|
|
|
|
#include "conf.h"
|
|
|
|
#include "def.h"
|
|
#include "thread.h"
|
|
|
|
#include <string.h>
|
|
|
|
#define VS_ARRAY_INITAL_CAP 32
|
|
#define VS_ARRAY_GROWTH_FACTOR 2
|
|
|
|
/* Generic array */
|
|
|
|
#define VS_G_ARRAY_APPEND(arr, item) \
|
|
do { \
|
|
if ((arr)->size >= (arr)->cap) { \
|
|
(arr)->cap = \
|
|
(arr)->cap == 0 ? VS_ARRAY_INITAL_CAP : ((arr)->cap * VS_ARRAY_GROWTH_FACTOR); \
|
|
(arr)->items = VS_REALLOC((arr)->items, (arr)->cap * sizeof(*(arr)->items)); \
|
|
} \
|
|
(arr)->items[(arr)->size++] = (item); \
|
|
} while (0)
|
|
|
|
#define VS_G_ARRAY_DESTROY(arr) VS_FREE((arr)->items)
|
|
|
|
/* Typed array */
|
|
|
|
#define VS_ARRAY_DECLARE_STRUCT(name, type) \
|
|
struct name { \
|
|
size_t cap, size; \
|
|
Lock lock; \
|
|
(type) * items; \
|
|
}; \
|
|
bool name##_init((name) * a); \
|
|
bool name##_grow((name) * a); \
|
|
bool name##_append((name) * a, const type item); \
|
|
bool name##_clear((name) * a); \
|
|
bool name##_copy((name) * a, (name) * b); \
|
|
bool name##_pop((name) * a, (type) * out); \
|
|
bool name##_destroy((name) * a)
|
|
|
|
#define VS_ARRAY_DECLARE(name, type) \
|
|
ARRAY_DECLARE_STRUCT(name, type); \
|
|
typedef struct name name
|
|
|
|
#define VS_ARRAY_DEFINE(name, type) \
|
|
bool name##_init(struct name *a) { \
|
|
if (!a) \
|
|
return false; \
|
|
if (!Lock_init(&a->lock)) \
|
|
return false; \
|
|
if (!Lock_lock(&a->lock)) { \
|
|
Lock_destroy(&a->lock); \
|
|
return false; \
|
|
} \
|
|
a->cap = VS_ARRAY_INITAL_CAP; \
|
|
a->size = 0; \
|
|
a->items = VS_MALLOC(sizeof(*a->items) * a->cap); \
|
|
if (!a->items) { \
|
|
Lock_unlock(&a->lock); \
|
|
Lock_destroy(&a->lock); \
|
|
return false; \
|
|
} \
|
|
return Lock_unlock(&a->lock); \
|
|
} \
|
|
bool name##_grow(struct name *a) { \
|
|
(type) * new_items; \
|
|
const size_t new_cap = sizeof(*a->items) * a->cap * VS_ARRAY_GROWTH_FACTOR; \
|
|
if (!a || !Lock_lock(&a->lock)) \
|
|
return false; \
|
|
new_items = VS_REALLOC(a->items, new_cap); \
|
|
if (!new_items) { \
|
|
Lock_unlock(&a->lock); \
|
|
return false; \
|
|
} \
|
|
a->items = new_items; \
|
|
a->cap = new_cap; \
|
|
return Lock_unlock(&a->lock); \
|
|
} \
|
|
bool name##_append(struct name *a, const type item) { \
|
|
if (!a || !Lock_lock(&a->lock)) \
|
|
return false; \
|
|
if (!Lock_unlock(&a->lock)) \
|
|
return false; \
|
|
if ((a->size + 1) >= a->cap && !name##_grow(a)) \
|
|
return false; \
|
|
if (!Lock_lock(&a->lock)) \
|
|
return false; \
|
|
a->items[a->size++] = item; \
|
|
return Lock_unlock(&a->lock); \
|
|
} \
|
|
bool name##_clear(struct name *a) { \
|
|
if (!a || !Lock_lock(&a->lock)) \
|
|
return false; \
|
|
a->size = 0; \
|
|
return Lock_unlock(&a->lock); \
|
|
} \
|
|
bool name##_copy(struct name *a, struct name *b) { \
|
|
if (!a || !b) \
|
|
return false; \
|
|
if (!Lock_lock(&a->lock)) \
|
|
return false; \
|
|
if (!Lock_lock(&b->lock)) { \
|
|
Lock_unlock(&a->lock); \
|
|
return false; \
|
|
} \
|
|
b->cap = a->cap; \
|
|
b->size = a->size; \
|
|
b->items = VS_MALLOC(sizeof(*b->items) * b->cap); \
|
|
if (!b->items) { \
|
|
Lock_unlock(&a->lock); \
|
|
Lock_unlock(&b->lock); \
|
|
return false; \
|
|
} \
|
|
memmove(b->items, a->items, sizeof(*b->items) * b->cap); \
|
|
const bool al = Lock_unlock(&a->lock); \
|
|
const bool bl = Lock_unlock(&b->lock); \
|
|
return al && bl; \
|
|
} \
|
|
bool name##_pop(struct name *a, struct type *out) { \
|
|
if (!a || !out || !Lock_lock(&a->lock)) \
|
|
return false; \
|
|
if (a->size == 0) { \
|
|
Lock_unlock(&a->lock); \
|
|
return false; \
|
|
} \
|
|
*out = a->items[--a->size]; \
|
|
return Lock_unlock(&a->lock); \
|
|
} \
|
|
bool name##_destroy(struct name *a) { \
|
|
if (!Lock_lock(&a->lock)) \
|
|
return false; \
|
|
VS_FREE(a->items); \
|
|
const bool al = Lock_unlock(&a->lock); \
|
|
const bool bl = Lock_destroy(&a->lock); \
|
|
return al && bl; \
|
|
} \
|
|
const bool __##name##_defined__ = true
|
|
|
|
#endif /* VESSEL_ARRAY_H_ */
|