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