1/* 2 * This file is part of ltrace. 3 * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation; either version 2 of the 8 * License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 * 02110-1301 USA 19 */ 20 21#ifndef VECT_H 22#define VECT_H 23 24#include <stddef.h> 25#include <assert.h> 26 27#include "callback.h" 28 29/* Vector is an array that can grow as needed to accommodate the data 30 * that it needs to hold. ELT_SIZE is also used as an elementary 31 * sanity check, because the array itself is not typed. */ 32 33struct vect 34{ 35 void *data; 36 size_t size; /* In elements. */ 37 size_t allocated; /* In elements. */ 38 size_t elt_size; /* In bytes. */ 39}; 40 41/* Initialize VEC, which will hold elements of size ELT_SIZE. */ 42void vect_init(struct vect *vec, size_t elt_size); 43 44/* Initialize VECP, which will hold elements of type ELT_TYPE. */ 45#define VECT_INIT(VECP, ELT_TYPE) \ 46 (vect_init(VECP, sizeof(ELT_TYPE))) 47 48/* Initialize TARGET by copying over contents of vector SOURCE. If 49 * CLONE is non-NULL, it's evoked on each element, and should clone 50 * SRC into TGT. It should return 0 on success or negative value on 51 * failure. DATA is passed to CLONE verbatim. This function returns 52 * 0 on success or negative value on failure. In case of failure, if 53 * DTOR is non-NULL, it is invoked on all hitherto created elements 54 * with the same DATA. If one of CLONE, DTOR is non-NULL, then both 55 * have to be. */ 56int vect_clone(struct vect *target, const struct vect *source, 57 int (*clone)(void *tgt, const void *src, void *data), 58 void (*dtor)(void *elt, void *data), 59 void *data); 60 61/* Destroy VEC, which holds elements of type ELT_TYPE, using DTOR. */ 62#define VECT_CLONE(TGT_VEC, SRC_VEC, ELT_TYPE, CLONE, DTOR, DATA) \ 63 /* xxx GCC-ism necessary to get in the safety latches. */ \ 64 ({ \ 65 const struct vect *_source_vec = (SRC_VEC); \ 66 assert(_source_vec->elt_size == sizeof(ELT_TYPE)); \ 67 /* Check that callbacks are typed properly. */ \ 68 void (*_dtor_callback)(ELT_TYPE *, void *) = DTOR; \ 69 int (*_clone_callback)(ELT_TYPE *, const ELT_TYPE *, \ 70 void *) = CLONE; \ 71 vect_clone((TGT_VEC), _source_vec, \ 72 (int (*)(void *, const void *, \ 73 void *))_clone_callback, \ 74 (void (*)(void *, void *))_dtor_callback, \ 75 DATA); \ 76 }) 77 78/* Return number of elements in VEC. */ 79size_t vect_size(const struct vect *vec); 80 81/* Emptiness predicate. */ 82int vect_empty(const struct vect *vec); 83 84/* Accessor. Fetch ELT_NUM-th argument of type ELT_TYPE from the 85 * vector referenced by VECP. */ 86#define VECT_ELEMENT(VECP, ELT_TYPE, ELT_NUM) \ 87 (assert((VECP)->elt_size == sizeof(ELT_TYPE)), \ 88 assert((ELT_NUM) < (VECP)->size), \ 89 ((ELT_TYPE *)(VECP)->data) + (ELT_NUM)) 90 91#define VECT_BACK(VECP, ELT_TYPE) \ 92 VECT_ELEMENT(VECP, ELT_TYPE, (VECP)->size - 1) 93 94/* Copy element referenced by ELTP to the end of VEC. The object 95 * referenced by ELTP is now owned by VECT. Returns 0 if the 96 * operation was successful, or negative value on error. */ 97int vect_pushback(struct vect *vec, void *eltp); 98 99/* Drop last element of VECP. This is like calling 100 * vect_erase(VEC, vect_size(VEC)-1, vect_size(VEC), DTOR, DATA); */ 101void vect_popback(struct vect *vec, 102 void (*dtor)(void *emt, void *data), void *data); 103 104#define VECT_POPBACK(VECP, ELT_TYPE, DTOR, DATA) \ 105 do \ 106 VECT_ERASE((VECP), ELT_TYPE, \ 107 vect_size(VECP) - 1, vect_size(VECP), \ 108 DTOR, DATA); \ 109 while (0) 110 111/* Drop elements START (inclusive) to END (non-inclusive) of VECP. If 112 * DTOR is non-NULL, it is called on each of the removed elements. 113 * DATA is passed verbatim to DTOR. */ 114void vect_erase(struct vect *vec, size_t start, size_t end, 115 void (*dtor)(void *emt, void *data), void *data); 116 117#define VECT_ERASE(VECP, ELT_TYPE, START, END, DTOR, DATA) \ 118 do { \ 119 assert((VECP)->elt_size == sizeof(ELT_TYPE)); \ 120 /* Check that DTOR is typed properly. */ \ 121 void (*_dtor_callback)(ELT_TYPE *, void *) = DTOR; \ 122 vect_erase((VECP), (START), (END), \ 123 (void (*)(void *, void *))_dtor_callback, DATA); \ 124 } while (0) 125 126/* Copy element referenced by ELTP to the end of VEC. See 127 * vect_pushback for details. In addition, make a check whether VECP 128 * holds elements of the right size. */ 129#define VECT_PUSHBACK(VECP, ELTP) \ 130 (assert((VECP)->elt_size == sizeof(*(ELTP))), \ 131 vect_pushback((VECP), (ELTP))) 132 133/* Make sure that VEC can hold at least COUNT elements. Return 0 on 134 * success, negative value on failure. */ 135int vect_reserve(struct vect *vec, size_t count); 136 137/* Make sure that VEC can accommodate COUNT additional elements. */ 138int vect_reserve_additional(struct vect *vec, size_t count); 139 140/* Destroy VEC. If DTOR is non-NULL, then it's called on each element 141 * of the vector. DATA is passed to DTOR verbatim. The memory 142 * pointed-to by VEC is not freed. */ 143void vect_destroy(struct vect *vec, 144 void (*dtor)(void *emt, void *data), void *data); 145 146/* Destroy VEC, which holds elements of type ELT_TYPE, using DTOR. */ 147#define VECT_DESTROY(VECP, ELT_TYPE, DTOR, DATA) \ 148 do { \ 149 assert((VECP)->elt_size == sizeof(ELT_TYPE)); \ 150 /* Check that DTOR is typed properly. */ \ 151 void (*_dtor_callback)(ELT_TYPE *, void *) = DTOR; \ 152 vect_destroy((VECP), (void (*)(void *, void *))_dtor_callback, \ 153 DATA); \ 154 } while (0) 155 156/* Iterate through vector VEC. See callback.h for notes on iteration 157 * interfaces. */ 158void *vect_each(struct vect *vec, void *start_after, 159 enum callback_status (*cb)(void *, void *), void *data); 160 161#define VECT_EACH(VECP, ELT_TYPE, START_AFTER, CB, DATA) \ 162 /* xxx GCC-ism necessary to get in the safety latches. */ \ 163 ({ \ 164 assert((VECP)->elt_size == sizeof(ELT_TYPE)); \ 165 /* Check that CB is typed properly. */ \ 166 enum callback_status (*_cb)(ELT_TYPE *, void *) = CB; \ 167 ELT_TYPE *_start_after = (START_AFTER); \ 168 (ELT_TYPE *)vect_each((VECP), _start_after, \ 169 (enum callback_status \ 170 (*)(void *, void *))_cb, \ 171 DATA); \ 172 }) 173 174/* Iterate through vector VEC. See callback.h for notes on iteration 175 * interfaces. */ 176const void *vect_each_cst(const struct vect *vec, const void *start_after, 177 enum callback_status (*cb)(const void *, void *), 178 void *data); 179 180#define VECT_EACH_CST(VECP, ELT_TYPE, START_AFTER, CB, DATA) \ 181 /* xxx GCC-ism necessary to get in the safety latches. */ \ 182 ({ \ 183 assert((VECP)->elt_size == sizeof(ELT_TYPE)); \ 184 /* Check that CB is typed properly. */ \ 185 enum callback_status (*_cb)(const ELT_TYPE *, void *) = CB; \ 186 const ELT_TYPE *start_after = (START_AFTER); \ 187 (const ELT_TYPE *)vect_each_cst((VECP), start_after, \ 188 (enum callback_status \ 189 (*)(const void *, \ 190 void *))_cb, \ 191 DATA); \ 192 }) 193 194/* Call qsort on elements of VECT, with COMPAR as a comparison 195 * function. */ 196void vect_qsort(struct vect *vec, int (*compar)(const void *, const void *)); 197 198#define VECT_QSORT(VECP, ELT_TYPE, COMPAR) \ 199 do { \ 200 assert((VECP)->elt_size == sizeof(ELT_TYPE)); \ 201 /* Check that CB is typed properly. */ \ 202 int (*_compar)(const ELT_TYPE *, const ELT_TYPE *) = COMPAR; \ 203 vect_qsort((VECP), \ 204 (int (*)(const void *, const void *))_compar); \ 205 } while (0) 206 207 208/* A dtor which calls 'free' on elements of a vector. */ 209void vect_dtor_string(char **key, void *data); 210 211#endif /* VECT_H */ 212