GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
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 */ |
Generated by: GCOVR (Version 3.3) |