Coverage Report

Created: 2026-03-09 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5VM.c
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() */