aboutsummaryrefslogtreecommitdiff
path: root/vect.h
blob: 50401bbc689716903c1f0682538ab241b03cfa51 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
 * This file is part of ltrace.
 * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#ifndef VECT_H
#define VECT_H

#include <stddef.h>

/* Vector is an array that can grow as needed to accommodate the data
 * that it needs to hold.  ELT_SIZE is also used as an elementary
 * sanity check, because the array itself is not typed.  */

struct vect
{
	void *data;
	size_t size;		/* In elements.  */
	size_t allocated;	/* In elements.  */
	size_t elt_size;	/* In bytes.  */
};

/* Initialize VEC, which will hold elements of size ELT_SIZE.  */
void vect_init(struct vect *vec, size_t elt_size);

/* Initialize VECP, which will hold elements of type ELT_TYPE.  */
#define VECT_INIT(VECP, ELT_TYPE)		\
	(vect_init(VECP, sizeof(ELT_TYPE)))

/* Initialize TARGET by copying over contents of vector SOURCE.  If
 * CLONE is non-NULL, it's evoked on each element, and should clone
 * SRC into TGT.  It should return 0 on success or negative value on
 * failure.  DATA is passed to CLONE verbatim.  This function returns
 * 0 on success or negative value on failure.  In case of failure, if
 * DTOR is non-NULL, it is invoked on all hitherto created elements
 * with the same DATA.  If one of CLONE, DTOR is non-NULL, then both
 * have to be.  */
int vect_clone(struct vect *target, struct vect *source,
	       int (*clone)(void *tgt, void *src, void *data),
	       void (*dtor)(void *elt, void *data),
	       void *data);

/* Destroy VEC, which holds elements of type ELT_TYPE, using DTOR.  */
#define VECT_CLONE(TGT_VEC, SRC_VEC, ELT_TYPE, CLONE, DTOR, DATA)	\
	/* xxx GCC-ism necessary to get in the safety latches.  */	\
	({								\
		struct vect *_source_vec = (SRC_VEC);			\
		assert(_source_vec->elt_size == sizeof(ELT_TYPE));	\
		/* Check that callbacks are typed properly.  */		\
		void (*_dtor_callback)(ELT_TYPE *, void *) = DTOR;	\
		int (*_clone_callback)(ELT_TYPE *,			\
				       ELT_TYPE *, void *) = CLONE;	\
		vect_clone((TGT_VEC), _source_vec,			\
			   (int (*)(void *, void *, void *))_clone_callback, \
			   (void (*)(void *, void *))_dtor_callback,	\
			   DATA);					\
	 })

/* Return number of elements in VEC.  */
size_t vect_size(struct vect *vec);

/* Emptiness predicate.  */
int vect_empty(struct vect *vec);

/* Accessor.  Fetch ELT_NUM-th argument of type ELT_TYPE from the
 * vector referenced by VECP.  */
#define VECT_ELEMENT(VECP, ELT_TYPE, ELT_NUM)		\
	(assert((VECP)->elt_size == sizeof(ELT_TYPE)),	\
	 assert((ELT_NUM) < (VECP)->size),		\
	 ((ELT_TYPE *)(VECP)->data) + (ELT_NUM))

#define VECT_BACK(VECP, ELT_TYPE)		\
	VECT_ELEMENT(VECP, ELT_TYPE, (VECP)->size)

/* Copy element referenced by ELTP to the end of VEC.  The object
 * referenced by ELTP is now owned by VECT.  Returns 0 if the
 * operation was successful, or negative value on error.  */
int vect_pushback(struct vect *vec, void *eltp);

/* Copy element referenced by ELTP to the end of VEC.  See
 * vect_pushback for details.  In addition, make a check whether VECP
 * holds elements of the right size.  */
#define VECT_PUSHBACK(VECP, ELTP)			\
	(assert((VECP)->elt_size == sizeof(*(ELTP))),	\
	 vect_pushback((VECP), (ELTP)))

/* Make sure that VEC can hold at least COUNT elements.  Return 0 on
 * success, negative value on failure.  */
int vect_reserve(struct vect *vec, size_t count);

/* Make sure that VEC can accommodate COUNT additional elements.  */
int vect_reserve_additional(struct vect *vec, size_t count);

/* Destroy VEC.  If DTOR is non-NULL, then it's called on each element
 * of the vector.  DATA is passed to DTOR verbatim.  The memory
 * pointed-to by VEC is not freed.  */
void vect_destroy(struct vect *vec,
		  void (*dtor)(void *emt, void *data), void *data);

/* Destroy VEC, which holds elements of type ELT_TYPE, using DTOR.  */
#define VECT_DESTROY(VECP, ELT_TYPE, DTOR, DATA)			\
	do {								\
		assert((VECP)->elt_size == sizeof(ELT_TYPE));		\
		/* Check that DTOR is typed properly.  */		\
		void (*_dtor_callback)(ELT_TYPE *, void *) = DTOR;	\
		vect_destroy((VECP), (void (*)(void *, void *))_dtor_callback, \
			     DATA);					\
	} while (0)

#endif /* VECT_H */