13 #pragma GCC diagnostic ignored "-Wunused-value"
17 * type generic list (dynamic array).
19 * unlike sblist, doesn't do any bounds check.
20 * so you can e.g. only delete positions that are valid,
21 * without causing memory corruption.
23 * this implementation is header-only, so it is easy
24 * to embed elsewhere, however there's some overhead
25 * if it's used in different TUs.
26 * however the code is pretty slim, the static funcs
27 * compile to about 400 byte total on x86_64.
29 * right now, this is in the testing stage.
30 * functions/macros ending in _impl are not supposed
31 * to be used by the user.
33 * the advantage of using a typed container is
34 * A) the declaration of the type already documents the use
35 * (like e.g. List<int> in java)
36 * B) no casts required when accessing the elements.
37 * C) added type safety
39 * use like tglist(somename_or_id, int) *l = tglist_new();
40 * the name or id can be anything that produces a valid token
41 * when concatenated to "tglist_". it simply serves to give
42 * the struct declaration a unique name.
44 * the code was designed such that the type/id is only required
45 * for the declaration of the struct, not for every function call.
46 * therefore unfortunately the static funcs have to resort to
50 #define tglist_impl(NAME, TYPE) \
61 #define tglist(TYPE) tglist_impl(, TYPE)
62 /* use tglist_decl if you need a named struct, e.g. to put in a header */
63 #define tglist_decl(ID, TYPE) tglist_impl(tglist_ ## ID, TYPE)
64 #define tglist_proto tglist_impl(, void*)
66 #define tglist_getsize(X) ((X)->count)
67 #define tglist_get_count(X) ((X)->count)
68 #define tglist_empty(X) ((X)->count == 0)
70 /* --- for dynamic style --- */
71 // allocate and initialize a new tglist
72 #define tglist_new() calloc(1, sizeof(tglist_proto))
74 // free dynamically allocated list and its internal buffers
75 #define tglist_free(X) do {free((X)->items); free(X);} while(0)
77 /* --- for static style --- */
78 // initialize existing list in user-allocated storage (e.g. stack-allocated)
79 #define tglist_init(X) memset(X, 0, sizeof(*(X)))
81 // free internal buffers of the list
82 #define tglist_free_items(X) free((X)->items)
84 /* in case your list contains pointers to heap-allocated mem,
85 not values, this will iterate over all list entries and
87 /* the casts here serve to suppress warnings when the macro
88 is expanded on a non-pointer list, (but using it would be
90 #define tglist_free_values(X) \
91 if(tglist_itemsize(X) == sizeof(void*)) while((X)->count > 0) \
92 {free(*(void**)(((char*)(X)->items)+ ( (--((X)->count)) *tglist_itemsize(X) ) ) \
96 #define tglist_get(L, POS) ((L)->items[POS])
98 #define tglist_set(X, ITEM, POS) \
99 ((X)->items[POS] = ITEM, 1)
101 #define tglist_itemsize(X) sizeof( (X)->items[0] )
103 #define tglist_foreach(X, ITER) for(ITER=0;ITER<tglist_getsize(X);++ITER)
105 // returns 1 on success, 0 on OOM
106 #define tglist_prepare_addition(X) ( \
107 tglist_grow_if_needed( X, tglist_itemsize(X) ) ? \
108 !!(++(X)->count) : 0 \
111 #define tglist_add(X, ITEM) ( \
112 tglist_prepare_addition(X) ? \
113 tglist_set(X, ITEM, (X)->count-1) : \
116 #define tglist_ptr_from_index_impl(L, POS, ITEMSZ) \
117 ( (char*) ((L)->items) + (POS * ITEMSZ) )
120 #define tglist_delete(X, POS) \
121 tglist_memmove_impl(X, POS, +1, tglist_itemsize(X)) && \
122 ( --((X)->count) , 1 )
124 /* int : 0=err, 1=success. */
125 #define tglist_insert(X, ITEM, POS) ( \
126 (((X)->tmp.s = (POS)), 1) && \
127 tglist_grow_if_needed( X, tglist_itemsize(X) ) ? \
128 tglist_memmove_impl(X, ((X)->tmp.s)+1, -1, tglist_itemsize(X)) && \
130 tglist_set(X, ITEM, (X)->tmp.s) \
134 #define tglist_insert_memcpy(X, ITEMPTR, POS, ITEMSIZE) ( \
135 tglist_grow_if_needed( X, ITEMSIZE ) ? \
136 tglist_memmove_impl(X, (POS)+1, -1, ITEMSIZE) && \
138 memcpy(tglist_ptr_from_index_impl(X, POS, ITEMSIZE), ITEMPTR, ITEMSIZE) \
141 /* the compare func for all sort-related stuff is qsort-style.
142 note that if the list contains pointers, the compare func will get
143 pointers to pointers. so to use e.g. strcmp, you need a wrapper to
144 deref the const char** pointers before passing them to strcmp. */
146 #define tglist_sort(X, COMPAREFUNC) \
147 qsort((X)->items, (X)->count, tglist_itemsize(X), COMPAREFUNC)
149 /* insert element into presorted list, returns listindex of new entry or -1
151 #define tglist_insert_sorted(X, ITEM, COMPAREFUNC) (\
152 ((X)->tmp.vt = (void*)&(ITEM)), \
153 tglist_insert_sorted_impl(X, (X)->tmp.vt, tglist_itemsize(X), COMPAREFUNC))
156 #define MAX(x, y) ((x) > (y) ? (x) : (y))
159 static int tglist_grow_if_needed(void* lst
, size_t itemsize
) {
160 tglist_proto
*l
= lst
;
162 if(l
->count
== l
->capa
) {
163 size_t newsz
= l
->capa
== 0 ? 4 : l
->capa
*2;
164 temp
= realloc(l
->items
, newsz
* itemsize
);
172 static int tglist_memmove_impl(void *lst
, size_t pos1
, int pos2diff
, size_t itemsz
) {
173 tglist_proto
*l
= lst
;
174 char* dst
= tglist_ptr_from_index_impl(l
, pos1
, itemsz
);
175 const char* src
= dst
+ (itemsz
*pos2diff
);
176 return !!memmove(dst
, src
, (tglist_getsize(l
) - (pos1
+ pos2diff
))*itemsz
);
179 static size_t tglist_sorted_insert_pos_impl(void* lst
, void* o
, size_t itemsz
, int (*compar
)(const void *, const void *)) {
180 tglist_proto
*l
= lst
;
182 lo
= tglist_getsize(l
);
187 size_t c
= hi
+ ((lo
- hi
) / 2);
188 void *p
= tglist_ptr_from_index_impl(l
, c
, itemsz
);
189 int r
= compar(o
, p
);
194 if(r
< 0) lo
= c
? c
-1 : 0;
195 else if(r
> 0) hi
= c
+1;
201 static size_t tglist_insert_sorted_impl(void *lst
, void *ptr_to_item
, size_t itemsz
, int (*compar
)(const void *, const void *)) {
202 size_t idx
= tglist_sorted_insert_pos_impl(lst
, ptr_to_item
, itemsz
, compar
);
203 if(idx
== (size_t) -1) return idx
;
204 if(tglist_insert_memcpy((tglist_proto
*) lst
, ptr_to_item
, idx
, itemsz
)) return idx
;