/ libpkg / pkg / vec.h
vec.h
  1  /*-
  2   * Copyright(c) 2024-2025 Baptiste Daroussin <bapt@FreeBSD.org>
  3   *
  4   * SPDX-License-Identifier: BSD-2-Clause
  5   */
  6  
  7  #ifndef VEC_H
  8  #define VEC_H
  9  
 10  #include <stdbool.h>
 11  #include <stdlib.h>
 12  #include <stddef.h>
 13  
 14  #define vec_t(Type) \
 15    struct { Type *d; size_t len, cap; }
 16  
 17  #define vec_init() \
 18  	{ .d = NULL, .len = 0, .cap = 0 }
 19  
 20  #define vec_foreach(list, __i) \
 21  	for (size_t __i = 0; __i < (list).len; __i++)
 22  
 23  /* ssize_t because the value can be negative */
 24  #define vec_rforeach(list, __i) \
 25  	for (ssize_t __i = ((ssize_t)(list).len) -1 ; __i >= 0; __i--)
 26  
 27  #define vec_free(v) \
 28  	do { \
 29  		free((v)->d); \
 30  		memset((v), 0, sizeof(*(v))); \
 31  	} while (0)
 32  
 33  #define vec_free_and_free(v, free_func)        \
 34  	do {                                   \
 35  		vec_foreach(*(v), _i) {        \
 36  			free_func((v)->d[_i]); \
 37  			(v)->d[_i] = NULL;     \
 38  		}                              \
 39  		vec_free((v));                 \
 40  	} while(0)
 41  
 42  #define vec_first(v) \
 43  	(v)->d[0]
 44  
 45  #define vec_last(v) \
 46  	(v)->d[(v)->len -1]
 47  
 48  #define vec_clear(v) \
 49  	(v)->len = 0
 50  
 51  #define vec_clear_and_free(v, free_func)       \
 52  	do {                                   \
 53  		vec_foreach(*(v), _i) {        \
 54  			free_func((v)->d[_i]); \
 55  			(v)->d[_i] = NULL;     \
 56  		}                              \
 57  		(v)->len = 0;                  \
 58  	} while (0)
 59  
 60  #define vec_push(v, _d)                                            \
 61  	do {                                                          \
 62  		if ((v)->len >= (v)->cap) {                            \
 63  			if ((v)->cap == 0)                              \
 64  				(v)->cap = 1;                          \
 65  			else                                          \
 66  				(v)->cap *=2;                           \
 67  			(v)->d = realloc((v)->d, (v)->cap * sizeof(*(v)->d)); \
 68  			if ((v)->d == NULL)                             \
 69  				abort();                              \
 70  		}                                                     \
 71  		(v)->d[(v)->len++] = (_d);                                  \
 72  	} while (0)                                                   \
 73  
 74  #define vec_pop(v) \
 75  	(v)->d[--(v)->len]
 76  
 77  #define vec_remove(v, cnt) \
 78  	do {                                                    \
 79  		for (size_t _i = cnt; _i < (v)->len - 1; _i++) {    \
 80  			(v)->d[_i] = (v)->d[_i + 1];            \
 81  		}                                               \
 82  		(v)->len--;                                     \
 83  	} while (0)
 84  
 85  #define vec_remove_and_free(v, cnt, free_func) \
 86  	do {                                                    \
 87  		free_func((v)->d[cnt]);                         \
 88  		vec_remove(v, cnt);                             \
 89  	} while (0)
 90  
 91  /*
 92   * Remove the element at the given index and replace it with the last
 93   * element in the vec. Does not preserve order, but is O(1).
 94   */
 95  #define vec_swap_remove(v, index)                    \
 96  	do {                                         \
 97  		assert((index) < (v)->len);          \
 98  		assert((v)->len > 0);                \
 99  		if ((index) < (v)->len - 1) {        \
100  			(v)->d[index] = vec_last(v); \
101  		}                                    \
102  		(v)->len--;                          \
103  	} while (0)
104  
105  #define vec_len(v) \
106  	(v)->len
107  
108  #define DEFINE_VEC_INSERT_SORTED_PROTO(type, name, element_type) \
109  	element_type *name##_insert_sorted(type *v, element_type el)
110  
111  #define DEFINE_VEC_INSERT_SORTED_FUNC(type, _name, element_type, compare_func) \
112  	element_type *_name##_insert_sorted(type *v, element_type el) { \
113  		/* Verify if the element already exists */ \
114  		if (v->len > 0) { \
115  			element_type *found = bsearch(&el, v->d, v->len, sizeof(element_type), compare_func); \
116  			if (found != NULL){ \
117  				return (found); \
118  			} \
119  		} \
120  		if (v->len >= v->cap) { \
121  			v->cap = (v->cap == 0) ? 1 : v->cap * 2; \
122  			v->d = realloc(v->d, v->cap * sizeof(element_type)); \
123  			if (v->d == NULL) \
124  				abort(); \
125  		} \
126  		/* Find where to insert */ \
127  		size_t i; \
128  		for (i = v->len; i > 0 && compare_func(&v->d[i - 1], &el) > 0; i--) { \
129  			v->d[i] = v->d[i - 1]; \
130  		} \
131  		v->d[i] = el; \
132  		v->len++; \
133  		return (NULL); \
134  	}
135  
136  typedef vec_t(char *) charv_t;
137  typedef vec_t(const char *) c_charv_t;
138  
139  #endif