1 /*******************************************************************
2 uLan Utilities Library - C library of basic reusable constructions
4 ul_gsa.h - generic sorted arrays
6 (C) Copyright 2001 by Pavel Pisa - Originator
8 The uLan utilities library can be used, copied and modified under
10 - GPL - GNU General Public License
11 - LGPL - GNU Lesser General Public License
12 - MPL - Mozilla Public License
13 - and other licenses added by project originators
14 Code can be modified and re-distributed under any combination
15 of the above listed licenses. If contributor does not agree with
16 some of the licenses, he/she can delete appropriate line.
17 Warning, if you delete all lines, you are not allowed to
18 distribute source code and/or binaries utilizing code.
20 See files COPYING and README for details.
22 *******************************************************************/
27 #include "ul_utdefs.h"
28 #include "ul_itbase.h"
38 /* function to compare fields of two array items */
39 typedef int gsa_cmp_fnc_t(const void *a, const void *b) UL_ATTR_REENTRANT;
41 /* compare two integer fields */
42 int gsa_cmp_int(const void *a, const void *b) UL_ATTR_REENTRANT;
44 /* compare two unsigned long fields */
45 int gsa_cmp_ulong(const void *a, const void *b) UL_ATTR_REENTRANT;
47 /* define structure representing head of array */
48 #define GSA_ARRAY_FOR(_type) \
52 unsigned alloc_count; \
54 gsa_cmp_fnc_t *cmp_fnc; \
57 /* array type for functions independent on stored type */
58 typedef GSA_ARRAY_FOR(void) gsa_array_t;
60 /* initialize array head structure */
62 gsa_struct_init(gsa_array_t *array, int key_offs,
63 gsa_cmp_fnc_t *cmp_fnc);
65 /* delete all pointers from array */
67 gsa_delete_all(gsa_array_t *array);
69 /* Core binary search routine for GSA arrays
70 searches in "array" for index "indx" of item
71 with value of item field at offset "key_offs"
72 equal to "*key". Values are compared by function
74 Integer "mode" modifies search algorithm
75 0 .. finds index of any item with field value "*key"
76 1 .. finds index of first item with "*key"
77 2 .. index points after last item with "*key" value
78 reworded - index points at first item with higher
79 value of field or after last item
80 Return of nonzerro value indicates match found.
83 gsa_bsearch_indx(gsa_array_t *array, void *key, int key_offs,
84 gsa_cmp_fnc_t *cmp_fnc, int mode, unsigned *indx);
86 /* returns item with key field value equal to "*key" or NULL */
88 gsa_find(gsa_array_t *array, void *key);
90 /* same as above, but first matching item is found */
92 gsa_find_first(gsa_array_t *array, void *key);
94 /* find index "indx" of the first matching item */
96 gsa_find_indx(gsa_array_t *array, void *key, int *indx);
98 /* insert new item at index "where" */
100 gsa_insert_at(gsa_array_t *array, void *item, unsigned where);
102 /* insert new item at the right index,
103 "mode" has same meaning as in "gsa_bsearch_indx"
104 if mode==0 then strict sorting is required
105 and violation result in ignore of new item
109 gsa_insert(gsa_array_t *array, void *item, int mode);
111 /* delete item at index */
113 gsa_delete_at(gsa_array_t *array, unsigned indx);
115 /* delete item from array */
117 gsa_delete(gsa_array_t *array, void *item);
119 /* set new sorting field and function
120 returns 0 if no change needed */
122 gsa_setsort(gsa_array_t *array, int key_offs,
123 gsa_cmp_fnc_t *cmp_fnc);
125 /*===========================================================*/
126 /* Macrodefinitions to prepare custom GSA arrays with */
129 * struct gsa_array_field_t - Structure Representing Anchor of custom GSA Array
130 * @items: pointer to array of pointers to individual items
131 * @count: number of items in the sorted array
132 * @alloc_count: allocated pointer array capacity
135 typedef struct gsa_array_field_t{
138 unsigned alloc_count;
141 typedef struct gsa_static_array_field_t{
144 } gsa_static_array_field_t;
146 void gsa_cust_init_array_field(gsa_array_field_t *array);
147 int gsa_cust_insert_at(gsa_array_field_t *array, void *item, unsigned where);
148 int gsa_cust_delete_at(gsa_array_field_t *array, unsigned indx);
149 void gsa_cust_delete_all(gsa_array_field_t *array);
152 /* User must provide his/her own compare routine with
153 int cust_cmp_fnc(cust_key_t *a, cust_key_t *b) */
155 /*** Base declaration of custom GSA array ***/
156 #define GSA_BASE_CUST_DEC_SCOPE(cust_scope, cust_prefix, cust_array_t, cust_item_t, cust_key_t,\
157 cust_array_field, cust_item_key, cust_cmp_fnc) \
159 static inline cust_item_t * \
160 cust_prefix##_indx2item(const cust_array_t *array, unsigned indx) \
162 if(indx>=array->cust_array_field.count) return NULL;\
163 return (cust_item_t*)array->cust_array_field.items[indx];\
166 static inline cust_key_t *\
167 cust_prefix##_indx2key(const cust_array_t *array, unsigned indx)\
168 { return &(cust_prefix##_indx2item(array, indx)->cust_item_key);}\
170 cust_scope int cust_prefix##_bsearch_indx(const cust_array_t *array, cust_key_t const *key, int mode, unsigned *indxp);\
172 static inline cust_item_t *\
173 cust_prefix##_at(const cust_array_t *array, unsigned indx)\
175 return cust_prefix##_indx2item(array, indx);\
178 static inline cust_item_t *\
179 cust_prefix##_find(const cust_array_t *array, cust_key_t const *key)\
182 if(!cust_prefix##_bsearch_indx(array, key, 0, &indx)) return NULL;\
183 return cust_prefix##_indx2item(array, indx);\
186 static inline cust_item_t *\
187 cust_prefix##_find_first(const cust_array_t *array, cust_key_t const *key)\
190 if(!cust_prefix##_bsearch_indx(array, key, GSA_FFIRST, &indx)) return NULL;\
191 return cust_prefix##_indx2item(array, indx);\
194 static inline unsigned \
195 cust_prefix##_find_first_indx(const cust_array_t *array, cust_key_t const *key)\
198 if(!cust_prefix##_bsearch_indx(array, key, GSA_FFIRST, &indx)) return -1;\
202 static inline cust_item_t *\
203 cust_prefix##_find_after(const cust_array_t *array, cust_key_t const *key)\
206 if(!cust_prefix##_bsearch_indx(array, key, GSA_FAFTER, &indx)) return NULL;\
207 return cust_prefix##_indx2item(array, indx);\
210 static inline unsigned \
211 cust_prefix##_find_after_indx(const cust_array_t *array, cust_key_t const *key)\
214 cust_prefix##_bsearch_indx(array, key, GSA_FAFTER, &indx);\
219 cust_prefix##_is_empty(const cust_array_t *array)\
221 return !array->cust_array_field.count;\
224 static inline cust_item_t *\
225 cust_prefix##_first(const cust_array_t *array)\
227 return cust_prefix##_indx2item(array, 0);\
230 static inline unsigned \
231 cust_prefix##_first_indx(const cust_array_t *array)\
237 static inline cust_item_t *\
238 cust_prefix##_last(const cust_array_t *array)\
240 return cust_prefix##_indx2item(array, array->cust_array_field.count-1);\
243 static inline unsigned \
244 cust_prefix##_last_indx(const cust_array_t *array)\
246 return array->cust_array_field.count-1;\
249 /*** Iterators for GSA arrays ***/
250 #define GSA_IT_CUST_DEC(cust_prefix, cust_array_t, cust_item_t, cust_key_t) \
253 cust_array_t *container;\
255 } cust_prefix##_it_t;\
257 static inline cust_item_t *\
258 cust_prefix##_it2item(const cust_prefix##_it_t *it)\
260 return cust_prefix##_indx2item(it->container,it->indx);\
264 cust_prefix##_first_it(cust_array_t *container, cust_prefix##_it_t *it)\
266 it->container=container;\
267 it->indx=cust_prefix##_first_indx(container);\
271 cust_prefix##_last_it(cust_array_t *container, cust_prefix##_it_t *it)\
273 it->container=container;\
274 it->indx=cust_prefix##_last_indx(container);\
278 cust_prefix##_next_it(cust_prefix##_it_t *it)\
280 if(it->indx<=cust_prefix##_last_indx(it->container)) it->indx++;\
281 else it->indx=cust_prefix##_first_indx(it->container);\
285 cust_prefix##_prev_it(cust_prefix##_it_t *it)\
287 if(it->indx<=cust_prefix##_last_indx(it->container)) it->indx--;\
288 else it->indx=cust_prefix##_first_indx(it->container);\
292 cust_prefix##_is_end_it(cust_prefix##_it_t *it)\
294 if(!it->container) return 1;\
295 return it->indx>cust_prefix##_last_indx(it->container);\
299 cust_prefix##_find_it(cust_array_t *container, cust_key_t const *key, cust_prefix##_it_t *it)\
301 it->container=container;\
302 return (it->indx=cust_prefix##_find_first_indx(container, key))!=(unsigned)-1;\
306 cust_prefix##_find_first_it(cust_array_t *container, cust_key_t const *key, cust_prefix##_it_t *it)\
308 it->container=container;\
309 return (it->indx=cust_prefix##_find_first_indx(container, key))!=(unsigned)-1;\
313 cust_prefix##_find_after_it(cust_array_t *container, cust_key_t const *key, cust_prefix##_it_t *it)\
315 it->container=container;\
316 return (it->indx=cust_prefix##_find_after_indx(container, key))!=(unsigned)-1;\
319 /* Declaration of new const custom array without support of runtime modifications */
320 #define GSA_CONST_CUST_DEC_SCOPE(cust_scope, cust_prefix, cust_array_t, cust_item_t, cust_key_t,\
321 cust_array_field, cust_item_key, cust_cmp_fnc) \
323 GSA_BASE_CUST_DEC_SCOPE(cust_scope, cust_prefix, cust_array_t, cust_item_t, cust_key_t,\
324 cust_array_field, cust_item_key, cust_cmp_fnc) \
326 GSA_IT_CUST_DEC(cust_prefix, const cust_array_t, cust_item_t, cust_key_t)
328 #define GSA_CONST_CUST_DEC(cust_prefix, cust_array_t, cust_item_t, cust_key_t,\
329 cust_array_field, cust_item_key, cust_cmp_fnc) \
330 GSA_CONST_CUST_DEC_SCOPE(extern, cust_prefix, cust_array_t, cust_item_t, cust_key_t,\
331 cust_array_field, cust_item_key, cust_cmp_fnc)
333 /*** Declaration of dynamic custom array with full functions ***/
334 #define GSA_CUST_DEC_SCOPE(cust_scope, cust_prefix, cust_array_t, cust_item_t, cust_key_t,\
335 cust_array_field, cust_item_key, cust_cmp_fnc) \
337 GSA_BASE_CUST_DEC_SCOPE(cust_scope, cust_prefix, cust_array_t, cust_item_t, cust_key_t,\
338 cust_array_field, cust_item_key, cust_cmp_fnc) \
340 cust_scope int cust_prefix##_insert(cust_array_t *array, cust_item_t *item);\
341 cust_scope int cust_prefix##_delete(cust_array_t *array, const cust_item_t *item);\
344 cust_prefix##_init_array_field(cust_array_t *array)\
346 gsa_cust_init_array_field(&array->cust_array_field);\
350 cust_prefix##_insert_at(cust_array_t *array, cust_item_t *item, unsigned indx)\
352 return gsa_cust_insert_at(&array->cust_array_field, item, indx);\
356 cust_prefix##_delete_at(cust_array_t *array, unsigned indx)\
358 return gsa_cust_delete_at(&array->cust_array_field, indx);\
362 cust_prefix##_delete_all(cust_array_t *array)\
364 gsa_cust_delete_all(&array->cust_array_field);\
367 static inline cust_item_t *\
368 cust_prefix##_cut_last(cust_array_t *array)\
370 if(cust_prefix##_is_empty(array)) return NULL;\
371 return (cust_item_t *)array->cust_array_field.items\
372 [--array->cust_array_field.count];\
375 GSA_IT_CUST_DEC(cust_prefix, cust_array_t, cust_item_t, cust_key_t) \
378 cust_prefix##_delete_it(cust_prefix##_it_t *it)\
380 cust_prefix##_delete_at(it->container,it->indx);\
383 #define GSA_CUST_DEC(cust_prefix, cust_array_t, cust_item_t, cust_key_t,\
384 cust_array_field, cust_item_key, cust_cmp_fnc) \
385 GSA_CUST_DEC_SCOPE(extern, cust_prefix, cust_array_t, cust_item_t, cust_key_t,\
386 cust_array_field, cust_item_key, cust_cmp_fnc) \
388 /*** Declaration of static custom array with limited functions ***/
389 #define GSA_STATIC_CUST_DEC_SCOPE(cust_scope, cust_prefix, cust_array_t, cust_item_t, cust_key_t,\
390 cust_array_field, cust_item_key, cust_cmp_fnc) \
392 GSA_BASE_CUST_DEC_SCOPE(cust_scope, cust_prefix, cust_array_t, cust_item_t, cust_key_t,\
393 cust_array_field, cust_item_key, cust_cmp_fnc) \
395 cust_scope int cust_prefix##_insert(cust_array_t *array, cust_item_t *item);\
396 cust_scope int cust_prefix##_delete(cust_array_t *array, const cust_item_t *item);\
397 cust_scope void cust_prefix##_init_array_field(cust_array_t *array);\
398 cust_scope int cust_prefix##_insert_at(cust_array_t *array, cust_item_t *item, unsigned indx);\
399 cust_scope int cust_prefix##_delete_at(cust_array_t *array, unsigned indx); \
402 cust_prefix##_delete_all(cust_array_t *array)\
404 array->cust_array_field.count=0;\
407 static inline cust_item_t *\
408 cust_prefix##_cut_last(cust_array_t *array)\
410 if(cust_prefix##_is_empty(array)) return NULL;\
411 return (cust_item_t *)array->cust_array_field.items\
412 [--array->cust_array_field.count];\
415 GSA_IT_CUST_DEC(cust_prefix, cust_array_t, cust_item_t, cust_key_t) \
418 cust_prefix##_delete_it(cust_prefix##_it_t *it)\
420 cust_prefix##_delete_at(it->container,it->indx);\
423 #define GSA_STATIC_CUST_DEC(cust_prefix, cust_array_t, cust_item_t, cust_key_t,\
424 cust_array_field, cust_item_key, cust_cmp_fnc) \
425 GSA_STATIC_CUST_DEC_SCOPE(extern, cust_prefix, cust_array_t, cust_item_t, cust_key_t,\
426 cust_array_field, cust_item_key, cust_cmp_fnc)
428 /* The next implementation of foreaach is elegant, but can not
429 be used in C99 non-conformant C compiler */
432 #define gsa_cust_for_each(cust_prefix, array, ptr) \
433 for(unsigned __fe_indx=cust_prefix##_first_indx(array);\
434 (ptr=cust_prefix##_indx2item(array,__fe_indx));\
437 #define gsa_cust_for_each_rev(cust_prefix, array, ptr) \
438 for(unsigned __fe_indx=cust_prefix##_last_indx(array);\
439 (ptr=cust_prefix##_indx2item(array,__fe_indx));\
442 #define gsa_cust_for_each_from(cust_prefix, array, key, ptr) \
443 for(unsigned __fe_indx=cust_prefix##_find_first_indx(array, key); \
444 (ptr=cust_prefix##_indx2item(array,__fe_indx)); \
447 #define gsa_cust_for_each_after(cust_prefix, array, key, ptr) \
448 for(unsigned __fe_indx=cust_prefix##_find_after_indx(array, key); \
449 (ptr=cust_prefix##_indx2item(array,__fe_indx)); \
454 #define gsa_cust_for_each_cut(cust_prefix, array, ptr) \
455 for(;(ptr=cust_prefix##_cut_last(array));)
462 #endif /* _UL_GSA_H */