source: lib/data-struct/vector.c @ 2193905

develop
Last change on this file since 2193905 was 2193905, checked in by Jacob Van Walraven <jcv9@…>, 2 years ago

Apply changes required for pull request #81

  • Property mode set to 100644
File size: 5.4 KB
Line 
1/*
2 *
3 * Copyright (c) 2007-2016 The University of Waikato, Hamilton, New Zealand.
4 * All rights reserved.
5 *
6 * This file is part of libtrace.
7 *
8 * This code has been developed by the University of Waikato WAND
9 * research group. For further information please see http://www.wand.net.nz/
10 *
11 * libtrace is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * libtrace is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 *
24 *
25 */
26#include "vector.h"
27
28#include <stdlib.h>
29#include <string.h>
30#include <assert.h>
31
32DLLEXPORT void libtrace_vector_init(libtrace_vector_t *v, size_t element_size) {
33        v->element_size = element_size;
34        v->size = 0; // Starts empty
35        v->max_size = 128; // Pick a largish size to begin with
36        v->elements = malloc(v->max_size * v->element_size);
37        ASSERT_RET(pthread_mutex_init(&v->lock, NULL), == 0);
38}
39
40DLLEXPORT void libtrace_vector_destroy(libtrace_vector_t *v) {
41        ASSERT_RET(pthread_mutex_destroy(&v->lock), == 0);
42        free(v->elements);
43        // Be safe make sure we wont work any more
44        v->elements = NULL;
45        v->size = 0;
46        v->max_size = 0;
47        v->element_size = 0;
48}
49
50DLLEXPORT void libtrace_vector_push_back(libtrace_vector_t *v, void *d) {
51        ASSERT_RET(pthread_mutex_lock(&v->lock), == 0);
52        if (v->size >= v->max_size) {
53                /* Resize */
54                v->max_size *= 2;
55                v->elements = realloc(v->elements, v->max_size * v->element_size);
56                if (!v->elements) {
57                        fprintf(stderr, "Unable to allocate memory for v->elements in libtrace_vector_push_back()\n");
58                        return;
59                }
60        }
61        memcpy(&v->elements[v->size*v->element_size], d, v->element_size);
62        v->size++;
63        ASSERT_RET(pthread_mutex_unlock(&v->lock), == 0);
64}
65
66DLLEXPORT size_t libtrace_vector_get_size(libtrace_vector_t *v) {
67        return v->size;
68}
69
70DLLEXPORT int libtrace_vector_get(libtrace_vector_t *v, size_t location, void *d) {
71        ASSERT_RET(pthread_mutex_lock(&v->lock), == 0);
72        if (location >= v->size) {
73                ASSERT_RET(pthread_mutex_unlock(&v->lock), == 0);
74                return 0;
75        }
76        memcpy(d, &v->elements[location*v->element_size], v->element_size);
77        ASSERT_RET(pthread_mutex_unlock(&v->lock), == 0);
78        return 1;
79}
80
81DLLEXPORT int libtrace_vector_remove_front(libtrace_vector_t *v) {
82        size_t i;
83        ASSERT_RET(pthread_mutex_lock(&v->lock), == 0);
84        if (!v->size) {
85                ASSERT_RET(pthread_mutex_unlock(&v->lock), == 0);
86                return 0;
87        }
88        v->size--;
89        // Of course this is mega slow
90        for (i = 0; i < v->size * v->element_size; i++)
91                v->elements[i] = v->elements[i+v->element_size];
92        ASSERT_RET(pthread_mutex_unlock(&v->lock), == 0);
93        return 1;
94}
95
96static inline void memswap(void *a, void *b, size_t size) {
97        char c;
98        size_t i;
99        for (i=0; i<size; i++) {
100                c = ((char *)a)[i];
101                ((char *)a)[i] = ((char *)b)[i];
102                ((char *)b)[i] = c;
103        }
104}
105// Note elements must be the same size
106// This also empties the second source array
107DLLEXPORT void libtrace_vector_append(libtrace_vector_t *dest, libtrace_vector_t *src)
108{
109        if (dest->element_size != src->element_size) {
110                fprintf(stderr, "Elements must be the same size in libtrace_vector_append()\n");
111                return;
112        }
113        if (src->size == 0) // Nothing to do if this is the case
114                return;
115        ASSERT_RET(pthread_mutex_lock(&dest->lock), == 0);
116        ASSERT_RET(pthread_mutex_lock(&src->lock), == 0);
117        if (src->size == 0) // Double check now we've got the locks - Nothing to do if this is the case
118                goto unlock;
119        if (dest->size == 0) {
120                memswap(&dest->max_size, &src->max_size, sizeof(src->max_size));
121                memswap(&dest->size, &src->size, sizeof(src->size));
122                memswap(&dest->element_size, &src->element_size, sizeof(src->element_size));
123                memswap(&dest->elements, &src->elements, sizeof(src->elements));
124        } else {
125                size_t oldmax = dest->max_size;
126                while (dest->max_size - dest->size < src->size) dest->max_size *= 2;
127                if (oldmax != dest->max_size)
128                        dest->elements = realloc(dest->elements, dest->max_size * dest->element_size);
129                // Now do the move
130                memcpy(&dest->elements[dest->element_size * dest->size], src->elements, src->element_size * src->size);
131                // Update the dest size
132                dest->size += src->size;
133                // Wipe the src
134                src->size = 0;
135        }
136unlock:
137        ASSERT_RET(pthread_mutex_unlock(&src->lock), == 0);
138        ASSERT_RET(pthread_mutex_unlock(&dest->lock), == 0);
139}
140
141DLLEXPORT void libtrace_zero_vector(libtrace_vector_t *v)
142{
143        v->max_size = 0;
144        v->size = 0;
145        v->element_size = 0;
146        v->elements = NULL;
147}
148
149DLLEXPORT void libtrace_vector_empty(libtrace_vector_t *v) {
150        ASSERT_RET(pthread_mutex_lock(&v->lock), == 0);
151        v->size = 0;
152        ASSERT_RET(pthread_mutex_unlock(&v->lock), == 0);
153}
154
155
156DLLEXPORT void libtrace_vector_apply_function(libtrace_vector_t *v, vector_data_fn fn)
157{
158        size_t cur;
159        ASSERT_RET(pthread_mutex_lock(&v->lock), == 0);
160        for (cur = 0; cur < v->size; cur++) {
161                (*fn)(&v->elements[cur*v->element_size]);
162        }
163        ASSERT_RET(pthread_mutex_unlock(&v->lock), == 0);
164}
165
166DLLEXPORT void libtrace_vector_qsort(libtrace_vector_t *v, int (*compar)(const void *, const void*)) {
167        ASSERT_RET(pthread_mutex_lock(&v->lock), == 0);
168        qsort(v->elements, v->element_size, v->element_size, compar);
169        ASSERT_RET(pthread_mutex_unlock(&v->lock), == 0);
170}
Note: See TracBrowser for help on using the repository browser.