Line | Count | Source |
1 | | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | | * Copyright by The HDF Group. * |
3 | | * All rights reserved. * |
4 | | * * |
5 | | * This file is part of HDF5. The full HDF5 copyright notice, including * |
6 | | * terms governing use, modification, and redistribution, is contained in * |
7 | | * the LICENSE file, which can be found at the root of the source code * |
8 | | * distribution tree, or in https://www.hdfgroup.org/licenses. * |
9 | | * If you do not have access to either file, you may request a copy from * |
10 | | * help@hdfgroup.org. * |
11 | | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
12 | | |
13 | | #include "H5private.h" |
14 | | #include "H5Eprivate.h" |
15 | | #include "H5MMprivate.h" /* Memory management */ |
16 | | #include "H5Oprivate.h" |
17 | | #include "H5VMprivate.h" |
18 | | |
19 | | /* Local typedefs */ |
20 | | typedef struct H5VM_memcpy_ud_t { |
21 | | unsigned char *dst; /* Pointer to destination buffer */ |
22 | | const unsigned char *src; /* Pointer to source buffer */ |
23 | | } H5VM_memcpy_ud_t; |
24 | | |
25 | | /* Local macros */ |
26 | | #define H5VM_HYPER_NDIMS H5O_LAYOUT_NDIMS |
27 | | |
28 | | /* Local prototypes */ |
29 | | static void H5VM__stride_optimize1(unsigned *np /*in,out*/, hsize_t *elmt_size /*in,out*/, |
30 | | const hsize_t *size, hsize_t *stride1); |
31 | | static void H5VM__stride_optimize2(unsigned *np /*in,out*/, hsize_t *elmt_size /*in,out*/, |
32 | | const hsize_t *size, hsize_t *stride1, hsize_t *stride2); |
33 | | |
34 | | /*------------------------------------------------------------------------- |
35 | | * Function: H5VM__stride_optimize1 |
36 | | * |
37 | | * Purpose: Given a stride vector which references elements of the |
38 | | * specified size, optimize the dimensionality, the stride |
39 | | * vector, and the element size to minimize the dimensionality |
40 | | * and the number of memory accesses. |
41 | | * |
42 | | * All arguments are passed by reference and their values may be |
43 | | * modified by this function. |
44 | | * |
45 | | * Return: void |
46 | | * |
47 | | *------------------------------------------------------------------------- |
48 | | */ |
49 | | static void |
50 | | H5VM__stride_optimize1(unsigned *np /*in,out*/, hsize_t *elmt_size /*in,out*/, const hsize_t *size, |
51 | | hsize_t *stride1) |
52 | 0 | { |
53 | 0 | FUNC_ENTER_PACKAGE_NOERR |
54 | | |
55 | | /* This has to be true because if we optimize the dimensionality down to |
56 | | * zero we still must make one reference. |
57 | | */ |
58 | 0 | assert(1 == H5VM_vector_reduce_product(0, NULL)); |
59 | | |
60 | | /* Combine adjacent memory accesses */ |
61 | 0 | while (*np && stride1[*np - 1] > 0 && (hsize_t)(stride1[*np - 1]) == *elmt_size) { |
62 | 0 | *elmt_size *= size[*np - 1]; |
63 | 0 | if (--*np) |
64 | 0 | stride1[*np - 1] += size[*np] * stride1[*np]; |
65 | 0 | } |
66 | |
|
67 | 0 | FUNC_LEAVE_NOAPI_VOID |
68 | 0 | } |
69 | | |
70 | | /*------------------------------------------------------------------------- |
71 | | * Function: H5VM__stride_optimize2 |
72 | | * |
73 | | * Purpose: Given two stride vectors which reference elements of the |
74 | | * specified size, optimize the dimensionality, the stride |
75 | | * vectors, and the element size to minimize the dimensionality |
76 | | * and the number of memory accesses. |
77 | | * |
78 | | * All arguments are passed by reference and their values may be |
79 | | * modified by this function. |
80 | | * |
81 | | * Return: Non-negative on success/Negative on failure |
82 | | * |
83 | | *------------------------------------------------------------------------- |
84 | | */ |
85 | | static void |
86 | | H5VM__stride_optimize2(unsigned *np /*in,out*/, hsize_t *elmt_size /*in,out*/, const hsize_t *size, |
87 | | hsize_t *stride1, hsize_t *stride2) |
88 | 0 | { |
89 | 0 | FUNC_ENTER_PACKAGE_NOERR |
90 | | |
91 | | /* This has to be true because if we optimize the dimensionality down to |
92 | | * zero we still must make one reference. |
93 | | */ |
94 | 0 | assert(1 == H5VM_vector_reduce_product(0, NULL)); |
95 | 0 | assert(*elmt_size > 0); |
96 | | |
97 | | /* Combine adjacent memory accesses */ |
98 | | |
99 | | /* Unroll loop for common cases */ |
100 | 0 | switch (*np) { |
101 | 0 | case 1: /* For 0-D datasets (dunno if this ever gets used...) */ |
102 | 0 | if (stride1[0] == *elmt_size && stride2[0] == *elmt_size) { |
103 | 0 | *elmt_size *= size[0]; |
104 | 0 | --*np; /* *np decrements to a value of 0 now */ |
105 | 0 | } /* end if */ |
106 | 0 | break; |
107 | | |
108 | 0 | case 2: /* For 1-D datasets */ |
109 | 0 | if (stride1[1] == *elmt_size && stride2[1] == *elmt_size) { |
110 | 0 | *elmt_size *= size[1]; |
111 | 0 | --*np; /* *np decrements to a value of 1 now */ |
112 | 0 | stride1[0] += size[1] * stride1[1]; |
113 | 0 | stride2[0] += size[1] * stride2[1]; |
114 | |
|
115 | 0 | if (stride1[0] == *elmt_size && stride2[0] == *elmt_size) { |
116 | 0 | *elmt_size *= size[0]; |
117 | 0 | --*np; /* *np decrements to a value of 0 now */ |
118 | 0 | } /* end if */ |
119 | 0 | } /* end if */ |
120 | 0 | break; |
121 | | |
122 | 0 | case 3: /* For 2-D datasets */ |
123 | 0 | if (stride1[2] == *elmt_size && stride2[2] == *elmt_size) { |
124 | 0 | *elmt_size *= size[2]; |
125 | 0 | --*np; /* *np decrements to a value of 2 now */ |
126 | 0 | stride1[1] += size[2] * stride1[2]; |
127 | 0 | stride2[1] += size[2] * stride2[2]; |
128 | |
|
129 | 0 | if (stride1[1] == *elmt_size && stride2[1] == *elmt_size) { |
130 | 0 | *elmt_size *= size[1]; |
131 | 0 | --*np; /* *np decrements to a value of 1 now */ |
132 | 0 | stride1[0] += size[1] * stride1[1]; |
133 | 0 | stride2[0] += size[1] * stride2[1]; |
134 | |
|
135 | 0 | if (stride1[0] == *elmt_size && stride2[0] == *elmt_size) { |
136 | 0 | *elmt_size *= size[0]; |
137 | 0 | --*np; /* *np decrements to a value of 0 now */ |
138 | 0 | } /* end if */ |
139 | 0 | } /* end if */ |
140 | 0 | } /* end if */ |
141 | 0 | break; |
142 | | |
143 | 0 | case 4: /* For 3-D datasets */ |
144 | 0 | if (stride1[3] == *elmt_size && stride2[3] == *elmt_size) { |
145 | 0 | *elmt_size *= size[3]; |
146 | 0 | --*np; /* *np decrements to a value of 3 now */ |
147 | 0 | stride1[2] += size[3] * stride1[3]; |
148 | 0 | stride2[2] += size[3] * stride2[3]; |
149 | |
|
150 | 0 | if (stride1[2] == *elmt_size && stride2[2] == *elmt_size) { |
151 | 0 | *elmt_size *= size[2]; |
152 | 0 | --*np; /* *np decrements to a value of 2 now */ |
153 | 0 | stride1[1] += size[2] * stride1[2]; |
154 | 0 | stride2[1] += size[2] * stride2[2]; |
155 | |
|
156 | 0 | if (stride1[1] == *elmt_size && stride2[1] == *elmt_size) { |
157 | 0 | *elmt_size *= size[1]; |
158 | 0 | --*np; /* *np decrements to a value of 1 now */ |
159 | 0 | stride1[0] += size[1] * stride1[1]; |
160 | 0 | stride2[0] += size[1] * stride2[1]; |
161 | |
|
162 | 0 | if (stride1[0] == *elmt_size && stride2[0] == *elmt_size) { |
163 | 0 | *elmt_size *= size[0]; |
164 | 0 | --*np; /* *np decrements to a value of 0 now */ |
165 | 0 | } /* end if */ |
166 | 0 | } /* end if */ |
167 | 0 | } /* end if */ |
168 | 0 | } /* end if */ |
169 | 0 | break; |
170 | | |
171 | 0 | default: |
172 | 0 | while (*np && stride1[*np - 1] == *elmt_size && stride2[*np - 1] == *elmt_size) { |
173 | 0 | *elmt_size *= size[*np - 1]; |
174 | 0 | if (--*np) { |
175 | 0 | stride1[*np - 1] += size[*np] * stride1[*np]; |
176 | 0 | stride2[*np - 1] += size[*np] * stride2[*np]; |
177 | 0 | } |
178 | 0 | } |
179 | 0 | break; |
180 | 0 | } /* end switch */ |
181 | | |
182 | 0 | FUNC_LEAVE_NOAPI_VOID |
183 | 0 | } |
184 | | |
185 | | /*------------------------------------------------------------------------- |
186 | | * Function: H5VM_hyper_stride |
187 | | * |
188 | | * Purpose: Given a description of a hyperslab, this function returns |
189 | | * (through STRIDE[]) the byte strides appropriate for accessing |
190 | | * all bytes of the hyperslab and the byte offset where the |
191 | | * striding will begin. The SIZE can be passed to the various |
192 | | * stride functions. |
193 | | * |
194 | | * The dimensionality of the whole array, the hyperslab, and the |
195 | | * returned stride array is N. The whole array dimensions are |
196 | | * TOTAL_SIZE and the hyperslab is at offset OFFSET and has |
197 | | * dimensions SIZE. |
198 | | * |
199 | | * The stride and starting point returned will cause the |
200 | | * hyperslab elements to be referenced in C order. |
201 | | * |
202 | | * Return: Byte offset from beginning of array to start of striding. |
203 | | * |
204 | | *------------------------------------------------------------------------- |
205 | | */ |
206 | | hsize_t |
207 | | H5VM_hyper_stride(unsigned n, const hsize_t *size, const hsize_t *total_size, const hsize_t *offset, |
208 | | hsize_t *stride /*out*/) |
209 | 0 | { |
210 | 0 | hsize_t skip; /*starting point byte offset */ |
211 | 0 | hsize_t acc; /*accumulator */ |
212 | 0 | int i; /*counter */ |
213 | 0 | hsize_t ret_value; /* Return value */ |
214 | |
|
215 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
216 | |
|
217 | 0 | assert(n <= H5VM_HYPER_NDIMS); |
218 | 0 | assert(size); |
219 | 0 | assert(total_size); |
220 | 0 | assert(stride); |
221 | | |
222 | | /* init */ |
223 | 0 | assert(n > 0); |
224 | 0 | stride[n - 1] = 1; |
225 | 0 | skip = offset ? offset[n - 1] : 0; |
226 | |
|
227 | 0 | switch (n) { |
228 | 0 | case 2: /* 1-D dataset */ |
229 | 0 | assert(total_size[1] >= size[1]); |
230 | 0 | stride[0] = total_size[1] - size[1]; /*overflow checked*/ |
231 | 0 | acc = total_size[1]; |
232 | 0 | skip += acc * (offset ? offset[0] : 0); |
233 | 0 | break; |
234 | | |
235 | 0 | case 3: /* 2-D dataset */ |
236 | 0 | assert(total_size[2] >= size[2]); |
237 | 0 | stride[1] = total_size[2] - size[2]; /*overflow checked*/ |
238 | 0 | acc = total_size[2]; |
239 | 0 | skip += acc * (offset ? (hsize_t)offset[1] : 0); |
240 | |
|
241 | 0 | assert(total_size[1] >= size[1]); |
242 | 0 | stride[0] = acc * (total_size[1] - size[1]); /*overflow checked*/ |
243 | 0 | acc *= total_size[1]; |
244 | 0 | skip += acc * (offset ? (hsize_t)offset[0] : 0); |
245 | 0 | break; |
246 | | |
247 | 0 | case 4: /* 3-D dataset */ |
248 | 0 | assert(total_size[3] >= size[3]); |
249 | 0 | stride[2] = total_size[3] - size[3]; /*overflow checked*/ |
250 | 0 | acc = total_size[3]; |
251 | 0 | skip += acc * (offset ? (hsize_t)offset[2] : 0); |
252 | |
|
253 | 0 | assert(total_size[2] >= size[2]); |
254 | 0 | stride[1] = acc * (total_size[2] - size[2]); /*overflow checked*/ |
255 | 0 | acc *= total_size[2]; |
256 | 0 | skip += acc * (offset ? (hsize_t)offset[1] : 0); |
257 | |
|
258 | 0 | assert(total_size[1] >= size[1]); |
259 | 0 | stride[0] = acc * (total_size[1] - size[1]); /*overflow checked*/ |
260 | 0 | acc *= total_size[1]; |
261 | 0 | skip += acc * (offset ? (hsize_t)offset[0] : 0); |
262 | 0 | break; |
263 | | |
264 | 0 | default: |
265 | | /* others */ |
266 | 0 | for (i = (int)(n - 2), acc = 1; i >= 0; --i) { |
267 | 0 | assert(total_size[i + 1] >= size[i + 1]); |
268 | 0 | stride[i] = acc * (total_size[i + 1] - size[i + 1]); /*overflow checked*/ |
269 | 0 | acc *= total_size[i + 1]; |
270 | 0 | skip += acc * (offset ? (hsize_t)offset[i] : 0); |
271 | 0 | } |
272 | 0 | break; |
273 | 0 | } /* end switch */ |
274 | | |
275 | | /* Set return value */ |
276 | 0 | ret_value = skip; |
277 | |
|
278 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
279 | 0 | } |
280 | | |
281 | | /*------------------------------------------------------------------------- |
282 | | * Function: H5VM_hyper_eq |
283 | | * |
284 | | * Purpose: Determines whether two hyperslabs are equal. This function |
285 | | * assumes that both hyperslabs are relative to the same array, |
286 | | * for if not, they could not possibly be equal. |
287 | | * |
288 | | * Return: true if the hyperslabs are equal (that is, |
289 | | * both refer to exactly the same elements of an |
290 | | * array) |
291 | | * |
292 | | * false otherwise |
293 | | * |
294 | | * Never returns FAIL |
295 | | * |
296 | | *------------------------------------------------------------------------- |
297 | | */ |
298 | | htri_t |
299 | | H5VM_hyper_eq(unsigned n, const hsize_t *offset1, const hsize_t *size1, const hsize_t *offset2, |
300 | | const hsize_t *size2) |
301 | 0 | { |
302 | 0 | hsize_t nelmts1 = 1, nelmts2 = 1; |
303 | 0 | unsigned i; |
304 | 0 | htri_t ret_value = true; /* Return value */ |
305 | | |
306 | | /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ |
307 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
308 | |
|
309 | 0 | if (n == 0) |
310 | 0 | HGOTO_DONE(true); |
311 | | |
312 | 0 | for (i = 0; i < n; i++) { |
313 | 0 | if ((offset1 ? offset1[i] : 0) != (offset2 ? offset2[i] : 0)) |
314 | 0 | HGOTO_DONE(false); |
315 | 0 | if ((size1 ? size1[i] : 0) != (size2 ? size2[i] : 0)) |
316 | 0 | HGOTO_DONE(false); |
317 | 0 | if (0 == (nelmts1 *= (size1 ? size1[i] : 0))) |
318 | 0 | HGOTO_DONE(false); |
319 | 0 | if (0 == (nelmts2 *= (size2 ? size2[i] : 0))) |
320 | 0 | HGOTO_DONE(false); |
321 | 0 | } |
322 | | |
323 | 0 | done: |
324 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
325 | 0 | } |
326 | | |
327 | | /*------------------------------------------------------------------------- |
328 | | * Function: H5VM_hyper_fill |
329 | | * |
330 | | * Purpose: Similar to memset() except it operates on hyperslabs... |
331 | | * |
332 | | * Fills a hyperslab of array BUF with some value VAL. BUF |
333 | | * is treated like a C-order array with N dimensions where the |
334 | | * size of each dimension is TOTAL_SIZE[]. The hyperslab which |
335 | | * will be filled with VAL begins at byte offset OFFSET[] from |
336 | | * the minimum corner of BUF and continues for SIZE[] bytes in |
337 | | * each dimension. |
338 | | * |
339 | | * Return: Non-negative on success/Negative on failure |
340 | | * |
341 | | *------------------------------------------------------------------------- |
342 | | */ |
343 | | herr_t |
344 | | H5VM_hyper_fill(unsigned n, const hsize_t *_size, const hsize_t *total_size, const hsize_t *offset, |
345 | | void *_dst, unsigned fill_value) |
346 | 0 | { |
347 | 0 | uint8_t *dst = (uint8_t *)_dst; /*cast for ptr arithmetic */ |
348 | 0 | hsize_t size[H5VM_HYPER_NDIMS]; /*a modifiable copy of _size */ |
349 | 0 | hsize_t dst_stride[H5VM_HYPER_NDIMS]; /*destination stride info */ |
350 | 0 | hsize_t dst_start; /*byte offset to start of stride*/ |
351 | 0 | hsize_t elmt_size = 1; /*bytes per element */ |
352 | 0 | herr_t ret_value; /*function return status */ |
353 | | #ifndef NDEBUG |
354 | | unsigned u; |
355 | | #endif |
356 | |
|
357 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
358 | | |
359 | | /* check args */ |
360 | 0 | assert(n > 0 && n <= H5VM_HYPER_NDIMS); |
361 | 0 | assert(_size); |
362 | 0 | assert(total_size); |
363 | 0 | assert(dst); |
364 | | #ifndef NDEBUG |
365 | | for (u = 0; u < n; u++) { |
366 | | assert(_size[u] > 0); |
367 | | assert(total_size[u] > 0); |
368 | | } |
369 | | #endif |
370 | | |
371 | | /* Copy the size vector so we can modify it */ |
372 | 0 | H5VM_vector_cpy(n, size, _size); |
373 | | |
374 | | /* Compute an optimal destination stride vector */ |
375 | 0 | dst_start = H5VM_hyper_stride(n, size, total_size, offset, dst_stride); |
376 | 0 | H5VM__stride_optimize1(&n, &elmt_size, size, dst_stride); |
377 | | |
378 | | /* Copy */ |
379 | 0 | ret_value = H5VM_stride_fill(n, elmt_size, size, dst_stride, dst + dst_start, fill_value); |
380 | |
|
381 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
382 | 0 | } |
383 | | |
384 | | /*------------------------------------------------------------------------- |
385 | | * Function: H5VM_hyper_copy |
386 | | * |
387 | | * Purpose: Copies a hyperslab from the source to the destination. |
388 | | * |
389 | | * A hyperslab is a logically contiguous region of |
390 | | * multi-dimensional size SIZE of an array whose dimensionality |
391 | | * is N and whose total size is DST_TOTAL_SIZE or SRC_TOTAL_SIZE. |
392 | | * The minimum corner of the hyperslab begins at a |
393 | | * multi-dimensional offset from the minimum corner of the DST |
394 | | * (destination) or SRC (source) array. The sizes and offsets |
395 | | * are assumed to be in C order, that is, the first size/offset |
396 | | * varies the slowest while the last varies the fastest in the |
397 | | * mapping from N-dimensional space to linear space. This |
398 | | * function assumes that the array elements are single bytes (if |
399 | | * your array has multi-byte elements then add an additional |
400 | | * dimension whose size is that of your element). |
401 | | * |
402 | | * The SRC and DST array may be the same array, but the results |
403 | | * are undefined if the source hyperslab overlaps the |
404 | | * destination hyperslab. |
405 | | * |
406 | | * Return: Non-negative on success/Negative on failure |
407 | | * |
408 | | *------------------------------------------------------------------------- |
409 | | */ |
410 | | herr_t |
411 | | H5VM_hyper_copy(unsigned n, const hsize_t *_size, const hsize_t *dst_size, const hsize_t *dst_offset, |
412 | | void *_dst, const hsize_t *src_size, const hsize_t *src_offset, const void *_src) |
413 | 0 | { |
414 | 0 | const uint8_t *src = (const uint8_t *)_src; /*cast for ptr arithmtc */ |
415 | 0 | uint8_t *dst = (uint8_t *)_dst; /*cast for ptr arithmtc */ |
416 | 0 | hsize_t size[H5VM_HYPER_NDIMS]; /*a modifiable _size */ |
417 | 0 | hsize_t src_stride[H5VM_HYPER_NDIMS]; /*source stride info */ |
418 | 0 | hsize_t dst_stride[H5VM_HYPER_NDIMS]; /*dest stride info */ |
419 | 0 | hsize_t dst_start, src_start; /*offset to start at */ |
420 | 0 | hsize_t elmt_size = 1; /*element size in bytes */ |
421 | 0 | herr_t ret_value; /*return status */ |
422 | | #ifndef NDEBUG |
423 | | unsigned u; |
424 | | #endif |
425 | |
|
426 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
427 | | |
428 | | /* check args */ |
429 | 0 | assert(n > 0 && n <= H5VM_HYPER_NDIMS); |
430 | 0 | assert(_size); |
431 | 0 | assert(dst_size); |
432 | 0 | assert(src_size); |
433 | 0 | assert(dst); |
434 | 0 | assert(src); |
435 | | #ifndef NDEBUG |
436 | | for (u = 0; u < n; u++) { |
437 | | assert(_size[u] > 0); |
438 | | assert(dst_size[u] > 0); |
439 | | assert(src_size[u] > 0); |
440 | | } |
441 | | #endif |
442 | | |
443 | | /* Copy the size vector so we can modify it */ |
444 | 0 | H5VM_vector_cpy(n, size, _size); |
445 | | |
446 | | /* Compute stride vectors for source and destination */ |
447 | | #ifdef NO_INLINED_CODE |
448 | | dst_start = H5VM_hyper_stride(n, size, dst_size, dst_offset, dst_stride); |
449 | | src_start = H5VM_hyper_stride(n, size, src_size, src_offset, src_stride); |
450 | | #else /* NO_INLINED_CODE */ |
451 | | /* in-line version of two calls to H5VM_hyper_stride() */ |
452 | 0 | { |
453 | 0 | hsize_t dst_acc; /*accumulator */ |
454 | 0 | hsize_t src_acc; /*accumulator */ |
455 | 0 | int ii; /*counter */ |
456 | | |
457 | | /* init */ |
458 | 0 | assert(n > 0); |
459 | 0 | dst_stride[n - 1] = 1; |
460 | 0 | src_stride[n - 1] = 1; |
461 | 0 | dst_start = dst_offset ? dst_offset[n - 1] : 0; |
462 | 0 | src_start = src_offset ? src_offset[n - 1] : 0; |
463 | | |
464 | | /* Unroll loop for common cases */ |
465 | 0 | switch (n) { |
466 | 0 | case 2: |
467 | 0 | assert(dst_size[1] >= size[1]); |
468 | 0 | assert(src_size[1] >= size[1]); |
469 | 0 | dst_stride[0] = dst_size[1] - size[1]; /*overflow checked*/ |
470 | 0 | src_stride[0] = src_size[1] - size[1]; /*overflow checked*/ |
471 | 0 | dst_acc = dst_size[1]; |
472 | 0 | src_acc = src_size[1]; |
473 | 0 | dst_start += dst_acc * (dst_offset ? dst_offset[0] : 0); |
474 | 0 | src_start += src_acc * (src_offset ? src_offset[0] : 0); |
475 | 0 | break; |
476 | | |
477 | 0 | case 3: |
478 | 0 | assert(dst_size[2] >= size[2]); |
479 | 0 | assert(src_size[2] >= size[2]); |
480 | 0 | dst_stride[1] = dst_size[2] - size[2]; /*overflow checked*/ |
481 | 0 | src_stride[1] = src_size[2] - size[2]; /*overflow checked*/ |
482 | 0 | dst_acc = dst_size[2]; |
483 | 0 | src_acc = src_size[2]; |
484 | 0 | dst_start += dst_acc * (dst_offset ? dst_offset[1] : 0); |
485 | 0 | src_start += src_acc * (src_offset ? src_offset[1] : 0); |
486 | |
|
487 | 0 | assert(dst_size[1] >= size[1]); |
488 | 0 | assert(src_size[1] >= size[1]); |
489 | 0 | dst_stride[0] = dst_acc * (dst_size[1] - size[1]); /*overflow checked*/ |
490 | 0 | src_stride[0] = src_acc * (src_size[1] - size[1]); /*overflow checked*/ |
491 | 0 | dst_acc *= dst_size[1]; |
492 | 0 | src_acc *= src_size[1]; |
493 | 0 | dst_start += dst_acc * (dst_offset ? dst_offset[0] : 0); |
494 | 0 | src_start += src_acc * (src_offset ? src_offset[0] : 0); |
495 | 0 | break; |
496 | | |
497 | 0 | case 4: |
498 | 0 | assert(dst_size[3] >= size[3]); |
499 | 0 | assert(src_size[3] >= size[3]); |
500 | 0 | dst_stride[2] = dst_size[3] - size[3]; /*overflow checked*/ |
501 | 0 | src_stride[2] = src_size[3] - size[3]; /*overflow checked*/ |
502 | 0 | dst_acc = dst_size[3]; |
503 | 0 | src_acc = src_size[3]; |
504 | 0 | dst_start += dst_acc * (dst_offset ? dst_offset[2] : 0); |
505 | 0 | src_start += src_acc * (src_offset ? src_offset[2] : 0); |
506 | |
|
507 | 0 | assert(dst_size[2] >= size[2]); |
508 | 0 | assert(src_size[2] >= size[2]); |
509 | 0 | dst_stride[1] = dst_acc * (dst_size[2] - size[2]); /*overflow checked*/ |
510 | 0 | src_stride[1] = src_acc * (src_size[2] - size[2]); /*overflow checked*/ |
511 | 0 | dst_acc *= dst_size[2]; |
512 | 0 | src_acc *= src_size[2]; |
513 | 0 | dst_start += dst_acc * (dst_offset ? dst_offset[1] : 0); |
514 | 0 | src_start += src_acc * (src_offset ? src_offset[1] : 0); |
515 | |
|
516 | 0 | assert(dst_size[1] >= size[1]); |
517 | 0 | assert(src_size[1] >= size[1]); |
518 | 0 | dst_stride[0] = dst_acc * (dst_size[1] - size[1]); /*overflow checked*/ |
519 | 0 | src_stride[0] = src_acc * (src_size[1] - size[1]); /*overflow checked*/ |
520 | 0 | dst_acc *= dst_size[1]; |
521 | 0 | src_acc *= src_size[1]; |
522 | 0 | dst_start += dst_acc * (dst_offset ? dst_offset[0] : 0); |
523 | 0 | src_start += src_acc * (src_offset ? src_offset[0] : 0); |
524 | 0 | break; |
525 | | |
526 | 0 | default: |
527 | | /* others */ |
528 | 0 | for (ii = (int)(n - 2), dst_acc = 1, src_acc = 1; ii >= 0; --ii) { |
529 | 0 | assert(dst_size[ii + 1] >= size[ii + 1]); |
530 | 0 | assert(src_size[ii + 1] >= size[ii + 1]); |
531 | 0 | dst_stride[ii] = dst_acc * (dst_size[ii + 1] - size[ii + 1]); /*overflow checked*/ |
532 | 0 | src_stride[ii] = src_acc * (src_size[ii + 1] - size[ii + 1]); /*overflow checked*/ |
533 | 0 | dst_acc *= dst_size[ii + 1]; |
534 | 0 | src_acc *= src_size[ii + 1]; |
535 | 0 | dst_start += dst_acc * (dst_offset ? dst_offset[ii] : 0); |
536 | 0 | src_start += src_acc * (src_offset ? src_offset[ii] : 0); |
537 | 0 | } |
538 | 0 | break; |
539 | 0 | } /* end switch */ |
540 | 0 | } |
541 | 0 | #endif /* NO_INLINED_CODE */ |
542 | | |
543 | | /* Optimize the strides as a pair */ |
544 | 0 | H5VM__stride_optimize2(&n, &elmt_size, size, dst_stride, src_stride); |
545 | | |
546 | | /* Perform the copy in terms of stride */ |
547 | 0 | ret_value = |
548 | 0 | H5VM_stride_copy(n, elmt_size, size, dst_stride, dst + dst_start, src_stride, src + src_start); |
549 | |
|
550 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
551 | 0 | } |
552 | | |
553 | | /*------------------------------------------------------------------------- |
554 | | * Function: H5VM_stride_fill |
555 | | * |
556 | | * Purpose: Fills all bytes of a hyperslab with the same value using |
557 | | * memset(). |
558 | | * |
559 | | * Return: Non-negative on success/Negative on failure |
560 | | * |
561 | | *------------------------------------------------------------------------- |
562 | | */ |
563 | | herr_t |
564 | | H5VM_stride_fill(unsigned n, hsize_t elmt_size, const hsize_t *size, const hsize_t *stride, void *_dst, |
565 | | unsigned fill_value) |
566 | 0 | { |
567 | 0 | uint8_t *dst = (uint8_t *)_dst; /*cast for ptr arithmetic */ |
568 | 0 | hsize_t idx[H5VM_HYPER_NDIMS]; /*1-origin indices */ |
569 | 0 | hsize_t nelmts; /*number of elements to fill */ |
570 | 0 | hsize_t i; /*counter */ |
571 | 0 | int j; /*counter */ |
572 | 0 | bool carry; /*subtraction carray value */ |
573 | |
|
574 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
575 | |
|
576 | 0 | assert(elmt_size < SIZE_MAX); |
577 | |
|
578 | 0 | H5VM_vector_cpy(n, idx, size); |
579 | 0 | nelmts = H5VM_vector_reduce_product(n, size); |
580 | 0 | for (i = 0; i < nelmts; i++) { |
581 | | /* Copy an element */ |
582 | 0 | H5_CHECK_OVERFLOW(elmt_size, hsize_t, size_t); |
583 | 0 | memset(dst, (int)fill_value, (size_t)elmt_size); |
584 | | |
585 | | /* Decrement indices and advance pointer */ |
586 | 0 | for (j = (int)(n - 1), carry = true; j >= 0 && carry; --j) { |
587 | 0 | dst += stride[j]; |
588 | |
|
589 | 0 | if (--idx[j]) |
590 | 0 | carry = false; |
591 | 0 | else { |
592 | 0 | assert(size); |
593 | 0 | idx[j] = size[j]; |
594 | 0 | } /* end else */ |
595 | 0 | } |
596 | 0 | } |
597 | |
|
598 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
599 | 0 | } |
600 | | |
601 | | /*------------------------------------------------------------------------- |
602 | | * Function: H5VM_stride_copy |
603 | | * |
604 | | * Purpose: Uses DST_STRIDE and SRC_STRIDE to advance through the arrays |
605 | | * DST and SRC while copying bytes from SRC to DST. This |
606 | | * function minimizes the number of calls to memcpy() by |
607 | | * combining various strides, but it will never touch memory |
608 | | * outside the hyperslab defined by the strides. |
609 | | * |
610 | | * Note: If the src_stride is all zero and elmt_size is one, then it's |
611 | | * probably more efficient to use H5VM_stride_fill() instead. |
612 | | * |
613 | | * Return: Non-negative on success/Negative on failure |
614 | | * |
615 | | *------------------------------------------------------------------------- |
616 | | */ |
617 | | herr_t |
618 | | H5VM_stride_copy(unsigned n, hsize_t elmt_size, const hsize_t *size, const hsize_t *dst_stride, void *_dst, |
619 | | const hsize_t *src_stride, const void *_src) |
620 | 0 | { |
621 | 0 | uint8_t *dst = (uint8_t *)_dst; /*cast for ptr arithmetic*/ |
622 | 0 | const uint8_t *src = (const uint8_t *)_src; /*cast for ptr arithmetic*/ |
623 | 0 | hsize_t idx[H5VM_HYPER_NDIMS]; /*1-origin indices */ |
624 | 0 | hsize_t nelmts; /*num elements to copy */ |
625 | 0 | hsize_t i; /*counter */ |
626 | 0 | int j; /*counters */ |
627 | 0 | bool carry; /*carray for subtraction*/ |
628 | |
|
629 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
630 | |
|
631 | 0 | assert(elmt_size < SIZE_MAX); |
632 | |
|
633 | 0 | if (n) { |
634 | 0 | H5VM_vector_cpy(n, idx, size); |
635 | 0 | nelmts = H5VM_vector_reduce_product(n, size); |
636 | 0 | for (i = 0; i < nelmts; i++) { |
637 | | |
638 | | /* Copy an element */ |
639 | 0 | H5_CHECK_OVERFLOW(elmt_size, hsize_t, size_t); |
640 | 0 | H5MM_memcpy(dst, src, (size_t)elmt_size); |
641 | | |
642 | | /* Decrement indices and advance pointers */ |
643 | 0 | for (j = (int)(n - 1), carry = true; j >= 0 && carry; --j) { |
644 | 0 | src += src_stride[j]; |
645 | 0 | dst += dst_stride[j]; |
646 | |
|
647 | 0 | if (--idx[j]) |
648 | 0 | carry = false; |
649 | 0 | else { |
650 | 0 | assert(size); |
651 | 0 | idx[j] = size[j]; |
652 | 0 | } |
653 | 0 | } |
654 | 0 | } |
655 | 0 | } |
656 | 0 | else { |
657 | 0 | H5_CHECK_OVERFLOW(elmt_size, hsize_t, size_t); |
658 | 0 | H5MM_memcpy(dst, src, (size_t)elmt_size); |
659 | 0 | } |
660 | |
|
661 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
662 | 0 | } |
663 | | |
664 | | /*------------------------------------------------------------------------- |
665 | | * Function: H5VM_stride_copy_s |
666 | | * |
667 | | * Purpose: Uses DST_STRIDE and SRC_STRIDE to advance through the arrays |
668 | | * DST and SRC while copying bytes from SRC to DST. This |
669 | | * function minimizes the number of calls to memcpy() by |
670 | | * combining various strides, but it will never touch memory |
671 | | * outside the hyperslab defined by the strides. |
672 | | * |
673 | | * Note: If the src_stride is all zero and elmt_size is one, then it's |
674 | | * probably more efficient to use H5VM_stride_fill() instead. |
675 | | * |
676 | | * Return: Non-negative on success/Negative on failure |
677 | | * |
678 | | *------------------------------------------------------------------------- |
679 | | */ |
680 | | herr_t |
681 | | H5VM_stride_copy_s(unsigned n, hsize_t elmt_size, const hsize_t *size, const hssize_t *dst_stride, void *_dst, |
682 | | const hssize_t *src_stride, const void *_src) |
683 | 0 | { |
684 | 0 | uint8_t *dst = (uint8_t *)_dst; /*cast for ptr arithmetic*/ |
685 | 0 | const uint8_t *src = (const uint8_t *)_src; /*cast for ptr arithmetic*/ |
686 | 0 | hsize_t idx[H5VM_HYPER_NDIMS]; /*1-origin indices */ |
687 | 0 | hsize_t nelmts; /*num elements to copy */ |
688 | 0 | hsize_t i; /*counter */ |
689 | 0 | int j; /*counters */ |
690 | 0 | bool carry; /*carray for subtraction*/ |
691 | |
|
692 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
693 | |
|
694 | 0 | assert(elmt_size < SIZE_MAX); |
695 | |
|
696 | 0 | if (n) { |
697 | 0 | H5VM_vector_cpy(n, idx, size); |
698 | 0 | nelmts = H5VM_vector_reduce_product(n, size); |
699 | 0 | for (i = 0; i < nelmts; i++) { |
700 | | |
701 | | /* Copy an element */ |
702 | 0 | H5_CHECK_OVERFLOW(elmt_size, hsize_t, size_t); |
703 | 0 | H5MM_memcpy(dst, src, (size_t)elmt_size); |
704 | | |
705 | | /* Decrement indices and advance pointers */ |
706 | 0 | for (j = (int)(n - 1), carry = true; j >= 0 && carry; --j) { |
707 | 0 | src += src_stride[j]; |
708 | 0 | dst += dst_stride[j]; |
709 | |
|
710 | 0 | if (--idx[j]) |
711 | 0 | carry = false; |
712 | 0 | else { |
713 | 0 | assert(size); |
714 | 0 | idx[j] = size[j]; |
715 | 0 | } |
716 | 0 | } |
717 | 0 | } |
718 | 0 | } |
719 | 0 | else { |
720 | 0 | H5_CHECK_OVERFLOW(elmt_size, hsize_t, size_t); |
721 | 0 | H5MM_memcpy(dst, src, (size_t)elmt_size); |
722 | 0 | } |
723 | |
|
724 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
725 | 0 | } |
726 | | |
727 | | /*------------------------------------------------------------------------- |
728 | | * Function: H5VM_array_fill |
729 | | * |
730 | | * Purpose: Fills all bytes of an array with the same value using |
731 | | * memset(). Increases amount copied by power of two until the |
732 | | * halfway point is crossed, then copies the rest in one swoop. |
733 | | * |
734 | | * Return: Non-negative on success/Negative on failure |
735 | | * |
736 | | *------------------------------------------------------------------------- |
737 | | */ |
738 | | herr_t |
739 | | H5VM_array_fill(void *_dst, const void *src, size_t size, size_t count) |
740 | 0 | { |
741 | 0 | size_t copy_size; /* size of the buffer to copy */ |
742 | 0 | size_t copy_items; /* number of items currently copying*/ |
743 | 0 | size_t items_left; /* number of items left to copy */ |
744 | 0 | uint8_t *dst = (uint8_t *)_dst; /* alias for pointer arithmetic */ |
745 | |
|
746 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
747 | |
|
748 | 0 | assert(dst); |
749 | 0 | assert(src); |
750 | 0 | assert(size < SIZE_MAX && size > 0); |
751 | 0 | assert(count < SIZE_MAX && count > 0); |
752 | |
|
753 | 0 | H5MM_memcpy(dst, src, size); /* copy first item */ |
754 | | |
755 | | /* Initialize counters, etc. while compensating for first element copied */ |
756 | 0 | copy_size = size; |
757 | 0 | copy_items = 1; |
758 | 0 | items_left = count - 1; |
759 | 0 | dst += size; |
760 | | |
761 | | /* copy until we've copied at least half of the items */ |
762 | 0 | while (items_left >= copy_items) { |
763 | 0 | H5MM_memcpy(dst, _dst, copy_size); /* copy the current chunk */ |
764 | 0 | dst += copy_size; /* move the offset for the next chunk */ |
765 | 0 | items_left -= copy_items; /* decrement the number of items left */ |
766 | |
|
767 | 0 | copy_size *= 2; /* increase the size of the chunk to copy */ |
768 | 0 | copy_items *= 2; /* increase the count of items we are copying */ |
769 | 0 | } /* end while */ |
770 | 0 | if (items_left > 0) /* if there are any items left to copy */ |
771 | 0 | H5MM_memcpy(dst, _dst, items_left * size); |
772 | |
|
773 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
774 | 0 | } /* H5VM_array_fill() */ |
775 | | |
776 | | /*------------------------------------------------------------------------- |
777 | | * Function: H5VM_array_down |
778 | | * |
779 | | * Purpose: Given a set of dimension sizes, calculate the size of each |
780 | | * "down" slice. This is the size of the dimensions for all the |
781 | | * dimensions below the current one, which is used for indexing |
782 | | * offsets in this dimension. |
783 | | * |
784 | | * Return: void |
785 | | * |
786 | | *------------------------------------------------------------------------- |
787 | | */ |
788 | | void |
789 | | H5VM_array_down(unsigned n, const hsize_t *total_size, hsize_t *down) |
790 | 0 | { |
791 | 0 | hsize_t acc; /* Accumulator */ |
792 | 0 | int i; /* Counter */ |
793 | |
|
794 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
795 | |
|
796 | 0 | assert(n <= H5VM_HYPER_NDIMS); |
797 | 0 | assert(total_size); |
798 | 0 | assert(down); |
799 | | |
800 | | /* Build the sizes of each dimension in the array |
801 | | * (From fastest to slowest) |
802 | | */ |
803 | 0 | for (i = (int)(n - 1), acc = 1; i >= 0; i--) { |
804 | 0 | down[i] = acc; |
805 | 0 | acc *= total_size[i]; |
806 | 0 | } |
807 | |
|
808 | 0 | FUNC_LEAVE_NOAPI_VOID |
809 | 0 | } /* end H5VM_array_down() */ |
810 | | |
811 | | /*------------------------------------------------------------------------- |
812 | | * Function: H5VM_array_offset_pre |
813 | | * |
814 | | * Purpose: Given a coordinate description of a location in an array, this |
815 | | * function returns the byte offset of the coordinate. |
816 | | * |
817 | | * The dimensionality of the whole array, and the offset is N. |
818 | | * The whole array dimensions are TOTAL_SIZE and the coordinate |
819 | | * is at offset OFFSET. |
820 | | * |
821 | | * Return: Byte offset from beginning of array to element offset |
822 | | * |
823 | | *------------------------------------------------------------------------- |
824 | | */ |
825 | | hsize_t |
826 | | H5VM_array_offset_pre(unsigned n, const hsize_t *acc, const hsize_t *offset) |
827 | 0 | { |
828 | 0 | unsigned u; /* Local index variable */ |
829 | 0 | hsize_t ret_value; /* Return value */ |
830 | |
|
831 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
832 | |
|
833 | 0 | assert(n <= H5VM_HYPER_NDIMS); |
834 | 0 | assert(acc); |
835 | 0 | assert(offset); |
836 | | |
837 | | /* Compute offset in array */ |
838 | 0 | for (u = 0, ret_value = 0; u < n; u++) |
839 | 0 | ret_value += acc[u] * offset[u]; |
840 | |
|
841 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
842 | 0 | } /* end H5VM_array_offset_pre() */ |
843 | | |
844 | | /*------------------------------------------------------------------------- |
845 | | * Function: H5VM_array_offset |
846 | | * |
847 | | * Purpose: Given a coordinate description of a location in an array, |
848 | | * this function returns the byte offset of the coordinate. |
849 | | * |
850 | | * The dimensionality of the whole array, and the offset is N. |
851 | | * The whole array dimensions are TOTAL_SIZE and the coordinate |
852 | | * is at offset OFFSET. |
853 | | * |
854 | | * Return: Byte offset from beginning of array to element offset |
855 | | * |
856 | | *------------------------------------------------------------------------- |
857 | | */ |
858 | | hsize_t |
859 | | H5VM_array_offset(unsigned n, const hsize_t *total_size, const hsize_t *offset) |
860 | 0 | { |
861 | 0 | hsize_t acc_arr[H5VM_HYPER_NDIMS]; /* Accumulated size of down dimensions */ |
862 | 0 | hsize_t ret_value; /* Return value */ |
863 | |
|
864 | 0 | FUNC_ENTER_NOAPI_NOERR |
865 | |
|
866 | 0 | assert(n <= H5VM_HYPER_NDIMS); |
867 | 0 | assert(total_size); |
868 | 0 | assert(offset); |
869 | | |
870 | | /* Build the sizes of each dimension in the array */ |
871 | 0 | H5VM_array_down(n, total_size, acc_arr); |
872 | | |
873 | | /* Set return value */ |
874 | 0 | ret_value = H5VM_array_offset_pre(n, acc_arr, offset); |
875 | |
|
876 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
877 | 0 | } /* end H5VM_array_offset() */ |
878 | | |
879 | | /*------------------------------------------------------------------------- |
880 | | * Function: H5VM_array_calc_pre |
881 | | * |
882 | | * Purpose: Given a linear offset in an array, the dimensions of that |
883 | | * array and the pre-computed 'down' (accumulator) sizes, this |
884 | | * function computes the coordinates of that offset in the array. |
885 | | * |
886 | | * The dimensionality of the whole array, and the coordinates is N. |
887 | | * The array dimensions are TOTAL_SIZE and the coordinates |
888 | | * are returned in COORD. The linear offset is in OFFSET. |
889 | | * |
890 | | * Return: Non-negative on success/Negative on failure |
891 | | * |
892 | | *------------------------------------------------------------------------- |
893 | | */ |
894 | | herr_t |
895 | | H5VM_array_calc_pre(hsize_t offset, unsigned n, const hsize_t *down, hsize_t *coords) |
896 | 0 | { |
897 | 0 | unsigned u; /* Local index variable */ |
898 | |
|
899 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
900 | | |
901 | | /* Sanity check */ |
902 | 0 | assert(n <= H5VM_HYPER_NDIMS); |
903 | 0 | assert(coords); |
904 | | |
905 | | /* Compute the coordinates from the offset */ |
906 | 0 | for (u = 0; u < n; u++) { |
907 | 0 | coords[u] = offset / down[u]; |
908 | 0 | offset %= down[u]; |
909 | 0 | } /* end for */ |
910 | |
|
911 | 0 | FUNC_LEAVE_NOAPI(SUCCEED) |
912 | 0 | } /* end H5VM_array_calc_pre() */ |
913 | | |
914 | | /*------------------------------------------------------------------------- |
915 | | * Function: H5VM_array_calc |
916 | | * |
917 | | * Purpose: Given a linear offset in an array and the dimensions of that |
918 | | * array, this function computes the coordinates of that offset |
919 | | * in the array. |
920 | | * |
921 | | * The dimensionality of the whole array, and the coordinates is N. |
922 | | * The array dimensions are TOTAL_SIZE and the coordinates |
923 | | * are returned in COORD. The linear offset is in OFFSET. |
924 | | * |
925 | | * Return: Non-negative on success/Negative on failure |
926 | | * |
927 | | *------------------------------------------------------------------------- |
928 | | */ |
929 | | herr_t |
930 | | H5VM_array_calc(hsize_t offset, unsigned n, const hsize_t *total_size, hsize_t *coords) |
931 | 0 | { |
932 | 0 | hsize_t idx[H5VM_HYPER_NDIMS]; /* Size of each dimension in bytes */ |
933 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
934 | |
|
935 | 0 | FUNC_ENTER_NOAPI(FAIL) |
936 | | |
937 | | /* Sanity check */ |
938 | 0 | assert(n <= H5VM_HYPER_NDIMS); |
939 | 0 | assert(total_size); |
940 | 0 | assert(coords); |
941 | | |
942 | | /* Build the sizes of each dimension in the array */ |
943 | 0 | H5VM_array_down(n, total_size, idx); |
944 | | |
945 | | /* Compute the coordinates from the offset */ |
946 | 0 | if (H5VM_array_calc_pre(offset, n, idx, coords) < 0) |
947 | 0 | HGOTO_ERROR(H5E_INTERNAL, H5E_BADVALUE, FAIL, "can't compute coordinates"); |
948 | | |
949 | 0 | done: |
950 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
951 | 0 | } /* end H5VM_array_calc() */ |
952 | | |
953 | | /*------------------------------------------------------------------------- |
954 | | * Function: H5VM_chunk_index |
955 | | * |
956 | | * Purpose: Given a coordinate offset (COORD), the size of each chunk |
957 | | * (CHUNK), the number of chunks in each dimension (NCHUNKS) |
958 | | * and the number of dimensions of all of these (NDIMS), calculate |
959 | | * a "chunk index" for the chunk that the coordinate offset is |
960 | | * located in. |
961 | | * |
962 | | * The chunk index starts at 0 and increases according to the |
963 | | * fastest changing dimension, then the next fastest, etc. |
964 | | * |
965 | | * For example, with a 3x5 chunk size and 6 chunks in the fastest |
966 | | * changing dimension and 3 chunks in the slowest changing |
967 | | * dimension, the chunk indices are as follows: |
968 | | * |
969 | | * +-----+-----+-----+-----+-----+-----+ |
970 | | * | | | | | | | |
971 | | * | 0 | 1 | 2 | 3 | 4 | 5 | |
972 | | * | | | | | | | |
973 | | * +-----+-----+-----+-----+-----+-----+ |
974 | | * | | | | | | | |
975 | | * | 6 | 7 | 8 | 9 | 10 | 11 | |
976 | | * | | | | | | | |
977 | | * +-----+-----+-----+-----+-----+-----+ |
978 | | * | | | | | | | |
979 | | * | 12 | 13 | 14 | 15 | 16 | 17 | |
980 | | * | | | | | | | |
981 | | * +-----+-----+-----+-----+-----+-----+ |
982 | | * |
983 | | * The chunk index is placed in the CHUNK_IDX location for return |
984 | | * from this function |
985 | | * |
986 | | * Return: Chunk index on success (can't fail) |
987 | | * |
988 | | *------------------------------------------------------------------------- |
989 | | */ |
990 | | hsize_t |
991 | | H5VM_chunk_index(unsigned ndims, const hsize_t *coord, const hsize_t *chunk, const hsize_t *down_nchunks) |
992 | 0 | { |
993 | 0 | hsize_t scaled_coord[H5VM_HYPER_NDIMS]; /* Scaled, coordinates, in terms of chunks */ |
994 | 0 | hsize_t chunk_idx; /* Chunk index computed */ |
995 | |
|
996 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
997 | | |
998 | | /* Sanity check */ |
999 | 0 | assert(ndims <= H5VM_HYPER_NDIMS); |
1000 | 0 | assert(coord); |
1001 | 0 | assert(chunk); |
1002 | 0 | assert(down_nchunks); |
1003 | | |
1004 | | /* Defer to H5VM_chunk_index_scaled */ |
1005 | 0 | chunk_idx = H5VM_chunk_index_scaled(ndims, coord, chunk, down_nchunks, scaled_coord); |
1006 | |
|
1007 | 0 | FUNC_LEAVE_NOAPI(chunk_idx) |
1008 | 0 | } /* end H5VM_chunk_index() */ |
1009 | | |
1010 | | /*------------------------------------------------------------------------- |
1011 | | * Function: H5VM_chunk_scaled |
1012 | | * |
1013 | | * Purpose: Compute the scaled coordinates for a chunk offset |
1014 | | * |
1015 | | * Return: void |
1016 | | * |
1017 | | *------------------------------------------------------------------------- |
1018 | | */ |
1019 | | void |
1020 | | H5VM_chunk_scaled(unsigned ndims, const hsize_t *coord, const hsize_t *chunk, hsize_t *scaled) |
1021 | 0 | { |
1022 | 0 | unsigned u; /* Local index variable */ |
1023 | |
|
1024 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
1025 | | |
1026 | | /* Sanity check */ |
1027 | 0 | assert(ndims <= H5VM_HYPER_NDIMS); |
1028 | 0 | assert(coord); |
1029 | 0 | assert(chunk); |
1030 | 0 | assert(scaled); |
1031 | | |
1032 | | /* Compute the scaled coordinates for actual coordinates */ |
1033 | | /* (Note that the 'scaled' array is an 'OUT' parameter) */ |
1034 | 0 | for (u = 0; u < ndims; u++) |
1035 | 0 | scaled[u] = coord[u] / chunk[u]; |
1036 | |
|
1037 | 0 | FUNC_LEAVE_NOAPI_VOID |
1038 | 0 | } /* end H5VM_chunk_scaled() */ |
1039 | | |
1040 | | /*------------------------------------------------------------------------- |
1041 | | * Function: H5VM_chunk_index_scaled |
1042 | | * |
1043 | | * Purpose: Given a coordinate offset (COORD), the size of each chunk |
1044 | | * (CHUNK), the number of chunks in each dimension (NCHUNKS) |
1045 | | * and the number of dimensions of all of these (NDIMS), calculate |
1046 | | * a "chunk index" for the chunk that the coordinate offset is |
1047 | | * located in. |
1048 | | * |
1049 | | * The chunk index starts at 0 and increases according to the |
1050 | | * fastest changing dimension, then the next fastest, etc. |
1051 | | * |
1052 | | * For example, with a 3x5 chunk size and 6 chunks in the fastest |
1053 | | * changing dimension and 3 chunks in the slowest changing |
1054 | | * dimension, the chunk indices are as follows: |
1055 | | * |
1056 | | * +-----+-----+-----+-----+-----+-----+ |
1057 | | * | | | | | | | |
1058 | | * | 0 | 1 | 2 | 3 | 4 | 5 | |
1059 | | * | | | | | | | |
1060 | | * +-----+-----+-----+-----+-----+-----+ |
1061 | | * | | | | | | | |
1062 | | * | 6 | 7 | 8 | 9 | 10 | 11 | |
1063 | | * | | | | | | | |
1064 | | * +-----+-----+-----+-----+-----+-----+ |
1065 | | * | | | | | | | |
1066 | | * | 12 | 13 | 14 | 15 | 16 | 17 | |
1067 | | * | | | | | | | |
1068 | | * +-----+-----+-----+-----+-----+-----+ |
1069 | | * |
1070 | | * The chunk index is placed in the CHUNK_IDX location for return |
1071 | | * from this function |
1072 | | * |
1073 | | * Note: This routine is identical to H5VM_chunk_index(), except for |
1074 | | * caching the scaled information. Make changes in both places. |
1075 | | * |
1076 | | * Return: Chunk index on success (can't fail) |
1077 | | * |
1078 | | *------------------------------------------------------------------------- |
1079 | | */ |
1080 | | hsize_t |
1081 | | H5VM_chunk_index_scaled(unsigned ndims, const hsize_t *coord, const hsize_t *chunk, |
1082 | | const hsize_t *down_nchunks, hsize_t *scaled) |
1083 | 0 | { |
1084 | 0 | hsize_t chunk_idx; /* Computed chunk index */ |
1085 | 0 | unsigned u; /* Local index variable */ |
1086 | |
|
1087 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
1088 | | |
1089 | | /* Sanity check */ |
1090 | 0 | assert(ndims <= H5VM_HYPER_NDIMS); |
1091 | 0 | assert(coord); |
1092 | 0 | assert(chunk); |
1093 | 0 | assert(down_nchunks); |
1094 | 0 | assert(scaled); |
1095 | | |
1096 | | /* Compute the scaled coordinates for actual coordinates */ |
1097 | | /* (Note that the 'scaled' array is an 'OUT' parameter) */ |
1098 | 0 | for (u = 0; u < ndims; u++) |
1099 | 0 | scaled[u] = coord[u] / chunk[u]; |
1100 | | |
1101 | | /* Compute the chunk index */ |
1102 | 0 | chunk_idx = H5VM_array_offset_pre(ndims, down_nchunks, scaled); |
1103 | |
|
1104 | 0 | FUNC_LEAVE_NOAPI(chunk_idx) |
1105 | 0 | } /* end H5VM_chunk_index_scaled() */ |
1106 | | |
1107 | | /*------------------------------------------------------------------------- |
1108 | | * Function: H5VM_opvv |
1109 | | * |
1110 | | * Purpose: Perform an operation on a source & destination sequences |
1111 | | * of offset/length pairs. Each set of sequences has an array |
1112 | | * of lengths, an array of offsets, the maximum number of |
1113 | | * sequences and the current sequence to start at in the sequence. |
1114 | | * |
1115 | | * There may be different numbers of bytes in the source and |
1116 | | * destination sequences, the operation stops when either the |
1117 | | * source or destination sequence runs out of information. |
1118 | | * |
1119 | | * Note: The algorithm in this routine is [basically] the same as for |
1120 | | * H5VM_memcpyvv(). Changes should be made to both! |
1121 | | * |
1122 | | * Return: Non-negative # of bytes operated on, on success/Negative on failure |
1123 | | * |
1124 | | *------------------------------------------------------------------------- |
1125 | | */ |
1126 | | ssize_t |
1127 | | H5VM_opvv(size_t dst_max_nseq, size_t *dst_curr_seq, size_t dst_len_arr[], hsize_t dst_off_arr[], |
1128 | | size_t src_max_nseq, size_t *src_curr_seq, size_t src_len_arr[], hsize_t src_off_arr[], |
1129 | | H5VM_opvv_func_t op, void *op_data) |
1130 | 0 | { |
1131 | 0 | hsize_t *max_dst_off_ptr, *max_src_off_ptr; /* Pointers to max. source and destination offset locations */ |
1132 | 0 | hsize_t *dst_off_ptr, *src_off_ptr; /* Pointers to source and destination offset arrays */ |
1133 | 0 | size_t *dst_len_ptr, *src_len_ptr; /* Pointers to source and destination length arrays */ |
1134 | 0 | hsize_t tmp_dst_off, tmp_src_off; /* Temporary source and destination offset values */ |
1135 | 0 | size_t tmp_dst_len, tmp_src_len; /* Temporary source and destination length values */ |
1136 | 0 | size_t acc_len; /* Accumulated length of sequences */ |
1137 | 0 | ssize_t ret_value = 0; /* Return value (Total size of sequence in bytes) */ |
1138 | |
|
1139 | 0 | FUNC_ENTER_NOAPI(FAIL) |
1140 | | |
1141 | | /* Sanity check */ |
1142 | 0 | assert(dst_curr_seq); |
1143 | 0 | assert(*dst_curr_seq < dst_max_nseq); |
1144 | 0 | assert(dst_len_arr); |
1145 | 0 | assert(dst_off_arr); |
1146 | 0 | assert(src_curr_seq); |
1147 | 0 | assert(*src_curr_seq < src_max_nseq); |
1148 | 0 | assert(src_len_arr); |
1149 | 0 | assert(src_off_arr); |
1150 | 0 | assert(op); |
1151 | | |
1152 | | /* Set initial offset & length pointers */ |
1153 | 0 | dst_len_ptr = dst_len_arr + *dst_curr_seq; |
1154 | 0 | dst_off_ptr = dst_off_arr + *dst_curr_seq; |
1155 | 0 | src_len_ptr = src_len_arr + *src_curr_seq; |
1156 | 0 | src_off_ptr = src_off_arr + *src_curr_seq; |
1157 | | |
1158 | | /* Get temporary source & destination sequence offsets & lengths */ |
1159 | 0 | tmp_dst_len = *dst_len_ptr; |
1160 | 0 | tmp_dst_off = *dst_off_ptr; |
1161 | 0 | tmp_src_len = *src_len_ptr; |
1162 | 0 | tmp_src_off = *src_off_ptr; |
1163 | | |
1164 | | /* Compute maximum offset pointer values */ |
1165 | 0 | max_dst_off_ptr = dst_off_arr + dst_max_nseq; |
1166 | 0 | max_src_off_ptr = src_off_arr + src_max_nseq; |
1167 | | |
1168 | | /* Work through the sequences */ |
1169 | | /* (Choose smallest sequence available initially) */ |
1170 | | |
1171 | | /* Source sequence is less than destination sequence */ |
1172 | 0 | if (tmp_src_len < tmp_dst_len) { |
1173 | 0 | src_smaller: |
1174 | 0 | acc_len = 0; |
1175 | 0 | do { |
1176 | | /* Make operator callback */ |
1177 | 0 | if ((*op)(tmp_dst_off, tmp_src_off, tmp_src_len, op_data) < 0) |
1178 | 0 | HGOTO_ERROR(H5E_INTERNAL, H5E_CANTOPERATE, FAIL, "can't perform operation"); |
1179 | | |
1180 | | /* Accumulate number of bytes copied */ |
1181 | 0 | acc_len += tmp_src_len; |
1182 | | |
1183 | | /* Update destination length */ |
1184 | 0 | tmp_dst_off += tmp_src_len; |
1185 | 0 | tmp_dst_len -= tmp_src_len; |
1186 | | |
1187 | | /* Advance source offset & check for being finished */ |
1188 | 0 | src_off_ptr++; |
1189 | 0 | if (src_off_ptr >= max_src_off_ptr) { |
1190 | | /* Roll accumulated changes into appropriate counters */ |
1191 | 0 | *dst_off_ptr = tmp_dst_off; |
1192 | 0 | *dst_len_ptr = tmp_dst_len; |
1193 | | |
1194 | | /* Done with sequences */ |
1195 | 0 | goto finished; |
1196 | 0 | } /* end if */ |
1197 | 0 | tmp_src_off = *src_off_ptr; |
1198 | | |
1199 | | /* Update source information */ |
1200 | 0 | src_len_ptr++; |
1201 | 0 | tmp_src_len = *src_len_ptr; |
1202 | 0 | } while (tmp_src_len < tmp_dst_len); |
1203 | | |
1204 | | /* Roll accumulated sequence lengths into return value */ |
1205 | 0 | ret_value += (ssize_t)acc_len; |
1206 | | |
1207 | | /* Transition to next state */ |
1208 | 0 | if (tmp_dst_len < tmp_src_len) |
1209 | 0 | goto dst_smaller; |
1210 | 0 | else |
1211 | 0 | goto equal; |
1212 | 0 | } /* end if */ |
1213 | | /* Destination sequence is less than source sequence */ |
1214 | 0 | else if (tmp_dst_len < tmp_src_len) { |
1215 | 0 | dst_smaller: |
1216 | 0 | acc_len = 0; |
1217 | 0 | do { |
1218 | | /* Make operator callback */ |
1219 | 0 | if ((*op)(tmp_dst_off, tmp_src_off, tmp_dst_len, op_data) < 0) |
1220 | 0 | HGOTO_ERROR(H5E_INTERNAL, H5E_CANTOPERATE, FAIL, "can't perform operation"); |
1221 | | |
1222 | | /* Accumulate number of bytes copied */ |
1223 | 0 | acc_len += tmp_dst_len; |
1224 | | |
1225 | | /* Update source length */ |
1226 | 0 | tmp_src_off += tmp_dst_len; |
1227 | 0 | tmp_src_len -= tmp_dst_len; |
1228 | | |
1229 | | /* Advance destination offset & check for being finished */ |
1230 | 0 | dst_off_ptr++; |
1231 | 0 | if (dst_off_ptr >= max_dst_off_ptr) { |
1232 | | /* Roll accumulated changes into appropriate counters */ |
1233 | 0 | *src_off_ptr = tmp_src_off; |
1234 | 0 | *src_len_ptr = tmp_src_len; |
1235 | | |
1236 | | /* Done with sequences */ |
1237 | 0 | goto finished; |
1238 | 0 | } /* end if */ |
1239 | 0 | tmp_dst_off = *dst_off_ptr; |
1240 | | |
1241 | | /* Update destination information */ |
1242 | 0 | dst_len_ptr++; |
1243 | 0 | tmp_dst_len = *dst_len_ptr; |
1244 | 0 | } while (tmp_dst_len < tmp_src_len); |
1245 | | |
1246 | | /* Roll accumulated sequence lengths into return value */ |
1247 | 0 | ret_value += (ssize_t)acc_len; |
1248 | | |
1249 | | /* Transition to next state */ |
1250 | 0 | if (tmp_src_len < tmp_dst_len) |
1251 | 0 | goto src_smaller; |
1252 | 0 | else |
1253 | 0 | goto equal; |
1254 | 0 | } /* end else-if */ |
1255 | | /* Destination sequence and source sequence are same length */ |
1256 | 0 | else { |
1257 | 0 | equal: |
1258 | 0 | acc_len = 0; |
1259 | 0 | do { |
1260 | | /* Make operator callback */ |
1261 | 0 | if ((*op)(tmp_dst_off, tmp_src_off, tmp_dst_len, op_data) < 0) |
1262 | 0 | HGOTO_ERROR(H5E_INTERNAL, H5E_CANTOPERATE, FAIL, "can't perform operation"); |
1263 | | |
1264 | | /* Accumulate number of bytes copied */ |
1265 | 0 | acc_len += tmp_dst_len; |
1266 | | |
1267 | | /* Advance source & destination offset & check for being finished */ |
1268 | 0 | src_off_ptr++; |
1269 | 0 | dst_off_ptr++; |
1270 | 0 | if (src_off_ptr >= max_src_off_ptr || dst_off_ptr >= max_dst_off_ptr) |
1271 | | /* Done with sequences */ |
1272 | 0 | goto finished; |
1273 | 0 | tmp_src_off = *src_off_ptr; |
1274 | 0 | tmp_dst_off = *dst_off_ptr; |
1275 | | |
1276 | | /* Update source information */ |
1277 | 0 | src_len_ptr++; |
1278 | 0 | tmp_src_len = *src_len_ptr; |
1279 | | |
1280 | | /* Update destination information */ |
1281 | 0 | dst_len_ptr++; |
1282 | 0 | tmp_dst_len = *dst_len_ptr; |
1283 | 0 | } while (tmp_dst_len == tmp_src_len); |
1284 | | |
1285 | | /* Roll accumulated sequence lengths into return value */ |
1286 | 0 | ret_value += (ssize_t)acc_len; |
1287 | | |
1288 | | /* Transition to next state */ |
1289 | 0 | if (tmp_dst_len < tmp_src_len) |
1290 | 0 | goto dst_smaller; |
1291 | 0 | else |
1292 | 0 | goto src_smaller; |
1293 | 0 | } /* end else */ |
1294 | | |
1295 | 0 | finished: |
1296 | | /* Roll accumulated sequence lengths into return value */ |
1297 | 0 | ret_value += (ssize_t)acc_len; |
1298 | | |
1299 | | /* Update current sequence vectors */ |
1300 | 0 | *dst_curr_seq = (size_t)(dst_off_ptr - dst_off_arr); |
1301 | 0 | *src_curr_seq = (size_t)(src_off_ptr - src_off_arr); |
1302 | |
|
1303 | 0 | done: |
1304 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1305 | 0 | } /* end H5VM_opvv() */ |
1306 | | |
1307 | | /*------------------------------------------------------------------------- |
1308 | | * Function: H5VM_memcpyvv |
1309 | | * |
1310 | | * Purpose: Given source and destination buffers in memory (SRC & DST) |
1311 | | * copy sequences of from the source buffer into the destination |
1312 | | * buffer. Each set of sequences has an array of lengths, an |
1313 | | * array of offsets, the maximum number of sequences and the |
1314 | | * current sequence to start at in the sequence. |
1315 | | * |
1316 | | * There may be different numbers of bytes in the source and |
1317 | | * destination sequences, data copying stops when either the |
1318 | | * source or destination buffer runs out of sequence information. |
1319 | | * |
1320 | | * Note: The algorithm in this routine is [basically] the same as for |
1321 | | * H5VM_opvv(). Changes should be made to both! |
1322 | | * |
1323 | | * Return: Non-negative # of bytes copied on success/Negative on failure |
1324 | | * |
1325 | | *------------------------------------------------------------------------- |
1326 | | */ |
1327 | | ssize_t |
1328 | | H5VM_memcpyvv(void *_dst, size_t dst_max_nseq, size_t *dst_curr_seq, size_t dst_len_arr[], |
1329 | | hsize_t dst_off_arr[], const void *_src, size_t src_max_nseq, size_t *src_curr_seq, |
1330 | | size_t src_len_arr[], hsize_t src_off_arr[]) |
1331 | 0 | { |
1332 | 0 | unsigned char *dst; /* Destination buffer pointer */ |
1333 | 0 | const unsigned char *src; /* Source buffer pointer */ |
1334 | 0 | hsize_t *max_dst_off_ptr, *max_src_off_ptr; /* Pointers to max. source and destination offset locations */ |
1335 | 0 | hsize_t *dst_off_ptr, *src_off_ptr; /* Pointers to source and destination offset arrays */ |
1336 | 0 | size_t *dst_len_ptr, *src_len_ptr; /* Pointers to source and destination length arrays */ |
1337 | 0 | size_t tmp_dst_len; /* Temporary dest. length value */ |
1338 | 0 | size_t tmp_src_len; /* Temporary source length value */ |
1339 | 0 | size_t acc_len; /* Accumulated length of sequences */ |
1340 | 0 | ssize_t ret_value = 0; /* Return value (Total size of sequence in bytes) */ |
1341 | |
|
1342 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
1343 | | |
1344 | | /* Sanity check */ |
1345 | 0 | assert(_dst); |
1346 | 0 | assert(dst_curr_seq); |
1347 | 0 | assert(*dst_curr_seq < dst_max_nseq); |
1348 | 0 | assert(dst_len_arr); |
1349 | 0 | assert(dst_off_arr); |
1350 | 0 | assert(_src); |
1351 | 0 | assert(src_curr_seq); |
1352 | 0 | assert(*src_curr_seq < src_max_nseq); |
1353 | 0 | assert(src_len_arr); |
1354 | 0 | assert(src_off_arr); |
1355 | | |
1356 | | /* Set initial offset & length pointers */ |
1357 | 0 | dst_len_ptr = dst_len_arr + *dst_curr_seq; |
1358 | 0 | dst_off_ptr = dst_off_arr + *dst_curr_seq; |
1359 | 0 | src_len_ptr = src_len_arr + *src_curr_seq; |
1360 | 0 | src_off_ptr = src_off_arr + *src_curr_seq; |
1361 | | |
1362 | | /* Get temporary source & destination sequence lengths */ |
1363 | 0 | tmp_dst_len = *dst_len_ptr; |
1364 | 0 | tmp_src_len = *src_len_ptr; |
1365 | | |
1366 | | /* Compute maximum offset pointer values */ |
1367 | 0 | max_dst_off_ptr = dst_off_arr + dst_max_nseq; |
1368 | 0 | max_src_off_ptr = src_off_arr + src_max_nseq; |
1369 | | |
1370 | | /* Compute buffer offsets */ |
1371 | 0 | dst = (unsigned char *)_dst + *dst_off_ptr; |
1372 | 0 | src = (const unsigned char *)_src + *src_off_ptr; |
1373 | | |
1374 | | /* Work through the sequences */ |
1375 | | /* (Choose smallest sequence available initially) */ |
1376 | | |
1377 | | /* Source sequence is less than destination sequence */ |
1378 | 0 | if (tmp_src_len < tmp_dst_len) { |
1379 | 0 | src_smaller: |
1380 | 0 | acc_len = 0; |
1381 | 0 | do { |
1382 | | /* Copy data */ |
1383 | 0 | H5MM_memcpy(dst, src, tmp_src_len); |
1384 | | |
1385 | | /* Accumulate number of bytes copied */ |
1386 | 0 | acc_len += tmp_src_len; |
1387 | | |
1388 | | /* Update destination length */ |
1389 | 0 | tmp_dst_len -= tmp_src_len; |
1390 | | |
1391 | | /* Advance source offset & check for being finished */ |
1392 | 0 | src_off_ptr++; |
1393 | 0 | if (src_off_ptr >= max_src_off_ptr) { |
1394 | | /* Roll accumulated changes into appropriate counters */ |
1395 | 0 | *dst_off_ptr += acc_len; |
1396 | 0 | *dst_len_ptr = tmp_dst_len; |
1397 | | |
1398 | | /* Done with sequences */ |
1399 | 0 | goto finished; |
1400 | 0 | } /* end if */ |
1401 | | |
1402 | | /* Update destination pointer */ |
1403 | 0 | dst += tmp_src_len; |
1404 | | |
1405 | | /* Update source information */ |
1406 | 0 | src_len_ptr++; |
1407 | 0 | tmp_src_len = *src_len_ptr; |
1408 | 0 | src = (const unsigned char *)_src + *src_off_ptr; |
1409 | 0 | } while (tmp_src_len < tmp_dst_len); |
1410 | | |
1411 | | /* Roll accumulated sequence lengths into return value */ |
1412 | 0 | ret_value += (ssize_t)acc_len; |
1413 | | |
1414 | | /* Transition to next state */ |
1415 | 0 | if (tmp_dst_len < tmp_src_len) |
1416 | 0 | goto dst_smaller; |
1417 | 0 | else |
1418 | 0 | goto equal; |
1419 | 0 | } /* end if */ |
1420 | | /* Destination sequence is less than source sequence */ |
1421 | 0 | else if (tmp_dst_len < tmp_src_len) { |
1422 | 0 | dst_smaller: |
1423 | 0 | acc_len = 0; |
1424 | 0 | do { |
1425 | | /* Copy data */ |
1426 | 0 | H5MM_memcpy(dst, src, tmp_dst_len); |
1427 | | |
1428 | | /* Accumulate number of bytes copied */ |
1429 | 0 | acc_len += tmp_dst_len; |
1430 | | |
1431 | | /* Update source length */ |
1432 | 0 | tmp_src_len -= tmp_dst_len; |
1433 | | |
1434 | | /* Advance destination offset & check for being finished */ |
1435 | 0 | dst_off_ptr++; |
1436 | 0 | if (dst_off_ptr >= max_dst_off_ptr) { |
1437 | | /* Roll accumulated changes into appropriate counters */ |
1438 | 0 | *src_off_ptr += acc_len; |
1439 | 0 | *src_len_ptr = tmp_src_len; |
1440 | | |
1441 | | /* Done with sequences */ |
1442 | 0 | goto finished; |
1443 | 0 | } /* end if */ |
1444 | | |
1445 | | /* Update source pointer */ |
1446 | 0 | src += tmp_dst_len; |
1447 | | |
1448 | | /* Update destination information */ |
1449 | 0 | dst_len_ptr++; |
1450 | 0 | tmp_dst_len = *dst_len_ptr; |
1451 | 0 | dst = (unsigned char *)_dst + *dst_off_ptr; |
1452 | 0 | } while (tmp_dst_len < tmp_src_len); |
1453 | | |
1454 | | /* Roll accumulated sequence lengths into return value */ |
1455 | 0 | ret_value += (ssize_t)acc_len; |
1456 | | |
1457 | | /* Transition to next state */ |
1458 | 0 | if (tmp_src_len < tmp_dst_len) |
1459 | 0 | goto src_smaller; |
1460 | 0 | else |
1461 | 0 | goto equal; |
1462 | 0 | } /* end else-if */ |
1463 | | /* Destination sequence and source sequence are same length */ |
1464 | 0 | else { |
1465 | 0 | equal: |
1466 | 0 | acc_len = 0; |
1467 | 0 | do { |
1468 | | /* Copy data */ |
1469 | 0 | H5MM_memcpy(dst, src, tmp_dst_len); |
1470 | | |
1471 | | /* Accumulate number of bytes copied */ |
1472 | 0 | acc_len += tmp_dst_len; |
1473 | | |
1474 | | /* Advance source & destination offset & check for being finished */ |
1475 | 0 | src_off_ptr++; |
1476 | 0 | dst_off_ptr++; |
1477 | 0 | if (src_off_ptr >= max_src_off_ptr || dst_off_ptr >= max_dst_off_ptr) |
1478 | | /* Done with sequences */ |
1479 | 0 | goto finished; |
1480 | | |
1481 | | /* Update source information */ |
1482 | 0 | src_len_ptr++; |
1483 | 0 | tmp_src_len = *src_len_ptr; |
1484 | 0 | src = (const unsigned char *)_src + *src_off_ptr; |
1485 | | |
1486 | | /* Update destination information */ |
1487 | 0 | dst_len_ptr++; |
1488 | 0 | tmp_dst_len = *dst_len_ptr; |
1489 | 0 | dst = (unsigned char *)_dst + *dst_off_ptr; |
1490 | 0 | } while (tmp_dst_len == tmp_src_len); |
1491 | | |
1492 | | /* Roll accumulated sequence lengths into return value */ |
1493 | 0 | ret_value += (ssize_t)acc_len; |
1494 | | |
1495 | | /* Transition to next state */ |
1496 | 0 | if (tmp_dst_len < tmp_src_len) |
1497 | 0 | goto dst_smaller; |
1498 | 0 | else |
1499 | 0 | goto src_smaller; |
1500 | 0 | } /* end else */ |
1501 | | |
1502 | 0 | finished: |
1503 | | /* Roll accumulated sequence lengths into return value */ |
1504 | 0 | ret_value += (ssize_t)acc_len; |
1505 | | |
1506 | | /* Update current sequence vectors */ |
1507 | 0 | *dst_curr_seq = (size_t)(dst_off_ptr - dst_off_arr); |
1508 | 0 | *src_curr_seq = (size_t)(src_off_ptr - src_off_arr); |
1509 | |
|
1510 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
1511 | 0 | } /* end H5VM_memcpyvv() */ |