vect.c 4.55 KB
Newer Older
1 2
/*
 * This file is part of ltrace.
Petr Machata's avatar
Petr Machata committed
3
 * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc.
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
 *
 * 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
 */

#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "vect.h"

static void *
slot(struct vect *vec, size_t i)
{
29 30 31 32 33 34 35
	return ((unsigned char *)vec->data) + vec->elt_size * i;
}

static const void *
cslot(const struct vect *vec, size_t i)
{
	return ((const unsigned char *)vec->data) + vec->elt_size * i;
36 37 38 39 40 41 42 43 44
}

void
vect_init(struct vect *vec, size_t elt_size)
{
	*vec = (struct vect){ NULL, 0, 0, elt_size };
}

static int
45
copy_elt(void *tgt, const void *src, void *data)
46 47 48 49 50 51 52
{
	struct vect *target = data;
	memcpy(tgt, src, target->elt_size);
	return 0;
}

int
53 54
vect_clone(struct vect *target, const struct vect *source,
	   int (*clone)(void *tgt, const void *src, void *data),
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
	   void (*dtor)(void *elt, void *data),
	   void *data)
{
	vect_init(target, source->elt_size);
	if (vect_reserve(target, source->size) < 0)
		return -1;

	if (clone == NULL) {
		assert(dtor == NULL);
		clone = copy_elt;
		data = target;
	} else {
		assert(dtor != NULL);
	}

	size_t i;
	for (i = 0; i < source->size; ++i)
72
		if (clone(slot(target, i), cslot(source, i), data) < 0)
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
			goto fail;

	target->size = source->size;
	return 0;

fail:
	/* N.B. destroy the elements in opposite order.  */
	if (dtor != NULL)
		while (i-- != 0)
			dtor(slot(target, i), data);
	vect_destroy(target, NULL, NULL);
	return -1;
}

int
vect_reserve(struct vect *vec, size_t count)
{
	if (count > vec->allocated) {
		size_t na = vec->allocated != 0 ? 2 * vec->allocated : 4;
Petr Machata's avatar
Petr Machata committed
92 93
		while (na < count)
			na *= 2;
94 95 96 97 98 99 100 101 102 103 104
		void *n = realloc(vec->data, na * vec->elt_size);
		if (n == NULL)
			return -1;
		vec->data = n;
		vec->allocated = na;
	}
	assert(count <= vec->allocated);
	return 0;
}

size_t
105
vect_size(const struct vect *vec)
106 107 108 109 110
{
	return vec->size;
}

int
111
vect_empty(const struct vect *vec)
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
{
	return vec->size == 0;
}

int
vect_reserve_additional(struct vect *vec, size_t count)
{
	return vect_reserve(vec, vect_size(vec) + count);
}

int
vect_pushback(struct vect *vec, void *eltp)
{
	if (vect_reserve_additional(vec, 1) < 0)
		return -1;
	memcpy(slot(vec, vec->size++), eltp, vec->elt_size);
	return 0;
}

Petr Machata's avatar
Petr Machata committed
131
void
132 133
vect_erase(struct vect *vec, size_t start, size_t end,
	   void (*dtor)(void *emt, void *data), void *data)
Petr Machata's avatar
Petr Machata committed
134
{
135 136 137 138 139 140 141 142 143 144 145
	assert(start < vect_size(vec) || start == 0);
	assert(end <= vect_size(vec));

	/* First, destroy the elements that are to be erased.  */
	if (dtor != NULL) {
		size_t i;
		for (i = start; i < end; ++i)
			dtor(slot(vec, i), data);
	}

	/* Now move the tail forward and adjust size.  */
146 147
	memmove(slot(vec, start), slot(vec, end),
		slot(vec, vec->size) - slot(vec, end));
148 149 150 151 152 153 154 155 156
	vec->size -= end - start;
}

void
vect_popback(struct vect *vec,
	     void (*dtor)(void *emt, void *data), void *data)
{
	assert(vect_size(vec) > 0);
	vect_erase(vec, vect_size(vec)-1, vect_size(vec), dtor, data);
Petr Machata's avatar
Petr Machata committed
157 158
}

159 160 161 162 163 164
void
vect_destroy(struct vect *vec, void (*dtor)(void *emt, void *data), void *data)
{
	if (vec == NULL)
		return;

165 166
	vect_erase(vec, 0, vect_size(vec), dtor, data);
	assert(vect_size(vec) == 0);
167 168
	free(vec->data);
}
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190

void *
vect_each(struct vect *vec, void *start_after,
	  enum callback_status (*cb)(void *, void *), void *data)
{
	size_t i = start_after == NULL ? 0
		: ((start_after - vec->data) / vec->elt_size) + 1;

	for (; i < vec->size; ++i) {
		void *slt = slot(vec, i);
		switch ((*cb)(slt, data)) {
		case CBS_FAIL:
			/* XXX handle me */
		case CBS_STOP:
			return slt;
		case CBS_CONT:
			break;
		}
	}

	return NULL;
}
Petr Machata's avatar
Petr Machata committed
191 192 193 194 195 196

void
vect_qsort(struct vect *vec, int (*compar)(const void *, const void *))
{
	qsort(vec->data, vec->size, vec->elt_size, compar);
}
197 198 199 200 201 202 203 204

const void *
vect_each_cst(const struct vect *vec, const void *start_after,
	      enum callback_status (*cb)(const void *, void *), void *data)
{
	return vect_each((struct vect *)vec, (void *)start_after,
			 (void *)cb, data);
}
205 206 207 208 209 210

void
vect_dtor_string(char **key, void *data)
{
	free(*key);
}