230 lines
5.2 KiB
C
Executable File
230 lines
5.2 KiB
C
Executable File
#ifndef LIST_H
|
|
#define LIST_H
|
|
// possible todo: overload macros to be able to pass them the header too
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
#include "types/types.h"
|
|
#include "bit/bit.h"
|
|
|
|
|
|
struct list_header {
|
|
u32 cap;
|
|
u32 size;
|
|
int tsize;
|
|
int type;
|
|
};
|
|
|
|
enum LIST_TYPE {
|
|
LIST_STATIC,
|
|
LIST_DYNAMIC,
|
|
LIST_NAIVE_DYNAMIC,
|
|
};
|
|
|
|
|
|
#define LIST(T) typeof(T) *
|
|
#define LIST_INIT_CAP 31
|
|
|
|
#define list_header(l) ({ \
|
|
(l) ? (struct list_header *)(((void*)l) - sizeof(struct list_header)) : NULL; \
|
|
})
|
|
|
|
#define list_cap(l) ({ \
|
|
struct list_header *h = list_header(l); \
|
|
h != NULL ? h->cap : 0; \
|
|
})
|
|
|
|
#define list_size(l) ({ \
|
|
struct list_header *h = list_header(l); \
|
|
h != NULL ? h->size : 0; \
|
|
})
|
|
|
|
#define list_tsize(l) ({ \
|
|
struct list_header *h = list_header(l); \
|
|
h != NULL ? h->tsize : 0; \
|
|
})
|
|
|
|
#define list_type(l) ({ \
|
|
struct list_header *h = list_header(l); \
|
|
h != NULL ? h->type : 0; \
|
|
})
|
|
|
|
#define list_full(l) ({ \
|
|
struct list_header *h = list_header(l); \
|
|
h->size < h->cap ? false : true; \
|
|
})
|
|
|
|
#define init_slist(l, n) ({ \
|
|
_init_list((void**)&(l), n, sizeof(*(l)), LIST_STATIC); \
|
|
})
|
|
|
|
#define init_dlist(l) ({ \
|
|
_init_list((void**)&(l), LIST_INIT_CAP, sizeof(*(l)), LIST_DYNAMIC); \
|
|
})
|
|
|
|
#define init_nlist(l) ({ \
|
|
_init_list((void**)&(l), 1, sizeof(*(l)), LIST_NAIVE_DYNAMIC); \
|
|
})
|
|
|
|
// if you init with 2 arguments, you init a static list. otherwise,
|
|
// a dynamic list. naive list has to be explicitly initialized
|
|
#define _choose_init(_1, _2, NAME, ...) NAME
|
|
#define init_list(...) _choose_init(__VA_ARGS__, init_slist, init_dlist)(__VA_ARGS__)
|
|
|
|
#define list_peek(l) ({ \
|
|
typeof((l)[0]) d = {0}; \
|
|
struct list_header *h = list_header(l); \
|
|
if(h != NULL && h->size > 0) d = l[h->size-1]; \
|
|
d; \
|
|
})
|
|
|
|
#define list_pop(l) ({ \
|
|
struct list_header *h = list_header(l); \
|
|
typeof((l)[0]) d = {0}; \
|
|
if(h != NULL){ \
|
|
if(h->size > 0){ \
|
|
d = l[h->size-1]; \
|
|
l[h->size-1] = (typeof(d)){0}; \
|
|
h->size--; \
|
|
_list_adjust((void**)&(l)); \
|
|
} \
|
|
} \
|
|
d; \
|
|
})
|
|
|
|
#define list_remove(l, i) ({ \
|
|
struct list_header *h = list_header(l); \
|
|
typeof(*(l)) d = {0}; \
|
|
if(h != NULL && i < h->size){ \
|
|
d = l[i]; \
|
|
_list_remove((void**)&(l), i); \
|
|
} \
|
|
d; \
|
|
})
|
|
|
|
#define list_remove_entry(l, d) ({ \
|
|
struct list_header *h = list_header(l); \
|
|
typeof(d) _d = (d); \
|
|
if(h != NULL){ \
|
|
for(u32 i = 0; i < h->size; i++){ \
|
|
if(!memcmp(&(l[i]), &(_d), sizeof(_d))){ \
|
|
_list_remove((void**)&(l), i); \
|
|
_list_adjust((void**)&(l)); \
|
|
break; \
|
|
} \
|
|
} \
|
|
} \
|
|
d; \
|
|
})
|
|
|
|
#define list_entry_exists(l, d) ({ \
|
|
struct list_header *h = list_header(l); \
|
|
bool found = false; \
|
|
if(h != NULL){ \
|
|
typeof(d) _d = (d); \
|
|
for(u32 i = 0; i < h->size; i++){ \
|
|
if(!memcmp(&(l[i]), &(_d), sizeof(_d))){ \
|
|
found = true; \
|
|
break; \
|
|
} \
|
|
} \
|
|
} \
|
|
found; \
|
|
})
|
|
|
|
#define list_push(l, d) ({ \
|
|
_list_adjust((void**)&(l)); \
|
|
struct list_header *h = list_header(l); \
|
|
if(h != NULL && h->tsize == sizeof(d)){ \
|
|
if(h->size < h->cap){ \
|
|
l[h->size] = d; \
|
|
h->size++; \
|
|
} \
|
|
} \
|
|
})
|
|
|
|
#define list_push_i(l, d, i) ({ \
|
|
_list_adjust((void**)&(l)); \
|
|
struct list_header *h = list_header(l); \
|
|
if(h != NULL && h->tsize == sizeof(d) && i < h->size){ \
|
|
u32 n = (h->size-i < h->cap-i-1) ? h->size-i : h->cap-i-1; \
|
|
memmove(((void*)l)+(i+1)*h->tsize, ((void*)l)+i*h->tsize, n*h->tsize); \
|
|
l[i] = d; \
|
|
h->size += h->size < h->cap ; \
|
|
} \
|
|
})
|
|
|
|
#define list_append(l1, l2) ({ \
|
|
struct list_header *h1 = list_header(l1); \
|
|
struct list_header *h2 = list_header(l2); \
|
|
if(h1 != NULL && h2 != NULL && h1->tsize == h2->tsize){ \
|
|
u32 ins = h2->size; \
|
|
if(h1->size+h2->size > h1->cap){ \
|
|
if(h1->type == LIST_STATIC){ \
|
|
ins = h1->cap-h1->size; \
|
|
}else if(h1->type == LIST_DYNAMIC){ \
|
|
_list_realloc((void**)&(l1), clp2_32(h1->cap+ins)-1); \
|
|
}else if(h1->type == LIST_NAIVE_DYNAMIC){ \
|
|
_list_realloc((void**)&(l1), h1->cap+ins); \
|
|
} \
|
|
} \
|
|
h1 = list_header(l1); \
|
|
memcpy(l1+h1->size, l2, ins); \
|
|
h1->size += ins; \
|
|
} \
|
|
})
|
|
|
|
#define list_append_array(l, a, n) ({ \
|
|
struct list_header *h = list_header(l); \
|
|
if(h != NULL && h->tsize == sizeof(a[0])){ \
|
|
u32 ins = n; \
|
|
if(h->size+n > h->cap){ \
|
|
if(h->type == LIST_STATIC){ \
|
|
ins = h->cap-h->size; \
|
|
}else if(h->type == LIST_DYNAMIC){ \
|
|
_list_realloc((void**)&(l), clp2_32(h->cap+ins)-1); \
|
|
}else if(h->type == LIST_NAIVE_DYNAMIC){ \
|
|
_list_realloc((void**)&(l), h->cap+ins); \
|
|
} \
|
|
} \
|
|
h = list_header(l); \
|
|
memcpy(l+h->size, a, ins); \
|
|
h->size += ins; \
|
|
} \
|
|
})
|
|
|
|
#define list_clamp_n(l, n) ({ \
|
|
struct list_header *h = list_header(l); \
|
|
if(h != NULL){ \
|
|
u32 _n = h->size > n ? h->size : n; \
|
|
_list_realloc((void**)&l, _n); \
|
|
} \
|
|
})
|
|
|
|
#define list_clamp_s(l) ({ \
|
|
struct list_header *h = list_header(l); \
|
|
if(h != NULL){ \
|
|
_list_realloc((void**)&l, h->size); \
|
|
} \
|
|
})
|
|
|
|
#define _choose_clamp(_1, _2, NAME, ...) NAME
|
|
#define list_clamp(...) _choose_clamp(__VA_ARGS__, list_clamp_n, list_clamp_s)(__VA_ARGS__)
|
|
|
|
#define list_free(l) _list_free((void**)&(l))
|
|
|
|
|
|
void _init_list(void **list, u32 n, int tsize, enum LIST_TYPE type);
|
|
|
|
void _list_realloc(void **list, u32 n);
|
|
|
|
void _list_adjust(void **list);
|
|
|
|
void _list_remove(void **list, u32 i);
|
|
|
|
void _list_free(void **list);
|
|
|
|
#endif
|