GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/nrrd/accessors.c Lines: 24 109 22.0 %
Date: 2017-05-26 Branches: 26 174 14.9 %

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 "nrrd.h"
25
#include "privateNrrd.h"
26
#include "float.h"
27
28
/*
29
** making these typedefs here allows us to used one token for both
30
** constructing function names, and for specifying argument types
31
*/
32
typedef signed char CH;
33
typedef unsigned char UC;
34
typedef signed short SH;
35
typedef unsigned short US;
36
/* Microsoft apparently uses 'IN' as a keyword, so we changed 'IN' to 'JN'. */
37
typedef signed int JN;
38
typedef unsigned int UI;
39
typedef airLLong LL;
40
/* ui64 to double conversion is not implemented, sorry */
41
#if _MSC_VER < 1300
42
typedef airLLong UL;
43
#else
44
typedef airULLong UL;
45
#endif
46
typedef float FL;
47
typedef double DB;
48
49
#define MAP(F, A) \
50
F(A, CH) \
51
F(A, UC) \
52
F(A, SH) \
53
F(A, US) \
54
F(A, JN) \
55
F(A, UI) \
56
F(A, LL) \
57
F(A, UL) \
58
F(A, FL) \
59
F(A, DB)
60
61
/*
62
** _nrrdLoad<TA><TB>(<TB> *v)
63
**
64
** Dereferences v as TB*, casts it to TA, returns it.
65
*/
66
#define LOAD_DEF(TA, TB)                    \
67
static TA                                   \
68
_nrrdLoad##TA##TB(TB *v) {                  \
69
  return (TA)(*v);                          \
70
}
71
#define LOAD_LIST(TA, TB)                   \
72
  (TA (*)(const void *))_nrrdLoad##TA##TB,
73
74
MAP(LOAD_DEF, UI)
75
MAP(LOAD_DEF, JN)
76
MAP(LOAD_DEF, FL)
77
24906248
MAP(LOAD_DEF, DB)
78
79
unsigned int (*
80
nrrdUILoad[NRRD_TYPE_MAX+1])(const void*) = {
81
  NULL, MAP(LOAD_LIST, UI) NULL
82
};
83
int (*
84
nrrdILoad[NRRD_TYPE_MAX+1])(const void*) = {
85
  NULL, MAP(LOAD_LIST, JN) NULL
86
};
87
float (*
88
nrrdFLoad[NRRD_TYPE_MAX+1])(const void*) = {
89
  NULL, MAP(LOAD_LIST, FL) NULL
90
};
91
double (*
92
nrrdDLoad[NRRD_TYPE_MAX+1])(const void*) = {
93
  NULL, MAP(LOAD_LIST, DB) NULL
94
};
95
96
97
/*
98
** _nrrdStore<TA><TB>(<TB> *v, <TA> j)
99
**
100
** Takes a TA j, and stores it in *v, thereby implicitly casting it to TB.
101
** Returns the result of the assignment, which may not be the same as
102
** the value that was passed in.
103
*/
104
#define STORE_DEF(TA, TB)                   \
105
static TA                                   \
106
_nrrdStore##TA##TB(TB *v, TA j) {           \
107
  return (TA)(*v = (TB)j);                  \
108
}
109
#define STORE_LIST(TA, TB)                  \
110
  (TA (*)(void *, TA))_nrrdStore##TA##TB,
111
112
MAP(STORE_DEF, UI)
113
MAP(STORE_DEF, JN)
114
MAP(STORE_DEF, FL)
115
MAP(STORE_DEF, DB)
116
117
unsigned int (*
118
nrrdUIStore[NRRD_TYPE_MAX+1])(void *, unsigned int) = {
119
  NULL, MAP(STORE_LIST, UI) NULL
120
};
121
int (*
122
nrrdIStore[NRRD_TYPE_MAX+1])(void *, int) = {
123
  NULL, MAP(STORE_LIST, JN) NULL
124
};
125
float (*
126
nrrdFStore[NRRD_TYPE_MAX+1])(void *, float) = {
127
  NULL, MAP(STORE_LIST, FL) NULL
128
};
129
double (*
130
nrrdDStore[NRRD_TYPE_MAX+1])(void *, double) = {
131
  NULL, MAP(STORE_LIST, DB) NULL
132
};
133
134
135
/*
136
** _nrrdLookup<TA><TB>(<TB> *v, size_t I)
137
**
138
** Looks up element I of TB array v, and returns it cast to a TA.
139
*/
140
#define LOOKUP_DEF(TA, TB)                    \
141
static TA                                     \
142
_nrrdLookup##TA##TB(TB *v, size_t I) {        \
143
  return (TA)v[I];                            \
144
}
145
#define LOOKUP_LIST(TA, TB)                   \
146
  (TA (*)(const void*, size_t))_nrrdLookup##TA##TB,
147
148
MAP(LOOKUP_DEF, UI)
149
MAP(LOOKUP_DEF, JN)
150
MAP(LOOKUP_DEF, FL)
151
2382557856
MAP(LOOKUP_DEF, DB)
152
153
unsigned int (*
154
nrrdUILookup[NRRD_TYPE_MAX+1])(const void *, size_t) = {
155
  NULL, MAP(LOOKUP_LIST, UI) NULL
156
};
157
int (*
158
nrrdILookup[NRRD_TYPE_MAX+1])(const void *, size_t) = {
159
  NULL, MAP(LOOKUP_LIST, JN) NULL
160
};
161
float (*
162
nrrdFLookup[NRRD_TYPE_MAX+1])(const void *, size_t) = {
163
  NULL, MAP(LOOKUP_LIST, FL) NULL
164
};
165
double (*
166
nrrdDLookup[NRRD_TYPE_MAX+1])(const void *, size_t) = {
167
  NULL, MAP(LOOKUP_LIST, DB) NULL
168
};
169
170
171
/*
172
** _nrrdInsert<TA><TB>(<TB> *v, size_t I, <TA> j)
173
**
174
** Given TA j, stores it in v[i] (implicitly casting to TB).
175
** Returns the result of the assignment, which may not be the same as
176
** the value that was passed in.
177
*/
178
#define INSERT_DEF(TA, TB)                         \
179
static TA                                          \
180
_nrrdInsert##TA##TB(TB *v, size_t I, TA j) {       \
181
  return (TA)(v[I] = (TB)j);                       \
182
}
183
#define INSERT_LIST(TA, TB)                        \
184
  (TA (*)(void*, size_t, TA))_nrrdInsert##TA##TB,
185
186
MAP(INSERT_DEF, UI)
187
MAP(INSERT_DEF, JN)
188
MAP(INSERT_DEF, FL)
189
33025688
MAP(INSERT_DEF, DB)
190
191
unsigned int (*
192
nrrdUIInsert[NRRD_TYPE_MAX+1])(void *, size_t, unsigned int) = {
193
  NULL, MAP(INSERT_LIST, UI) NULL
194
};
195
int (*
196
nrrdIInsert[NRRD_TYPE_MAX+1])(void *, size_t, int) = {
197
  NULL, MAP(INSERT_LIST, JN) NULL
198
};
199
float (*
200
nrrdFInsert[NRRD_TYPE_MAX+1])(void *, size_t, float) = {
201
  NULL, MAP(INSERT_LIST, FL) NULL
202
};
203
double (*
204
nrrdDInsert[NRRD_TYPE_MAX+1])(void *, size_t, double) = {
205
  NULL, MAP(INSERT_LIST, DB) NULL
206
};
207
208
/*
209
******** nrrdSprint
210
**
211
** Dereferences pointer v and sprintf()s that value into given string s,
212
** returns the result of sprintf()
213
**
214
** There is obviously no provision for ensuring that the sprint'ing
215
** doesn't overflow the buffer, which is unfortunate...
216
*/
217
static int _nrrdSprintCH(char *s, const CH *v) { return sprintf(s, "%d", *v); }
218
static int _nrrdSprintUC(char *s, const UC *v) { return sprintf(s, "%u", *v); }
219
static int _nrrdSprintSH(char *s, const SH *v) { return sprintf(s, "%d", *v); }
220
static int _nrrdSprintUS(char *s, const US *v) { return sprintf(s, "%u", *v); }
221
static int _nrrdSprintIN(char *s, const JN *v) { return sprintf(s, "%d", *v); }
222
static int _nrrdSprintUI(char *s, const UI *v) { return sprintf(s, "%u", *v); }
223
static int _nrrdSprintLL(char *s, const LL *v) {
224
  return sprintf(s, AIR_LLONG_FMT, *v);
225
}
226
static int _nrrdSprintUL(char *s, const UL *v) {
227
  return sprintf(s, AIR_ULLONG_FMT, *v);
228
}
229
/* HEY: sizeof(float) and sizeof(double) assumed here, since we're
230
   basing "8" and "17" on 6 == FLT_DIG and 15 == DBL_DIG, which are
231
   digits of precision for floats and doubles, respectively */
232
static int _nrrdSprintFL(char *s, const FL *v) {
233
  return airSinglePrintf(NULL, s, "%.8g", (double)(*v)); }
234
static int _nrrdSprintDB(char *s, const DB *v) {
235
  return airSinglePrintf(NULL, s, "%.17g", *v); }
236
int (*
237
nrrdSprint[NRRD_TYPE_MAX+1])(char *, const void *) = {
238
  NULL,
239
  (int (*)(char *, const void *))_nrrdSprintCH,
240
  (int (*)(char *, const void *))_nrrdSprintUC,
241
  (int (*)(char *, const void *))_nrrdSprintSH,
242
  (int (*)(char *, const void *))_nrrdSprintUS,
243
  (int (*)(char *, const void *))_nrrdSprintIN,
244
  (int (*)(char *, const void *))_nrrdSprintUI,
245
  (int (*)(char *, const void *))_nrrdSprintLL,
246
  (int (*)(char *, const void *))_nrrdSprintUL,
247
  (int (*)(char *, const void *))_nrrdSprintFL,
248
  (int (*)(char *, const void *))_nrrdSprintDB,
249
  NULL};
250
251
/* ---- BEGIN non-NrrdIO */
252
253
/*
254
******** nrrdFprint
255
**
256
** Dereferences pointer v and fprintf()s that value into given file f;
257
** returns the result of fprintf()
258
*/
259
static int _nrrdFprintCH(FILE *f, const CH *v) { return fprintf(f, "%d", *v); }
260
static int _nrrdFprintUC(FILE *f, const UC *v) { return fprintf(f, "%u", *v); }
261
static int _nrrdFprintSH(FILE *f, const SH *v) { return fprintf(f, "%d", *v); }
262
static int _nrrdFprintUS(FILE *f, const US *v) { return fprintf(f, "%u", *v); }
263
static int _nrrdFprintIN(FILE *f, const JN *v) { return fprintf(f, "%d", *v); }
264
static int _nrrdFprintUI(FILE *f, const UI *v) { return fprintf(f, "%u", *v); }
265
static int _nrrdFprintLL(FILE *f, const LL *v) {
266
  return fprintf(f, AIR_LLONG_FMT, *v);
267
}
268
static int _nrrdFprintUL(FILE *f, const UL *v) {
269
  return fprintf(f, AIR_ULLONG_FMT, *v);
270
}
271
static int _nrrdFprintFL(FILE *f, const FL *v) {
272
  return airSinglePrintf(f, NULL, "%.8g", (double)(*v)); }
273
static int _nrrdFprintDB(FILE *f, const DB *v) {
274
  return airSinglePrintf(f, NULL, "%.17g", *v); }
275
int (*
276
nrrdFprint[NRRD_TYPE_MAX+1])(FILE *, const void *) = {
277
  NULL,
278
  (int (*)(FILE *, const void *))_nrrdFprintCH,
279
  (int (*)(FILE *, const void *))_nrrdFprintUC,
280
  (int (*)(FILE *, const void *))_nrrdFprintSH,
281
  (int (*)(FILE *, const void *))_nrrdFprintUS,
282
  (int (*)(FILE *, const void *))_nrrdFprintIN,
283
  (int (*)(FILE *, const void *))_nrrdFprintUI,
284
  (int (*)(FILE *, const void *))_nrrdFprintLL,
285
  (int (*)(FILE *, const void *))_nrrdFprintUL,
286
  (int (*)(FILE *, const void *))_nrrdFprintFL,
287
  (int (*)(FILE *, const void *))_nrrdFprintDB,
288
  NULL};
289
290
/* about here is where Gordon admits he might have some use for C++ */
291
292
#define _MMEF_ARGS(type) type *minP, type *maxP, int *hneP, const Nrrd *nrrd
293
294
#define _MMEF_FIXED(type)                                                \
295
  size_t I, N;                                                           \
296
  type a, b, min, max, *v;                                               \
297
                                                                         \
298
  if (!(minP && maxP))                                                   \
299
    return;                                                              \
300
                                                                         \
301
  /* all integral values exist */                                        \
302
  *hneP = nrrdHasNonExistFalse;                                          \
303
                                                                         \
304
  /* set the local data pointer */                                       \
305
  v = (type*)(nrrd->data);                                               \
306
                                                                         \
307
  /* get initial values */                                               \
308
  N = nrrdElementNumber(nrrd);                                           \
309
  min = max = v[0];                                                      \
310
                                                                         \
311
  /* run through array in pairs; by doing a compare on successive        \
312
     elements, we can do three compares per pair instead of the naive    \
313
     four.  In one very unexhaustive test on irix6.64, this resulted     \
314
     in a 20% decrease in running time.  I learned this trick from       \
315
     Numerical Recipes in C, long time ago, but I can't find it          \
316
     anywhere in the book now ... */                                     \
317
  if (N>1) /* size_t is unsigned, so N-2 may overflow */                 \
318
  for (I=0; I<=N-2; I+=2) {                                              \
319
    a = v[0 + I];                                                        \
320
    b = v[1 + I];                                                        \
321
    if (a < b) {                                                         \
322
      min = AIR_MIN(a, min);                                             \
323
      max = AIR_MAX(b, max);                                             \
324
    } else {                                                             \
325
      max = AIR_MAX(a, max);                                             \
326
      min = AIR_MIN(b, min);                                             \
327
    }                                                                    \
328
  }                                                                      \
329
                                                                         \
330
  /* get the very last one (may be redundant) */                         \
331
  a = v[N-1];                                                            \
332
  min = AIR_MIN(a, min);                                                 \
333
  max = AIR_MAX(a, max);                                                 \
334
                                                                         \
335
  /* record results */                                                   \
336
  *minP = min;                                                           \
337
  *maxP = max;
338
339
#define _MMEF_FLOAT(type)                                                \
340
  size_t I, N;                                                           \
341
  type a, min, max, *v;                                                  \
342
                                                                         \
343
  if (!(minP && maxP))                                                   \
344
    return;                                                              \
345
                                                                         \
346
  /* this may be over-written below */                                   \
347
  *hneP = nrrdHasNonExistFalse;                                          \
348
                                                                         \
349
  /* set the local data pointer */                                       \
350
  N = nrrdElementNumber(nrrd);                                           \
351
  v = (type*)(nrrd->data);                                               \
352
                                                                         \
353
  /* we have to explicitly search for the first non-NaN value */         \
354
  max = min = AIR_NAN;                                                   \
355
  for (I=0; I<N; I++) {                                                  \
356
    a = v[I];                                                            \
357
    if (AIR_EXISTS(a)) {                                                 \
358
      min = max = a;                                                     \
359
      break;                                                             \
360
    } else {                                                             \
361
      *hneP = nrrdHasNonExistTrue;                                       \
362
    }                                                                    \
363
  }                                                                      \
364
  if (I == N) {                                                          \
365
    /* oh dear, there were NO existent values */                         \
366
    min = max = AIR_NAN;                                                 \
367
    *hneP = nrrdHasNonExistOnly;                                         \
368
  } else {                                                               \
369
    /* there was at least one existent value; we continue searching,     \
370
       still checking AIR_EXISTS at each value */                        \
371
    for (I=I+1; I<N; I++) {                                              \
372
      a = v[I];                                                          \
373
      if (AIR_EXISTS(a)) {                                               \
374
        if (a < min) {                                                   \
375
          min = a;                                                       \
376
        } else {                                                         \
377
          if (a > max) {                                                 \
378
            max = a;                                                     \
379
          }                                                              \
380
        }                                                                \
381
      } else {                                                           \
382
        *hneP = nrrdHasNonExistTrue;                                     \
383
      }                                                                  \
384
    }                                                                    \
385
  }                                                                      \
386
  *minP = min;                                                           \
387
  *maxP = max;
388
389
static void _nrrdMinMaxExactFindCH (_MMEF_ARGS(CH)) {_MMEF_FIXED(CH)}
390
static void _nrrdMinMaxExactFindUC (_MMEF_ARGS(UC)) {_MMEF_FIXED(UC)}
391
static void _nrrdMinMaxExactFindSH (_MMEF_ARGS(SH)) {_MMEF_FIXED(SH)}
392
static void _nrrdMinMaxExactFindUS (_MMEF_ARGS(US)) {_MMEF_FIXED(US)}
393
static void _nrrdMinMaxExactFindIN (_MMEF_ARGS(JN)) {_MMEF_FIXED(JN)}
394
static void _nrrdMinMaxExactFindUI (_MMEF_ARGS(UI)) {_MMEF_FIXED(UI)}
395
static void _nrrdMinMaxExactFindLL (_MMEF_ARGS(LL)) {_MMEF_FIXED(LL)}
396
static void _nrrdMinMaxExactFindUL (_MMEF_ARGS(UL)) {_MMEF_FIXED(UL)}
397
static void _nrrdMinMaxExactFindFL (_MMEF_ARGS(FL)) {_MMEF_FLOAT(FL)}
398




840537
static void _nrrdMinMaxExactFindDB (_MMEF_ARGS(DB)) {_MMEF_FLOAT(DB)}
399
400
/*
401
******** nrrdMinMaxExactFind[]
402
**
403
** the role of these is to allow finding the EXACT min and max of a nrrd,
404
** so that one does not have to rely on the potentially lossy storage
405
** of the min and max values in range->min and range->max, which are doubles.
406
**
407
** These also sets *hneP, using a value from the nrrdHasNonExist* enum
408
*/
409
void (*
410
nrrdMinMaxExactFind[NRRD_TYPE_MAX+1])(void *minP, void *maxP,
411
                                      int *hneP, const Nrrd *) = {
412
  NULL,
413
  (void (*)(void *, void *, int *, const Nrrd *))_nrrdMinMaxExactFindCH,
414
  (void (*)(void *, void *, int *, const Nrrd *))_nrrdMinMaxExactFindUC,
415
  (void (*)(void *, void *, int *, const Nrrd *))_nrrdMinMaxExactFindSH,
416
  (void (*)(void *, void *, int *, const Nrrd *))_nrrdMinMaxExactFindUS,
417
  (void (*)(void *, void *, int *, const Nrrd *))_nrrdMinMaxExactFindIN,
418
  (void (*)(void *, void *, int *, const Nrrd *))_nrrdMinMaxExactFindUI,
419
  (void (*)(void *, void *, int *, const Nrrd *))_nrrdMinMaxExactFindLL,
420
  (void (*)(void *, void *, int *, const Nrrd *))_nrrdMinMaxExactFindUL,
421
  (void (*)(void *, void *, int *, const Nrrd *))_nrrdMinMaxExactFindFL,
422
  (void (*)(void *, void *, int *, const Nrrd *))_nrrdMinMaxExactFindDB,
423
  NULL
424
};
425
426
/*
427
******** nrrdValCompare[]
428
**
429
** the sort of compare you'd give to qsort() to sort in ascending order:
430
** return < 0 if A < B,
431
**          0 if A == B,
432
**        > 0 if A > B
433
** The non-trivial part of this is that for floating-point values, we
434
** dictate that all non-existent values are smaller than all existent
435
** values, regardless of their actual values (so +infinity < -42).  This
436
** is to make sure that we have comparison that won't confuse qsort(),
437
** which underlies _nrrdMeasureMedian(), and to make it easier to separate
438
** existent from non-existent values.
439
*/
440
#define _VC_ARGS(type) const type *A, const type *B
441
#define _VC_FIXED (*A < *B ? -1 : (*A > *B ? 1 : 0))
442
#define _VC_FLOAT                                                        \
443
  int ex, ret;                                                           \
444
                                                                         \
445
  ex = AIR_EXISTS(*A) + AIR_EXISTS(*B);                                  \
446
  switch (ex) {                                                          \
447
  case 2: ret = _VC_FIXED; break;                                        \
448
  case 1: ret = AIR_EXISTS(*A) ? 1 : -1; break;                          \
449
  case 0: default: ret = 0;                                              \
450
  }
451
452
static int _nrrdValCompareCH (_VC_ARGS(CH)) {return _VC_FIXED;}
453
8000000
static int _nrrdValCompareUC (_VC_ARGS(UC)) {return _VC_FIXED;}
454
static int _nrrdValCompareSH (_VC_ARGS(SH)) {return _VC_FIXED;}
455
static int _nrrdValCompareUS (_VC_ARGS(US)) {return _VC_FIXED;}
456
8000
static int _nrrdValCompareIN (_VC_ARGS(JN)) {return _VC_FIXED;}
457
static int _nrrdValCompareUI (_VC_ARGS(UI)) {return _VC_FIXED;}
458
static int _nrrdValCompareLL (_VC_ARGS(LL)) {return _VC_FIXED;}
459
static int _nrrdValCompareUL (_VC_ARGS(UL)) {return _VC_FIXED;}
460
static int _nrrdValCompareFL (_VC_ARGS(FL)) {_VC_FLOAT; return ret;}
461

1728576
static int _nrrdValCompareDB (_VC_ARGS(DB)) {_VC_FLOAT; return ret;}
462
int (*
463
nrrdValCompare[NRRD_TYPE_MAX+1])(const void *, const void *) = {
464
  NULL,
465
  (int (*)(const void *, const void *))_nrrdValCompareCH,
466
  (int (*)(const void *, const void *))_nrrdValCompareUC,
467
  (int (*)(const void *, const void *))_nrrdValCompareSH,
468
  (int (*)(const void *, const void *))_nrrdValCompareUS,
469
  (int (*)(const void *, const void *))_nrrdValCompareIN,
470
  (int (*)(const void *, const void *))_nrrdValCompareUI,
471
  (int (*)(const void *, const void *))_nrrdValCompareLL,
472
  (int (*)(const void *, const void *))_nrrdValCompareUL,
473
  (int (*)(const void *, const void *))_nrrdValCompareFL,
474
  (int (*)(const void *, const void *))_nrrdValCompareDB,
475
  NULL
476
};
477
478
/*
479
** ...Inv: for descending order
480
*/
481
static int _nrrdValCompareInvCH (_VC_ARGS(CH)) {return -_VC_FIXED;}
482
static int _nrrdValCompareInvUC (_VC_ARGS(UC)) {return -_VC_FIXED;}
483
static int _nrrdValCompareInvSH (_VC_ARGS(SH)) {return -_VC_FIXED;}
484
static int _nrrdValCompareInvUS (_VC_ARGS(US)) {return -_VC_FIXED;}
485
static int _nrrdValCompareInvIN (_VC_ARGS(JN)) {return -_VC_FIXED;}
486
static int _nrrdValCompareInvUI (_VC_ARGS(UI)) {return -_VC_FIXED;}
487
static int _nrrdValCompareInvLL (_VC_ARGS(LL)) {return -_VC_FIXED;}
488
static int _nrrdValCompareInvUL (_VC_ARGS(UL)) {return -_VC_FIXED;}
489
static int _nrrdValCompareInvFL (_VC_ARGS(FL)) {_VC_FLOAT; return -ret;}
490
static int _nrrdValCompareInvDB (_VC_ARGS(DB)) {_VC_FLOAT; return -ret;}
491
int (*
492
nrrdValCompareInv[NRRD_TYPE_MAX+1])(const void *, const void *) = {
493
  NULL,
494
  (int (*)(const void *, const void *))_nrrdValCompareInvCH,
495
  (int (*)(const void *, const void *))_nrrdValCompareInvUC,
496
  (int (*)(const void *, const void *))_nrrdValCompareInvSH,
497
  (int (*)(const void *, const void *))_nrrdValCompareInvUS,
498
  (int (*)(const void *, const void *))_nrrdValCompareInvIN,
499
  (int (*)(const void *, const void *))_nrrdValCompareInvUI,
500
  (int (*)(const void *, const void *))_nrrdValCompareInvLL,
501
  (int (*)(const void *, const void *))_nrrdValCompareInvUL,
502
  (int (*)(const void *, const void *))_nrrdValCompareInvFL,
503
  (int (*)(const void *, const void *))_nrrdValCompareInvDB,
504
  NULL
505
};
506
507
/*
508
** nrrdArrayCompare
509
**
510
** something like strcmp() for arrays of numeric values, except
511
** that the arrays have to be equal length, and it has to do
512
** error checking.
513
**
514
** See comment about logic of return value above nrrdCompare()
515
**
516
** This is a very rare kind of nrrd function that operates on
517
** a bare array and not a Nrrd itself
518
*/
519
int nrrdArrayCompare(int type, const void *_valA, const void *_valB,
520
                     size_t valNum, double epsilon, int *differ,
521
                     char explain[AIR_STRLEN_LARGE]) {
522
  static const char me[]="nrrdArrayCompare";
523
  const unsigned char *valA, *valB;
524
  int (*compare)(const void *, const void *);
525
  size_t ii, sze;
526
20
  char stmp[AIR_STRLEN_SMALL];
527
528
10
  if (!(_valA && _valB && differ)) {
529
    biffAddf(NRRD, "%s: got NULL pointer (%p, %p, or %p)", me,
530
             _valA, _valB, AIR_VOIDP(differ));
531
    return 1;
532
  }
533
10
  if (!valNum) {
534
    biffAddf(NRRD, "%s: can't work with 0-length arrays", me);
535
    return 1;
536
  }
537
10
  if (!AIR_EXISTS(epsilon)) {
538
    biffAddf(NRRD, "%s: non-existent epsilon %g", me, epsilon);
539
    return 1;
540
  }
541
10
  if (airEnumValCheck(nrrdType, type)) {
542
    biffAddf(NRRD, "%s: invalid nrrd type %d", me, type);
543
    return 1;
544
  }
545
10
  if (nrrdTypeBlock == type) {
546
    biffAddf(NRRD, "%s: can't use type %s", me, airEnumStr(nrrdType, type));
547
    return 1;
548
  }
549
550
10
  if (explain) {
551
10
    strcpy(explain, "");
552
10
  }
553
10
  if (type == nrrdTypeLLong || type == nrrdTypeULLong) {
554
    fprintf(stderr, "%s: WARNING: possible erroneous comparison of "
555
            "%s values with %s-based comparison\n", me,
556
            airEnumStr(nrrdType, type),
557
            airEnumStr(nrrdType, nrrdTypeDouble));
558
  }
559
10
  sze = nrrdTypeSize[type];
560
10
  compare = nrrdValCompare[type];
561
  valA = AIR_CAST(const unsigned char *, _valA);
562
  valB = AIR_CAST(const unsigned char *, _valB);
563
4590580
  for (ii=0; ii<valNum; ii++) {
564
2295280
    *differ = compare(valA + ii*sze, valB + ii*sze);
565
2295280
    if (*differ) {
566
      double aa, bb;
567
      /* same loss of precision as warned about above */
568
      aa = nrrdDLookup[type](valA, ii);
569
      bb = nrrdDLookup[type](valB, ii);
570
      if (0 == epsilon
571
          || fabs(aa - bb) > epsilon) {
572
        if (explain) {
573
          airSprintSize_t(stmp, ii);
574
          if (0 == epsilon) {
575
            sprintf(explain, "valA[%s]=%.17g %s valB[%s]=%.17g "
576
                    "by %g",
577
                    stmp, aa, *differ < 0 ? "<" : ">", stmp, bb,
578
                    fabs(aa - bb));
579
          } else {
580
            sprintf(explain, "valA[%s]=%.17g %s valB[%s]=%.17g "
581
                    "by %g, more than eps %g",
582
                    stmp, aa, *differ < 0 ? "<" : ">", stmp, bb,
583
                    fabs(aa - bb), epsilon);
584
          }
585
        }
586
        break;
587
      } else {
588
        /* we did detect a difference, but it was not in excess of
589
           epsilon, so we reset *differ to 0 */
590
        *differ = 0;
591
      }
592
    }
593
  }
594
595
10
  return 0;
596
10
}
597
598
/* ---- END non-NrrdIO */