| /* |
| * This file is part of ltrace. |
| * Copyright (C) 2011,2012,2013 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 |
| */ |
| |
| #include <stdlib.h> |
| #include <assert.h> |
| #include <string.h> |
| #include "vect.h" |
| |
| static void * |
| slot(struct vect *vec, size_t i) |
| { |
| 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; |
| } |
| |
| void |
| vect_init(struct vect *vec, size_t elt_size) |
| { |
| *vec = (struct vect){ NULL, 0, 0, elt_size }; |
| } |
| |
| static int |
| copy_elt(void *tgt, const void *src, void *data) |
| { |
| struct vect *target = data; |
| memcpy(tgt, src, target->elt_size); |
| return 0; |
| } |
| |
| int |
| vect_clone(struct vect *target, const struct vect *source, |
| int (*clone)(void *tgt, const void *src, void *data), |
| 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) |
| if (clone(slot(target, i), cslot(source, i), data) < 0) |
| 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; |
| while (na < count) |
| na *= 2; |
| 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 |
| vect_size(const struct vect *vec) |
| { |
| return vec->size; |
| } |
| |
| int |
| vect_empty(const struct vect *vec) |
| { |
| 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; |
| } |
| |
| void |
| vect_erase(struct vect *vec, size_t start, size_t end, |
| void (*dtor)(void *emt, void *data), void *data) |
| { |
| 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. */ |
| memmove(slot(vec, start), slot(vec, end), |
| slot(vec, vec->size) - slot(vec, end)); |
| 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); |
| } |
| |
| void |
| vect_destroy(struct vect *vec, void (*dtor)(void *emt, void *data), void *data) |
| { |
| if (vec == NULL) |
| return; |
| |
| vect_erase(vec, 0, vect_size(vec), dtor, data); |
| assert(vect_size(vec) == 0); |
| free(vec->data); |
| } |
| |
| 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; |
| } |
| |
| void |
| vect_qsort(struct vect *vec, int (*compar)(const void *, const void *)) |
| { |
| qsort(vec->data, vec->size, vec->elt_size, compar); |
| } |
| |
| 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); |
| } |
| |
| void |
| vect_dtor_string(char **key, void *data) |
| { |
| free(*key); |
| } |