1 |
|
|
/* |
2 |
|
|
Teem: Tools to process and visualize scientific data and images . |
3 |
|
|
Copyright (C) 2013, 2012, 2011, 2010, 2009 University of Chicago |
4 |
|
|
Copyright (C) 2008, 2007, 2006, 2005 Gordon Kindlmann |
5 |
|
|
Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998 University of Utah |
6 |
|
|
|
7 |
|
|
This library is free software; you can redistribute it and/or |
8 |
|
|
modify it under the terms of the GNU Lesser General Public License |
9 |
|
|
(LGPL) as published by the Free Software Foundation; either |
10 |
|
|
version 2.1 of the License, or (at your option) any later version. |
11 |
|
|
The terms of redistributing and/or modifying this software also |
12 |
|
|
include exceptions to the LGPL that facilitate static linking. |
13 |
|
|
|
14 |
|
|
This library is distributed in the hope that it will be useful, |
15 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 |
|
|
Lesser General Public License for more details. |
18 |
|
|
|
19 |
|
|
You should have received a copy of the GNU Lesser General Public License |
20 |
|
|
along with this library; if not, write to Free Software Foundation, Inc., |
21 |
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
22 |
|
|
*/ |
23 |
|
|
|
24 |
|
|
#include "air.h" |
25 |
|
|
|
26 |
|
|
static void |
27 |
|
|
_airLenSet(airArray *a, unsigned int len) { |
28 |
|
|
|
29 |
|
217890 |
a->len = len; |
30 |
|
|
/* printf(" HEY: len = %d\n", a->len); */ |
31 |
✓✓ |
108945 |
if (a->lenP) { |
32 |
|
1051 |
*(a->lenP) = len; |
33 |
|
|
/* printf(" HEY: *(a->lenP) = *(%lu) = %d\n", |
34 |
|
|
(unsigned long)a->lenP, *(a->lenP)); */ |
35 |
|
1051 |
} |
36 |
|
108945 |
} |
37 |
|
|
|
38 |
|
|
static void |
39 |
|
|
_airSetData(airArray *a, void *data) { |
40 |
|
|
|
41 |
|
111030 |
a->data = data; |
42 |
✓✓ |
55515 |
if (a->dataP) { |
43 |
|
45506 |
*(a->dataP) = data; |
44 |
|
45506 |
} |
45 |
|
55515 |
} |
46 |
|
|
|
47 |
|
|
/* |
48 |
|
|
******** airArrayNew() |
49 |
|
|
** |
50 |
|
|
** creates a new airArray struct and returns a pointer to it. |
51 |
|
|
** dataP is a pointer to the user's data pointer |
52 |
|
|
** lenP is a pointer to the user's array length variable (optional) |
53 |
|
|
** unit is the size (in bytes) of one element in the array |
54 |
|
|
** incr is the number of units by which the array will grow or shrink |
55 |
|
|
** |
56 |
|
|
** returns NULL on error, or the new airArray pointer if okay |
57 |
|
|
** errors: bogus arguments, or couldn't alloc airArray struct |
58 |
|
|
** |
59 |
|
|
** --> The user CAN NOT change the pointer variable (of which *dataP |
60 |
|
|
** is the address) after this is called, or else everything will |
61 |
|
|
** get all bolloxed up. The same goes for the array length |
62 |
|
|
** variable, if its address is passed- though in that case the |
63 |
|
|
** correct value will over-write any other. |
64 |
|
|
*/ |
65 |
|
|
airArray * |
66 |
|
|
airArrayNew(void **dataP, unsigned int *lenP, size_t unit, unsigned int incr) { |
67 |
|
|
airArray *a; |
68 |
|
|
|
69 |
✗✓ |
10704 |
if (!unit || !incr) { |
70 |
|
|
return NULL; |
71 |
|
|
} |
72 |
|
|
|
73 |
|
5352 |
a = AIR_CALLOC(1, airArray); |
74 |
✗✓ |
5352 |
if (!a) { |
75 |
|
|
return NULL; |
76 |
|
|
} |
77 |
|
|
|
78 |
|
5352 |
a->dataP = dataP; |
79 |
|
5352 |
_airSetData(a, NULL); |
80 |
|
5352 |
a->lenP = lenP; |
81 |
|
5352 |
_airLenSet(a, 0); |
82 |
|
5352 |
a->incr = incr; |
83 |
|
5352 |
a->unit = unit; |
84 |
|
5352 |
a->noReallocWhenSmaller = AIR_FALSE; |
85 |
|
|
|
86 |
|
5352 |
a->allocCB = NULL; |
87 |
|
5352 |
a->freeCB = NULL; |
88 |
|
5352 |
a->initCB = NULL; |
89 |
|
5352 |
a->doneCB = NULL; |
90 |
|
|
|
91 |
|
5352 |
return a; |
92 |
|
5352 |
} |
93 |
|
|
|
94 |
|
|
/* |
95 |
|
|
******** airArrayStructCB() |
96 |
|
|
** |
97 |
|
|
** set callbacks to maintain array of structs |
98 |
|
|
*/ |
99 |
|
|
void |
100 |
|
|
airArrayStructCB(airArray *a, |
101 |
|
|
void (*initCB)(void *), void (*doneCB)(void *)) { |
102 |
|
|
|
103 |
|
|
if (a) { |
104 |
|
|
a->initCB = initCB; |
105 |
|
|
a->doneCB = doneCB; |
106 |
|
|
a->allocCB = NULL; |
107 |
|
|
a->freeCB = NULL; |
108 |
|
|
} |
109 |
|
|
} |
110 |
|
|
|
111 |
|
|
/* |
112 |
|
|
******** airArrayPointerCB() |
113 |
|
|
** |
114 |
|
|
** set callbacks to maintain array of pointers |
115 |
|
|
*/ |
116 |
|
|
void |
117 |
|
|
airArrayPointerCB(airArray *a, |
118 |
|
|
void *(*allocCB)(void), void *(*freeCB)(void *)) { |
119 |
|
|
|
120 |
✓✗ |
1444 |
if (a) { |
121 |
|
722 |
a->initCB = NULL; |
122 |
|
722 |
a->doneCB = NULL; |
123 |
|
722 |
a->allocCB = allocCB; |
124 |
|
722 |
a->freeCB = freeCB; |
125 |
|
722 |
} |
126 |
|
722 |
} |
127 |
|
|
|
128 |
|
|
/* ---- BEGIN non-NrrdIO */ |
129 |
|
|
/* |
130 |
|
|
******** airArrayLenPreSet() |
131 |
|
|
** |
132 |
|
|
** allocates the array to hold up to given length, without |
133 |
|
|
** actually changing the length. In order for this to be |
134 |
|
|
** useful, this also turns on noReallocWhenSmaller |
135 |
|
|
** |
136 |
|
|
** NB: this used to have a "boolean" return to indicate allocation |
137 |
|
|
** error, but nothing in Teem actually did the error checking. Now |
138 |
|
|
** conscientious users can look at NULL-ity of a->data to detect such |
139 |
|
|
** an error. |
140 |
|
|
*/ |
141 |
|
|
void |
142 |
|
|
airArrayLenPreSet(airArray *a, unsigned int newlen) { |
143 |
|
|
/* char me[]="airArrayLenPreSet"; */ |
144 |
|
|
unsigned int newsize; |
145 |
|
|
void *newdata; |
146 |
|
|
|
147 |
|
|
if (!a) { |
148 |
|
|
return; |
149 |
|
|
} |
150 |
|
|
|
151 |
|
|
if (newlen == 0) { |
152 |
|
|
/* there is no pre-set length, turn off noReallocWhenSmaller */ |
153 |
|
|
a->noReallocWhenSmaller = AIR_FALSE; |
154 |
|
|
} else { |
155 |
|
|
newsize = (newlen-1)/a->incr + 1; |
156 |
|
|
/* |
157 |
|
|
fprintf(stderr, "!%s: newlen = %u, incr = %u -> newsize = %u\n", me, |
158 |
|
|
newlen, a->incr, newsize); |
159 |
|
|
fprintf(stderr, "!%s: a->size = %u, a->len = %u, a->unit = %u\n", me, |
160 |
|
|
a->size, a->len, a->unit); |
161 |
|
|
*/ |
162 |
|
|
if (newsize > a->size) { |
163 |
|
|
newdata = calloc(newsize*a->incr, a->unit); |
164 |
|
|
/* |
165 |
|
|
fprintf(stderr, "!%s: a->data = %p, newdata = %p\n", me, |
166 |
|
|
a->data, newdata); |
167 |
|
|
*/ |
168 |
|
|
if (!newdata) { |
169 |
|
|
free(a->data); |
170 |
|
|
_airSetData(a, NULL); |
171 |
|
|
return; |
172 |
|
|
} |
173 |
|
|
if (a->data) { |
174 |
|
|
memcpy(newdata, a->data, AIR_MIN(a->len*a->unit, |
175 |
|
|
newsize*a->incr*a->unit)); |
176 |
|
|
free(a->data); |
177 |
|
|
} |
178 |
|
|
_airSetData(a, newdata); |
179 |
|
|
a->size = newsize; |
180 |
|
|
} |
181 |
|
|
a->noReallocWhenSmaller = AIR_TRUE; |
182 |
|
|
} |
183 |
|
|
|
184 |
|
|
/* fprintf(stderr, "!%s: returning data %p\n", me, a->data); */ |
185 |
|
|
return; |
186 |
|
|
} |
187 |
|
|
/* ---- END non-NrrdIO */ |
188 |
|
|
|
189 |
|
|
/* |
190 |
|
|
******** airArrayLenSet() |
191 |
|
|
** |
192 |
|
|
** Set the length of the array, allocating or freeing as needed |
193 |
|
|
** |
194 |
|
|
** returns 1 on error, otherwise 0 if okay |
195 |
|
|
** possible errors: bogus arguments, or couldn't allocate new memory segment |
196 |
|
|
** |
197 |
|
|
** In case we can't allocate the new space, the old space is left untouched, |
198 |
|
|
** however if the new length is smaller, the free/done callbacks will |
199 |
|
|
** have been called on invalidated elements |
200 |
|
|
** |
201 |
|
|
** NB: this used to have a "boolean" return to indicate allocation |
202 |
|
|
** error, but almost nothing in Teem actually did the error checking. |
203 |
|
|
** Now conscientious users can look at NULL-ity of a->data to detect |
204 |
|
|
** such an error. |
205 |
|
|
*/ |
206 |
|
|
void |
207 |
|
|
airArrayLenSet(airArray *a, unsigned int newlen) { |
208 |
|
|
/* char me[]="airArrayLenSet"; */ |
209 |
|
|
unsigned int ii, newsize; |
210 |
|
|
void *addr, *newdata; |
211 |
|
|
|
212 |
✗✓ |
217204 |
if (!a) { |
213 |
|
|
/* user is a moron, what can you do */ |
214 |
|
|
return; |
215 |
|
|
} |
216 |
|
|
|
217 |
✓✓ |
108602 |
if (newlen == a->len) { |
218 |
|
|
/* nothing to do */ |
219 |
|
5009 |
return; |
220 |
|
|
} |
221 |
|
|
|
222 |
|
|
/* call freeCB/doneCB on all the elements which are going bye-bye */ |
223 |
|
|
/* Wed Sep 12 14:40:45 EDT 2007: the order in which these called is |
224 |
|
|
now ascending, instead of descending (as was the way before) */ |
225 |
✓✓✓✓ ✗✓ |
110372 |
if (newlen < a->len && (a->freeCB || a->doneCB)) { |
226 |
✓✓ |
570 |
for (ii=newlen; ii<a->len; ii++) { |
227 |
|
198 |
addr = (char*)(a->data) + ii*a->unit; |
228 |
✓✗ |
198 |
if (a->freeCB) { |
229 |
|
198 |
(a->freeCB)(*((void**)addr)); |
230 |
|
198 |
} else { |
231 |
|
|
(a->doneCB)(addr); |
232 |
|
|
} |
233 |
|
|
} |
234 |
|
|
} |
235 |
|
|
|
236 |
✓✓ |
307355 |
newsize = newlen ? (newlen-1)/a->incr + 1 : 0; |
237 |
✓✓ |
103593 |
if (newsize != a->size) { |
238 |
|
|
/* we have to change the size of the array */ |
239 |
✓✓ |
50163 |
if (newsize) { |
240 |
|
|
/* array should be bigger or smaller, but not zero-length */ |
241 |
✓✗ |
46740 |
if (newsize > a->size |
242 |
✓✓✓✗
|
46741 |
|| (newsize < a->size && !(a->noReallocWhenSmaller)) ) { |
243 |
|
46739 |
newdata = calloc(newsize*a->incr, a->unit); |
244 |
✗✓ |
46739 |
if (!newdata) { |
245 |
|
|
free(a->data); |
246 |
|
|
_airSetData(a, NULL); |
247 |
|
|
return; |
248 |
|
|
} |
249 |
✓✓ |
140217 |
memcpy(newdata, a->data, AIR_MIN(a->len*a->unit, |
250 |
|
|
newsize*a->incr*a->unit)); |
251 |
|
46739 |
free(a->data); |
252 |
|
46739 |
_airSetData(a, newdata); |
253 |
|
46739 |
a->size = newsize; |
254 |
|
46739 |
} |
255 |
|
|
} else { |
256 |
|
|
/* array should be zero-length */ |
257 |
|
3424 |
free(a->data); |
258 |
|
3424 |
_airSetData(a, NULL); |
259 |
|
3424 |
a->size = newsize; |
260 |
|
|
} |
261 |
|
|
} |
262 |
|
|
/* else new size is still within current allocated length, |
263 |
|
|
and neither "size" nor "data" need to change */ |
264 |
|
|
|
265 |
|
|
/* call allocCB/initCB on newly created elements */ |
266 |
✓✓✓✓ ✗✓ |
303765 |
if (newlen > a->len && (a->allocCB || a->initCB)) { |
267 |
✓✓ |
592 |
for (ii=a->len; ii<newlen; ii++) { |
268 |
|
148 |
addr = (char*)(a->data) + ii*a->unit; |
269 |
✓✗ |
148 |
if (a->allocCB) { |
270 |
|
148 |
*((void**)addr) = (a->allocCB)(); |
271 |
|
148 |
} else { |
272 |
|
|
(a->initCB)(addr); |
273 |
|
|
} |
274 |
|
|
} |
275 |
|
|
} |
276 |
|
103593 |
_airLenSet(a, newlen); |
277 |
|
|
|
278 |
|
103593 |
return; |
279 |
|
108602 |
} |
280 |
|
|
|
281 |
|
|
/* |
282 |
|
|
******** airArrayLenIncr() |
283 |
|
|
** |
284 |
|
|
** Like airArrayLenSet, but works with an increment instead of an |
285 |
|
|
** absolute length. Return value is different: |
286 |
|
|
** got NULL: return 0 |
287 |
|
|
** allocation error: return 0, and a->data set to NULL |
288 |
|
|
** no error, delta > 0: return index of 1st element in newly allocated |
289 |
|
|
** segment (a->len before length was increased) |
290 |
|
|
** no error, delta <= 0: return 0, and a->data unchanged |
291 |
|
|
** |
292 |
|
|
** HEY: it is apparently not clear how to do error checking (aside from |
293 |
|
|
** looking at a->data) when there was NO data previously allocated, and the |
294 |
|
|
** first index of the newly allocated data is zero. |
295 |
|
|
*/ |
296 |
|
|
unsigned int |
297 |
|
|
airArrayLenIncr(airArray *a, int delta) { |
298 |
|
|
/* char me[]="airArrayLenIncr"; */ |
299 |
|
|
unsigned int oldlen, ret, negdel; |
300 |
|
|
|
301 |
✗✓ |
200220 |
if (!a) { |
302 |
|
|
return 0; |
303 |
|
|
} |
304 |
|
200220 |
negdel = (delta < 0 |
305 |
|
100110 |
? AIR_UINT(-delta) |
306 |
|
|
: 0); |
307 |
✓✓✗✓
|
100135 |
if (delta < 0 && negdel > a->len) { |
308 |
|
|
/* error: asked for newlength to be negative */ |
309 |
|
|
airArrayLenSet(a, 0); |
310 |
|
|
return 0; |
311 |
|
|
} |
312 |
|
100110 |
oldlen = a->len; |
313 |
|
200220 |
airArrayLenSet(a, (delta >= 0 |
314 |
|
100110 |
? oldlen + AIR_UINT(delta) |
315 |
|
100110 |
: oldlen - negdel)); |
316 |
✓✓ |
100110 |
if (!a->data) { |
317 |
|
|
/* allocation error */ |
318 |
|
|
ret = 0; |
319 |
|
16 |
} else { |
320 |
|
100094 |
ret = (delta <= 0 ? 0 : oldlen); |
321 |
|
|
} |
322 |
|
|
|
323 |
|
100110 |
return ret; |
324 |
|
100110 |
} |
325 |
|
|
|
326 |
|
|
/* |
327 |
|
|
******** airArrayNuke() |
328 |
|
|
** |
329 |
|
|
** free both the memory pointed to by the struct and the struct itself |
330 |
|
|
*/ |
331 |
|
|
airArray * |
332 |
|
|
airArrayNuke(airArray *a) { |
333 |
|
|
|
334 |
✓✗ |
8234 |
if (a) { |
335 |
|
4117 |
airArrayLenSet(a, 0); |
336 |
|
4117 |
free(a); |
337 |
|
4117 |
} |
338 |
|
4117 |
return NULL; |
339 |
|
|
} |
340 |
|
|
|
341 |
|
|
/* |
342 |
|
|
******** airArrayNix() |
343 |
|
|
** |
344 |
|
|
** frees just the struct, leaving the memory it points to untouched |
345 |
|
|
*/ |
346 |
|
|
airArray * |
347 |
|
|
airArrayNix(airArray *a) { |
348 |
|
|
|
349 |
✓✗ |
2438 |
if (a) { |
350 |
|
1219 |
free(a); |
351 |
|
1219 |
} |
352 |
|
1219 |
return NULL; |
353 |
|
|
} |