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#include <stdlib.h> 22#include <assert.h> 23#include <string.h> 24#include "vect.h" 25 26static void * 27slot(struct vect *vec, size_t i) 28{ 29 return ((unsigned char *)vec->data) + vec->elt_size * i; 30} 31 32static const void * 33cslot(const struct vect *vec, size_t i) 34{ 35 return ((const unsigned char *)vec->data) + vec->elt_size * i; 36} 37 38void 39vect_init(struct vect *vec, size_t elt_size) 40{ 41 *vec = (struct vect){ NULL, 0, 0, elt_size }; 42} 43 44static int 45copy_elt(void *tgt, const void *src, void *data) 46{ 47 struct vect *target = data; 48 memcpy(tgt, src, target->elt_size); 49 return 0; 50} 51 52int 53vect_clone(struct vect *target, const struct vect *source, 54 int (*clone)(void *tgt, const void *src, void *data), 55 void (*dtor)(void *elt, void *data), 56 void *data) 57{ 58 vect_init(target, source->elt_size); 59 if (vect_reserve(target, source->size) < 0) 60 return -1; 61 62 if (clone == NULL) { 63 assert(dtor == NULL); 64 clone = copy_elt; 65 data = target; 66 } else { 67 assert(dtor != NULL); 68 } 69 70 size_t i; 71 for (i = 0; i < source->size; ++i) 72 if (clone(slot(target, i), cslot(source, i), data) < 0) 73 goto fail; 74 75 target->size = source->size; 76 return 0; 77 78fail: 79 /* N.B. destroy the elements in opposite order. */ 80 if (dtor != NULL) 81 while (i-- != 0) 82 dtor(slot(target, i), data); 83 vect_destroy(target, NULL, NULL); 84 return -1; 85} 86 87int 88vect_reserve(struct vect *vec, size_t count) 89{ 90 if (count > vec->allocated) { 91 size_t na = vec->allocated != 0 ? 2 * vec->allocated : 4; 92 while (na < count) 93 na *= 2; 94 void *n = realloc(vec->data, na * vec->elt_size); 95 if (n == NULL) 96 return -1; 97 vec->data = n; 98 vec->allocated = na; 99 } 100 assert(count <= vec->allocated); 101 return 0; 102} 103 104size_t 105vect_size(const struct vect *vec) 106{ 107 return vec->size; 108} 109 110int 111vect_empty(const struct vect *vec) 112{ 113 return vec->size == 0; 114} 115 116int 117vect_reserve_additional(struct vect *vec, size_t count) 118{ 119 return vect_reserve(vec, vect_size(vec) + count); 120} 121 122int 123vect_pushback(struct vect *vec, void *eltp) 124{ 125 if (vect_reserve_additional(vec, 1) < 0) 126 return -1; 127 memcpy(slot(vec, vec->size++), eltp, vec->elt_size); 128 return 0; 129} 130 131void 132vect_erase(struct vect *vec, size_t start, size_t end, 133 void (*dtor)(void *emt, void *data), void *data) 134{ 135 assert(start < vect_size(vec) || start == 0); 136 assert(end <= vect_size(vec)); 137 138 /* First, destroy the elements that are to be erased. */ 139 if (dtor != NULL) { 140 size_t i; 141 for (i = start; i < end; ++i) 142 dtor(slot(vec, i), data); 143 } 144 145 /* Now move the tail forward and adjust size. */ 146 memmove(slot(vec, start), slot(vec, end), 147 slot(vec, vec->size) - slot(vec, end)); 148 vec->size -= end - start; 149} 150 151void 152vect_popback(struct vect *vec, 153 void (*dtor)(void *emt, void *data), void *data) 154{ 155 assert(vect_size(vec) > 0); 156 vect_erase(vec, vect_size(vec)-1, vect_size(vec), dtor, data); 157} 158 159void 160vect_destroy(struct vect *vec, void (*dtor)(void *emt, void *data), void *data) 161{ 162 if (vec == NULL) 163 return; 164 165 vect_erase(vec, 0, vect_size(vec), dtor, data); 166 assert(vect_size(vec) == 0); 167 free(vec->data); 168} 169 170void * 171vect_each(struct vect *vec, void *start_after, 172 enum callback_status (*cb)(void *, void *), void *data) 173{ 174 size_t i = start_after == NULL ? 0 175 : ((start_after - vec->data) / vec->elt_size) + 1; 176 177 for (; i < vec->size; ++i) { 178 void *slt = slot(vec, i); 179 switch ((*cb)(slt, data)) { 180 case CBS_FAIL: 181 /* XXX handle me */ 182 case CBS_STOP: 183 return slt; 184 case CBS_CONT: 185 break; 186 } 187 } 188 189 return NULL; 190} 191 192void 193vect_qsort(struct vect *vec, int (*compar)(const void *, const void *)) 194{ 195 qsort(vec->data, vec->size, vec->elt_size, compar); 196} 197 198const void * 199vect_each_cst(const struct vect *vec, const void *start_after, 200 enum callback_status (*cb)(const void *, void *), void *data) 201{ 202 return vect_each((struct vect *)vec, (void *)start_after, 203 (void *)cb, data); 204} 205 206void 207vect_dtor_string(char **key, void *data) 208{ 209 free(*key); 210} 211