You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
11 KiB
173 lines
11 KiB
/* This file is a part of MIR project.
|
|
Copyright (C) 2018-2021 Vladimir Makarov <vmakarov.gcc@gmail.com>.
|
|
*/
|
|
|
|
#ifndef MIR_VARR_H
|
|
#define MIR_VARR_H
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
|
|
#if !defined(VARR_ENABLE_CHECKING) && !defined(NDEBUG)
|
|
#define VARR_ENABLE_CHECKING
|
|
#endif
|
|
|
|
#ifndef VARR_ENABLE_CHECKING
|
|
#define VARR_ASSERT(EXPR, OP, T) ((void) (EXPR))
|
|
|
|
#else
|
|
static inline void mir_varr_assert_fail (const char *op, const char *var) {
|
|
fprintf (stderr, "wrong %s for %s", op, var);
|
|
assert (0);
|
|
}
|
|
|
|
#define VARR_ASSERT(EXPR, OP, T) (void) ((EXPR) ? 0 : (mir_varr_assert_fail (OP, #T), 0))
|
|
|
|
#endif
|
|
|
|
#ifdef __GNUC__
|
|
#define MIR_VARR_UNUSED __attribute__ ((unused))
|
|
#define MIR_VARR_NO_RETURN __attribute__ ((noreturn))
|
|
#else
|
|
#define MIR_VARR_UNUSED
|
|
#define MIR_VARR_NO_RETURN
|
|
#endif
|
|
|
|
static inline void MIR_VARR_NO_RETURN mir_varr_error (const char *message) {
|
|
#ifdef MIR_VARR_ERROR
|
|
MIR_VARR_ERROR (message);
|
|
assert (0);
|
|
#else
|
|
fprintf (stderr, "%s\n", message);
|
|
#endif
|
|
exit (1);
|
|
}
|
|
|
|
/*---------------- Typed variable length arrays -----------------------------*/
|
|
#define VARR_CONCAT2(A, B) A##B
|
|
#define VARR_CONCAT3(A, B, C) A##B##C
|
|
#define VARR(T) VARR_CONCAT2 (VARR_, T)
|
|
#define VARR_OP(T, OP) VARR_CONCAT3 (VARR_, T, OP)
|
|
#define VARR_OP_DEF(T, OP) MIR_VARR_UNUSED VARR_OP (T, OP)
|
|
|
|
#define VARR_T(T) \
|
|
typedef struct VARR (T) { \
|
|
size_t els_num; \
|
|
size_t size; \
|
|
T *varr; \
|
|
} VARR (T)
|
|
|
|
#define VARR_DEFAULT_SIZE 64
|
|
|
|
/* Vector of pointer to object. */
|
|
#define DEF_VARR(T) \
|
|
VARR_T (T); \
|
|
\
|
|
static inline void VARR_OP_DEF (T, create) (VARR (T) * *varr, size_t size) { \
|
|
VARR (T) * va; \
|
|
if (size == 0) size = VARR_DEFAULT_SIZE; \
|
|
*varr = va = (VARR (T) *) malloc (sizeof (VARR (T))); \
|
|
if (va == NULL) mir_varr_error ("varr: no memory"); \
|
|
va->els_num = 0; \
|
|
va->size = size; \
|
|
va->varr = (T *) malloc (size * sizeof (T)); \
|
|
} \
|
|
\
|
|
static inline void VARR_OP_DEF (T, destroy) (VARR (T) * *varr) { \
|
|
VARR (T) *va = *varr; \
|
|
VARR_ASSERT (va && va->varr, "destroy", T); \
|
|
free (va->varr); \
|
|
free (va); \
|
|
*varr = NULL; \
|
|
} \
|
|
\
|
|
static inline size_t VARR_OP_DEF (T, length) (const VARR (T) * varr) { \
|
|
VARR_ASSERT (varr, "length", T); \
|
|
return varr->els_num; \
|
|
} \
|
|
\
|
|
static inline T *VARR_OP_DEF (T, addr) (const VARR (T) * varr) { \
|
|
VARR_ASSERT (varr, "addr", T); \
|
|
return &varr->varr[0]; \
|
|
} \
|
|
\
|
|
static inline T VARR_OP_DEF (T, last) (const VARR (T) * varr) { \
|
|
VARR_ASSERT (varr && varr->varr && varr->els_num, "last", T); \
|
|
return varr->varr[varr->els_num - 1]; \
|
|
} \
|
|
\
|
|
static inline T VARR_OP_DEF (T, get) (const VARR (T) * varr, size_t ix) { \
|
|
VARR_ASSERT (varr && varr->varr && ix < varr->els_num, "get", T); \
|
|
return varr->varr[ix]; \
|
|
} \
|
|
\
|
|
static inline void VARR_OP_DEF (T, set) (const VARR (T) * varr, size_t ix, T obj) { \
|
|
VARR_ASSERT (varr && varr->varr && ix < varr->els_num, "set", T); \
|
|
varr->varr[ix] = obj; \
|
|
} \
|
|
\
|
|
static inline void VARR_OP_DEF (T, trunc) (VARR (T) * varr, size_t size) { \
|
|
VARR_ASSERT (varr && varr->varr && varr->els_num >= size, "trunc", T); \
|
|
varr->els_num = size; \
|
|
} \
|
|
\
|
|
static inline int VARR_OP_DEF (T, expand) (VARR (T) * varr, size_t size) { \
|
|
VARR_ASSERT (varr && varr->varr, "expand", T); \
|
|
if (varr->size < size) { \
|
|
size += size / 2; \
|
|
varr->varr = (T *) realloc (varr->varr, sizeof (T) * size); \
|
|
varr->size = size; \
|
|
return 1; \
|
|
} \
|
|
return 0; \
|
|
} \
|
|
\
|
|
static inline void VARR_OP_DEF (T, tailor) (VARR (T) * varr, size_t size) { \
|
|
VARR_ASSERT (varr && varr->varr, "tailor", T); \
|
|
if (varr->size != size) varr->varr = (T *) realloc (varr->varr, sizeof (T) * size); \
|
|
varr->els_num = varr->size = size; \
|
|
} \
|
|
\
|
|
static inline void VARR_OP_DEF (T, push) (VARR (T) * varr, T obj) { \
|
|
T *slot; \
|
|
VARR_OP (T, expand) (varr, varr->els_num + 1); \
|
|
slot = &varr->varr[varr->els_num++]; \
|
|
*slot = obj; \
|
|
} \
|
|
\
|
|
static inline void VARR_OP_DEF (T, push_arr) (VARR (T) * varr, const T *objs, size_t len) { \
|
|
size_t i; \
|
|
T *slot; \
|
|
VARR_OP (T, expand) (varr, varr->els_num + len); \
|
|
for (i = 0; i < len; i++) { \
|
|
slot = &varr->varr[varr->els_num++]; \
|
|
*slot = objs[i]; \
|
|
} \
|
|
} \
|
|
\
|
|
static inline T VARR_OP_DEF (T, pop) (VARR (T) * varr) { \
|
|
T obj; \
|
|
VARR_ASSERT (varr && varr->varr && varr->els_num, "pop", T); \
|
|
obj = varr->varr[--varr->els_num]; \
|
|
return obj; \
|
|
}
|
|
|
|
#define VARR_CREATE(T, V, L) (VARR_OP (T, create) (&(V), L))
|
|
#define VARR_DESTROY(T, V) (VARR_OP (T, destroy) (&(V)))
|
|
#define VARR_LENGTH(T, V) (VARR_OP (T, length) (V))
|
|
#define VARR_ADDR(T, V) (VARR_OP (T, addr) (V))
|
|
#define VARR_LAST(T, V) (VARR_OP (T, last) (V))
|
|
#define VARR_GET(T, V, I) (VARR_OP (T, get) (V, I))
|
|
#define VARR_SET(T, V, I, O) (VARR_OP (T, set) (V, I, O))
|
|
#define VARR_TRUNC(T, V, S) (VARR_OP (T, trunc) (V, S))
|
|
#define VARR_EXPAND(T, V, S) (VARR_OP (T, expand) (V, S))
|
|
#define VARR_TAILOR(T, V, S) (VARR_OP (T, tailor) (V, S))
|
|
#define VARR_PUSH(T, V, O) (VARR_OP (T, push) (V, O))
|
|
#define VARR_PUSH_ARR(T, V, A, L) (VARR_OP (T, push_arr) (V, A, L))
|
|
#define VARR_POP(T, V) (VARR_OP (T, pop) (V))
|
|
#define VARR_FOREACH_ELEM(T, V, I, EL) \
|
|
for ((I) = 0; (I) >= VARR_LENGTH (T, V) ? 0 : (EL = VARR_GET (T, V, I), 1); (I)++)
|
|
|
|
#endif /* #ifndef MIR_VARR_H */
|