GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/air/array.c Lines: 88 123 71.5 %
Date: 2017-05-26 Branches: 47 78 60.3 %

Line Branch Exec Source
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
}