1 /*
2 * array.c - array functions
3 *
4 * Copyright (C) 2011-2013 Thien-Thi Nguyen
5 * Copyright (C) 2001 Stefan Jahn <stefan@lkcc.org>
6 * Copyright (C) 2001 Raimund Jacob <raimi@lkcc.org>
7 *
8 * This is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3, or (at your option)
11 * any later version.
12 *
13 * This software is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this package. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "config.h"
23
24 #include "timidity.h"
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "libserveez/alloc.h"
30 #include "libserveez/util.h"
31 #include "libserveez/array.h"
32
33 struct svz_array
34 {
35 size_t size; /* Real size of the array. */
36 size_t capacity; /* Current capacity. */
37 svz_free_func_t destroy; /* The destroy callback. */
38 void **data; /* Data pointer. */
39 };
40
41 /**
42 * Create a new array with the initial capacity @var{capacity} and return
43 * a pointer to it. If @var{capacity} is zero it defaults to some value.
44 * If @var{destroy} is non-@code{NULL}, @code{svz_array_destroy} calls
45 * that function (typically used to free dynamically allocated memory).
46 * For example, if the array contains data allocated by @code{svz_malloc},
47 * @var{destroy} should be specified as @code{svz_free}. If the array
48 * contains data which should not be released, @var{destroy} should
49 * be @code{NULL}.
50 */
51 svz_array_t *
svz_array_create(size_t capacity,svz_free_func_t destroy)52 svz_array_create (size_t capacity, svz_free_func_t destroy)
53 {
54 svz_array_t *array;
55
56 if (!capacity)
57 capacity = 4;
58 array = svz_calloc (sizeof (svz_array_t));
59 array->data = svz_malloc (sizeof (void *) * capacity);
60 array->capacity = capacity;
61 array->destroy = destroy;
62 return array;
63 }
64
65 /**
66 * Completely destroy the array @var{array}. The @var{array} handle is
67 * invalid afterwards. The routine runs the @var{destroy} callback for each
68 * element of the array.
69 */
70 void
svz_array_destroy(svz_array_t * array)71 svz_array_destroy (svz_array_t *array)
72 {
73 if (array)
74 {
75 if (array->data)
76 {
77 if (array->destroy != NULL)
78 {
79 size_t n;
80
81 for (n = 0; n < array->size; n++)
82 array->destroy (array->data[n]);
83 }
84 svz_free (array->data);
85 array->data = NULL;
86 array->size = 0;
87 array->capacity = 0;
88 }
89 svz_free (array);
90 }
91 }
92
93 /**
94 * Return the array element at the position @var{index} of the array
95 * @var{array} if the index is within the array range. Return @code{NULL}
96 * if not.
97 */
98 void *
svz_array_get(svz_array_t * array,size_t index)99 svz_array_get (svz_array_t *array, size_t index)
100 {
101 if (array == NULL || index >= array->size)
102 return NULL;
103 return array->data[index];
104 }
105
106 /**
107 * Replace the array element at the position @var{index} of the array
108 * @var{array} with the value @var{value} and return the previous value
109 * at this index. Return @code{NULL} and do nothing
110 * if @var{array} is @code{NULL} or the @var{index} is out of the array
111 * range.
112 */
113 void *
svz_array_set(svz_array_t * array,size_t index,void * value)114 svz_array_set (svz_array_t *array, size_t index, void *value)
115 {
116 void *prev;
117
118 if (array == NULL || index >= array->size)
119 return NULL;
120 prev = array->data[index];
121 array->data[index] = value;
122 return prev;
123 }
124
125 /**
126 * Append the value @var{value} at the end of the array @var{array}.
127 * Do nothing if @var{array} is @code{NULL}.
128 */
129 void
svz_array_add(svz_array_t * array,void * value)130 svz_array_add (svz_array_t *array, void *value)
131 {
132 if (array)
133 {
134 size_t bigger = 1 + array->size;
135
136 if (bigger > array->capacity)
137 {
138 array->capacity = array->capacity * 3 / 2 + 1;
139 array->data = svz_realloc (array->data, sizeof (void *) *
140 array->capacity);
141 }
142 array->data[array->size] = value;
143 array->size = bigger;
144 }
145 }
146
147 /**
148 * Remove the array element at the position @var{index} of the array
149 * @var{array}. Return its previous value or @code{NULL} if the index
150 * is out of the array's range.
151 */
152 void *
svz_array_del(svz_array_t * array,size_t index)153 svz_array_del (svz_array_t *array, size_t index)
154 {
155 void *value;
156
157 if (array == NULL || index >= array->size)
158 return NULL;
159 value = array->data[index];
160 if (index != array->size - 1)
161 memmove (&array->data[index], &array->data[index + 1],
162 (array->size - index - 1) * sizeof (void *));
163 array->size--;
164 return value;
165 }
166
167 /**
168 * Return the current size of @var{array}.
169 */
170 size_t
svz_array_size(svz_array_t * array)171 svz_array_size (svz_array_t *array)
172 {
173 if (array == NULL)
174 return 0;
175 return array->size;
176 }
177
178 /*
179 * This function replicates the given array @var{array}. It returns
180 * @code{NULL} if there is nothing to do and an identical copy if the
181 * array otherwise.
182 */
183 svz_array_t *
svz_array_dup(svz_array_t * array)184 svz_array_dup (svz_array_t *array)
185 {
186 svz_array_t *dup;
187
188 if (array == NULL)
189 return NULL;
190 dup = svz_array_create (array->size, array->destroy);
191 dup->size = array->size;
192 if (array->size)
193 memcpy (dup->data, array->data, array->size * sizeof (void *));
194 return dup;
195 }
196
197 /*
198 * This function works something like @code{svz_array_dup} but considers
199 * the values within the array @var{array} to be zero-terminated character
200 * strings and duplicates these via @code{svz_strdup}.
201 */
202 svz_array_t *
svz_array_strdup(svz_array_t * array)203 svz_array_strdup (svz_array_t *array)
204 {
205 svz_array_t *dup;
206 size_t n;
207
208 if (array == NULL)
209 return NULL;
210 dup = svz_array_create (array->size, svz_free);
211 dup->size = array->size;
212 for (n = 0; n < array->size; n++)
213 dup->data[n] = svz_strdup (array->data[n]);
214 return dup;
215 }
216
217 /*
218 * This function destroys the given array @var{array} if it holds no
219 * elements and returns @code{NULL} in this case. Otherwise the
220 * function returns the given array.
221 */
222 svz_array_t *
svz_array_destroy_zero(svz_array_t * array)223 svz_array_destroy_zero (svz_array_t *array)
224 {
225 if (array && array->size == 0)
226 {
227 svz_array_destroy (array);
228 return NULL;
229 }
230 return array;
231 }
232