SCM Repository
Annotation of /branches/vis12/src/lib/common/dyn-seq.c
Parent Directory
|
Revision Log
Revision 1978 - (view) (download) (as text)
1 : | jhr | 1733 | /*! \file dyn-seq.c |
2 : | * | ||
3 : | * \author John Reppy | ||
4 : | * | ||
5 : | * An implementation of dynamic sequences. | ||
6 : | */ | ||
7 : | |||
8 : | /* | ||
9 : | * COPYRIGHT (c) 2012 The Diderot Project (http://diderot-language.cs.uchicago.edu) | ||
10 : | * All rights reserved. | ||
11 : | */ | ||
12 : | |||
13 : | #include "Diderot/diderot.h" | ||
14 : | jhr | 1978 | #include <teem/nrrd.h> |
15 : | jhr | 1733 | |
16 : | // compute the address of the i'th element in the sequence | ||
17 : | STATIC_INLINE void* ElemAddr(void *base, size_t elemSz, unsigned int i) | ||
18 : | { | ||
19 : | return (void *)((char *)base + i*elemSz); | ||
20 : | } | ||
21 : | |||
22 : | //! append an element to a sequence | ||
23 : | Diderot_DynSeq_t *Diderot_DynSeqAppend (size_t elemSz, Diderot_DynSeq_t *seq, void *item) | ||
24 : | { | ||
25 : | if (seq->nElems == seq->size) { | ||
26 : | // grow the data array | ||
27 : | unsigned int newSize = (seq->size < 64) ? seq->size + 8 : seq->size + 64; | ||
28 : | void *newData = CheckedAlloc (elemSz * newSize); | ||
29 : | Diderot_DynSeqCopy (elemSz, newData, seq); | ||
30 : | seq->size = newSize; | ||
31 : | seq->base = 0; | ||
32 : | FREE(seq->data); | ||
33 : | seq->data = newData; | ||
34 : | } | ||
35 : | unsigned int i = (seq->base + seq->nElems) % seq->size; | ||
36 : | jhr | 1906 | seq->nElems++; |
37 : | jhr | 1733 | memcpy(ElemAddr(seq->data, elemSz, i), item, elemSz); |
38 : | return seq; | ||
39 : | } | ||
40 : | |||
41 : | //! prepend an element to a sequence | ||
42 : | //Diderot_DynSeq_t *Diderot_DynSeqPrepend (size_t elemSz, void *, Diderot_DynSeq_t *); | ||
43 : | |||
44 : | //! concatenate two sequences | ||
45 : | //Diderot_DynSeq_t *Diderot_DynSeqConcat (size_t elemSz, Diderot_DynSeq_t *, Diderot_DynSeq_t *); | ||
46 : | |||
47 : | //! \brief copy the elements of a sequence to an array | ||
48 : | //! \param elemSz the size of the sequence elements in bytes | ||
49 : | //! \param dst the destination array | ||
50 : | //! \param seq the source sequence | ||
51 : | //! \return the address of the element that follows the array | ||
52 : | void *Diderot_DynSeqCopy (size_t elemSz, void *dst, Diderot_DynSeq_t *seq) | ||
53 : | { | ||
54 : | unsigned int n = seq->nElems; | ||
55 : | if (seq->base + n > seq->size) { | ||
56 : | // sequence wraps around, so we need to copy it in two steps | ||
57 : | n = seq->size - seq->base; | ||
58 : | memcpy (dst, ElemAddr(seq->data, elemSz, seq->base), n*elemSz); | ||
59 : | dst = (void *)((char *)dst + n*elemSz); | ||
60 : | n = seq->nElems - n; | ||
61 : | memcpy (dst, ElemAddr(seq->data, elemSz, 0), n*elemSz); | ||
62 : | return (void *)((char *)dst + n*elemSz); | ||
63 : | } | ||
64 : | else { | ||
65 : | size_t cpySz = n*elemSz; | ||
66 : | memcpy (dst, ElemAddr(seq->data, elemSz, seq->base), cpySz); | ||
67 : | return (void *)((char *)dst + cpySz); | ||
68 : | } | ||
69 : | } | ||
70 : | jhr | 1978 | |
71 : | static struct { | ||
72 : | bool isFloat; | ||
73 : | unsigned int sizeb; | ||
74 : | } NrrdTypeInfo[nrrdTypeLast] = { | ||
75 : | [nrrdTypeDefault] = {false, 0}, /* 0: signifies "determine output type for me" */ | ||
76 : | [nrrdTypeChar] = {false, 1}, /* 1: signed 1-byte integer */ | ||
77 : | [nrrdTypeUChar] = {false, 1}, /* 2: unsigned 1-byte integer */ | ||
78 : | [nrrdTypeShort] = {false, 2}, /* 3: signed 2-byte integer */ | ||
79 : | [nrrdTypeUShort] = {false, 2}, /* 4: unsigned 2-byte integer */ | ||
80 : | [nrrdTypeInt] = {false, 4}, /* 5: signed 4-byte integer */ | ||
81 : | [nrrdTypeUInt] = {false, 4}, /* 6: unsigned 4-byte integer */ | ||
82 : | [nrrdTypeLLong] = {false, 8}, /* 7: signed 8-byte integer */ | ||
83 : | [nrrdTypeULLong] = {false, 8}, /* 8: unsigned 8-byte integer */ | ||
84 : | [nrrdTypeFloat] = {true, 4}, /* 9: 4-byte floating point */ | ||
85 : | [nrrdTypeDouble] = {true, 8}, /* 10: 8-byte floating point */ | ||
86 : | [nrrdTypeBlock] = {false, 0}, /* 11: size user defined at run time; MUST BE LAST */ | ||
87 : | }; | ||
88 : | |||
89 : | //! Check that a nrrd has the expected structure for loading into a dynamic sequence | ||
90 : | //! \param wrld the world; used to report errors | ||
91 : | //! \param nin the nrrd to check | ||
92 : | //! \param nDims the number of dimensions in the sequence elements | ||
93 : | //! \param dims the array of sequence element dimensions | ||
94 : | //! \return the number of values per element, or zero on error | ||
95 : | static unsigned int CheckNrrd ( | ||
96 : | WorldPrefix_t *wrld, | ||
97 : | Nrrd *nin, | ||
98 : | unsigned int nDims, | ||
99 : | unsigned int *dims) | ||
100 : | { | ||
101 : | |||
102 : | // compute the expected number of values per sequence element | ||
103 : | unsigned int nValuesPerElem = 1; | ||
104 : | for (unsigned int i = 0; i < nDims; i++) { | ||
105 : | nValuesPerElem *= dims[i]; | ||
106 : | } | ||
107 : | |||
108 : | // check the structure of the nrrd file | ||
109 : | if (nin->spaceDim != 1) { | ||
110 : | Diderot_Error (wrld, "unexpected number of axes in nrrd; expected 1, found %d\n", | ||
111 : | nin->spaceDim); | ||
112 : | return 0; | ||
113 : | } | ||
114 : | if (nin->dim - 1 != nDims) { | ||
115 : | Diderot_Error (wrld, "unexpected nrrd dimension; expected %d, found %d\n", | ||
116 : | nDims, nin->dim-1); | ||
117 : | return 0; | ||
118 : | } | ||
119 : | for (unsigned int i = 0; i < nDims; i++) { | ||
120 : | if (dims[i] != nin->axis[i+1].size) { | ||
121 : | Diderot_Error (wrld, "nrrd shape does not match expected structure\n"); | ||
122 : | return 0; | ||
123 : | } | ||
124 : | } | ||
125 : | if (NrrdTypeInfo[nin->type].size == 0) { | ||
126 : | Diderot_Error (wrld, "bogus element type %d in nrrd\n", nin->type); | ||
127 : | return 0; | ||
128 : | } | ||
129 : | |||
130 : | return nValuesPerElem; | ||
131 : | } | ||
132 : | |||
133 : | //! load a dynamic sequence from a Nrrd file, where the sequence elements have real ground type. | ||
134 : | //! \param wrld the world; used to report errors | ||
135 : | //! \param nin the nrrd to check | ||
136 : | //! \param nDims the number of dimensions in the sequence elements | ||
137 : | //! \param dims the array of sequence element dimensions | ||
138 : | //! \return the dynamic sequence, or zero on error | ||
139 : | Diderot_DynSeq_t *Diderot_DynSeqLoadReal ( | ||
140 : | WorldPrefix_t *wrld, | ||
141 : | Nrrd *nin, | ||
142 : | unsigned int nDims, | ||
143 : | unsigned int *dims) | ||
144 : | { | ||
145 : | unsigned int nValuesPerElem = CheckNrrd(wrld, nin, nDims, dims); | ||
146 : | size_t elemSz = SIZEOF_DIDEROT_REAL * nValuesPerElem; | ||
147 : | |||
148 : | if (nValuesPerElem == 0) | ||
149 : | return (Diderot_DynSeq_t *)0; | ||
150 : | |||
151 : | // get the number of elements | ||
152 : | size_t nElems = nin->axis[0].size; | ||
153 : | |||
154 : | // allocate the dynamic sequence | ||
155 : | Diderot_DynSeq_t *seq = Diderot_DynSeqAlloc(elemSz, nElems); | ||
156 : | |||
157 : | // initialize the sequence from the nrrd | ||
158 : | if (! nrrdTypeInfo[nin->type].isFloat || (nrrdTypeInfo[nin->type].size != SIZEOF_DIDEROT_REAL)) { | ||
159 : | // this is the slow path; we have to convert values as they are copied from the nrrd | ||
160 : | #if defined(DIDEROT_DOUBLE_PRECISION) | ||
161 : | double (*loadFn)(const void *) = nrrdDLoad[nin->type]; | ||
162 : | #else | ||
163 : | float (*loadFn)(const void *) = nrrdFLoad[nin->type]; | ||
164 : | #endif | ||
165 : | Diderot_real_t *dst = (Diderot_real_t *)seq->data; | ||
166 : | char *src = (char *)nin->data; | ||
167 : | size_t srcElemSz = NrrdTypeInfo[nin->type].size; | ||
168 : | for (size_t i = 0; i < nElems * nValuesPerElem; i++) { | ||
169 : | *dst++ = loadFn(src); | ||
170 : | src += srcElemSz; | ||
171 : | } | ||
172 : | } | ||
173 : | else { | ||
174 : | // this is the fast path, where we can just do a bulk memcpy | ||
175 : | memcpy (seq->data, nin->data, nElems * elemSz); | ||
176 : | } | ||
177 : | |||
178 : | return seq; | ||
179 : | |||
180 : | } | ||
181 : | |||
182 : | |||
183 : | //! load a dynamic sequence from a Nrrd file, where the sequence elements have int ground type. | ||
184 : | //! \param wrld the world; used to report errors | ||
185 : | //! \param nin the nrrd to check | ||
186 : | //! \param nDims the number of dimensions in the sequence elements | ||
187 : | //! \param dims the array of sequence element dimensions | ||
188 : | //! \return the dynamic sequence, or zero on error | ||
189 : | Diderot_DynSeq_t *Diderot_DynSeqLoadInt ( | ||
190 : | WorldPrefix_t *wrld, | ||
191 : | Nrrd *nin, | ||
192 : | unsigned int nDims, | ||
193 : | unsigned int *dims) | ||
194 : | { | ||
195 : | unsigned int nValuesPerElem = CheckNrrd(wrld, nin, nDims, dims); | ||
196 : | size_t elemSz = SIZEOF_DIDEROT_INT * nValuesPerElem; | ||
197 : | |||
198 : | if (nValuesPerElem == 0) | ||
199 : | return (Diderot_DynSeq_t *)0; | ||
200 : | |||
201 : | if (nrrdTypeInfo[nin->type].isFloat) { | ||
202 : | Diderot_Error (wrld, "expected integer element type for int sequence, but found %d\n", nin->type); | ||
203 : | return 0; | ||
204 : | } | ||
205 : | |||
206 : | // get the number of elements | ||
207 : | size_t nElems = nin->axis[0].size; | ||
208 : | |||
209 : | // allocate the dynamic sequence | ||
210 : | Diderot_DynSeq_t *seq = Diderot_DynSeqAlloc(elemSz, nElems); | ||
211 : | |||
212 : | // initialize the sequence from the nrrd | ||
213 : | if (nrrdTypeInfo[nin->type].size != SIZEOF_DIDEROT_INT) { | ||
214 : | // this is the slow path; we have to convert values as they are copied from the nrrd | ||
215 : | int (*loadFn)(const void *) = nrrdILoad[nin->type]; | ||
216 : | Diderot_int_t *dst = (Diderot_int_t *)seq->data; | ||
217 : | char *src = (char *)nin->data; | ||
218 : | size_t srcElemSz = NrrdTypeInfo[nin->type].size; | ||
219 : | for (size_t i = 0; i < nElems * nValuesPerElem; i++) { | ||
220 : | *dst++ = loadFn(src); | ||
221 : | src += srcElemSz; | ||
222 : | } | ||
223 : | } | ||
224 : | else { | ||
225 : | // this is the fast path, where we can just do a bulk memcpy | ||
226 : | memcpy (seq->data, nin->data, nElems * elemSz); | ||
227 : | } | ||
228 : | |||
229 : | return seq; | ||
230 : | |||
231 : | } | ||
232 : | |||
233 : | |||
234 : | //! load a dynamic sequence from a Nrrd file, where the sequence elements have bool ground type. | ||
235 : | //! \param wrld the world; used to report errors | ||
236 : | //! \param nin the nrrd to check | ||
237 : | //! \param nDims the number of dimensions in the sequence elements | ||
238 : | //! \param dims the array of sequence element dimensions | ||
239 : | //! \return the dynamic sequence, or zero on error | ||
240 : | Diderot_DynSeq_t *Diderot_DynSeqLoadBool ( | ||
241 : | WorldPrefix_t *wrld, | ||
242 : | Nrrd *nin, | ||
243 : | unsigned int nDims, | ||
244 : | unsigned int *dims) | ||
245 : | { | ||
246 : | unsigned int nValuesPerElem = CheckNrrd(wrld, nin, nDims, dims); | ||
247 : | size_t elemSz = SIZEOF_DIDEROT_BOOL * nValuesPerElem; | ||
248 : | |||
249 : | if (nValuesPerElem == 0) | ||
250 : | return (Diderot_DynSeq_t *)0; | ||
251 : | |||
252 : | if (nrrdTypeInfo[nin->type].isFloat) { | ||
253 : | Diderot_Error (wrld, "expected integer element type for bool sequence, but found %d\n", nin->type); | ||
254 : | return 0; | ||
255 : | } | ||
256 : | |||
257 : | // get the number of elements | ||
258 : | size_t nElems = nin->axis[0].size; | ||
259 : | |||
260 : | // allocate the dynamic sequence | ||
261 : | Diderot_DynSeq_t *seq = Diderot_DynSeqAlloc(elemSz, nElems); | ||
262 : | |||
263 : | // initialize the sequence from the nrrd | ||
264 : | if (nrrdTypeInfo[nin->type].size != sizeof(bool)) { | ||
265 : | // this is the slow path; we have to convert values as they are copied from the nrrd | ||
266 : | int (*loadFn)(const void *) = nrrdILoad[nin->type]; | ||
267 : | bool *dst = (bool *)seq->data; | ||
268 : | char *src = (char *)nin->data; | ||
269 : | size_t srcElemSz = NrrdTypeInfo[nin->type].size; | ||
270 : | for (size_t i = 0; i < nElems * nValuesPerElem; i++) { | ||
271 : | *dst++ = loadFn(src) ? true : false; | ||
272 : | src += srcElemSz; | ||
273 : | } | ||
274 : | } | ||
275 : | else { | ||
276 : | // this is the fast path, where we can just do a bulk memcpy | ||
277 : | memcpy (seq->data, nin->data, nElems * elemSz); | ||
278 : | } | ||
279 : | |||
280 : | return seq; | ||
281 : | |||
282 : | } |
root@smlnj-gforge.cs.uchicago.edu | ViewVC Help |
Powered by ViewVC 1.0.0 |