Coverage Report

Created: 2025-08-26 06:30

/src/hdf5/src/H5Shyper.c
Line
Count
Source (jump to first uncovered line)
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
/*
14
 * Purpose:     Hyperslab selection dataspace I/O functions.
15
 */
16
17
/****************/
18
/* Module Setup */
19
/****************/
20
21
#include "H5Smodule.h" /* This source code file is part of the H5S module */
22
23
/***********/
24
/* Headers */
25
/***********/
26
#include "H5private.h"   /* Generic Functions                        */
27
#include "H5CXprivate.h" /* API Contexts                             */
28
#include "H5Eprivate.h"  /* Error handling                           */
29
#include "H5FLprivate.h" /* Free Lists                               */
30
#include "H5Iprivate.h"  /* ID Functions                             */
31
#include "H5MMprivate.h" /* Memory management                        */
32
#include "H5Spkg.h"      /* Dataspace functions                      */
33
#include "H5VMprivate.h" /* Vector functions                         */
34
35
/****************/
36
/* Local Macros */
37
/****************/
38
39
/* Flags for which hyperslab fragments to compute */
40
0
#define H5S_HYPER_COMPUTE_B_NOT_A 0x01
41
0
#define H5S_HYPER_COMPUTE_A_AND_B 0x02
42
0
#define H5S_HYPER_COMPUTE_A_NOT_B 0x04
43
44
/* Macro to advance a span, possibly recycling it first */
45
#define H5S_HYPER_ADVANCE_SPAN(recover, curr_span, next_span, ERR)                                           \
46
0
    do {                                                                                                     \
47
0
        H5S_hyper_span_t *saved_next_span = (next_span);                                                     \
48
0
                                                                                                             \
49
0
        /* Check if the span should be recovered */                                                          \
50
0
        if (recover) {                                                                                       \
51
0
            if (H5S__hyper_free_span(curr_span) < 0)                                                         \
52
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, ERR, "unable to free span");                        \
53
0
            (recover) = false;                                                                               \
54
0
        }                                                                                                    \
55
0
                                                                                                             \
56
0
        /* Set the current span to saved next span */                                                        \
57
0
        (curr_span) = saved_next_span;                                                                       \
58
0
    } while (0)
59
60
/* Macro to add "skipped" elements to projection during the execution of
61
 * H5S__hyper_project_intersect() */
62
#define H5S_HYPER_PROJ_INT_ADD_SKIP(UDATA, ADD, ERR)                                                         \
63
0
    do {                                                                                                     \
64
0
        /* If there are any elements to add, we must add them                                                \
65
0
         * to the projection first before adding skip */                                                     \
66
0
        if ((UDATA)->nelem > 0)                                                                              \
67
0
            if (H5S__hyper_proj_int_build_proj(UDATA) < 0)                                                   \
68
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, ERR,                                              \
69
0
                            "can't add elements to projected selection");                                    \
70
0
        (UDATA)->skip += (ADD);                                                                              \
71
0
    } while (0) /* end H5S_HYPER_PROJ_INT_ADD_SKIP() */
72
73
/******************/
74
/* Local Typedefs */
75
/******************/
76
77
/* Define alias for hsize_t, for allocating H5S_hyper_span_info_t + bounds objects */
78
/* (Makes it easier to understand the alloc / free calls) */
79
typedef hsize_t hbounds_t;
80
81
/* Struct for holding persistent information during iteration for
82
 * H5S__hyper_project_intersect() */
83
typedef struct {
84
    const H5S_hyper_span_t
85
           *ds_span[H5S_MAX_RANK]; /* Array of the current spans in the destination space in each dimension */
86
    hsize_t ds_low[H5S_MAX_RANK]; /* Array of current low bounds (of iteration) for each element in ds_span */
87
    H5S_hyper_span_info_t
88
            *ps_span_info[H5S_MAX_RANK]; /* Array of span info structs for projected space during iteration */
89
    uint32_t ps_clean_bitmap; /* Bitmap of whether the nth rank has a clean projected space since the last
90
                                 time it was set to 1 */
91
    unsigned ss_rank;         /* Rank of source space */
92
    unsigned ds_rank;         /* Rank of destination space */
93
    unsigned depth;           /* Current depth of iterator in destination space */
94
    hsize_t  skip;            /* Number of elements to skip in projected space */
95
    hsize_t  nelem;           /* Number of elements to add to projected space (after skip) */
96
    uint64_t op_gen;          /* Operation generation for counting elements */
97
    bool     share_selection; /* Whether span trees in dst_space can be shared with proj_space */
98
} H5S_hyper_project_intersect_ud_t;
99
100
/* Assert that H5S_MAX_RANK is <= 32 so our trick with using a 32 bit bitmap
101
 * (ps_clean_bitmap) works.  If H5S_MAX_RANK increases either increase the size
102
 * of ps_clean_bitmap or change the algorithm to use an array. */
103
#if H5S_MAX_RANK > 32
104
#error H5S_MAX_RANK too large for ps_clean_bitmap field in H5S_hyper_project_intersect_ud_t struct
105
#endif
106
107
/********************/
108
/* Local Prototypes */
109
/********************/
110
static H5S_hyper_span_t      *H5S__hyper_new_span(hsize_t low, hsize_t high, H5S_hyper_span_info_t *down,
111
                                                  H5S_hyper_span_t *next);
112
static H5S_hyper_span_info_t *H5S__hyper_new_span_info(unsigned rank);
113
static H5S_hyper_span_info_t *H5S__hyper_copy_span_helper(H5S_hyper_span_info_t *spans, unsigned rank,
114
                                                          unsigned op_info_i, uint64_t op_gen);
115
static H5S_hyper_span_info_t *H5S__hyper_copy_span(H5S_hyper_span_info_t *spans, unsigned rank);
116
static bool                   H5S__hyper_cmp_spans(const H5S_hyper_span_info_t *span_info1,
117
                                                   const H5S_hyper_span_info_t *span_info2);
118
static herr_t                 H5S__hyper_free_span_info(H5S_hyper_span_info_t *span_info);
119
static herr_t                 H5S__hyper_free_span(H5S_hyper_span_t *span);
120
static herr_t H5S__hyper_span_blocklist(const H5S_hyper_span_info_t *spans, hsize_t start[], hsize_t end[],
121
                                        hsize_t rank, hsize_t *startblock, hsize_t *numblocks, hsize_t **buf);
122
static herr_t H5S__get_select_hyper_blocklist(H5S_t *space, hsize_t startblock, hsize_t numblocks,
123
                                              hsize_t *buf);
124
static H5S_hyper_span_t *H5S__hyper_coord_to_span(unsigned rank, const hsize_t *coords);
125
static herr_t  H5S__hyper_append_span(H5S_hyper_span_info_t **span_tree, unsigned ndims, hsize_t low,
126
                                      hsize_t high, H5S_hyper_span_info_t *down);
127
static herr_t  H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_spans,
128
                                     unsigned selector, unsigned ndims, H5S_hyper_span_info_t **a_not_b,
129
                                     H5S_hyper_span_info_t **a_and_b, H5S_hyper_span_info_t **b_not_a);
130
static herr_t  H5S__hyper_merge_spans(H5S_t *space, H5S_hyper_span_info_t *new_spans);
131
static hsize_t H5S__hyper_spans_nelem_helper(H5S_hyper_span_info_t *spans, unsigned op_info_i,
132
                                             uint64_t op_gen);
133
static hsize_t H5S__hyper_spans_nelem(H5S_hyper_span_info_t *spans);
134
static herr_t  H5S__hyper_add_disjoint_spans(H5S_t *space, H5S_hyper_span_info_t *new_spans);
135
static H5S_hyper_span_info_t *H5S__hyper_make_spans(unsigned rank, const hsize_t *start,
136
                                                    const hsize_t *stride, const hsize_t *count,
137
                                                    const hsize_t *block);
138
static herr_t                 H5S__hyper_update_diminfo(H5S_t *space, H5S_seloper_t op,
139
                                                        const H5S_hyper_dim_t *new_hyper_diminfo);
140
static herr_t                 H5S__hyper_generate_spans(H5S_t *space);
141
static bool                   H5S__check_spans_overlap(const H5S_hyper_span_info_t *spans1,
142
                                                       const H5S_hyper_span_info_t *spans2);
143
static herr_t  H5S__fill_in_new_space(H5S_t *space1, H5S_seloper_t op, H5S_hyper_span_info_t *space2_span_lst,
144
                                      bool can_own_span2, bool *span2_owned, bool *updated_spans,
145
                                      H5S_t **result);
146
static herr_t  H5S__generate_hyperslab(H5S_t *space, H5S_seloper_t op, const hsize_t start[],
147
                                       const hsize_t stride[], const hsize_t count[], const hsize_t block[]);
148
static herr_t  H5S__set_regular_hyperslab(H5S_t *space, const hsize_t start[], const hsize_t *app_stride,
149
                                          const hsize_t app_count[], const hsize_t *app_block,
150
                                          const hsize_t *opt_stride, const hsize_t opt_count[],
151
                                          const hsize_t *opt_block);
152
static herr_t  H5S__fill_in_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2, H5S_t **result);
153
static H5S_t  *H5S__combine_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2);
154
static herr_t  H5S__hyper_iter_get_seq_list_gen(H5S_sel_iter_t *iter, size_t maxseq, size_t maxelem,
155
                                                size_t *nseq, size_t *nelem, hsize_t *off, size_t *len);
156
static herr_t  H5S__hyper_iter_get_seq_list_opt(H5S_sel_iter_t *iter, size_t maxseq, size_t maxelem,
157
                                                size_t *nseq, size_t *nelem, hsize_t *off, size_t *len);
158
static herr_t  H5S__hyper_iter_get_seq_list_single(H5S_sel_iter_t *iter, size_t maxseq, size_t maxelem,
159
                                                   size_t *nseq, size_t *nelem, hsize_t *off, size_t *len);
160
static herr_t  H5S__hyper_proj_int_build_proj(H5S_hyper_project_intersect_ud_t *udata);
161
static herr_t  H5S__hyper_proj_int_iterate(H5S_hyper_span_info_t       *ss_span_info,
162
                                           const H5S_hyper_span_info_t *sis_span_info, hsize_t count,
163
                                           unsigned depth, H5S_hyper_project_intersect_ud_t *udata);
164
static void    H5S__hyper_get_clip_diminfo(hsize_t start, hsize_t stride, hsize_t *count, hsize_t *block,
165
                                           hsize_t clip_size);
166
static hsize_t H5S__hyper_get_clip_extent_real(const H5S_t *clip_space, hsize_t num_slices, bool incl_trail);
167
168
/* Selection callbacks */
169
static herr_t   H5S__hyper_copy(H5S_t *dst, const H5S_t *src, bool share_selection);
170
static herr_t   H5S__hyper_release(H5S_t *space);
171
static htri_t   H5S__hyper_is_valid(const H5S_t *space);
172
static hsize_t  H5S__hyper_span_nblocks(H5S_hyper_span_info_t *spans);
173
static hssize_t H5S__hyper_serial_size(H5S_t *space);
174
static herr_t   H5S__hyper_serialize(H5S_t *space, uint8_t **p);
175
static herr_t   H5S__hyper_deserialize(H5S_t **space, const uint8_t **p, const size_t p_size, bool skip);
176
static herr_t   H5S__hyper_bounds(const H5S_t *space, hsize_t *start, hsize_t *end);
177
static herr_t   H5S__hyper_offset(const H5S_t *space, hsize_t *offset);
178
static int      H5S__hyper_unlim_dim(const H5S_t *space);
179
static herr_t   H5S__hyper_num_elem_non_unlim(const H5S_t *space, hsize_t *num_elem_non_unlim);
180
static htri_t   H5S__hyper_is_contiguous(const H5S_t *space);
181
static htri_t   H5S__hyper_is_single(const H5S_t *space);
182
static htri_t   H5S__hyper_is_regular(H5S_t *space);
183
static htri_t   H5S__hyper_shape_same(H5S_t *space1, H5S_t *space2);
184
static htri_t   H5S__hyper_intersect_block(H5S_t *space, const hsize_t *start, const hsize_t *end);
185
static herr_t   H5S__hyper_adjust_u(H5S_t *space, const hsize_t *offset);
186
static herr_t   H5S__hyper_adjust_s(H5S_t *space, const hssize_t *offset);
187
static herr_t   H5S__hyper_project_scalar(const H5S_t *space, hsize_t *offset);
188
static herr_t   H5S__hyper_project_simple(const H5S_t *space, H5S_t *new_space, hsize_t *offset);
189
static herr_t   H5S__hyper_iter_init(H5S_t *space, H5S_sel_iter_t *iter);
190
191
/* Selection iteration callbacks */
192
static herr_t  H5S__hyper_iter_coords(const H5S_sel_iter_t *iter, hsize_t *coords);
193
static herr_t  H5S__hyper_iter_block(const H5S_sel_iter_t *iter, hsize_t *start, hsize_t *end);
194
static hsize_t H5S__hyper_iter_nelmts(const H5S_sel_iter_t *iter);
195
static htri_t  H5S__hyper_iter_has_next_block(const H5S_sel_iter_t *sel_iter);
196
static herr_t  H5S__hyper_iter_next(H5S_sel_iter_t *sel_iter, size_t nelem);
197
static herr_t  H5S__hyper_iter_next_block(H5S_sel_iter_t *sel_iter);
198
static herr_t H5S__hyper_iter_get_seq_list(H5S_sel_iter_t *iter, size_t maxseq, size_t maxbytes, size_t *nseq,
199
                                           size_t *nbytes, hsize_t *off, size_t *len);
200
static herr_t H5S__hyper_iter_release(H5S_sel_iter_t *sel_iter);
201
202
/*****************************/
203
/* Library Private Variables */
204
/*****************************/
205
206
/*********************/
207
/* Package Variables */
208
/*********************/
209
210
/* Selection properties for hyperslab selections */
211
const H5S_select_class_t H5S_sel_hyper[1] = {{
212
    H5S_SEL_HYPERSLABS,
213
214
    /* Methods on selection */
215
    H5S__hyper_copy,
216
    H5S__hyper_release,
217
    H5S__hyper_is_valid,
218
    H5S__hyper_serial_size,
219
    H5S__hyper_serialize,
220
    H5S__hyper_deserialize,
221
    H5S__hyper_bounds,
222
    H5S__hyper_offset,
223
    H5S__hyper_unlim_dim,
224
    H5S__hyper_num_elem_non_unlim,
225
    H5S__hyper_is_contiguous,
226
    H5S__hyper_is_single,
227
    H5S__hyper_is_regular,
228
    H5S__hyper_shape_same,
229
    H5S__hyper_intersect_block,
230
    H5S__hyper_adjust_u,
231
    H5S__hyper_adjust_s,
232
    H5S__hyper_project_scalar,
233
    H5S__hyper_project_simple,
234
    H5S__hyper_iter_init,
235
}};
236
237
/* Format version bounds for dataspace hyperslab selection */
238
static const unsigned H5O_sds_hyper_ver_bounds[] = {
239
    H5S_HYPER_VERSION_1, /* H5F_LIBVER_EARLIEST */
240
    H5S_HYPER_VERSION_1, /* H5F_LIBVER_V18 */
241
    H5S_HYPER_VERSION_2, /* H5F_LIBVER_V110 */
242
    H5S_HYPER_VERSION_3, /* H5F_LIBVER_V112 */
243
    H5S_HYPER_VERSION_3, /* H5F_LIBVER_V114 */
244
    H5S_HYPER_VERSION_3, /* H5F_LIBVER_V200 */
245
    H5S_HYPER_VERSION_3  /* H5F_LIBVER_LATEST */
246
};
247
248
/*******************/
249
/* Local Variables */
250
/*******************/
251
252
/* Iteration properties for hyperslab selections */
253
static const H5S_sel_iter_class_t H5S_sel_iter_hyper[1] = {{
254
    H5S_SEL_HYPERSLABS,
255
256
    /* Methods on selection iterator */
257
    H5S__hyper_iter_coords,
258
    H5S__hyper_iter_block,
259
    H5S__hyper_iter_nelmts,
260
    H5S__hyper_iter_has_next_block,
261
    H5S__hyper_iter_next,
262
    H5S__hyper_iter_next_block,
263
    H5S__hyper_iter_get_seq_list,
264
    H5S__hyper_iter_release,
265
}};
266
267
/* Arrays for default stride, block, etc. */
268
static const hsize_t H5S_hyper_zeros_g[H5S_MAX_RANK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
269
                                                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
270
static const hsize_t H5S_hyper_ones_g[H5S_MAX_RANK]  = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
271
                                                        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
272
273
/* Declare a free list to manage the H5S_hyper_sel_t struct */
274
H5FL_DEFINE_STATIC(H5S_hyper_sel_t);
275
276
/* Declare a free list to manage the H5S_hyper_span_t struct */
277
H5FL_DEFINE_STATIC(H5S_hyper_span_t);
278
279
/* Declare a free list to manage the H5S_hyper_span_info_t + hsize_t array struct */
280
H5FL_BARR_DEFINE_STATIC(H5S_hyper_span_info_t, hbounds_t, H5S_MAX_RANK * 2);
281
282
/* Declare extern free list to manage the H5S_sel_iter_t struct */
283
H5FL_EXTERN(H5S_sel_iter_t);
284
285
/* Current operation generation */
286
/* (Start with '1' to avoid clashing with '0' value in newly allocated structs) */
287
static uint64_t H5S_hyper_op_gen_g = 1;
288
289
/* Uncomment this to provide the debugging routines for printing selection info */
290
/* #define H5S_HYPER_DEBUG */
291
#ifdef H5S_HYPER_DEBUG
292
static herr_t
293
H5S__hyper_print_spans_helper(FILE *f, const H5S_hyper_span_t *span, unsigned depth)
294
{
295
    FUNC_ENTER_PACKAGE_NOERR
296
297
    while (span) {
298
        fprintf(f, "%s: %*sdepth=%u, span=%p, (%" PRIuHSIZE ", %" PRIuHSIZE "), next=%p\n", __func__,
299
                depth * 2, "", depth, (void *)span, span->low, span->high, (void *)span->next);
300
        if (span->down) {
301
            fprintf(f, "%s: %*sspans=%p, count=%u, bounds[0]={%" PRIuHSIZE ", %" PRIuHSIZE "}, head=%p\n",
302
                    __func__, (depth + 1) * 2, "", (void *)span->down, span->down->count,
303
                    span->down->low_bounds[0], span->down->high_bounds[0], (void *)span->down->head);
304
            H5S__hyper_print_spans_helper(f, span->down->head, depth + 1);
305
        } /* end if */
306
        span = span->next;
307
    } /* end while */
308
309
    FUNC_LEAVE_NOAPI(SUCCEED)
310
}
311
312
static herr_t
313
H5S__hyper_print_spans(FILE *f, const H5S_hyper_span_info_t *span_lst)
314
{
315
    FUNC_ENTER_PACKAGE_NOERR
316
317
    if (span_lst != NULL) {
318
        fprintf(f, "%s: spans=%p, count=%u, bounds[0]={%" PRIuHSIZE ", %" PRIuHSIZE "}, head=%p\n", __func__,
319
                (void *)span_lst, span_lst->count, span_lst->low_bounds[0], span_lst->high_bounds[0],
320
                (void *)span_lst->head);
321
        H5S__hyper_print_spans_helper(f, span_lst->head, 0);
322
    } /* end if */
323
324
    FUNC_LEAVE_NOAPI(SUCCEED)
325
}
326
327
static herr_t
328
H5S__space_print_spans(FILE *f, const H5S_t *space)
329
{
330
    FUNC_ENTER_PACKAGE_NOERR
331
332
    H5S__hyper_print_spans(f, space->select.sel_info.hslab->span_lst);
333
334
    FUNC_LEAVE_NOAPI(SUCCEED)
335
}
336
337
static herr_t
338
H5S__hyper_print_diminfo_helper(FILE *f, const char *field, unsigned ndims, const H5S_hyper_dim_t *dinfo)
339
{
340
    unsigned u; /* Local index variable */
341
342
    FUNC_ENTER_PACKAGE_NOERR
343
344
    if (dinfo != NULL) {
345
        fprintf(f, "%s: %s: start=[", __func__, field);
346
        for (u = 0; u < ndims; u++)
347
            fprintf(f, "%" PRIuHSIZE "%s", dinfo[u].start, (u < (ndims - 1) ? ", " : "]\n"));
348
        fprintf(f, "%s: %s: stride=[", __func__, field);
349
        for (u = 0; u < ndims; u++)
350
            fprintf(f, "%" PRIuHSIZE "%s", dinfo[u].stride, (u < (ndims - 1) ? ", " : "]\n"));
351
        fprintf(f, "%s: %s: count=[", __func__, field);
352
        for (u = 0; u < ndims; u++)
353
            fprintf(f, "%" PRIuHSIZE "%s", dinfo[u].count, (u < (ndims - 1) ? ", " : "]\n"));
354
        fprintf(f, "%s: %s: block=[", __func__, field);
355
        for (u = 0; u < ndims; u++)
356
            fprintf(f, "%" PRIuHSIZE "%s", dinfo[u].block, (u < (ndims - 1) ? ", " : "]\n"));
357
    } /* end if */
358
    else
359
        fprintf(f, "%s: %s==NULL\n", __func__, field);
360
361
    FUNC_LEAVE_NOAPI(SUCCEED)
362
}
363
364
static herr_t
365
H5S__hyper_print_diminfo(FILE *f, const H5S_t *space)
366
{
367
    FUNC_ENTER_PACKAGE_NOERR
368
369
    H5S__hyper_print_diminfo_helper(f, "diminfo.opt", space->extent.rank,
370
                                    space->select.sel_info.hslab->diminfo.opt);
371
    H5S__hyper_print_diminfo_helper(f, "diminfo.app", space->extent.rank,
372
                                    space->select.sel_info.hslab->diminfo.app);
373
374
    FUNC_LEAVE_NOAPI(SUCCEED)
375
}
376
377
/*--------------------------------------------------------------------------
378
 NAME
379
    H5S__hyper_print_spans_dfs
380
 PURPOSE
381
    Output the span elements for one span list in depth-first order
382
 USAGE
383
    herr_t H5S__hyper_print_spans_dfs(f, span_lst, depth)
384
        FILE *f;                                  IN: the file to output
385
        const H5S_hyper_span_info_t *span_lst;    IN: the span list to output
386
        unsigned depth;                           IN: the level of this span list
387
 RETURNS
388
    non-negative on success, negative on failure
389
 GLOBAL VARIABLES
390
 COMMENTS, BUGS, ASSUMPTIONS
391
 EXAMPLES
392
 REVISION LOG
393
--------------------------------------------------------------------------*/
394
static herr_t
395
H5S__hyper_print_spans_dfs(FILE *f, const H5S_hyper_span_info_t *span_lst, unsigned depth, unsigned dims)
396
{
397
    H5S_hyper_span_t *actual_tail = NULL;
398
    H5S_hyper_span_t *cur_elem;
399
    unsigned          num_elems = 0;
400
    unsigned          u, elem_idx;
401
402
    FUNC_ENTER_PACKAGE_NOERR
403
404
    /* get the actual tail from head */
405
    cur_elem = span_lst->head;
406
    assert(cur_elem); /* at least 1 element */
407
    while (cur_elem) {
408
        actual_tail = cur_elem;
409
        cur_elem    = cur_elem->next;
410
        num_elems++;
411
    } /* end while */
412
413
    for (u = 0; u < depth; u++)
414
        fprintf(f, "\t");
415
    fprintf(f, "DIM[%u]: ref_count=%u, #elems=%u, head=%p, tail=%p, actual_tail=%p, matched=%d\n", depth,
416
            span_lst->count, num_elems, (void *)span_lst->head, (void *)span_lst->tail, (void *)actual_tail,
417
            (span_lst->tail == actual_tail));
418
419
    for (u = 0; u < depth; u++)
420
        fprintf(f, "\t");
421
    fprintf(f, "low_bounds=[");
422
    for (u = 0; u < dims - 1; u++)
423
        fprintf(f, "%" PRIuHSIZE ",", span_lst->low_bounds[u]);
424
    fprintf(f, "%" PRIuHSIZE "]\n", span_lst->low_bounds[dims - 1]);
425
426
    for (u = 0; u < depth; u++)
427
        fprintf(f, "\t");
428
    fprintf(f, "high_bounds=[");
429
    for (u = 0; u < dims - 1; u++)
430
        fprintf(f, "%" PRIuHSIZE ",", span_lst->high_bounds[u]);
431
    fprintf(f, "%" PRIuHSIZE "]\n", span_lst->high_bounds[dims - 1]);
432
433
    cur_elem = span_lst->head;
434
    elem_idx = 0;
435
    while (cur_elem) {
436
        for (u = 0; u < depth; u++)
437
            fprintf(f, "\t");
438
        fprintf(f, "ELEM[%u]: ptr=%p, low=%" PRIuHSIZE ", high=%" PRIuHSIZE ", down=%p\n", elem_idx++,
439
                (void *)cur_elem, cur_elem->low, cur_elem->high, (void *)cur_elem->down);
440
        if (cur_elem->down)
441
            H5S__hyper_print_spans_dfs(f, cur_elem->down, depth + 1, dims);
442
        cur_elem = cur_elem->next;
443
    } /* end while */
444
445
    FUNC_LEAVE_NOAPI(SUCCEED)
446
} /* end H5S__hyper_print_spans_dfs() */
447
448
/*--------------------------------------------------------------------------
449
 NAME
450
    H5S__hyper_print_space_dfs
451
 PURPOSE
452
    Output the span elements for one hyperslab selection space in depth-first order
453
 USAGE
454
    herr_t H5S__hyper_print_space_dfs(f, space)
455
        FILE *f;               IN: the file to output
456
        const H5S_t *space;    IN: the selection space to output
457
 RETURNS
458
    non-negative on success, negative on failure
459
 GLOBAL VARIABLES
460
 COMMENTS, BUGS, ASSUMPTIONS
461
 EXAMPLES
462
 REVISION LOG
463
--------------------------------------------------------------------------*/
464
static herr_t
465
H5S__hyper_print_space_dfs(FILE *f, const H5S_t *space)
466
{
467
    const H5S_hyper_sel_t *hslab = space->select.sel_info.hslab;
468
    const unsigned         dims  = space->extent.rank;
469
    unsigned               u;
470
471
    FUNC_ENTER_PACKAGE_NOERR
472
473
    assert(hslab);
474
475
    fprintf(f, "=======================\n");
476
    fprintf(f, "SPACE: span_lst=%p, #dims=%u, offset_changed=%d\n", (void *)hslab->span_lst, dims,
477
            space->select.offset_changed);
478
479
    fprintf(f, "       offset=[");
480
    for (u = 0; u < dims - 1; u++)
481
        fprintf(f, "%lld,", space->select.offset[u]);
482
    fprintf(f, "%lld]\n", space->select.offset[dims - 1]);
483
484
    fprintf(f, "       low_bounds=[");
485
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
486
        for (u = 0; u < dims - 1; u++)
487
            fprintf(f, "%" PRIuHSIZE ",", space->select.sel_info.hslab->diminfo.low_bounds[u]);
488
        fprintf(f, "%" PRIuHSIZE "]\n", space->select.sel_info.hslab->diminfo.low_bounds[dims - 1]);
489
    } /* end if */
490
    else {
491
        for (u = 0; u < dims - 1; u++)
492
            fprintf(f, "%" PRIuHSIZE ",", space->select.sel_info.hslab->span_lst->low_bounds[u]);
493
        fprintf(f, "%" PRIuHSIZE "]\n", space->select.sel_info.hslab->span_lst->low_bounds[dims - 1]);
494
    } /* end else */
495
496
    fprintf(f, "       high_bounds=[");
497
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
498
        for (u = 0; u < dims - 1; u++)
499
            fprintf(f, "%" PRIuHSIZE ",", space->select.sel_info.hslab->diminfo.high_bounds[u]);
500
        fprintf(f, "%" PRIuHSIZE "]\n", space->select.sel_info.hslab->diminfo.high_bounds[dims - 1]);
501
    } /* end if */
502
    else {
503
        for (u = 0; u < dims - 1; u++)
504
            fprintf(f, "%" PRIuHSIZE ",", space->select.sel_info.hslab->span_lst->high_bounds[u]);
505
        fprintf(f, "%" PRIuHSIZE "]\n", space->select.sel_info.hslab->span_lst->high_bounds[dims - 1]);
506
    } /* end else */
507
508
    /* Print out diminfo, if it's valid */
509
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES)
510
        H5S__hyper_print_diminfo(f, space);
511
512
    /* Start print out the highest-order of dimension */
513
    if (hslab->span_lst)
514
        H5S__hyper_print_spans_dfs(f, hslab->span_lst, 0, dims);
515
    fprintf(f, "=======================\n\n");
516
517
    FUNC_LEAVE_NOAPI(SUCCEED)
518
} /* end H5S__hyper_print_space_dfs() */
519
#endif /* H5S_HYPER_DEBUG */
520
521
/*-------------------------------------------------------------------------
522
 * Function:    H5S__hyper_get_op_gen
523
 *
524
 * Purpose:    Acquire a unique operation generation value
525
 *
526
 * Return:    Operation generation value (can't fail)
527
 *
528
 * Notes:       Assumes that a 64-bit value will not wrap around during
529
 *              the lifespan of the process.
530
 *
531
 *-------------------------------------------------------------------------
532
 */
533
uint64_t
534
H5S__hyper_get_op_gen(void)
535
0
{
536
0
    FUNC_ENTER_PACKAGE_NOERR
537
538
0
    FUNC_LEAVE_NOAPI(H5S_hyper_op_gen_g++)
539
0
} /* end H5S__hyper_op_gen() */
540
541
/*-------------------------------------------------------------------------
542
 * Function:    H5S__hyper_iter_init
543
 *
544
 * Purpose:     Initializes iteration information for hyperslab selection.
545
 *
546
 * Return:      Non-negative on success, negative on failure.
547
 *
548
 * Notes:       If the 'iter->elmt_size' field is set to zero, the regular
549
 *              hyperslab selection iterator will not be 'flattened'.  This
550
 *              is used by the H5S_select_shape_same() code to avoid changing
551
 *              the rank and appearance of the selection.
552
 *
553
 *-------------------------------------------------------------------------
554
 */
555
static herr_t
556
H5S__hyper_iter_init(H5S_t *space, H5S_sel_iter_t *iter)
557
0
{
558
0
    hsize_t *slab_size;           /* Pointer to the dataspace dimensions to use for calc. slab */
559
0
    hsize_t  acc;                 /* Accumulator for computing cumulative sizes */
560
0
    unsigned slab_dim;            /* Rank of the fastest changing dimension for calc. slab */
561
0
    unsigned rank;                /* Dataspace's dimension rank */
562
0
    unsigned u;                   /* Index variable */
563
0
    int      i;                   /* Index variable */
564
0
    herr_t   ret_value = SUCCEED; /* return value */
565
566
0
    FUNC_ENTER_PACKAGE
567
568
    /* Check args */
569
0
    assert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space));
570
0
    assert(iter);
571
0
    assert(space->select.sel_info.hslab->unlim_dim < 0);
572
573
    /* Initialize the hyperslab iterator's rank */
574
0
    iter->u.hyp.iter_rank = 0;
575
576
    /* Get the rank of the dataspace */
577
0
    rank = iter->rank;
578
579
    /* Attempt to rebuild diminfo if it is invalid and has not been confirmed
580
     * to be impossible.
581
     */
582
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO)
583
0
        H5S__hyper_rebuild(space);
584
585
    /* Check for the special case of just one H5Sselect_hyperslab call made */
586
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
587
        /* Initialize the information needed for regular hyperslab I/O */
588
0
        const H5S_hyper_dim_t *tdiminfo;     /* Temporary pointer to diminfo information */
589
0
        const hsize_t         *mem_size;     /* Temporary pointer to dataspace extent's dimension sizes */
590
0
        unsigned               cont_dim = 0; /* # of contiguous dimensions */
591
592
        /* Set the temporary pointer to the dimension information */
593
0
        tdiminfo = space->select.sel_info.hslab->diminfo.opt;
594
595
        /* Set the temporary pointer to the dataspace extent's dimension sizes */
596
0
        mem_size = iter->dims;
597
598
        /*
599
         * For a regular hyperslab to be contiguous up to some dimension, it
600
         * must have only one block (i.e. count==1 in all dimensions up to that
601
         * dimension) and the block size must be the same as the dataspace's
602
         * extent in that dimension and all dimensions up to that dimension.
603
         */
604
605
        /* Don't flatten adjacent elements into contiguous block if the
606
         * element size is 0.  This is for the H5S_select_shape_same() code.
607
         */
608
0
        if (iter->elmt_size > 0) {
609
            /* Check for any "contiguous" blocks that can be flattened */
610
0
            for (u = (rank - 1); u > 0; u--) {
611
0
                if (tdiminfo[u].count == 1 && tdiminfo[u].block == mem_size[u]) {
612
0
                    cont_dim++;
613
0
                    iter->u.hyp.flattened[u] = true;
614
0
                } /* end if */
615
0
                else
616
0
                    iter->u.hyp.flattened[u] = false;
617
0
            } /* end for */
618
0
            iter->u.hyp.flattened[0] = false;
619
0
        } /* end if */
620
621
        /* Check if the regular selection can be "flattened" */
622
0
        if (cont_dim > 0) {
623
0
            bool     last_dim_flattened = true; /* Flag to indicate that the last dimension was flattened */
624
0
            unsigned flat_rank          = rank - cont_dim; /* Number of dimensions after flattening */
625
0
            unsigned curr_dim;                             /* Current dimension */
626
627
            /* Set the iterator's rank to the contiguous dimensions */
628
0
            iter->u.hyp.iter_rank = flat_rank;
629
630
            /* "Flatten" dataspace extent and selection information */
631
0
            curr_dim = flat_rank - 1;
632
0
            for (i = (int)rank - 1, acc = 1; i >= 0; i--) {
633
0
                if (tdiminfo[i].block == mem_size[i] && i > 0) {
634
                    /* "Flatten" this dimension */
635
0
                    assert(tdiminfo[i].start == 0);
636
0
                    acc *= mem_size[i];
637
638
                    /* Indicate that the dimension was flattened */
639
0
                    last_dim_flattened = true;
640
0
                } /* end if */
641
0
                else {
642
0
                    if (last_dim_flattened) {
643
                        /* First dimension after flattened dimensions */
644
0
                        iter->u.hyp.diminfo[curr_dim].start = tdiminfo[i].start * acc;
645
646
                        /* Special case for single block regular selections */
647
0
                        if (tdiminfo[i].count == 1)
648
0
                            iter->u.hyp.diminfo[curr_dim].stride = 1;
649
0
                        else
650
0
                            iter->u.hyp.diminfo[curr_dim].stride = tdiminfo[i].stride * acc;
651
0
                        iter->u.hyp.diminfo[curr_dim].count = tdiminfo[i].count;
652
0
                        iter->u.hyp.diminfo[curr_dim].block = tdiminfo[i].block * acc;
653
0
                        iter->u.hyp.size[curr_dim]          = mem_size[i] * acc;
654
0
                        iter->u.hyp.sel_off[curr_dim]       = iter->sel_off[i] * (hssize_t)acc;
655
656
                        /* Reset the "last dim flattened" flag to avoid flattened any further dimensions */
657
0
                        last_dim_flattened = false;
658
659
                        /* Reset the "accumulator" for possible further dimension flattening */
660
0
                        acc = 1;
661
0
                    } /* end if */
662
0
                    else {
663
                        /* All other dimensions */
664
0
                        iter->u.hyp.diminfo[curr_dim].start  = tdiminfo[i].start;
665
0
                        iter->u.hyp.diminfo[curr_dim].stride = tdiminfo[i].stride;
666
0
                        iter->u.hyp.diminfo[curr_dim].count  = tdiminfo[i].count;
667
0
                        iter->u.hyp.diminfo[curr_dim].block  = tdiminfo[i].block;
668
0
                        iter->u.hyp.size[curr_dim]           = mem_size[i];
669
0
                        iter->u.hyp.sel_off[curr_dim]        = iter->sel_off[i];
670
0
                    } /* end else */
671
672
                    /* Decrement "current" flattened dimension */
673
0
                    curr_dim--;
674
0
                } /* end if */
675
0
            }     /* end for */
676
677
            /* Initialize "flattened" iterator offset to initial location and dataspace extent and selection
678
             * information to correct values */
679
0
            for (u = 0; u < flat_rank; u++)
680
0
                iter->u.hyp.off[u] = iter->u.hyp.diminfo[u].start;
681
682
            /* Set up information for computing slab sizes */
683
0
            slab_dim  = iter->u.hyp.iter_rank - 1;
684
0
            slab_size = iter->u.hyp.size;
685
0
        } /* end if */
686
0
        else {
687
            /* Make local copy of the regular selection information */
688
0
            HDcompile_assert(sizeof(iter->u.hyp.diminfo) ==
689
0
                             sizeof(space->select.sel_info.hslab->diminfo.opt));
690
0
            H5MM_memcpy(iter->u.hyp.diminfo, tdiminfo, sizeof(iter->u.hyp.diminfo));
691
692
            /* Initialize position to initial location */
693
0
            for (u = 0; u < rank; u++)
694
0
                iter->u.hyp.off[u] = tdiminfo[u].start;
695
696
            /* Set up information for computing slab sizes */
697
0
            slab_dim  = iter->rank - 1;
698
0
            slab_size = iter->dims;
699
0
        } /* end else */
700
701
        /* Flag the diminfo information as valid in the iterator */
702
0
        iter->u.hyp.diminfo_valid = true;
703
704
        /* Initialize irregular region information also (for release) */
705
0
        iter->u.hyp.spans = NULL;
706
0
    }                                 /* end if */
707
0
    else {                            /* Initialize the information needed for non-regular hyperslab I/O */
708
0
        H5S_hyper_span_info_t *spans; /* Pointer to hyperslab span info node */
709
710
        /* If this iterator is created from an API call, by default we clone the
711
         *  selection now, as the dataspace could be modified or go out of scope.
712
         *
713
         *  However, if the H5S_SEL_ITER_SHARE_WITH_DATASPACE flag is given,
714
         *  the selection is shared between the selection iterator and the
715
         *  dataspace.  In this case, the application _must_not_ modify or
716
         *  close the dataspace that the iterator is operating on, or undefined
717
         *  behavior will occur.
718
         */
719
0
        if ((iter->flags & H5S_SEL_ITER_API_CALL) && !(iter->flags & H5S_SEL_ITER_SHARE_WITH_DATASPACE)) {
720
            /* Copy the span tree */
721
0
            if (NULL == (iter->u.hyp.spans = H5S__hyper_copy_span(space->select.sel_info.hslab->span_lst,
722
0
                                                                  space->extent.rank)))
723
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy span tree");
724
0
        } /* end if */
725
0
        else {
726
            /* Share the source dataspace's span tree by incrementing the reference count on it */
727
0
            assert(space->select.sel_info.hslab->span_lst);
728
0
            iter->u.hyp.spans = space->select.sel_info.hslab->span_lst;
729
0
            iter->u.hyp.spans->count++;
730
0
        } /* end else */
731
732
        /* Initialize the starting span_info's and spans */
733
0
        spans = iter->u.hyp.spans;
734
0
        for (u = 0; u < rank; u++) {
735
            /* Set the pointers to the initial span in each dimension */
736
0
            assert(spans);
737
0
            assert(spans->head);
738
739
            /* Set the pointer to the first span in the list for this node */
740
0
            iter->u.hyp.span[u] = spans->head;
741
742
            /* Set the initial offset to low bound of span */
743
0
            iter->u.hyp.off[u] = iter->u.hyp.span[u]->low;
744
745
            /* Get the pointer to the next level down */
746
0
            spans = spans->head->down;
747
0
        } /* end for */
748
749
        /* Set up information for computing slab sizes */
750
0
        slab_dim  = iter->rank - 1;
751
0
        slab_size = iter->dims;
752
753
        /* Flag the diminfo information as not valid in the iterator */
754
0
        iter->u.hyp.diminfo_valid = false;
755
0
    } /* end else */
756
757
    /* Compute the cumulative size of dataspace dimensions */
758
0
    for (i = (int)slab_dim, acc = iter->elmt_size; i >= 0; i--) {
759
0
        iter->u.hyp.slab[i] = acc;
760
0
        acc *= slab_size[i];
761
0
    } /* end for */
762
763
    /* Initialize more information for irregular hyperslab selections */
764
0
    if (!iter->u.hyp.diminfo_valid) {
765
        /* Set the offset of the first element iterated on, in each dimension */
766
0
        for (u = 0; u < rank; u++)
767
            /* Compute the sequential element offset */
768
0
            iter->u.hyp.loc_off[u] =
769
0
                ((hsize_t)((hssize_t)iter->u.hyp.off[u] + iter->sel_off[u])) * iter->u.hyp.slab[u];
770
0
    } /* end if */
771
772
    /* Initialize type of selection iterator */
773
0
    iter->type = H5S_sel_iter_hyper;
774
775
0
done:
776
0
    FUNC_LEAVE_NOAPI(ret_value)
777
0
} /* end H5S__hyper_iter_init() */
778
779
/*-------------------------------------------------------------------------
780
 * Function:    H5S__hyper_iter_coords
781
 *
782
 * Purpose:     Retrieve the current coordinates of iterator for current
783
 *              selection
784
 *
785
 * Return:      Non-negative on success, negative on failure
786
 *
787
 *-------------------------------------------------------------------------
788
 */
789
static herr_t
790
H5S__hyper_iter_coords(const H5S_sel_iter_t *iter, hsize_t *coords)
791
0
{
792
0
    FUNC_ENTER_PACKAGE_NOERR
793
794
    /* Check args */
795
0
    assert(iter);
796
0
    assert(coords);
797
798
    /* Copy the offset of the current point */
799
800
    /* Check for a single "regular" hyperslab */
801
0
    if (iter->u.hyp.diminfo_valid) {
802
        /* Check if this is a "flattened" regular hyperslab selection */
803
0
        if (iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < iter->rank) {
804
0
            int u, v; /* Dimension indices */
805
806
            /* Set the starting rank of both the "natural" & "flattened" dimensions */
807
0
            u = (int)iter->rank - 1;
808
0
            v = (int)iter->u.hyp.iter_rank - 1;
809
810
            /* Construct the "natural" dimensions from a set of flattened coordinates */
811
0
            while (u >= 0) {
812
0
                if (iter->u.hyp.flattened[u]) {
813
0
                    int begin = u; /* The rank of the first flattened dimension */
814
815
                    /* Walk up through as many flattened dimensions as possible */
816
0
                    do {
817
0
                        u--;
818
0
                    } while (u >= 0 && iter->u.hyp.flattened[u]);
819
820
                    /* Compensate for possibly overshooting dim 0 */
821
0
                    if (u < 0)
822
0
                        u = 0;
823
824
                    /* Sanity check */
825
0
                    assert(v >= 0);
826
827
                    /* Compute the coords for the flattened dimensions */
828
0
                    H5VM_array_calc(iter->u.hyp.off[v], (unsigned)((begin - u) + 1), &(iter->dims[u]),
829
0
                                    &(coords[u]));
830
831
                    /* Continue to faster dimension in both indices */
832
0
                    u--;
833
0
                    v--;
834
0
                } /* end if */
835
0
                else {
836
                    /* Walk up through as many non-flattened dimensions as possible */
837
0
                    while (u >= 0 && !iter->u.hyp.flattened[u]) {
838
                        /* Sanity check */
839
0
                        assert(v >= 0);
840
841
                        /* Copy the coordinate */
842
0
                        coords[u] = iter->u.hyp.off[v];
843
844
                        /* Continue to faster dimension in both indices */
845
0
                        u--;
846
0
                        v--;
847
0
                    } /* end while */
848
0
                }     /* end else */
849
0
            }         /* end while */
850
0
            assert(v < 0);
851
0
        } /* end if */
852
0
        else
853
0
            H5MM_memcpy(coords, iter->u.hyp.off, sizeof(hsize_t) * iter->rank);
854
0
    } /* end if */
855
0
    else
856
0
        H5MM_memcpy(coords, iter->u.hyp.off, sizeof(hsize_t) * iter->rank);
857
858
0
    FUNC_LEAVE_NOAPI(SUCCEED)
859
0
} /* end H5S__hyper_iter_coords() */
860
861
/*-------------------------------------------------------------------------
862
 * Function:    H5S__hyper_iter_block
863
 *
864
 * Purpose:     Retrieve the current block of iterator for current
865
 *              selection
866
 *
867
 * Return:      Non-negative on success, negative on failure
868
 *
869
 * Notes:       This routine assumes that the iterator is always located at
870
 *              the beginning of a block.
871
 *
872
 *-------------------------------------------------------------------------
873
 */
874
static herr_t
875
H5S__hyper_iter_block(const H5S_sel_iter_t *iter, hsize_t *start, hsize_t *end)
876
0
{
877
0
    unsigned u; /* Local index variable */
878
879
0
    FUNC_ENTER_PACKAGE_NOERR
880
881
    /* Check args */
882
0
    assert(iter);
883
0
    assert(start);
884
0
    assert(end);
885
886
    /* Copy the offset of the current point */
887
888
    /* Check for a single "regular" hyperslab */
889
0
    if (iter->u.hyp.diminfo_valid) {
890
        /* Copy the start and compute the end of the block */
891
0
        for (u = 0; u < iter->rank; u++) {
892
0
            start[u] = iter->u.hyp.off[u];
893
0
            end[u]   = (start[u] + iter->u.hyp.diminfo[u].block) - 1;
894
0
        }
895
0
    } /* end if */
896
0
    else {
897
        /* Copy the start & end of the block */
898
0
        for (u = 0; u < iter->rank; u++) {
899
0
            start[u] = iter->u.hyp.span[u]->low;
900
0
            end[u]   = iter->u.hyp.span[u]->high;
901
0
        }
902
0
    } /* end else */
903
904
0
    FUNC_LEAVE_NOAPI(SUCCEED)
905
0
} /* end H5S__hyper_iter_block() */
906
907
/*-------------------------------------------------------------------------
908
 * Function:    H5S__hyper_iter_nelmts
909
 *
910
 * Purpose:     Return number of elements left to process in iterator
911
 *
912
 * Return:      Non-negative number of elements on success, zero on failure
913
 *
914
 *-------------------------------------------------------------------------
915
 */
916
static hsize_t
917
H5S__hyper_iter_nelmts(const H5S_sel_iter_t *iter)
918
0
{
919
0
    FUNC_ENTER_PACKAGE_NOERR
920
921
    /* Check args */
922
0
    assert(iter);
923
924
0
    FUNC_LEAVE_NOAPI(iter->elmt_left)
925
0
} /* end H5S__hyper_iter_nelmts() */
926
927
/*--------------------------------------------------------------------------
928
 NAME
929
    H5S__hyper_iter_has_next_block
930
 PURPOSE
931
    Check if there is another block left in the current iterator
932
 USAGE
933
    htri_t H5S__hyper_iter_has_next_block(iter)
934
        const H5S_sel_iter_t *iter;       IN: Pointer to selection iterator
935
 RETURNS
936
    Non-negative (true/false) on success/Negative on failure
937
 DESCRIPTION
938
    Check if there is another block available in the selection iterator.
939
 GLOBAL VARIABLES
940
 COMMENTS, BUGS, ASSUMPTIONS
941
 EXAMPLES
942
 REVISION LOG
943
--------------------------------------------------------------------------*/
944
static H5_ATTR_PURE htri_t
945
H5S__hyper_iter_has_next_block(const H5S_sel_iter_t *iter)
946
0
{
947
0
    unsigned u;                 /* Local index variable */
948
0
    htri_t   ret_value = false; /* Return value */
949
950
0
    FUNC_ENTER_PACKAGE_NOERR
951
952
    /* Check args */
953
0
    assert(iter);
954
955
    /* Check for a single "regular" hyperslab */
956
0
    if (iter->u.hyp.diminfo_valid) {
957
0
        const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */
958
0
        const hsize_t         *toff;     /* Temporary offset in selection */
959
960
        /* Check if the offset of the iterator is at the last location in all dimensions */
961
0
        tdiminfo = iter->u.hyp.diminfo;
962
0
        toff     = iter->u.hyp.off;
963
0
        for (u = 0; u < iter->rank; u++) {
964
            /* If there is only one block, continue */
965
0
            if (tdiminfo[u].count == 1)
966
0
                continue;
967
0
            if (toff[u] != (tdiminfo[u].start + ((tdiminfo[u].count - 1) * tdiminfo[u].stride)))
968
0
                HGOTO_DONE(true);
969
0
        } /* end for */
970
0
    }     /* end if */
971
0
    else {
972
        /* Check for any levels of the tree with more sequences in them */
973
0
        for (u = 0; u < iter->rank; u++)
974
0
            if (iter->u.hyp.span[u]->next != NULL)
975
0
                HGOTO_DONE(true);
976
0
    } /* end else */
977
978
0
done:
979
0
    FUNC_LEAVE_NOAPI(ret_value)
980
0
} /* end H5S__hyper_iter_has_next_block() */
981
982
/*-------------------------------------------------------------------------
983
 * Function:    H5S__hyper_iter_next
984
 *
985
 * Purpose:     Moves a hyperslab iterator to the beginning of the next sequence
986
 *              of elements to read.  Handles walking off the end in all dimensions.
987
 *
988
 * Return:      Success:    non-negative
989
 *              Failure:    negative
990
 *
991
 *-------------------------------------------------------------------------
992
 */
993
static herr_t
994
H5S__hyper_iter_next(H5S_sel_iter_t *iter, size_t nelem)
995
0
{
996
0
    unsigned ndims;    /* Number of dimensions of dataset */
997
0
    int      fast_dim; /* Rank of the fastest changing dimension for the dataspace */
998
0
    unsigned u;        /* Counters */
999
1000
0
    FUNC_ENTER_PACKAGE_NOERR
1001
1002
    /* Check for the special case of just one H5Sselect_hyperslab call made */
1003
    /* (i.e. a regular hyperslab selection */
1004
0
    if (iter->u.hyp.diminfo_valid) {
1005
0
        const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */
1006
0
        hsize_t                iter_offset[H5S_MAX_RANK];
1007
0
        hsize_t                iter_count[H5S_MAX_RANK];
1008
0
        int                    temp_dim; /* Temporary rank holder */
1009
1010
        /* Check if this is a "flattened" regular hyperslab selection */
1011
0
        if (iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < iter->rank)
1012
            /* Set the aliases for the dimension rank */
1013
0
            ndims = iter->u.hyp.iter_rank;
1014
0
        else
1015
            /* Set the aliases for the dimension rank */
1016
0
            ndims = iter->rank;
1017
1018
        /* Set the fastest dimension rank */
1019
0
        fast_dim = (int)ndims - 1;
1020
1021
        /* Set the local copy of the diminfo pointer */
1022
0
        tdiminfo = iter->u.hyp.diminfo;
1023
1024
        /* Calculate the offset and block count for each dimension */
1025
0
        for (u = 0; u < ndims; u++) {
1026
0
            if (tdiminfo[u].count == 1) {
1027
0
                iter_offset[u] = iter->u.hyp.off[u] - tdiminfo[u].start;
1028
0
                iter_count[u]  = 0;
1029
0
            } /* end if */
1030
0
            else {
1031
0
                iter_offset[u] = (iter->u.hyp.off[u] - tdiminfo[u].start) % tdiminfo[u].stride;
1032
0
                iter_count[u]  = (iter->u.hyp.off[u] - tdiminfo[u].start) / tdiminfo[u].stride;
1033
0
            } /* end else */
1034
0
        }     /* end for */
1035
1036
        /* Loop through, advancing the offset & counts, until all the nelements are accounted for */
1037
0
        while (nelem > 0) {
1038
            /* Start with the fastest changing dimension */
1039
0
            temp_dim = fast_dim;
1040
0
            while (temp_dim >= 0) {
1041
0
                if (temp_dim == fast_dim) {
1042
0
                    size_t  actual_elem; /* Actual # of elements advanced on each iteration through loop */
1043
0
                    hsize_t block_elem;  /* Number of elements left in a block */
1044
1045
                    /* Compute the number of elements left in block */
1046
0
                    block_elem = tdiminfo[temp_dim].block - iter_offset[temp_dim];
1047
1048
                    /* Compute the number of actual elements to advance */
1049
0
                    actual_elem = (size_t)MIN(nelem, block_elem);
1050
1051
                    /* Move the iterator over as many elements as possible */
1052
0
                    iter_offset[temp_dim] += actual_elem;
1053
1054
                    /* Decrement the number of elements advanced */
1055
0
                    nelem -= actual_elem;
1056
0
                } /* end if */
1057
0
                else
1058
                    /* Move to the next row in the current dimension */
1059
0
                    iter_offset[temp_dim]++;
1060
1061
                /* If this block is still in the range of blocks to output for the dimension, break out of
1062
                 * loop */
1063
0
                if (iter_offset[temp_dim] < tdiminfo[temp_dim].block)
1064
0
                    break;
1065
0
                else {
1066
                    /* Move to the next block in the current dimension */
1067
0
                    iter_offset[temp_dim] = 0;
1068
0
                    iter_count[temp_dim]++;
1069
1070
                    /* If this block is still in the range of blocks to output for the dimension, break out of
1071
                     * loop */
1072
0
                    if (iter_count[temp_dim] < tdiminfo[temp_dim].count)
1073
0
                        break;
1074
0
                    else
1075
0
                        iter_count[temp_dim] = 0; /* reset back to the beginning of the line */
1076
0
                }                                 /* end else */
1077
1078
                /* Decrement dimension count */
1079
0
                temp_dim--;
1080
0
            } /* end while */
1081
0
        }     /* end while */
1082
1083
        /* Translate current iter_offset and iter_count into iterator position */
1084
0
        for (u = 0; u < ndims; u++)
1085
0
            iter->u.hyp.off[u] = tdiminfo[u].start + (tdiminfo[u].stride * iter_count[u]) + iter_offset[u];
1086
0
    } /* end if */
1087
    /* Must be an irregular hyperslab selection */
1088
0
    else {
1089
0
        H5S_hyper_span_t  *curr_span = NULL; /* Current hyperslab span node */
1090
0
        H5S_hyper_span_t **ispan;            /* Iterator's hyperslab span nodes */
1091
0
        hsize_t           *abs_arr;          /* Absolute hyperslab span position */
1092
0
        int                curr_dim;         /* Temporary rank holder */
1093
1094
        /* Set the rank of the fastest changing dimension */
1095
0
        ndims    = iter->rank;
1096
0
        fast_dim = (int)ndims - 1;
1097
1098
        /* Get the pointers to the current span info and span nodes */
1099
0
        abs_arr = iter->u.hyp.off;
1100
0
        ispan   = iter->u.hyp.span;
1101
1102
        /* Loop through, advancing the span information, until all the nelements are accounted for */
1103
0
        while (nelem > 0) {
1104
            /* Start at the fastest dim */
1105
0
            curr_dim = fast_dim;
1106
1107
            /* Work back up through the dimensions */
1108
0
            while (curr_dim >= 0) {
1109
                /* Reset the current span */
1110
0
                curr_span = ispan[curr_dim];
1111
1112
                /* Increment absolute position */
1113
0
                if (curr_dim == fast_dim) {
1114
0
                    size_t  actual_elem; /* Actual # of elements advanced on each iteration through loop */
1115
0
                    hsize_t span_elem;   /* Number of elements left in a span */
1116
1117
                    /* Compute the number of elements left in block */
1118
0
                    span_elem = (curr_span->high - abs_arr[curr_dim]) + 1;
1119
1120
                    /* Compute the number of actual elements to advance */
1121
0
                    actual_elem = (size_t)MIN(nelem, span_elem);
1122
1123
                    /* Move the iterator over as many elements as possible */
1124
0
                    abs_arr[curr_dim] += actual_elem;
1125
1126
                    /* Decrement the number of elements advanced */
1127
0
                    nelem -= actual_elem;
1128
0
                } /* end if */
1129
0
                else
1130
                    /* Move to the next row in the current dimension */
1131
0
                    abs_arr[curr_dim]++;
1132
1133
                /* Check if we are still within the span */
1134
0
                if (abs_arr[curr_dim] <= curr_span->high)
1135
0
                    break;
1136
                /* If we walked off that span, advance to the next span */
1137
0
                else {
1138
                    /* Advance span in this dimension */
1139
0
                    curr_span = curr_span->next;
1140
1141
                    /* Check if we have a valid span in this dimension still */
1142
0
                    if (curr_span != NULL) {
1143
                        /* Reset the span in the current dimension */
1144
0
                        ispan[curr_dim] = curr_span;
1145
1146
                        /* Reset absolute position */
1147
0
                        abs_arr[curr_dim] = curr_span->low;
1148
1149
0
                        break;
1150
0
                    } /* end if */
1151
0
                    else
1152
                        /* If we finished the span list in this dimension, decrement the dimension worked on
1153
                         * and loop again */
1154
0
                        curr_dim--;
1155
0
                } /* end else */
1156
0
            }     /* end while */
1157
1158
            /* Check if we are finished with the spans in the tree */
1159
0
            if (curr_dim >= 0) {
1160
                /* Walk back down the iterator positions, resetting them */
1161
0
                while (curr_dim < fast_dim) {
1162
0
                    assert(curr_span);
1163
0
                    assert(curr_span->down);
1164
0
                    assert(curr_span->down->head);
1165
1166
                    /* Increment current dimension */
1167
0
                    curr_dim++;
1168
1169
                    /* Set the new span_info & span for this dimension */
1170
0
                    ispan[curr_dim] = curr_span->down->head;
1171
1172
                    /* Advance span down the tree */
1173
0
                    curr_span = curr_span->down->head;
1174
1175
                    /* Reset the absolute offset for the dim */
1176
0
                    abs_arr[curr_dim] = curr_span->low;
1177
0
                } /* end while */
1178
1179
                /* Verify that the curr_span points to the fastest dim */
1180
0
                assert(curr_span == ispan[fast_dim]);
1181
0
            } /* end if */
1182
0
        }     /* end while */
1183
0
    }         /* end else */
1184
1185
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1186
0
} /* end H5S__hyper_iter_next() */
1187
1188
/*-------------------------------------------------------------------------
1189
 * Function:    H5S__hyper_iter_next_block
1190
 *
1191
 * Purpose:     Moves a hyperslab iterator to the beginning of the next sequence
1192
 *              of elements to read.  Handles walking off the end in all dimensions.
1193
 *
1194
 * Return:      Success:    non-negative
1195
 *              Failure:    negative
1196
 *
1197
 *-------------------------------------------------------------------------
1198
 */
1199
static herr_t
1200
H5S__hyper_iter_next_block(H5S_sel_iter_t *iter)
1201
0
{
1202
0
    unsigned ndims;    /* Number of dimensions of dataset */
1203
0
    int      fast_dim; /* Rank of the fastest changing dimension for the dataspace */
1204
0
    unsigned u;        /* Counters */
1205
1206
0
    FUNC_ENTER_PACKAGE_NOERR
1207
1208
    /* Check for the special case of just one H5Sselect_hyperslab call made */
1209
    /* (i.e. a regular hyperslab selection) */
1210
0
    if (iter->u.hyp.diminfo_valid) {
1211
0
        const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */
1212
0
        hsize_t                iter_offset[H5S_MAX_RANK];
1213
0
        hsize_t                iter_count[H5S_MAX_RANK];
1214
0
        int                    temp_dim; /* Temporary rank holder */
1215
1216
        /* Check if this is a "flattened" regular hyperslab selection */
1217
0
        if (iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < iter->rank)
1218
            /* Set the aliases for the dimension rank */
1219
0
            ndims = iter->u.hyp.iter_rank;
1220
0
        else
1221
            /* Set the aliases for the dimension rank */
1222
0
            ndims = iter->rank;
1223
1224
        /* Set the fastest dimension rank */
1225
0
        fast_dim = (int)ndims - 1;
1226
1227
        /* Set the local copy of the diminfo pointer */
1228
0
        tdiminfo = iter->u.hyp.diminfo;
1229
1230
        /* Calculate the offset and block count for each dimension */
1231
0
        for (u = 0; u < ndims; u++) {
1232
0
            if (tdiminfo[u].count == 1) {
1233
0
                iter_offset[u] = iter->u.hyp.off[u] - tdiminfo[u].start;
1234
0
                iter_count[u]  = 0;
1235
0
            } /* end if */
1236
0
            else {
1237
0
                iter_offset[u] = (iter->u.hyp.off[u] - tdiminfo[u].start) % tdiminfo[u].stride;
1238
0
                iter_count[u]  = (iter->u.hyp.off[u] - tdiminfo[u].start) / tdiminfo[u].stride;
1239
0
            } /* end else */
1240
0
        }     /* end for */
1241
1242
        /* Advance one block */
1243
0
        temp_dim = fast_dim; /* Start with the fastest changing dimension */
1244
0
        while (temp_dim >= 0) {
1245
0
            if (temp_dim == fast_dim)
1246
                /* Move iterator over current block */
1247
0
                iter_offset[temp_dim] += tdiminfo[temp_dim].block;
1248
0
            else
1249
                /* Move to the next row in the current dimension */
1250
0
                iter_offset[temp_dim]++;
1251
1252
            /* If this block is still in the range of blocks to output for the dimension, break out of loop */
1253
0
            if (iter_offset[temp_dim] < tdiminfo[temp_dim].block)
1254
0
                break;
1255
0
            else {
1256
                /* Move to the next block in the current dimension */
1257
0
                iter_offset[temp_dim] = 0;
1258
0
                iter_count[temp_dim]++;
1259
1260
                /* If this block is still in the range of blocks to output for the dimension, break out of
1261
                 * loop */
1262
0
                if (iter_count[temp_dim] < tdiminfo[temp_dim].count)
1263
0
                    break;
1264
0
                else
1265
0
                    iter_count[temp_dim] = 0; /* reset back to the beginning of the line */
1266
0
            }                                 /* end else */
1267
1268
            /* Decrement dimension count */
1269
0
            temp_dim--;
1270
0
        } /* end while */
1271
1272
        /* Translate current iter_offset and iter_count into iterator position */
1273
0
        for (u = 0; u < ndims; u++)
1274
0
            iter->u.hyp.off[u] = tdiminfo[u].start + (tdiminfo[u].stride * iter_count[u]) + iter_offset[u];
1275
0
    } /* end if */
1276
    /* Must be an irregular hyperslab selection */
1277
0
    else {
1278
0
        H5S_hyper_span_t  *curr_span = NULL; /* Current hyperslab span node */
1279
0
        H5S_hyper_span_t **ispan;            /* Iterator's hyperslab span nodes */
1280
0
        hsize_t           *abs_arr;          /* Absolute hyperslab span position */
1281
0
        int                curr_dim;         /* Temporary rank holder */
1282
1283
        /* Set the rank of the fastest changing dimension */
1284
0
        ndims    = iter->rank;
1285
0
        fast_dim = (int)ndims - 1;
1286
1287
        /* Get the pointers to the current span info and span nodes */
1288
0
        abs_arr = iter->u.hyp.off;
1289
0
        ispan   = iter->u.hyp.span;
1290
1291
        /* Loop through, advancing the span information, until all the nelements are accounted for */
1292
0
        curr_dim = fast_dim; /* Start at the fastest dim */
1293
1294
        /* Work back up through the dimensions */
1295
0
        while (curr_dim >= 0) {
1296
            /* Reset the current span */
1297
0
            curr_span = ispan[curr_dim];
1298
1299
            /* Increment absolute position */
1300
0
            if (curr_dim == fast_dim)
1301
                /* Move the iterator over rest of element in span */
1302
0
                abs_arr[curr_dim] = curr_span->high + 1;
1303
0
            else
1304
                /* Move to the next row in the current dimension */
1305
0
                abs_arr[curr_dim]++;
1306
1307
            /* Check if we are still within the span */
1308
0
            if (abs_arr[curr_dim] <= curr_span->high)
1309
0
                break;
1310
            /* If we walked off that span, advance to the next span */
1311
0
            else {
1312
                /* Advance span in this dimension */
1313
0
                curr_span = curr_span->next;
1314
1315
                /* Check if we have a valid span in this dimension still */
1316
0
                if (curr_span != NULL) {
1317
                    /* Reset the span in the current dimension */
1318
0
                    ispan[curr_dim] = curr_span;
1319
1320
                    /* Reset absolute position */
1321
0
                    abs_arr[curr_dim] = curr_span->low;
1322
1323
0
                    break;
1324
0
                } /* end if */
1325
0
                else
1326
                    /* If we finished the span list in this dimension, decrement the dimension worked on and
1327
                     * loop again */
1328
0
                    curr_dim--;
1329
0
            } /* end else */
1330
0
        }     /* end while */
1331
1332
        /* Check if we are finished with the spans in the tree */
1333
0
        if (curr_dim >= 0) {
1334
            /* Walk back down the iterator positions, resetting them */
1335
0
            while (curr_dim < fast_dim) {
1336
0
                assert(curr_span);
1337
0
                assert(curr_span->down);
1338
0
                assert(curr_span->down->head);
1339
1340
                /* Increment current dimension */
1341
0
                curr_dim++;
1342
1343
                /* Set the new span_info & span for this dimension */
1344
0
                ispan[curr_dim] = curr_span->down->head;
1345
1346
                /* Advance span down the tree */
1347
0
                curr_span = curr_span->down->head;
1348
1349
                /* Reset the absolute offset for the dim */
1350
0
                abs_arr[curr_dim] = curr_span->low;
1351
0
            } /* end while */
1352
1353
            /* Verify that the curr_span points to the fastest dim */
1354
0
            assert(curr_span == ispan[fast_dim]);
1355
0
        } /* end if */
1356
0
    }     /* end else */
1357
1358
0
    FUNC_LEAVE_NOAPI(SUCCEED)
1359
0
} /* end H5S__hyper_iter_next_block() */
1360
1361
/*--------------------------------------------------------------------------
1362
 NAME
1363
    H5S__hyper_iter_get_seq_list_gen
1364
 PURPOSE
1365
    Create a list of offsets & lengths for a selection
1366
 USAGE
1367
    herr_t H5S__hyper_iter_get_seq_list_gen(iter,maxseq,maxelem,nseq,nelem,off,len)
1368
        H5S_sel_iter_t *iter;   IN/OUT: Selection iterator describing last
1369
                                    position of interest in selection.
1370
        size_t maxseq;          IN: Maximum number of sequences to generate
1371
        size_t maxelem;         IN: Maximum number of elements to include in the
1372
                                    generated sequences
1373
        size_t *nseq;           OUT: Actual number of sequences generated
1374
        size_t *nelem;          OUT: Actual number of elements in sequences generated
1375
        hsize_t *off;           OUT: Array of offsets
1376
        size_t *len;            OUT: Array of lengths
1377
 RETURNS
1378
    Non-negative on success/Negative on failure
1379
 DESCRIPTION
1380
    Use the selection in the dataspace to generate a list of byte offsets and
1381
    lengths for the region(s) selected.  Start/Restart from the position in the
1382
    ITER parameter.  The number of sequences generated is limited by the MAXSEQ
1383
    parameter and the number of sequences actually generated is stored in the
1384
    NSEQ parameter.
1385
 GLOBAL VARIABLES
1386
 COMMENTS, BUGS, ASSUMPTIONS
1387
 EXAMPLES
1388
 REVISION LOG
1389
--------------------------------------------------------------------------*/
1390
static herr_t
1391
H5S__hyper_iter_get_seq_list_gen(H5S_sel_iter_t *iter, size_t maxseq, size_t maxelem, size_t *nseq,
1392
                                 size_t *nelem, hsize_t *off, size_t *len)
1393
0
{
1394
0
    H5S_hyper_span_t  *curr_span;         /* Current hyperslab span node */
1395
0
    H5S_hyper_span_t **ispan;             /* Iterator's hyperslab span nodes */
1396
0
    hsize_t           *slab;              /* Cumulative size of each dimension in bytes */
1397
0
    hsize_t            loc_off;           /* Byte offset in the dataspace */
1398
0
    hsize_t            last_span_end = 0; /* The offset of the end of the last span */
1399
0
    hsize_t           *abs_arr;           /* Absolute hyperslab span position, in elements */
1400
0
    hsize_t           *loc_arr;           /* Byte offset of hyperslab span position within buffer */
1401
0
    const hssize_t    *sel_off;           /* Offset within the dataspace extent */
1402
0
    size_t             span_elmts = 0;    /* Number of elements to actually use for this span */
1403
0
    size_t             span_size  = 0;    /* Number of bytes in current span to actually process */
1404
0
    size_t             io_left;           /* Initial number of elements to process */
1405
0
    size_t             io_elmts_left;     /* Number of elements left to process */
1406
0
    size_t             io_used;           /* Number of elements processed */
1407
0
    size_t             curr_seq = 0;      /* Number of sequence/offsets stored in the arrays */
1408
0
    size_t             elem_size;         /* Size of each element iterating over */
1409
0
    unsigned           ndims;             /* Number of dimensions of dataset */
1410
0
    unsigned           fast_dim;          /* Rank of the fastest changing dimension for the dataspace */
1411
0
    int                curr_dim;          /* Current dimension being operated on */
1412
0
    unsigned           u;                 /* Index variable */
1413
0
    herr_t             ret_value = SUCCEED;
1414
1415
0
    FUNC_ENTER_PACKAGE
1416
1417
    /* Check args */
1418
0
    assert(iter);
1419
0
    assert(maxseq > 0);
1420
0
    assert(maxelem > 0);
1421
0
    assert(nseq);
1422
0
    assert(nelem);
1423
0
    assert(off);
1424
0
    assert(len);
1425
1426
    /* Set the rank of the fastest changing dimension */
1427
0
    ndims    = iter->rank;
1428
0
    fast_dim = (ndims - 1);
1429
1430
    /* Get the pointers to the current span info and span nodes */
1431
0
    curr_span = iter->u.hyp.span[fast_dim];
1432
0
    abs_arr   = iter->u.hyp.off;
1433
0
    loc_arr   = iter->u.hyp.loc_off;
1434
0
    slab      = iter->u.hyp.slab;
1435
0
    sel_off   = iter->sel_off;
1436
0
    ispan     = iter->u.hyp.span;
1437
0
    elem_size = iter->elmt_size;
1438
1439
    /* Set the amount of elements to perform I/O on, etc. */
1440
0
    H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t);
1441
0
    io_elmts_left = io_left = MIN(maxelem, (size_t)iter->elmt_left);
1442
1443
    /* Set the offset of the first element iterated on */
1444
0
    for (u = 0, loc_off = 0; u < ndims; u++)
1445
0
        loc_off += loc_arr[u];
1446
1447
    /* Take care of any partial spans leftover from previous I/Os */
1448
0
    if (abs_arr[fast_dim] != curr_span->low) {
1449
        /* Finish the span in the fastest changing dimension */
1450
1451
        /* Compute the number of elements to attempt in this span */
1452
0
        H5_CHECKED_ASSIGN(span_elmts, size_t, ((curr_span->high - abs_arr[fast_dim]) + 1), hsize_t);
1453
1454
        /* Check number of elements against upper bounds allowed */
1455
0
        if (span_elmts > io_elmts_left)
1456
0
            span_elmts = io_elmts_left;
1457
1458
        /* Set the span_size, in bytes */
1459
0
        span_size = span_elmts * elem_size;
1460
1461
        /* Add the partial span to the list of sequences */
1462
0
        off[curr_seq] = loc_off;
1463
0
        len[curr_seq] = span_size;
1464
1465
        /* Increment sequence count */
1466
0
        curr_seq++;
1467
1468
        /* Set the location of the last span's end */
1469
0
        last_span_end = loc_off + span_size;
1470
1471
        /* Decrement I/O left to perform */
1472
0
        io_elmts_left -= span_elmts;
1473
1474
        /* Check if we are done */
1475
0
        if (io_elmts_left > 0) {
1476
            /* Move to next span in fastest changing dimension */
1477
0
            curr_span = curr_span->next;
1478
1479
0
            if (NULL != curr_span) {
1480
                /* Move location offset of destination */
1481
0
                loc_off += (curr_span->low - abs_arr[fast_dim]) * elem_size;
1482
1483
                /* Move iterator for fastest changing dimension */
1484
0
                abs_arr[fast_dim] = curr_span->low;
1485
0
                loc_arr[fast_dim] =
1486
0
                    ((hsize_t)((hssize_t)curr_span->low + sel_off[fast_dim])) * slab[fast_dim];
1487
0
                ispan[fast_dim] = curr_span;
1488
0
            } /* end if */
1489
0
        }     /* end if */
1490
0
        else {
1491
            /* Advance the hyperslab iterator */
1492
0
            abs_arr[fast_dim] += span_elmts;
1493
1494
            /* Check if we are still within the span */
1495
0
            if (abs_arr[fast_dim] <= curr_span->high) {
1496
                /* Sanity check */
1497
0
                assert(ispan[fast_dim] == curr_span);
1498
1499
                /* Update byte offset */
1500
0
                loc_arr[fast_dim] += span_size;
1501
0
            } /* end if */
1502
            /* If we walked off that span, advance to the next span */
1503
0
            else {
1504
                /* Advance span in this dimension */
1505
0
                curr_span = curr_span->next;
1506
1507
                /* Check if we have a valid span in this dimension still */
1508
0
                if (NULL != curr_span) {
1509
                    /* Reset absolute position */
1510
0
                    abs_arr[fast_dim] = curr_span->low;
1511
1512
                    /* Update location offset */
1513
0
                    loc_arr[fast_dim] =
1514
0
                        ((hsize_t)((hssize_t)curr_span->low + sel_off[fast_dim])) * slab[fast_dim];
1515
1516
                    /* Reset the span in the current dimension */
1517
0
                    ispan[fast_dim] = curr_span;
1518
0
                } /* end if */
1519
0
            }     /* end else */
1520
0
        }         /* end else */
1521
1522
        /* Adjust iterator pointers */
1523
1524
0
        if (NULL == curr_span) {
1525
            /* Same as code in main loop */
1526
            /* Start at the next fastest dim */
1527
0
            curr_dim = (int)(fast_dim - 1);
1528
1529
            /* Work back up through the dimensions */
1530
0
            while (curr_dim >= 0) {
1531
                /* Reset the current span */
1532
0
                curr_span = ispan[curr_dim];
1533
1534
                /* Increment absolute position */
1535
0
                abs_arr[curr_dim]++;
1536
1537
                /* Check if we are still within the span */
1538
0
                if (abs_arr[curr_dim] <= curr_span->high) {
1539
                    /* Update location offset */
1540
0
                    loc_arr[curr_dim] += slab[curr_dim];
1541
1542
0
                    break;
1543
0
                } /* end if */
1544
                /* If we walked off that span, advance to the next span */
1545
0
                else {
1546
                    /* Advance span in this dimension */
1547
0
                    curr_span = curr_span->next;
1548
1549
                    /* Check if we have a valid span in this dimension still */
1550
0
                    if (NULL != curr_span) {
1551
                        /* Reset the span in the current dimension */
1552
0
                        ispan[curr_dim] = curr_span;
1553
1554
                        /* Reset absolute position */
1555
0
                        abs_arr[curr_dim] = curr_span->low;
1556
1557
                        /* Update byte location */
1558
0
                        loc_arr[curr_dim] =
1559
0
                            ((hsize_t)((hssize_t)curr_span->low + sel_off[curr_dim])) * slab[curr_dim];
1560
1561
0
                        break;
1562
0
                    } /* end if */
1563
0
                    else
1564
                        /* If we finished the span list in this dimension, decrement the dimension worked on
1565
                         * and loop again */
1566
0
                        curr_dim--;
1567
0
                } /* end else */
1568
0
            }     /* end while */
1569
1570
            /* Check if we have more spans in the tree */
1571
0
            if (curr_dim >= 0) {
1572
                /* Walk back down the iterator positions, resetting them */
1573
0
                while ((unsigned)curr_dim < fast_dim) {
1574
0
                    assert(curr_span);
1575
0
                    assert(curr_span->down);
1576
0
                    assert(curr_span->down->head);
1577
1578
                    /* Increment current dimension */
1579
0
                    curr_dim++;
1580
1581
                    /* Set the new span_info & span for this dimension */
1582
0
                    ispan[curr_dim] = curr_span->down->head;
1583
1584
                    /* Advance span down the tree */
1585
0
                    curr_span = curr_span->down->head;
1586
1587
                    /* Reset the absolute offset for the dim */
1588
0
                    abs_arr[curr_dim] = curr_span->low;
1589
1590
                    /* Update the location offset */
1591
0
                    loc_arr[curr_dim] =
1592
0
                        ((hsize_t)((hssize_t)curr_span->low + sel_off[curr_dim])) * slab[curr_dim];
1593
0
                } /* end while */
1594
1595
                /* Verify that the curr_span points to the fastest dim */
1596
0
                assert(curr_span == ispan[fast_dim]);
1597
1598
                /* Reset the buffer offset */
1599
0
                for (u = 0, loc_off = 0; u < ndims; u++)
1600
0
                    loc_off += loc_arr[u];
1601
0
            } /* end else */
1602
0
            else
1603
                /* We had better be done with I/O or bad things are going to happen... */
1604
0
                assert(io_elmts_left == 0);
1605
0
        } /* end if */
1606
0
    }     /* end if */
1607
1608
    /* Perform the I/O on the elements, based on the position of the iterator */
1609
0
    while (io_elmts_left > 0 && curr_seq < maxseq) {
1610
0
        H5S_hyper_span_t *prev_span; /* Previous hyperslab span node */
1611
1612
        /* Sanity check */
1613
0
        assert(curr_span);
1614
1615
        /* Set to current span, so the first adjustment to loc_off is 0 */
1616
0
        prev_span = curr_span;
1617
1618
        /* Loop over all the spans in the fastest changing dimension */
1619
0
        while (curr_span != NULL) {
1620
0
            hsize_t nelmts; /* # of elements covered by current span */
1621
1622
            /* Move location offset of current span */
1623
0
            loc_off += (curr_span->low - prev_span->low) * elem_size;
1624
1625
            /* Compute the number of elements to attempt in this span */
1626
0
            nelmts = (curr_span->high - curr_span->low) + 1;
1627
0
            H5_CHECKED_ASSIGN(span_elmts, size_t, nelmts, hsize_t);
1628
1629
            /* Check number of elements against upper bounds allowed */
1630
0
            if (span_elmts >= io_elmts_left) {
1631
                /* Trim the number of elements to output */
1632
0
                span_elmts    = io_elmts_left;
1633
0
                span_size     = span_elmts * elem_size;
1634
0
                io_elmts_left = 0;
1635
1636
                /* COMMON */
1637
                /* Store the I/O information for the span */
1638
1639
                /* Check if this is appending onto previous sequence */
1640
0
                if (curr_seq > 0 && last_span_end == loc_off)
1641
0
                    len[curr_seq - 1] += span_size;
1642
0
                else {
1643
0
                    off[curr_seq] = loc_off;
1644
0
                    len[curr_seq] = span_size;
1645
1646
                    /* Increment the number of sequences in arrays */
1647
0
                    curr_seq++;
1648
0
                } /* end else */
1649
                  /* end COMMON */
1650
1651
                /* Break out now, we are finished with I/O */
1652
0
                break;
1653
0
            } /* end if */
1654
0
            else {
1655
                /* Decrement I/O left to perform */
1656
0
                span_size = span_elmts * elem_size;
1657
0
                io_elmts_left -= span_elmts;
1658
1659
                /* COMMON */
1660
                /* Store the I/O information for the span */
1661
1662
                /* Check if this is appending onto previous sequence */
1663
0
                if (curr_seq > 0 && last_span_end == loc_off)
1664
0
                    len[curr_seq - 1] += span_size;
1665
0
                else {
1666
0
                    off[curr_seq] = loc_off;
1667
0
                    len[curr_seq] = span_size;
1668
1669
                    /* Increment the number of sequences in arrays */
1670
0
                    curr_seq++;
1671
0
                } /* end else */
1672
                  /* end COMMON */
1673
1674
                /* If the sequence & offset arrays are full, do what? */
1675
0
                if (curr_seq >= maxseq)
1676
                    /* Break out now, we are finished with sequences */
1677
0
                    break;
1678
0
            } /* end else */
1679
1680
            /* Set the location of the last span's end */
1681
0
            last_span_end = loc_off + span_size;
1682
1683
            /* Move to next span in fastest changing dimension */
1684
0
            prev_span = curr_span;
1685
0
            curr_span = curr_span->next;
1686
0
        } /* end while */
1687
1688
        /* Check if we are done */
1689
0
        if (io_elmts_left == 0 || curr_seq >= maxseq) {
1690
            /* Sanity checks */
1691
0
            if (!curr_span)
1692
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "curr_span pointer was NULL");
1693
1694
            /* Update absolute position */
1695
0
            abs_arr[fast_dim] = curr_span->low + span_elmts;
1696
1697
            /* Check if we are still within the span */
1698
0
            if (abs_arr[fast_dim] <= curr_span->high) {
1699
                /* Reset the span for the fast dimension */
1700
0
                ispan[fast_dim] = curr_span;
1701
1702
                /* Update location offset */
1703
0
                loc_arr[fast_dim] =
1704
0
                    ((hsize_t)((hssize_t)curr_span->low + (hssize_t)span_elmts + sel_off[fast_dim])) *
1705
0
                    slab[fast_dim];
1706
1707
0
                break;
1708
0
            } /* end if */
1709
            /* If we walked off that span, advance to the next span */
1710
0
            else {
1711
                /* Advance span in this dimension */
1712
0
                curr_span = curr_span->next;
1713
1714
                /* Check if we have a valid span in this dimension still */
1715
0
                if (curr_span != NULL) {
1716
                    /* Reset absolute position */
1717
0
                    abs_arr[fast_dim] = curr_span->low;
1718
0
                    loc_arr[fast_dim] =
1719
0
                        ((hsize_t)((hssize_t)curr_span->low + sel_off[fast_dim])) * slab[fast_dim];
1720
0
                    ispan[fast_dim] = curr_span;
1721
1722
0
                    break;
1723
0
                } /* end if */
1724
0
            }     /* end else */
1725
0
        }         /* end if */
1726
1727
        /* Adjust iterator pointers */
1728
1729
        /* Start at the next fastest dim */
1730
0
        curr_dim = (int)(fast_dim - 1);
1731
1732
        /* Work back up through the dimensions */
1733
0
        while (curr_dim >= 0) {
1734
            /* Reset the current span */
1735
0
            curr_span = ispan[curr_dim];
1736
1737
            /* Increment absolute position */
1738
0
            abs_arr[curr_dim]++;
1739
1740
            /* Check if we are still within the span */
1741
0
            if (abs_arr[curr_dim] <= curr_span->high) {
1742
                /* Update location offset */
1743
0
                loc_arr[curr_dim] += slab[curr_dim];
1744
1745
0
                break;
1746
0
            } /* end if */
1747
            /* If we walked off that span, advance to the next span */
1748
0
            else {
1749
                /* Advance span in this dimension */
1750
0
                curr_span = curr_span->next;
1751
1752
                /* Check if we have a valid span in this dimension still */
1753
0
                if (curr_span != NULL) {
1754
                    /* Reset the span in the current dimension */
1755
0
                    ispan[curr_dim] = curr_span;
1756
1757
                    /* Reset absolute position */
1758
0
                    abs_arr[curr_dim] = curr_span->low;
1759
1760
                    /* Update location offset */
1761
0
                    loc_arr[curr_dim] =
1762
0
                        ((hsize_t)((hssize_t)curr_span->low + sel_off[curr_dim])) * slab[curr_dim];
1763
1764
0
                    break;
1765
0
                } /* end if */
1766
0
                else
1767
                    /* If we finished the span list in this dimension, decrement the dimension worked on and
1768
                     * loop again */
1769
0
                    curr_dim--;
1770
0
            } /* end else */
1771
0
        }     /* end while */
1772
1773
        /* Check if we are finished with the spans in the tree */
1774
0
        if (curr_dim < 0) {
1775
            /* We had better be done with I/O or bad things are going to happen... */
1776
0
            assert(io_elmts_left == 0);
1777
0
            break;
1778
0
        } /* end if */
1779
0
        else {
1780
            /* Walk back down the iterator positions, resetting them */
1781
0
            while ((unsigned)curr_dim < fast_dim) {
1782
0
                assert(curr_span);
1783
0
                assert(curr_span->down);
1784
0
                assert(curr_span->down->head);
1785
1786
                /* Increment current dimension to the next dimension down */
1787
0
                curr_dim++;
1788
1789
                /* Set the new span for the next dimension down */
1790
0
                ispan[curr_dim] = curr_span->down->head;
1791
1792
                /* Advance span down the tree */
1793
0
                curr_span = curr_span->down->head;
1794
1795
                /* Reset the absolute offset for the dim */
1796
0
                abs_arr[curr_dim] = curr_span->low;
1797
1798
                /* Update location offset */
1799
0
                loc_arr[curr_dim] =
1800
0
                    ((hsize_t)((hssize_t)curr_span->low + sel_off[curr_dim])) * slab[curr_dim];
1801
0
            } /* end while */
1802
1803
            /* Verify that the curr_span points to the fastest dim */
1804
0
            assert(curr_span == ispan[fast_dim]);
1805
0
        } /* end else */
1806
1807
        /* Reset the buffer offset */
1808
0
        for (u = 0, loc_off = 0; u < ndims; u++)
1809
0
            loc_off += loc_arr[u];
1810
0
    } /* end while */
1811
1812
    /* Decrement number of elements left in iterator */
1813
0
    io_used = io_left - io_elmts_left;
1814
0
    iter->elmt_left -= io_used;
1815
1816
    /* Set the number of sequences generated */
1817
0
    *nseq = curr_seq;
1818
1819
    /* Set the number of elements used */
1820
0
    *nelem = io_used;
1821
1822
0
done:
1823
0
    FUNC_LEAVE_NOAPI(ret_value)
1824
0
} /* end H5S__hyper_iter_get_seq_list_gen() */
1825
1826
/*--------------------------------------------------------------------------
1827
 NAME
1828
    H5S__hyper_iter_get_seq_list_opt
1829
 PURPOSE
1830
    Create a list of offsets & lengths for a selection
1831
 USAGE
1832
    herr_t H5S__hyper_iter_get_seq_list_opt(iter,maxseq,maxelem,nseq,nelem,off,len)
1833
        H5S_sel_iter_t *iter;   IN/OUT: Selection iterator describing last
1834
                                    position of interest in selection.
1835
        size_t maxseq;          IN: Maximum number of sequences to generate
1836
        size_t maxelem;         IN: Maximum number of elements to include in the
1837
                                    generated sequences
1838
        size_t *nseq;           OUT: Actual number of sequences generated
1839
        size_t *nelem;          OUT: Actual number of elements in sequences generated
1840
        hsize_t *off;           OUT: Array of offsets
1841
        size_t *len;            OUT: Array of lengths
1842
 RETURNS
1843
    Non-negative on success/Negative on failure.
1844
 DESCRIPTION
1845
    Use the selection in the dataspace to generate a list of byte offsets and
1846
    lengths for the region(s) selected.  Start/Restart from the position in the
1847
    ITER parameter.  The number of sequences generated is limited by the MAXSEQ
1848
    parameter and the number of sequences actually generated is stored in the
1849
    NSEQ parameter.
1850
 GLOBAL VARIABLES
1851
 COMMENTS, BUGS, ASSUMPTIONS
1852
 EXAMPLES
1853
 REVISION LOG
1854
--------------------------------------------------------------------------*/
1855
static herr_t
1856
H5S__hyper_iter_get_seq_list_opt(H5S_sel_iter_t *iter, size_t maxseq, size_t maxelem, size_t *nseq,
1857
                                 size_t *nelem, hsize_t *off, size_t *len)
1858
0
{
1859
0
    hsize_t               *mem_size;                /* Size of the source buffer */
1860
0
    hsize_t               *slab;                    /* Hyperslab size */
1861
0
    const hssize_t        *sel_off;                 /* Selection offset in dataspace */
1862
0
    hsize_t                offset[H5S_MAX_RANK];    /* Coordinate offset in dataspace */
1863
0
    hsize_t                tmp_count[H5S_MAX_RANK]; /* Temporary block count */
1864
0
    hsize_t                tmp_block[H5S_MAX_RANK]; /* Temporary block offset */
1865
0
    hsize_t                wrap[H5S_MAX_RANK];      /* Bytes to wrap around at the end of a row */
1866
0
    hsize_t                skip[H5S_MAX_RANK];      /* Bytes to skip between blocks */
1867
0
    const H5S_hyper_dim_t *tdiminfo;                /* Temporary pointer to diminfo information */
1868
0
    hsize_t                fast_dim_start,          /* Local copies of fastest changing dimension info */
1869
0
        fast_dim_stride, fast_dim_block, fast_dim_offset;
1870
0
    size_t   fast_dim_buf_off; /* Local copy of amount to move fastest dimension buffer offset */
1871
0
    size_t   fast_dim_count;   /* Number of blocks left in fastest changing dimension */
1872
0
    size_t   tot_blk_count;    /* Total number of blocks left to output */
1873
0
    size_t   act_blk_count;    /* Actual number of blocks to output */
1874
0
    size_t   total_rows;       /* Total number of entire rows to output */
1875
0
    size_t   curr_rows;        /* Current number of entire rows to output */
1876
0
    unsigned fast_dim;         /* Rank of the fastest changing dimension for the dataspace */
1877
0
    unsigned ndims;            /* Number of dimensions of dataset */
1878
0
    int      temp_dim;         /* Temporary rank holder */
1879
0
    hsize_t  loc;              /* Coordinate offset */
1880
0
    size_t   curr_seq = 0;     /* Current sequence being operated on */
1881
0
    size_t   actual_elem;      /* The actual number of elements to count */
1882
0
    size_t   actual_bytes;     /* The actual number of bytes to copy */
1883
0
    size_t   io_left;          /* The number of elements left in I/O operation */
1884
0
    size_t   start_io_left;    /* The initial number of elements left in I/O operation */
1885
0
    size_t   elem_size;        /* Size of each element iterating over */
1886
0
    unsigned u;                /* Local index variable */
1887
1888
0
    FUNC_ENTER_PACKAGE_NOERR
1889
1890
    /* Check args */
1891
0
    assert(iter);
1892
0
    assert(maxseq > 0);
1893
0
    assert(maxelem > 0);
1894
0
    assert(nseq);
1895
0
    assert(nelem);
1896
0
    assert(off);
1897
0
    assert(len);
1898
1899
    /* Set the local copy of the diminfo pointer */
1900
0
    tdiminfo = iter->u.hyp.diminfo;
1901
1902
    /* Check if this is a "flattened" regular hyperslab selection */
1903
0
    if (iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < iter->rank) {
1904
        /* Set the aliases for a few important dimension ranks */
1905
0
        ndims = iter->u.hyp.iter_rank;
1906
1907
        /* Set the local copy of the selection offset */
1908
0
        sel_off = iter->u.hyp.sel_off;
1909
1910
        /* Set up the pointer to the size of the memory dataspace */
1911
0
        mem_size = iter->u.hyp.size;
1912
0
    } /* end if */
1913
0
    else {
1914
        /* Set the aliases for a few important dimension ranks */
1915
0
        ndims = iter->rank;
1916
1917
        /* Set the local copy of the selection offset */
1918
0
        sel_off = iter->sel_off;
1919
1920
        /* Set up the pointer to the size of the memory dataspace */
1921
0
        mem_size = iter->dims;
1922
0
    } /* end else */
1923
1924
    /* Set up some local variables */
1925
0
    fast_dim  = ndims - 1;
1926
0
    elem_size = iter->elmt_size;
1927
0
    slab      = iter->u.hyp.slab;
1928
1929
    /* Calculate the number of elements to sequence through */
1930
0
    H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t);
1931
0
    io_left = MIN((size_t)iter->elmt_left, maxelem);
1932
1933
    /* Sanity check that there aren't any "remainder" sequences in process */
1934
0
    assert(!((iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start) % tdiminfo[fast_dim].stride != 0 ||
1935
0
             ((iter->u.hyp.off[fast_dim] != tdiminfo[fast_dim].start) && tdiminfo[fast_dim].count == 1)));
1936
1937
    /* We've cleared the "remainder" of the previous fastest dimension
1938
     * sequence before calling this routine, so we must be at the beginning of
1939
     * a sequence.  Use the fancy algorithm to compute the offsets and run
1940
     * through as many as possible, until the buffer fills up.
1941
     */
1942
1943
    /* Keep the number of elements we started with */
1944
0
    start_io_left = io_left;
1945
1946
    /* Compute the arrays to perform I/O on */
1947
1948
    /* Copy the location of the point to get */
1949
    /* (Add in the selection offset) */
1950
0
    for (u = 0; u < ndims; u++)
1951
0
        offset[u] = (hsize_t)((hssize_t)iter->u.hyp.off[u] + sel_off[u]);
1952
1953
    /* Compute the current "counts" for this location */
1954
0
    for (u = 0; u < ndims; u++) {
1955
0
        if (tdiminfo[u].count == 1) {
1956
0
            tmp_count[u] = 0;
1957
0
            tmp_block[u] = iter->u.hyp.off[u] - tdiminfo[u].start;
1958
0
        } /* end if */
1959
0
        else {
1960
0
            tmp_count[u] = (iter->u.hyp.off[u] - tdiminfo[u].start) / tdiminfo[u].stride;
1961
0
            tmp_block[u] = (iter->u.hyp.off[u] - tdiminfo[u].start) % tdiminfo[u].stride;
1962
0
        } /* end else */
1963
0
    }     /* end for */
1964
1965
    /* Compute the initial buffer offset */
1966
0
    for (u = 0, loc = 0; u < ndims; u++)
1967
0
        loc += offset[u] * slab[u];
1968
1969
    /* Set the number of elements to write each time */
1970
0
    H5_CHECKED_ASSIGN(actual_elem, size_t, tdiminfo[fast_dim].block, hsize_t);
1971
1972
    /* Set the number of actual bytes */
1973
0
    actual_bytes = actual_elem * elem_size;
1974
1975
    /* Set local copies of information for the fastest changing dimension */
1976
0
    fast_dim_start  = tdiminfo[fast_dim].start;
1977
0
    fast_dim_stride = tdiminfo[fast_dim].stride;
1978
0
    fast_dim_block  = tdiminfo[fast_dim].block;
1979
0
    H5_CHECKED_ASSIGN(fast_dim_buf_off, size_t, slab[fast_dim] * fast_dim_stride, hsize_t);
1980
0
    fast_dim_offset = (hsize_t)((hssize_t)fast_dim_start + sel_off[fast_dim]);
1981
1982
    /* Compute the number of blocks which would fit into the buffer */
1983
0
    H5_CHECK_OVERFLOW(io_left / fast_dim_block, hsize_t, size_t);
1984
0
    tot_blk_count = (size_t)(io_left / fast_dim_block);
1985
1986
    /* Don't go over the maximum number of sequences allowed */
1987
0
    tot_blk_count = MIN(tot_blk_count, (maxseq - curr_seq));
1988
1989
    /* Compute the amount to wrap at the end of each row */
1990
0
    for (u = 0; u < ndims; u++)
1991
0
        wrap[u] = (mem_size[u] - (tdiminfo[u].stride * tdiminfo[u].count)) * slab[u];
1992
1993
    /* Compute the amount to skip between blocks */
1994
0
    for (u = 0; u < ndims; u++)
1995
0
        skip[u] = (tdiminfo[u].stride - tdiminfo[u].block) * slab[u];
1996
1997
    /* Check if there is a partial row left (with full blocks) */
1998
0
    if (tmp_count[fast_dim] > 0) {
1999
        /* Get number of blocks in fastest dimension */
2000
0
        H5_CHECKED_ASSIGN(fast_dim_count, size_t, tdiminfo[fast_dim].count - tmp_count[fast_dim], hsize_t);
2001
2002
        /* Make certain this entire row will fit into buffer */
2003
0
        fast_dim_count = MIN(fast_dim_count, tot_blk_count);
2004
2005
        /* Number of blocks to sequence over */
2006
0
        act_blk_count = fast_dim_count;
2007
2008
        /* Loop over all the blocks in the fastest changing dimension */
2009
0
        while (fast_dim_count > 0) {
2010
            /* Store the sequence information */
2011
0
            off[curr_seq] = loc;
2012
0
            len[curr_seq] = actual_bytes;
2013
2014
            /* Increment sequence count */
2015
0
            curr_seq++;
2016
2017
            /* Increment information to reflect block just processed */
2018
0
            loc += fast_dim_buf_off;
2019
2020
            /* Decrement number of blocks */
2021
0
            fast_dim_count--;
2022
0
        } /* end while */
2023
2024
        /* Decrement number of elements left */
2025
0
        io_left -= actual_elem * act_blk_count;
2026
2027
        /* Decrement number of blocks left */
2028
0
        tot_blk_count -= act_blk_count;
2029
2030
        /* Increment information to reflect block just processed */
2031
0
        tmp_count[fast_dim] += act_blk_count;
2032
2033
        /* Check if we finished the entire row of blocks */
2034
0
        if (tmp_count[fast_dim] >= tdiminfo[fast_dim].count) {
2035
            /* Increment offset in destination buffer */
2036
0
            loc += wrap[fast_dim];
2037
2038
            /* Increment information to reflect block just processed */
2039
0
            offset[fast_dim]    = fast_dim_offset; /* reset the offset in the fastest dimension */
2040
0
            tmp_count[fast_dim] = 0;
2041
2042
            /* Increment the offset and count for the other dimensions */
2043
0
            temp_dim = (int)fast_dim - 1;
2044
0
            while (temp_dim >= 0) {
2045
                /* Move to the next row in the current dimension */
2046
0
                offset[temp_dim]++;
2047
0
                tmp_block[temp_dim]++;
2048
2049
                /* If this block is still in the range of blocks to output for the dimension, break out of
2050
                 * loop */
2051
0
                if (tmp_block[temp_dim] < tdiminfo[temp_dim].block)
2052
0
                    break;
2053
0
                else {
2054
                    /* Move to the next block in the current dimension */
2055
0
                    offset[temp_dim] += (tdiminfo[temp_dim].stride - tdiminfo[temp_dim].block);
2056
0
                    loc += skip[temp_dim];
2057
0
                    tmp_block[temp_dim] = 0;
2058
0
                    tmp_count[temp_dim]++;
2059
2060
                    /* If this block is still in the range of blocks to output for the dimension, break out of
2061
                     * loop */
2062
0
                    if (tmp_count[temp_dim] < tdiminfo[temp_dim].count)
2063
0
                        break;
2064
0
                    else {
2065
0
                        offset[temp_dim] = (hsize_t)((hssize_t)tdiminfo[temp_dim].start + sel_off[temp_dim]);
2066
0
                        loc += wrap[temp_dim];
2067
0
                        tmp_count[temp_dim] = 0; /* reset back to the beginning of the line */
2068
0
                        tmp_block[temp_dim] = 0;
2069
0
                    } /* end else */
2070
0
                }     /* end else */
2071
2072
                /* Decrement dimension count */
2073
0
                temp_dim--;
2074
0
            } /* end while */
2075
0
        }     /* end if */
2076
0
        else {
2077
            /* Update the offset in the fastest dimension */
2078
0
            offset[fast_dim] += (fast_dim_stride * act_blk_count);
2079
0
        } /* end else */
2080
0
    }     /* end if */
2081
2082
    /* Compute the number of entire rows to read in */
2083
0
    H5_CHECK_OVERFLOW(tot_blk_count / tdiminfo[fast_dim].count, hsize_t, size_t);
2084
0
    curr_rows = total_rows = (size_t)(tot_blk_count / tdiminfo[fast_dim].count);
2085
2086
    /* Reset copy of number of blocks in fastest dimension */
2087
0
    H5_CHECKED_ASSIGN(fast_dim_count, size_t, tdiminfo[fast_dim].count, hsize_t);
2088
2089
    /* Read in data until an entire sequence can't be written out any longer */
2090
0
    while (curr_rows > 0) {
2091
2092
0
#define DUFF_GUTS                                                                                            \
2093
    /* Store the sequence information */                                                                     \
2094
0
    off[curr_seq] = loc;                                                                                     \
2095
0
    len[curr_seq] = actual_bytes;                                                                            \
2096
0
                                                                                                             \
2097
    /* Increment sequence count */                                                                           \
2098
0
    curr_seq++;                                                                                              \
2099
0
                                                                                                             \
2100
    /* Increment information to reflect block just processed */                                              \
2101
0
    loc += fast_dim_buf_off;
2102
2103
#ifdef NO_DUFFS_DEVICE
2104
        /* Loop over all the blocks in the fastest changing dimension */
2105
        while (fast_dim_count > 0) {
2106
            DUFF_GUTS
2107
2108
            /* Decrement number of blocks */
2109
            fast_dim_count--;
2110
        } /* end while */
2111
#else     /* NO_DUFFS_DEVICE */
2112
0
        {
2113
0
            size_t duffs_index; /* Counting index for Duff's device */
2114
2115
0
            duffs_index = (fast_dim_count + 7) / 8;
2116
0
            switch (fast_dim_count % 8) {
2117
0
                default:
2118
0
                    assert(0 && "This Should never be executed!");
2119
0
                    break;
2120
0
                case 0:
2121
0
                    do {
2122
0
                        DUFF_GUTS
2123
                        /* FALLTHROUGH */
2124
0
                        H5_ATTR_FALLTHROUGH
2125
0
                        case 7:
2126
0
                            DUFF_GUTS
2127
                            /* FALLTHROUGH */
2128
0
                            H5_ATTR_FALLTHROUGH
2129
0
                        case 6:
2130
0
                            DUFF_GUTS
2131
                            /* FALLTHROUGH */
2132
0
                            H5_ATTR_FALLTHROUGH
2133
0
                        case 5:
2134
0
                            DUFF_GUTS
2135
                            /* FALLTHROUGH */
2136
0
                            H5_ATTR_FALLTHROUGH
2137
0
                        case 4:
2138
0
                            DUFF_GUTS
2139
                            /* FALLTHROUGH */
2140
0
                            H5_ATTR_FALLTHROUGH
2141
0
                        case 3:
2142
0
                            DUFF_GUTS
2143
                            /* FALLTHROUGH */
2144
0
                            H5_ATTR_FALLTHROUGH
2145
0
                        case 2:
2146
0
                            DUFF_GUTS
2147
                            /* FALLTHROUGH */
2148
0
                            H5_ATTR_FALLTHROUGH
2149
0
                        case 1:
2150
0
                            DUFF_GUTS
2151
0
                    } while (--duffs_index > 0);
2152
0
            } /* end switch */
2153
0
        }
2154
0
#endif    /* NO_DUFFS_DEVICE */
2155
0
#undef DUFF_GUTS
2156
2157
        /* Increment offset in destination buffer */
2158
0
        loc += wrap[fast_dim];
2159
2160
        /* Increment the offset and count for the other dimensions */
2161
0
        temp_dim = (int)fast_dim - 1;
2162
0
        while (temp_dim >= 0) {
2163
            /* Move to the next row in the current dimension */
2164
0
            offset[temp_dim]++;
2165
0
            tmp_block[temp_dim]++;
2166
2167
            /* If this block is still in the range of blocks to output for the dimension, break out of loop */
2168
0
            if (tmp_block[temp_dim] < tdiminfo[temp_dim].block)
2169
0
                break;
2170
0
            else {
2171
                /* Move to the next block in the current dimension */
2172
0
                offset[temp_dim] += (tdiminfo[temp_dim].stride - tdiminfo[temp_dim].block);
2173
0
                loc += skip[temp_dim];
2174
0
                tmp_block[temp_dim] = 0;
2175
0
                tmp_count[temp_dim]++;
2176
2177
                /* If this block is still in the range of blocks to output for the dimension, break out of
2178
                 * loop */
2179
0
                if (tmp_count[temp_dim] < tdiminfo[temp_dim].count)
2180
0
                    break;
2181
0
                else {
2182
0
                    offset[temp_dim] = (hsize_t)((hssize_t)tdiminfo[temp_dim].start + sel_off[temp_dim]);
2183
0
                    loc += wrap[temp_dim];
2184
0
                    tmp_count[temp_dim] = 0; /* reset back to the beginning of the line */
2185
0
                    tmp_block[temp_dim] = 0;
2186
0
                } /* end else */
2187
0
            }     /* end else */
2188
2189
            /* Decrement dimension count */
2190
0
            temp_dim--;
2191
0
        } /* end while */
2192
2193
        /* Decrement the number of rows left */
2194
0
        curr_rows--;
2195
0
    } /* end while */
2196
2197
    /* Adjust the number of blocks & elements left to transfer */
2198
2199
    /* Decrement number of elements left */
2200
0
    H5_CHECK_OVERFLOW(actual_elem * (total_rows * tdiminfo[fast_dim].count), hsize_t, size_t);
2201
0
    io_left -= (size_t)(actual_elem * (total_rows * tdiminfo[fast_dim].count));
2202
2203
    /* Decrement number of blocks left */
2204
0
    H5_CHECK_OVERFLOW((total_rows * tdiminfo[fast_dim].count), hsize_t, size_t);
2205
0
    tot_blk_count -= (size_t)(total_rows * tdiminfo[fast_dim].count);
2206
2207
    /* Read in partial row of blocks */
2208
0
    if (io_left > 0 && curr_seq < maxseq) {
2209
        /* Get remaining number of blocks left to output */
2210
0
        fast_dim_count = tot_blk_count;
2211
2212
        /* Loop over all the blocks in the fastest changing dimension */
2213
0
        while (fast_dim_count > 0) {
2214
            /* Store the sequence information */
2215
0
            off[curr_seq] = loc;
2216
0
            len[curr_seq] = actual_bytes;
2217
2218
            /* Increment sequence count */
2219
0
            curr_seq++;
2220
2221
            /* Increment information to reflect block just processed */
2222
0
            loc += fast_dim_buf_off;
2223
2224
            /* Decrement number of blocks */
2225
0
            fast_dim_count--;
2226
0
        } /* end while */
2227
2228
        /* Decrement number of elements left */
2229
0
        io_left -= actual_elem * tot_blk_count;
2230
2231
        /* Increment information to reflect block just processed */
2232
0
        offset[fast_dim] += (fast_dim_stride * tot_blk_count); /* move the offset in the fastest dimension */
2233
2234
        /* Handle any leftover, partial blocks in this row */
2235
0
        if (io_left > 0 && curr_seq < maxseq) {
2236
0
            actual_elem  = io_left;
2237
0
            actual_bytes = actual_elem * elem_size;
2238
2239
            /* Store the sequence information */
2240
0
            off[curr_seq] = loc;
2241
0
            len[curr_seq] = actual_bytes;
2242
2243
            /* Increment sequence count */
2244
0
            curr_seq++;
2245
2246
            /* Decrement the number of elements left */
2247
0
            io_left -= actual_elem;
2248
2249
            /* Increment buffer correctly */
2250
0
            offset[fast_dim] += actual_elem;
2251
0
        } /* end if */
2252
2253
        /* don't bother checking slower dimensions */
2254
0
        assert(io_left == 0 || curr_seq == maxseq);
2255
0
    } /* end if */
2256
2257
    /* Update the iterator */
2258
2259
    /* Update the iterator with the location we stopped */
2260
    /* (Subtract out the selection offset) */
2261
0
    for (u = 0; u < ndims; u++)
2262
0
        iter->u.hyp.off[u] = (hsize_t)((hssize_t)offset[u] - sel_off[u]);
2263
2264
    /* Decrement the number of elements left in selection */
2265
0
    iter->elmt_left -= (start_io_left - io_left);
2266
2267
    /* Increment the number of sequences generated */
2268
0
    *nseq += curr_seq;
2269
2270
    /* Increment the number of elements used */
2271
0
    *nelem += start_io_left - io_left;
2272
2273
0
    FUNC_LEAVE_NOAPI(SUCCEED)
2274
0
} /* end H5S__hyper_iter_get_seq_list_opt() */
2275
2276
/*--------------------------------------------------------------------------
2277
 NAME
2278
    H5S__hyper_iter_get_seq_list_single
2279
 PURPOSE
2280
    Create a list of offsets & lengths for a selection
2281
 USAGE
2282
    herr_t H5S__hyper_iter_get_seq_list_single(flags, iter, maxseq, maxelem, nseq, nelem, off, len)
2283
        unsigned flags;         IN: Flags for extra information about operation
2284
        H5S_sel_iter_t *iter;   IN/OUT: Selection iterator describing last
2285
                                    position of interest in selection.
2286
        size_t maxseq;          IN: Maximum number of sequences to generate
2287
        size_t maxelem;         IN: Maximum number of elements to include in the
2288
                                    generated sequences
2289
        size_t *nseq;           OUT: Actual number of sequences generated
2290
        size_t *nelem;          OUT: Actual number of elements in sequences generated
2291
        hsize_t *off;           OUT: Array of offsets
2292
        size_t *len;            OUT: Array of lengths
2293
 RETURNS
2294
    Non-negative on success/Negative on failure.
2295
 DESCRIPTION
2296
    Use the selection in the dataspace to generate a list of byte offsets and
2297
    lengths for the region(s) selected.  Start/Restart from the position in the
2298
    ITER parameter.  The number of sequences generated is limited by the MAXSEQ
2299
    parameter and the number of sequences actually generated is stored in the
2300
    NSEQ parameter.
2301
 GLOBAL VARIABLES
2302
 COMMENTS, BUGS, ASSUMPTIONS
2303
 EXAMPLES
2304
 REVISION LOG
2305
--------------------------------------------------------------------------*/
2306
static herr_t
2307
H5S__hyper_iter_get_seq_list_single(H5S_sel_iter_t *iter, size_t maxseq, size_t maxelem, size_t *nseq,
2308
                                    size_t *nelem, hsize_t *off, size_t *len)
2309
0
{
2310
0
    const H5S_hyper_dim_t *tdiminfo;                  /* Temporary pointer to diminfo information */
2311
0
    const hssize_t        *sel_off;                   /* Selection offset in dataspace */
2312
0
    hsize_t               *mem_size;                  /* Size of the source buffer */
2313
0
    hsize_t                base_offset[H5S_MAX_RANK]; /* Base coordinate offset in dataspace */
2314
0
    hsize_t                offset[H5S_MAX_RANK];      /* Coordinate offset in dataspace */
2315
0
    hsize_t               *slab;                      /* Hyperslab size */
2316
0
    hsize_t                fast_dim_block;            /* Local copies of fastest changing dimension info */
2317
0
    hsize_t                loc;                       /* Coordinate offset */
2318
0
    size_t                 tot_blk_count;             /* Total number of blocks left to output */
2319
0
    size_t                 elem_size;                 /* Size of each element iterating over */
2320
0
    size_t                 io_left;                   /* The number of elements left in I/O operation */
2321
0
    size_t                 actual_elem;               /* The actual number of elements to count */
2322
0
    unsigned               ndims;                     /* Number of dimensions of dataset */
2323
0
    unsigned               fast_dim; /* Rank of the fastest changing dimension for the dataspace */
2324
0
    unsigned               skip_dim; /* Rank of the dimension to skip along */
2325
0
    unsigned               u;        /* Local index variable */
2326
2327
0
    FUNC_ENTER_PACKAGE_NOERR
2328
2329
    /* Check args */
2330
0
    assert(iter);
2331
0
    assert(maxseq > 0);
2332
0
    assert(maxelem > 0);
2333
0
    assert(nseq);
2334
0
    assert(nelem);
2335
0
    assert(off);
2336
0
    assert(len);
2337
2338
    /* Set a local copy of the diminfo pointer */
2339
0
    tdiminfo = iter->u.hyp.diminfo;
2340
2341
    /* Check if this is a "flattened" regular hyperslab selection */
2342
0
    if (iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < iter->rank) {
2343
        /* Set the aliases for a few important dimension ranks */
2344
0
        ndims = iter->u.hyp.iter_rank;
2345
2346
        /* Set the local copy of the selection offset */
2347
0
        sel_off = iter->u.hyp.sel_off;
2348
2349
        /* Set up the pointer to the size of the memory dataspace */
2350
0
        mem_size = iter->u.hyp.size;
2351
0
    } /* end if */
2352
0
    else {
2353
        /* Set the aliases for a few important dimension ranks */
2354
0
        ndims = iter->rank;
2355
2356
        /* Set the local copy of the selection offset */
2357
0
        sel_off = iter->sel_off;
2358
2359
        /* Set up the pointer to the size of the memory dataspace */
2360
0
        mem_size = iter->dims;
2361
0
    } /* end else */
2362
2363
    /* Set up some local variables */
2364
0
    fast_dim  = ndims - 1;
2365
0
    elem_size = iter->elmt_size;
2366
0
    slab      = iter->u.hyp.slab;
2367
2368
    /* Copy the base location of the block */
2369
    /* (Add in the selection offset) */
2370
0
    for (u = 0; u < ndims; u++)
2371
0
        base_offset[u] = (hsize_t)((hssize_t)tdiminfo[u].start + sel_off[u]);
2372
2373
    /* Copy the location of the point to get */
2374
    /* (Add in the selection offset) */
2375
0
    for (u = 0; u < ndims; u++)
2376
0
        offset[u] = (hsize_t)((hssize_t)iter->u.hyp.off[u] + sel_off[u]);
2377
2378
    /* Compute the initial buffer offset */
2379
0
    for (u = 0, loc = 0; u < ndims; u++)
2380
0
        loc += offset[u] * slab[u];
2381
2382
    /* Set local copies of information for the fastest changing dimension */
2383
0
    fast_dim_block = tdiminfo[fast_dim].block;
2384
2385
    /* Calculate the number of elements to sequence through */
2386
0
    H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t);
2387
0
    io_left = MIN((size_t)iter->elmt_left, maxelem);
2388
2389
    /* Compute the number of blocks which would fit into the buffer */
2390
0
    H5_CHECK_OVERFLOW(io_left / fast_dim_block, hsize_t, size_t);
2391
0
    tot_blk_count = (size_t)(io_left / fast_dim_block);
2392
2393
    /* Don't go over the maximum number of sequences allowed */
2394
0
    tot_blk_count = MIN(tot_blk_count, maxseq);
2395
2396
    /* Set the number of elements to write each time */
2397
0
    H5_CHECKED_ASSIGN(actual_elem, size_t, fast_dim_block, hsize_t);
2398
2399
    /* Check for blocks to operate on */
2400
0
    if (tot_blk_count > 0) {
2401
0
        size_t actual_bytes; /* The actual number of bytes to copy */
2402
2403
        /* Set the number of actual bytes */
2404
0
        actual_bytes = actual_elem * elem_size;
2405
2406
        /* Check for 1-dim selection */
2407
0
        if (0 == fast_dim) {
2408
            /* Sanity checks */
2409
0
            assert(1 == tot_blk_count);
2410
0
            assert(io_left == actual_elem);
2411
2412
            /* Store the sequence information */
2413
0
            *off++ = loc;
2414
0
            *len++ = actual_bytes;
2415
0
        } /* end if */
2416
0
        else {
2417
0
            hsize_t skip_slab; /* Temporary copy of slab[fast_dim - 1] */
2418
0
            size_t  blk_count; /* Total number of blocks left to output */
2419
0
            int     i;         /* Local index variable */
2420
2421
            /* Find first dimension w/block >1 */
2422
0
            skip_dim = fast_dim;
2423
0
            for (i = (int)(fast_dim - 1); i >= 0; i--)
2424
0
                if (tdiminfo[i].block > 1) {
2425
0
                    skip_dim = (unsigned)i;
2426
0
                    break;
2427
0
                } /* end if */
2428
0
            skip_slab = slab[skip_dim];
2429
2430
            /* Check for being able to use fast algorithm for 1-D */
2431
0
            if (0 == skip_dim) {
2432
                /* Create sequences until an entire row can't be used */
2433
0
                blk_count = tot_blk_count;
2434
0
                while (blk_count > 0) {
2435
                    /* Store the sequence information */
2436
0
                    *off++ = loc;
2437
0
                    *len++ = actual_bytes;
2438
2439
                    /* Increment offset in destination buffer */
2440
0
                    loc += skip_slab;
2441
2442
                    /* Decrement block count */
2443
0
                    blk_count--;
2444
0
                } /* end while */
2445
2446
                /* Move to the next location */
2447
0
                offset[skip_dim] += tot_blk_count;
2448
0
            } /* end if */
2449
0
            else {
2450
0
                hsize_t tmp_block[H5S_MAX_RANK]; /* Temporary block offset */
2451
0
                hsize_t skip[H5S_MAX_RANK];      /* Bytes to skip between blocks */
2452
0
                int     temp_dim;                /* Temporary rank holder */
2453
2454
                /* Set the starting block location */
2455
0
                for (u = 0; u < ndims; u++)
2456
0
                    tmp_block[u] = iter->u.hyp.off[u] - tdiminfo[u].start;
2457
2458
                /* Compute the amount to skip between sequences */
2459
0
                for (u = 0; u < ndims; u++)
2460
0
                    skip[u] = (mem_size[u] - tdiminfo[u].block) * slab[u];
2461
2462
                /* Create sequences until an entire row can't be used */
2463
0
                blk_count = tot_blk_count;
2464
0
                while (blk_count > 0) {
2465
                    /* Store the sequence information */
2466
0
                    *off++ = loc;
2467
0
                    *len++ = actual_bytes;
2468
2469
                    /* Set temporary dimension for advancing offsets */
2470
0
                    temp_dim = (int)skip_dim;
2471
2472
                    /* Increment offset in destination buffer */
2473
0
                    loc += skip_slab;
2474
2475
                    /* Increment the offset and count for the other dimensions */
2476
0
                    while (temp_dim >= 0) {
2477
                        /* Move to the next row in the current dimension */
2478
0
                        offset[temp_dim]++;
2479
0
                        tmp_block[temp_dim]++;
2480
2481
                        /* If this block is still in the range of blocks to output for the dimension, break
2482
                         * out of loop */
2483
0
                        if (tmp_block[temp_dim] < tdiminfo[temp_dim].block)
2484
0
                            break;
2485
0
                        else {
2486
0
                            offset[temp_dim] = base_offset[temp_dim];
2487
0
                            loc += skip[temp_dim];
2488
0
                            tmp_block[temp_dim] = 0;
2489
0
                        } /* end else */
2490
2491
                        /* Decrement dimension count */
2492
0
                        temp_dim--;
2493
0
                    } /* end while */
2494
2495
                    /* Decrement block count */
2496
0
                    blk_count--;
2497
0
                } /* end while */
2498
0
            }     /* end else */
2499
0
        }         /* end else */
2500
2501
        /* Update the iterator, if there were any blocks used */
2502
2503
        /* Decrement the number of elements left in selection */
2504
0
        iter->elmt_left -= tot_blk_count * actual_elem;
2505
2506
        /* Check if there are elements left in iterator */
2507
0
        if (iter->elmt_left > 0) {
2508
            /* Update the iterator with the location we stopped */
2509
            /* (Subtract out the selection offset) */
2510
0
            for (u = 0; u < ndims; u++)
2511
0
                iter->u.hyp.off[u] = (hsize_t)((hssize_t)offset[u] - sel_off[u]);
2512
0
        } /* end if */
2513
2514
        /* Increment the number of sequences generated */
2515
0
        *nseq += tot_blk_count;
2516
2517
        /* Increment the number of elements used */
2518
0
        *nelem += tot_blk_count * actual_elem;
2519
0
    } /* end if */
2520
2521
    /* Check for partial block, with room for another sequence */
2522
0
    if (io_left > (tot_blk_count * actual_elem) && tot_blk_count < maxseq) {
2523
0
        size_t elmt_remainder; /* Elements remaining */
2524
2525
        /* Compute elements left */
2526
0
        elmt_remainder = io_left - (tot_blk_count * actual_elem);
2527
0
        assert(elmt_remainder < fast_dim_block);
2528
0
        assert(elmt_remainder > 0);
2529
2530
        /* Store the sequence information */
2531
0
        *off++ = loc;
2532
0
        *len++ = elmt_remainder * elem_size;
2533
2534
        /* Update the iterator with the location we stopped */
2535
0
        iter->u.hyp.off[fast_dim] += (hsize_t)elmt_remainder;
2536
2537
        /* Decrement the number of elements left in selection */
2538
0
        iter->elmt_left -= elmt_remainder;
2539
2540
        /* Increment the number of sequences generated */
2541
0
        (*nseq)++;
2542
2543
        /* Increment the number of elements used */
2544
0
        *nelem += elmt_remainder;
2545
0
    } /* end if */
2546
2547
    /* Sanity check */
2548
0
    assert(*nseq > 0);
2549
0
    assert(*nelem > 0);
2550
2551
0
    FUNC_LEAVE_NOAPI(SUCCEED)
2552
0
} /* end H5S__hyper_iter_get_seq_list_single() */
2553
2554
/*--------------------------------------------------------------------------
2555
 NAME
2556
    H5S__hyper_iter_get_seq_list
2557
 PURPOSE
2558
    Create a list of offsets & lengths for a selection
2559
 USAGE
2560
    herr_t H5S__hyper_iter_get_seq_list(iter,maxseq,maxelem,nseq,nelem,off,len)
2561
        H5S_t *space;           IN: Dataspace containing selection to use.
2562
        H5S_sel_iter_t *iter;   IN/OUT: Selection iterator describing last
2563
                                    position of interest in selection.
2564
        size_t maxseq;          IN: Maximum number of sequences to generate
2565
        size_t maxelem;         IN: Maximum number of elements to include in the
2566
                                    generated sequences
2567
        size_t *nseq;           OUT: Actual number of sequences generated
2568
        size_t *nelem;          OUT: Actual number of elements in sequences generated
2569
        hsize_t *off;           OUT: Array of offsets (in bytes)
2570
        size_t *len;            OUT: Array of lengths (in bytes)
2571
 RETURNS
2572
    Non-negative on success/Negative on failure.
2573
 DESCRIPTION
2574
    Use the selection in the dataspace to generate a list of byte offsets and
2575
    lengths for the region(s) selected.  Start/Restart from the position in the
2576
    ITER parameter.  The number of sequences generated is limited by the MAXSEQ
2577
    parameter and the number of sequences actually generated is stored in the
2578
    NSEQ parameter.
2579
 GLOBAL VARIABLES
2580
 COMMENTS, BUGS, ASSUMPTIONS
2581
 EXAMPLES
2582
 REVISION LOG
2583
--------------------------------------------------------------------------*/
2584
static herr_t
2585
H5S__hyper_iter_get_seq_list(H5S_sel_iter_t *iter, size_t maxseq, size_t maxelem, size_t *nseq, size_t *nelem,
2586
                             hsize_t *off, size_t *len)
2587
0
{
2588
0
    herr_t ret_value = FAIL; /* return value */
2589
2590
0
    FUNC_ENTER_PACKAGE_NOERR
2591
2592
    /* Check args */
2593
0
    assert(iter);
2594
0
    assert(iter->elmt_left > 0);
2595
0
    assert(maxseq > 0);
2596
0
    assert(maxelem > 0);
2597
0
    assert(nseq);
2598
0
    assert(nelem);
2599
0
    assert(off);
2600
0
    assert(len);
2601
2602
    /* Check for the special case of just one H5Sselect_hyperslab call made */
2603
0
    if (iter->u.hyp.diminfo_valid) {
2604
0
        const H5S_hyper_dim_t *tdiminfo;     /* Temporary pointer to diminfo information */
2605
0
        const hssize_t        *sel_off;      /* Selection offset in dataspace */
2606
0
        unsigned               ndims;        /* Number of dimensions of dataset */
2607
0
        unsigned               fast_dim;     /* Rank of the fastest changing dimension for the dataspace */
2608
0
        bool                   single_block; /* Whether the selection is a single block */
2609
0
        unsigned               u;            /* Local index variable */
2610
2611
        /* Set a local copy of the diminfo pointer */
2612
0
        tdiminfo = iter->u.hyp.diminfo;
2613
2614
        /* Check if this is a "flattened" regular hyperslab selection */
2615
0
        if (iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < iter->rank) {
2616
            /* Set the aliases for a few important dimension ranks */
2617
0
            ndims = iter->u.hyp.iter_rank;
2618
2619
            /* Set the local copy of the selection offset */
2620
0
            sel_off = iter->u.hyp.sel_off;
2621
0
        } /* end if */
2622
0
        else {
2623
            /* Set the aliases for a few important dimension ranks */
2624
0
            ndims = iter->rank;
2625
2626
            /* Set the local copy of the selection offset */
2627
0
            sel_off = iter->sel_off;
2628
0
        } /* end else */
2629
0
        fast_dim = ndims - 1;
2630
2631
        /* Check if we stopped in the middle of a sequence of elements */
2632
0
        if ((iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start) % tdiminfo[fast_dim].stride != 0 ||
2633
0
            ((iter->u.hyp.off[fast_dim] != tdiminfo[fast_dim].start) && tdiminfo[fast_dim].count == 1)) {
2634
0
            hsize_t *slab;        /* Hyperslab size */
2635
0
            hsize_t  loc;         /* Coordinate offset */
2636
0
            size_t   leftover;    /* The number of elements left over from the last sequence */
2637
0
            size_t   actual_elem; /* The actual number of elements to count */
2638
0
            size_t   elem_size;   /* Size of each element iterating over */
2639
2640
            /* Calculate the number of elements left in the sequence */
2641
0
            if (tdiminfo[fast_dim].count == 1) {
2642
0
                H5_CHECKED_ASSIGN(leftover, size_t,
2643
0
                                  tdiminfo[fast_dim].block -
2644
0
                                      (iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start),
2645
0
                                  hsize_t);
2646
0
            } /* end if */
2647
0
            else {
2648
0
                H5_CHECKED_ASSIGN(
2649
0
                    leftover, size_t,
2650
0
                    tdiminfo[fast_dim].block -
2651
0
                        ((iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start) % tdiminfo[fast_dim].stride),
2652
0
                    hsize_t);
2653
0
            } /* end else */
2654
2655
            /* Make certain that we don't write too many */
2656
0
            actual_elem = MIN3(leftover, (size_t)iter->elmt_left, maxelem);
2657
2658
            /* Set up some local variables */
2659
0
            elem_size = iter->elmt_size;
2660
0
            slab      = iter->u.hyp.slab;
2661
2662
            /* Compute the initial buffer offset */
2663
0
            for (u = 0, loc = 0; u < ndims; u++)
2664
0
                loc += ((hsize_t)((hssize_t)iter->u.hyp.off[u] + sel_off[u])) * slab[u];
2665
2666
            /* Add a new sequence */
2667
0
            off[0] = loc;
2668
0
            H5_CHECKED_ASSIGN(len[0], size_t, actual_elem * elem_size, hsize_t);
2669
2670
            /* Increment sequence array locations */
2671
0
            off++;
2672
0
            len++;
2673
2674
            /* Advance the hyperslab iterator */
2675
0
            H5S__hyper_iter_next(iter, actual_elem);
2676
2677
            /* Decrement the number of elements left in selection */
2678
0
            iter->elmt_left -= actual_elem;
2679
2680
            /* Decrement element/sequence limits */
2681
0
            maxelem -= actual_elem;
2682
0
            maxseq--;
2683
2684
            /* Set the number of sequences generated and elements used */
2685
0
            *nseq  = 1;
2686
0
            *nelem = actual_elem;
2687
2688
            /* Check for using up all the sequences/elements */
2689
0
            if (0 == iter->elmt_left || 0 == maxelem || 0 == maxseq)
2690
0
                return (SUCCEED);
2691
0
        } /* end if */
2692
0
        else {
2693
            /* Reset the number of sequences generated and elements used */
2694
0
            *nseq  = 0;
2695
0
            *nelem = 0;
2696
0
        } /* end else */
2697
2698
        /* Check for a single block selected */
2699
0
        single_block = true;
2700
0
        for (u = 0; u < ndims; u++)
2701
0
            if (1 != tdiminfo[u].count) {
2702
0
                single_block = false;
2703
0
                break;
2704
0
            } /* end if */
2705
2706
        /* Check for single block selection */
2707
0
        if (single_block)
2708
            /* Use single-block optimized call to generate sequence list */
2709
0
            ret_value = H5S__hyper_iter_get_seq_list_single(iter, maxseq, maxelem, nseq, nelem, off, len);
2710
0
        else
2711
            /* Use optimized call to generate sequence list */
2712
0
            ret_value = H5S__hyper_iter_get_seq_list_opt(iter, maxseq, maxelem, nseq, nelem, off, len);
2713
0
    } /* end if */
2714
0
    else
2715
        /* Call the general sequence generator routine */
2716
0
        ret_value = H5S__hyper_iter_get_seq_list_gen(iter, maxseq, maxelem, nseq, nelem, off, len);
2717
2718
0
    FUNC_LEAVE_NOAPI(ret_value)
2719
0
} /* end H5S__hyper_iter_get_seq_list() */
2720
2721
/*--------------------------------------------------------------------------
2722
 NAME
2723
    H5S__hyper_iter_release
2724
 PURPOSE
2725
    Release hyperslab selection iterator information for a dataspace
2726
 USAGE
2727
    herr_t H5S__hyper_iter_release(iter)
2728
        H5S_sel_iter_t *iter;       IN: Pointer to selection iterator
2729
 RETURNS
2730
    Non-negative on success/Negative on failure
2731
 DESCRIPTION
2732
    Releases all information for a dataspace hyperslab selection iterator
2733
 GLOBAL VARIABLES
2734
 COMMENTS, BUGS, ASSUMPTIONS
2735
 EXAMPLES
2736
 REVISION LOG
2737
--------------------------------------------------------------------------*/
2738
static herr_t
2739
H5S__hyper_iter_release(H5S_sel_iter_t *iter)
2740
0
{
2741
0
    herr_t ret_value = SUCCEED;
2742
2743
0
    FUNC_ENTER_PACKAGE
2744
2745
    /* Check args */
2746
0
    assert(iter);
2747
2748
    /* Free the copy of the hyperslab selection span tree */
2749
0
    if (iter->u.hyp.spans != NULL)
2750
0
        if (H5S__hyper_free_span_info(iter->u.hyp.spans) < 0)
2751
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
2752
2753
0
done:
2754
0
    FUNC_LEAVE_NOAPI(ret_value)
2755
0
} /* end H5S__hyper_iter_release() */
2756
2757
/*--------------------------------------------------------------------------
2758
 NAME
2759
    H5S__hyper_new_span
2760
 PURPOSE
2761
    Make a new hyperslab span node
2762
 USAGE
2763
    H5S_hyper_span_t *H5S__hyper_new_span(low, high, down, next)
2764
        hsize_t low, high;         IN: Low and high bounds for new span node
2765
        H5S_hyper_span_info_t *down;     IN: Down span tree for new node
2766
        H5S_hyper_span_t *next;     IN: Next span for new node
2767
 RETURNS
2768
    Pointer to new span node on success, NULL on failure
2769
 DESCRIPTION
2770
    Allocate and initialize a new hyperslab span node, filling in the low &
2771
    high bounds, the down span and next span pointers also.  Increment the
2772
    reference count of the 'down span' if applicable.
2773
 GLOBAL VARIABLES
2774
 COMMENTS, BUGS, ASSUMPTIONS
2775
 EXAMPLES
2776
 REVISION LOG
2777
--------------------------------------------------------------------------*/
2778
static H5S_hyper_span_t *
2779
H5S__hyper_new_span(hsize_t low, hsize_t high, H5S_hyper_span_info_t *down, H5S_hyper_span_t *next)
2780
0
{
2781
0
    H5S_hyper_span_t *ret_value = NULL; /* Return value */
2782
2783
0
    FUNC_ENTER_PACKAGE
2784
2785
    /* Allocate a new span node */
2786
0
    if (NULL == (ret_value = H5FL_MALLOC(H5S_hyper_span_t)))
2787
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
2788
2789
    /* Copy the span's basic information */
2790
0
    ret_value->low  = low;
2791
0
    ret_value->high = high;
2792
0
    ret_value->down = down;
2793
0
    ret_value->next = next;
2794
2795
    /* Increment the reference count of the 'down span' if there is one */
2796
0
    if (ret_value->down)
2797
0
        ret_value->down->count++;
2798
2799
0
done:
2800
0
    FUNC_LEAVE_NOAPI(ret_value)
2801
0
} /* end H5S__hyper_new_span() */
2802
2803
/*--------------------------------------------------------------------------
2804
 NAME
2805
    H5S__hyper_new_span_info
2806
 PURPOSE
2807
    Make a new hyperslab span info node
2808
 USAGE
2809
    H5S_hyper_span_info_t *H5S__hyper_new_span_info(rank)
2810
        unsigned rank;          IN: Rank of span info, in selection
2811
 RETURNS
2812
    Pointer to new span node info on success, NULL on failure
2813
 DESCRIPTION
2814
    Allocate and initialize a new hyperslab span info node of a given rank,
2815
    setting up the low & high bound array pointers.
2816
 GLOBAL VARIABLES
2817
 COMMENTS, BUGS, ASSUMPTIONS
2818
    Note that this uses the C99 "flexible array member" feature.
2819
 EXAMPLES
2820
 REVISION LOG
2821
--------------------------------------------------------------------------*/
2822
static H5S_hyper_span_info_t *
2823
H5S__hyper_new_span_info(unsigned rank)
2824
0
{
2825
0
    H5S_hyper_span_info_t *ret_value = NULL; /* Return value */
2826
2827
0
    FUNC_ENTER_PACKAGE
2828
2829
    /* Sanity check */
2830
0
    assert(rank <= H5S_MAX_RANK);
2831
2832
0
    if (rank == 0)
2833
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, NULL, "dataspace has invalid extent");
2834
2835
    /* Allocate a new span info node */
2836
0
    if (NULL == (ret_value = (H5S_hyper_span_info_t *)H5FL_ARR_CALLOC(hbounds_t, rank * 2)))
2837
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span info");
2838
2839
    /* Set low & high bound pointers into the 'bounds' array */
2840
0
    ret_value->low_bounds  = ret_value->bounds;
2841
0
    ret_value->high_bounds = &ret_value->bounds[rank];
2842
2843
0
done:
2844
0
    FUNC_LEAVE_NOAPI(ret_value)
2845
0
} /* end H5S__hyper_new_span_info() */
2846
2847
/*--------------------------------------------------------------------------
2848
 NAME
2849
    H5S__hyper_copy_span_helper
2850
 PURPOSE
2851
    Helper routine to copy a hyperslab span tree
2852
 USAGE
2853
    H5S_hyper_span_info_t * H5S__hyper_copy_span_helper(spans, rank, op_info_i, op_gen)
2854
        H5S_hyper_span_info_t *spans;   IN: Span tree to copy
2855
        unsigned rank;                  IN: Rank of span tree
2856
        unsigned op_info_i;             IN: Index of op info to use
2857
        uint64_t op_gen;                IN: Operation generation
2858
 RETURNS
2859
    Pointer to the copied span tree on success, NULL on failure
2860
 DESCRIPTION
2861
    Copy a hyperslab span tree, using reference counting as appropriate.
2862
 GLOBAL VARIABLES
2863
 COMMENTS, BUGS, ASSUMPTIONS
2864
 EXAMPLES
2865
 REVISION LOG
2866
--------------------------------------------------------------------------*/
2867
static H5S_hyper_span_info_t *
2868
H5S__hyper_copy_span_helper(H5S_hyper_span_info_t *spans, unsigned rank, unsigned op_info_i, uint64_t op_gen)
2869
0
{
2870
0
    H5S_hyper_span_t      *span;             /* Hyperslab span */
2871
0
    H5S_hyper_span_t      *new_span;         /* Temporary hyperslab span */
2872
0
    H5S_hyper_span_t      *prev_span;        /* Previous hyperslab span */
2873
0
    H5S_hyper_span_info_t *new_down;         /* New down span tree */
2874
0
    H5S_hyper_span_info_t *ret_value = NULL; /* Return value */
2875
2876
0
    FUNC_ENTER_PACKAGE
2877
2878
    /* Sanity checks */
2879
0
    assert(spans);
2880
2881
    /* Check if the span tree was already copied */
2882
0
    if (spans->op_info[op_info_i].op_gen == op_gen) {
2883
        /* Just return the value of the already copied span tree */
2884
0
        ret_value = spans->op_info[op_info_i].u.copied;
2885
2886
        /* Increment the reference count of the span tree */
2887
0
        ret_value->count++;
2888
0
    } /* end if */
2889
0
    else {
2890
        /* Allocate a new span_info node */
2891
0
        if (NULL == (ret_value = H5S__hyper_new_span_info(rank)))
2892
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span info");
2893
2894
        /* Set the non-zero span_info information */
2895
0
        H5MM_memcpy(ret_value->low_bounds, spans->low_bounds, rank * sizeof(hsize_t));
2896
0
        H5MM_memcpy(ret_value->high_bounds, spans->high_bounds, rank * sizeof(hsize_t));
2897
0
        ret_value->count = 1;
2898
2899
        /* Set the operation generation for the span info, to avoid future copies */
2900
0
        spans->op_info[op_info_i].op_gen = op_gen;
2901
2902
        /* Set the 'copied' pointer in the node being copied to the newly allocated node */
2903
0
        spans->op_info[op_info_i].u.copied = ret_value;
2904
2905
        /* Copy over the nodes in the span list */
2906
0
        span      = spans->head;
2907
0
        prev_span = NULL;
2908
0
        while (span != NULL) {
2909
            /* Allocate a new node */
2910
0
            if (NULL == (new_span = H5S__hyper_new_span(span->low, span->high, NULL, NULL)))
2911
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
2912
2913
            /* Append to list of spans */
2914
0
            if (NULL == prev_span)
2915
0
                ret_value->head = new_span;
2916
0
            else
2917
0
                prev_span->next = new_span;
2918
2919
            /* Recurse to copy the 'down' spans, if there are any */
2920
0
            if (span->down != NULL) {
2921
0
                if (NULL == (new_down = H5S__hyper_copy_span_helper(span->down, rank - 1, op_info_i, op_gen)))
2922
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, NULL, "can't copy hyperslab spans");
2923
0
                new_span->down = new_down;
2924
0
            } /* end if */
2925
2926
            /* Update the previous (new) span */
2927
0
            prev_span = new_span;
2928
2929
            /* Advance to next span */
2930
0
            span = span->next;
2931
0
        } /* end while */
2932
2933
        /* Retain a pointer to the last span */
2934
0
        ret_value->tail = prev_span;
2935
0
    } /* end else */
2936
2937
0
done:
2938
0
    FUNC_LEAVE_NOAPI(ret_value)
2939
0
} /* end H5S__hyper_copy_span_helper() */
2940
2941
/*--------------------------------------------------------------------------
2942
 NAME
2943
    H5S__hyper_copy_span
2944
 PURPOSE
2945
    Copy a hyperslab span tree
2946
 USAGE
2947
    H5S_hyper_span_info_t * H5S__hyper_copy_span(span_info, rank)
2948
        H5S_hyper_span_info_t *span_info;       IN: Span tree to copy
2949
        unsigned rank;                          IN: Rank of span tree
2950
 RETURNS
2951
    Pointer to the copied span tree on success, NULL on failure
2952
 DESCRIPTION
2953
    Copy a hyperslab span tree, using reference counting as appropriate.
2954
    (Which means that just the nodes in the top span tree are duplicated and
2955
    the reference counts of their 'down spans' are just incremented)
2956
 GLOBAL VARIABLES
2957
 COMMENTS, BUGS, ASSUMPTIONS
2958
 EXAMPLES
2959
 REVISION LOG
2960
--------------------------------------------------------------------------*/
2961
static H5S_hyper_span_info_t *
2962
H5S__hyper_copy_span(H5S_hyper_span_info_t *spans, unsigned rank)
2963
0
{
2964
0
    uint64_t               op_gen;           /* Operation generation value */
2965
0
    H5S_hyper_span_info_t *ret_value = NULL; /* Return value */
2966
2967
0
    FUNC_ENTER_PACKAGE
2968
2969
    /* Sanity check */
2970
0
    assert(spans);
2971
2972
    /* Acquire an operation generation value for this operation */
2973
0
    op_gen = H5S__hyper_get_op_gen();
2974
2975
    /* Copy the hyperslab span tree */
2976
    /* Always use op_info[0] since we own this op_info, so there can be no
2977
     * simultaneous operations */
2978
0
    if (NULL == (ret_value = H5S__hyper_copy_span_helper(spans, rank, 0, op_gen)))
2979
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, NULL, "can't copy hyperslab span tree");
2980
2981
0
done:
2982
0
    FUNC_LEAVE_NOAPI(ret_value)
2983
0
} /* end H5S__hyper_copy_span() */
2984
2985
/*--------------------------------------------------------------------------
2986
 NAME
2987
    H5S__hyper_cmp_spans
2988
 PURPOSE
2989
    Check if two hyperslab span trees are the same
2990
 USAGE
2991
    bool H5S__hyper_cmp_spans(span1, span2)
2992
        H5S_hyper_span_info_t *span_info1;      IN: First span tree to compare
2993
        H5S_hyper_span_info_t *span_info2;      IN: Second span tree to compare
2994
 RETURNS
2995
    true (1) or false (0) on success, can't fail
2996
 DESCRIPTION
2997
    Compare two hyperslab span trees to determine if they refer to the same
2998
    selection.  If span1 & span2 are both NULL, that counts as equal.
2999
 GLOBAL VARIABLES
3000
 COMMENTS, BUGS, ASSUMPTIONS
3001
 EXAMPLES
3002
 REVISION LOG
3003
--------------------------------------------------------------------------*/
3004
static H5_ATTR_PURE bool
3005
H5S__hyper_cmp_spans(const H5S_hyper_span_info_t *span_info1, const H5S_hyper_span_info_t *span_info2)
3006
0
{
3007
0
    bool ret_value = true; /* Return value */
3008
3009
0
    FUNC_ENTER_PACKAGE_NOERR
3010
3011
    /* Check for redundant comparison (or both spans being NULL) */
3012
0
    if (span_info1 != span_info2) {
3013
        /* Check for one span being NULL */
3014
0
        if (span_info1 == NULL || span_info2 == NULL)
3015
0
            HGOTO_DONE(false);
3016
0
        else {
3017
            /* Compare low & high bounds for this span list */
3018
            /* (Could compare lower dimensions also, but not certain if
3019
             *      that's worth it. - QAK, 2019/01/23)
3020
             */
3021
0
            if (span_info1->low_bounds[0] != span_info2->low_bounds[0])
3022
0
                HGOTO_DONE(false);
3023
0
            else if (span_info1->high_bounds[0] != span_info2->high_bounds[0])
3024
0
                HGOTO_DONE(false);
3025
0
            else {
3026
0
                const H5S_hyper_span_t *span1;
3027
0
                const H5S_hyper_span_t *span2;
3028
3029
                /* Get the pointers to the actual lists of spans */
3030
0
                span1 = span_info1->head;
3031
0
                span2 = span_info2->head;
3032
3033
                /* Sanity checking */
3034
0
                assert(span1);
3035
0
                assert(span2);
3036
3037
                /* infinite loop which must be broken out of */
3038
0
                while (1) {
3039
                    /* Check for both spans being NULL */
3040
0
                    if (span1 == NULL && span2 == NULL)
3041
0
                        HGOTO_DONE(true);
3042
0
                    else {
3043
                        /* Check for one span being NULL */
3044
0
                        if (span1 == NULL || span2 == NULL)
3045
0
                            HGOTO_DONE(false);
3046
0
                        else {
3047
                            /* Check if the actual low & high span information is the same */
3048
0
                            if (span1->low != span2->low || span1->high != span2->high)
3049
0
                                HGOTO_DONE(false);
3050
0
                            else {
3051
0
                                if (span1->down != NULL || span2->down != NULL) {
3052
0
                                    if (!H5S__hyper_cmp_spans(span1->down, span2->down))
3053
0
                                        HGOTO_DONE(false);
3054
0
                                    else {
3055
                                        /* Keep going... */
3056
0
                                    } /* end else */
3057
0
                                }     /* end if */
3058
0
                                else {
3059
                                    /* Keep going... */
3060
0
                                } /* end else */
3061
0
                            }     /* end else */
3062
0
                        }         /* end else */
3063
0
                    }             /* end else */
3064
3065
                    /* Advance to the next nodes in the span list */
3066
0
                    span1 = span1->next;
3067
0
                    span2 = span2->next;
3068
0
                } /* end while */
3069
0
            }     /* end else */
3070
0
        }         /* end else */
3071
0
    }             /* end if */
3072
3073
    /* Fall through, with default return value of 'true' if spans were already visited */
3074
3075
0
done:
3076
0
    FUNC_LEAVE_NOAPI(ret_value)
3077
0
} /* end H5S__hyper_cmp_spans() */
3078
3079
/*--------------------------------------------------------------------------
3080
 NAME
3081
    H5S__hyper_free_span_info
3082
 PURPOSE
3083
    Free a hyperslab span info node
3084
 USAGE
3085
    herr_t H5S__hyper_free_span_info(span_info)
3086
        H5S_hyper_span_info_t *span_info;      IN: Span info node to free
3087
 RETURNS
3088
    SUCCEED/FAIL
3089
 DESCRIPTION
3090
    Free a hyperslab span info node, along with all the span nodes and the
3091
    'down spans' from the nodes, if reducing their reference count to zero
3092
    indicates it is appropriate to do so.
3093
 GLOBAL VARIABLES
3094
 COMMENTS, BUGS, ASSUMPTIONS
3095
 EXAMPLES
3096
 REVISION LOG
3097
--------------------------------------------------------------------------*/
3098
static herr_t
3099
H5S__hyper_free_span_info(H5S_hyper_span_info_t *span_info)
3100
0
{
3101
0
    herr_t ret_value = SUCCEED;
3102
3103
0
    FUNC_ENTER_PACKAGE
3104
3105
    /* Sanity check */
3106
0
    if (!span_info)
3107
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "span_info pointer was NULL");
3108
3109
    /* Decrement the span tree's reference count */
3110
0
    span_info->count--;
3111
3112
    /* Free the span tree if the reference count drops to zero */
3113
0
    if (span_info->count == 0) {
3114
0
        H5S_hyper_span_t *span; /* Pointer to spans to iterate over */
3115
3116
        /* Work through the list of spans pointed to by this 'info' node */
3117
0
        span = span_info->head;
3118
0
        while (span != NULL) {
3119
0
            H5S_hyper_span_t *next_span; /* Pointer to next span to iterate over */
3120
3121
            /* Keep a pointer to the next span */
3122
0
            next_span = span->next;
3123
3124
            /* Free the current span */
3125
0
            if (H5S__hyper_free_span(span) < 0)
3126
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span");
3127
3128
            /* Advance to next span */
3129
0
            span = next_span;
3130
0
        }
3131
3132
        /* Free this span info */
3133
0
        span_info = (H5S_hyper_span_info_t *)H5FL_ARR_FREE(hbounds_t, span_info);
3134
0
    }
3135
3136
0
done:
3137
0
    FUNC_LEAVE_NOAPI(ret_value)
3138
0
} /* end H5S__hyper_free_span_info() */
3139
3140
/*--------------------------------------------------------------------------
3141
 NAME
3142
    H5S__hyper_free_span
3143
 PURPOSE
3144
    Free a hyperslab span node
3145
 USAGE
3146
    herr_t H5S__hyper_free_span(span)
3147
        H5S_hyper_span_t *span;      IN: Span node to free
3148
 RETURNS
3149
    SUCCEED/FAIL
3150
 DESCRIPTION
3151
    Free a hyperslab span node, along with the 'down spans' from the node,
3152
    if reducing their reference count to zero indicates it is appropriate to
3153
    do so.
3154
 GLOBAL VARIABLES
3155
 COMMENTS, BUGS, ASSUMPTIONS
3156
 EXAMPLES
3157
 REVISION LOG
3158
--------------------------------------------------------------------------*/
3159
static herr_t
3160
H5S__hyper_free_span(H5S_hyper_span_t *span)
3161
0
{
3162
0
    herr_t ret_value = SUCCEED;
3163
3164
0
    FUNC_ENTER_PACKAGE
3165
3166
    /* Sanity check */
3167
0
    assert(span);
3168
3169
    /* Decrement the reference count of the 'down spans', freeing them if appropriate */
3170
0
    if (span->down != NULL)
3171
0
        if (H5S__hyper_free_span_info(span->down) < 0)
3172
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
3173
3174
    /* Free this span */
3175
0
    span = H5FL_FREE(H5S_hyper_span_t, span);
3176
3177
0
done:
3178
0
    FUNC_LEAVE_NOAPI(ret_value)
3179
0
} /* end H5S__hyper_free_span() */
3180
3181
/*--------------------------------------------------------------------------
3182
 NAME
3183
    H5S__hyper_copy
3184
 PURPOSE
3185
    Copy a selection from one dataspace to another
3186
 USAGE
3187
    herr_t H5S__hyper_copy(dst, src, share_selection)
3188
        H5S_t *dst;  OUT: Pointer to the destination dataspace
3189
        H5S_t *src;  IN: Pointer to the source dataspace
3190
        bool;     IN: Whether to share the selection between the dataspaces
3191
 RETURNS
3192
    Non-negative on success, negative on failure
3193
 DESCRIPTION
3194
    Copies all the hyperslab selection information from the source
3195
    dataspace to the destination dataspace.
3196
3197
    If the SHARE_SELECTION flag is set, then the selection can be shared
3198
    between the source and destination dataspaces.  (This should only occur in
3199
    situations where the destination dataspace will immediately change to a new
3200
    selection)
3201
 GLOBAL VARIABLES
3202
 COMMENTS, BUGS, ASSUMPTIONS
3203
 EXAMPLES
3204
 REVISION LOG
3205
--------------------------------------------------------------------------*/
3206
static herr_t
3207
H5S__hyper_copy(H5S_t *dst, const H5S_t *src, bool share_selection)
3208
0
{
3209
0
    H5S_hyper_sel_t       *dst_hslab = NULL;    /* Pointer to destination hyperslab info */
3210
0
    const H5S_hyper_sel_t *src_hslab;           /* Pointer to source hyperslab info */
3211
0
    herr_t                 ret_value = SUCCEED; /* Return value */
3212
3213
0
    FUNC_ENTER_PACKAGE
3214
3215
    /* Sanity check */
3216
0
    assert(src);
3217
0
    assert(dst);
3218
3219
    /* Allocate space for the hyperslab selection information */
3220
0
    if (NULL == (dst_hslab = H5FL_MALLOC(H5S_hyper_sel_t)))
3221
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab info");
3222
0
    dst_hslab->span_lst = NULL;
3223
3224
    /* Set temporary pointers */
3225
0
    src_hslab = src->select.sel_info.hslab;
3226
3227
    /* Copy the hyperslab information */
3228
0
    dst_hslab->diminfo_valid = src_hslab->diminfo_valid;
3229
0
    if (src_hslab->diminfo_valid == H5S_DIMINFO_VALID_YES)
3230
0
        H5MM_memcpy(&dst_hslab->diminfo, &src_hslab->diminfo, sizeof(H5S_hyper_diminfo_t));
3231
3232
    /* Check if there is hyperslab span information to copy */
3233
    /* (Regular hyperslab information is copied with the selection structure) */
3234
0
    if (src_hslab->span_lst != NULL) {
3235
0
        if (share_selection) {
3236
            /* Share the source's span tree by incrementing the reference count on it */
3237
0
            dst_hslab->span_lst = src_hslab->span_lst;
3238
0
            dst_hslab->span_lst->count++;
3239
0
        } /* end if */
3240
0
        else {
3241
            /* Copy the hyperslab span information */
3242
0
            dst_hslab->span_lst = H5S__hyper_copy_span(src_hslab->span_lst, src->extent.rank);
3243
0
            if (NULL == dst_hslab->span_lst)
3244
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy hyperslab span information");
3245
0
        }
3246
0
    } /* end if */
3247
0
    else
3248
0
        dst_hslab->span_lst = NULL;
3249
3250
    /* Copy the unlimited dimension info */
3251
0
    dst_hslab->unlim_dim          = src_hslab->unlim_dim;
3252
0
    dst_hslab->num_elem_non_unlim = src_hslab->num_elem_non_unlim;
3253
3254
0
    dst->select.sel_info.hslab = dst_hslab;
3255
3256
0
done:
3257
0
    if (ret_value < 0) {
3258
0
        if (dst_hslab) {
3259
0
            if (dst_hslab->span_lst && H5S__hyper_free_span_info(dst_hslab->span_lst) < 0)
3260
0
                HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free hyperslab span information");
3261
3262
0
            H5FL_FREE(H5S_hyper_sel_t, dst_hslab);
3263
0
        }
3264
0
    }
3265
3266
0
    FUNC_LEAVE_NOAPI(ret_value)
3267
0
} /* end H5S__hyper_copy() */
3268
3269
/*--------------------------------------------------------------------------
3270
 NAME
3271
    H5S__hyper_is_valid
3272
 PURPOSE
3273
    Check whether the selection fits within the extent, with the current
3274
    offset defined.
3275
 USAGE
3276
    htri_t H5S__hyper_is_valid(space);
3277
        H5S_t *space;             IN: Dataspace pointer to query
3278
 RETURNS
3279
    true if the selection fits within the extent, false if it does not and
3280
        Negative on an error.
3281
 DESCRIPTION
3282
    Determines if the current selection at the current offset fits within the
3283
    extent for the dataspace.
3284
 GLOBAL VARIABLES
3285
 COMMENTS, BUGS, ASSUMPTIONS
3286
 EXAMPLES
3287
 REVISION LOG
3288
--------------------------------------------------------------------------*/
3289
static htri_t
3290
H5S__hyper_is_valid(const H5S_t *space)
3291
0
{
3292
0
    const hsize_t *low_bounds, *high_bounds; /* Pointers to the correct pair of low & high bounds */
3293
0
    unsigned       u;                        /* Counter */
3294
0
    htri_t         ret_value = true;         /* return value */
3295
3296
0
    FUNC_ENTER_PACKAGE_NOERR
3297
3298
0
    assert(space);
3299
3300
    /* Check if dataspace has scalar or null extent, which are
3301
     * both unsupported by hyperslab selections
3302
     */
3303
0
    if (H5S_SCALAR == H5S_GET_EXTENT_TYPE(space))
3304
0
        HGOTO_DONE(false);
3305
0
    if (H5S_NULL == H5S_GET_EXTENT_TYPE(space))
3306
0
        HGOTO_DONE(false);
3307
3308
    /* Check for unlimited selection */
3309
0
    if (space->select.sel_info.hslab->unlim_dim >= 0)
3310
0
        HGOTO_DONE(false);
3311
3312
    /* Check which set of low & high bounds we should be using */
3313
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
3314
0
        low_bounds  = space->select.sel_info.hslab->diminfo.low_bounds;
3315
0
        high_bounds = space->select.sel_info.hslab->diminfo.high_bounds;
3316
0
    } /* end if */
3317
0
    else {
3318
0
        low_bounds  = space->select.sel_info.hslab->span_lst->low_bounds;
3319
0
        high_bounds = space->select.sel_info.hslab->span_lst->high_bounds;
3320
0
    } /* end else */
3321
3322
    /* Check each dimension */
3323
0
    for (u = 0; u < space->extent.rank; u++) {
3324
        /* Bounds check the selected point + offset against the extent */
3325
0
        if (((hssize_t)low_bounds[u] + space->select.offset[u]) < 0)
3326
0
            HGOTO_DONE(false);
3327
0
        if ((high_bounds[u] + (hsize_t)space->select.offset[u]) >= space->extent.size[u])
3328
0
            HGOTO_DONE(false);
3329
0
    } /* end for */
3330
3331
0
done:
3332
0
    FUNC_LEAVE_NOAPI(ret_value)
3333
0
} /* end H5S__hyper_is_valid() */
3334
3335
/*--------------------------------------------------------------------------
3336
 NAME
3337
    H5S__hyper_span_nblocks_helper
3338
 PURPOSE
3339
    Helper routine to count the number of blocks in a span tree
3340
 USAGE
3341
    hsize_t H5S__hyper_span_nblocks_helper(spans, op_info_i, op_gen)
3342
        H5S_hyper_span_info_t *spans; IN: Hyperslab span tree to count blocks of
3343
        unsigned op_info_i; IN: Index of op info to use
3344
        uint64_t op_gen;   IN: Operation generation
3345
 RETURNS
3346
    Number of blocks in span tree on success; negative on failure
3347
 DESCRIPTION
3348
    Counts the number of blocks described by the spans in a span tree.
3349
 GLOBAL VARIABLES
3350
 COMMENTS, BUGS, ASSUMPTIONS
3351
 EXAMPLES
3352
 REVISION LOG
3353
--------------------------------------------------------------------------*/
3354
static hsize_t
3355
H5S__hyper_span_nblocks_helper(H5S_hyper_span_info_t *spans, unsigned op_info_i, uint64_t op_gen)
3356
0
{
3357
0
    hsize_t ret_value = 0; /* Return value */
3358
3359
0
    FUNC_ENTER_PACKAGE_NOERR
3360
3361
    /* Sanity check */
3362
0
    assert(spans);
3363
3364
    /* Check if the span tree was already counted */
3365
0
    if (spans->op_info[op_info_i].op_gen == op_gen)
3366
        /* Just return the # of blocks in the already counted span tree */
3367
0
        ret_value = spans->op_info[op_info_i].u.nblocks;
3368
0
    else {                      /* Count the number of elements in the span tree */
3369
0
        H5S_hyper_span_t *span; /* Hyperslab span */
3370
3371
0
        span = spans->head;
3372
0
        if (span->down) {
3373
0
            while (span) {
3374
                /* If there are down spans, add the total down span blocks */
3375
0
                ret_value += H5S__hyper_span_nblocks_helper(span->down, op_info_i, op_gen);
3376
3377
                /* Advance to next span */
3378
0
                span = span->next;
3379
0
            } /* end while */
3380
0
        }     /* end if */
3381
0
        else {
3382
0
            while (span) {
3383
                /* If there are no down spans, just count the block in this span */
3384
0
                ret_value++;
3385
3386
                /* Advance to next span */
3387
0
                span = span->next;
3388
0
            } /* end while */
3389
0
        }     /* end else */
3390
3391
        /* Set the operation generation for this span tree, to avoid re-computing */
3392
0
        spans->op_info[op_info_i].op_gen = op_gen;
3393
3394
        /* Hold a copy of the # of blocks */
3395
0
        spans->op_info[op_info_i].u.nblocks = ret_value;
3396
0
    } /* end else */
3397
3398
0
    FUNC_LEAVE_NOAPI(ret_value)
3399
0
} /* end H5S__hyper_span_nblocks_helper() */
3400
3401
/*--------------------------------------------------------------------------
3402
 NAME
3403
    H5S__hyper_span_nblocks
3404
 PURPOSE
3405
    Count the number of blocks in a span tree
3406
 USAGE
3407
    hsize_t H5S__hyper_span_nblocks(spans)
3408
        H5S_hyper_span_info_t *spans; IN: Hyperslab span tree to count blocks of
3409
 RETURNS
3410
    Number of blocks in span tree on success; negative on failure
3411
 DESCRIPTION
3412
    Counts the number of blocks described by the spans in a span tree.
3413
 GLOBAL VARIABLES
3414
 COMMENTS, BUGS, ASSUMPTIONS
3415
 EXAMPLES
3416
 REVISION LOG
3417
--------------------------------------------------------------------------*/
3418
static hsize_t
3419
H5S__hyper_span_nblocks(H5S_hyper_span_info_t *spans)
3420
0
{
3421
0
    hsize_t ret_value = 0; /* Return value */
3422
3423
0
    FUNC_ENTER_PACKAGE_NOERR
3424
3425
    /* Count the number of elements in the span tree */
3426
0
    if (spans != NULL) {
3427
0
        uint64_t op_gen; /* Operation generation value */
3428
3429
        /* Acquire an operation generation value for this operation */
3430
0
        op_gen = H5S__hyper_get_op_gen();
3431
3432
        /* Count the blocks */
3433
        /* Always use op_info[0] since we own this op_info, so there can be no
3434
         * simultaneous operations */
3435
0
        ret_value = H5S__hyper_span_nblocks_helper(spans, 0, op_gen);
3436
0
    } /* end if */
3437
3438
0
    FUNC_LEAVE_NOAPI(ret_value)
3439
0
} /* end H5S__hyper_span_nblocks() */
3440
3441
/*--------------------------------------------------------------------------
3442
 NAME
3443
    H5S__get_select_hyper_nblocks
3444
 PURPOSE
3445
    Get the number of hyperslab blocks in current hyperslab selection
3446
 USAGE
3447
    hsize_t H5S__get_select_hyper_nblocks(space, app_ref)
3448
        H5S_t *space;             IN: Dataspace ptr of selection to query
3449
        bool app_ref;          IN: Whether this is an appl. ref. call
3450
 RETURNS
3451
    The number of hyperslab blocks in selection on success, negative on failure
3452
 DESCRIPTION
3453
    Returns the number of hyperslab blocks in current selection for dataspace.
3454
 GLOBAL VARIABLES
3455
 COMMENTS, BUGS, ASSUMPTIONS
3456
 EXAMPLES
3457
 REVISION LOG
3458
--------------------------------------------------------------------------*/
3459
static hsize_t
3460
H5S__get_select_hyper_nblocks(const H5S_t *space, bool app_ref)
3461
0
{
3462
0
    hsize_t ret_value = 0; /* Return value */
3463
3464
0
    FUNC_ENTER_PACKAGE_NOERR
3465
3466
0
    assert(space);
3467
0
    assert(space->select.sel_info.hslab->unlim_dim < 0);
3468
3469
    /* Check for a "regular" hyperslab selection */
3470
    /* (No need to rebuild the dimension info yet -QAK) */
3471
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
3472
0
        unsigned u; /* Local index variable */
3473
3474
        /* Check each dimension */
3475
0
        for (ret_value = 1, u = 0; u < space->extent.rank; u++)
3476
0
            ret_value *= (app_ref ? space->select.sel_info.hslab->diminfo.app[u].count
3477
0
                                  : space->select.sel_info.hslab->diminfo.opt[u].count);
3478
0
    } /* end if */
3479
0
    else
3480
0
        ret_value = H5S__hyper_span_nblocks(space->select.sel_info.hslab->span_lst);
3481
3482
0
    FUNC_LEAVE_NOAPI(ret_value)
3483
0
} /* end H5S__get_select_hyper_nblocks() */
3484
3485
/*--------------------------------------------------------------------------
3486
 NAME
3487
    H5Sget_select_hyper_nblocks
3488
 PURPOSE
3489
    Get the number of hyperslab blocks in current hyperslab selection
3490
 USAGE
3491
    hssize_t H5Sget_select_hyper_nblocks(dsid)
3492
        hid_t dsid;             IN: Dataspace ID of selection to query
3493
 RETURNS
3494
    The number of hyperslab blocks in selection on success, negative on failure
3495
 DESCRIPTION
3496
    Returns the number of hyperslab blocks in current selection for dataspace.
3497
 GLOBAL VARIABLES
3498
 COMMENTS, BUGS, ASSUMPTIONS
3499
 EXAMPLES
3500
 REVISION LOG
3501
--------------------------------------------------------------------------*/
3502
hssize_t
3503
H5Sget_select_hyper_nblocks(hid_t spaceid)
3504
0
{
3505
0
    H5S_t   *space;     /* Dataspace to modify selection of */
3506
0
    hssize_t ret_value; /* return value */
3507
3508
0
    FUNC_ENTER_API(FAIL)
3509
3510
    /* Check args */
3511
0
    if (NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE)))
3512
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace");
3513
0
    if (H5S_GET_SELECT_TYPE(space) != H5S_SEL_HYPERSLABS)
3514
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a hyperslab selection");
3515
0
    if (space->select.sel_info.hslab->unlim_dim >= 0)
3516
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL,
3517
0
                    "cannot get number of blocks for unlimited selection");
3518
3519
0
    ret_value = (hssize_t)H5S__get_select_hyper_nblocks(space, true);
3520
3521
0
done:
3522
0
    FUNC_LEAVE_API(ret_value)
3523
0
} /* end H5Sget_select_hyper_nblocks() */
3524
3525
/*--------------------------------------------------------------------------
3526
 NAME
3527
    H5S__hyper_get_enc_size_real
3528
 PURPOSE
3529
    Determine the size to encode the hyperslab selection info
3530
 USAGE
3531
    hssize_t H5S__hyper_get_enc_size_real(max_size, enc_size)
3532
        hsize_t max_size:       IN: The maximum size of the hyperslab selection info
3533
        uint8_t *enc_size:      OUT:The encoding size
3534
 RETURNS
3535
    The size to encode hyperslab selection info
3536
 DESCRIPTION
3537
    Determine the size by comparing "max_size" with (2^32 - 1) and (2^16 - 1).
3538
 GLOBAL VARIABLES
3539
 COMMENTS, BUGS, ASSUMPTIONS
3540
 EXAMPLES
3541
 REVISION LOG
3542
--------------------------------------------------------------------------*/
3543
static uint8_t
3544
H5S__hyper_get_enc_size_real(hsize_t max_size)
3545
0
{
3546
0
    uint8_t ret_value = H5S_SELECT_INFO_ENC_SIZE_2;
3547
3548
0
    FUNC_ENTER_PACKAGE_NOERR
3549
3550
0
    if (max_size > H5S_UINT32_MAX)
3551
0
        ret_value = H5S_SELECT_INFO_ENC_SIZE_8;
3552
0
    else if (max_size > H5S_UINT16_MAX)
3553
0
        ret_value = H5S_SELECT_INFO_ENC_SIZE_4;
3554
0
    else
3555
0
        ret_value = H5S_SELECT_INFO_ENC_SIZE_2;
3556
3557
0
    FUNC_LEAVE_NOAPI(ret_value)
3558
0
} /* H5S__hyper_get_enc_size_real() */
3559
3560
/*--------------------------------------------------------------------------
3561
 NAME
3562
    H5S__hyper_get_version_enc_size
3563
 PURPOSE
3564
    Determine the version and encoded size to use for encoding hyperslab selection info
3565
 USAGE
3566
    hssize_t H5S__hyper_get_version_enc_size(space, block_count, version, enc_size)
3567
        const H5S_t *space:             IN: The dataspace
3568
        hsize_t block_count:            IN: The number of blocks in the selection
3569
        uint32_t *version:              OUT: The version to use for encoding
3570
        uint8_t *enc_size:              OUT: The encoded size to use
3571
3572
 RETURNS
3573
    The version and the size to encode hyperslab selection info
3574
 DESCRIPTION
3575
    Determine the version to use for encoding hyperslab selection info based
3576
    on the following:
3577
    (1) the file format setting in fapl
3578
    (2) whether the number of blocks or selection high bounds exceeds H5S_UINT32_MAX or not
3579
3580
    Determine the encoded size based on version:
3581
    For version 3, the encoded size is determined according to:
3582
    (a) regular hyperslab
3583
        (1) The maximum needed to store start/stride/count/block
3584
        (2) Special handling for count/block: need to provide room for H5S_UNLIMITED
3585
    (b) irregular hyperslab
3586
        The maximum size needed to store:
3587
            (1) the number of blocks
3588
            (2) the selection high bounds
3589
 GLOBAL VARIABLES
3590
 COMMENTS, BUGS, ASSUMPTIONS
3591
 EXAMPLES
3592
 REVISION LOG
3593
--------------------------------------------------------------------------*/
3594
static herr_t
3595
H5S__hyper_get_version_enc_size(H5S_t *space, hsize_t block_count, uint32_t *version, uint8_t *enc_size)
3596
0
{
3597
0
    hsize_t      bounds_start[H5S_MAX_RANK]; /* Starting coordinate of bounding box */
3598
0
    hsize_t      bounds_end[H5S_MAX_RANK];   /* Opposite coordinate of bounding box */
3599
0
    bool         count_up_version = false;   /* Whether number of blocks exceed H5S_UINT32_MAX */
3600
0
    bool         bound_up_version = false;   /* Whether high bounds exceed H5S_UINT32_MAX */
3601
0
    H5F_libver_t low_bound;                  /* The 'low' bound of library format versions */
3602
0
    H5F_libver_t high_bound;                 /* The 'high' bound of library format versions */
3603
0
    htri_t       is_regular;                 /* A regular hyperslab or not */
3604
0
    uint32_t     tmp_version;                /* Local temporary version */
3605
0
    unsigned     u;                          /* Local index variable */
3606
0
    herr_t       ret_value = SUCCEED;        /* Return value */
3607
3608
0
    FUNC_ENTER_PACKAGE
3609
3610
    /* Get bounding box for the selection */
3611
0
    memset(bounds_end, 0, sizeof(bounds_end));
3612
3613
0
    if (space->select.sel_info.hslab->unlim_dim < 0) /* ! H5S_UNLIMITED */
3614
        /* Get bounding box for the selection */
3615
0
        if (H5S__hyper_bounds(space, bounds_start, bounds_end) < 0)
3616
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get selection bounds");
3617
3618
    /* Determine whether the number of blocks or the high bounds in the selection exceed (2^32 - 1) */
3619
0
    if (block_count > H5S_UINT32_MAX)
3620
0
        count_up_version = true;
3621
0
    else {
3622
0
        for (u = 0; u < space->extent.rank; u++)
3623
0
            if (bounds_end[u] > H5S_UINT32_MAX) {
3624
0
                bound_up_version = true;
3625
0
                break;
3626
0
            } /* end if */
3627
0
    }         /* end else */
3628
3629
    /* Get the file's low_bound and high_bound */
3630
0
    if (H5CX_get_libver_bounds(&low_bound, &high_bound) < 0)
3631
0
        HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get low/high bounds from API context");
3632
3633
    /* Determine regular hyperslab */
3634
0
    is_regular = H5S__hyper_is_regular(space);
3635
3636
0
    if (low_bound >= H5F_LIBVER_V112 || space->select.sel_info.hslab->unlim_dim >= 0)
3637
0
        tmp_version = MAX(H5S_HYPER_VERSION_2, H5O_sds_hyper_ver_bounds[low_bound]);
3638
0
    else {
3639
0
        if (count_up_version || bound_up_version)
3640
0
            tmp_version = is_regular ? H5S_HYPER_VERSION_2 : H5S_HYPER_VERSION_3;
3641
0
        else
3642
0
            tmp_version =
3643
0
                (is_regular && block_count >= 4) ? H5O_sds_hyper_ver_bounds[low_bound] : H5S_HYPER_VERSION_1;
3644
0
    } /* end else */
3645
3646
    /* Version bounds check */
3647
0
    if (tmp_version > H5O_sds_hyper_ver_bounds[high_bound]) {
3648
        /* Fail for irregular hyperslab if exceeds 32 bits */
3649
0
        if (count_up_version)
3650
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL,
3651
0
                        "The number of blocks in hyperslab selection exceeds 2^32");
3652
0
        else if (bound_up_version)
3653
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL,
3654
0
                        "The end of bounding box in hyperslab selection exceeds 2^32");
3655
0
        else
3656
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL,
3657
0
                        "Dataspace hyperslab selection version out of bounds");
3658
0
    } /* end if */
3659
3660
    /* Set the message version */
3661
0
    *version = tmp_version;
3662
3663
    /* Determine the encoded size based on version */
3664
0
    switch (tmp_version) {
3665
0
        case H5S_HYPER_VERSION_1:
3666
0
            *enc_size = H5S_SELECT_INFO_ENC_SIZE_4;
3667
0
            break;
3668
3669
0
        case H5S_HYPER_VERSION_2:
3670
0
            *enc_size = H5S_SELECT_INFO_ENC_SIZE_8;
3671
0
            break;
3672
3673
0
        case H5S_HYPER_VERSION_3:
3674
0
            if (is_regular) {
3675
0
                uint8_t enc1, enc2;
3676
0
                hsize_t max1 = 0;
3677
0
                hsize_t max2 = 0;
3678
3679
                /* Find max for count[] and block[] */
3680
0
                for (u = 0; u < space->extent.rank; u++) {
3681
0
                    if (space->select.sel_info.hslab->diminfo.opt[u].count != H5S_UNLIMITED &&
3682
0
                        space->select.sel_info.hslab->diminfo.opt[u].count > max1)
3683
0
                        max1 = space->select.sel_info.hslab->diminfo.opt[u].count;
3684
0
                    if (space->select.sel_info.hslab->diminfo.opt[u].block != H5S_UNLIMITED &&
3685
0
                        space->select.sel_info.hslab->diminfo.opt[u].block > max1)
3686
0
                        max1 = space->select.sel_info.hslab->diminfo.opt[u].block;
3687
0
                } /* end for */
3688
3689
                /* +1 to provide room for H5S_UNLIMITED */
3690
0
                enc1 = H5S__hyper_get_enc_size_real(++max1);
3691
3692
                /* Find max for start[] and stride[] */
3693
0
                for (u = 0; u < space->extent.rank; u++) {
3694
0
                    if (space->select.sel_info.hslab->diminfo.opt[u].start > max2)
3695
0
                        max2 = space->select.sel_info.hslab->diminfo.opt[u].start;
3696
0
                    if (space->select.sel_info.hslab->diminfo.opt[u].stride > max2)
3697
0
                        max2 = space->select.sel_info.hslab->diminfo.opt[u].stride;
3698
0
                } /* end for */
3699
3700
                /* Determine the encoding size */
3701
0
                enc2 = H5S__hyper_get_enc_size_real(max2);
3702
3703
0
                *enc_size = (uint8_t)MAX(enc1, enc2);
3704
0
            } /* end if */
3705
0
            else {
3706
0
                hsize_t max_size = block_count;
3707
0
                assert(space->select.sel_info.hslab->unlim_dim < 0);
3708
3709
                /* Find max for block_count and bounds_end[] */
3710
0
                for (u = 0; u < space->extent.rank; u++)
3711
0
                    if (bounds_end[u] > max_size)
3712
0
                        max_size = bounds_end[u];
3713
3714
                /* Determine the encoding size */
3715
0
                *enc_size = H5S__hyper_get_enc_size_real(max_size);
3716
0
            } /* end else */
3717
0
            break;
3718
3719
0
        default:
3720
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unknown hyperslab selection version");
3721
0
            break;
3722
0
    }
3723
3724
0
done:
3725
0
    FUNC_LEAVE_NOAPI(ret_value)
3726
0
} /* H5S__hyper_get_version_enc_size() */
3727
3728
/*--------------------------------------------------------------------------
3729
 NAME
3730
    H5S__hyper_serial_size
3731
 PURPOSE
3732
    Determine the number of bytes needed to store the serialized hyperslab
3733
        selection information.
3734
 USAGE
3735
    hssize_t H5S__hyper_serial_size(space)
3736
        H5S_t *space;             IN: Dataspace pointer to query
3737
 RETURNS
3738
    The number of bytes required on success, negative on an error.
3739
 DESCRIPTION
3740
    Determines the number of bytes required to serialize the current hyperslab
3741
    selection information for storage on disk.
3742
 GLOBAL VARIABLES
3743
 COMMENTS, BUGS, ASSUMPTIONS
3744
 EXAMPLES
3745
 REVISION LOG
3746
--------------------------------------------------------------------------*/
3747
static hssize_t
3748
H5S__hyper_serial_size(H5S_t *space)
3749
0
{
3750
0
    hsize_t  block_count = 0;        /* block counter for regular hyperslabs */
3751
0
    uint32_t version     = UINT_MAX; /* Version number */
3752
0
    uint8_t  enc_size;               /* Encoded size of hyperslab selection info */
3753
0
    hssize_t ret_value = -1;         /* return value */
3754
3755
0
    FUNC_ENTER_PACKAGE
3756
3757
0
    assert(space);
3758
3759
    /* Determine the number of blocks */
3760
0
    if (space->select.sel_info.hslab->unlim_dim < 0) /* ! H5S_UNLIMITED */
3761
0
        block_count = H5S__get_select_hyper_nblocks(space, false);
3762
3763
    /* Determine the version and the encoded size */
3764
0
    if (H5S__hyper_get_version_enc_size(space, block_count, &version, &enc_size) < 0)
3765
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't determine hyper version & enc_size");
3766
3767
0
    if (version == H5S_HYPER_VERSION_3) {
3768
        /* Version 3: regular */
3769
        /* Size required is always:
3770
         * <type (4 bytes)> + <version (4 bytes)> + <flags (1 byte)> +
3771
         * <size of offset info (1 byte)> + <rank (4 bytes)> +
3772
         * (4 (start/stride/count/block) * <enc_size> * <rank>) =
3773
         * 14 + (4 * enc_size * rank) bytes
3774
         */
3775
0
        if (H5S__hyper_is_regular(space))
3776
0
            ret_value = (hssize_t)14 + ((hssize_t)4 * (hssize_t)enc_size * (hssize_t)space->extent.rank);
3777
0
        else {
3778
            /* Version 3: irregular */
3779
            /* Size required is always:
3780
             * <type (4 bytes)> + <version (4 bytes)> + <flags (1 byte)> +
3781
             * <size of offset info (1 byte)> + <rank (4 bytes)> +
3782
             * < # of blocks (depend on enc_size) > +
3783
             * (2 (starting/ending offset) * <rank> * <enc_size> * <# of blocks) =
3784
             * = 14 bytes + enc_size (block_count) + (2 * enc_size * rank * block_count) bytes
3785
             */
3786
0
            ret_value = 14 + enc_size;
3787
0
            H5_CHECK_OVERFLOW(((unsigned)2 * enc_size * space->extent.rank * block_count), hsize_t, hssize_t);
3788
0
            ret_value += (hssize_t)((unsigned)2 * enc_size * space->extent.rank * block_count);
3789
0
        } /* end else */
3790
0
    }     /* end if */
3791
0
    else if (version == H5S_HYPER_VERSION_2) {
3792
        /* Version 2 */
3793
        /* Size required is always:
3794
         * <type (4 bytes)> + <version (4 bytes)> + <flags (1 byte)> +
3795
         * <length (4 bytes)> + <rank (4 bytes)> +
3796
         * (4 (start/stride/count/block) * <enc_size (8 bytes)> * <rank>) =
3797
         * 17 + (4 * 8 * rank) bytes
3798
         */
3799
0
        assert(enc_size == 8);
3800
0
        ret_value = (hssize_t)17 + ((hssize_t)4 * (hssize_t)8 * (hssize_t)space->extent.rank);
3801
0
    }
3802
0
    else {
3803
0
        assert(version == H5S_HYPER_VERSION_1);
3804
0
        assert(enc_size == 4);
3805
        /* Version 1 */
3806
        /* Basic number of bytes required to serialize hyperslab selection:
3807
         * <type (4 bytes)> + <version (4 bytes)> + <padding (4 bytes)> +
3808
         * <length (4 bytes)> + <rank (4 bytes)> + <# of blocks (4 bytes)> +
3809
         * (2 (starting/ending offset) * <enc_size (4 bytes)> * <rank> * <# of blocks) =
3810
         * = 24 bytes + (2 * 4 * rank * block_count)
3811
         */
3812
0
        ret_value = 24;
3813
0
        H5_CHECK_OVERFLOW((8 * space->extent.rank * block_count), hsize_t, hssize_t);
3814
0
        ret_value += (hssize_t)(8 * space->extent.rank * block_count);
3815
0
    } /* end else */
3816
3817
0
done:
3818
0
    FUNC_LEAVE_NOAPI(ret_value)
3819
0
} /* end H5S__hyper_serial_size() */
3820
3821
/*--------------------------------------------------------------------------
3822
 NAME
3823
    H5S__hyper_serialize_helper
3824
 PURPOSE
3825
    Serialize the current selection into a user-provided buffer.
3826
 USAGE
3827
    void H5S__hyper_serialize_helper(spans, start, end, rank, enc_size, buf)
3828
        H5S_hyper_span_info_t *spans;   IN: Hyperslab span tree to serialize
3829
        hssize_t start[];       IN/OUT: Accumulated start points
3830
        hssize_t end[];         IN/OUT: Accumulated end points
3831
        hsize_t rank;           IN: Current rank looking at
3832
        uint8_t enc_size        IN: Encoded size of hyperslab selection info
3833
        uint8_t *buf;           OUT: Buffer to put serialized selection into
3834
 RETURNS
3835
    None
3836
 DESCRIPTION
3837
    Serializes the current element selection into a buffer.  (Primarily for
3838
    storing on disk).
3839
 GLOBAL VARIABLES
3840
 COMMENTS, BUGS, ASSUMPTIONS
3841
 EXAMPLES
3842
 REVISION LOG
3843
--------------------------------------------------------------------------*/
3844
static void
3845
H5S__hyper_serialize_helper(const H5S_hyper_span_info_t *spans, hsize_t *start, hsize_t *end, hsize_t rank,
3846
                            uint8_t enc_size, uint8_t **p)
3847
0
{
3848
0
    H5S_hyper_span_t *curr;      /* Pointer to current hyperslab span */
3849
0
    uint8_t          *pp = (*p); /* Local pointer for decoding */
3850
3851
0
    FUNC_ENTER_PACKAGE_NOERR
3852
3853
    /* Sanity checks */
3854
0
    assert(spans);
3855
0
    assert(start);
3856
0
    assert(end);
3857
0
    assert(rank < H5S_MAX_RANK);
3858
0
    assert(p && pp);
3859
3860
    /* Walk through the list of spans, recursing or outputting them */
3861
0
    curr = spans->head;
3862
0
    while (curr != NULL) {
3863
        /* Recurse if this node has down spans */
3864
0
        if (curr->down != NULL) {
3865
            /* Add the starting and ending points for this span to the list */
3866
0
            start[rank] = curr->low;
3867
0
            end[rank]   = curr->high;
3868
3869
            /* Recurse down to the next dimension */
3870
0
            H5S__hyper_serialize_helper(curr->down, start, end, rank + 1, enc_size, &pp);
3871
0
        } /* end if */
3872
0
        else {
3873
0
            hsize_t u; /* Index variable */
3874
3875
            /* Encode all the previous dimensions starting & ending points */
3876
0
            switch (enc_size) {
3877
0
                case H5S_SELECT_INFO_ENC_SIZE_2:
3878
                    /* Encode previous starting points */
3879
0
                    for (u = 0; u < rank; u++)
3880
0
                        UINT16ENCODE(pp, (uint16_t)start[u]);
3881
3882
                    /* Encode starting point for this span */
3883
0
                    UINT16ENCODE(pp, (uint16_t)curr->low);
3884
3885
                    /* Encode previous ending points */
3886
0
                    for (u = 0; u < rank; u++)
3887
0
                        UINT16ENCODE(pp, (uint16_t)end[u]);
3888
3889
                    /* Encode starting point for this span */
3890
0
                    UINT16ENCODE(pp, (uint16_t)curr->high);
3891
0
                    break;
3892
3893
0
                case H5S_SELECT_INFO_ENC_SIZE_4:
3894
                    /* Encode previous starting points */
3895
0
                    for (u = 0; u < rank; u++)
3896
0
                        UINT32ENCODE(pp, (uint32_t)start[u]);
3897
3898
                    /* Encode starting point for this span */
3899
0
                    UINT32ENCODE(pp, (uint32_t)curr->low);
3900
3901
                    /* Encode previous ending points */
3902
0
                    for (u = 0; u < rank; u++)
3903
0
                        UINT32ENCODE(pp, (uint32_t)end[u]);
3904
3905
                    /* Encode starting point for this span */
3906
0
                    UINT32ENCODE(pp, (uint32_t)curr->high);
3907
0
                    break;
3908
3909
0
                case H5S_SELECT_INFO_ENC_SIZE_8:
3910
                    /* Encode previous starting points */
3911
0
                    for (u = 0; u < rank; u++)
3912
0
                        UINT64ENCODE(pp, (uint64_t)start[u]);
3913
3914
                    /* Encode starting point for this span */
3915
0
                    UINT64ENCODE(pp, (uint64_t)curr->low);
3916
3917
                    /* Encode previous ending points */
3918
0
                    for (u = 0; u < rank; u++)
3919
0
                        UINT64ENCODE(pp, (uint64_t)end[u]);
3920
3921
                    /* Encode starting point for this span */
3922
0
                    UINT64ENCODE(pp, (uint64_t)curr->high);
3923
0
                    break;
3924
3925
0
                default:
3926
0
                    assert(0 && "Unknown enc size?!?");
3927
3928
0
            } /* end switch */
3929
0
        }     /* end else */
3930
3931
        /* Advance to next node */
3932
0
        curr = curr->next;
3933
0
    } /* end while */
3934
3935
    /* Update encoding pointer */
3936
0
    *p = pp;
3937
3938
0
    FUNC_LEAVE_NOAPI_VOID
3939
0
} /* end H5S__hyper_serialize_helper() */
3940
3941
/*--------------------------------------------------------------------------
3942
 NAME
3943
    H5S__hyper_serialize
3944
 PURPOSE
3945
    Serialize the current selection into a user-provided buffer.
3946
 USAGE
3947
    herr_t H5S__hyper_serialize(space, p)
3948
        H5S_t *space;           IN: Dataspace with selection to serialize
3949
        uint8_t **p;            OUT: Pointer to buffer to put serialized
3950
                                selection.  Will be advanced to end of
3951
                                serialized selection.
3952
 RETURNS
3953
    Non-negative on success/Negative on failure
3954
 DESCRIPTION
3955
    Serializes the current element selection into a buffer.  (Primarily for
3956
    storing on disk).
3957
 GLOBAL VARIABLES
3958
 COMMENTS, BUGS, ASSUMPTIONS
3959
 EXAMPLES
3960
 REVISION LOG
3961
--------------------------------------------------------------------------*/
3962
static herr_t
3963
H5S__hyper_serialize(H5S_t *space, uint8_t **p)
3964
0
{
3965
0
    const H5S_hyper_dim_t *diminfo;                 /* Alias for dataspace's diminfo information */
3966
0
    hsize_t                tmp_count[H5S_MAX_RANK]; /* Temporary hyperslab counts */
3967
0
    hsize_t                offset[H5S_MAX_RANK];    /* Offset of element in dataspace */
3968
0
    hsize_t                start[H5S_MAX_RANK];     /* Location of start of hyperslab */
3969
0
    hsize_t                end[H5S_MAX_RANK];       /* Location of end of hyperslab */
3970
0
    uint8_t               *pp;                      /* Local pointer for encoding */
3971
0
    uint8_t               *lenp = NULL;             /* pointer to length location for later storage */
3972
0
    uint32_t               len  = 0;                /* number of bytes used */
3973
0
    uint32_t               version;                 /* Version number */
3974
0
    uint8_t                flags       = 0;         /* Flags for message */
3975
0
    hsize_t                block_count = 0;         /* block counter for regular hyperslabs */
3976
0
    unsigned               fast_dim;            /* Rank of the fastest changing dimension for the dataspace */
3977
0
    unsigned               ndims;               /* Rank of the dataspace */
3978
0
    unsigned               u;                   /* Local counting variable */
3979
0
    bool                   complete = false;    /* Whether we are done with the iteration */
3980
0
    bool                   is_regular;          /* Whether selection is regular */
3981
0
    uint8_t                enc_size;            /* Encoded size */
3982
0
    herr_t                 ret_value = SUCCEED; /* return value */
3983
3984
0
    FUNC_ENTER_PACKAGE
3985
3986
    /* Sanity checks */
3987
0
    assert(space);
3988
0
    assert(p);
3989
0
    pp = (*p);
3990
0
    assert(pp);
3991
3992
    /* Set some convenience values */
3993
0
    ndims   = space->extent.rank;
3994
0
    diminfo = space->select.sel_info.hslab->diminfo.opt;
3995
3996
    /* Calculate the # of blocks */
3997
0
    if (space->select.sel_info.hslab->unlim_dim < 0) /* ! H5S_UNLIMITED */
3998
0
        block_count = H5S__get_select_hyper_nblocks(space, false);
3999
4000
    /* Determine the version and the encoded size */
4001
0
    if (H5S__hyper_get_version_enc_size(space, block_count, &version, &enc_size) < 0)
4002
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't determine hyper version & enc_size");
4003
4004
0
    is_regular = H5S__hyper_is_regular(space);
4005
0
    if (is_regular && (version == H5S_HYPER_VERSION_2 || version == H5S_HYPER_VERSION_3))
4006
0
        flags |= H5S_HYPER_REGULAR;
4007
4008
    /* Store the preamble information */
4009
0
    UINT32ENCODE(pp, (uint32_t)H5S_GET_SELECT_TYPE(space)); /* Store the type of selection */
4010
0
    UINT32ENCODE(pp, version);                              /* Store the version number */
4011
4012
0
    if (version >= 3) {
4013
0
        *(pp)++ = flags;    /* Store the flags */
4014
0
        *(pp)++ = enc_size; /* Store size of offset info */
4015
0
    }                       /* end if */
4016
0
    else {
4017
0
        if (version == 2)
4018
0
            *(pp)++ = flags; /* Store the flags */
4019
0
        else
4020
0
            UINT32ENCODE(pp, (uint32_t)0); /* Store the un-used padding */
4021
0
        lenp = pp;                         /* keep the pointer to the length location for later */
4022
0
        pp += 4;                           /* skip over space for length */
4023
4024
0
        len += 4; /* ndims */
4025
0
    }             /* end else */
4026
4027
    /* Encode number of dimensions */
4028
0
    UINT32ENCODE(pp, (uint32_t)ndims);
4029
4030
0
    if (is_regular) {
4031
0
        if (version >= H5S_HYPER_VERSION_2) {
4032
0
            assert(H5S_UNLIMITED == HSIZE_UNDEF);
4033
4034
            /* Iterate over dimensions */
4035
            /* Encode start/stride/block/count */
4036
0
            switch (enc_size) {
4037
0
                case H5S_SELECT_INFO_ENC_SIZE_2:
4038
0
                    assert(version == H5S_HYPER_VERSION_3);
4039
0
                    for (u = 0; u < space->extent.rank; u++) {
4040
0
                        UINT16ENCODE(pp, diminfo[u].start);
4041
0
                        UINT16ENCODE(pp, diminfo[u].stride);
4042
0
                        if (diminfo[u].count == H5S_UNLIMITED)
4043
0
                            UINT16ENCODE(pp, H5S_UINT16_MAX);
4044
0
                        else
4045
0
                            UINT16ENCODE(pp, diminfo[u].count);
4046
0
                        if (diminfo[u].block == H5S_UNLIMITED)
4047
0
                            UINT16ENCODE(pp, H5S_UINT16_MAX);
4048
0
                        else
4049
0
                            UINT16ENCODE(pp, diminfo[u].block);
4050
0
                    } /* end for */
4051
0
                    break;
4052
4053
0
                case H5S_SELECT_INFO_ENC_SIZE_4:
4054
0
                    assert(version == H5S_HYPER_VERSION_3);
4055
0
                    for (u = 0; u < space->extent.rank; u++) {
4056
0
                        UINT32ENCODE(pp, diminfo[u].start);
4057
0
                        UINT32ENCODE(pp, diminfo[u].stride);
4058
0
                        if (diminfo[u].count == H5S_UNLIMITED)
4059
0
                            UINT32ENCODE(pp, H5S_UINT32_MAX);
4060
0
                        else
4061
0
                            UINT32ENCODE(pp, diminfo[u].count);
4062
0
                        if (diminfo[u].block == H5S_UNLIMITED)
4063
0
                            UINT32ENCODE(pp, H5S_UINT32_MAX);
4064
0
                        else
4065
0
                            UINT32ENCODE(pp, diminfo[u].block);
4066
0
                    } /* end for */
4067
0
                    break;
4068
4069
0
                case H5S_SELECT_INFO_ENC_SIZE_8:
4070
0
                    assert(version == H5S_HYPER_VERSION_2 || version == H5S_HYPER_VERSION_3);
4071
0
                    for (u = 0; u < space->extent.rank; u++) {
4072
0
                        UINT64ENCODE(pp, diminfo[u].start);
4073
0
                        UINT64ENCODE(pp, diminfo[u].stride);
4074
0
                        if (diminfo[u].count == H5S_UNLIMITED)
4075
0
                            UINT64ENCODE(pp, H5S_UINT64_MAX);
4076
0
                        else
4077
0
                            UINT64ENCODE(pp, diminfo[u].count);
4078
0
                        if (diminfo[u].block == H5S_UNLIMITED)
4079
0
                            UINT64ENCODE(pp, H5S_UINT64_MAX);
4080
0
                        else
4081
0
                            UINT64ENCODE(pp, diminfo[u].block);
4082
0
                    } /* end for */
4083
0
                    if (version == H5S_HYPER_VERSION_2)
4084
0
                        len += (4 * space->extent.rank * 8);
4085
0
                    break;
4086
0
                default:
4087
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL,
4088
0
                                "unknown offset info size for hyperslab");
4089
0
                    break;
4090
0
            } /* end switch */
4091
0
        }     /* end if */
4092
0
        else {
4093
0
            assert(version == H5S_HYPER_VERSION_1);
4094
4095
            /* Set some convenience values */
4096
0
            fast_dim = ndims - 1;
4097
4098
            /* Encode number of hyperslabs */
4099
0
            H5_CHECK_OVERFLOW(block_count, hsize_t, uint32_t);
4100
0
            UINT32ENCODE(pp, (uint32_t)block_count);
4101
0
            len += 4;
4102
4103
            /* Now serialize the information for the regular hyperslab */
4104
4105
            /* Build the tables of count sizes as well as the initial offset */
4106
0
            for (u = 0; u < ndims; u++) {
4107
0
                tmp_count[u] = diminfo[u].count;
4108
0
                offset[u]    = diminfo[u].start;
4109
0
            } /* end for */
4110
4111
            /* Go iterate over the hyperslabs */
4112
0
            while (complete == false) {
4113
                /* Iterate over the blocks in the fastest dimension */
4114
0
                while (tmp_count[fast_dim] > 0) {
4115
                    /* Add 8 bytes times the rank for each hyperslab selected */
4116
0
                    len += 8 * ndims;
4117
4118
                    /* Encode hyperslab starting location */
4119
0
                    for (u = 0; u < ndims; u++)
4120
0
                        UINT32ENCODE(pp, (uint32_t)offset[u]);
4121
4122
                    /* Encode hyperslab ending location */
4123
0
                    for (u = 0; u < ndims; u++)
4124
0
                        UINT32ENCODE(pp, (uint32_t)(offset[u] + (diminfo[u].block - 1)));
4125
4126
                    /* Move the offset to the next sequence to start */
4127
0
                    offset[fast_dim] += diminfo[fast_dim].stride;
4128
4129
                    /* Decrement the block count */
4130
0
                    tmp_count[fast_dim]--;
4131
0
                } /* end while */
4132
4133
                /* Work on other dimensions if necessary */
4134
0
                if (fast_dim > 0) {
4135
0
                    int temp_dim; /* Temporary rank holder */
4136
4137
                    /* Reset the block counts */
4138
0
                    tmp_count[fast_dim] = diminfo[fast_dim].count;
4139
4140
                    /* Bubble up the decrement to the slower changing dimensions */
4141
0
                    temp_dim = (int)fast_dim - 1;
4142
0
                    while (temp_dim >= 0 && complete == false) {
4143
                        /* Decrement the block count */
4144
0
                        tmp_count[temp_dim]--;
4145
4146
                        /* Check if we have more blocks left */
4147
0
                        if (tmp_count[temp_dim] > 0)
4148
0
                            break;
4149
4150
                        /* Check for getting out of iterator */
4151
0
                        if (temp_dim == 0)
4152
0
                            complete = true;
4153
4154
                        /* Reset the block count in this dimension */
4155
0
                        tmp_count[temp_dim] = diminfo[temp_dim].count;
4156
4157
                        /* Wrapped a dimension, go up to next dimension */
4158
0
                        temp_dim--;
4159
0
                    } /* end while */
4160
0
                }     /* end if */
4161
0
                else
4162
0
                    break; /* Break out now, for 1-D selections */
4163
4164
                /* Re-compute offset array */
4165
0
                for (u = 0; u < ndims; u++)
4166
0
                    offset[u] = diminfo[u].start + diminfo[u].stride * (diminfo[u].count - tmp_count[u]);
4167
0
            } /* end while */
4168
0
        }     /* end else */
4169
0
    }         /* end if */
4170
0
    else {    /* irregular */
4171
        /* Encode number of hyperslabs */
4172
0
        switch (enc_size) {
4173
0
            case H5S_SELECT_INFO_ENC_SIZE_2:
4174
0
                assert(version == H5S_HYPER_VERSION_3);
4175
0
                H5_CHECK_OVERFLOW(block_count, hsize_t, uint16_t);
4176
0
                UINT16ENCODE(pp, (uint16_t)block_count);
4177
0
                break;
4178
4179
0
            case H5S_SELECT_INFO_ENC_SIZE_4:
4180
0
                assert(version == H5S_HYPER_VERSION_1 || version == H5S_HYPER_VERSION_3);
4181
0
                H5_CHECK_OVERFLOW(block_count, hsize_t, uint32_t);
4182
0
                UINT32ENCODE(pp, (uint32_t)block_count);
4183
0
                break;
4184
4185
0
            case H5S_SELECT_INFO_ENC_SIZE_8:
4186
0
                assert(version == H5S_HYPER_VERSION_3);
4187
0
                UINT64ENCODE(pp, block_count);
4188
0
                break;
4189
4190
0
            default:
4191
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unknown offset info size for hyperslab");
4192
0
                break;
4193
0
        } /* end switch */
4194
4195
0
        if (version == H5S_HYPER_VERSION_1) {
4196
0
            len += 4; /* block_count */
4197
4198
            /* Add 8 bytes times the rank for each hyperslab selected */
4199
0
            H5_CHECK_OVERFLOW((8 * ndims * block_count), hsize_t, size_t);
4200
0
            len += (uint32_t)(8 * ndims * block_count);
4201
0
        } /* end if */
4202
4203
0
        H5S__hyper_serialize_helper(space->select.sel_info.hslab->span_lst, start, end, (hsize_t)0, enc_size,
4204
0
                                    &pp);
4205
0
    } /* end else */
4206
4207
    /* Encode length */
4208
0
    if (version <= H5S_HYPER_VERSION_2)
4209
0
        UINT32ENCODE(lenp, (uint32_t)len); /* Store the length of the extra information */
4210
4211
    /* Update encoding pointer */
4212
0
    *p = pp;
4213
4214
0
done:
4215
0
    FUNC_LEAVE_NOAPI(ret_value)
4216
0
} /* end H5S__hyper_serialize() */
4217
4218
/*--------------------------------------------------------------------------
4219
 NAME
4220
    H5S__hyper_deserialize
4221
 PURPOSE
4222
    Deserialize the current selection from a user-provided buffer.
4223
 USAGE
4224
    herr_t H5S__hyper_deserialize(space, p)
4225
        H5S_t **space;          IN/OUT: Dataspace pointer to place
4226
                                selection into
4227
        uint8 **p;              OUT: Pointer to buffer holding serialized
4228
                                selection.  Will be advanced to end of
4229
                                serialized selection.
4230
 RETURNS
4231
    Non-negative on success/Negative on failure
4232
 DESCRIPTION
4233
    Deserializes the current selection into a buffer.  (Primarily for retrieving
4234
    from disk).
4235
 GLOBAL VARIABLES
4236
 COMMENTS, BUGS, ASSUMPTIONS
4237
 EXAMPLES
4238
 REVISION LOG
4239
--------------------------------------------------------------------------*/
4240
static herr_t
4241
H5S__hyper_deserialize(H5S_t **space, const uint8_t **p, const size_t p_size, bool skip)
4242
0
{
4243
0
    H5S_t *tmp_space = NULL;                    /* Pointer to actual dataspace to use,
4244
                                                   either *space or a newly allocated one */
4245
0
    hsize_t        dims[H5S_MAX_RANK];          /* Dimension sizes */
4246
0
    hsize_t        start[H5S_MAX_RANK];         /* hyperslab start information */
4247
0
    hsize_t        block[H5S_MAX_RANK];         /* hyperslab block information */
4248
0
    uint32_t       version;                     /* Version number */
4249
0
    uint8_t        flags    = 0;                /* Flags */
4250
0
    uint8_t        enc_size = 0;                /* Encoded size of selection info */
4251
0
    unsigned       rank;                        /* rank of points */
4252
0
    const uint8_t *pp;                          /* Local pointer for decoding */
4253
0
    unsigned       u;                           /* Local counting variable */
4254
0
    herr_t         ret_value = FAIL;            /* return value */
4255
0
    const uint8_t *p_end     = *p + p_size - 1; /* Pointer to last valid byte in buffer */
4256
0
    FUNC_ENTER_PACKAGE
4257
4258
    /* Check args */
4259
0
    assert(p);
4260
0
    pp = (*p);
4261
0
    assert(pp);
4262
4263
    /* As part of the efforts to push all selection-type specific coding
4264
       to the callbacks, the coding for the allocation of a null dataspace
4265
       is moved from H5S_select_deserialize() in H5Sselect.c to here.
4266
       This is needed for decoding virtual layout in H5O__layout_decode() */
4267
    /* Allocate space if not provided */
4268
0
    if (!*space) {
4269
0
        if (NULL == (tmp_space = H5S_create(H5S_SIMPLE)))
4270
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create dataspace");
4271
0
    } /* end if */
4272
0
    else
4273
0
        tmp_space = *space;
4274
4275
    /* Decode version */
4276
0
    if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, sizeof(uint32_t), p_end))
4277
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL, "buffer overflow while decoding selection version");
4278
0
    UINT32DECODE(pp, version);
4279
4280
0
    if (version < H5S_HYPER_VERSION_1 || version > H5S_HYPER_VERSION_LATEST)
4281
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "bad version number for hyperslab selection");
4282
4283
0
    if (version >= (uint32_t)H5S_HYPER_VERSION_2) {
4284
        /* Decode flags */
4285
0
        if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, 1, p_end))
4286
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL, "buffer overflow while decoding selection flags");
4287
0
        flags = *(pp)++;
4288
4289
0
        if (version >= (uint32_t)H5S_HYPER_VERSION_3) {
4290
            /* decode size of offset info */
4291
0
            if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, 1, p_end))
4292
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4293
0
                            "buffer overflow while decoding selection encoding size");
4294
0
            enc_size = *(pp)++;
4295
0
        }
4296
0
        else {
4297
            /* Skip over the remainder of the header */
4298
0
            if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, 4, p_end))
4299
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4300
0
                            "buffer overflow while decoding selection header");
4301
0
            pp += 4;
4302
0
            enc_size = H5S_SELECT_INFO_ENC_SIZE_8;
4303
0
        } /* end else */
4304
4305
        /* Check for unknown flags */
4306
0
        if (flags & ~H5S_SELECT_FLAG_BITS)
4307
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTLOAD, FAIL, "unknown flag for selection");
4308
0
    }
4309
0
    else {
4310
        /* Skip over the remainder of the header */
4311
0
        if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, 8, p_end))
4312
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL, "buffer overflow while decoding selection header");
4313
0
        pp += 8;
4314
0
        enc_size = H5S_SELECT_INFO_ENC_SIZE_4;
4315
0
    } /* end else */
4316
4317
    /* Check encoded */
4318
0
    if (enc_size & ~H5S_SELECT_INFO_ENC_SIZE_BITS)
4319
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTLOAD, FAIL, "unknown size of point/offset info for selection");
4320
4321
    /* Decode the rank of the point selection */
4322
0
    if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, sizeof(uint32_t), p_end))
4323
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL, "buffer overflow while decoding selection rank");
4324
0
    UINT32DECODE(pp, rank);
4325
4326
0
    if (!*space) {
4327
        /* Patch the rank of the allocated dataspace */
4328
0
        memset(dims, 0, (size_t)rank * sizeof(dims[0]));
4329
0
        if (H5S_set_extent_simple(tmp_space, rank, dims, NULL) < 0)
4330
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't set dimensions");
4331
0
    } /* end if */
4332
0
    else
4333
        /* Verify the rank of the provided dataspace */
4334
0
        if (rank != tmp_space->extent.rank)
4335
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL,
4336
0
                        "rank of serialized selection does not match dataspace");
4337
4338
0
    if (flags & H5S_HYPER_REGULAR) {
4339
0
        hsize_t stride[H5S_MAX_RANK]; /* Hyperslab stride information */
4340
0
        hsize_t count[H5S_MAX_RANK];  /* Hyperslab count information */
4341
4342
        /* Sanity checks */
4343
0
        assert(H5S_UNLIMITED == HSIZE_UNDEF);
4344
0
        assert(version >= H5S_HYPER_VERSION_2);
4345
4346
        /* Decode start/stride/block/count */
4347
0
        switch (enc_size) {
4348
0
            case H5S_SELECT_INFO_ENC_SIZE_2:
4349
0
                for (u = 0; u < tmp_space->extent.rank; u++) {
4350
0
                    if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, 4 * sizeof(uint16_t), p_end))
4351
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4352
0
                                    "buffer overflow while decoding selection ranks");
4353
4354
0
                    UINT16DECODE(pp, start[u]);
4355
0
                    UINT16DECODE(pp, stride[u]);
4356
4357
0
                    UINT16DECODE(pp, count[u]);
4358
0
                    if ((uint16_t)count[u] == H5S_UINT16_MAX)
4359
0
                        count[u] = H5S_UNLIMITED;
4360
4361
0
                    UINT16DECODE(pp, block[u]);
4362
0
                    if ((uint16_t)block[u] == H5S_UINT16_MAX)
4363
0
                        block[u] = H5S_UNLIMITED;
4364
0
                } /* end for */
4365
0
                break;
4366
4367
0
            case H5S_SELECT_INFO_ENC_SIZE_4:
4368
0
                for (u = 0; u < tmp_space->extent.rank; u++) {
4369
0
                    if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, 4 * sizeof(uint32_t), p_end))
4370
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4371
0
                                    "buffer overflow while decoding selection ranks");
4372
4373
0
                    UINT32DECODE(pp, start[u]);
4374
0
                    UINT32DECODE(pp, stride[u]);
4375
4376
0
                    UINT32DECODE(pp, count[u]);
4377
0
                    if ((uint32_t)count[u] == H5S_UINT32_MAX)
4378
0
                        count[u] = H5S_UNLIMITED;
4379
4380
0
                    UINT32DECODE(pp, block[u]);
4381
0
                    if ((uint32_t)block[u] == H5S_UINT32_MAX)
4382
0
                        block[u] = H5S_UNLIMITED;
4383
0
                } /* end for */
4384
0
                break;
4385
4386
0
            case H5S_SELECT_INFO_ENC_SIZE_8:
4387
0
                for (u = 0; u < tmp_space->extent.rank; u++) {
4388
0
                    if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, 4 * sizeof(uint64_t), p_end))
4389
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4390
0
                                    "buffer overflow while decoding selection ranks");
4391
4392
0
                    UINT64DECODE(pp, start[u]);
4393
0
                    UINT64DECODE(pp, stride[u]);
4394
4395
0
                    UINT64DECODE(pp, count[u]);
4396
0
                    if ((uint64_t)count[u] == H5S_UINT64_MAX)
4397
0
                        count[u] = H5S_UNLIMITED;
4398
4399
0
                    UINT64DECODE(pp, block[u]);
4400
0
                    if ((uint64_t)block[u] == H5S_UINT64_MAX)
4401
0
                        block[u] = H5S_UNLIMITED;
4402
0
                } /* end for */
4403
0
                break;
4404
4405
0
            default:
4406
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unknown offset info size for hyperslab");
4407
0
                break;
4408
0
        } /* end switch */
4409
4410
        /* Select the hyperslab to the current selection */
4411
0
        if ((ret_value = H5S_select_hyperslab(tmp_space, H5S_SELECT_SET, start, stride, count, block)) < 0)
4412
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't change selection");
4413
0
    } /* end if */
4414
0
    else {
4415
0
        const hsize_t *stride;            /* Hyperslab stride information */
4416
0
        const hsize_t *count;             /* Hyperslab count information */
4417
0
        hsize_t        end[H5S_MAX_RANK]; /* Hyperslab end information */
4418
0
        hsize_t       *tstart;            /* Temporary hyperslab pointers */
4419
0
        hsize_t       *tend;              /* Temporary hyperslab pointers */
4420
0
        hsize_t       *tblock;            /* Temporary hyperslab pointers */
4421
0
        size_t         num_elem;          /* Number of elements in selection */
4422
0
        unsigned       v;                 /* Local counting variable */
4423
4424
        /* Decode the number of blocks */
4425
0
        switch (enc_size) {
4426
0
            case H5S_SELECT_INFO_ENC_SIZE_2:
4427
0
                if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, sizeof(uint16_t), p_end))
4428
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4429
0
                                "buffer overflow while decoding number of selection blocks");
4430
0
                UINT16DECODE(pp, num_elem);
4431
0
                break;
4432
4433
0
            case H5S_SELECT_INFO_ENC_SIZE_4:
4434
0
                if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, sizeof(uint32_t), p_end))
4435
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4436
0
                                "buffer overflow while decoding number of selection blocks");
4437
0
                UINT32DECODE(pp, num_elem);
4438
0
                break;
4439
4440
0
            case H5S_SELECT_INFO_ENC_SIZE_8:
4441
0
                if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, sizeof(uint64_t), p_end))
4442
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4443
0
                                "buffer overflow while decoding number of selection blocks");
4444
0
                UINT64DECODE(pp, num_elem);
4445
0
                break;
4446
4447
0
            default:
4448
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unknown offset info size for hyperslab");
4449
0
                break;
4450
0
        } /* end switch */
4451
4452
        /* Set the count & stride for all blocks */
4453
0
        stride = count = H5S_hyper_ones_g;
4454
4455
        /* Retrieve the coordinates from the buffer */
4456
0
        for (u = 0; u < num_elem; u++) {
4457
            /* Decode the starting and ending points */
4458
0
            switch (enc_size) {
4459
0
                case H5S_SELECT_INFO_ENC_SIZE_2:
4460
0
                    if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, rank * 2 * sizeof(uint16_t), p_end))
4461
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4462
0
                                    "buffer overflow while decoding selection coordinates");
4463
4464
0
                    for (tstart = start, v = 0; v < rank; v++, tstart++)
4465
0
                        UINT16DECODE(pp, *tstart);
4466
0
                    for (tend = end, v = 0; v < rank; v++, tend++)
4467
0
                        UINT16DECODE(pp, *tend);
4468
0
                    break;
4469
4470
0
                case H5S_SELECT_INFO_ENC_SIZE_4:
4471
0
                    if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, rank * 2 * sizeof(uint32_t), p_end))
4472
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4473
0
                                    "buffer overflow while decoding selection coordinates");
4474
4475
0
                    for (tstart = start, v = 0; v < rank; v++, tstart++)
4476
0
                        UINT32DECODE(pp, *tstart);
4477
0
                    for (tend = end, v = 0; v < rank; v++, tend++)
4478
0
                        UINT32DECODE(pp, *tend);
4479
0
                    break;
4480
4481
0
                case H5S_SELECT_INFO_ENC_SIZE_8:
4482
0
                    if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, rank * 2 * sizeof(uint64_t), p_end))
4483
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4484
0
                                    "buffer overflow while decoding selection coordinates");
4485
4486
0
                    for (tstart = start, v = 0; v < rank; v++, tstart++)
4487
0
                        UINT64DECODE(pp, *tstart);
4488
0
                    for (tend = end, v = 0; v < rank; v++, tend++)
4489
0
                        UINT64DECODE(pp, *tend);
4490
0
                    break;
4491
4492
0
                default:
4493
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL,
4494
0
                                "unknown offset info size for hyperslab");
4495
0
                    break;
4496
0
            } /* end switch */
4497
4498
            /* Change the ending points into blocks */
4499
0
            for (tblock = block, tstart = start, tend = end, v = 0; v < rank; v++, tstart++, tend++, tblock++)
4500
0
                *tblock = (*tend - *tstart) + 1;
4501
4502
            /* Select or add the hyperslab to the current selection */
4503
0
            if ((ret_value = H5S_select_hyperslab(tmp_space, (u == 0 ? H5S_SELECT_SET : H5S_SELECT_OR), start,
4504
0
                                                  stride, count, block)) < 0)
4505
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't change selection");
4506
0
        } /* end for */
4507
0
    }     /* end else */
4508
4509
    /* Update decoding pointer */
4510
0
    *p = pp;
4511
4512
    /* Return space to the caller if allocated */
4513
0
    if (!*space)
4514
0
        *space = tmp_space;
4515
4516
0
done:
4517
    /* Free temporary space if not passed to caller (only happens on error) */
4518
0
    if (!*space && tmp_space)
4519
0
        if (H5S_close(tmp_space) < 0)
4520
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't close dataspace");
4521
4522
0
    FUNC_LEAVE_NOAPI(ret_value)
4523
0
} /* end H5S__hyper_deserialize() */
4524
4525
/*--------------------------------------------------------------------------
4526
 NAME
4527
    H5S__hyper_span_blocklist
4528
 PURPOSE
4529
    Get a list of hyperslab blocks currently selected
4530
 USAGE
4531
    herr_t H5S__hyper_span_blocklist(spans, start, end, rank, startblock, numblocks, buf)
4532
        H5S_hyper_span_info_t *spans;   IN: Dataspace pointer of selection to query
4533
        hsize_t start[];       IN/OUT: Accumulated start points
4534
        hsize_t end[];         IN/OUT: Accumulated end points
4535
        hsize_t rank;           IN: Rank of dataspace
4536
        hsize_t *startblock;    IN/OUT: Hyperslab block to start with
4537
        hsize_t *numblocks;     IN/OUT: Number of hyperslab blocks to get
4538
        hsize_t **buf;          OUT: List of hyperslab blocks selected
4539
 RETURNS
4540
    Non-negative on success/Negative on failure
4541
 DESCRIPTION
4542
        Puts a list of the hyperslab blocks into the user's buffer.  The blocks
4543
    start with the '*startblock'th block in the list of blocks and put
4544
    '*numblocks' number of blocks into the user's buffer (or until the end of
4545
    the list of blocks, whichever happens first)
4546
        The block coordinates have the same dimensionality (rank) as the
4547
    dataspace they are located within.  The list of blocks is formatted as
4548
    follows: <"start" coordinate> immediately followed by <"opposite" corner
4549
    coordinate>, followed by the next "start" and "opposite" coordinate, etc.
4550
    until all the block information requested has been put into the user's
4551
    buffer.
4552
        No guarantee of any order of the blocks is implied.
4553
 GLOBAL VARIABLES
4554
 COMMENTS, BUGS, ASSUMPTIONS
4555
 EXAMPLES
4556
 REVISION LOG
4557
--------------------------------------------------------------------------*/
4558
static herr_t
4559
H5S__hyper_span_blocklist(const H5S_hyper_span_info_t *spans, hsize_t start[], hsize_t end[], hsize_t rank,
4560
                          hsize_t *startblock, hsize_t *numblocks, hsize_t **buf)
4561
0
{
4562
0
    const H5S_hyper_span_t *curr;                /* Pointer to current hyperslab span */
4563
0
    herr_t                  ret_value = SUCCEED; /* return value */
4564
4565
0
    FUNC_ENTER_PACKAGE
4566
4567
    /* Sanity checks */
4568
0
    assert(spans);
4569
0
    assert(rank < H5S_MAX_RANK);
4570
0
    assert(start);
4571
0
    assert(end);
4572
0
    assert(startblock);
4573
0
    assert(numblocks && *numblocks > 0);
4574
0
    assert(buf && *buf);
4575
4576
    /* Walk through the list of spans, recursing or outputting them */
4577
0
    curr = spans->head;
4578
0
    while (curr != NULL && *numblocks > 0) {
4579
        /* Recurse if this node has down spans */
4580
0
        if (curr->down != NULL) {
4581
            /* Add the starting and ending points for this span to the list */
4582
0
            start[rank] = curr->low;
4583
0
            end[rank]   = curr->high;
4584
4585
            /* Recurse down to the next dimension */
4586
0
            if (H5S__hyper_span_blocklist(curr->down, start, end, (rank + 1), startblock, numblocks, buf) < 0)
4587
0
                HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans");
4588
0
        } /* end if */
4589
0
        else {
4590
            /* Skip this block if we haven't skipped all the startblocks yet */
4591
0
            if (*startblock > 0) {
4592
                /* Decrement the starting block */
4593
0
                (*startblock)--;
4594
0
            } /* end if */
4595
            /* Process this block */
4596
0
            else {
4597
                /* Encode all the previous dimensions starting & ending points */
4598
4599
                /* Copy previous starting points */
4600
0
                H5MM_memcpy(*buf, start, rank * sizeof(hsize_t));
4601
0
                (*buf) += rank;
4602
4603
                /* Copy starting point for this span */
4604
0
                **buf = curr->low;
4605
0
                (*buf)++;
4606
4607
                /* Copy previous ending points */
4608
0
                H5MM_memcpy(*buf, end, rank * sizeof(hsize_t));
4609
0
                (*buf) += rank;
4610
4611
                /* Copy ending point for this span */
4612
0
                **buf = curr->high;
4613
0
                (*buf)++;
4614
4615
                /* Decrement the number of blocks processed */
4616
0
                (*numblocks)--;
4617
0
            } /* end else */
4618
0
        }     /* end else */
4619
4620
        /* Advance to next node */
4621
0
        curr = curr->next;
4622
0
    } /* end while */
4623
4624
0
done:
4625
0
    FUNC_LEAVE_NOAPI(ret_value)
4626
0
} /* end H5S__hyper_span_blocklist() */
4627
4628
/*--------------------------------------------------------------------------
4629
 NAME
4630
    H5S__get_select_hyper_blocklist
4631
 PURPOSE
4632
    Get the list of hyperslab blocks currently selected
4633
 USAGE
4634
    herr_t H5S__get_select_hyper_blocklist(space, startblock, numblocks, buf)
4635
        H5S_t *space;           IN: Dataspace pointer of selection to query
4636
        hsize_t startblock;     IN: Hyperslab block to start with
4637
        hsize_t numblocks;      IN: Number of hyperslab blocks to get
4638
        hsize_t *buf;           OUT: List of hyperslab blocks selected
4639
 RETURNS
4640
    Non-negative on success, negative on failure
4641
 DESCRIPTION
4642
        Puts a list of the hyperslab blocks into the user's buffer.  The blocks
4643
    start with the 'startblock'th block in the list of blocks and put
4644
    'numblocks' number of blocks into the user's buffer (or until the end of
4645
    the list of blocks, whichever happens first)
4646
        The block coordinates have the same dimensionality (rank) as the
4647
    dataspace they are located within.  The list of blocks is formatted as
4648
    follows: <"start" coordinate> immediately followed by <"opposite" corner
4649
    coordinate>, followed by the next "start" and "opposite" coordinate, etc.
4650
    until all the block information requested has been put into the user's
4651
    buffer.
4652
        No guarantee of any order of the blocks is implied.
4653
 GLOBAL VARIABLES
4654
 COMMENTS, BUGS, ASSUMPTIONS
4655
 EXAMPLES
4656
 REVISION LOG
4657
--------------------------------------------------------------------------*/
4658
static herr_t
4659
H5S__get_select_hyper_blocklist(H5S_t *space, hsize_t startblock, hsize_t numblocks, hsize_t *buf)
4660
0
{
4661
0
    herr_t ret_value = SUCCEED; /* Return value */
4662
4663
0
    FUNC_ENTER_PACKAGE
4664
4665
0
    assert(space);
4666
0
    assert(buf);
4667
0
    assert(space->select.sel_info.hslab->unlim_dim < 0);
4668
4669
0
    if (space->extent.rank == 0)
4670
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL,
4671
0
                    "dataspace has invalid extent for hyperslab selection");
4672
4673
    /* Attempt to rebuild diminfo if it is invalid and has not been confirmed
4674
     * to be impossible.
4675
     */
4676
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO)
4677
0
        H5S__hyper_rebuild(space);
4678
4679
    /* Check for a "regular" hyperslab selection */
4680
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
4681
0
        const H5S_hyper_dim_t *diminfo;                 /* Alias for dataspace's diminfo information */
4682
0
        hsize_t                tmp_count[H5S_MAX_RANK]; /* Temporary hyperslab counts */
4683
0
        hsize_t                offset[H5S_MAX_RANK];    /* Offset of element in dataspace */
4684
0
        hsize_t                end[H5S_MAX_RANK];       /* End of elements in dataspace */
4685
0
        unsigned               fast_dim; /* Rank of the fastest changing dimension for the dataspace */
4686
0
        unsigned               ndims;    /* Rank of the dataspace */
4687
0
        bool                   done;     /* Whether we are done with the iteration */
4688
0
        unsigned               u;        /* Counter */
4689
4690
        /* Set some convenience values */
4691
0
        ndims    = space->extent.rank;
4692
0
        fast_dim = ndims - 1;
4693
4694
        /* Check which set of dimension information to use */
4695
0
        if (space->select.sel_info.hslab->unlim_dim >= 0)
4696
            /*
4697
             * There is an unlimited dimension so we must use diminfo.opt as
4698
             * it has been "clipped" to the current extent.
4699
             */
4700
0
            diminfo = space->select.sel_info.hslab->diminfo.opt;
4701
0
        else
4702
            /*
4703
             * Use the "application dimension information" to pass back to
4704
             * the user the blocks they set, not the optimized, internal
4705
             * information.
4706
             */
4707
0
            diminfo = space->select.sel_info.hslab->diminfo.app;
4708
4709
        /* Build the tables of count sizes as well as the initial offset */
4710
0
        for (u = 0; u < ndims; u++) {
4711
0
            tmp_count[u] = diminfo[u].count;
4712
0
            offset[u]    = diminfo[u].start;
4713
0
            end[u]       = diminfo[u].start + (diminfo[u].block - 1);
4714
0
        } /* end for */
4715
4716
        /* We're not done with the iteration */
4717
0
        done = false;
4718
4719
        /* Go iterate over the hyperslabs */
4720
0
        while (!done && numblocks > 0) {
4721
            /* Skip over initial blocks */
4722
0
            if (startblock > 0) {
4723
                /* Skip all blocks in row */
4724
0
                if (startblock >= tmp_count[fast_dim]) {
4725
0
                    startblock -= tmp_count[fast_dim];
4726
0
                    tmp_count[fast_dim] = 0;
4727
0
                } /* end if */
4728
0
                else {
4729
                    /* Move the offset to the next sequence to start */
4730
0
                    offset[fast_dim] += diminfo[fast_dim].stride * startblock;
4731
0
                    end[fast_dim] += diminfo[fast_dim].stride * startblock;
4732
4733
                    /* Decrement the block count */
4734
0
                    tmp_count[fast_dim] -= startblock;
4735
4736
                    /* Done with starting blocks */
4737
0
                    startblock = 0;
4738
0
                } /* end else */
4739
0
            }     /* end if */
4740
4741
            /* Iterate over the blocks in the fastest dimension */
4742
0
            while (tmp_count[fast_dim] > 0 && numblocks > 0) {
4743
                /* Sanity check */
4744
0
                assert(startblock == 0);
4745
4746
                /* Copy the starting location */
4747
0
                H5MM_memcpy(buf, offset, sizeof(hsize_t) * ndims);
4748
0
                buf += ndims;
4749
4750
                /* Compute the ending location */
4751
0
                H5MM_memcpy(buf, end, sizeof(hsize_t) * ndims);
4752
0
                buf += ndims;
4753
4754
                /* Decrement the number of blocks to retrieve */
4755
0
                numblocks--;
4756
4757
                /* Move the offset to the next sequence to start */
4758
0
                offset[fast_dim] += diminfo[fast_dim].stride;
4759
0
                end[fast_dim] += diminfo[fast_dim].stride;
4760
4761
                /* Decrement the block count */
4762
0
                tmp_count[fast_dim]--;
4763
0
            } /* end while */
4764
4765
            /* Work on other dimensions if necessary */
4766
0
            if (fast_dim > 0 && numblocks > 0) {
4767
0
                int temp_dim; /* Temporary rank holder */
4768
4769
                /* Reset the block counts */
4770
0
                tmp_count[fast_dim] = diminfo[fast_dim].count;
4771
4772
                /* Bubble up the decrement to the slower changing dimensions */
4773
0
                temp_dim = (int)(fast_dim - 1);
4774
0
                while (temp_dim >= 0 && !done) {
4775
                    /* Decrement the block count */
4776
0
                    tmp_count[temp_dim]--;
4777
4778
                    /* Check if we have more blocks left */
4779
0
                    if (tmp_count[temp_dim] > 0)
4780
0
                        break;
4781
4782
                    /* Reset the block count in this dimension */
4783
0
                    tmp_count[temp_dim] = diminfo[temp_dim].count;
4784
4785
                    /* Check for getting out of iterator */
4786
0
                    if (temp_dim == 0)
4787
0
                        done = true;
4788
4789
                    /* Wrapped a dimension, go up to next dimension */
4790
0
                    temp_dim--;
4791
0
                } /* end while */
4792
0
            }     /* end if */
4793
4794
            /* Re-compute offset & end arrays */
4795
0
            if (!done)
4796
0
                for (u = 0; u < ndims; u++) {
4797
0
                    offset[u] = diminfo[u].start + diminfo[u].stride * (diminfo[u].count - tmp_count[u]);
4798
0
                    end[u]    = offset[u] + (diminfo[u].block - 1);
4799
0
                } /* end for */
4800
0
        }         /* end while */
4801
0
    }             /* end if */
4802
0
    else {
4803
0
        hsize_t start[H5S_MAX_RANK]; /* Location of start of hyperslab */
4804
0
        hsize_t end[H5S_MAX_RANK];   /* Location of end of hyperslab */
4805
4806
0
        ret_value = H5S__hyper_span_blocklist(space->select.sel_info.hslab->span_lst, start, end, (hsize_t)0,
4807
0
                                              &startblock, &numblocks, &buf);
4808
0
    } /* end else */
4809
4810
0
done:
4811
0
    FUNC_LEAVE_NOAPI(ret_value)
4812
0
} /* end H5S__get_select_hyper_blocklist() */
4813
4814
/*--------------------------------------------------------------------------
4815
 NAME
4816
    H5Sget_select_hyper_blocklist
4817
 PURPOSE
4818
    Get the list of hyperslab blocks currently selected
4819
 USAGE
4820
    herr_t H5Sget_select_hyper_blocklist(dsid, startblock, numblocks, buf)
4821
        hid_t dsid;             IN: Dataspace ID of selection to query
4822
        hsize_t startblock;     IN: Hyperslab block to start with
4823
        hsize_t numblocks;      IN: Number of hyperslab blocks to get
4824
        hsize_t buf[];          OUT: List of hyperslab blocks selected
4825
 RETURNS
4826
    Non-negative on success, negative on failure
4827
 DESCRIPTION
4828
        Puts a list of the hyperslab blocks into the user's buffer.  The blocks
4829
    start with the 'startblock'th block in the list of blocks and put
4830
    'numblocks' number of blocks into the user's buffer (or until the end of
4831
    the list of blocks, whichever happen first)
4832
        The block coordinates have the same dimensionality (rank) as the
4833
    dataspace they are located within.  The list of blocks is formatted as
4834
    follows: <"start" coordinate> immediately followed by <"opposite" corner
4835
    coordinate>, followed by the next "start" and "opposite" coordinate, etc.
4836
    until all the block information requested has been put into the user's
4837
    buffer.
4838
        No guarantee of any order of the blocks is implied.
4839
 GLOBAL VARIABLES
4840
 COMMENTS, BUGS, ASSUMPTIONS
4841
 EXAMPLES
4842
 REVISION LOG
4843
--------------------------------------------------------------------------*/
4844
herr_t
4845
H5Sget_select_hyper_blocklist(hid_t spaceid, hsize_t startblock, hsize_t numblocks,
4846
                              hsize_t buf[/*numblocks*/] /*out*/)
4847
0
{
4848
0
    H5S_t *space;     /* Dataspace to modify selection of */
4849
0
    herr_t ret_value; /* return value */
4850
4851
0
    FUNC_ENTER_API(FAIL)
4852
4853
    /* Check args */
4854
0
    if (buf == NULL)
4855
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid pointer");
4856
0
    if (NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE)))
4857
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace");
4858
0
    if (H5S_GET_SELECT_TYPE(space) != H5S_SEL_HYPERSLABS)
4859
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a hyperslab selection");
4860
0
    if (space->select.sel_info.hslab->unlim_dim >= 0)
4861
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot get blocklist for unlimited selection");
4862
4863
    /* Go get the correct number of blocks */
4864
0
    if (numblocks > 0)
4865
0
        ret_value = H5S__get_select_hyper_blocklist(space, startblock, numblocks, buf);
4866
0
    else
4867
0
        ret_value = SUCCEED; /* Successfully got 0 blocks... */
4868
4869
0
done:
4870
0
    FUNC_LEAVE_API(ret_value)
4871
0
} /* end H5Sget_select_hyper_blocklist() */
4872
4873
/*--------------------------------------------------------------------------
4874
 NAME
4875
    H5S__hyper_bounds
4876
 PURPOSE
4877
    Gets the bounding box containing the selection.
4878
 USAGE
4879
    herr_t H5S__hyper_bounds(space, hsize_t *start, hsize_t *end)
4880
        H5S_t *space;           IN: Dataspace pointer of selection to query
4881
        hsize_t *start;         OUT: Starting coordinate of bounding box
4882
        hsize_t *end;           OUT: Opposite coordinate of bounding box
4883
 RETURNS
4884
    Non-negative on success, negative on failure
4885
 DESCRIPTION
4886
    Retrieves the bounding box containing the current selection and places
4887
    it into the user's buffers.  The start and end buffers must be large
4888
    enough to hold the dataspace rank number of coordinates.  The bounding box
4889
    exactly contains the selection, ie. if a 2-D element selection is currently
4890
    defined with the following points: (4,5), (6,8) (10,7), the bounding box
4891
    with be (4, 5), (10, 8).
4892
        The bounding box calculations _does_ include the current offset of the
4893
    selection within the dataspace extent.
4894
 GLOBAL VARIABLES
4895
 COMMENTS, BUGS, ASSUMPTIONS
4896
 EXAMPLES
4897
 REVISION LOG
4898
--------------------------------------------------------------------------*/
4899
static herr_t
4900
H5S__hyper_bounds(const H5S_t *space, hsize_t *start, hsize_t *end)
4901
0
{
4902
0
    const hsize_t *low_bounds, *high_bounds; /* Pointers to the correct pair of low & high bounds */
4903
0
    herr_t         ret_value = SUCCEED;      /* Return value */
4904
4905
0
    FUNC_ENTER_PACKAGE
4906
4907
    /* Sanity check */
4908
0
    assert(space);
4909
0
    assert(start);
4910
0
    assert(end);
4911
4912
    /* Check which set of low & high bounds we should be using */
4913
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
4914
0
        low_bounds  = space->select.sel_info.hslab->diminfo.low_bounds;
4915
0
        high_bounds = space->select.sel_info.hslab->diminfo.high_bounds;
4916
0
    } /* end if */
4917
0
    else {
4918
0
        low_bounds  = space->select.sel_info.hslab->span_lst->low_bounds;
4919
0
        high_bounds = space->select.sel_info.hslab->span_lst->high_bounds;
4920
0
    } /* end else */
4921
4922
    /* Check for offset set */
4923
0
    if (space->select.offset_changed) {
4924
0
        unsigned u; /* Local index variable */
4925
4926
        /* Loop over dimensions */
4927
0
        for (u = 0; u < space->extent.rank; u++) {
4928
            /* Sanity check */
4929
0
            assert(low_bounds[u] <= high_bounds[u]);
4930
4931
            /* Check for offset moving selection negative */
4932
0
            if (((hssize_t)low_bounds[u] + space->select.offset[u]) < 0)
4933
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds");
4934
4935
            /* Set the low & high bounds in this dimension */
4936
0
            start[u] = (hsize_t)((hssize_t)low_bounds[u] + space->select.offset[u]);
4937
0
            if ((int)u == space->select.sel_info.hslab->unlim_dim)
4938
0
                end[u] = H5S_UNLIMITED;
4939
0
            else
4940
0
                end[u] = (hsize_t)((hssize_t)high_bounds[u] + space->select.offset[u]);
4941
0
        } /* end for */
4942
0
    }     /* end if */
4943
0
    else {
4944
        /* Offset vector is still zeros, just copy low & high bounds */
4945
0
        H5MM_memcpy(start, low_bounds, sizeof(hsize_t) * space->extent.rank);
4946
0
        H5MM_memcpy(end, high_bounds, sizeof(hsize_t) * space->extent.rank);
4947
0
    } /* end else */
4948
4949
0
done:
4950
0
    FUNC_LEAVE_NOAPI(ret_value)
4951
0
} /* end H5S__hyper_bounds() */
4952
4953
/*--------------------------------------------------------------------------
4954
 NAME
4955
    H5S__hyper_offset
4956
 PURPOSE
4957
    Gets the linear offset of the first element for the selection.
4958
 USAGE
4959
    herr_t H5S__hyper_offset(space, offset)
4960
        const H5S_t *space;     IN: Dataspace pointer of selection to query
4961
        hsize_t *offset;        OUT: Linear offset of first element in selection
4962
 RETURNS
4963
    Non-negative on success, negative on failure
4964
 DESCRIPTION
4965
    Retrieves the linear offset (in "units" of elements) of the first element
4966
    selected within the dataspace.
4967
 GLOBAL VARIABLES
4968
 COMMENTS, BUGS, ASSUMPTIONS
4969
    Calling this function on a "none" selection returns fail.
4970
 EXAMPLES
4971
 REVISION LOG
4972
--------------------------------------------------------------------------*/
4973
static herr_t
4974
H5S__hyper_offset(const H5S_t *space, hsize_t *offset)
4975
0
{
4976
0
    const hssize_t *sel_offset;          /* Pointer to the selection's offset */
4977
0
    const hsize_t  *dim_size;            /* Pointer to a dataspace's extent */
4978
0
    hsize_t         accum;               /* Accumulator for dimension sizes */
4979
0
    unsigned        rank;                /* Dataspace rank */
4980
0
    int             i;                   /* index variable */
4981
0
    herr_t          ret_value = SUCCEED; /* Return value */
4982
4983
0
    FUNC_ENTER_PACKAGE
4984
4985
0
    assert(space && space->extent.rank > 0);
4986
0
    assert(offset);
4987
4988
    /* Start at linear offset 0 */
4989
0
    *offset = 0;
4990
4991
    /* Set up pointers to arrays of values */
4992
0
    rank       = space->extent.rank;
4993
0
    sel_offset = space->select.offset;
4994
0
    dim_size   = space->extent.size;
4995
4996
    /* Check for a "regular" hyperslab selection */
4997
    /* (No need to rebuild the dimension info yet -QAK) */
4998
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
4999
0
        const H5S_hyper_dim_t *diminfo =
5000
0
            space->select.sel_info.hslab->diminfo.opt; /* Local alias for diminfo */
5001
5002
        /* Loop through starting coordinates, calculating the linear offset */
5003
0
        accum = 1;
5004
0
        for (i = (int)(rank - 1); i >= 0; i--) {
5005
0
            hssize_t hyp_offset =
5006
0
                (hssize_t)diminfo[i].start + sel_offset[i]; /* Hyperslab's offset in this dimension */
5007
5008
            /* Check for offset moving selection out of the dataspace */
5009
0
            if (hyp_offset < 0 || (hsize_t)hyp_offset >= dim_size[i])
5010
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds");
5011
5012
            /* Add the hyperslab's offset in this dimension to the total linear offset */
5013
0
            *offset += (hsize_t)(hyp_offset * (hssize_t)accum);
5014
5015
            /* Increase the accumulator */
5016
0
            accum *= dim_size[i];
5017
0
        } /* end for */
5018
0
    }     /* end if */
5019
0
    else {
5020
0
        const H5S_hyper_span_t *span;                    /* Hyperslab span node */
5021
0
        hsize_t                 dim_accum[H5S_MAX_RANK]; /* Accumulators, for each dimension */
5022
5023
        /* Calculate the accumulator for each dimension */
5024
0
        accum = 1;
5025
0
        for (i = (int)(rank - 1); i >= 0; i--) {
5026
            /* Set the accumulator for this dimension */
5027
0
            dim_accum[i] = accum;
5028
5029
            /* Increase the accumulator */
5030
0
            accum *= dim_size[i];
5031
0
        } /* end for */
5032
5033
        /* Get information for the first span, in the slowest changing dimension */
5034
0
        span = space->select.sel_info.hslab->span_lst->head;
5035
5036
        /* Work down the spans, computing the linear offset */
5037
0
        i = 0;
5038
0
        while (span) {
5039
0
            hssize_t hyp_offset =
5040
0
                (hssize_t)span->low + sel_offset[i]; /* Hyperslab's offset in this dimension */
5041
5042
            /* Check for offset moving selection out of the dataspace */
5043
0
            if (hyp_offset < 0 || (hsize_t)hyp_offset >= dim_size[i])
5044
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds");
5045
5046
            /* Add the hyperslab's offset in this dimension to the total linear offset */
5047
0
            *offset += (hsize_t)(hyp_offset * (hssize_t)dim_accum[i]);
5048
5049
            /* Advance to first span in "down" dimension */
5050
0
            if (span->down) {
5051
0
                assert(span->down->head);
5052
0
                span = span->down->head;
5053
0
            } /* end if */
5054
0
            else
5055
0
                span = NULL;
5056
0
            i++;
5057
0
        } /* end while */
5058
0
    }     /* end else */
5059
5060
0
done:
5061
0
    FUNC_LEAVE_NOAPI(ret_value)
5062
0
} /* end H5S__hyper_offset() */
5063
5064
/*--------------------------------------------------------------------------
5065
 NAME
5066
    H5S__hyper_unlim_dim
5067
 PURPOSE
5068
    Return unlimited dimension of selection, or -1 if none
5069
 USAGE
5070
    int H5S__hyper_unlim_dim(space)
5071
        H5S_t *space;           IN: Dataspace pointer to check
5072
 RETURNS
5073
    Unlimited dimension of selection, or -1 if none (never fails).
5074
 DESCRIPTION
5075
    Returns the index of the unlimited dimension of the selection, or -1
5076
    if the selection has no unlimited dimension.
5077
 GLOBAL VARIABLES
5078
 COMMENTS, BUGS, ASSUMPTIONS
5079
 EXAMPLES
5080
 REVISION LOG
5081
--------------------------------------------------------------------------*/
5082
static int
5083
H5S__hyper_unlim_dim(const H5S_t *space)
5084
0
{
5085
0
    FUNC_ENTER_PACKAGE_NOERR
5086
5087
0
    FUNC_LEAVE_NOAPI(space->select.sel_info.hslab->unlim_dim)
5088
0
} /* end H5S__hyper_unlim_dim() */
5089
5090
/*--------------------------------------------------------------------------
5091
 NAME
5092
    H5S__hyper_num_elem_non_unlim
5093
 PURPOSE
5094
    Return number of elements in the non-unlimited dimensions
5095
 USAGE
5096
    herr_t H5S__hyper_num_elem_non_unlim(space,num_elem_non_unlim)
5097
        H5S_t *space;           IN: Dataspace pointer to check
5098
        hsize_t *num_elem_non_unlim; OUT: Number of elements in the non-unlimited dimensions
5099
 RETURNS
5100
    Non-negative on success/Negative on failure
5101
 DESCRIPTION
5102
    Returns the number of elements in a slice through the non-unlimited
5103
    dimensions of the selection.  Fails if the selection has no unlimited
5104
    dimension.
5105
 GLOBAL VARIABLES
5106
 COMMENTS, BUGS, ASSUMPTIONS
5107
 EXAMPLES
5108
 REVISION LOG
5109
--------------------------------------------------------------------------*/
5110
static herr_t
5111
H5S__hyper_num_elem_non_unlim(const H5S_t *space, hsize_t *num_elem_non_unlim)
5112
0
{
5113
0
    herr_t ret_value = SUCCEED;
5114
5115
0
    FUNC_ENTER_PACKAGE
5116
5117
    /* Sanity check */
5118
0
    assert(space);
5119
0
    assert(num_elem_non_unlim);
5120
5121
    /* Get number of elements in the non-unlimited dimensions */
5122
0
    if (space->select.sel_info.hslab->unlim_dim >= 0)
5123
0
        *num_elem_non_unlim = space->select.sel_info.hslab->num_elem_non_unlim;
5124
0
    else
5125
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "selection has no unlimited dimension");
5126
5127
0
done:
5128
0
    FUNC_LEAVE_NOAPI(ret_value)
5129
0
} /* end H5S__hyper_num_elem_non_unlim() */
5130
5131
/*--------------------------------------------------------------------------
5132
 NAME
5133
    H5S__hyper_is_contiguous
5134
 PURPOSE
5135
    Check if a hyperslab selection is contiguous within the dataspace extent.
5136
 USAGE
5137
    htri_t H5S__hyper_is_contiguous(space)
5138
        H5S_t *space;           IN: Dataspace pointer to check
5139
 RETURNS
5140
    true/false/FAIL
5141
 DESCRIPTION
5142
    Checks to see if the current selection in the dataspace is contiguous.
5143
    This is primarily used for reading the entire selection in one swoop.
5144
 GLOBAL VARIABLES
5145
 COMMENTS, BUGS, ASSUMPTIONS
5146
 EXAMPLES
5147
 REVISION LOG
5148
--------------------------------------------------------------------------*/
5149
static H5_ATTR_PURE htri_t
5150
H5S__hyper_is_contiguous(const H5S_t *space)
5151
0
{
5152
0
    bool small_contiguous,      /* Flag for small contiguous block */
5153
0
        large_contiguous;       /* Flag for large contiguous block */
5154
0
    unsigned u;                 /* index variable */
5155
0
    htri_t   ret_value = false; /* Return value */
5156
5157
0
    FUNC_ENTER_PACKAGE_NOERR
5158
5159
0
    assert(space);
5160
5161
    /* Check for a "regular" hyperslab selection */
5162
    /* (No need to rebuild the dimension info yet -QAK) */
5163
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
5164
0
        const H5S_hyper_dim_t *diminfo =
5165
0
            space->select.sel_info.hslab->diminfo.opt; /* local alias for diminfo */
5166
5167
        /*
5168
         * For a regular hyperslab to be contiguous, it must have only one
5169
         * block (i.e. count==1 in all dimensions) and the block size must be
5170
         * the same as the dataspace extent's in all but the slowest changing
5171
         * dimension. (dubbed "large contiguous" block)
5172
         *
5173
         * OR
5174
         *
5175
         * The selection must have only one block (i.e. count==1) in all
5176
         * dimensions and the block size must be 1 in all but the fastest
5177
         * changing dimension. (dubbed "small contiguous" block)
5178
         */
5179
5180
        /* Initialize flags */
5181
0
        large_contiguous = true;  /* assume true and reset if the dimensions don't match */
5182
0
        small_contiguous = false; /* assume false initially */
5183
5184
        /* Check for a "large contiguous" block */
5185
0
        for (u = 0; u < space->extent.rank; u++) {
5186
0
            if (diminfo[u].count > 1) {
5187
0
                large_contiguous = false;
5188
0
                break;
5189
0
            } /* end if */
5190
0
            if (u > 0 && diminfo[u].block != space->extent.size[u]) {
5191
0
                large_contiguous = false;
5192
0
                break;
5193
0
            } /* end if */
5194
0
        }     /* end for */
5195
5196
        /* If we didn't find a large contiguous block, check for a small one */
5197
0
        if (!large_contiguous) {
5198
0
            small_contiguous = true;
5199
0
            for (u = 0; u < space->extent.rank; u++) {
5200
0
                if (diminfo[u].count > 1) {
5201
0
                    small_contiguous = false;
5202
0
                    break;
5203
0
                } /* end if */
5204
0
                if (u < (space->extent.rank - 1) && diminfo[u].block != 1) {
5205
0
                    small_contiguous = false;
5206
0
                    break;
5207
0
                } /* end if */
5208
0
            }     /* end for */
5209
0
        }         /* end if */
5210
5211
        /* Indicate true if it's either a large or small contiguous block */
5212
0
        if (large_contiguous || small_contiguous)
5213
0
            ret_value = true;
5214
0
    } /* end if */
5215
0
    else {
5216
0
        H5S_hyper_span_info_t *spans; /* Hyperslab span info node */
5217
0
        H5S_hyper_span_t      *span;  /* Hyperslab span node */
5218
5219
        /*
5220
         * For a hyperslab to be contiguous, it must have only one block and
5221
         * either it's size must be the same as the dataspace extent's in all
5222
         *      but the slowest changing dimension
5223
         *   OR
5224
         *      block size must be 1 in all but the fastest changing dimension.
5225
         */
5226
        /* Initialize flags */
5227
0
        large_contiguous = true;  /* assume true and reset if the dimensions don't match */
5228
0
        small_contiguous = false; /* assume false initially */
5229
5230
        /* Get information for slowest changing information */
5231
0
        spans = space->select.sel_info.hslab->span_lst;
5232
0
        span  = spans->head;
5233
5234
        /* If there are multiple spans in the slowest changing dimension, the selection isn't contiguous */
5235
0
        if (span->next != NULL)
5236
0
            large_contiguous = false;
5237
0
        else {
5238
            /* Now check the rest of the dimensions */
5239
0
            if (span->down != NULL) {
5240
0
                u = 1; /* Current dimension working on */
5241
5242
                /* Get the span information for the next fastest dimension */
5243
0
                spans = span->down;
5244
5245
                /* Cycle down the spans until we run out of down spans or find a non-contiguous span */
5246
0
                while (spans != NULL) {
5247
0
                    span = spans->head;
5248
5249
                    /* Check that this is the only span and it spans the entire dimension */
5250
0
                    if (span->next != NULL) {
5251
0
                        large_contiguous = false;
5252
0
                        break;
5253
0
                    } /* end if */
5254
0
                    else {
5255
                        /* If this span doesn't cover the entire dimension, then this selection isn't
5256
                         * contiguous */
5257
0
                        if (((span->high - span->low) + 1) != space->extent.size[u]) {
5258
0
                            large_contiguous = false;
5259
0
                            break;
5260
0
                        } /* end if */
5261
0
                        else {
5262
                            /* Walk down to the next span */
5263
0
                            spans = span->down;
5264
5265
                            /* Increment dimension */
5266
0
                            u++;
5267
0
                        } /* end else */
5268
0
                    }     /* end else */
5269
0
                }         /* end while */
5270
0
            }             /* end if */
5271
0
        }                 /* end else */
5272
5273
        /* If we didn't find a large contiguous block, check for a small one */
5274
0
        if (!large_contiguous) {
5275
0
            small_contiguous = true;
5276
5277
            /* Get information for slowest changing information */
5278
0
            spans = space->select.sel_info.hslab->span_lst;
5279
0
            span  = spans->head;
5280
5281
            /* Current dimension working on */
5282
0
            u = 0;
5283
5284
            /* Cycle down the spans until we run out of down spans or find a non-contiguous span */
5285
0
            while (spans != NULL) {
5286
0
                span = spans->head;
5287
5288
                /* Check that this is the only span and it spans the entire dimension */
5289
0
                if (span->next != NULL) {
5290
0
                    small_contiguous = false;
5291
0
                    break;
5292
0
                } /* end if */
5293
0
                else {
5294
                    /* If this span doesn't cover the entire dimension, then this selection isn't contiguous
5295
                     */
5296
0
                    if (u < (space->extent.rank - 1) && ((span->high - span->low) + 1) != 1) {
5297
0
                        small_contiguous = false;
5298
0
                        break;
5299
0
                    } /* end if */
5300
0
                    else {
5301
                        /* Walk down to the next span */
5302
0
                        spans = span->down;
5303
5304
                        /* Increment dimension */
5305
0
                        u++;
5306
0
                    } /* end else */
5307
0
                }     /* end else */
5308
0
            }         /* end while */
5309
0
        }             /* end if */
5310
5311
        /* Indicate true if it's either a large or small contiguous block */
5312
0
        if (large_contiguous || small_contiguous)
5313
0
            ret_value = true;
5314
0
    } /* end else */
5315
5316
0
    FUNC_LEAVE_NOAPI(ret_value)
5317
0
} /* end H5S__hyper_is_contiguous() */
5318
5319
/*--------------------------------------------------------------------------
5320
 NAME
5321
    H5S__hyper_is_single
5322
 PURPOSE
5323
    Check if a hyperslab selection is a single block within the dataspace extent.
5324
 USAGE
5325
    htri_t H5S__hyper_is_single(space)
5326
        H5S_t *space;           IN: Dataspace pointer to check
5327
 RETURNS
5328
    true/false/FAIL
5329
 DESCRIPTION
5330
    Checks to see if the current selection in the dataspace is a single block.
5331
    This is primarily used for reading the entire selection in one swoop.
5332
 GLOBAL VARIABLES
5333
 COMMENTS, BUGS, ASSUMPTIONS
5334
 EXAMPLES
5335
 REVISION LOG
5336
--------------------------------------------------------------------------*/
5337
static H5_ATTR_PURE htri_t
5338
H5S__hyper_is_single(const H5S_t *space)
5339
0
{
5340
0
    htri_t ret_value = true; /* return value */
5341
5342
0
    FUNC_ENTER_PACKAGE_NOERR
5343
5344
0
    assert(space);
5345
5346
    /* Check for a "single" hyperslab selection */
5347
    /* (No need to rebuild the dimension info yet, since the span-tree
5348
     *  algorithm is fast -QAK)
5349
     */
5350
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
5351
0
        unsigned u; /* index variable */
5352
5353
        /*
5354
         * For a regular hyperslab to be single, it must have only one
5355
         * block (i.e. count==1 in all dimensions)
5356
         */
5357
5358
        /* Check for a single block */
5359
0
        for (u = 0; u < space->extent.rank; u++)
5360
0
            if (space->select.sel_info.hslab->diminfo.opt[u].count > 1)
5361
0
                HGOTO_DONE(false);
5362
0
    } /* end if */
5363
0
    else {
5364
0
        H5S_hyper_span_info_t *spans; /* Hyperslab span info node */
5365
5366
        /*
5367
         * For a region to be single, it must have only one block
5368
         */
5369
        /* Get information for slowest changing information */
5370
0
        spans = space->select.sel_info.hslab->span_lst;
5371
5372
        /* Cycle down the spans until we run out of down spans or find a non-contiguous span */
5373
0
        while (spans != NULL) {
5374
0
            H5S_hyper_span_t *span; /* Hyperslab span node */
5375
5376
0
            span = spans->head;
5377
5378
            /* Check that this is the only span and it spans the entire dimension */
5379
0
            if (span->next != NULL)
5380
0
                HGOTO_DONE(false);
5381
0
            else
5382
                /* Walk down to the next span */
5383
0
                spans = span->down;
5384
0
        } /* end while */
5385
0
    }     /* end else */
5386
5387
0
done:
5388
0
    FUNC_LEAVE_NOAPI(ret_value)
5389
0
} /* end H5S__hyper_is_single() */
5390
5391
/*--------------------------------------------------------------------------
5392
 NAME
5393
    H5S__hyper_is_regular
5394
 PURPOSE
5395
    Check if a hyperslab selection is "regular"
5396
 USAGE
5397
    htri_t H5S__hyper_is_regular(space)
5398
        H5S_t *space;     IN: Dataspace pointer to check
5399
 RETURNS
5400
    true/false/FAIL
5401
 DESCRIPTION
5402
    Checks to see if the current selection in a dataspace is the a regular
5403
    pattern.
5404
    This is primarily used for reading the entire selection in one swoop.
5405
 GLOBAL VARIABLES
5406
 COMMENTS, BUGS, ASSUMPTIONS
5407
 EXAMPLES
5408
 REVISION LOG
5409
--------------------------------------------------------------------------*/
5410
static htri_t
5411
H5S__hyper_is_regular(H5S_t *space)
5412
0
{
5413
0
    htri_t ret_value = FAIL; /* return value */
5414
5415
0
    FUNC_ENTER_PACKAGE_NOERR
5416
5417
    /* Check args */
5418
0
    assert(space);
5419
5420
    /* Attempt to rebuild diminfo if it is invalid and has not been confirmed
5421
     * to be impossible.
5422
     */
5423
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO)
5424
0
        H5S__hyper_rebuild(space);
5425
5426
    /* Only simple check for regular hyperslabs for now... */
5427
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES)
5428
0
        ret_value = true;
5429
0
    else
5430
0
        ret_value = false;
5431
5432
0
    FUNC_LEAVE_NOAPI(ret_value)
5433
0
} /* end H5S__hyper_is_regular() */
5434
5435
/*--------------------------------------------------------------------------
5436
 NAME
5437
    H5S__hyper_spans_shape_same_helper
5438
 PURPOSE
5439
    Helper routine to check if two hyperslab span trees are the same shape
5440
 USAGE
5441
    bool H5S__hyper_spans_shape_same_helper(span1, span2, offset, rest_zeros)
5442
        H5S_hyper_span_info_t *span_info1;      IN: First span tree to compare
5443
        H5S_hyper_span_info_t *span_info2;      IN: Second span tree to compare
5444
        hssize_t offset[];                      IN: Offset between the span trees
5445
        bool rest_zeros[];                   IN: Array of flags which indicate
5446
                                                    the rest of the offset[] array
5447
                                                    is zero values.
5448
 RETURNS
5449
    true (1) or false (0) on success, can't fail
5450
 DESCRIPTION
5451
    Compare two hyperslab span trees to determine if they refer to a selection
5452
    with the same shape, with a possible (constant) offset between their
5453
    elements.  Very similar to H5S__hyper_cmp_spans, except the selected
5454
    elements can be offset by a vector.
5455
 GLOBAL VARIABLES
5456
 COMMENTS, BUGS, ASSUMPTIONS
5457
 EXAMPLES
5458
 REVISION LOG
5459
--------------------------------------------------------------------------*/
5460
static H5_ATTR_PURE bool
5461
H5S__hyper_spans_shape_same_helper(const H5S_hyper_span_info_t *span_info1,
5462
                                   const H5S_hyper_span_info_t *span_info2, hssize_t offset[],
5463
                                   bool rest_zeros[])
5464
0
{
5465
0
    bool ret_value = true; /* Return value */
5466
5467
0
    FUNC_ENTER_PACKAGE_NOERR
5468
5469
    /* Sanity checks */
5470
0
    assert(span_info1);
5471
0
    assert(span_info2);
5472
0
    assert(offset);
5473
0
    assert(rest_zeros);
5474
5475
    /* Compare low & high bounds for this span list */
5476
    /* (Could compare lower dimensions also, but not certain if
5477
     *      that's worth it. - QAK, 2019/01/23)
5478
     */
5479
0
    if ((hsize_t)((hssize_t)span_info1->low_bounds[0] + offset[0]) != span_info2->low_bounds[0])
5480
0
        HGOTO_DONE(false);
5481
0
    else if ((hsize_t)((hssize_t)span_info1->high_bounds[0] + offset[0]) != span_info2->high_bounds[0])
5482
0
        HGOTO_DONE(false);
5483
0
    else {
5484
0
        const H5S_hyper_span_t *span1;
5485
0
        const H5S_hyper_span_t *span2;
5486
5487
        /* Get the pointers to the actual lists of spans */
5488
0
        span1 = span_info1->head;
5489
0
        span2 = span_info2->head;
5490
5491
        /* Sanity checking */
5492
0
        assert(span1);
5493
0
        assert(span2);
5494
5495
        /* infinite loop which must be broken out of */
5496
0
        while (1) {
5497
            /* Check for both spans being NULL */
5498
0
            if (span1 == NULL && span2 == NULL)
5499
0
                HGOTO_DONE(true);
5500
5501
            /* Check for one span being NULL */
5502
0
            if (span1 == NULL || span2 == NULL)
5503
0
                HGOTO_DONE(false);
5504
5505
            /* Check if the actual low & high span information is the same */
5506
0
            if ((hsize_t)((hssize_t)span1->low + offset[0]) != span2->low ||
5507
0
                (hsize_t)((hssize_t)span1->high + offset[0]) != span2->high)
5508
0
                HGOTO_DONE(false);
5509
5510
            /* Check for down tree for this span */
5511
0
            if (span1->down != NULL || span2->down != NULL) {
5512
                /* If the rest of the span trees have a zero offset, use the faster comparison routine */
5513
0
                if (rest_zeros[0]) {
5514
0
                    if (!H5S__hyper_cmp_spans(span1->down, span2->down))
5515
0
                        HGOTO_DONE(false);
5516
0
                    else {
5517
                        /* Keep going... */
5518
0
                    } /* end else */
5519
0
                }     /* end if */
5520
0
                else {
5521
0
                    if (!H5S__hyper_spans_shape_same_helper(span1->down, span2->down, &offset[1],
5522
0
                                                            &rest_zeros[1]))
5523
0
                        HGOTO_DONE(false);
5524
0
                    else {
5525
                        /* Keep going... */
5526
0
                    } /* end else */
5527
0
                }     /* end else */
5528
0
            }         /* end if */
5529
0
            else {
5530
                /* Keep going... */
5531
0
            } /* end else */
5532
5533
            /* Advance to the next nodes in the span list */
5534
0
            span1 = span1->next;
5535
0
            span2 = span2->next;
5536
0
        } /* end while */
5537
0
    }     /* end else */
5538
5539
    /* Fall through, with default return value of 'true' if spans were already visited */
5540
5541
0
done:
5542
0
    FUNC_LEAVE_NOAPI(ret_value)
5543
0
} /* end H5S__hyper_spans_shape_same_helper() */
5544
5545
/*--------------------------------------------------------------------------
5546
 NAME
5547
    H5S__hyper_spans_shape_same
5548
 PURPOSE
5549
    Check if two hyperslab span trees are the same shape
5550
 USAGE
5551
    bool H5S__hyper_spans_shape_same(span1, span2)
5552
        H5S_hyper_span_info_t *span_info1;      IN: First span tree to compare
5553
        H5S_hyper_span_info_t *span_info2;      IN: Second span tree to compare
5554
 RETURNS
5555
    true (1) or false (0) on success, can't fail
5556
 DESCRIPTION
5557
    Compare two hyperslab span trees to determine if they refer to a selection
5558
    with the same shape.  Very similar to H5S__hyper_cmp_spans, except the
5559
    selected elements can be offset by a vector.
5560
 GLOBAL VARIABLES
5561
 COMMENTS, BUGS, ASSUMPTIONS
5562
 EXAMPLES
5563
 REVISION LOG
5564
--------------------------------------------------------------------------*/
5565
static H5_ATTR_PURE bool
5566
H5S__hyper_spans_shape_same(const H5S_hyper_span_info_t *span_info1, const H5S_hyper_span_info_t *span_info2,
5567
                            unsigned ndims)
5568
0
{
5569
0
    const H5S_hyper_span_t *span1;                /* Pointer to spans in first span tree */
5570
0
    const H5S_hyper_span_t *span2;                /* Pointer to spans in second span tree */
5571
0
    hssize_t                offset[H5S_MAX_RANK]; /* Offset vector for selections */
5572
0
    bool     rest_zeros[H5S_MAX_RANK]; /* Vector of flags to indicate when remaining offset is all zero */
5573
0
    bool     zero_offset;              /* Whether the two selections have a non-zero offset */
5574
0
    unsigned u;                        /* Local index variable */
5575
0
    bool     ret_value = true;         /* Return value */
5576
5577
0
    FUNC_ENTER_PACKAGE_NOERR
5578
5579
    /* Sanity check */
5580
0
    assert(span_info1);
5581
0
    assert(span_info2);
5582
0
    assert(ndims > 0);
5583
5584
    /* Initialize arrays */
5585
0
    memset(offset, 0, sizeof(offset));
5586
0
    memset(rest_zeros, 0, sizeof(rest_zeros));
5587
5588
    /* Check for an offset between the two selections */
5589
0
    span1       = span_info1->head;
5590
0
    span2       = span_info2->head;
5591
0
    zero_offset = true;
5592
0
    for (u = 0; u < ndims; u++) {
5593
        /* Check for offset in this dimension */
5594
0
        if (span1->low != span2->low) {
5595
0
            offset[u] = (hssize_t)span2->low - (hssize_t)span1->low;
5596
5597
            /* Indicate that the offset vector is not all zeros */
5598
0
            if (zero_offset)
5599
0
                zero_offset = false;
5600
0
        } /* end if */
5601
5602
        /* Sanity check */
5603
        /* (Both span trees must have the same depth) */
5604
0
        assert((span1->down && span2->down) || (NULL == span1->down && NULL == span2->down));
5605
5606
        /* Advance to next dimension */
5607
0
        if (span1->down) {
5608
0
            span1 = span1->down->head;
5609
0
            span2 = span2->down->head;
5610
0
        } /* end if */
5611
0
    }     /* end for */
5612
5613
    /* Check if there's a "tail" of all zeros in a non-zero offset vector */
5614
0
    if (!zero_offset) {
5615
0
        int i; /* Local index variable */
5616
5617
        /* Find first non-zero offset, from the fastest dimension up */
5618
0
        for (i = (int)(ndims - 1); i >= 0; i--)
5619
0
            if (offset[i]) {
5620
0
                rest_zeros[i] = true;
5621
0
                break;
5622
0
            } /* end if */
5623
5624
        /* Sanity check */
5625
        /* (Must eventually have found a non-zero offset) */
5626
0
        assert(i >= 0);
5627
0
    } /* end if */
5628
5629
    /* If the offset vector is all zero, we can use the faster span tree
5630
     *  comparison routine.  Otherwise, use a generalized version of that
5631
     *  routine.
5632
     */
5633
0
    if (zero_offset)
5634
0
        ret_value = H5S__hyper_cmp_spans(span_info1, span_info2);
5635
0
    else
5636
0
        ret_value = H5S__hyper_spans_shape_same_helper(span_info1, span_info2, offset, rest_zeros);
5637
5638
0
    FUNC_LEAVE_NOAPI(ret_value)
5639
0
} /* end H5S__hyper_spans_shape_same() */
5640
5641
/*--------------------------------------------------------------------------
5642
 NAME
5643
    H5S__hyper_shape_same
5644
 PURPOSE
5645
    Check if a two hyperslab selections are the same shape
5646
 USAGE
5647
    htri_t H5S__hyper_shape_same(space1, space2)
5648
        H5S_t *space1;           IN: First dataspace to check
5649
        H5S_t *space2;           IN: Second dataspace to check
5650
 RETURNS
5651
    true / false / FAIL
5652
 DESCRIPTION
5653
    Checks to see if the current selection in each dataspace are the same
5654
    shape.
5655
 GLOBAL VARIABLES
5656
 COMMENTS, BUGS, ASSUMPTIONS
5657
    Handles when both are regular in an efficient way, otherwise converts
5658
    both to span tree form (if necessary) and compares efficiently them in
5659
    that form.
5660
5661
    Rank of space1 must always be >= to rank of space2.
5662
 EXAMPLES
5663
 REVISION LOG
5664
--------------------------------------------------------------------------*/
5665
static htri_t
5666
H5S__hyper_shape_same(H5S_t *space1, H5S_t *space2)
5667
0
{
5668
0
    unsigned space1_rank;      /* Number of dimensions of first dataspace */
5669
0
    unsigned space2_rank;      /* Number of dimensions of second dataspace */
5670
0
    htri_t   ret_value = true; /* Return value */
5671
5672
0
    FUNC_ENTER_PACKAGE
5673
5674
    /* Check args */
5675
0
    assert(space1);
5676
0
    assert(space2);
5677
5678
    /* Get dataspace ranks */
5679
0
    space1_rank = space1->extent.rank;
5680
0
    space2_rank = space2->extent.rank;
5681
5682
    /* Sanity check */
5683
0
    assert(space1_rank >= space2_rank);
5684
0
    assert(space2_rank > 0);
5685
5686
    /* Rebuild diminfo if it is invalid and has not been confirmed to be
5687
     * impossible */
5688
0
    if (space1->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO)
5689
0
        H5S__hyper_rebuild(space1);
5690
0
    if (space2->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO)
5691
0
        H5S__hyper_rebuild(space2);
5692
5693
    /* If both are regular hyperslabs, compare their diminfo values */
5694
0
    if (space1->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES &&
5695
0
        space2->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
5696
0
        int space1_dim; /* Current dimension in first dataspace */
5697
0
        int space2_dim; /* Current dimension in second dataspace */
5698
5699
        /* Initialize dimensions */
5700
0
        space1_dim = (int)space1_rank - 1;
5701
0
        space2_dim = (int)space2_rank - 1;
5702
5703
        /* Check that the shapes are the same in the common dimensions, and that
5704
         * block == 1 in all dimensions that appear only in space1.
5705
         */
5706
0
        while (space2_dim >= 0) {
5707
0
            if (space1->select.sel_info.hslab->diminfo.opt[space1_dim].stride !=
5708
0
                space2->select.sel_info.hslab->diminfo.opt[space2_dim].stride)
5709
0
                HGOTO_DONE(false);
5710
5711
0
            if (space1->select.sel_info.hslab->diminfo.opt[space1_dim].count !=
5712
0
                space2->select.sel_info.hslab->diminfo.opt[space2_dim].count)
5713
0
                HGOTO_DONE(false);
5714
5715
0
            if (space1->select.sel_info.hslab->diminfo.opt[space1_dim].block !=
5716
0
                space2->select.sel_info.hslab->diminfo.opt[space2_dim].block)
5717
0
                HGOTO_DONE(false);
5718
5719
0
            space1_dim--;
5720
0
            space2_dim--;
5721
0
        } /* end while */
5722
5723
0
        while (space1_dim >= 0) {
5724
0
            if (space1->select.sel_info.hslab->diminfo.opt[space1_dim].block != 1)
5725
0
                HGOTO_DONE(false);
5726
5727
0
            space1_dim--;
5728
0
        } /* end while */
5729
0
    }     /* end if */
5730
    /* If both aren't regular, use fast irregular comparison */
5731
0
    else {
5732
0
        H5S_hyper_span_info_t *spans1; /* Hyperslab spans for first dataspace */
5733
5734
        /* Make certain that both selections have span trees */
5735
0
        if (NULL == space1->select.sel_info.hslab->span_lst)
5736
0
            if (H5S__hyper_generate_spans(space1) < 0)
5737
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL,
5738
0
                            "can't construct span tree for hyperslab selection");
5739
0
        if (NULL == space2->select.sel_info.hslab->span_lst)
5740
0
            if (H5S__hyper_generate_spans(space2) < 0)
5741
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL,
5742
0
                            "can't construct span tree for hyperslab selection");
5743
5744
        /* If rank of space A is different (guaranteed greater) than
5745
         *      rank of space B, walk down the span tree, verifying
5746
         *      that the block size is 1 on the way down.
5747
         */
5748
0
        if (space1_rank > space2_rank) {
5749
0
            unsigned diff_rank = space1_rank - space2_rank; /* Difference in ranks */
5750
5751
            /* Walk down the dimensions */
5752
0
            spans1 = space1->select.sel_info.hslab->span_lst;
5753
0
            while (diff_rank > 0) {
5754
0
                H5S_hyper_span_t *span; /* Span for this dimension */
5755
5756
                /* Get pointer to first span in tree */
5757
0
                span = spans1->head;
5758
5759
                /* Check for more spans in this dimension */
5760
0
                if (span->next)
5761
0
                    HGOTO_DONE(false);
5762
5763
                /* Check for span size > 1 element */
5764
0
                if (span->low != span->high)
5765
0
                    HGOTO_DONE(false);
5766
5767
                /* Walk down to the next dimension */
5768
0
                spans1 = span->down;
5769
0
                diff_rank--;
5770
0
            } /* end while */
5771
5772
            /* Sanity check */
5773
0
            assert(spans1);
5774
0
        } /* end if */
5775
0
        else
5776
0
            spans1 = space1->select.sel_info.hslab->span_lst;
5777
5778
        /* Compare the span trees */
5779
0
        ret_value = H5S__hyper_spans_shape_same(spans1, space2->select.sel_info.hslab->span_lst, space2_rank);
5780
0
    } /* end else */
5781
5782
    /* Fall through with 'true' value, if not set earlier */
5783
5784
0
done:
5785
0
    FUNC_LEAVE_NOAPI(ret_value)
5786
0
} /* end H5S__hyper_shape_same() */
5787
5788
/*--------------------------------------------------------------------------
5789
 NAME
5790
    H5S__hyper_release
5791
 PURPOSE
5792
    Release hyperslab selection information for a dataspace
5793
 USAGE
5794
    herr_t H5S__hyper_release(space)
5795
        H5S_t *space;       IN: Pointer to dataspace
5796
 RETURNS
5797
    Non-negative on success/Negative on failure
5798
 DESCRIPTION
5799
    Releases all hyperslab selection information for a dataspace
5800
 GLOBAL VARIABLES
5801
 COMMENTS, BUGS, ASSUMPTIONS
5802
 EXAMPLES
5803
 REVISION LOG
5804
--------------------------------------------------------------------------*/
5805
static herr_t
5806
H5S__hyper_release(H5S_t *space)
5807
0
{
5808
0
    herr_t ret_value = SUCCEED;
5809
5810
0
    FUNC_ENTER_PACKAGE
5811
5812
    /* Check args */
5813
0
    assert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space));
5814
5815
    /* Reset the number of points selected */
5816
0
    space->select.num_elem = 0;
5817
5818
    /* Release irregular hyperslab information */
5819
0
    if (space->select.sel_info.hslab) {
5820
0
        if (space->select.sel_info.hslab->span_lst != NULL)
5821
0
            if (H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst) < 0)
5822
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "unable to free span info");
5823
5824
        /* Release space for the hyperslab selection information */
5825
0
        space->select.sel_info.hslab = H5FL_FREE(H5S_hyper_sel_t, space->select.sel_info.hslab);
5826
0
    }
5827
5828
0
done:
5829
0
    FUNC_LEAVE_NOAPI(ret_value)
5830
0
} /* end H5S__hyper_release() */
5831
5832
/*--------------------------------------------------------------------------
5833
 NAME
5834
    H5S__hyper_coord_to_span
5835
 PURPOSE
5836
    Create a span tree for a single element
5837
 USAGE
5838
    H5S_hyper_span_t *H5S__hyper_coord_to_span(rank, coords)
5839
        unsigned rank;                  IN: Number of dimensions of coordinate
5840
        hsize_t *coords;               IN: Location of element
5841
 RETURNS
5842
    Non-NULL pointer to new span tree on success, NULL on failure
5843
 DESCRIPTION
5844
    Create a span tree for a single element
5845
 GLOBAL VARIABLES
5846
 COMMENTS, BUGS, ASSUMPTIONS
5847
 EXAMPLES
5848
 REVISION LOG
5849
--------------------------------------------------------------------------*/
5850
static H5S_hyper_span_t *
5851
H5S__hyper_coord_to_span(unsigned rank, const hsize_t *coords)
5852
0
{
5853
0
    H5S_hyper_span_t      *new_span;         /* Pointer to new span tree for coordinate */
5854
0
    H5S_hyper_span_info_t *down      = NULL; /* Pointer to new span tree for next level down */
5855
0
    H5S_hyper_span_t      *ret_value = NULL; /* Return value */
5856
5857
0
    FUNC_ENTER_PACKAGE
5858
5859
0
    assert(rank > 0);
5860
0
    assert(coords);
5861
5862
    /* Search for location to insert new element in tree */
5863
0
    if (rank > 1) {
5864
        /* Allocate a span info node for coordinates below this one */
5865
0
        if (NULL == (down = H5S__hyper_new_span_info(rank - 1)))
5866
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
5867
5868
        /* Set the low & high bounds for this span info node */
5869
0
        H5MM_memcpy(down->low_bounds, &coords[1], (rank - 1) * sizeof(hsize_t));
5870
0
        H5MM_memcpy(down->high_bounds, &coords[1], (rank - 1) * sizeof(hsize_t));
5871
5872
        /* Build span tree for coordinates below this one */
5873
0
        if (NULL == (down->head = H5S__hyper_coord_to_span(rank - 1, &coords[1])))
5874
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
5875
5876
        /* Update the tail pointer of the down dimension, and it's a single span element */
5877
0
        down->tail = down->head;
5878
0
    } /* end if */
5879
5880
    /* Build span for this coordinate */
5881
0
    if (NULL == (new_span = H5S__hyper_new_span(coords[0], coords[0], down, NULL)))
5882
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
5883
5884
    /* Set return value */
5885
0
    ret_value = new_span;
5886
5887
0
done:
5888
0
    if (ret_value == NULL && down != NULL)
5889
0
        if (H5S__hyper_free_span_info(down) < 0)
5890
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, NULL, "unable to free span info");
5891
5892
0
    FUNC_LEAVE_NOAPI(ret_value)
5893
0
} /* end H5S__hyper_coord_to_span() */
5894
5895
/*--------------------------------------------------------------------------
5896
 NAME
5897
    H5S__hyper_add_span_element_helper
5898
 PURPOSE
5899
    Helper routine to add a single element to a span tree
5900
 USAGE
5901
    herr_t H5S__hyper_add_span_element_helper(span_tree, rank, coords, first_dim_modified)
5902
        H5S_hyper_span_info_t *span_tree;  IN/OUT: Pointer to span tree to append to
5903
        unsigned rank;                  IN: Number of dimensions of coordinates
5904
        hsize_t *coords;                IN: Location of element to add to span tree
5905
        int *first_dim_modified;        IN: Index of the first dimension modified
5906
 RETURNS
5907
    Non-negative on success, negative on failure
5908
 DESCRIPTION
5909
    Add a single element to an existing span tree.
5910
 GLOBAL VARIABLES
5911
 COMMENTS, BUGS, ASSUMPTIONS
5912
    Assumes that the element is not already covered by the span tree
5913
 EXAMPLES
5914
 REVISION LOG
5915
--------------------------------------------------------------------------*/
5916
static herr_t
5917
H5S__hyper_add_span_element_helper(H5S_hyper_span_info_t *span_tree, unsigned rank, const hsize_t *coords,
5918
                                   int *first_dim_modified)
5919
0
{
5920
0
    H5S_hyper_span_t *tail_span;           /* Pointer to the tail span of one dimension */
5921
0
    herr_t            ret_value = SUCCEED; /* Return value */
5922
5923
0
    FUNC_ENTER_PACKAGE
5924
5925
    /* Sanity check */
5926
0
    assert(span_tree);
5927
0
    assert(rank > 0);
5928
0
    assert(coords);
5929
0
    assert(first_dim_modified);
5930
5931
    /* Get pointer to last span in span tree */
5932
0
    tail_span = span_tree->tail;
5933
5934
    /* Determine if tail span includes a portion of the coordinate */
5935
    /* (Should never happen with the lowest level in the span tree) */
5936
0
    if (coords[0] >= tail_span->low && coords[0] <= tail_span->high) {
5937
0
        H5S_hyper_span_t *prev_down_tail_span;      /* Pointer to previous down spans' tail pointer */
5938
0
        hsize_t           prev_down_tail_span_high; /* Value of previous down spans' tail's high value */
5939
5940
        /* Retain into about down spans' tail */
5941
0
        prev_down_tail_span      = tail_span->down->tail;
5942
0
        prev_down_tail_span_high = tail_span->down->tail->high;
5943
5944
        /* Drop down a dimension */
5945
0
        assert(rank > 1);
5946
0
        if (H5S__hyper_add_span_element_helper(tail_span->down, rank - 1, &coords[1], first_dim_modified) < 0)
5947
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "can't insert coordinate into span tree");
5948
5949
        /* Check & update high bounds for lower dimensions */
5950
0
        if (*first_dim_modified >= 0) {
5951
0
            unsigned first_dim;             /* First dimension modified, relative to this span tree */
5952
0
            bool     first_dim_set = false; /* Whether first dimension modified is set */
5953
0
            unsigned u;                     /* Local index variable */
5954
5955
            /* Adjust first dimension modified to be relative to this span tree */
5956
0
            first_dim = (unsigned)(*first_dim_modified + 1);
5957
5958
            /* Reset modified dimension, in case no bounds in this span tree change */
5959
0
            *first_dim_modified = -1;
5960
5961
            /* Iterate through coordinates */
5962
0
            for (u = first_dim; u < rank; u++) {
5963
                /* Check if coordinate is outside the bounds for this span tree */
5964
0
                if (coords[u] > span_tree->high_bounds[u]) {
5965
                    /* Update high bounds for this tree */
5966
0
                    span_tree->high_bounds[u] = coords[u];
5967
5968
                    /* Need to signal to higher dimensions if high bounds changed */
5969
0
                    if (!first_dim_set) {
5970
0
                        *first_dim_modified = (int)u;
5971
0
                        first_dim_set       = true;
5972
0
                    } /* end if */
5973
0
                }     /* end if */
5974
0
            }         /* end for */
5975
0
        }             /* end if */
5976
5977
        /* Check if previous tail span in down spans is different than current
5978
         * tail span, or if its high value changed, in which case we should
5979
         * check if the updated node can share down spans with other nodes.
5980
         */
5981
0
        if (tail_span->down->tail != prev_down_tail_span ||
5982
0
            prev_down_tail_span_high != tail_span->down->tail->high) {
5983
0
            H5S_hyper_span_t *stop_span; /* Pointer to span to stop at */
5984
0
            H5S_hyper_span_t *tmp_span;  /* Temporary pointer to a span */
5985
0
            uint64_t          op_gen;    /* Operation generation value */
5986
5987
            /* Determine which span to stop at */
5988
0
            if (tail_span->down->tail != prev_down_tail_span) {
5989
                /* Sanity check */
5990
0
                assert(prev_down_tail_span->next == tail_span->down->tail);
5991
5992
                /* Set the span to stop at */
5993
0
                stop_span = prev_down_tail_span;
5994
0
            } /* end if */
5995
0
            else {
5996
                /* Sanity check */
5997
0
                assert(prev_down_tail_span_high != tail_span->down->tail->high);
5998
5999
                /* Set the span to stop at */
6000
0
                stop_span = tail_span->down->tail;
6001
0
            } /* end else */
6002
6003
            /* Acquire an operation generation value for this operation */
6004
0
            op_gen = H5S__hyper_get_op_gen();
6005
6006
            /* Check if the 'stop' span in the "down tree" is equal to any other
6007
             * spans in the list of spans in the span tree.
6008
             *
6009
             * If so, release last span information and make last span merge into
6010
             * previous span (if possible), or at least share their "down tree"
6011
             * information.
6012
             */
6013
0
            tmp_span = tail_span->down->head;
6014
0
            while (tmp_span != stop_span) {
6015
0
                bool attempt_merge_spans = false; /* Whether to merge spans */
6016
6017
                /* Different tests for when to run the 'merge' algorithm,
6018
                 * depending whether there's "down trees" or not.
6019
                 */
6020
0
                if (NULL == tmp_span->down) {
6021
                    /* Spin through spans until we find the one before the 'stop' span */
6022
0
                    if (tmp_span->next == stop_span)
6023
0
                        attempt_merge_spans = true;
6024
0
                } /* end if */
6025
0
                else {
6026
                    /* Check if we've compared the 'stop' span's "down tree" to
6027
                     *      this span's "down tree" already.
6028
                     */
6029
0
                    if (tmp_span->down->op_info[0].op_gen != op_gen) {
6030
0
                        if (H5S__hyper_cmp_spans(tmp_span->down, stop_span->down))
6031
0
                            attempt_merge_spans = true;
6032
6033
                        /* Remember that we visited this span's "down tree" already */
6034
                        /* (Because it wasn't the same as the 'stop' span's down tree
6035
                         *      and we don't need to compare it again)
6036
                         */
6037
0
                        tmp_span->down->op_info[0].op_gen = op_gen;
6038
0
                    } /* end if */
6039
0
                }     /* end else */
6040
6041
                /* Check for merging into previous span */
6042
0
                if (attempt_merge_spans) {
6043
0
                    if (tmp_span->high + 1 == stop_span->low) {
6044
                        /* Increase size of previous span */
6045
0
                        tmp_span->high++;
6046
6047
                        /* Update pointers appropriately */
6048
0
                        if (stop_span == prev_down_tail_span) {
6049
                            /* Sanity check */
6050
0
                            assert(stop_span->next == tail_span->down->tail);
6051
6052
0
                            tmp_span->next = stop_span->next;
6053
0
                        } /* end if */
6054
0
                        else {
6055
                            /* Sanity check */
6056
0
                            assert(tmp_span->next == tail_span->down->tail);
6057
6058
0
                            tmp_span->next        = NULL;
6059
0
                            tail_span->down->tail = tmp_span;
6060
0
                        } /* end else */
6061
6062
                        /* Release last span created */
6063
0
                        if (H5S__hyper_free_span(stop_span) < 0)
6064
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span");
6065
0
                    }
6066
                    /* Span is disjoint, but has the same "down tree" selection */
6067
                    /* (If it has a "down tree") */
6068
0
                    else if (stop_span->down) {
6069
                        /* Release "down tree" information */
6070
0
                        if (H5S__hyper_free_span_info(stop_span->down) < 0)
6071
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
6072
6073
                        /* Point at earlier span's "down tree" */
6074
0
                        stop_span->down = tmp_span->down;
6075
6076
                        /* Increment reference count on shared "down tree" */
6077
0
                        stop_span->down->count++;
6078
0
                    } /* end else */
6079
6080
                    /* Found span to merge into, break out now */
6081
0
                    break;
6082
0
                } /* end if */
6083
6084
                /* Advance to next span to check */
6085
0
                tmp_span = tmp_span->next;
6086
0
            } /* end while */
6087
0
        }     /* end if */
6088
0
    }         /* end if */
6089
0
    else {
6090
0
        unsigned u; /* Local index variable */
6091
6092
        /* Check if we made it all the way to the bottom span list in the tree
6093
         *      and the new coordinate adjoins the current tail span.
6094
         */
6095
0
        if (rank == 1 && (tail_span->high + 1) == coords[0])
6096
            /* Append element to current tail span */
6097
0
            tail_span->high++;
6098
0
        else {
6099
0
            H5S_hyper_span_t *new_span; /* New span created for element */
6100
6101
            /* Make span tree for current coordinate(s) */
6102
0
            if (NULL == (new_span = H5S__hyper_coord_to_span(rank, coords)))
6103
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL,
6104
0
                            "can't allocate hyperslab spans for coordinate");
6105
6106
            /* Add new span to span tree list */
6107
0
            tail_span->next = new_span;
6108
0
            span_tree->tail = new_span;
6109
0
        } /* end else */
6110
6111
        /* Update high bound for current span tree */
6112
0
        assert(coords[0] > span_tree->high_bounds[0]);
6113
0
        span_tree->high_bounds[0] = coords[0];
6114
6115
        /* Update high bounds for dimensions below this one */
6116
0
        for (u = 1; u < rank; u++)
6117
0
            if (coords[u] > span_tree->high_bounds[u])
6118
0
                span_tree->high_bounds[u] = coords[u];
6119
6120
        /* Need to signal to higher dimensions that high bounds changed */
6121
0
        *first_dim_modified = 0;
6122
0
    } /* end else */
6123
6124
0
done:
6125
0
    FUNC_LEAVE_NOAPI(ret_value)
6126
0
} /* end H5S__hyper_add_span_element_helper() */
6127
6128
/*--------------------------------------------------------------------------
6129
 NAME
6130
    H5S_hyper_add_span_element
6131
 PURPOSE
6132
    Add a single element to a span tree
6133
 USAGE
6134
    herr_t H5S_hyper_add_span_element(space, span_tree, rank, coords)
6135
        H5S_t *space;           IN/OUT: Pointer to dataspace to add coordinate to
6136
        unsigned rank;          IN: Number of dimensions of coordinates
6137
        hsize_t *coords;       IN: Location of element to add to span tree
6138
 RETURNS
6139
    Non-negative on success, negative on failure
6140
 DESCRIPTION
6141
    Add a single element to an existing span tree.
6142
 GLOBAL VARIABLES
6143
 COMMENTS, BUGS, ASSUMPTIONS
6144
    Assumes that the element is not already in the dataspace's selection
6145
6146
    NOTE: There's also an assumption about the context of this function call -
6147
        This function is only called is only being called from H5D_chunk_mem_cb
6148
        in src/H5Dchunk.c, when the library is iterating over a memory
6149
        selection, so the coordinates passed to H5S_hyper_add_span_element will
6150
        always be in increasing order (according to a row-major (i.e. C, not
6151
        FORTRAN) scan) over the dataset. Therefore, for every input of
6152
        coordinates, only the last span element (i.e., the tail pointer) in
6153
        one dimension is checked against the input.
6154
6155
    NOTE: This algorithm is definitely "correct" and tries to conserve memory
6156
        as much as possible, but it's doing a _lot_ of work that might be
6157
        better spent running a similar algorithm to "condense" the span tree
6158
        (possibly even back into a regular selection) just before the selection
6159
        is used for I/O on the chunk.  I'm not going to spend the time on this
6160
        currently, but it does sound like a good direction to explore.
6161
        QAK, 2019/01/24
6162
6163
 EXAMPLES
6164
 REVISION LOG
6165
--------------------------------------------------------------------------*/
6166
herr_t
6167
H5S_hyper_add_span_element(H5S_t *space, unsigned rank, const hsize_t *coords)
6168
0
{
6169
0
    H5S_hyper_span_info_t *head      = NULL;    /* Pointer to new head of span tree */
6170
0
    herr_t                 ret_value = SUCCEED; /* Return value */
6171
6172
0
    FUNC_ENTER_NOAPI(FAIL)
6173
6174
0
    assert(space);
6175
0
    assert(rank > 0);
6176
0
    assert(coords);
6177
0
    assert(space->extent.rank == rank);
6178
6179
    /* Check if this is the first element in the selection */
6180
0
    if (NULL == space->select.sel_info.hslab) {
6181
        /* Allocate a span info node */
6182
0
        if (NULL == (head = H5S__hyper_new_span_info(rank)))
6183
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span info");
6184
6185
        /* Set the low & high bounds for this span info node */
6186
0
        H5MM_memcpy(head->low_bounds, coords, rank * sizeof(hsize_t));
6187
0
        H5MM_memcpy(head->high_bounds, coords, rank * sizeof(hsize_t));
6188
6189
        /* Set the reference count */
6190
0
        head->count = 1;
6191
6192
        /* Build span tree for this coordinate */
6193
0
        if (NULL == (head->head = H5S__hyper_coord_to_span(rank, coords)))
6194
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab spans for coordinate");
6195
6196
        /* Update the tail pointer of this newly created span in dimension "rank" */
6197
0
        head->tail = head->head;
6198
6199
        /* Allocate selection info */
6200
0
        if (NULL == (space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t)))
6201
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab selection");
6202
6203
        /* Set the selection to the new span tree */
6204
0
        space->select.sel_info.hslab->span_lst = head;
6205
6206
        /* Set selection type */
6207
0
        space->select.type = H5S_sel_hyper;
6208
6209
        /* Reset "regular" hyperslab flag */
6210
0
        space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
6211
6212
        /* Set unlim_dim */
6213
0
        space->select.sel_info.hslab->unlim_dim = -1;
6214
6215
        /* Set # of elements in selection */
6216
0
        space->select.num_elem = 1;
6217
0
    } /* end if */
6218
0
    else {
6219
0
        int first_dim_modified = -1; /* Index of first dimension modified */
6220
6221
        /* Add the element to the current set of spans */
6222
0
        if (H5S__hyper_add_span_element_helper(space->select.sel_info.hslab->span_lst, rank, coords,
6223
0
                                               &first_dim_modified) < 0)
6224
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert coordinate into span tree");
6225
6226
        /* Increment # of elements in selection */
6227
0
        space->select.num_elem++;
6228
0
    } /* end else */
6229
6230
0
done:
6231
0
    if (ret_value < 0)
6232
0
        if (head)
6233
0
            if (H5S__hyper_free_span_info(head) < 0)
6234
0
                HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
6235
6236
0
    FUNC_LEAVE_NOAPI(ret_value)
6237
0
} /* end H5S_hyper_add_span_element() */
6238
6239
/*--------------------------------------------------------------------------
6240
 NAME
6241
    H5S__hyper_intersect_block_helper
6242
 PURPOSE
6243
    Helper routine to detect intersections in span trees
6244
 USAGE
6245
    bool H5S__hyper_intersect_block_helper(spans, rank, start, end, op_info_i, op_gen)
6246
        H5S_hyper_span_info_t *spans;     IN: First span tree to operate with
6247
        unsigned rank;     IN: Number of dimensions for span tree
6248
        hsize_t *start;    IN: Starting coordinate for block
6249
        hsize_t *end;      IN: Ending coordinate for block
6250
        unsigned op_info_i;             IN: Index of op info to use
6251
        uint64_t op_gen;   IN: Operation generation
6252
 RETURN
6253
    Non-negative (true/false) on success, can't fail
6254
 DESCRIPTION
6255
    Quickly detect intersections between span tree and block
6256
 GLOBAL VARIABLES
6257
 COMMENTS, BUGS, ASSUMPTIONS
6258
 EXAMPLES
6259
 REVISION LOG
6260
--------------------------------------------------------------------------*/
6261
static bool
6262
H5S__hyper_intersect_block_helper(H5S_hyper_span_info_t *spans, unsigned rank, const hsize_t *start,
6263
                                  const hsize_t *end, unsigned op_info_i, uint64_t op_gen)
6264
0
{
6265
0
    bool ret_value = false; /* Return value */
6266
6267
0
    FUNC_ENTER_PACKAGE_NOERR
6268
6269
    /* Sanity check */
6270
0
    assert(spans);
6271
0
    assert(start);
6272
0
    assert(end);
6273
6274
    /* Check if we've already visited this span tree */
6275
0
    if (spans->op_info[op_info_i].op_gen != op_gen) {
6276
0
        H5S_hyper_span_t *curr; /* Pointer to current span in 1st span tree */
6277
0
        unsigned          u;    /* Local index variable */
6278
6279
        /* Verify that there is a possibility of an overlap by checking the block
6280
         *  against the low & high bounds for the span tree.
6281
         */
6282
0
        for (u = 0; u < rank; u++)
6283
0
            if (start[u] > spans->high_bounds[u] || end[u] < spans->low_bounds[u])
6284
0
                HGOTO_DONE(false);
6285
6286
        /* Get the span list for spans in this tree */
6287
0
        curr = spans->head;
6288
6289
        /* Iterate over the spans in the tree */
6290
0
        while (curr != NULL) {
6291
            /* Check for span entirely before block */
6292
0
            if (curr->high < *start)
6293
                /* Advance to next span in this dimension */
6294
0
                curr = curr->next;
6295
            /* If this span is past the end of the block, then we're done in this dimension */
6296
0
            else if (curr->low > *end)
6297
0
                HGOTO_DONE(false);
6298
            /* block & span overlap */
6299
0
            else {
6300
                /* If this is the bottom dimension, then the span tree overlaps the block */
6301
0
                if (curr->down == NULL)
6302
0
                    HGOTO_DONE(true);
6303
                /* Recursively check spans in next dimension down */
6304
0
                else {
6305
                    /* If there is an intersection in the "down" dimensions,
6306
                     * the span trees overlap.
6307
                     */
6308
0
                    if (H5S__hyper_intersect_block_helper(curr->down, rank - 1, start + 1, end + 1, op_info_i,
6309
0
                                                          op_gen))
6310
0
                        HGOTO_DONE(true);
6311
6312
                    /* No intersection in down dimensions, advance to next span */
6313
0
                    curr = curr->next;
6314
0
                } /* end else */
6315
0
            }     /* end else */
6316
0
        }         /* end while */
6317
6318
        /* Set the tree's operation generation */
6319
0
        spans->op_info[op_info_i].op_gen = op_gen;
6320
0
    } /* end if */
6321
6322
    /* Fall through with 'false' return value */
6323
6324
0
done:
6325
0
    FUNC_LEAVE_NOAPI(ret_value)
6326
0
} /* end H5S__hyper_intersect_block_helper() */
6327
6328
/*--------------------------------------------------------------------------
6329
 NAME
6330
    H5S__hyper_intersect_block
6331
 PURPOSE
6332
    Detect intersections of selection with block
6333
 USAGE
6334
    htri_t H5S__hyper_intersect_block(space, start, end)
6335
        H5S_t *space;           IN: Dataspace with selection to use
6336
        const hsize_t *start;   IN: Starting coordinate for block
6337
        const hsize_t *end;     IN: Ending coordinate for block
6338
 RETURNS
6339
    Non-negative true / false on success, negative on failure
6340
 DESCRIPTION
6341
    Quickly detect intersections between both regular hyperslabs and span trees
6342
    with a block
6343
 GLOBAL VARIABLES
6344
 COMMENTS, BUGS, ASSUMPTIONS
6345
    Does not use selection offset.
6346
 EXAMPLES
6347
 REVISION LOG
6348
--------------------------------------------------------------------------*/
6349
static htri_t
6350
H5S__hyper_intersect_block(H5S_t *space, const hsize_t *start, const hsize_t *end)
6351
0
{
6352
0
    htri_t ret_value = FAIL; /* Return value */
6353
6354
0
    FUNC_ENTER_PACKAGE_NOERR
6355
6356
    /* Sanity check */
6357
0
    assert(space);
6358
0
    assert(H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space));
6359
0
    assert(start);
6360
0
    assert(end);
6361
6362
    /* Attempt to rebuild diminfo if it is invalid and has not been confirmed
6363
     * to be impossible.
6364
     */
6365
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO)
6366
0
        H5S__hyper_rebuild(space);
6367
6368
    /* Check for regular hyperslab intersection */
6369
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
6370
0
        bool     single_block; /* Whether the regular selection is a single block */
6371
0
        unsigned u;            /* Local index variable */
6372
6373
        /* Check for a single block */
6374
        /* For a regular hyperslab to be single, it must have only one block
6375
         * (i.e. count == 1 in all dimensions).
6376
         */
6377
0
        single_block = true;
6378
0
        for (u = 0; u < space->extent.rank; u++)
6379
0
            if (space->select.sel_info.hslab->diminfo.opt[u].count > 1)
6380
0
                single_block = false;
6381
6382
        /* Single blocks have already been "compared" above, in the low / high
6383
         * bound checking, so just return true if we've reached here - they
6384
         * would have been rejected earlier, if they didn't intersect.
6385
         */
6386
0
        if (single_block)
6387
0
            HGOTO_DONE(true);
6388
0
        else {
6389
            /* Loop over the dimensions, checking for an intersection */
6390
0
            for (u = 0; u < space->extent.rank; u++) {
6391
                /* If the block's start is <= the hyperslab start, they intersect */
6392
                /* (So, if the start is > the hyperslab start, check more conditions) */
6393
0
                if (start[u] > space->select.sel_info.hslab->diminfo.opt[u].start) {
6394
0
                    hsize_t adj_start; /* Start coord, adjusted for hyperslab selection parameters */
6395
0
                    hsize_t nstride;   /* Number of strides into the selection */
6396
6397
                    /* Adjust start coord for selection's 'start' offset */
6398
0
                    adj_start = start[u] - space->select.sel_info.hslab->diminfo.opt[u].start;
6399
6400
                    /* Compute # of strides into the selection */
6401
0
                    if (space->select.sel_info.hslab->diminfo.opt[u].count > 1)
6402
0
                        nstride = adj_start / space->select.sel_info.hslab->diminfo.opt[u].stride;
6403
0
                    else
6404
0
                        nstride = 0;
6405
6406
                    /* Sanity check */
6407
0
                    assert(nstride <= space->select.sel_info.hslab->diminfo.opt[u].count);
6408
6409
                    /* "Rebase" the adjusted start coord into the same range
6410
                     *      range of values as the selections's first block.
6411
                     */
6412
0
                    adj_start -= nstride * space->select.sel_info.hslab->diminfo.opt[u].stride;
6413
6414
                    /* If the adjusted start doesn't fall within the first hyperslab
6415
                     *  span, check for the block overlapping with the next one.
6416
                     */
6417
0
                    if (adj_start >= space->select.sel_info.hslab->diminfo.opt[u].block) {
6418
0
                        hsize_t adj_end; /* End coord, adjusted for hyperslab selection parameters */
6419
6420
                        /* Adjust end coord for selection's 'start' offset */
6421
0
                        adj_end = end[u] - space->select.sel_info.hslab->diminfo.opt[u].start;
6422
6423
                        /* "Rebase" the adjusted end coord into the same range
6424
                         *      range of values as the selections's first block.
6425
                         */
6426
0
                        adj_end -= nstride * space->select.sel_info.hslab->diminfo.opt[u].stride;
6427
6428
                        /* If block doesn't extend over beginning of next span,
6429
                         *  it doesn't intersect.
6430
                         */
6431
0
                        if (adj_end < space->select.sel_info.hslab->diminfo.opt[u].stride)
6432
0
                            HGOTO_DONE(false);
6433
0
                    } /* end if */
6434
0
                }     /* end if */
6435
0
            }         /* end for */
6436
6437
            /* If we've looped through all dimensions and none of them didn't
6438
             *  overlap, then all of them do, so we report true.
6439
             */
6440
0
            HGOTO_DONE(true);
6441
0
        } /* end else */
6442
0
    }     /* end if */
6443
0
    else {
6444
0
        uint64_t op_gen; /* Operation generation value */
6445
6446
        /* Acquire an operation generation value for this operation */
6447
0
        op_gen = H5S__hyper_get_op_gen();
6448
6449
        /* Perform the span-by-span intersection check */
6450
        /* Always use op_info[0] since we own this op_info, so there can be no
6451
         * simultaneous operations */
6452
0
        ret_value = H5S__hyper_intersect_block_helper(space->select.sel_info.hslab->span_lst,
6453
0
                                                      space->extent.rank, start, end, 0, op_gen);
6454
0
    } /* end else */
6455
6456
0
done:
6457
0
    FUNC_LEAVE_NOAPI(ret_value)
6458
0
} /* end H5S__hyper_intersect_block() */
6459
6460
/*--------------------------------------------------------------------------
6461
 NAME
6462
    H5S__hyper_adjust_u_helper
6463
 PURPOSE
6464
    Helper routine to adjust offsets in span trees
6465
 USAGE
6466
    void H5S__hyper_adjust_u_helper(spans, rank, offset, op_info_i, op_gen)
6467
        H5S_hyper_span_info_t *spans;   IN: Span tree to operate with
6468
        unsigned rank;                  IN: Number of dimensions for span tree
6469
        const hsize_t *offset;          IN: Offset to subtract
6470
        unsigned op_info_i;             IN: Index of op info to use
6471
        uint64_t op_gen;                IN: Operation generation
6472
 RETURNS
6473
    None
6474
 DESCRIPTION
6475
    Adjust the location of the spans in a span tree by subtracting an offset
6476
 GLOBAL VARIABLES
6477
 COMMENTS, BUGS, ASSUMPTIONS
6478
 EXAMPLES
6479
 REVISION LOG
6480
--------------------------------------------------------------------------*/
6481
static void
6482
H5S__hyper_adjust_u_helper(H5S_hyper_span_info_t *spans, unsigned rank, const hsize_t *offset,
6483
                           unsigned op_info_i, uint64_t op_gen)
6484
0
{
6485
0
    FUNC_ENTER_PACKAGE_NOERR
6486
6487
    /* Sanity checks */
6488
0
    assert(spans);
6489
0
    assert(offset);
6490
6491
    /* Check if we've already set this span tree */
6492
0
    if (spans->op_info[op_info_i].op_gen != op_gen) {
6493
0
        H5S_hyper_span_t *span; /* Pointer to current span in span tree */
6494
0
        unsigned          u;    /* Local index variable */
6495
6496
        /* Adjust the span tree's low & high bounds */
6497
0
        for (u = 0; u < rank; u++) {
6498
0
            assert(spans->low_bounds[u] >= offset[u]);
6499
0
            spans->low_bounds[u] -= offset[u];
6500
0
            spans->high_bounds[u] -= offset[u];
6501
0
        } /* end for */
6502
6503
        /* Iterate over the spans in tree */
6504
0
        span = spans->head;
6505
0
        while (span != NULL) {
6506
            /* Adjust span offset */
6507
0
            assert(span->low >= *offset);
6508
0
            span->low -= *offset;
6509
0
            span->high -= *offset;
6510
6511
            /* Recursively adjust spans in next dimension down */
6512
0
            if (span->down != NULL)
6513
0
                H5S__hyper_adjust_u_helper(span->down, rank - 1, offset + 1, op_info_i, op_gen);
6514
6515
            /* Advance to next span in this dimension */
6516
0
            span = span->next;
6517
0
        } /* end while */
6518
6519
        /* Set the tree's operation generation */
6520
0
        spans->op_info[op_info_i].op_gen = op_gen;
6521
0
    } /* end if */
6522
6523
0
    FUNC_LEAVE_NOAPI_VOID
6524
0
} /* end H5S__hyper_adjust_u_helper() */
6525
6526
/*--------------------------------------------------------------------------
6527
 NAME
6528
    H5S__hyper_adjust_u
6529
 PURPOSE
6530
    Adjust a hyperslab selection by subtracting an offset
6531
 USAGE
6532
    void H5S__hyper_adjust_u(space,offset)
6533
        H5S_t *space;           IN/OUT: Pointer to dataspace to adjust
6534
        const hsize_t *offset; IN: Offset to subtract
6535
 RETURNS
6536
    Non-negative on success, negative on failure
6537
 DESCRIPTION
6538
    Moves a hyperslab selection by subtracting an offset from it.
6539
 GLOBAL VARIABLES
6540
 COMMENTS, BUGS, ASSUMPTIONS
6541
 EXAMPLES
6542
 REVISION LOG
6543
--------------------------------------------------------------------------*/
6544
static herr_t
6545
H5S__hyper_adjust_u(H5S_t *space, const hsize_t *offset)
6546
0
{
6547
0
    bool     non_zero_offset = false; /* Whether any offset is non-zero */
6548
0
    unsigned u;                       /* Local index variable */
6549
6550
0
    FUNC_ENTER_PACKAGE_NOERR
6551
6552
    /* Sanity check */
6553
0
    assert(space);
6554
0
    assert(offset);
6555
6556
    /* Check for an all-zero offset vector */
6557
0
    for (u = 0; u < space->extent.rank; u++)
6558
0
        if (0 != offset[u]) {
6559
0
            non_zero_offset = true;
6560
0
            break;
6561
0
        }
6562
6563
    /* Only perform operation if the offset is non-zero */
6564
0
    if (non_zero_offset) {
6565
        /* Subtract the offset from the "regular" coordinates, if they exist */
6566
        /* (No need to rebuild the dimension info yet -QAK) */
6567
0
        if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
6568
0
            for (u = 0; u < space->extent.rank; u++) {
6569
0
                assert(space->select.sel_info.hslab->diminfo.opt[u].start >= offset[u]);
6570
0
                space->select.sel_info.hslab->diminfo.opt[u].start -= offset[u];
6571
6572
                /* Adjust the low & high bounds */
6573
0
                assert(space->select.sel_info.hslab->diminfo.low_bounds[u] >= offset[u]);
6574
0
                space->select.sel_info.hslab->diminfo.low_bounds[u] -= offset[u];
6575
0
                space->select.sel_info.hslab->diminfo.high_bounds[u] -= offset[u];
6576
0
            } /* end for */
6577
0
        }     /* end if */
6578
6579
        /* Subtract the offset from the span tree coordinates, if they exist */
6580
0
        if (space->select.sel_info.hslab->span_lst) {
6581
0
            uint64_t op_gen; /* Operation generation value */
6582
6583
            /* Acquire an operation generation value for this operation */
6584
0
            op_gen = H5S__hyper_get_op_gen();
6585
6586
            /* Perform adjustment */
6587
            /* Always use op_info[0] since we own this op_info, so there can be no
6588
             * simultaneous operations */
6589
0
            H5S__hyper_adjust_u_helper(space->select.sel_info.hslab->span_lst, space->extent.rank, offset, 0,
6590
0
                                       op_gen);
6591
0
        } /* end if */
6592
0
    }     /* end if */
6593
6594
0
    FUNC_LEAVE_NOAPI(SUCCEED)
6595
0
} /* end H5S__hyper_adjust_u() */
6596
6597
/*-------------------------------------------------------------------------
6598
 * Function:    H5S__hyper_project_scalar
6599
 *
6600
 * Purpose:    Projects a single element hyperslab selection into a scalar
6601
 *              dataspace
6602
 *
6603
 * Return:    Non-negative on success, negative on failure.
6604
 *
6605
 *-------------------------------------------------------------------------
6606
 */
6607
static herr_t
6608
H5S__hyper_project_scalar(const H5S_t *space, hsize_t *offset)
6609
0
{
6610
0
    hsize_t block[H5S_MAX_RANK]; /* Block selected in base dataspace */
6611
6612
0
    FUNC_ENTER_PACKAGE_NOERR
6613
6614
    /* Check args */
6615
0
    assert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space));
6616
0
    assert(offset);
6617
6618
    /* Check for a "regular" hyperslab selection */
6619
    /* (No need to rebuild the dimension info yet -QAK) */
6620
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
6621
0
        const H5S_hyper_dim_t *diminfo =
6622
0
            space->select.sel_info.hslab->diminfo.opt; /* Alias for dataspace's diminfo information */
6623
0
        unsigned u;                                    /* Counter */
6624
6625
        /* Build the table of the initial offset */
6626
0
        for (u = 0; u < space->extent.rank; u++) {
6627
            /* Sanity check diminfo */
6628
0
            assert(1 == diminfo[u].count);
6629
0
            assert(1 == diminfo[u].block);
6630
6631
            /* Sanity check bounds, while we're here */
6632
0
            assert(diminfo[u].start == space->select.sel_info.hslab->diminfo.low_bounds[u]);
6633
6634
            /* Keep the offset for later */
6635
0
            block[u] = diminfo[u].start;
6636
0
        } /* end for */
6637
0
    }     /* end if */
6638
0
    else {
6639
0
        const H5S_hyper_span_t *curr;     /* Pointer to current hyperslab span */
6640
0
        unsigned                curr_dim; /* Current dimension being operated on */
6641
6642
        /* Advance down selected spans */
6643
0
        curr     = space->select.sel_info.hslab->span_lst->head;
6644
0
        curr_dim = 0;
6645
0
        while (1) {
6646
            /* Sanity checks */
6647
0
            assert(NULL == curr->next);
6648
0
            assert(curr->low == curr->high);
6649
0
            assert(curr_dim < space->extent.rank);
6650
6651
            /* Save the location of the selection in current dimension */
6652
0
            block[curr_dim] = curr->low;
6653
6654
            /* Advance down to next dimension */
6655
0
            if (curr->down) {
6656
0
                curr = curr->down->head;
6657
0
                curr_dim++;
6658
0
            } /* end if */
6659
0
            else
6660
0
                break;
6661
0
        } /* end while */
6662
0
    }     /* end else */
6663
6664
    /* Calculate offset of selection in projected buffer */
6665
0
    *offset = H5VM_array_offset(space->extent.rank, space->extent.size, block);
6666
6667
0
    FUNC_LEAVE_NOAPI(SUCCEED)
6668
0
} /* end H5S__hyper_project_scalar() */
6669
6670
/*-------------------------------------------------------------------------
6671
 * Function:    H5S__hyper_project_simple_lower
6672
 *
6673
 * Purpose:    Projects a hyperslab selection onto/into a simple dataspace
6674
 *              of a lower rank
6675
 *
6676
 * Return:    Non-negative on success, negative on failure.
6677
 *
6678
 *-------------------------------------------------------------------------
6679
 */
6680
static herr_t
6681
H5S__hyper_project_simple_lower(const H5S_t *base_space, H5S_t *new_space)
6682
0
{
6683
0
    H5S_hyper_span_info_t *down;                /* Pointer to list of spans */
6684
0
    unsigned               curr_dim;            /* Current dimension being operated on */
6685
0
    herr_t                 ret_value = SUCCEED; /* Return value */
6686
6687
0
    FUNC_ENTER_PACKAGE
6688
6689
    /* Check args */
6690
0
    assert(base_space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(base_space));
6691
0
    assert(new_space);
6692
0
    assert(new_space->extent.rank < base_space->extent.rank);
6693
6694
    /* Walk down the span tree until we reach the selection to project */
6695
0
    down     = base_space->select.sel_info.hslab->span_lst;
6696
0
    curr_dim = 0;
6697
0
    while (down && curr_dim < (base_space->extent.rank - new_space->extent.rank)) {
6698
        /* Sanity check */
6699
0
        assert(NULL == down->head->next);
6700
6701
        /* Advance down to next dimension */
6702
0
        down = down->head->down;
6703
0
        curr_dim++;
6704
0
    } /* end while */
6705
0
    if (NULL == down)
6706
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "NULL span list pointer");
6707
6708
    /* Share the underlying hyperslab span information */
6709
0
    new_space->select.sel_info.hslab->span_lst = down;
6710
0
    new_space->select.sel_info.hslab->span_lst->count++;
6711
6712
0
done:
6713
0
    FUNC_LEAVE_NOAPI(ret_value)
6714
0
} /* end H5S__hyper_project_simple_lower() */
6715
6716
/*-------------------------------------------------------------------------
6717
 * Function:    H5S__hyper_project_simple_higher
6718
 *
6719
 * Purpose:    Projects a hyperslab selection onto/into a simple dataspace
6720
 *              of a higher rank
6721
 *
6722
 * Return:    Non-negative on success, negative on failure.
6723
 *
6724
 *-------------------------------------------------------------------------
6725
 */
6726
static herr_t
6727
H5S__hyper_project_simple_higher(const H5S_t *base_space, H5S_t *new_space)
6728
0
{
6729
0
    H5S_hyper_span_t *prev_span = NULL;    /* Pointer to previous list of spans */
6730
0
    unsigned          delta_rank;          /* Difference in dataspace ranks */
6731
0
    unsigned          curr_dim;            /* Current dimension being operated on */
6732
0
    unsigned          u;                   /* Local index variable */
6733
0
    herr_t            ret_value = SUCCEED; /* Return value */
6734
6735
0
    FUNC_ENTER_PACKAGE
6736
6737
    /* Check args */
6738
0
    assert(base_space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(base_space));
6739
0
    assert(new_space);
6740
0
    assert(new_space->extent.rank > base_space->extent.rank);
6741
6742
    /* Create nodes until reaching the correct # of dimensions */
6743
0
    new_space->select.sel_info.hslab->span_lst = NULL;
6744
0
    curr_dim                                   = 0;
6745
0
    delta_rank                                 = (new_space->extent.rank - base_space->extent.rank);
6746
0
    while (curr_dim < delta_rank) {
6747
0
        H5S_hyper_span_info_t *new_span_info; /* Pointer to list of spans */
6748
0
        H5S_hyper_span_t      *new_span;      /* Temporary hyperslab span */
6749
6750
        /* Allocate a new span_info node */
6751
0
        if (NULL == (new_span_info = H5S__hyper_new_span_info(new_space->extent.rank))) {
6752
0
            if (prev_span)
6753
0
                (void)H5S__hyper_free_span(prev_span);
6754
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span info");
6755
0
        }
6756
6757
        /* Check for linking into higher span */
6758
0
        if (prev_span)
6759
0
            prev_span->down = new_span_info;
6760
6761
        /* Allocate a new node */
6762
0
        if (NULL == (new_span = H5S__hyper_new_span((hsize_t)0, (hsize_t)0, NULL, NULL))) {
6763
0
            assert(new_span_info);
6764
0
            if (!prev_span)
6765
0
                (void)H5FL_ARR_FREE(hbounds_t, new_span_info);
6766
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span");
6767
0
        } /* end if */
6768
6769
        /* Set the span_info information */
6770
0
        new_span_info->count = 1;
6771
0
        new_span_info->head  = new_span;
6772
0
        new_span_info->tail  = new_span;
6773
6774
        /* Set the bounding box */
6775
0
        for (u = 0; u < delta_rank; u++) {
6776
0
            new_span_info->low_bounds[u]  = 0;
6777
0
            new_span_info->high_bounds[u] = 0;
6778
0
        } /* end for */
6779
0
        for (; u < new_space->extent.rank; u++) {
6780
0
            new_span_info->low_bounds[u] =
6781
0
                base_space->select.sel_info.hslab->span_lst->low_bounds[u - delta_rank];
6782
0
            new_span_info->high_bounds[u] =
6783
0
                base_space->select.sel_info.hslab->span_lst->high_bounds[u - delta_rank];
6784
0
        } /* end for */
6785
6786
        /* Attach to new space, if top span info */
6787
0
        if (NULL == new_space->select.sel_info.hslab->span_lst)
6788
0
            new_space->select.sel_info.hslab->span_lst = new_span_info;
6789
6790
        /* Remember previous span info */
6791
0
        prev_span = new_span;
6792
6793
        /* Advance to next dimension */
6794
0
        curr_dim++;
6795
0
    } /* end while */
6796
0
    if (NULL == new_space->select.sel_info.hslab->span_lst)
6797
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "NULL span list pointer");
6798
0
    assert(prev_span);
6799
6800
    /* Share the underlying hyperslab span information */
6801
0
    prev_span->down = base_space->select.sel_info.hslab->span_lst;
6802
0
    prev_span->down->count++;
6803
6804
0
done:
6805
0
    if (ret_value < 0 && new_space->select.sel_info.hslab->span_lst) {
6806
0
        if (new_space->select.sel_info.hslab->span_lst->head)
6807
0
            if (H5S__hyper_free_span(new_space->select.sel_info.hslab->span_lst->head) < 0)
6808
0
                HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span");
6809
6810
0
        new_space->select.sel_info.hslab->span_lst =
6811
0
            (H5S_hyper_span_info_t *)H5FL_ARR_FREE(hbounds_t, new_space->select.sel_info.hslab->span_lst);
6812
0
    }
6813
6814
0
    FUNC_LEAVE_NOAPI(ret_value)
6815
0
} /* end H5S__hyper_project_simple_higher() */
6816
6817
/*-------------------------------------------------------------------------
6818
 * Function:    H5S__hyper_project_simple
6819
 *
6820
 * Purpose:    Projects a hyperslab selection onto/into a simple dataspace
6821
 *              of a different rank
6822
 *
6823
 * Return:    Non-negative on success, negative on failure.
6824
 *
6825
 *-------------------------------------------------------------------------
6826
 */
6827
static herr_t
6828
H5S__hyper_project_simple(const H5S_t *base_space, H5S_t *new_space, hsize_t *offset)
6829
0
{
6830
0
    herr_t ret_value = SUCCEED; /* Return value */
6831
6832
0
    FUNC_ENTER_PACKAGE
6833
6834
    /* Check args */
6835
0
    assert(base_space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(base_space));
6836
0
    assert(new_space);
6837
0
    assert(offset);
6838
6839
    /* We are setting a new selection, remove any current selection in new dataspace */
6840
0
    if (H5S_SELECT_RELEASE(new_space) < 0)
6841
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection");
6842
6843
    /* Allocate space for the hyperslab selection information */
6844
0
    if (NULL == (new_space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t)))
6845
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab info");
6846
6847
    /* Set unlim_dim */
6848
0
    new_space->select.sel_info.hslab->unlim_dim = -1;
6849
6850
    /* Check for a "regular" hyperslab selection */
6851
    /* (No need to rebuild the dimension info yet -QAK) */
6852
0
    if (base_space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
6853
0
        unsigned base_space_dim; /* Current dimension in the base dataspace */
6854
0
        unsigned new_space_dim;  /* Current dimension in the new dataspace */
6855
0
        unsigned u;              /* Local index variable */
6856
6857
        /* Check if the new space's rank is < or > base space's rank */
6858
0
        if (new_space->extent.rank < base_space->extent.rank) {
6859
0
            const H5S_hyper_dim_t *opt_diminfo = base_space->select.sel_info.hslab->diminfo
6860
0
                                                     .opt; /* Alias for dataspace's diminfo information */
6861
0
            hsize_t block[H5S_MAX_RANK];                   /* Block selected in base dataspace */
6862
6863
            /* Compute the offset for the down-projection */
6864
0
            memset(block, 0, sizeof(block));
6865
0
            for (u = 0; u < (base_space->extent.rank - new_space->extent.rank); u++)
6866
0
                block[u] = opt_diminfo[u].start;
6867
0
            *offset = H5VM_array_offset(base_space->extent.rank, base_space->extent.size, block);
6868
6869
            /* Set the correct dimensions for the base & new spaces */
6870
0
            base_space_dim = base_space->extent.rank - new_space->extent.rank;
6871
0
            new_space_dim  = 0;
6872
0
        } /* end if */
6873
0
        else {
6874
0
            assert(new_space->extent.rank > base_space->extent.rank);
6875
6876
            /* The offset is zero when projected into higher dimensions */
6877
0
            *offset = 0;
6878
6879
            /* Set the diminfo information for the higher dimensions */
6880
0
            for (new_space_dim = 0; new_space_dim < (new_space->extent.rank - base_space->extent.rank);
6881
0
                 new_space_dim++) {
6882
0
                new_space->select.sel_info.hslab->diminfo.app[new_space_dim].start  = 0;
6883
0
                new_space->select.sel_info.hslab->diminfo.app[new_space_dim].stride = 1;
6884
0
                new_space->select.sel_info.hslab->diminfo.app[new_space_dim].count  = 1;
6885
0
                new_space->select.sel_info.hslab->diminfo.app[new_space_dim].block  = 1;
6886
6887
0
                new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].start  = 0;
6888
0
                new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].stride = 1;
6889
0
                new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].count  = 1;
6890
0
                new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].block  = 1;
6891
0
            } /* end for */
6892
6893
            /* Start at beginning of base space's dimension info */
6894
0
            base_space_dim = 0;
6895
0
        } /* end else */
6896
6897
        /* Copy the diminfo */
6898
0
        while (base_space_dim < base_space->extent.rank) {
6899
0
            new_space->select.sel_info.hslab->diminfo.app[new_space_dim].start =
6900
0
                base_space->select.sel_info.hslab->diminfo.app[base_space_dim].start;
6901
0
            new_space->select.sel_info.hslab->diminfo.app[new_space_dim].stride =
6902
0
                base_space->select.sel_info.hslab->diminfo.app[base_space_dim].stride;
6903
0
            new_space->select.sel_info.hslab->diminfo.app[new_space_dim].count =
6904
0
                base_space->select.sel_info.hslab->diminfo.app[base_space_dim].count;
6905
0
            new_space->select.sel_info.hslab->diminfo.app[new_space_dim].block =
6906
0
                base_space->select.sel_info.hslab->diminfo.app[base_space_dim].block;
6907
6908
0
            new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].start =
6909
0
                base_space->select.sel_info.hslab->diminfo.opt[base_space_dim].start;
6910
0
            new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].stride =
6911
0
                base_space->select.sel_info.hslab->diminfo.opt[base_space_dim].stride;
6912
0
            new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].count =
6913
0
                base_space->select.sel_info.hslab->diminfo.opt[base_space_dim].count;
6914
0
            new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].block =
6915
0
                base_space->select.sel_info.hslab->diminfo.opt[base_space_dim].block;
6916
6917
            /* Advance to next dimensions */
6918
0
            base_space_dim++;
6919
0
            new_space_dim++;
6920
0
        } /* end for */
6921
6922
        /* Update the bounding box */
6923
0
        for (u = 0; u < new_space->extent.rank; u++) {
6924
0
            new_space->select.sel_info.hslab->diminfo.low_bounds[u] =
6925
0
                new_space->select.sel_info.hslab->diminfo.opt[u].start;
6926
0
            new_space->select.sel_info.hslab->diminfo.high_bounds[u] =
6927
0
                new_space->select.sel_info.hslab->diminfo.low_bounds[u] +
6928
0
                new_space->select.sel_info.hslab->diminfo.opt[u].stride *
6929
0
                    (new_space->select.sel_info.hslab->diminfo.opt[u].count - 1) +
6930
0
                (new_space->select.sel_info.hslab->diminfo.opt[u].block - 1);
6931
0
        } /* end for */
6932
6933
        /* Indicate that the dimension information is valid */
6934
0
        new_space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_YES;
6935
6936
        /* Indicate that there's no slab information */
6937
0
        new_space->select.sel_info.hslab->span_lst = NULL;
6938
0
    } /* end if */
6939
0
    else {
6940
        /* Check if the new space's rank is < or > base space's rank */
6941
0
        if (new_space->extent.rank < base_space->extent.rank) {
6942
0
            const H5S_hyper_span_t *curr;                /* Pointer to current hyperslab span */
6943
0
            hsize_t                 block[H5S_MAX_RANK]; /* Block selected in base dataspace */
6944
0
            unsigned                curr_dim;            /* Current dimension being operated on */
6945
6946
            /* Clear the block buffer */
6947
0
            memset(block, 0, sizeof(block));
6948
6949
            /* Advance down selected spans */
6950
0
            curr     = base_space->select.sel_info.hslab->span_lst->head;
6951
0
            curr_dim = 0;
6952
0
            while (curr && curr_dim < (base_space->extent.rank - new_space->extent.rank)) {
6953
                /* Save the location of the selection in current dimension */
6954
0
                block[curr_dim] = curr->low;
6955
6956
                /* Advance down to next dimension */
6957
0
                curr = curr->down->head;
6958
0
                curr_dim++;
6959
0
            } /* end while */
6960
6961
            /* Compute the offset for the down-projection */
6962
0
            *offset = H5VM_array_offset(base_space->extent.rank, base_space->extent.size, block);
6963
6964
            /* Project the base space's selection down in less dimensions */
6965
0
            if (H5S__hyper_project_simple_lower(base_space, new_space) < 0)
6966
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL,
6967
0
                            "can't project hyperslab selection into less dimensions");
6968
0
        } /* end if */
6969
0
        else {
6970
0
            assert(new_space->extent.rank > base_space->extent.rank);
6971
6972
            /* The offset is zero when projected into higher dimensions */
6973
0
            *offset = 0;
6974
6975
            /* Project the base space's selection down in more dimensions */
6976
0
            if (H5S__hyper_project_simple_higher(base_space, new_space) < 0)
6977
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL,
6978
0
                            "can't project hyperslab selection into less dimensions");
6979
0
        } /* end else */
6980
6981
        /* Copy the status of the dimension information */
6982
0
        new_space->select.sel_info.hslab->diminfo_valid = base_space->select.sel_info.hslab->diminfo_valid;
6983
0
    } /* end else */
6984
6985
    /* Number of elements selected will be the same */
6986
0
    new_space->select.num_elem = base_space->select.num_elem;
6987
6988
    /* Set selection type */
6989
0
    new_space->select.type = H5S_sel_hyper;
6990
6991
0
done:
6992
0
    FUNC_LEAVE_NOAPI(ret_value)
6993
0
} /* end H5S__hyper_project_simple() */
6994
6995
/*--------------------------------------------------------------------------
6996
 NAME
6997
    H5S__hyper_adjust_s_helper
6998
 PURPOSE
6999
    Helper routine to adjust offsets in span trees
7000
 USAGE
7001
    void H5S__hyper_adjust_s_helper(spans, rank, offset, op_info_i, op_gen)
7002
        H5S_hyper_span_info_t *spans;   IN: Span tree to operate with
7003
        unsigned rank;                  IN: Number of dimensions for span tree
7004
        const hssize_t *offset;         IN: Offset to subtract
7005
        unsigned op_info_i;             IN: Index of op info to use
7006
        uint64_t op_gen;                IN: Operation generation
7007
 RETURNS
7008
    None
7009
 DESCRIPTION
7010
    Adjust the location of the spans in a span tree by subtracting an offset
7011
 GLOBAL VARIABLES
7012
 COMMENTS, BUGS, ASSUMPTIONS
7013
 EXAMPLES
7014
 REVISION LOG
7015
--------------------------------------------------------------------------*/
7016
static void
7017
H5S__hyper_adjust_s_helper(H5S_hyper_span_info_t *spans, unsigned rank, const hssize_t *offset,
7018
                           unsigned op_info_i, uint64_t op_gen)
7019
0
{
7020
0
    FUNC_ENTER_PACKAGE_NOERR
7021
7022
    /* Sanity checks */
7023
0
    assert(spans);
7024
0
    assert(offset);
7025
7026
    /* Check if we've already set this span tree */
7027
0
    if (spans->op_info[op_info_i].op_gen != op_gen) {
7028
0
        H5S_hyper_span_t *span; /* Pointer to current span in span tree */
7029
0
        unsigned          u;    /* Local index variable */
7030
7031
        /* Adjust the span tree's low & high bounds */
7032
0
        for (u = 0; u < rank; u++) {
7033
0
            assert((hssize_t)spans->low_bounds[u] >= offset[u]);
7034
0
            spans->low_bounds[u]  = (hsize_t)((hssize_t)spans->low_bounds[u] - offset[u]);
7035
0
            spans->high_bounds[u] = (hsize_t)((hssize_t)spans->high_bounds[u] - offset[u]);
7036
0
        } /* end for */
7037
7038
        /* Iterate over the spans in tree */
7039
0
        span = spans->head;
7040
0
        while (span != NULL) {
7041
            /* Adjust span offset */
7042
0
            assert((hssize_t)span->low >= *offset);
7043
0
            span->low  = (hsize_t)((hssize_t)span->low - *offset);
7044
0
            span->high = (hsize_t)((hssize_t)span->high - *offset);
7045
7046
            /* Recursively adjust spans in next dimension down */
7047
0
            if (span->down != NULL)
7048
0
                H5S__hyper_adjust_s_helper(span->down, rank - 1, offset + 1, op_info_i, op_gen);
7049
7050
            /* Advance to next span in this dimension */
7051
0
            span = span->next;
7052
0
        } /* end while */
7053
7054
        /* Set the tree's operation generation */
7055
0
        spans->op_info[op_info_i].op_gen = op_gen;
7056
0
    } /* end if */
7057
7058
0
    FUNC_LEAVE_NOAPI_VOID
7059
0
} /* end H5S__hyper_adjust_s_helper() */
7060
7061
/*--------------------------------------------------------------------------
7062
 NAME
7063
    H5S__hyper_adjust_s
7064
 PURPOSE
7065
    Adjust a hyperslab selection by subtracting an offset
7066
 USAGE
7067
    herr_t H5S__hyper_adjust_s(space,offset)
7068
        H5S_t *space;           IN/OUT: Pointer to dataspace to adjust
7069
        const hssize_t *offset; IN: Offset to subtract
7070
 RETURNS
7071
    Non-negative on success, negative on failure
7072
 DESCRIPTION
7073
    Moves a hyperslab selection by subtracting an offset from it.
7074
 GLOBAL VARIABLES
7075
 COMMENTS, BUGS, ASSUMPTIONS
7076
 EXAMPLES
7077
 REVISION LOG
7078
--------------------------------------------------------------------------*/
7079
static herr_t
7080
H5S__hyper_adjust_s(H5S_t *space, const hssize_t *offset)
7081
0
{
7082
0
    bool     non_zero_offset = false; /* Whether any offset is non-zero */
7083
0
    unsigned u;                       /* Local index variable */
7084
7085
0
    FUNC_ENTER_PACKAGE_NOERR
7086
7087
    /* Sanity checks */
7088
0
    assert(space);
7089
0
    assert(offset);
7090
7091
    /* Check for an all-zero offset vector */
7092
0
    for (u = 0; u < space->extent.rank; u++)
7093
0
        if (0 != offset[u]) {
7094
0
            non_zero_offset = true;
7095
0
            break;
7096
0
        } /* end if */
7097
7098
    /* Only perform operation if the offset is non-zero */
7099
0
    if (non_zero_offset) {
7100
        /* Subtract the offset from the "regular" coordinates, if they exist */
7101
        /* (No need to rebuild the dimension info yet -QAK) */
7102
0
        if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
7103
0
            for (u = 0; u < space->extent.rank; u++) {
7104
0
                assert((hssize_t)space->select.sel_info.hslab->diminfo.opt[u].start >= offset[u]);
7105
0
                space->select.sel_info.hslab->diminfo.opt[u].start =
7106
0
                    (hsize_t)((hssize_t)space->select.sel_info.hslab->diminfo.opt[u].start - offset[u]);
7107
7108
                /* Adjust the low & high bounds */
7109
0
                assert((hssize_t)space->select.sel_info.hslab->diminfo.low_bounds[u] >= offset[u]);
7110
0
                space->select.sel_info.hslab->diminfo.low_bounds[u] =
7111
0
                    (hsize_t)((hssize_t)space->select.sel_info.hslab->diminfo.low_bounds[u] - offset[u]);
7112
0
                space->select.sel_info.hslab->diminfo.high_bounds[u] =
7113
0
                    (hsize_t)((hssize_t)space->select.sel_info.hslab->diminfo.high_bounds[u] - offset[u]);
7114
0
            } /* end for */
7115
0
        }     /* end if */
7116
7117
        /* Subtract the offset from the span tree coordinates, if they exist */
7118
0
        if (space->select.sel_info.hslab->span_lst) {
7119
0
            uint64_t op_gen; /* Operation generation value */
7120
7121
            /* Acquire an operation generation value for this operation */
7122
0
            op_gen = H5S__hyper_get_op_gen();
7123
7124
            /* Perform the adjustment */
7125
            /* Always use op_info[0] since we own this op_info, so there can be no
7126
             * simultaneous operations */
7127
0
            H5S__hyper_adjust_s_helper(space->select.sel_info.hslab->span_lst, space->extent.rank, offset, 0,
7128
0
                                       op_gen);
7129
0
        } /* end if */
7130
0
    }
7131
7132
0
    FUNC_LEAVE_NOAPI(SUCCEED)
7133
0
} /* end H5S__hyper_adjust_s() */
7134
7135
/*--------------------------------------------------------------------------
7136
 NAME
7137
    H5S_hyper_normalize_offset
7138
 PURPOSE
7139
    "Normalize" a hyperslab selection by adjusting it's coordinates by the
7140
    amount of the selection offset.
7141
 USAGE
7142
    htri_t H5S_hyper_normalize_offset(space, old_offset)
7143
        H5S_t *space;           IN/OUT: Pointer to dataspace to move
7144
        hssize_t *old_offset;   OUT: Pointer to space to store old offset
7145
 RETURNS
7146
    true/false for hyperslab selection, FAIL on error
7147
 DESCRIPTION
7148
    Copies the current selection offset into the array provided, then
7149
    inverts the selection offset, subtracts the offset from the hyperslab
7150
    selection and resets the offset to zero.
7151
 GLOBAL VARIABLES
7152
 COMMENTS, BUGS, ASSUMPTIONS
7153
 EXAMPLES
7154
 REVISION LOG
7155
--------------------------------------------------------------------------*/
7156
htri_t
7157
H5S_hyper_normalize_offset(H5S_t *space, hssize_t *old_offset)
7158
0
{
7159
0
    htri_t ret_value = false; /* Return value */
7160
7161
0
    FUNC_ENTER_NOAPI(FAIL)
7162
7163
    /* Sanity checks */
7164
0
    assert(space);
7165
0
    assert(old_offset);
7166
7167
    /* Check for hyperslab selection & offset changed */
7168
0
    if (H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS && space->select.offset_changed) {
7169
0
        unsigned u; /* Local index variable */
7170
7171
        /* Copy & invert the selection offset */
7172
0
        for (u = 0; u < space->extent.rank; u++) {
7173
0
            old_offset[u]           = space->select.offset[u];
7174
0
            space->select.offset[u] = -space->select.offset[u];
7175
0
        } /* end for */
7176
7177
        /* Call the 'adjust' routine */
7178
0
        if (H5S__hyper_adjust_s(space, space->select.offset) < 0)
7179
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't adjust selection");
7180
7181
        /* Zero out the selection offset */
7182
0
        memset(space->select.offset, 0, sizeof(hssize_t) * space->extent.rank);
7183
7184
        /* Indicate that the offset was normalized */
7185
0
        ret_value = true;
7186
0
    } /* end if */
7187
7188
0
done:
7189
0
    FUNC_LEAVE_NOAPI(ret_value)
7190
0
} /* end H5S_hyper_normalize_offset() */
7191
7192
/*--------------------------------------------------------------------------
7193
 NAME
7194
    H5S_hyper_denormalize_offset
7195
 PURPOSE
7196
    "Denormalize" a hyperslab selection by reverse adjusting it's coordinates
7197
    by the amount of the former selection offset.
7198
 USAGE
7199
    herr_t H5S_hyper_denormalize_offset(space, old_offset)
7200
        H5S_t *space;           IN/OUT: Pointer to dataspace to move
7201
        hssize_t *old_offset;   IN: Pointer to old offset array
7202
 RETURNS
7203
    Non-negative on success, negative on failure
7204
 DESCRIPTION
7205
    Subtracts the old offset from the current selection (canceling out the
7206
    effect of the "normalize" routine), then restores the old offset into
7207
    the dataspace.
7208
 GLOBAL VARIABLES
7209
 COMMENTS, BUGS, ASSUMPTIONS
7210
 EXAMPLES
7211
 REVISION LOG
7212
--------------------------------------------------------------------------*/
7213
herr_t
7214
H5S_hyper_denormalize_offset(H5S_t *space, const hssize_t *old_offset)
7215
0
{
7216
0
    herr_t ret_value = SUCCEED; /* Return value */
7217
7218
0
    FUNC_ENTER_NOAPI(FAIL)
7219
7220
    /* Sanity checks */
7221
0
    assert(space);
7222
0
    assert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS);
7223
7224
    /* Call the 'adjust' routine */
7225
0
    if (H5S__hyper_adjust_s(space, old_offset) < 0)
7226
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't adjust selection");
7227
7228
    /* Copy the selection offset over */
7229
0
    H5MM_memcpy(space->select.offset, old_offset, sizeof(hssize_t) * space->extent.rank);
7230
7231
0
done:
7232
0
    FUNC_LEAVE_NOAPI(ret_value)
7233
0
} /* end H5S_hyper_denormalize_offset() */
7234
7235
/*--------------------------------------------------------------------------
7236
 NAME
7237
    H5S__hyper_append_span
7238
 PURPOSE
7239
    Create a new span and append to span list
7240
 USAGE
7241
    herr_t H5S__hyper_append_span(span_tree, ndims, low, high, down)
7242
        H5S_hyper_span_info_t **span_tree;  IN/OUT: Pointer to span tree to append to
7243
        unsigned ndims;                  IN: Number of dimension for span
7244
        hsize_t low, high;               IN: Low and high bounds for new span node
7245
        H5S_hyper_span_info_t *down;     IN: Down span tree for new node
7246
 RETURNS
7247
    Non-negative on success, negative on failure
7248
 DESCRIPTION
7249
    Create a new span node and append to a span list.  Update the previous
7250
    span in the list also.
7251
 GLOBAL VARIABLES
7252
 COMMENTS, BUGS, ASSUMPTIONS
7253
 EXAMPLES
7254
 REVISION LOG
7255
--------------------------------------------------------------------------*/
7256
static herr_t
7257
H5S__hyper_append_span(H5S_hyper_span_info_t **span_tree, unsigned ndims, hsize_t low, hsize_t high,
7258
                       H5S_hyper_span_info_t *down)
7259
0
{
7260
0
    H5S_hyper_span_t *new_span  = NULL;
7261
0
    herr_t            ret_value = SUCCEED; /* Return value */
7262
7263
0
    FUNC_ENTER_PACKAGE
7264
7265
    /* Sanity checks */
7266
0
    assert(span_tree);
7267
7268
    /* Check for adding first node to merged spans */
7269
0
    if (*span_tree == NULL) {
7270
        /* Allocate new span node to append to list */
7271
0
        if (NULL == (new_span = H5S__hyper_new_span(low, high, down, NULL)))
7272
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span");
7273
7274
        /* Make new span the first node in span list */
7275
7276
        /* Allocate a new span_info node */
7277
0
        if (NULL == (*span_tree = H5S__hyper_new_span_info(ndims)))
7278
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span");
7279
7280
        /* Set the span tree's basic information */
7281
0
        (*span_tree)->count = 1;
7282
0
        (*span_tree)->head  = new_span;
7283
0
        (*span_tree)->tail  = new_span;
7284
7285
        /* Set low & high bounds for new span tree */
7286
0
        (*span_tree)->low_bounds[0]  = low;
7287
0
        (*span_tree)->high_bounds[0] = high;
7288
0
        if (down) {
7289
            /* Sanity check */
7290
0
            assert(ndims > 1);
7291
7292
0
            H5MM_memcpy(&((*span_tree)->low_bounds[1]), down->low_bounds, sizeof(hsize_t) * (ndims - 1));
7293
0
            H5MM_memcpy(&((*span_tree)->high_bounds[1]), down->high_bounds, sizeof(hsize_t) * (ndims - 1));
7294
0
        } /* end if */
7295
0
    }     /* end if */
7296
    /* Merge or append to existing merged spans list */
7297
0
    else {
7298
0
        htri_t down_cmp = (-1); /* Comparison value for down spans */
7299
7300
        /* Check if span can just extend the previous merged span */
7301
0
        if ((((*span_tree)->tail->high + 1) == low) &&
7302
0
            (down_cmp = H5S__hyper_cmp_spans(down, (*span_tree)->tail->down))) {
7303
            /* Extend previous merged span to include new high bound */
7304
0
            (*span_tree)->tail->high = high;
7305
7306
            /* Extend span tree's high bound in this dimension */
7307
            /* (No need to update lower dimensions, since this span shares them with previous span) */
7308
0
            (*span_tree)->high_bounds[0] = high;
7309
0
        } /* end if */
7310
0
        else {
7311
0
            H5S_hyper_span_info_t *new_down; /* Down pointer for new span node */
7312
7313
            /* Sanity check */
7314
            /* (If down_cmp was set to true above, we won't be in this branch) */
7315
0
            assert(down_cmp != true);
7316
7317
            /* Check if there is actually a down span */
7318
0
            if (down) {
7319
                /* Check if the down spans for the new span node are the same as the previous span node */
7320
                /* (Uses the 'down span comparison' from earlier, if already computed) */
7321
0
                if (down_cmp < 0 && (down_cmp = H5S__hyper_cmp_spans(down, (*span_tree)->tail->down)))
7322
                    /* Share the previous span's down span tree */
7323
0
                    new_down = (*span_tree)->tail->down;
7324
0
                else
7325
0
                    new_down = down;
7326
0
            } /* end if */
7327
0
            else
7328
0
                new_down = NULL;
7329
7330
            /* Allocate new span node to append to list */
7331
0
            if (NULL == (new_span = H5S__hyper_new_span(low, high, new_down, NULL)))
7332
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span");
7333
7334
            /* Update the high bounds for current dimension */
7335
0
            (*span_tree)->high_bounds[0] = high;
7336
7337
            /* Update low & high bounds in lower dimensions, if there are any */
7338
0
            if (down) {
7339
                /* Sanity checks */
7340
0
                assert(ndims > 1);
7341
0
                assert(down_cmp >= 0);
7342
7343
                /* Check if we are sharing down spans with a previous node */
7344
                /* (Only need to check for bounds changing if down spans aren't shared) */
7345
0
                if (down_cmp == false) {
7346
0
                    unsigned u; /* Local index variable */
7347
7348
                    /* Loop over lower dimensions, checking & updating low & high bounds */
7349
0
                    for (u = 0; u < (ndims - 1); u++) {
7350
0
                        if (down->low_bounds[u] < (*span_tree)->low_bounds[u + 1])
7351
0
                            (*span_tree)->low_bounds[u + 1] = down->low_bounds[u];
7352
0
                        if (down->high_bounds[u] > (*span_tree)->high_bounds[u + 1])
7353
0
                            (*span_tree)->high_bounds[u + 1] = down->high_bounds[u];
7354
0
                    } /* end for */
7355
0
                }     /* end if */
7356
0
            }         /* end if */
7357
7358
            /* Append to end of merged spans list */
7359
0
            (*span_tree)->tail->next = new_span;
7360
0
            (*span_tree)->tail       = new_span;
7361
0
        } /* end else */
7362
0
    }     /* end else */
7363
7364
0
done:
7365
0
    if (ret_value < 0)
7366
0
        if (new_span)
7367
0
            if (H5S__hyper_free_span(new_span) < 0)
7368
0
                HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span");
7369
7370
0
    FUNC_LEAVE_NOAPI(ret_value)
7371
0
} /* end H5S__hyper_append_span() */
7372
7373
/*--------------------------------------------------------------------------
7374
 NAME
7375
    H5S__hyper_clip_spans
7376
 PURPOSE
7377
    Clip a new span tree against the current spans in the hyperslab selection
7378
 USAGE
7379
    herr_t H5S__hyper_clip_spans(span_a, span_b, selector, curr_dim, dim_size,
7380
                                span_a_b_bounds[4], all_clips_bound,
7381
                                a_not_b, a_and_b, b_not_a)
7382
        H5S_hyper_span_t *a_spans;    IN: Span tree 'a' to clip with.
7383
        H5S_hyper_span_t *b_spans;    IN: Span tree 'b' to clip with.
7384
        unsigned selector;            IN: The parameter deciding which output is needed
7385
                                          (only considering the last three bits ABC:
7386
                                           If A is set, then a_not_b is needed;
7387
                                           If B is set, then a_and_b is needed;
7388
                                           If C is set, then b_not_a is needed;
7389
                                           )
7390
        unsigned ndims;               IN: Number of dimensions of this span tree
7391
        H5S_hyper_span_t **a_not_b;  OUT: Span tree of 'a' hyperslab spans which
7392
                                            doesn't overlap with 'b' hyperslab
7393
                                            spans.
7394
        H5S_hyper_span_t **a_and_b;  OUT: Span tree of 'a' hyperslab spans which
7395
                                            overlaps with 'b' hyperslab spans.
7396
        H5S_hyper_span_t **b_not_a;  OUT: Span tree of 'b' hyperslab spans which
7397
                                            doesn't overlap with 'a' hyperslab
7398
                                            spans.
7399
 RETURNS
7400
    non-negative on success, negative on failure
7401
 DESCRIPTION
7402
    Clip one span tree ('a') against another span tree ('b').  Creates span
7403
    trees for the area defined by the 'a' span tree which does not overlap the
7404
    'b' span tree ("a not b"), the area defined by the overlap of the 'a'
7405
    hyperslab span tree and the 'b' span tree ("a and b"), and the area defined
7406
    by the 'b' hyperslab span tree which does not overlap the 'a' span
7407
    tree ("b not a").
7408
 GLOBAL VARIABLES
7409
 COMMENTS, BUGS, ASSUMPTIONS
7410
 EXAMPLES
7411
 REVISION LOG
7412
--------------------------------------------------------------------------*/
7413
static herr_t
7414
H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_spans, unsigned selector,
7415
                      unsigned ndims, H5S_hyper_span_info_t **a_not_b, H5S_hyper_span_info_t **a_and_b,
7416
                      H5S_hyper_span_info_t **b_not_a)
7417
0
{
7418
0
    bool   need_a_not_b;        /* Whether to generate a_not_b list */
7419
0
    bool   need_a_and_b;        /* Whether to generate a_and_b list */
7420
0
    bool   need_b_not_a;        /* Whether to generate b_not_a list */
7421
0
    herr_t ret_value = SUCCEED; /* Return value */
7422
7423
0
    FUNC_ENTER_PACKAGE
7424
7425
    /* Check args */
7426
0
    assert(a_spans);
7427
0
    assert(b_spans);
7428
0
    assert(a_not_b);
7429
0
    assert(a_and_b);
7430
0
    assert(b_not_a);
7431
7432
    /* Set which list(s) to be generated, based on selector */
7433
0
    need_a_not_b = ((selector & H5S_HYPER_COMPUTE_A_NOT_B) != 0);
7434
0
    need_a_and_b = ((selector & H5S_HYPER_COMPUTE_A_AND_B) != 0);
7435
0
    need_b_not_a = ((selector & H5S_HYPER_COMPUTE_B_NOT_A) != 0);
7436
7437
    /* Check if both span trees are not defined */
7438
0
    if (a_spans == NULL && b_spans == NULL) {
7439
0
        *a_not_b = NULL;
7440
0
        *a_and_b = NULL;
7441
0
        *b_not_a = NULL;
7442
0
    } /* end if */
7443
    /* If span 'a' is not defined, but 'b' is, copy 'b' and set the other return span trees to empty */
7444
0
    else if (a_spans == NULL) {
7445
0
        *a_not_b = NULL;
7446
0
        *a_and_b = NULL;
7447
0
        if (need_b_not_a) {
7448
0
            if (NULL == (*b_not_a = H5S__hyper_copy_span(b_spans, ndims)))
7449
0
                HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree");
7450
0
        } /* end if */
7451
0
        else
7452
0
            *b_not_a = NULL;
7453
0
    } /* end if */
7454
    /* If span 'b' is not defined, but 'a' is, copy 'a' and set the other return span trees to empty */
7455
0
    else if (b_spans == NULL) {
7456
0
        *a_and_b = NULL;
7457
0
        *b_not_a = NULL;
7458
0
        if (need_a_not_b) {
7459
0
            if (NULL == (*a_not_b = H5S__hyper_copy_span(a_spans, ndims)))
7460
0
                HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree");
7461
0
        } /* end if */
7462
0
        else
7463
0
            *a_not_b = NULL;
7464
0
    } /* end if */
7465
    /* If span 'a' and 'b' are both defined, calculate the proper span trees */
7466
0
    else {
7467
        /* Check if both span trees completely overlap */
7468
0
        if (H5S__hyper_cmp_spans(a_spans, b_spans)) {
7469
0
            *a_not_b = NULL;
7470
0
            *b_not_a = NULL;
7471
0
            if (need_a_and_b) {
7472
0
                if (NULL == (*a_and_b = H5S__hyper_copy_span(a_spans, ndims)))
7473
0
                    HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree");
7474
0
            } /* end if */
7475
0
            else
7476
0
                *a_and_b = NULL;
7477
0
        } /* end if */
7478
0
        else {
7479
0
            H5S_hyper_span_t *span_a;               /* Pointer to a node in span tree 'a' */
7480
0
            H5S_hyper_span_t *span_b;               /* Pointer to a node in span tree 'b' */
7481
0
            bool              recover_a, recover_b; /* Flags to indicate when to recover temporary spans */
7482
7483
            /* Get the pointers to the new and old span lists */
7484
0
            span_a = a_spans->head;
7485
0
            span_b = b_spans->head;
7486
7487
            /* No spans to recover yet */
7488
0
            recover_a = recover_b = false;
7489
7490
            /* Work through the list of spans in the new list */
7491
0
            while (span_a != NULL && span_b != NULL) {
7492
0
                H5S_hyper_span_info_t *down_a_not_b; /* Temporary pointer to a_not_b span tree of down spans
7493
                                                        for overlapping nodes */
7494
0
                H5S_hyper_span_info_t *down_a_and_b; /* Temporary pointer to a_and_b span tree of down spans
7495
                                                        for overlapping nodes */
7496
0
                H5S_hyper_span_info_t *down_b_not_a; /* Temporary pointer to b_and_a span tree of down spans
7497
                                                        for overlapping nodes */
7498
0
                H5S_hyper_span_t *tmp_span;          /* Temporary pointer to new span */
7499
7500
                /* Check if span 'a' is completely before span 'b' */
7501
                /*    AAAAAAA                            */
7502
                /* <-----------------------------------> */
7503
                /*             BBBBBBBBBB                */
7504
0
                if (span_a->high < span_b->low) {
7505
                    /* Copy span 'a' and add to a_not_b list */
7506
7507
                    /* Merge/add span 'a' with/to a_not_b list */
7508
0
                    if (need_a_not_b)
7509
0
                        if (H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_a->high, span_a->down) <
7510
0
                            0)
7511
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
7512
7513
                    /* Advance span 'a', leave span 'b' */
7514
0
                    H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, FAIL);
7515
0
                } /* end if */
7516
                /* Check if span 'a' overlaps only the lower bound */
7517
                /*  of span 'b' , up to the upper bound of span 'b' */
7518
                /*    AAAAAAAAAAAA                       */
7519
                /* <-----------------------------------> */
7520
                /*             BBBBBBBBBB                */
7521
0
                else if (span_a->low < span_b->low &&
7522
0
                         (span_a->high >= span_b->low && span_a->high <= span_b->high)) {
7523
                    /* Split span 'a' into two parts at the low bound of span 'b' */
7524
7525
                    /* Merge/add lower part of span 'a' with/to a_not_b list */
7526
0
                    if (need_a_not_b)
7527
0
                        if (H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_b->low - 1,
7528
0
                                                   span_a->down) < 0)
7529
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
7530
7531
                    /* Check for overlaps between upper part of span 'a' and lower part of span 'b' */
7532
7533
                    /* Make certain both spans either have a down span or both don't have one */
7534
0
                    assert((span_a->down != NULL && span_b->down != NULL) ||
7535
0
                           (span_a->down == NULL && span_b->down == NULL));
7536
7537
                    /* If there are no down spans, just add the overlapping area to the a_and_b list */
7538
0
                    if (span_a->down == NULL) {
7539
                        /* Merge/add overlapped part with/to a_and_b list */
7540
0
                        if (need_a_and_b)
7541
0
                            if (H5S__hyper_append_span(a_and_b, ndims, span_b->low, span_a->high, NULL) < 0)
7542
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7543
0
                                            "can't allocate hyperslab span");
7544
0
                    } /* end if */
7545
                    /* If there are down spans, check for the overlap in them and add to each appropriate list
7546
                     */
7547
0
                    else {
7548
                        /* NULL out the temporary pointers to clipped areas in down spans */
7549
0
                        down_a_not_b = NULL;
7550
0
                        down_a_and_b = NULL;
7551
0
                        down_b_not_a = NULL;
7552
7553
                        /* Check for overlaps in the 'down spans' of span 'a' & 'b' */
7554
                        /** Note: since the bound box of remaining dimensions
7555
                         *  has been updated in the following clip function (via
7556
                         *  all_clips_bounds), there's no need updating the bound box
7557
                         *  after each append call in the following codes */
7558
0
                        if (H5S__hyper_clip_spans(span_a->down, span_b->down, selector, ndims - 1,
7559
0
                                                  &down_a_not_b, &down_a_and_b, &down_b_not_a) < 0)
7560
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL,
7561
0
                                        "can't clip hyperslab information");
7562
7563
                        /* Check for additions to the a_not_b list */
7564
0
                        if (down_a_not_b) {
7565
0
                            assert(need_a_not_b == true);
7566
7567
                            /* Merge/add overlapped part with/to a_not_b list */
7568
0
                            if (H5S__hyper_append_span(a_not_b, ndims, span_b->low, span_a->high,
7569
0
                                                       down_a_not_b) < 0)
7570
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7571
0
                                            "can't allocate hyperslab span");
7572
7573
                            /* Release the down span tree generated */
7574
0
                            if (H5S__hyper_free_span_info(down_a_not_b) < 0)
7575
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7576
0
                        }
7577
7578
                        /* Check for additions to the a_and_b list */
7579
0
                        if (down_a_and_b) {
7580
0
                            assert(need_a_and_b == true);
7581
7582
                            /* Merge/add overlapped part with/to a_and_b list */
7583
0
                            if (H5S__hyper_append_span(a_and_b, ndims, span_b->low, span_a->high,
7584
0
                                                       down_a_and_b) < 0)
7585
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7586
0
                                            "can't allocate hyperslab span");
7587
7588
                            /* Release the down span tree generated */
7589
0
                            if (H5S__hyper_free_span_info(down_a_and_b) < 0)
7590
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7591
0
                        }
7592
7593
                        /* Check for additions to the b_not_a list */
7594
0
                        if (down_b_not_a) {
7595
0
                            assert(need_b_not_a == true);
7596
7597
                            /* Merge/add overlapped part with/to b_not_a list */
7598
0
                            if (H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_a->high,
7599
0
                                                       down_b_not_a) < 0)
7600
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7601
0
                                            "can't allocate hyperslab span");
7602
7603
                            /* Release the down span tree generated */
7604
0
                            if (H5S__hyper_free_span_info(down_b_not_a) < 0)
7605
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7606
0
                        }
7607
0
                    } /* end else */
7608
7609
                    /* Split off upper part of span 'b' at upper span of span 'a' */
7610
7611
                    /* Check if there is actually an upper part of span 'b' to split off */
7612
0
                    if (span_a->high < span_b->high) {
7613
                        /* Allocate new span node for upper part of span 'b' */
7614
0
                        if (NULL == (tmp_span = H5S__hyper_new_span(span_a->high + 1, span_b->high,
7615
0
                                                                    span_b->down, span_b->next)))
7616
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span");
7617
7618
                        /* Advance span 'a' */
7619
0
                        H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, FAIL);
7620
7621
                        /* Make upper part of span 'b' into new span 'b' */
7622
0
                        H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, tmp_span, FAIL);
7623
0
                        recover_b = true;
7624
0
                    } /* end if */
7625
                    /* No upper part of span 'b' to split */
7626
0
                    else {
7627
                        /* Advance both 'a' and 'b' */
7628
0
                        H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, FAIL);
7629
0
                        H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, FAIL);
7630
0
                    } /* end else */
7631
0
                }     /* end if */
7632
                /* Check if span 'a' overlaps the lower & upper bound */
7633
                /*  of span 'b' */
7634
                /*    AAAAAAAAAAAAAAAAAAAAA              */
7635
                /* <-----------------------------------> */
7636
                /*             BBBBBBBBBB                */
7637
0
                else if (span_a->low < span_b->low && span_a->high > span_b->high) {
7638
                    /* Split off lower part of span 'a' at lower span of span 'b' */
7639
7640
                    /* Merge/add lower part of span 'a' with/to a_not_b list */
7641
0
                    if (need_a_not_b)
7642
0
                        if (H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_b->low - 1,
7643
0
                                                   span_a->down) < 0)
7644
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
7645
7646
                    /* Check for overlaps between middle part of span 'a' and span 'b' */
7647
7648
                    /* Make certain both spans either have a down span or both don't have one */
7649
0
                    assert((span_a->down != NULL && span_b->down != NULL) ||
7650
0
                           (span_a->down == NULL && span_b->down == NULL));
7651
7652
                    /* If there are no down spans, just add the overlapping area to the a_and_b list */
7653
0
                    if (span_a->down == NULL) {
7654
                        /* Merge/add overlapped part with/to a_and_b list */
7655
0
                        if (need_a_and_b)
7656
0
                            if (H5S__hyper_append_span(a_and_b, ndims, span_b->low, span_b->high, NULL) < 0)
7657
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7658
0
                                            "can't allocate hyperslab span");
7659
0
                    } /* end if */
7660
                    /* If there are down spans, check for the overlap in them and add to each appropriate list
7661
                     */
7662
0
                    else {
7663
                        /* NULL out the temporary pointers to clipped areas in down spans */
7664
0
                        down_a_not_b = NULL;
7665
0
                        down_a_and_b = NULL;
7666
0
                        down_b_not_a = NULL;
7667
7668
                        /* Check for overlaps in the 'down spans' of span 'a' & 'b' */
7669
0
                        if (H5S__hyper_clip_spans(span_a->down, span_b->down, selector, ndims - 1,
7670
0
                                                  &down_a_not_b, &down_a_and_b, &down_b_not_a) < 0)
7671
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL,
7672
0
                                        "can't clip hyperslab information");
7673
7674
                        /* Check for additions to the a_not_b list */
7675
0
                        if (down_a_not_b) {
7676
0
                            assert(need_a_not_b == true);
7677
7678
                            /* Merge/add overlapped part with/to a_not_b list */
7679
0
                            if (H5S__hyper_append_span(a_not_b, ndims, span_b->low, span_b->high,
7680
0
                                                       down_a_not_b) < 0)
7681
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7682
0
                                            "can't allocate hyperslab span");
7683
7684
                            /* Release the down span tree generated */
7685
0
                            if (H5S__hyper_free_span_info(down_a_not_b) < 0)
7686
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7687
0
                        }
7688
7689
                        /* Check for additions to the a_and_b list */
7690
0
                        if (down_a_and_b) {
7691
0
                            assert(need_a_and_b == true);
7692
7693
                            /* Merge/add overlapped part with/to a_and_b list */
7694
0
                            if (H5S__hyper_append_span(a_and_b, ndims, span_b->low, span_b->high,
7695
0
                                                       down_a_and_b) < 0)
7696
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7697
0
                                            "can't allocate hyperslab span");
7698
7699
                            /* Release the down span tree generated */
7700
0
                            if (H5S__hyper_free_span_info(down_a_and_b) < 0)
7701
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7702
0
                        }
7703
7704
                        /* Check for additions to the b_not_a list */
7705
0
                        if (down_b_not_a) {
7706
0
                            assert(need_b_not_a == true);
7707
7708
                            /* Merge/add overlapped part with/to b_not_a list */
7709
0
                            if (H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_b->high,
7710
0
                                                       down_b_not_a) < 0)
7711
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7712
0
                                            "can't allocate hyperslab span");
7713
7714
                            /* Release the down span tree generated */
7715
0
                            if (H5S__hyper_free_span_info(down_b_not_a) < 0)
7716
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7717
0
                        }
7718
0
                    } /* end else */
7719
7720
                    /* Split off upper part of span 'a' at upper span of span 'b' */
7721
7722
                    /* Allocate new span node for upper part of span 'a' */
7723
0
                    if (NULL == (tmp_span = H5S__hyper_new_span(span_b->high + 1, span_a->high, span_a->down,
7724
0
                                                                span_a->next)))
7725
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span");
7726
7727
                    /* Make upper part of span 'a' the new span 'a' */
7728
0
                    H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, tmp_span, FAIL);
7729
0
                    recover_a = true;
7730
7731
                    /* Advance span 'b' */
7732
0
                    H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, FAIL);
7733
0
                } /* end if */
7734
                /* Check if span 'a' is entirely within span 'b' */
7735
                /*                AAAAA                  */
7736
                /* <-----------------------------------> */
7737
                /*             BBBBBBBBBB                */
7738
0
                else if (span_a->low >= span_b->low && span_a->high <= span_b->high) {
7739
                    /* Split off lower part of span 'b' at lower span of span 'a' */
7740
7741
                    /* Check if there is actually a lower part of span 'b' to split off */
7742
0
                    if (span_a->low > span_b->low) {
7743
                        /* Merge/add lower part of span 'b' with/to b_not_a list */
7744
0
                        if (need_b_not_a)
7745
0
                            if (H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_a->low - 1,
7746
0
                                                       span_b->down) < 0)
7747
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7748
0
                                            "can't allocate hyperslab span");
7749
0
                    } /* end if */
7750
0
                    else {
7751
                        /* Keep going, nothing to split off */
7752
0
                    } /* end else */
7753
7754
                    /* Check for overlaps between span 'a' and middle of span 'b' */
7755
7756
                    /* Make certain both spans either have a down span or both don't have one */
7757
0
                    assert((span_a->down != NULL && span_b->down != NULL) ||
7758
0
                           (span_a->down == NULL && span_b->down == NULL));
7759
7760
                    /* If there are no down spans, just add the overlapping area to the a_and_b list */
7761
0
                    if (span_a->down == NULL) {
7762
                        /* Merge/add overlapped part with/to a_and_b list */
7763
0
                        if (need_a_and_b)
7764
0
                            if (H5S__hyper_append_span(a_and_b, ndims, span_a->low, span_a->high, NULL) < 0)
7765
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7766
0
                                            "can't allocate hyperslab span");
7767
0
                    } /* end if */
7768
                    /* If there are down spans, check for the overlap in them and add to each appropriate list
7769
                     */
7770
0
                    else {
7771
                        /* NULL out the temporary pointers to clipped areas in down spans */
7772
0
                        down_a_not_b = NULL;
7773
0
                        down_a_and_b = NULL;
7774
0
                        down_b_not_a = NULL;
7775
7776
                        /* Check for overlaps in the 'down spans' of span 'a' & 'b' */
7777
0
                        if (H5S__hyper_clip_spans(span_a->down, span_b->down, selector, ndims - 1,
7778
0
                                                  &down_a_not_b, &down_a_and_b, &down_b_not_a) < 0)
7779
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL,
7780
0
                                        "can't clip hyperslab information");
7781
7782
                        /* Check for additions to the a_not_b list */
7783
0
                        if (down_a_not_b) {
7784
0
                            assert(need_a_not_b == true);
7785
7786
                            /* Merge/add overlapped part with/to a_not_b list */
7787
0
                            if (H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_a->high,
7788
0
                                                       down_a_not_b) < 0)
7789
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7790
0
                                            "can't allocate hyperslab span");
7791
7792
                            /* Release the down span tree generated */
7793
0
                            if (H5S__hyper_free_span_info(down_a_not_b) < 0)
7794
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7795
0
                        }
7796
7797
                        /* Check for additions to the a_and_b list */
7798
0
                        if (down_a_and_b) {
7799
0
                            assert(need_a_and_b == true);
7800
7801
                            /* Merge/add overlapped part with/to a_and_b list */
7802
0
                            if (H5S__hyper_append_span(a_and_b, ndims, span_a->low, span_a->high,
7803
0
                                                       down_a_and_b) < 0)
7804
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7805
0
                                            "can't allocate hyperslab span");
7806
7807
                            /* Release the down span tree generated */
7808
0
                            if (H5S__hyper_free_span_info(down_a_and_b) < 0)
7809
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7810
0
                        }
7811
7812
                        /* Check for additions to the b_not_a list */
7813
0
                        if (down_b_not_a) {
7814
0
                            assert(need_b_not_a == true);
7815
7816
                            /* Merge/add overlapped part with/to b_not_a list */
7817
0
                            if (H5S__hyper_append_span(b_not_a, ndims, span_a->low, span_a->high,
7818
0
                                                       down_b_not_a) < 0)
7819
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7820
0
                                            "can't allocate hyperslab span");
7821
7822
                            /* Release the down span tree generated */
7823
0
                            if (H5S__hyper_free_span_info(down_b_not_a) < 0)
7824
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7825
0
                        }
7826
0
                    } /* end else */
7827
7828
                    /* Check if there is actually an upper part of span 'b' to split off */
7829
0
                    if (span_a->high < span_b->high) {
7830
                        /* Split off upper part of span 'b' at upper span of span 'a' */
7831
7832
                        /* Allocate new span node for upper part of spans 'a' */
7833
0
                        if (NULL == (tmp_span = H5S__hyper_new_span(span_a->high + 1, span_b->high,
7834
0
                                                                    span_b->down, span_b->next)))
7835
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span");
7836
7837
                        /* And advance span 'a' */
7838
0
                        H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, FAIL);
7839
7840
                        /* Make upper part of span 'b' the new span 'b' */
7841
0
                        H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, tmp_span, FAIL);
7842
0
                        recover_b = true;
7843
0
                    } /* end if */
7844
0
                    else {
7845
                        /* Advance both span 'a' & span 'b' */
7846
0
                        H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, FAIL);
7847
0
                        H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, FAIL);
7848
0
                    } /* end else */
7849
0
                }     /* end if */
7850
                /* Check if span 'a' overlaps only the upper bound */
7851
                /*  of span 'b' */
7852
                /*                AAAAAAAAAA             */
7853
                /* <-----------------------------------> */
7854
                /*             BBBBBBBBBB                */
7855
0
                else if ((span_a->low >= span_b->low && span_a->low <= span_b->high) &&
7856
0
                         span_a->high > span_b->high) {
7857
                    /* Check if there is actually a lower part of span 'b' to split off */
7858
0
                    if (span_a->low > span_b->low) {
7859
                        /* Split off lower part of span 'b' at lower span of span 'a' */
7860
7861
                        /* Merge/add lower part of span 'b' with/to b_not_a list */
7862
0
                        if (need_b_not_a)
7863
0
                            if (H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_a->low - 1,
7864
0
                                                       span_b->down) < 0)
7865
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7866
0
                                            "can't allocate hyperslab span");
7867
0
                    } /* end if */
7868
0
                    else {
7869
                        /* Keep going, nothing to split off */
7870
0
                    } /* end else */
7871
7872
                    /* Check for overlaps between lower part of span 'a' and upper part of span 'b' */
7873
7874
                    /* Make certain both spans either have a down span or both don't have one */
7875
0
                    assert((span_a->down != NULL && span_b->down != NULL) ||
7876
0
                           (span_a->down == NULL && span_b->down == NULL));
7877
7878
                    /* If there are no down spans, just add the overlapping area to the a_and_b list */
7879
0
                    if (span_a->down == NULL) {
7880
                        /* Merge/add overlapped part with/to a_and_b list */
7881
0
                        if (need_a_and_b)
7882
0
                            if (H5S__hyper_append_span(a_and_b, ndims, span_a->low, span_b->high, NULL) < 0)
7883
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7884
0
                                            "can't allocate hyperslab span");
7885
0
                    } /* end if */
7886
                    /* If there are down spans, check for the overlap in them and add to each appropriate list
7887
                     */
7888
0
                    else {
7889
                        /* NULL out the temporary pointers to clipped areas in down spans */
7890
0
                        down_a_not_b = NULL;
7891
0
                        down_a_and_b = NULL;
7892
0
                        down_b_not_a = NULL;
7893
7894
                        /* Check for overlaps in the 'down spans' of span 'a' & 'b' */
7895
0
                        if (H5S__hyper_clip_spans(span_a->down, span_b->down, selector, ndims - 1,
7896
0
                                                  &down_a_not_b, &down_a_and_b, &down_b_not_a) < 0)
7897
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL,
7898
0
                                        "can't clip hyperslab information");
7899
7900
                        /* Check for additions to the a_not_b list */
7901
0
                        if (down_a_not_b) {
7902
0
                            assert(need_a_not_b == true);
7903
7904
                            /* Merge/add overlapped part with/to a_not_b list */
7905
0
                            if (H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_b->high,
7906
0
                                                       down_a_not_b) < 0)
7907
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7908
0
                                            "can't allocate hyperslab span");
7909
7910
                            /* Release the down span tree generated */
7911
0
                            if (H5S__hyper_free_span_info(down_a_not_b) < 0)
7912
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7913
0
                        }
7914
7915
                        /* Check for additions to the a_and_b list */
7916
0
                        if (down_a_and_b) {
7917
0
                            assert(need_a_and_b == true);
7918
7919
                            /* Merge/add overlapped part with/to a_and_b list */
7920
0
                            if (H5S__hyper_append_span(a_and_b, ndims, span_a->low, span_b->high,
7921
0
                                                       down_a_and_b) < 0)
7922
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7923
0
                                            "can't allocate hyperslab span");
7924
7925
                            /* Release the down span tree generated */
7926
0
                            if (H5S__hyper_free_span_info(down_a_and_b) < 0)
7927
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7928
0
                        }
7929
7930
                        /* Check for additions to the b_not_a list */
7931
0
                        if (down_b_not_a) {
7932
0
                            assert(need_b_not_a == true);
7933
7934
                            /* Merge/add overlapped part with/to b_not_a list */
7935
0
                            if (H5S__hyper_append_span(b_not_a, ndims, span_a->low, span_b->high,
7936
0
                                                       down_b_not_a) < 0)
7937
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7938
0
                                            "can't allocate hyperslab span");
7939
7940
                            /* Release the down span tree generated */
7941
0
                            if (H5S__hyper_free_span_info(down_b_not_a) < 0)
7942
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7943
0
                        }
7944
0
                    } /* end else */
7945
7946
                    /* Split off upper part of span 'a' at upper span of span 'b' */
7947
7948
                    /* Allocate new span node for upper part of span 'a' */
7949
0
                    if (NULL == (tmp_span = H5S__hyper_new_span(span_b->high + 1, span_a->high, span_a->down,
7950
0
                                                                span_a->next)))
7951
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span");
7952
7953
                    /* Make upper part of span 'a' into new span 'a' */
7954
0
                    H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, tmp_span, FAIL);
7955
0
                    recover_a = true;
7956
7957
                    /* Advance span 'b' */
7958
0
                    H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, FAIL);
7959
0
                } /* end if */
7960
                /* span 'a' must be entirely above span 'b' */
7961
                /*                         AAAAA         */
7962
                /* <-----------------------------------> */
7963
                /*             BBBBBBBBBB                */
7964
0
                else {
7965
                    /* Copy span 'b' and add to b_not_a list */
7966
7967
                    /* Merge/add span 'b' with/to b_not_a list */
7968
0
                    if (need_b_not_a)
7969
0
                        if (H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_b->high, span_b->down) <
7970
0
                            0)
7971
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
7972
7973
                    /* Advance span 'b', leave span 'a' */
7974
0
                    H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, FAIL);
7975
0
                } /* end else */
7976
0
            }     /* end while */
7977
7978
            /* Clean up 'a' spans which haven't been covered yet */
7979
0
            if (span_a != NULL && span_b == NULL) {
7980
                /* Check if need to merge/add 'a' spans with/to a_not_b list */
7981
0
                if (need_a_not_b) {
7982
                    /* (This loop, and the similar one below for 'b' spans,
7983
                     *  could be replaced with an optimized routine that quickly
7984
                     *  appended the remaining spans to the 'not' list, but
7985
                     *  until it looks like it's taking a lot of time for an
7986
                     *  important use case, it's been left generic, and similar
7987
                     *  to other code above. -QAK, 2019/02/01)
7988
                     */
7989
0
                    while (span_a != NULL) {
7990
                        /* Copy span 'a' and add to a_not_b list */
7991
0
                        if (H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_a->high, span_a->down) <
7992
0
                            0)
7993
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
7994
7995
                        /* Advance to the next 'a' span */
7996
0
                        H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, FAIL);
7997
0
                    } /* end while */
7998
0
                }     /* end if */
7999
0
                else {
8000
                    /* Free the span, if it's generated */
8001
0
                    if (recover_a)
8002
0
                        if (H5S__hyper_free_span(span_a) < 0)
8003
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span");
8004
0
                } /* end else */
8005
0
            }     /* end if */
8006
            /* Clean up 'b' spans which haven't been covered yet */
8007
0
            else if (span_a == NULL && span_b != NULL) {
8008
                /* Check if need to merge/add 'b' spans with/to b_not_a list */
8009
0
                if (need_b_not_a) {
8010
                    /* (This loop, and the similar one above for 'a' spans,
8011
                     *  could be replaced with an optimized routine that quickly
8012
                     *  appended the remaining spans to the 'not' list, but
8013
                     *  until it looks like it's taking a lot of time for an
8014
                     *  important use case, it's been left generic, and similar
8015
                     *  to other code above. -QAK, 2019/02/01)
8016
                     */
8017
0
                    while (span_b != NULL) {
8018
                        /* Copy span 'b' and add to b_not_a list */
8019
0
                        if (H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_b->high, span_b->down) <
8020
0
                            0)
8021
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
8022
8023
                        /* Advance to the next 'b' span */
8024
0
                        H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, FAIL);
8025
0
                    } /* end while */
8026
0
                }     /* end if */
8027
0
                else {
8028
                    /* Free the span, if it's generated */
8029
0
                    if (recover_b)
8030
0
                        if (H5S__hyper_free_span(span_b) < 0)
8031
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span");
8032
0
                } /* end else */
8033
0
            }     /* end if */
8034
0
            else
8035
                /* Sanity check */
8036
0
                assert(span_a == NULL && span_b == NULL);
8037
0
        } /* end else */
8038
0
    }     /* end else */
8039
8040
0
done:
8041
0
    FUNC_LEAVE_NOAPI(ret_value)
8042
0
} /* end H5S__hyper_clip_spans() */
8043
8044
/*--------------------------------------------------------------------------
8045
 NAME
8046
    H5S__hyper_merge_spans_helper
8047
 PURPOSE
8048
    Merge two hyperslab span tree together
8049
 USAGE
8050
    H5S_hyper_span_info_t *H5S__hyper_merge_spans_helper(a_spans, b_spans)
8051
        H5S_hyper_span_info_t *a_spans; IN: First hyperslab spans to merge
8052
                                                together
8053
        H5S_hyper_span_info_t *b_spans; IN: Second hyperslab spans to merge
8054
                                                together
8055
        unsigned ndims;                 IN: Number of dimensions of this span tree
8056
 RETURNS
8057
    Pointer to span tree containing the merged spans on success, NULL on failure
8058
 DESCRIPTION
8059
    Merge two sets of hyperslab spans together and return the span tree from
8060
    the merged set.
8061
 GLOBAL VARIABLES
8062
 COMMENTS, BUGS, ASSUMPTIONS
8063
    Handles merging span trees that overlap.
8064
 EXAMPLES
8065
 REVISION LOG
8066
--------------------------------------------------------------------------*/
8067
static H5S_hyper_span_info_t *
8068
H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_spans, unsigned ndims)
8069
0
{
8070
0
    H5S_hyper_span_info_t *merged_spans = NULL; /* Pointer to the merged span tree */
8071
0
    H5S_hyper_span_info_t *ret_value    = NULL; /* Return value */
8072
8073
0
    FUNC_ENTER_PACKAGE
8074
8075
    /* Make certain both 'a' & 'b' spans have down span trees or neither does */
8076
0
    assert((a_spans != NULL && b_spans != NULL) || (a_spans == NULL && b_spans == NULL));
8077
8078
    /* Check if the span trees for the 'a' span and the 'b' span are the same */
8079
0
    if (H5S__hyper_cmp_spans(a_spans, b_spans)) {
8080
0
        if (a_spans == NULL)
8081
0
            merged_spans = NULL;
8082
0
        else {
8083
            /* Copy one of the span trees to return */
8084
0
            if (NULL == (merged_spans = H5S__hyper_copy_span(a_spans, ndims)))
8085
0
                HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, NULL, "can't copy hyperslab span tree");
8086
0
        } /* end else */
8087
0
    }     /* end if */
8088
0
    else {
8089
0
        H5S_hyper_span_t *span_a;               /* Pointer to current span 'a' working on */
8090
0
        H5S_hyper_span_t *span_b;               /* Pointer to current span 'b' working on */
8091
0
        bool              recover_a, recover_b; /* Flags to indicate when to recover temporary spans */
8092
8093
        /* Get the pointers to the 'a' and 'b' span lists */
8094
0
        span_a = a_spans->head;
8095
0
        span_b = b_spans->head;
8096
8097
        /* No spans to recover yet */
8098
0
        recover_a = recover_b = false;
8099
8100
        /* Work through the list of spans in the new list */
8101
0
        while (span_a != NULL && span_b != NULL) {
8102
0
            H5S_hyper_span_info_t *tmp_spans; /* Pointer to temporary new span tree */
8103
0
            H5S_hyper_span_t      *tmp_span;  /* Pointer to temporary new span */
8104
8105
            /* Check if the 'a' span is completely before 'b' span */
8106
            /*    AAAAAAA                            */
8107
            /* <-----------------------------------> */
8108
            /*             BBBBBBBBBB                */
8109
0
            if (span_a->high < span_b->low) {
8110
                /* Merge/add span 'a' with/to the merged spans */
8111
0
                if (H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_a->high, span_a->down) < 0)
8112
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8113
8114
                /* Advance span 'a' */
8115
0
                H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, NULL);
8116
0
            } /* end if */
8117
            /* Check if span 'a' overlaps only the lower bound */
8118
            /*  of span 'b', up to the upper bound of span 'b' */
8119
            /*    AAAAAAAAAAAA                       */
8120
            /* <-----------------------------------> */
8121
            /*             BBBBBBBBBB                */
8122
0
            else if (span_a->low < span_b->low &&
8123
0
                     (span_a->high >= span_b->low && span_a->high <= span_b->high)) {
8124
                /* Check if span 'a' and span 'b' down spans are equal */
8125
0
                if (H5S__hyper_cmp_spans(span_a->down, span_b->down)) {
8126
                    /* Merge/add copy of span 'a' with/to merged spans */
8127
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_a->high,
8128
0
                                               span_a->down) < 0)
8129
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8130
0
                }
8131
0
                else {
8132
                    /* Merge/add lower part of span 'a' with/to merged spans */
8133
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_b->low - 1,
8134
0
                                               span_a->down) < 0)
8135
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8136
8137
                    /* Get merged span tree for overlapped section */
8138
0
                    tmp_spans = H5S__hyper_merge_spans_helper(span_a->down, span_b->down, ndims - 1);
8139
8140
                    /* Merge/add overlapped section to merged spans */
8141
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_a->high, tmp_spans) <
8142
0
                        0)
8143
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8144
8145
                    /* Release merged span tree for overlapped section */
8146
0
                    if (H5S__hyper_free_span_info(tmp_spans) < 0)
8147
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, NULL, "unable to free span info");
8148
0
                }
8149
8150
                /* Check if there is an upper part of span 'b' */
8151
0
                if (span_a->high < span_b->high) {
8152
                    /* Copy upper part of span 'b' as new span 'b' */
8153
8154
                    /* Allocate new span node to append to list */
8155
0
                    if (NULL == (tmp_span = H5S__hyper_new_span(span_a->high + 1, span_b->high, span_b->down,
8156
0
                                                                span_b->next)))
8157
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
8158
8159
                    /* Advance span 'a' */
8160
0
                    H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, NULL);
8161
8162
                    /* Set new span 'b' to tmp_span */
8163
0
                    H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, tmp_span, NULL);
8164
0
                    recover_b = true;
8165
0
                } /* end if */
8166
0
                else {
8167
                    /* Advance both span 'a' & 'b' */
8168
0
                    H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, NULL);
8169
0
                    H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, NULL);
8170
0
                } /* end else */
8171
0
            }     /* end if */
8172
            /* Check if span 'a' overlaps the lower & upper bound */
8173
            /*  of span 'b' */
8174
            /*    AAAAAAAAAAAAAAAAAAAAA              */
8175
            /* <-----------------------------------> */
8176
            /*             BBBBBBBBBB                */
8177
0
            else if (span_a->low < span_b->low && span_a->high > span_b->high) {
8178
                /* Check if span 'a' and span 'b' down spans are equal */
8179
0
                if (H5S__hyper_cmp_spans(span_a->down, span_b->down)) {
8180
                    /* Merge/add copy of lower & middle parts of span 'a' to merged spans */
8181
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_b->high,
8182
0
                                               span_a->down) < 0)
8183
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8184
0
                }
8185
0
                else {
8186
                    /* Merge/add lower part of span 'a' to merged spans */
8187
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_b->low - 1,
8188
0
                                               span_a->down) < 0)
8189
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8190
8191
                    /* Get merged span tree for overlapped section */
8192
0
                    tmp_spans = H5S__hyper_merge_spans_helper(span_a->down, span_b->down, ndims - 1);
8193
8194
                    /* Merge/add overlapped section to merged spans */
8195
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_b->high, tmp_spans) <
8196
0
                        0)
8197
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8198
8199
                    /* Release merged span tree for overlapped section */
8200
0
                    if (H5S__hyper_free_span_info(tmp_spans) < 0)
8201
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, NULL, "unable to free span info");
8202
0
                }
8203
8204
                /* Copy upper part of span 'a' as new span 'a' (remember to free) */
8205
8206
                /* Allocate new span node to append to list */
8207
0
                if (NULL == (tmp_span = H5S__hyper_new_span(span_b->high + 1, span_a->high, span_a->down,
8208
0
                                                            span_a->next)))
8209
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
8210
8211
                /* Set new span 'a' to tmp_span */
8212
0
                H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, tmp_span, NULL);
8213
0
                recover_a = true;
8214
8215
                /* Advance span 'b' */
8216
0
                H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, NULL);
8217
0
            } /* end if */
8218
            /* Check if span 'a' is entirely within span 'b' */
8219
            /*                AAAAA                  */
8220
            /* <-----------------------------------> */
8221
            /*             BBBBBBBBBB                */
8222
0
            else if (span_a->low >= span_b->low && span_a->high <= span_b->high) {
8223
                /* Check if span 'a' and span 'b' down spans are equal */
8224
0
                if (H5S__hyper_cmp_spans(span_a->down, span_b->down)) {
8225
                    /* Merge/add copy of lower & middle parts of span 'b' to merged spans */
8226
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_a->high,
8227
0
                                               span_a->down) < 0)
8228
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8229
0
                }
8230
0
                else {
8231
                    /* Check if there is a lower part of span 'b' */
8232
0
                    if (span_a->low > span_b->low) {
8233
                        /* Merge/add lower part of span 'b' to merged spans */
8234
0
                        if (H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_a->low - 1,
8235
0
                                                   span_b->down) < 0)
8236
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8237
0
                    } /* end if */
8238
0
                    else {
8239
                        /* No lower part of span 'b' , keep going... */
8240
0
                    } /* end else */
8241
8242
                    /* Get merged span tree for overlapped section */
8243
0
                    tmp_spans = H5S__hyper_merge_spans_helper(span_a->down, span_b->down, ndims - 1);
8244
8245
                    /* Merge/add overlapped section to merged spans */
8246
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_a->high, tmp_spans) <
8247
0
                        0)
8248
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8249
8250
                    /* Release merged span tree for overlapped section */
8251
0
                    if (H5S__hyper_free_span_info(tmp_spans) < 0)
8252
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, NULL, "unable to free span info");
8253
0
                }
8254
8255
                /* Check if there is an upper part of span 'b' */
8256
0
                if (span_a->high < span_b->high) {
8257
                    /* Copy upper part of span 'b' as new span 'b' (remember to free) */
8258
8259
                    /* Allocate new span node to append to list */
8260
0
                    if (NULL == (tmp_span = H5S__hyper_new_span(span_a->high + 1, span_b->high, span_b->down,
8261
0
                                                                span_b->next)))
8262
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
8263
8264
                    /* Advance span 'a' */
8265
0
                    H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, NULL);
8266
8267
                    /* Set new span 'b' to tmp_span */
8268
0
                    H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, tmp_span, NULL);
8269
0
                    recover_b = true;
8270
0
                } /* end if */
8271
0
                else {
8272
                    /* Advance both spans */
8273
0
                    H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, NULL);
8274
0
                    H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, NULL);
8275
0
                } /* end else */
8276
0
            }     /* end if */
8277
            /* Check if span 'a' overlaps only the upper bound */
8278
            /*  of span 'b' */
8279
            /*                AAAAAAAAAA             */
8280
            /* <-----------------------------------> */
8281
            /*             BBBBBBBBBB                */
8282
0
            else if ((span_a->low >= span_b->low && span_a->low <= span_b->high) &&
8283
0
                     span_a->high > span_b->high) {
8284
                /* Check if span 'a' and span 'b' down spans are equal */
8285
0
                if (H5S__hyper_cmp_spans(span_a->down, span_b->down)) {
8286
                    /* Merge/add copy of span 'b' to merged spans if so */
8287
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_b->high,
8288
0
                                               span_b->down) < 0)
8289
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8290
0
                }
8291
0
                else {
8292
                    /* Check if there is a lower part of span 'b' */
8293
0
                    if (span_a->low > span_b->low) {
8294
                        /* Merge/add lower part of span 'b' to merged spans */
8295
0
                        if (H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_a->low - 1,
8296
0
                                                   span_b->down) < 0)
8297
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8298
0
                    } /* end if */
8299
0
                    else {
8300
                        /* No lower part of span 'b' , keep going... */
8301
0
                    } /* end else */
8302
8303
                    /* Get merged span tree for overlapped section */
8304
0
                    tmp_spans = H5S__hyper_merge_spans_helper(span_a->down, span_b->down, ndims - 1);
8305
8306
                    /* Merge/add overlapped section to merged spans */
8307
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_b->high, tmp_spans) <
8308
0
                        0)
8309
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8310
8311
                    /* Release merged span tree for overlapped section */
8312
0
                    if (H5S__hyper_free_span_info(tmp_spans) < 0)
8313
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, NULL, "unable to free span info");
8314
0
                }
8315
8316
                /* Copy upper part of span 'a' as new span 'a' */
8317
8318
                /* Allocate new span node to append to list */
8319
0
                if (NULL == (tmp_span = H5S__hyper_new_span(span_b->high + 1, span_a->high, span_a->down,
8320
0
                                                            span_a->next)))
8321
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
8322
8323
                /* Set new span 'a' to tmp_span */
8324
0
                H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, tmp_span, NULL);
8325
0
                recover_a = true;
8326
8327
                /* Advance span 'b' */
8328
0
                H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, NULL);
8329
0
            } /* end if */
8330
            /* Span 'a' must be entirely above span 'b' */
8331
            /*                         AAAAA         */
8332
            /* <-----------------------------------> */
8333
            /*             BBBBBBBBBB                */
8334
0
            else {
8335
                /* Merge/add span 'b' with the merged spans */
8336
0
                if (H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_b->high, span_b->down) < 0)
8337
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8338
8339
                /* Advance span 'b' */
8340
0
                H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, NULL);
8341
0
            } /* end else */
8342
0
        }     /* end while */
8343
8344
        /* Clean up 'a' spans which haven't been added to the list of merged spans */
8345
0
        if (span_a != NULL && span_b == NULL) {
8346
0
            while (span_a != NULL) {
8347
                /* Merge/add all 'a' spans into the merged spans */
8348
0
                if (H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_a->high, span_a->down) < 0)
8349
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8350
8351
                /* Advance to next 'a' span, until all processed */
8352
0
                H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, NULL);
8353
0
            } /* end while */
8354
0
        }     /* end if */
8355
8356
        /* Clean up 'b' spans which haven't been added to the list of merged spans */
8357
0
        if (span_a == NULL && span_b != NULL) {
8358
0
            while (span_b != NULL) {
8359
                /* Merge/add all 'b' spans into the merged spans */
8360
0
                if (H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_b->high, span_b->down) < 0)
8361
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8362
8363
                /* Advance to next 'b' span, until all processed */
8364
0
                H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, NULL);
8365
0
            } /* end while */
8366
0
        }     /* end if */
8367
0
    }         /* end else */
8368
8369
    /* Set return value */
8370
0
    ret_value = merged_spans;
8371
8372
0
done:
8373
0
    if (ret_value == NULL)
8374
0
        if (merged_spans)
8375
0
            if (H5S__hyper_free_span_info(merged_spans) < 0)
8376
0
                HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, NULL, "unable to free span info");
8377
8378
0
    FUNC_LEAVE_NOAPI(ret_value)
8379
0
} /* end H5S__hyper_merge_spans_helper() */
8380
8381
/*--------------------------------------------------------------------------
8382
 NAME
8383
    H5S__hyper_merge_spans
8384
 PURPOSE
8385
    Merge new hyperslab spans to existing hyperslab selection
8386
 USAGE
8387
    herr_t H5S__hyper_merge_spans(space, new_spans, can_own)
8388
        H5S_t *space;             IN: Dataspace to add new spans to hyperslab
8389
                                        selection.
8390
        H5S_hyper_span_t *new_spans;    IN: Span tree of new spans to add to
8391
                                            hyperslab selection
8392
 RETURNS
8393
    non-negative on success, negative on failure
8394
 DESCRIPTION
8395
    Add a set of hyperslab spans to an existing hyperslab selection.
8396
 GLOBAL VARIABLES
8397
 COMMENTS, BUGS, ASSUMPTIONS
8398
 EXAMPLES
8399
 REVISION LOG
8400
--------------------------------------------------------------------------*/
8401
static herr_t
8402
H5S__hyper_merge_spans(H5S_t *space, H5S_hyper_span_info_t *new_spans)
8403
0
{
8404
0
    herr_t ret_value = SUCCEED; /* Return value */
8405
8406
0
    FUNC_ENTER_PACKAGE
8407
8408
    /* Sanity checks */
8409
0
    assert(space);
8410
0
    assert(new_spans);
8411
8412
    /* If this is the first span tree in the hyperslab selection, just use it */
8413
0
    if (space->select.sel_info.hslab->span_lst == NULL) {
8414
0
        space->select.sel_info.hslab->span_lst = new_spans;
8415
0
        space->select.sel_info.hslab->span_lst->count++;
8416
0
    } /* end if */
8417
0
    else {
8418
0
        H5S_hyper_span_info_t *merged_spans;
8419
8420
        /* Get the merged spans */
8421
0
        if (NULL == (merged_spans = H5S__hyper_merge_spans_helper(space->select.sel_info.hslab->span_lst,
8422
0
                                                                  new_spans, space->extent.rank)))
8423
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTMERGE, FAIL, "can't merge hyperslab spans");
8424
8425
        /* Free the previous spans */
8426
0
        if (H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst) < 0)
8427
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
8428
8429
        /* Point to the new merged spans */
8430
0
        space->select.sel_info.hslab->span_lst = merged_spans;
8431
0
    } /* end else */
8432
8433
0
done:
8434
0
    FUNC_LEAVE_NOAPI(ret_value)
8435
0
} /* end H5S__hyper_merge_spans() */
8436
8437
/*--------------------------------------------------------------------------
8438
 NAME
8439
    H5S__hyper_spans_nelem_helper
8440
 PURPOSE
8441
    Count the number of elements in a span tree
8442
 USAGE
8443
    hsize_t H5S__hyper_spans_nelem_helper(spans, op_info_i, op_gen)
8444
        const H5S_hyper_span_info_t *spans; IN: Hyperslan span tree to count elements of
8445
        unsigned op_info_i;             IN: Index of op info to use
8446
        uint64_t op_gen;                IN: Operation generation
8447
 RETURNS
8448
    Number of elements in span tree on success; negative on failure
8449
 DESCRIPTION
8450
    Counts the number of elements described by the spans in a span tree.
8451
 GLOBAL VARIABLES
8452
 COMMENTS, BUGS, ASSUMPTIONS
8453
 EXAMPLES
8454
 REVISION LOG
8455
--------------------------------------------------------------------------*/
8456
static hsize_t
8457
H5S__hyper_spans_nelem_helper(H5S_hyper_span_info_t *spans, unsigned op_info_i, uint64_t op_gen)
8458
0
{
8459
0
    hsize_t ret_value = 0; /* Return value */
8460
8461
0
    FUNC_ENTER_PACKAGE_NOERR
8462
8463
    /* Sanity check */
8464
0
    assert(spans);
8465
8466
    /* Check if the span tree was already counted */
8467
0
    if (spans->op_info[op_info_i].op_gen == op_gen)
8468
        /* Just return the # of elements in the already counted span tree */
8469
0
        ret_value = spans->op_info[op_info_i].u.nelmts;
8470
0
    else {                            /* Count the number of elements in the span tree */
8471
0
        const H5S_hyper_span_t *span; /* Hyperslab span */
8472
8473
0
        span = spans->head;
8474
0
        if (NULL == span->down) {
8475
0
            while (span != NULL) {
8476
                /* Compute # of elements covered */
8477
0
                ret_value += (span->high - span->low) + 1;
8478
8479
                /* Advance to next span */
8480
0
                span = span->next;
8481
0
            } /* end while */
8482
0
        }     /* end if */
8483
0
        else {
8484
0
            while (span != NULL) {
8485
0
                hsize_t nelmts; /* # of elements covered by current span */
8486
8487
                /* Compute # of elements covered */
8488
0
                nelmts = (span->high - span->low) + 1;
8489
8490
                /* Multiply the size of this span by the total down span elements */
8491
0
                ret_value += nelmts * H5S__hyper_spans_nelem_helper(span->down, op_info_i, op_gen);
8492
8493
                /* Advance to next span */
8494
0
                span = span->next;
8495
0
            } /* end while */
8496
0
        }     /* end else */
8497
8498
        /* Set the operation generation for this span tree, to avoid re-computing */
8499
0
        spans->op_info[op_info_i].op_gen = op_gen;
8500
8501
        /* Hold a copy of the # of elements */
8502
0
        spans->op_info[op_info_i].u.nelmts = ret_value;
8503
0
    } /* end else */
8504
8505
0
    FUNC_LEAVE_NOAPI(ret_value)
8506
0
} /* end H5S__hyper_spans_nelem_helper() */
8507
8508
/*--------------------------------------------------------------------------
8509
 NAME
8510
    H5S__hyper_spans_nelem
8511
 PURPOSE
8512
    Count the number of elements in a span tree
8513
 USAGE
8514
    hsize_t H5S__hyper_spans_nelem(spans)
8515
        const H5S_hyper_span_info_t *spans; IN: Hyperslan span tree to count elements of
8516
 RETURNS
8517
    Number of elements in span tree on success; negative on failure
8518
 DESCRIPTION
8519
    Counts the number of elements described by the spans in a span tree.
8520
 GLOBAL VARIABLES
8521
 COMMENTS, BUGS, ASSUMPTIONS
8522
 EXAMPLES
8523
 REVISION LOG
8524
--------------------------------------------------------------------------*/
8525
static hsize_t
8526
H5S__hyper_spans_nelem(H5S_hyper_span_info_t *spans)
8527
0
{
8528
0
    uint64_t op_gen;        /* Operation generation value */
8529
0
    hsize_t  ret_value = 0; /* Return value */
8530
8531
0
    FUNC_ENTER_PACKAGE_NOERR
8532
8533
    /* Sanity check */
8534
0
    assert(spans);
8535
8536
    /* Acquire an operation generation value for this operation */
8537
0
    op_gen = H5S__hyper_get_op_gen();
8538
8539
    /* Count the number of elements in the span tree */
8540
    /* Always use op_info[0] since we own this op_info, so there can be no
8541
     * simultaneous operations */
8542
0
    ret_value = H5S__hyper_spans_nelem_helper(spans, 0, op_gen);
8543
8544
0
    FUNC_LEAVE_NOAPI(ret_value)
8545
0
} /* end H5S__hyper_spans_nelem() */
8546
8547
/*--------------------------------------------------------------------------
8548
 NAME
8549
    H5S__hyper_add_disjoint_spans
8550
 PURPOSE
8551
    Add new hyperslab spans to existing hyperslab selection in the case the
8552
    new hyperslab spans don't overlap with the existing hyperslab selection
8553
 USAGE
8554
    herr_t H5S__hyper_add_disjoint_spans(space, new_spans)
8555
        H5S_t *space;             IN: Dataspace to add new spans to hyperslab
8556
                                        selection.
8557
        H5S_hyper_span_t *new_spans;    IN: Span tree of new spans to add to
8558
                                            hyperslab selection
8559
 RETURNS
8560
    Non-negative on success, negative on failure
8561
 DESCRIPTION
8562
    Add a set of hyperslab spans to an existing hyperslab selection.  The
8563
    new spans are required not to overlap with the existing spans in the
8564
    dataspace's current hyperslab selection in terms of bound box.
8565
 GLOBAL VARIABLES
8566
 COMMENTS, BUGS, ASSUMPTIONS
8567
 EXAMPLES
8568
 REVISION LOG
8569
--------------------------------------------------------------------------*/
8570
static herr_t
8571
H5S__hyper_add_disjoint_spans(H5S_t *space, H5S_hyper_span_info_t *new_spans)
8572
0
{
8573
0
    herr_t ret_value = SUCCEED; /* Return value */
8574
8575
0
    FUNC_ENTER_PACKAGE
8576
8577
    /* Check args */
8578
0
    assert(space);
8579
0
    assert(new_spans);
8580
8581
    /* Update the number of elements in the selection */
8582
0
    space->select.num_elem += H5S__hyper_spans_nelem(new_spans);
8583
8584
    /* Add the new spans to the existing selection in the dataspace */
8585
0
    if (H5S__hyper_merge_spans(space, new_spans) < 0)
8586
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't merge hyperslabs");
8587
8588
    /* Free the memory space for new spans */
8589
0
    if (H5S__hyper_free_span_info(new_spans) < 0)
8590
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
8591
8592
0
done:
8593
0
    FUNC_LEAVE_NOAPI(ret_value)
8594
0
} /* end H5S__hyper_add_disjoint_spans */
8595
8596
/*--------------------------------------------------------------------------
8597
 NAME
8598
    H5S__hyper_make_spans
8599
 PURPOSE
8600
    Create a span tree
8601
 USAGE
8602
    H5S_hyper_span_t *H5S__hyper_make_spans(rank, start, stride, count, block)
8603
        unsigned rank;          IN: # of dimensions of the space
8604
        const hsize_t *start;   IN: Starting location of the hyperslabs
8605
        const hsize_t *stride;  IN: Stride from the beginning of one block to
8606
                                        the next
8607
        const hsize_t *count;   IN: Number of blocks
8608
        const hsize_t *block;   IN: Size of hyperslab block
8609
 RETURNS
8610
    Pointer to new span tree on success, NULL on failure
8611
 DESCRIPTION
8612
    Generates a new span tree for the hyperslab parameters specified.
8613
    Each span tree has a list of the elements spanned in each dimension, with
8614
    each span node containing a pointer to the list of spans in the next
8615
    dimension down.
8616
 GLOBAL VARIABLES
8617
 COMMENTS, BUGS, ASSUMPTIONS
8618
 EXAMPLES
8619
 REVISION LOG
8620
--------------------------------------------------------------------------*/
8621
static H5S_hyper_span_info_t *
8622
H5S__hyper_make_spans(unsigned rank, const hsize_t *start, const hsize_t *stride, const hsize_t *count,
8623
                      const hsize_t *block)
8624
0
{
8625
0
    H5S_hyper_span_info_t *down = NULL;      /* Pointer to spans in next dimension down */
8626
0
    H5S_hyper_span_t      *last_span;        /* Current position in hyperslab span list */
8627
0
    H5S_hyper_span_t      *head = NULL;      /* Head of new hyperslab span list */
8628
0
    int                    i;                /* Counters */
8629
0
    H5S_hyper_span_info_t *ret_value = NULL; /* Return value */
8630
8631
0
    FUNC_ENTER_PACKAGE
8632
8633
    /* Check args */
8634
0
    assert(start);
8635
0
    assert(stride);
8636
0
    assert(count);
8637
0
    assert(block);
8638
8639
0
    if (rank == 0)
8640
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, NULL, "dataspace has invalid extent");
8641
8642
    /* Start creating spans in fastest changing dimension */
8643
0
    for (i = (int)(rank - 1); i >= 0; i--) {
8644
0
        hsize_t  curr_low, curr_high; /* Current low & high values */
8645
0
        hsize_t  dim_stride;          /* Current dim's stride */
8646
0
        unsigned u;                   /* Local index variable */
8647
8648
        /* Sanity check */
8649
0
        if (0 == count[i])
8650
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, NULL, "count == 0 is invalid");
8651
8652
        /* Start a new list in this dimension */
8653
0
        head      = NULL;
8654
0
        last_span = NULL;
8655
8656
        /* Generate all the span segments for this dimension */
8657
0
        curr_low   = start[i];
8658
0
        curr_high  = start[i] + (block[i] - 1);
8659
0
        dim_stride = stride[i];
8660
0
        for (u = 0; u < count[i]; u++, curr_low += dim_stride, curr_high += dim_stride) {
8661
0
            H5S_hyper_span_t *span; /* New hyperslab span */
8662
8663
            /* Allocate a span node */
8664
0
            if (NULL == (span = H5FL_MALLOC(H5S_hyper_span_t)))
8665
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
8666
8667
            /* Set the span's basic information */
8668
0
            span->low  = curr_low;
8669
0
            span->high = curr_high;
8670
0
            span->next = NULL;
8671
8672
            /* Set the information for the next dimension down's spans */
8673
            /* (Will be NULL for fastest changing dimension) */
8674
0
            span->down = down;
8675
8676
            /* Append to the list of spans in this dimension */
8677
0
            if (head == NULL)
8678
0
                head = span;
8679
0
            else
8680
0
                last_span->next = span;
8681
8682
            /* Move current pointer */
8683
0
            last_span = span;
8684
0
        } /* end for */
8685
8686
        /* Increment ref. count of shared span */
8687
0
        if (down != NULL)
8688
0
            down->count = (unsigned)count[i];
8689
8690
        /* Allocate a span info node */
8691
0
        if (NULL == (down = H5S__hyper_new_span_info(rank)))
8692
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
8693
8694
        /* Keep the pointer to the next dimension down's completed list */
8695
0
        down->head = head;
8696
8697
        /* Keep the tail pointer to the next dimension down's completed list */
8698
0
        down->tail = last_span;
8699
8700
        /* Set the low & high bounds for this dimension */
8701
0
        down->low_bounds[0]  = down->head->low;
8702
0
        down->high_bounds[0] = down->tail->high;
8703
8704
        /* Copy bounds from lower dimensions */
8705
        /* (head & tail pointers share lower dimensions, so using either is OK) */
8706
0
        if (head->down) {
8707
0
            H5MM_memcpy(&down->low_bounds[1], &head->down->low_bounds[0],
8708
0
                        sizeof(hsize_t) * ((rank - 1) - (unsigned)i));
8709
0
            H5MM_memcpy(&down->high_bounds[1], &head->down->high_bounds[0],
8710
0
                        sizeof(hsize_t) * ((rank - 1) - (unsigned)i));
8711
0
        } /* end if */
8712
0
    }     /* end for */
8713
8714
    /* Indicate that there is a pointer to this tree */
8715
0
    if (down)
8716
0
        down->count = 1;
8717
8718
    /* Success!  Return the head of the list in the slowest changing dimension */
8719
0
    ret_value = down;
8720
8721
0
done:
8722
    /* cleanup if error (ret_value will be NULL) */
8723
0
    if (!ret_value) {
8724
0
        if (head || down) {
8725
0
            if (head && down)
8726
0
                if (down->head != head)
8727
0
                    down = NULL;
8728
8729
0
            do {
8730
0
                if (down) {
8731
0
                    head = down->head;
8732
0
                    down = (H5S_hyper_span_info_t *)H5FL_ARR_FREE(hbounds_t, down);
8733
0
                } /* end if */
8734
0
                down = head->down;
8735
8736
0
                while (head) {
8737
0
                    last_span = head->next;
8738
0
                    head      = H5FL_FREE(H5S_hyper_span_t, head);
8739
0
                    head      = last_span;
8740
0
                } /* end while */
8741
0
            } while (down);
8742
0
        } /* end if */
8743
0
    }     /* end if */
8744
8745
0
    FUNC_LEAVE_NOAPI(ret_value)
8746
0
} /* end H5S__hyper_make_spans() */
8747
8748
/*--------------------------------------------------------------------------
8749
 NAME
8750
    H5S__hyper_update_diminfo
8751
 PURPOSE
8752
    Attempt to update optimized hyperslab information quickly.  (It can be
8753
    recovered with regular selection).  If this algorithm cannot determine
8754
    the optimized dimension info quickly, this function will simply mark it
8755
    as invalid and unknown if it can be built (H5S_DIMINFO_VALID_NO), so
8756
    H5S__hyper_rebuild can be run later to determine for sure.
8757
 USAGE
8758
    herr_t H5S__hyper_update_diminfo(space, op, new_hyper_diminfo)
8759
        H5S_t *space;       IN: Dataspace to check
8760
        H5S_seloper_t op;   IN: The operation being performed on the
8761
                                selection
8762
        const H5S_hyper_dim_t new_hyper_diminfo; IN: The new selection that
8763
                                                     is being combined with
8764
                                                     the current
8765
 RETURNS
8766
    >=0 on success, <0 on failure
8767
 DESCRIPTION
8768
    Examine the span tree for a hyperslab selection and rebuild
8769
    the start/stride/count/block information for the selection, if possible.
8770
8771
 GLOBAL VARIABLES
8772
 COMMENTS, BUGS, ASSUMPTIONS
8773
 EXAMPLES
8774
 REVISION LOG
8775
--------------------------------------------------------------------------*/
8776
static herr_t
8777
H5S__hyper_update_diminfo(H5S_t *space, H5S_seloper_t op, const H5S_hyper_dim_t *new_hyper_diminfo)
8778
0
{
8779
0
    herr_t ret_value = SUCCEED; /* Return value */
8780
8781
0
    FUNC_ENTER_PACKAGE_NOERR
8782
8783
    /* Check args */
8784
0
    assert(space);
8785
0
    assert(new_hyper_diminfo);
8786
8787
    /* Check for conditions that prevent us from using the fast algorithm here */
8788
    /* (and instead require H5S__hyper_rebuild) */
8789
0
    if (!((op == H5S_SELECT_OR) || (op == H5S_SELECT_XOR)) ||
8790
0
        space->select.sel_info.hslab->diminfo_valid != H5S_DIMINFO_VALID_YES ||
8791
0
        !space->select.sel_info.hslab->span_lst->head)
8792
0
        space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
8793
0
    else {
8794
0
        H5S_hyper_dim_t tmp_diminfo[H5S_MAX_RANK]; /* Temporary dimension info */
8795
0
        bool            found_nonidentical_dim = false;
8796
0
        unsigned        curr_dim;
8797
8798
        /* Copy current diminfo.opt values */
8799
0
        H5MM_memcpy(tmp_diminfo, space->select.sel_info.hslab->diminfo.opt, sizeof(tmp_diminfo));
8800
8801
        /* Loop over dimensions */
8802
0
        for (curr_dim = 0; curr_dim < space->extent.rank; curr_dim++) {
8803
            /* Check for this being identical */
8804
0
            if ((tmp_diminfo[curr_dim].start != new_hyper_diminfo[curr_dim].start) ||
8805
0
                (tmp_diminfo[curr_dim].stride != new_hyper_diminfo[curr_dim].stride) ||
8806
0
                (tmp_diminfo[curr_dim].count != new_hyper_diminfo[curr_dim].count) ||
8807
0
                (tmp_diminfo[curr_dim].block != new_hyper_diminfo[curr_dim].block)) {
8808
0
                hsize_t high_start, high_count,
8809
0
                    high_block; /* The start, count & block values for the higher block */
8810
8811
                /* Dimension is not identical */
8812
                /* Check if we already found a nonidentical dim - only one is
8813
                 * allowed */
8814
0
                if (found_nonidentical_dim) {
8815
0
                    space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
8816
0
                    break;
8817
0
                } /* end if */
8818
8819
                /* Check that strides are the same, or count is 1 for one of the
8820
                 * slabs */
8821
0
                if ((tmp_diminfo[curr_dim].stride != new_hyper_diminfo[curr_dim].stride) &&
8822
0
                    (tmp_diminfo[curr_dim].count > 1) && (new_hyper_diminfo[curr_dim].count > 1)) {
8823
0
                    space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
8824
0
                    break;
8825
0
                } /* end if */
8826
8827
                /* Patch tmp_diminfo.stride if its count is 1 */
8828
0
                if ((tmp_diminfo[curr_dim].count == 1) && (new_hyper_diminfo[curr_dim].count > 1))
8829
0
                    tmp_diminfo[curr_dim].stride = new_hyper_diminfo[curr_dim].stride;
8830
8831
                /* Determine lowest start, and set tmp_diminfo.start, count and
8832
                 *  block to use the lowest, and high_start, high_count and
8833
                 *  high_block to use the highest
8834
                 */
8835
0
                if (tmp_diminfo[curr_dim].start < new_hyper_diminfo[curr_dim].start) {
8836
0
                    high_start = new_hyper_diminfo[curr_dim].start;
8837
0
                    high_count = new_hyper_diminfo[curr_dim].count;
8838
0
                    high_block = new_hyper_diminfo[curr_dim].block;
8839
0
                } /* end if */
8840
0
                else {
8841
0
                    high_start                  = tmp_diminfo[curr_dim].start;
8842
0
                    tmp_diminfo[curr_dim].start = new_hyper_diminfo[curr_dim].start;
8843
0
                    high_count                  = tmp_diminfo[curr_dim].count;
8844
0
                    tmp_diminfo[curr_dim].count = new_hyper_diminfo[curr_dim].count;
8845
0
                    high_block                  = tmp_diminfo[curr_dim].block;
8846
0
                    tmp_diminfo[curr_dim].block = new_hyper_diminfo[curr_dim].block;
8847
0
                } /* end else */
8848
8849
                /* If count is 1 for both slabs, take different actions */
8850
0
                if ((tmp_diminfo[curr_dim].count == 1) && (high_count == 1)) {
8851
                    /* Check for overlap */
8852
0
                    if ((tmp_diminfo[curr_dim].start + tmp_diminfo[curr_dim].block) > high_start) {
8853
                        /* Check operation type */
8854
0
                        if (op == H5S_SELECT_OR)
8855
                            /* Merge blocks */
8856
0
                            tmp_diminfo[curr_dim].block =
8857
0
                                ((high_start + high_block) >=
8858
0
                                 (tmp_diminfo[curr_dim].start + tmp_diminfo[curr_dim].block))
8859
0
                                    ? (high_start + high_block - tmp_diminfo[curr_dim].start)
8860
0
                                    : tmp_diminfo[curr_dim].block;
8861
0
                        else {
8862
                            /* Block values must be the same */
8863
0
                            if (tmp_diminfo[curr_dim].block != high_block) {
8864
0
                                space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
8865
0
                                break;
8866
0
                            } /* end if */
8867
8868
                            /* XOR - overlap creates 2 blocks */
8869
0
                            tmp_diminfo[curr_dim].stride = high_block;
8870
0
                            tmp_diminfo[curr_dim].count  = 2;
8871
0
                            tmp_diminfo[curr_dim].block  = high_start - tmp_diminfo[curr_dim].start;
8872
0
                        } /* end else */
8873
0
                    }     /* end if */
8874
0
                    else if ((tmp_diminfo[curr_dim].start + tmp_diminfo[curr_dim].block) == high_start)
8875
                        /* Blocks border, merge them */
8876
0
                        tmp_diminfo[curr_dim].block += high_block;
8877
0
                    else {
8878
                        /* Distinct blocks */
8879
                        /* Block values must be the same */
8880
0
                        if (tmp_diminfo[curr_dim].block != high_block) {
8881
0
                            space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
8882
0
                            break;
8883
0
                        } /* end if */
8884
8885
                        /* Create strided selection */
8886
0
                        tmp_diminfo[curr_dim].stride = high_start - tmp_diminfo[curr_dim].start;
8887
0
                        tmp_diminfo[curr_dim].count  = 2;
8888
0
                    } /* end else */
8889
0
                }     /* end if */
8890
0
                else {
8891
                    /* Check if block values are the same */
8892
0
                    if (tmp_diminfo[curr_dim].block != high_block) {
8893
0
                        space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
8894
0
                        break;
8895
0
                    } /* end if */
8896
8897
                    /* Check phase of strides */
8898
0
                    if ((tmp_diminfo[curr_dim].start % tmp_diminfo[curr_dim].stride) !=
8899
0
                        (high_start % tmp_diminfo[curr_dim].stride)) {
8900
0
                        space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
8901
0
                        break;
8902
0
                    } /* end if */
8903
8904
                    /* Check operation type */
8905
0
                    if (op == H5S_SELECT_OR) {
8906
                        /* Make sure the slabs border or overlap */
8907
0
                        if (high_start > (tmp_diminfo[curr_dim].start +
8908
0
                                          (tmp_diminfo[curr_dim].count * tmp_diminfo[curr_dim].stride))) {
8909
0
                            space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
8910
0
                            break;
8911
0
                        } /* end if */
8912
0
                    }     /* end if */
8913
0
                    else
8914
                        /* XOR: Make sure the slabs border */
8915
0
                        if (high_start != (tmp_diminfo[curr_dim].start +
8916
0
                                           (tmp_diminfo[curr_dim].count * tmp_diminfo[curr_dim].stride))) {
8917
0
                            space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
8918
0
                            break;
8919
0
                        } /* end if */
8920
8921
                    /* Set count for combined selection */
8922
0
                    tmp_diminfo[curr_dim].count =
8923
0
                        ((high_start - tmp_diminfo[curr_dim].start) / tmp_diminfo[curr_dim].stride) +
8924
0
                        high_count;
8925
0
                } /* end else */
8926
8927
                /* Indicate that we found a nonidentical dim */
8928
0
                found_nonidentical_dim = true;
8929
0
            } /* end if */
8930
0
        }     /* end for */
8931
8932
        /* Check if we succeeded, if so, set the new diminfo values */
8933
0
        if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES)
8934
0
            for (curr_dim = 0; curr_dim < space->extent.rank; curr_dim++) {
8935
0
                hsize_t tmp_high_bound;
8936
8937
                /* Set the new diminfo values */
8938
0
                space->select.sel_info.hslab->diminfo.app[curr_dim].start =
8939
0
                    space->select.sel_info.hslab->diminfo.opt[curr_dim].start = tmp_diminfo[curr_dim].start;
8940
0
                assert(tmp_diminfo[curr_dim].stride > 0);
8941
0
                space->select.sel_info.hslab->diminfo.app[curr_dim].stride =
8942
0
                    space->select.sel_info.hslab->diminfo.opt[curr_dim].stride = tmp_diminfo[curr_dim].stride;
8943
0
                assert(tmp_diminfo[curr_dim].count > 0);
8944
0
                space->select.sel_info.hslab->diminfo.app[curr_dim].count =
8945
0
                    space->select.sel_info.hslab->diminfo.opt[curr_dim].count = tmp_diminfo[curr_dim].count;
8946
0
                assert(tmp_diminfo[curr_dim].block > 0);
8947
0
                space->select.sel_info.hslab->diminfo.app[curr_dim].block =
8948
0
                    space->select.sel_info.hslab->diminfo.opt[curr_dim].block = tmp_diminfo[curr_dim].block;
8949
8950
                /* Check for updating the low & high bounds */
8951
0
                if (tmp_diminfo[curr_dim].start < space->select.sel_info.hslab->diminfo.low_bounds[curr_dim])
8952
0
                    space->select.sel_info.hslab->diminfo.low_bounds[curr_dim] = tmp_diminfo[curr_dim].start;
8953
0
                tmp_high_bound = tmp_diminfo[curr_dim].start + (tmp_diminfo[curr_dim].block - 1) +
8954
0
                                 (tmp_diminfo[curr_dim].stride * (tmp_diminfo[curr_dim].count - 1));
8955
0
                if (tmp_high_bound > space->select.sel_info.hslab->diminfo.low_bounds[curr_dim])
8956
0
                    space->select.sel_info.hslab->diminfo.high_bounds[curr_dim] = tmp_high_bound;
8957
0
            } /* end for */
8958
0
    }         /* end else */
8959
8960
0
    FUNC_LEAVE_NOAPI(ret_value)
8961
0
} /* end H5S__hyper_update_diminfo() */
8962
8963
/*--------------------------------------------------------------------------
8964
 NAME
8965
    H5S__hyper_rebuild_helper
8966
 PURPOSE
8967
    Helper routine to rebuild optimized hyperslab information if possible.
8968
    (It can be recovered with regular selection)
8969
 USAGE
8970
    herr_t H5S__hyper_rebuild_helper(space)
8971
        const H5S_hyper_span_t *spans;  IN: Portion of span tree to check
8972
        H5S_hyper_dim_t span_slab_info[]; OUT: Rebuilt section of hyperslab description
8973
 RETURNS
8974
    true/false for hyperslab selection rebuilt
8975
 DESCRIPTION
8976
    Examine the span tree for a hyperslab selection and rebuild
8977
    the start/stride/count/block information for the selection, if possible.
8978
 GLOBAL VARIABLES
8979
 COMMENTS, BUGS, ASSUMPTIONS
8980
    To be able to recover the optimized information, the span tree must conform
8981
    to span tree able to be generated from a single H5S_SELECT_SET operation.
8982
 EXAMPLES
8983
 REVISION LOG
8984
    KY, 2005/9/22
8985
--------------------------------------------------------------------------*/
8986
static bool
8987
H5S__hyper_rebuild_helper(const H5S_hyper_span_info_t *spans, H5S_hyper_dim_t span_slab_info[])
8988
0
{
8989
0
    const H5S_hyper_span_t *span;             /* Hyperslab span */
8990
0
    const H5S_hyper_span_t *prev_span;        /* Previous span in list */
8991
0
    hsize_t                 start;            /* Starting element for this dimension */
8992
0
    hsize_t                 stride;           /* Stride for this dimension */
8993
0
    hsize_t                 block;            /* Block size for this dimension */
8994
0
    hsize_t                 prev_low;         /* Low bound for previous span */
8995
0
    size_t                  spancount;        /* Number of spans encountered in this dimension */
8996
0
    bool                    ret_value = true; /* Return value */
8997
8998
0
    FUNC_ENTER_PACKAGE_NOERR
8999
9000
    /* Sanity check */
9001
0
    assert(spans);
9002
9003
    /* Initialization */
9004
0
    span      = spans->head;
9005
0
    stride    = 1;
9006
0
    prev_low  = 0;
9007
0
    spancount = 0;
9008
9009
    /* Get "canonical" down span information */
9010
0
    if (span->down)
9011
        /* Go to the next down span and check whether the selection can be rebuilt */
9012
0
        if (!H5S__hyper_rebuild_helper(span->down, &span_slab_info[1]))
9013
0
            HGOTO_DONE(false);
9014
9015
    /* Assign the initial starting point & block size for this dimension */
9016
0
    start = span->low;
9017
0
    block = (span->high - span->low) + 1;
9018
9019
    /* Loop the spans */
9020
0
    prev_span = NULL;
9021
0
    while (span) {
9022
0
        if (spancount > 0) {
9023
0
            hsize_t curr_stride; /* Current stride from previous span */
9024
0
            hsize_t curr_block;  /* Block size of current span */
9025
9026
            /* Sanity check */
9027
0
            assert(prev_span);
9028
9029
            /* Check that down spans match current slab info */
9030
            /* (Can skip check if previous span's down pointer is same as current one) */
9031
0
            if (span->down && prev_span->down != span->down)
9032
0
                if (!H5S__hyper_cmp_spans(span->down, prev_span->down))
9033
0
                    HGOTO_DONE(false);
9034
9035
            /* Obtain values for stride and block */
9036
0
            curr_stride = span->low - prev_low;
9037
0
            curr_block  = (span->high - span->low) + 1;
9038
9039
            /* Compare stride and block for this span.  To compare stride,
9040
             * three spans are needed.  Account for the first two spans.
9041
             */
9042
0
            if (curr_block != block)
9043
0
                HGOTO_DONE(false);
9044
0
            if (spancount > 1) {
9045
0
                if (stride != curr_stride)
9046
0
                    HGOTO_DONE(false);
9047
0
            } /* end if */
9048
0
            else
9049
0
                stride = curr_stride;
9050
0
        } /* end if */
9051
9052
        /* Keep current starting point */
9053
0
        prev_low = span->low;
9054
9055
        /* Advance to next span */
9056
0
        prev_span = span;
9057
0
        span      = span->next;
9058
0
        spancount++;
9059
0
    } /* end while */
9060
9061
    /* Save the span information. */
9062
0
    span_slab_info[0].start  = start;
9063
0
    span_slab_info[0].count  = spancount;
9064
0
    span_slab_info[0].block  = block;
9065
0
    span_slab_info[0].stride = stride;
9066
9067
0
done:
9068
0
    FUNC_LEAVE_NOAPI(ret_value)
9069
0
} /* end H5S__hyper_rebuild_helper() */
9070
9071
/*--------------------------------------------------------------------------
9072
 NAME
9073
    H5S__hyper_rebuild
9074
 PURPOSE
9075
    Rebuild optimized hyperslab information if possible.
9076
    (It can be recovered with regular selection)
9077
 USAGE
9078
    void H5S__hyper_rebuild(space)
9079
        H5S_t *space;     IN: Dataspace to check
9080
 RETURNS
9081
    None
9082
 DESCRIPTION
9083
    Examine the span tree for a hyperslab selection and rebuild a regular
9084
    start/stride/count/block hyperslab selection, if possible.
9085
 GLOBAL VARIABLES
9086
 COMMENTS, BUGS, ASSUMPTIONS
9087
    To be able to recover the optimized information, the span tree must conform
9088
    to span tree able to be generated from a single H5S_SELECT_SET operation.
9089
 EXAMPLES
9090
 REVISION LOG
9091
--------------------------------------------------------------------------*/
9092
void
9093
H5S__hyper_rebuild(H5S_t *space)
9094
0
{
9095
0
    H5S_hyper_dim_t rebuilt_slab_info[H5S_MAX_RANK];
9096
9097
0
    FUNC_ENTER_PACKAGE_NOERR
9098
9099
    /* Check args */
9100
0
    assert(space);
9101
0
    assert(space->select.sel_info.hslab->span_lst);
9102
9103
    /* Check whether the slab can be rebuilt */
9104
    /* (Only regular selection can be rebuilt. If yes, fill in correct values) */
9105
0
    if (false == H5S__hyper_rebuild_helper(space->select.sel_info.hslab->span_lst, rebuilt_slab_info))
9106
0
        space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_IMPOSSIBLE;
9107
0
    else {
9108
        /* Set the dimension info & bounds for the dataspace, from the rebuilt info */
9109
0
        H5MM_memcpy(space->select.sel_info.hslab->diminfo.app, rebuilt_slab_info, sizeof(rebuilt_slab_info));
9110
0
        H5MM_memcpy(space->select.sel_info.hslab->diminfo.opt, rebuilt_slab_info, sizeof(rebuilt_slab_info));
9111
0
        H5MM_memcpy(space->select.sel_info.hslab->diminfo.low_bounds,
9112
0
                    space->select.sel_info.hslab->span_lst->low_bounds, sizeof(hsize_t) * space->extent.rank);
9113
0
        H5MM_memcpy(space->select.sel_info.hslab->diminfo.high_bounds,
9114
0
                    space->select.sel_info.hslab->span_lst->high_bounds,
9115
0
                    sizeof(hsize_t) * space->extent.rank);
9116
9117
0
        space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_YES;
9118
0
    } /* end else */
9119
9120
0
    FUNC_LEAVE_NOAPI_VOID
9121
0
} /* end H5S__hyper_rebuild() */
9122
9123
/*--------------------------------------------------------------------------
9124
 NAME
9125
    H5S__hyper_generate_spans
9126
 PURPOSE
9127
    Create span tree for a regular hyperslab selection
9128
 USAGE
9129
    herr_t H5S__hyper_generate_spans(space)
9130
        H5S_t *space;           IN/OUT: Pointer to dataspace
9131
 RETURNS
9132
    Non-negative on success, negative on failure
9133
 DESCRIPTION
9134
    Create a span tree representation of a regular hyperslab selection and
9135
    add it to the information for the hyperslab selection.
9136
 GLOBAL VARIABLES
9137
 COMMENTS, BUGS, ASSUMPTIONS
9138
 EXAMPLES
9139
 REVISION LOG
9140
--------------------------------------------------------------------------*/
9141
static herr_t
9142
H5S__hyper_generate_spans(H5S_t *space)
9143
0
{
9144
0
    hsize_t  tmp_start[H5S_MAX_RANK];  /* Temporary start information */
9145
0
    hsize_t  tmp_stride[H5S_MAX_RANK]; /* Temporary stride information */
9146
0
    hsize_t  tmp_count[H5S_MAX_RANK];  /* Temporary count information */
9147
0
    hsize_t  tmp_block[H5S_MAX_RANK];  /* Temporary block information */
9148
0
    unsigned u;                        /* Local index variable */
9149
0
    herr_t   ret_value = SUCCEED;      /* Return value */
9150
9151
0
    FUNC_ENTER_PACKAGE
9152
9153
0
    assert(space);
9154
0
    assert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS);
9155
9156
    /* Get the diminfo */
9157
0
    for (u = 0; u < space->extent.rank; u++) {
9158
        /* Check for unlimited dimension and return error */
9159
        /* These should be able to be converted to assertions once everything
9160
         * that calls this function checks for unlimited selections first
9161
         * (especially the new hyperslab API)  -NAF */
9162
0
        if (space->select.sel_info.hslab->diminfo.opt[u].count == H5S_UNLIMITED)
9163
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "can't generate spans with unlimited count");
9164
0
        if (space->select.sel_info.hslab->diminfo.opt[u].block == H5S_UNLIMITED)
9165
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "can't generate spans with unlimited block");
9166
9167
0
        tmp_start[u]  = space->select.sel_info.hslab->diminfo.opt[u].start;
9168
0
        tmp_stride[u] = space->select.sel_info.hslab->diminfo.opt[u].stride;
9169
0
        tmp_count[u]  = space->select.sel_info.hslab->diminfo.opt[u].count;
9170
0
        tmp_block[u]  = space->select.sel_info.hslab->diminfo.opt[u].block;
9171
0
    } /* end for */
9172
9173
    /* Build the hyperslab information also */
9174
0
    if (H5S__generate_hyperslab(space, H5S_SELECT_SET, tmp_start, tmp_stride, tmp_count, tmp_block) < 0)
9175
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs");
9176
9177
0
done:
9178
0
    FUNC_LEAVE_NOAPI(ret_value)
9179
0
} /* end H5S__hyper_generate_spans() */
9180
9181
/*--------------------------------------------------------------------------
9182
 NAME
9183
    H5S__check_spans_overlap
9184
 PURPOSE
9185
    Check if two selections' bounds overlap.
9186
 USAGE
9187
    bool H5S__check_spans_overlap(spans1, spans2)
9188
        const H5S_hyper_span_info_t *spans1;  IN: Second span list
9189
        const H5S_hyper_span_info_t *spans2;  IN: Second span list
9190
 RETURNS
9191
    true for overlap, false for no overlap
9192
 PROGRAMMER
9193
 GLOBAL VARIABLES
9194
 COMMENTS, BUGS, ASSUMPTIONS
9195
 EXAMPLES
9196
 REVISION LOG
9197
--------------------------------------------------------------------------*/
9198
static H5_ATTR_PURE bool
9199
H5S__check_spans_overlap(const H5S_hyper_span_info_t *spans1, const H5S_hyper_span_info_t *spans2)
9200
0
{
9201
0
    bool ret_value = false; /* Return value */
9202
9203
0
    FUNC_ENTER_PACKAGE_NOERR
9204
9205
    /* Sanity checks */
9206
0
    assert(spans1);
9207
0
    assert(spans2);
9208
9209
    /* Use low & high bounds to try to avoid spinning through the span lists */
9210
0
    if (H5_RANGE_OVERLAP(spans1->low_bounds[0], spans1->high_bounds[0], spans2->low_bounds[0],
9211
0
                         spans2->high_bounds[0])) {
9212
0
        H5S_hyper_span_t *span1, *span2; /* Hyperslab spans */
9213
9214
        /* Walk over spans, comparing them for overlap */
9215
0
        span1 = spans1->head;
9216
0
        span2 = spans2->head;
9217
0
        while (span1 && span2) {
9218
            /* Check current two spans for overlap */
9219
0
            if (H5_RANGE_OVERLAP(span1->low, span1->high, span2->low, span2->high)) {
9220
                /* Check for spans in lowest dimension already */
9221
0
                if (span1->down) {
9222
                    /* Sanity check */
9223
0
                    assert(span2->down);
9224
9225
                    /* Check lower dimensions for overlap */
9226
0
                    if (H5S__check_spans_overlap(span1->down, span2->down))
9227
0
                        HGOTO_DONE(true);
9228
0
                } /* end if */
9229
0
                else
9230
0
                    HGOTO_DONE(true);
9231
0
            } /* end if */
9232
9233
            /* Advance one of the spans */
9234
0
            if (span1->high <= span2->high) {
9235
                /* Advance span1, unless it would be off the list and span2 has more nodes */
9236
0
                if (NULL == span1->next && NULL != span2->next)
9237
0
                    span2 = span2->next;
9238
0
                else
9239
0
                    span1 = span1->next;
9240
0
            } /* end if */
9241
0
            else {
9242
                /* Advance span2, unless it would be off the list and span1 has more nodes */
9243
0
                if (NULL == span2->next && NULL != span1->next)
9244
0
                    span1 = span1->next;
9245
0
                else
9246
0
                    span2 = span2->next;
9247
0
            } /* end else */
9248
0
        }     /* end while */
9249
9250
        /* Make certain we've exhausted our comparisons */
9251
0
        assert((NULL == span1 && (NULL != span2 && NULL == span2->next)) ||
9252
0
               ((NULL != span1 && NULL == span1->next) && NULL == span2));
9253
0
    } /* end of */
9254
9255
0
done:
9256
0
    FUNC_LEAVE_NOAPI(ret_value)
9257
0
} /* end H5S__check_spans_overlap() */
9258
9259
/*--------------------------------------------------------------------------
9260
 NAME
9261
    H5S__fill_in_new_space
9262
 PURPOSE
9263
    Combine two span lists, one from an existing dataspace and the
9264
    other from input arguments, into a new selection depending on the
9265
    selection operator. The new selection is put into a resulting dataspace
9266
    which could be allocated inside the function.
9267
 USAGE
9268
    herr_t H5S__fill_in_new_space(space1, op, space2_span_lst, can_own_span2,
9269
                                span2_owned, result)
9270
        H5S_t *space1;           IN: Dataspace containing the first span list
9271
        H5S_seloper_t op;        IN: Selection operation
9272
        H5S_hyper_span_info_t *space2_span_lst; IN: Second span list
9273
        bool can_own_span2;   IN: Indicates whether the 2nd span list could be
9274
                                     owned by the result. If not, the 2nd span list
9275
                                     has to be copied.
9276
        bool *span2_owned;  OUT: Indicates if the 2nd span list is actually owned
9277
        H5S_t **result;  OUT: The dataspace containing the new selection. It
9278
                              could be same with the 1st dataspace.
9279
 RETURNS
9280
    Non-negative on success, negative on failure
9281
 PROGRAMMER
9282
    Chao Mei July 8, 2011
9283
 GLOBAL VARIABLES
9284
 COMMENTS, BUGS, ASSUMPTIONS
9285
 EXAMPLES
9286
 REVISION LOG
9287
--------------------------------------------------------------------------*/
9288
static herr_t
9289
H5S__fill_in_new_space(H5S_t *space1, H5S_seloper_t op, H5S_hyper_span_info_t *space2_span_lst,
9290
                       bool can_own_span2, bool *span2_owned, bool *updated_spans, H5S_t **result)
9291
0
{
9292
0
    H5S_hyper_span_info_t *a_not_b =
9293
0
        NULL; /* Span tree for hyperslab spans in old span tree and not in new span tree */
9294
0
    H5S_hyper_span_info_t *a_and_b = NULL; /* Span tree for hyperslab spans in both old and new span trees */
9295
0
    H5S_hyper_span_info_t *b_not_a =
9296
0
        NULL; /* Span tree for hyperslab spans in new span tree and not in old span tree */
9297
0
    bool   overlapped    = false; /* Whether selections overlap */
9298
0
    bool   is_result_new = false;
9299
0
    herr_t ret_value     = SUCCEED; /* Return value */
9300
9301
0
    FUNC_ENTER_PACKAGE
9302
9303
0
    assert(space1);
9304
0
    assert(space2_span_lst);
9305
0
    assert(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA);
9306
    /* The result is either a to-be-created space or an empty one */
9307
0
    assert(*result == NULL || *result == space1);
9308
0
    assert(space1->select.sel_info.hslab->span_lst);
9309
0
    assert(span2_owned);
9310
9311
    /* Reset flags to return */
9312
0
    *span2_owned   = false;
9313
0
    *updated_spans = false;
9314
9315
    /* The result shares the same info from space1 */
9316
0
    if (*result == NULL) {
9317
0
        if (NULL == ((*result) = H5S_copy(space1, true, true)))
9318
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy dataspace");
9319
0
        space1->select.sel_info.hslab->span_lst->count--;
9320
0
        (*result)->select.sel_info.hslab->span_lst = NULL;
9321
0
        is_result_new                              = true;
9322
0
    } /* end if */
9323
9324
    /* Check both spaces to see if they overlap */
9325
0
    overlapped = H5S__check_spans_overlap(space1->select.sel_info.hslab->span_lst, space2_span_lst);
9326
9327
0
    if (!overlapped) {
9328
0
        switch (op) {
9329
0
            case H5S_SELECT_OR:
9330
0
            case H5S_SELECT_XOR:
9331
                /* Add the new disjoint spans to the space */
9332
                /* Copy of space1's spans to *result, and another copy of space2's spans */
9333
0
                if (is_result_new)
9334
0
                    (*result)->select.sel_info.hslab->span_lst =
9335
0
                        H5S__hyper_copy_span(space1->select.sel_info.hslab->span_lst, space1->extent.rank);
9336
0
                if (!can_own_span2) {
9337
0
                    b_not_a = H5S__hyper_copy_span(space2_span_lst, space1->extent.rank);
9338
0
                    if (H5S__hyper_add_disjoint_spans(*result, b_not_a) < 0)
9339
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't append hyperslabs");
9340
9341
                    /* The new_spans are now owned by 'space', so they should not be released */
9342
0
                    b_not_a = NULL;
9343
0
                } /* end if */
9344
0
                else {
9345
0
                    if (H5S__hyper_add_disjoint_spans(*result, space2_span_lst) < 0)
9346
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't append hyperslabs");
9347
0
                    *span2_owned = true;
9348
0
                } /* end else */
9349
9350
                /* Indicate that the spans changed */
9351
0
                *updated_spans = true;
9352
0
                break;
9353
9354
0
            case H5S_SELECT_AND:
9355
                /* Convert *result to "none" selection */
9356
0
                if (H5S_select_none(*result) < 0)
9357
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection");
9358
0
                HGOTO_DONE(SUCCEED);
9359
9360
0
            case H5S_SELECT_NOTB:
9361
                /* Copy space1's spans to *result */
9362
0
                if (is_result_new)
9363
0
                    (*result)->select.sel_info.hslab->span_lst =
9364
0
                        H5S__hyper_copy_span(space1->select.sel_info.hslab->span_lst, space1->extent.rank);
9365
9366
                /* Indicate that the spans changed */
9367
0
                *updated_spans = true;
9368
0
                break;
9369
9370
0
            case H5S_SELECT_NOTA:
9371
0
                if (!is_result_new) {
9372
0
                    assert(space1 == *result);
9373
9374
                    /* Free the current selection */
9375
0
                    if (H5S__hyper_free_span_info(space1->select.sel_info.hslab->span_lst) < 0)
9376
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
9377
0
                    space1->select.sel_info.hslab->span_lst = NULL;
9378
0
                }
9379
9380
                /* Copy space2's spans to *result */
9381
0
                if (!can_own_span2)
9382
0
                    (*result)->select.sel_info.hslab->span_lst =
9383
0
                        H5S__hyper_copy_span(space2_span_lst, space1->extent.rank);
9384
0
                else {
9385
0
                    (*result)->select.sel_info.hslab->span_lst = space2_span_lst;
9386
0
                    *span2_owned                               = true;
9387
0
                }
9388
9389
                /* Reset the number of items in selection */
9390
0
                (*result)->select.num_elem = H5S__hyper_spans_nelem(space2_span_lst);
9391
9392
                /* Indicate that the spans changed */
9393
0
                *updated_spans = true;
9394
0
                break;
9395
9396
0
            case H5S_SELECT_NOOP:
9397
0
            case H5S_SELECT_SET:
9398
0
            case H5S_SELECT_APPEND:
9399
0
            case H5S_SELECT_PREPEND:
9400
0
            case H5S_SELECT_INVALID:
9401
0
            default:
9402
0
                HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
9403
0
        } /* end switch */
9404
0
    }     /* end if */
9405
0
    else {
9406
0
        unsigned selector = 0; /* Select which clipping spans to generate */
9407
9408
        /* Generate mask for clip operation depending on the op */
9409
0
        switch (op) {
9410
0
            case H5S_SELECT_OR: /* a + b_not_a */
9411
0
                selector = H5S_HYPER_COMPUTE_B_NOT_A;
9412
0
                break;
9413
9414
0
            case H5S_SELECT_XOR: /* a_not_b + b_not_a */
9415
0
                selector = H5S_HYPER_COMPUTE_A_NOT_B | H5S_HYPER_COMPUTE_B_NOT_A;
9416
0
                break;
9417
9418
0
            case H5S_SELECT_AND: /* a_and_b */
9419
0
                selector = H5S_HYPER_COMPUTE_A_AND_B;
9420
0
                break;
9421
9422
0
            case H5S_SELECT_NOTB: /* a_not_b */
9423
0
                selector = H5S_HYPER_COMPUTE_A_NOT_B;
9424
0
                break;
9425
9426
0
            case H5S_SELECT_NOTA: /* b_not_a */
9427
0
                selector = H5S_HYPER_COMPUTE_B_NOT_A;
9428
0
                break;
9429
9430
0
            case H5S_SELECT_NOOP:
9431
0
            case H5S_SELECT_SET:
9432
0
            case H5S_SELECT_APPEND:
9433
0
            case H5S_SELECT_PREPEND:
9434
0
            case H5S_SELECT_INVALID:
9435
0
            default:
9436
0
                HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
9437
0
        } /* end switch */
9438
9439
        /* Generate lists of spans which overlap and don't overlap */
9440
0
        if (H5S__hyper_clip_spans(space1->select.sel_info.hslab->span_lst, space2_span_lst, selector,
9441
0
                                  space1->extent.rank, &a_not_b, &a_and_b, &b_not_a) < 0)
9442
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information");
9443
0
        switch (op) {
9444
0
            case H5S_SELECT_OR:
9445
0
                if (is_result_new)
9446
0
                    (*result)->select.sel_info.hslab->span_lst =
9447
0
                        H5S__hyper_copy_span(space1->select.sel_info.hslab->span_lst, space1->extent.rank);
9448
0
                break;
9449
9450
0
            case H5S_SELECT_AND:
9451
0
            case H5S_SELECT_XOR:
9452
0
            case H5S_SELECT_NOTB:
9453
0
            case H5S_SELECT_NOTA:
9454
0
                if (!is_result_new) {
9455
0
                    assert(space1 == *result);
9456
9457
                    /* Free the current selection */
9458
0
                    if (H5S__hyper_free_span_info(space1->select.sel_info.hslab->span_lst) < 0)
9459
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
9460
0
                    space1->select.sel_info.hslab->span_lst = NULL;
9461
0
                }
9462
9463
                /* Reset the number of items in selection */
9464
                /* (Will be set below) */
9465
0
                (*result)->select.num_elem = 0;
9466
0
                break;
9467
9468
0
            case H5S_SELECT_NOOP:
9469
0
            case H5S_SELECT_SET:
9470
0
            case H5S_SELECT_APPEND:
9471
0
            case H5S_SELECT_PREPEND:
9472
0
            case H5S_SELECT_INVALID:
9473
0
            default:
9474
0
                HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
9475
0
        } /* end switch */
9476
9477
        /* Check if there are any non-overlapped selections */
9478
0
        if (a_not_b) {
9479
            /* Other than OR, the span_lst is set to NULL. And in OR,
9480
             *      a_not_b is not needed
9481
             */
9482
0
            assert(NULL == (*result)->select.sel_info.hslab->span_lst);
9483
9484
            /* The results dataspace takes ownership of the spans */
9485
            /* (Since it must be NULL) */
9486
0
            (*result)->select.sel_info.hslab->span_lst = a_not_b;
9487
9488
            /* Update the number of elements in current selection */
9489
0
            (*result)->select.num_elem = H5S__hyper_spans_nelem(a_not_b);
9490
9491
            /* Indicate that the spans were updated */
9492
0
            *updated_spans = true;
9493
9494
            /* Indicate that the a_not_b spans are owned */
9495
0
            a_not_b = NULL;
9496
0
        } /* end if */
9497
9498
0
        if (a_and_b) {
9499
            /**
9500
             * 1. Other than OR, the span_lst is set to NULL. And in OR,
9501
             *      a_and_b is not needed
9502
             * 2. a_not_b will never be computed together with a_and_b
9503
             *      because merging these two equals to a.
9504
             */
9505
0
            assert(NULL == (*result)->select.sel_info.hslab->span_lst);
9506
9507
            /* The results dataspace takes ownership of the spans */
9508
            /* (Since it must be NULL) */
9509
0
            (*result)->select.sel_info.hslab->span_lst = a_and_b;
9510
9511
            /* Update the number of elements in current selection */
9512
0
            (*result)->select.num_elem = H5S__hyper_spans_nelem(a_and_b);
9513
9514
            /* Indicate that the spans were updated */
9515
0
            *updated_spans = true;
9516
9517
            /* Indicate that the a_and_b spans are owned */
9518
0
            a_and_b = NULL;
9519
0
        } /* end if */
9520
9521
0
        if (b_not_a) {
9522
            /* Merge the b_not_a spans into the result dataspace */
9523
0
            if (H5S__hyper_merge_spans(*result, b_not_a) < 0)
9524
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs");
9525
9526
            /* Update the number of elements in current selection */
9527
0
            (*result)->select.num_elem += H5S__hyper_spans_nelem(b_not_a);
9528
9529
            /* Indicate that the spans were updated */
9530
0
            *updated_spans = true;
9531
0
        } /* end if */
9532
0
    }     /* end else for the case the new span overlaps with the old (i.e. space) */
9533
9534
    /* Check if the spans weren't updated, and reset selection if so */
9535
0
    if (!*updated_spans) {
9536
        /* If updated_spans remains false as in this branch, it means the
9537
         *  result has been cleared in XOR / AND / NOTB / NOTA cases, and the
9538
         *  result is a copy of the dataspace in the OR case.
9539
         *
9540
         *  If two dataspaces have generated any of the three clipped
9541
         *  span trees (i.e. a_not_b, a_and_b, and b_not_a), the
9542
         *  updated_spans must be true.
9543
         */
9544
0
        if (H5S_SELECT_OR != op) {
9545
            /* Convert *result to "none" selection */
9546
0
            if (H5S_select_none(*result) < 0)
9547
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection");
9548
0
        }
9549
0
    }
9550
9551
0
done:
9552
    /* Free resources */
9553
0
    if (a_not_b)
9554
0
        if (H5S__hyper_free_span_info(a_not_b) < 0)
9555
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
9556
0
    if (a_and_b)
9557
0
        if (H5S__hyper_free_span_info(a_and_b) < 0)
9558
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
9559
0
    if (b_not_a)
9560
0
        if (H5S__hyper_free_span_info(b_not_a) < 0)
9561
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
9562
9563
0
    FUNC_LEAVE_NOAPI(ret_value)
9564
0
} /* end H5S__fill_in_new_space() */
9565
9566
/*-------------------------------------------------------------------------
9567
 * Function:    H5S__generate_hyperlab
9568
 *
9569
 * Purpose:     Generate hyperslab information from H5S_select_hyperslab()
9570
 *
9571
 * Return:      Non-negative on success/Negative on failure
9572
 *
9573
 *-------------------------------------------------------------------------
9574
 */
9575
static herr_t
9576
H5S__generate_hyperslab(H5S_t *space, H5S_seloper_t op, const hsize_t start[], const hsize_t stride[],
9577
                        const hsize_t count[], const hsize_t block[])
9578
0
{
9579
0
    H5S_hyper_span_info_t *new_spans = NULL;    /* Span tree for new hyperslab */
9580
0
    herr_t                 ret_value = SUCCEED; /* Return value */
9581
9582
0
    FUNC_ENTER_PACKAGE
9583
9584
    /* Check args */
9585
0
    assert(space);
9586
0
    assert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID);
9587
0
    assert(start);
9588
0
    assert(stride);
9589
0
    assert(count);
9590
0
    assert(block);
9591
9592
    /* Generate span tree for new hyperslab information */
9593
0
    if (NULL == (new_spans = H5S__hyper_make_spans(space->extent.rank, start, stride, count, block)))
9594
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't create hyperslab information");
9595
9596
    /* Generate list of blocks to add/remove based on selection operation */
9597
0
    if (op == H5S_SELECT_SET) {
9598
        /* Free current selection */
9599
0
        if (NULL != space->select.sel_info.hslab->span_lst)
9600
0
            if (H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst) < 0)
9601
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
9602
9603
        /* Set the hyperslab selection to the new span tree */
9604
0
        space->select.sel_info.hslab->span_lst = new_spans;
9605
9606
        /* Set the number of elements in current selection */
9607
0
        space->select.num_elem = H5S__hyper_spans_nelem(new_spans);
9608
9609
        /* Indicate that the new_spans are owned */
9610
0
        new_spans = NULL;
9611
0
    }
9612
0
    else {
9613
0
        bool new_spans_owned = false;
9614
0
        bool updated_spans   = false;
9615
9616
        /* Generate new spans for space */
9617
0
        if (H5S__fill_in_new_space(space, op, new_spans, true, &new_spans_owned, &updated_spans, &space) < 0)
9618
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't generate the specified hyperslab");
9619
9620
        /* Check if the spans were updated by H5S__fill_in_new_space */
9621
0
        if (updated_spans) {
9622
0
            H5S_hyper_dim_t new_hyper_diminfo[H5S_MAX_RANK];
9623
0
            unsigned        u; /* Local index variable */
9624
9625
            /* Sanity check */
9626
0
            assert(space->select.sel_info.hslab->span_lst->head);
9627
9628
            /* Build diminfo struct */
9629
0
            for (u = 0; u < space->extent.rank; u++) {
9630
0
                new_hyper_diminfo[u].start  = start[u];
9631
0
                new_hyper_diminfo[u].stride = stride[u];
9632
0
                new_hyper_diminfo[u].count  = count[u];
9633
0
                new_hyper_diminfo[u].block  = block[u];
9634
0
            } /* end for */
9635
9636
            /* Update space's dim info */
9637
0
            if (H5S__hyper_update_diminfo(space, op, new_hyper_diminfo) < 0)
9638
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't update hyperslab info");
9639
0
        } /* end if */
9640
9641
        /* Indicate that the new_spans are owned, there's no need to free */
9642
0
        if (new_spans_owned)
9643
0
            new_spans = NULL;
9644
0
    }
9645
9646
0
done:
9647
0
    if (new_spans)
9648
0
        if (H5S__hyper_free_span_info(new_spans) < 0)
9649
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
9650
9651
0
    FUNC_LEAVE_NOAPI(ret_value)
9652
0
} /* end H5S__generate_hyperslab() */
9653
9654
/*-------------------------------------------------------------------------
9655
 * Function:    H5S__set_regular_hyperslab
9656
 *
9657
 * Purpose:    Set a regular hyperslab
9658
 *
9659
 * Return:    Non-negative on success/Negative on failure
9660
 *
9661
 *-------------------------------------------------------------------------
9662
 */
9663
herr_t
9664
H5S__set_regular_hyperslab(H5S_t *space, const hsize_t start[], const hsize_t *app_stride,
9665
                           const hsize_t app_count[], const hsize_t *app_block, const hsize_t *opt_stride,
9666
                           const hsize_t opt_count[], const hsize_t *opt_block)
9667
0
{
9668
0
    unsigned u;                   /* Local index variable */
9669
0
    herr_t   ret_value = SUCCEED; /* Return value */
9670
9671
0
    FUNC_ENTER_PACKAGE
9672
9673
    /* Check args */
9674
0
    assert(space);
9675
0
    assert(start);
9676
0
    assert(app_stride);
9677
0
    assert(app_count);
9678
0
    assert(app_block);
9679
0
    assert(opt_stride);
9680
0
    assert(opt_count);
9681
0
    assert(opt_block);
9682
9683
    /* If we are setting a new selection, remove current selection first */
9684
0
    if (H5S_SELECT_RELEASE(space) < 0)
9685
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection");
9686
9687
    /* Allocate space for the hyperslab selection information */
9688
0
    if (NULL == (space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t)))
9689
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab info");
9690
9691
    /* Set the diminfo */
9692
0
    space->select.num_elem                  = 1;
9693
0
    space->select.sel_info.hslab->unlim_dim = -1;
9694
0
    for (u = 0; u < space->extent.rank; u++) {
9695
        /* Set application and optimized hyperslab info */
9696
0
        space->select.sel_info.hslab->diminfo.app[u].start  = start[u];
9697
0
        space->select.sel_info.hslab->diminfo.app[u].stride = app_stride[u];
9698
0
        space->select.sel_info.hslab->diminfo.app[u].count  = app_count[u];
9699
0
        space->select.sel_info.hslab->diminfo.app[u].block  = app_block[u];
9700
9701
0
        space->select.sel_info.hslab->diminfo.opt[u].start  = start[u];
9702
0
        space->select.sel_info.hslab->diminfo.opt[u].stride = opt_stride[u];
9703
0
        space->select.sel_info.hslab->diminfo.opt[u].count  = opt_count[u];
9704
0
        space->select.sel_info.hslab->diminfo.opt[u].block  = opt_block[u];
9705
9706
        /* Update # of elements selected */
9707
0
        space->select.num_elem *= (opt_count[u] * opt_block[u]);
9708
9709
        /* Set low bound of bounding box for the hyperslab selection */
9710
0
        space->select.sel_info.hslab->diminfo.low_bounds[u] = start[u];
9711
9712
        /* Check for unlimited dimension & set high bound */
9713
0
        if ((app_count[u] == H5S_UNLIMITED) || (app_block[u] == H5S_UNLIMITED)) {
9714
0
            space->select.sel_info.hslab->unlim_dim              = (int)u;
9715
0
            space->select.sel_info.hslab->diminfo.high_bounds[u] = H5S_UNLIMITED;
9716
0
        } /* end if */
9717
0
        else
9718
0
            space->select.sel_info.hslab->diminfo.high_bounds[u] =
9719
0
                start[u] + opt_stride[u] * (opt_count[u] - 1) + (opt_block[u] - 1);
9720
0
    } /* end for */
9721
9722
    /* Handle unlimited selections */
9723
0
    if (space->select.sel_info.hslab->unlim_dim >= 0) {
9724
        /* Calculate num_elem_non_unlim */
9725
0
        space->select.sel_info.hslab->num_elem_non_unlim = (hsize_t)1;
9726
0
        for (u = 0; u < space->extent.rank; u++)
9727
0
            if ((int)u != space->select.sel_info.hslab->unlim_dim)
9728
0
                space->select.sel_info.hslab->num_elem_non_unlim *= (opt_count[u] * opt_block[u]);
9729
9730
        /* Update num_elem */
9731
0
        space->select.num_elem = H5S_UNLIMITED;
9732
0
    } /* end if */
9733
9734
    /* Indicate that the dimension information is valid */
9735
0
    space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_YES;
9736
9737
    /* Indicate that there's no slab information */
9738
0
    space->select.sel_info.hslab->span_lst = NULL;
9739
9740
    /* Set selection type */
9741
0
    space->select.type = H5S_sel_hyper;
9742
9743
0
done:
9744
0
    FUNC_LEAVE_NOAPI(ret_value)
9745
0
} /* end H5S__set_regular_hyperslab() */
9746
9747
/*-------------------------------------------------------------------------
9748
 * Function:    H5S__hyper_regular_and_single_block
9749
 *
9750
 * Purpose:    Optimized routine to perform "AND" operation of a single
9751
 *        block against a regular hyperslab selection.
9752
 *
9753
 * Note:    This algorithm is invoked when constructing the chunk map
9754
 *              and a regular hyperslab is selected in the file's dataspace.
9755
 *
9756
 * Return:    Non-negative on success / Negative on failure
9757
 *
9758
 *-------------------------------------------------------------------------
9759
 */
9760
static herr_t
9761
H5S__hyper_regular_and_single_block(H5S_t *space, const hsize_t start[], const hsize_t block[])
9762
0
{
9763
0
    hsize_t  select_end, block_end; /* End of block & selection */
9764
0
    bool     single_block;          /* Whether the selection is a single block */
9765
0
    bool     overlap;               /* Whether block & selection overlap */
9766
0
    unsigned u;                     /* Local index variable */
9767
0
    herr_t   ret_value = SUCCEED;   /* Return value */
9768
9769
0
    FUNC_ENTER_PACKAGE
9770
9771
    /* Check args */
9772
0
    assert(space);
9773
0
    assert(start);
9774
0
    assert(block);
9775
9776
    /* Check for single block selection in dataspace */
9777
0
    single_block = true;
9778
0
    for (u = 0; u < space->extent.rank; u++)
9779
0
        if (1 != space->select.sel_info.hslab->diminfo.opt[u].count) {
9780
0
            single_block = false;
9781
0
            break;
9782
0
        } /* end if */
9783
9784
    /* Perform different optimizations, based on type of regular selection */
9785
0
    if (single_block) {
9786
0
        hsize_t new_start[H5S_MAX_RANK]; /* New starting coordinate */
9787
0
        hsize_t new_block[H5S_MAX_RANK]; /* New block size */
9788
9789
        /* Check for overlap and compute new start offset & block sizes */
9790
0
        overlap = true;
9791
0
        for (u = 0; u < space->extent.rank; u++) {
9792
            /* Compute the end of the selection & block in this dimension */
9793
0
            select_end = space->select.sel_info.hslab->diminfo.high_bounds[u];
9794
0
            block_end  = (start[u] + block[u]) - 1;
9795
9796
            /* Check for overlap */
9797
0
            if (!H5_RANGE_OVERLAP(space->select.sel_info.hslab->diminfo.opt[u].start, select_end, start[u],
9798
0
                                  block_end)) {
9799
0
                overlap = false;
9800
0
                break;
9801
0
            } /* end if */
9802
9803
            /* Set new start & block size in this dimension */
9804
0
            new_start[u] = MAX(space->select.sel_info.hslab->diminfo.opt[u].start, start[u]);
9805
0
            new_block[u] = (MIN(select_end, block_end) - new_start[u]) + 1;
9806
0
        } /* end for */
9807
9808
        /* Check for overlap of selection & block */
9809
0
        if (overlap) {
9810
            /* Set selection to regular hyperslab */
9811
0
            if (H5S__set_regular_hyperslab(space, new_start, H5S_hyper_ones_g, H5S_hyper_ones_g, new_block,
9812
0
                                           H5S_hyper_ones_g, H5S_hyper_ones_g, new_block) < 0)
9813
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't set regular hyperslab selection");
9814
0
        } /* end if */
9815
0
        else
9816
            /* Selection & block don't overlap, set to "none" selection */
9817
0
            if (H5S_select_none(space) < 0)
9818
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection");
9819
0
    } /* end if */
9820
0
    else {
9821
0
        hsize_t new_start[H5S_MAX_RANK]; /* New start for hyperslab selection */
9822
0
        hsize_t new_count[H5S_MAX_RANK]; /* New count for hyperslab selection */
9823
0
        hsize_t stride[H5S_MAX_RANK];    /* Stride for hyperslab selection */
9824
0
        hsize_t new_block[H5S_MAX_RANK]; /* New block for hyperslab selection */
9825
0
        bool    partial_first_span;      /* Whether first span in intersection is partial */
9826
0
        bool    partial_last_span;       /* Whether last span in intersection is partial */
9827
9828
        /* Iterate over selection, checking for overlap and computing first / last
9829
         *      span that intersects with the block.
9830
         */
9831
0
        overlap            = true;
9832
0
        partial_first_span = false;
9833
0
        partial_last_span  = false;
9834
0
        for (u = 0; u < space->extent.rank; u++) {
9835
0
            hsize_t first_span_start, first_span_end; /* Start / end of first span */
9836
0
            hsize_t last_span_start, last_span_end;   /* Start / end of last span */
9837
0
            hsize_t nstride;                          /* Number of strides into the selection */
9838
9839
            /* Compute the end of the selection & block in this dimension */
9840
0
            select_end = space->select.sel_info.hslab->diminfo.high_bounds[u];
9841
0
            block_end  = (start[u] + block[u]) - 1;
9842
9843
            /* Check for overlap */
9844
0
            if (!H5_RANGE_OVERLAP(space->select.sel_info.hslab->diminfo.opt[u].start, select_end, start[u],
9845
0
                                  block_end)) {
9846
0
                overlap = false;
9847
0
                break;
9848
0
            } /* end if */
9849
9850
            /* Find first span that is before or overlaps with start of block */
9851
0
            if (space->select.sel_info.hslab->diminfo.opt[u].start >= start[u]) {
9852
                /* Calculate start & end of first span */
9853
0
                first_span_start = space->select.sel_info.hslab->diminfo.opt[u].start;
9854
0
                first_span_end = (first_span_start + space->select.sel_info.hslab->diminfo.opt[u].block) - 1;
9855
9856
                /* Check if first span overlaps _end_ of block */
9857
0
                if (block_end >= first_span_start && block_end <= first_span_end)
9858
0
                    partial_first_span = true;
9859
0
            } /* end if */
9860
0
            else {
9861
0
                hsize_t adj_start; /* Start coord, adjusted for hyperslab selection parameters */
9862
9863
                /* Adjust start coord for selection's 'start' offset */
9864
0
                adj_start = start[u] - space->select.sel_info.hslab->diminfo.opt[u].start;
9865
9866
                /* Compute # of strides into the selection */
9867
0
                if (space->select.sel_info.hslab->diminfo.opt[u].count > 1)
9868
0
                    nstride = adj_start / space->select.sel_info.hslab->diminfo.opt[u].stride;
9869
0
                else
9870
0
                    nstride = 0;
9871
9872
                /* Calculate start & end of first span */
9873
0
                first_span_start = space->select.sel_info.hslab->diminfo.opt[u].start +
9874
0
                                   (nstride * space->select.sel_info.hslab->diminfo.opt[u].stride);
9875
0
                first_span_end = (first_span_start + space->select.sel_info.hslab->diminfo.opt[u].block) - 1;
9876
9877
                /* Check if first span overlaps start of block */
9878
0
                if (first_span_start < start[u] && first_span_end >= start[u])
9879
0
                    partial_first_span = true;
9880
9881
                /* Advance first span to start higher than block's start,
9882
                 *      if it's not partial.
9883
                 */
9884
0
                if (first_span_end < start[u]) {
9885
0
                    first_span_start += space->select.sel_info.hslab->diminfo.opt[u].stride;
9886
0
                    first_span_end += space->select.sel_info.hslab->diminfo.opt[u].stride;
9887
0
                } /* end if */
9888
0
            }     /* end else */
9889
9890
            /* Find last span that is before or overlaps with end of block */
9891
0
            if (select_end < block_end) {
9892
                /* Calculate start & end of last span */
9893
0
                last_span_start = (select_end - space->select.sel_info.hslab->diminfo.opt[u].block) + 1;
9894
0
                last_span_end   = select_end;
9895
9896
                /* Check if last span overlaps _start_ of block */
9897
0
                if (start[u] >= last_span_start && start[u] <= last_span_end)
9898
0
                    partial_last_span = true;
9899
0
            } /* end if */
9900
0
            else {
9901
0
                hsize_t adj_end; /* End coord, adjusted for hyperslab selection parameters */
9902
9903
                /* Adjust end coord for selection's 'start' offset */
9904
0
                adj_end = block_end - space->select.sel_info.hslab->diminfo.opt[u].start;
9905
9906
                /* Compute # of strides into the selection */
9907
0
                if (space->select.sel_info.hslab->diminfo.opt[u].count > 1)
9908
0
                    nstride = adj_end / space->select.sel_info.hslab->diminfo.opt[u].stride;
9909
0
                else
9910
0
                    nstride = 0;
9911
9912
                /* Calculate start & end of last span */
9913
0
                last_span_start = space->select.sel_info.hslab->diminfo.opt[u].start +
9914
0
                                  (nstride * space->select.sel_info.hslab->diminfo.opt[u].stride);
9915
0
                last_span_end = (last_span_start + space->select.sel_info.hslab->diminfo.opt[u].block) - 1;
9916
9917
                /* Check if last span overlaps end of block */
9918
0
                if (block_end >= last_span_start && block_end <= last_span_end)
9919
0
                    partial_last_span = true;
9920
0
            } /* end else */
9921
9922
            /* Check if no spans are inside block */
9923
            /* (Can happen when block falls in "gap" between spans) */
9924
0
            if (last_span_end < start[u]) {
9925
0
                overlap = false;
9926
0
                break;
9927
0
            } /* end if */
9928
9929
            /* Sanity check */
9930
0
            assert(first_span_start <= last_span_start);
9931
9932
            /* Compute new start / count / block values */
9933
0
            new_start[u] = first_span_start;
9934
0
            if (last_span_start != first_span_start)
9935
0
                new_count[u] = ((last_span_start - first_span_start) /
9936
0
                                space->select.sel_info.hslab->diminfo.opt[u].stride) +
9937
0
                               1;
9938
0
            else
9939
0
                new_count[u] = 1;
9940
0
            new_block[u] = space->select.sel_info.hslab->diminfo.opt[u].block;
9941
9942
            /* Keep same stride */
9943
0
            stride[u] = space->select.sel_info.hslab->diminfo.opt[u].stride;
9944
0
        } /* end for */
9945
9946
        /* Check for overlap of selection & block */
9947
0
        if (overlap) {
9948
            /* Set selection to regular hyperslab */
9949
0
            if (H5S__set_regular_hyperslab(space, new_start, stride, new_count, new_block, stride, new_count,
9950
0
                                           new_block) < 0)
9951
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't set regular hyperslab selection");
9952
9953
            /* If there's a partial first or last span, have to 'AND' against selection */
9954
0
            if (partial_first_span || partial_last_span) {
9955
                /* Generate span tree for regular selection */
9956
0
                if (H5S__hyper_generate_spans(space) < 0)
9957
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree");
9958
9959
                /* 'AND' against block */
9960
0
                if (H5S__generate_hyperslab(space, H5S_SELECT_AND, start, H5S_hyper_ones_g, H5S_hyper_ones_g,
9961
0
                                            block) < 0)
9962
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs");
9963
0
            } /* end if */
9964
0
        }     /* end if */
9965
0
        else {
9966
            /* Selection & block don't overlap, set to "none" selection */
9967
0
            if (H5S_select_none(space) < 0)
9968
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection");
9969
0
        } /* end else */
9970
0
    }     /* end else */
9971
9972
0
done:
9973
0
    FUNC_LEAVE_NOAPI(ret_value)
9974
0
} /* end H5S__hyper_regular_and_single_block() */
9975
9976
/*-------------------------------------------------------------------------
9977
 * Function:    H5S_select_hyperslab
9978
 *
9979
 * Purpose:     Internal version of H5Sselect_hyperslab().
9980
 *
9981
 * Return:      Non-negative on success/Negative on failure
9982
 *
9983
 *-------------------------------------------------------------------------
9984
 */
9985
herr_t
9986
H5S_select_hyperslab(H5S_t *space, H5S_seloper_t op, const hsize_t start[], const hsize_t *stride,
9987
                     const hsize_t count[], const hsize_t *block)
9988
0
{
9989
0
    hsize_t        int_stride[H5S_MAX_RANK]; /* Internal storage for stride information */
9990
0
    hsize_t        int_count[H5S_MAX_RANK];  /* Internal storage for count information */
9991
0
    hsize_t        int_block[H5S_MAX_RANK];  /* Internal storage for block information */
9992
0
    const hsize_t *opt_stride;               /* Optimized stride information */
9993
0
    const hsize_t *opt_count;                /* Optimized count information */
9994
0
    const hsize_t *opt_block;                /* Optimized block information */
9995
0
    int            unlim_dim = -1;           /* Unlimited dimension in selection, of -1 if none */
9996
0
    unsigned       u;                        /* Local index variable */
9997
0
    herr_t         ret_value = SUCCEED;      /* Return value */
9998
9999
0
    FUNC_ENTER_NOAPI(FAIL)
10000
10001
    /* Check args */
10002
0
    assert(space);
10003
0
    assert(start);
10004
0
    assert(count);
10005
0
    assert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID);
10006
10007
    /* Point to the correct stride values */
10008
0
    if (stride == NULL)
10009
0
        stride = H5S_hyper_ones_g;
10010
10011
    /* Point to the correct block values */
10012
0
    if (block == NULL)
10013
0
        block = H5S_hyper_ones_g;
10014
10015
    /* Check new selection */
10016
0
    for (u = 0; u < space->extent.rank; u++) {
10017
        /* Check for overlapping hyperslab blocks in new selection. */
10018
0
        if (count[u] > 1 && stride[u] < block[u])
10019
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab blocks overlap");
10020
10021
        /* Detect zero-sized hyperslabs in new selection */
10022
0
        if (count[u] == 0 || block[u] == 0) {
10023
0
            switch (op) {
10024
0
                case H5S_SELECT_SET:  /* Select "set" operation */
10025
0
                case H5S_SELECT_AND:  /* Binary "and" operation for hyperslabs */
10026
0
                case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */
10027
                    /* Convert to "none" selection */
10028
0
                    if (H5S_select_none(space) < 0)
10029
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection");
10030
0
                    HGOTO_DONE(SUCCEED);
10031
10032
0
                case H5S_SELECT_OR:      /* Binary "or" operation for hyperslabs */
10033
0
                case H5S_SELECT_XOR:     /* Binary "xor" operation for hyperslabs */
10034
0
                case H5S_SELECT_NOTB:    /* Binary "A not B" operation for hyperslabs */
10035
0
                    HGOTO_DONE(SUCCEED); /* Selection stays same */
10036
10037
0
                case H5S_SELECT_NOOP:
10038
0
                case H5S_SELECT_APPEND:
10039
0
                case H5S_SELECT_PREPEND:
10040
0
                case H5S_SELECT_INVALID:
10041
0
                default:
10042
0
                    HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
10043
0
            } /* end switch */
10044
0
        }     /* end if */
10045
10046
        /* Check for unlimited dimension */
10047
0
        if ((count[u] == H5S_UNLIMITED) || (block[u] == H5S_UNLIMITED)) {
10048
0
            if (unlim_dim >= 0)
10049
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL,
10050
0
                            "cannot have more than one unlimited dimension in selection");
10051
0
            else {
10052
0
                if (count[u] == block[u]) /* Both are H5S_UNLIMITED */
10053
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL,
10054
0
                                "count and block cannot both be unlimited");
10055
0
                unlim_dim = (int)u;
10056
0
            } /* end else */
10057
0
        }     /* end if */
10058
0
    }         /* end for */
10059
10060
    /* Optimize hyperslab parameters to merge contiguous blocks, etc. */
10061
0
    if (stride == H5S_hyper_ones_g && block == H5S_hyper_ones_g) {
10062
        /* Point to existing arrays */
10063
0
        opt_stride = H5S_hyper_ones_g;
10064
0
        opt_count  = H5S_hyper_ones_g;
10065
0
        opt_block  = count;
10066
0
    } /* end if */
10067
0
    else {
10068
        /* Point to local arrays */
10069
0
        opt_stride = int_stride;
10070
0
        opt_count  = int_count;
10071
0
        opt_block  = int_block;
10072
0
        for (u = 0; u < space->extent.rank; u++) {
10073
            /* contiguous hyperslabs have the block size equal to the stride */
10074
0
            if ((stride[u] == block[u]) && (count[u] != H5S_UNLIMITED)) {
10075
0
                int_count[u]  = 1;
10076
0
                int_stride[u] = 1;
10077
0
                if (block[u] == 1)
10078
0
                    int_block[u] = count[u];
10079
0
                else
10080
0
                    int_block[u] = block[u] * count[u];
10081
0
            } /* end if */
10082
0
            else {
10083
0
                if (count[u] == 1)
10084
0
                    int_stride[u] = 1;
10085
0
                else {
10086
0
                    assert((stride[u] > block[u]) ||
10087
0
                           ((stride[u] == block[u]) && (count[u] == H5S_UNLIMITED)));
10088
0
                    int_stride[u] = stride[u];
10089
0
                } /* end else */
10090
0
                int_count[u] = count[u];
10091
0
                int_block[u] = block[u];
10092
0
            } /* end else */
10093
0
        }     /* end for */
10094
0
    }         /* end else */
10095
10096
    /* Check for operating on unlimited selection */
10097
0
    if ((H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS) &&
10098
0
        (space->select.sel_info.hslab->unlim_dim >= 0) && (op != H5S_SELECT_SET)) {
10099
        /* Check for invalid operation */
10100
0
        if (unlim_dim >= 0)
10101
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL,
10102
0
                        "cannot modify unlimited selection with another unlimited selection");
10103
0
        if (!((op == H5S_SELECT_AND) || (op == H5S_SELECT_NOTA)))
10104
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unsupported operation on unlimited selection");
10105
0
        assert(space->select.sel_info.hslab->diminfo_valid);
10106
10107
        /* Clip unlimited selection to include new selection */
10108
0
        if (H5S_hyper_clip_unlim(space,
10109
0
                                 start[space->select.sel_info.hslab->unlim_dim] +
10110
0
                                     ((opt_count[space->select.sel_info.hslab->unlim_dim] - (hsize_t)1) *
10111
0
                                      opt_stride[space->select.sel_info.hslab->unlim_dim]) +
10112
0
                                     opt_block[space->select.sel_info.hslab->unlim_dim]) < 0)
10113
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection");
10114
10115
        /* If an empty space was returned it must be "none" */
10116
0
        assert((space->select.num_elem > (hsize_t)0) || (space->select.type->type == H5S_SEL_NONE));
10117
0
    } /* end if */
10118
10119
    /* Fixup operation for non-hyperslab selections */
10120
0
    switch (H5S_GET_SELECT_TYPE(space)) {
10121
0
        case H5S_SEL_NONE: /* No elements selected in dataspace */
10122
0
            switch (op) {
10123
0
                case H5S_SELECT_SET: /* Select "set" operation */
10124
                    /* Change "none" selection to hyperslab selection */
10125
0
                    break;
10126
10127
0
                case H5S_SELECT_OR:      /* Binary "or" operation for hyperslabs */
10128
0
                case H5S_SELECT_XOR:     /* Binary "xor" operation for hyperslabs */
10129
0
                case H5S_SELECT_NOTA:    /* Binary "B not A" operation for hyperslabs */
10130
0
                    op = H5S_SELECT_SET; /* Maps to "set" operation when applied to "none" selection */
10131
0
                    break;
10132
10133
0
                case H5S_SELECT_AND:     /* Binary "and" operation for hyperslabs */
10134
0
                case H5S_SELECT_NOTB:    /* Binary "A not B" operation for hyperslabs */
10135
0
                    HGOTO_DONE(SUCCEED); /* Selection stays "none" */
10136
10137
0
                case H5S_SELECT_NOOP:
10138
0
                case H5S_SELECT_APPEND:
10139
0
                case H5S_SELECT_PREPEND:
10140
0
                case H5S_SELECT_INVALID:
10141
0
                default:
10142
0
                    HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
10143
0
            } /* end switch */
10144
0
            break;
10145
10146
0
        case H5S_SEL_ALL: /* All elements selected in dataspace */
10147
0
            switch (op) {
10148
0
                case H5S_SELECT_SET: /* Select "set" operation */
10149
                    /* Change "all" selection to hyperslab selection */
10150
0
                    break;
10151
10152
0
                case H5S_SELECT_OR:      /* Binary "or" operation for hyperslabs */
10153
0
                    HGOTO_DONE(SUCCEED); /* Selection stays "all" */
10154
10155
0
                case H5S_SELECT_AND:     /* Binary "and" operation for hyperslabs */
10156
0
                    op = H5S_SELECT_SET; /* Maps to "set" operation when applied to "none" selection */
10157
0
                    break;
10158
10159
0
                case H5S_SELECT_XOR:  /* Binary "xor" operation for hyperslabs */
10160
0
                case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */
10161
                    /* Convert current "all" selection to "real" hyperslab selection */
10162
                    /* Then allow operation to proceed */
10163
0
                    {
10164
0
                        const hsize_t *tmp_start;  /* Temporary start information */
10165
0
                        const hsize_t *tmp_stride; /* Temporary stride information */
10166
0
                        const hsize_t *tmp_count;  /* Temporary count information */
10167
0
                        const hsize_t *tmp_block;  /* Temporary block information */
10168
10169
                        /* Set up temporary information for the dimensions */
10170
0
                        tmp_start  = H5S_hyper_zeros_g;
10171
0
                        tmp_stride = tmp_count = H5S_hyper_ones_g;
10172
0
                        tmp_block              = space->extent.size;
10173
10174
                        /* Convert to hyperslab selection */
10175
0
                        if (H5S_select_hyperslab(space, H5S_SELECT_SET, tmp_start, tmp_stride, tmp_count,
10176
0
                                                 tmp_block) < 0)
10177
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection");
10178
0
                    } /* end case */
10179
0
                    break;
10180
10181
0
                case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */
10182
                    /* Convert to "none" selection */
10183
0
                    if (H5S_select_none(space) < 0)
10184
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection");
10185
0
                    HGOTO_DONE(SUCCEED);
10186
10187
0
                case H5S_SELECT_NOOP:
10188
0
                case H5S_SELECT_APPEND:
10189
0
                case H5S_SELECT_PREPEND:
10190
0
                case H5S_SELECT_INVALID:
10191
0
                default:
10192
0
                    HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
10193
0
            } /* end switch */
10194
0
            break;
10195
10196
0
        case H5S_SEL_HYPERSLABS:
10197
            /* Hyperslab operation on hyperslab selection, OK */
10198
0
            break;
10199
10200
0
        case H5S_SEL_POINTS:          /* Can't combine hyperslab operations and point selections currently */
10201
0
            if (op == H5S_SELECT_SET) /* Allow only "set" operation to proceed */
10202
0
                break;
10203
            /* FALLTHROUGH (to error) */
10204
0
            H5_ATTR_FALLTHROUGH
10205
10206
0
        case H5S_SEL_ERROR:
10207
0
        case H5S_SEL_N:
10208
0
        default:
10209
0
            HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
10210
0
    } /* end switch */
10211
10212
0
    if (op == H5S_SELECT_SET) {
10213
        /* Set selection to regular hyperslab */
10214
0
        if (H5S__set_regular_hyperslab(space, start, stride, count, block, opt_stride, opt_count, opt_block) <
10215
0
            0)
10216
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't set regular hyperslab selection");
10217
0
    } /* end if */
10218
0
    else if (op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA) {
10219
0
        bool single_block; /* Whether the selection is a single block */
10220
10221
        /* Sanity check */
10222
0
        assert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS);
10223
10224
        /* Handle unlimited selections */
10225
0
        if (unlim_dim >= 0) {
10226
0
            hsize_t bounds_start[H5S_MAX_RANK];
10227
0
            hsize_t bounds_end[H5S_MAX_RANK];
10228
0
            hsize_t tmp_count = opt_count[unlim_dim];
10229
0
            hsize_t tmp_block = opt_block[unlim_dim];
10230
10231
            /* Check for invalid operation */
10232
0
            if (space->select.sel_info.hslab->unlim_dim >= 0)
10233
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL,
10234
0
                            "cannot modify unlimited selection with another unlimited selection");
10235
0
            if (!((op == H5S_SELECT_AND) || (op == H5S_SELECT_NOTB)))
10236
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL,
10237
0
                            "unsupported operation with unlimited selection");
10238
10239
            /* Get bounds of existing selection */
10240
0
            if (H5S__hyper_bounds(space, bounds_start, bounds_end) < 0)
10241
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get selection bounds");
10242
10243
            /* Patch count and block to remove unlimited and include the
10244
             * existing selection.
10245
             */
10246
0
            H5S__hyper_get_clip_diminfo(start[unlim_dim], opt_stride[unlim_dim], &tmp_count, &tmp_block,
10247
0
                                        bounds_end[unlim_dim] + (hsize_t)1);
10248
0
            assert((tmp_count == 1) || (opt_count != H5S_hyper_ones_g));
10249
0
            assert((tmp_block == 1) || (opt_block != H5S_hyper_ones_g));
10250
0
            if (opt_count != H5S_hyper_ones_g) {
10251
0
                assert(opt_count == int_count);
10252
0
                int_count[unlim_dim] = tmp_count;
10253
0
            } /* end if */
10254
0
            if (opt_block != H5S_hyper_ones_g) {
10255
0
                assert(opt_block == int_block);
10256
0
                int_block[unlim_dim] = tmp_block;
10257
0
            } /* end if */
10258
0
        }     /* end if */
10259
10260
        /* Check for a single block selected */
10261
0
        single_block = true;
10262
0
        for (u = 0; u < space->extent.rank; u++)
10263
0
            if (1 != opt_count[u]) {
10264
0
                single_block = false;
10265
0
                break;
10266
0
            } /* end if */
10267
10268
        /* Check for single block "AND" operation on a regular hyperslab, which
10269
         *      is used for constructing chunk maps and can be optimized for.
10270
         */
10271
0
        if (H5S_SELECT_AND == op && single_block &&
10272
0
            space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
10273
0
            if (H5S__hyper_regular_and_single_block(space, start, opt_block) < 0)
10274
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTOPERATE, FAIL,
10275
0
                            "can't 'AND' single block against regular hyperslab");
10276
0
        } /* end if */
10277
0
        else {
10278
            /* Check if there's no hyperslab span information currently */
10279
0
            if (NULL == space->select.sel_info.hslab->span_lst)
10280
0
                if (H5S__hyper_generate_spans(space) < 0)
10281
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree");
10282
10283
            /* Set selection type */
10284
0
            space->select.type = H5S_sel_hyper;
10285
10286
            /* Add in the new hyperslab information */
10287
0
            if (H5S__generate_hyperslab(space, op, start, opt_stride, opt_count, opt_block) < 0)
10288
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs");
10289
0
        } /* end else */
10290
0
    }     /* end if */
10291
0
    else
10292
0
        HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
10293
10294
0
done:
10295
0
    FUNC_LEAVE_NOAPI(ret_value)
10296
0
} /* end H5S_select_hyperslab() */
10297
10298
/*--------------------------------------------------------------------------
10299
 NAME
10300
    H5Sselect_hyperslab
10301
 PURPOSE
10302
    Specify a hyperslab to combine with the current hyperslab selection
10303
 USAGE
10304
    herr_t H5Sselect_hyperslab(dsid, op, start, stride, count, block)
10305
        hid_t dsid;             IN: Dataspace ID of selection to modify
10306
        H5S_seloper_t op;       IN: Operation to perform on current selection
10307
        const hsize_t *start;        IN: Offset of start of hyperslab
10308
        const hsize_t *stride;       IN: Hyperslab stride
10309
        const hsize_t *count;        IN: Number of blocks included in hyperslab
10310
        const hsize_t *block;        IN: Size of block in hyperslab
10311
 RETURNS
10312
    Non-negative on success/Negative on failure
10313
 DESCRIPTION
10314
    Combines a hyperslab selection with the current selection for a dataspace.
10315
    If the current selection is not a hyperslab, it is freed and the hyperslab
10316
    parameters passed in are combined with the H5S_SEL_ALL hyperslab (ie. a
10317
    selection composing the entire current extent).  If STRIDE or BLOCK is
10318
    NULL, they are assumed to be set to all '1'.
10319
 GLOBAL VARIABLES
10320
 COMMENTS, BUGS, ASSUMPTIONS
10321
 EXAMPLES
10322
 REVISION LOG
10323
--------------------------------------------------------------------------*/
10324
herr_t
10325
H5Sselect_hyperslab(hid_t space_id, H5S_seloper_t op, const hsize_t start[], const hsize_t stride[],
10326
                    const hsize_t count[], const hsize_t block[])
10327
0
{
10328
0
    H5S_t *space;               /* Dataspace to modify selection of */
10329
0
    herr_t ret_value = SUCCEED; /* Return value */
10330
10331
0
    FUNC_ENTER_API(FAIL)
10332
10333
    /* Check args */
10334
0
    if (NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
10335
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace");
10336
0
    if (H5S_SCALAR == H5S_GET_EXTENT_TYPE(space))
10337
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hyperslab doesn't support H5S_SCALAR space");
10338
0
    if (H5S_NULL == H5S_GET_EXTENT_TYPE(space))
10339
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hyperslab doesn't support H5S_NULL space");
10340
0
    if (start == NULL || count == NULL)
10341
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab not specified");
10342
0
    if (!(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID))
10343
0
        HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
10344
0
    if (stride != NULL) {
10345
0
        unsigned u; /* Local index variable */
10346
10347
        /* Check for 0-sized strides */
10348
0
        for (u = 0; u < space->extent.rank; u++)
10349
0
            if (stride[u] == 0)
10350
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid stride==0 value");
10351
0
    } /* end if */
10352
10353
0
    if (H5S_select_hyperslab(space, op, start, stride, count, block) < 0)
10354
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection");
10355
10356
0
done:
10357
0
    FUNC_LEAVE_API(ret_value)
10358
0
} /* end H5Sselect_hyperslab() */
10359
10360
/*--------------------------------------------------------------------------
10361
 NAME
10362
    H5S_combine_hyperslab
10363
 PURPOSE
10364
    Specify a hyperslab to combine with the current hyperslab selection, and
10365
    store the result in the new hyperslab selection.
10366
 USAGE
10367
    herr_t H5S_combine_hyperslab(old_space, op, start, stride, count, block, new_space)
10368
        H5S_t *old_space;            IN: The old space the selection is performed on
10369
        H5S_seloper_t op;            IN: Operation to perform on current selection
10370
        const hsize_t start[];       IN: Offset of start of hyperslab
10371
        const hsize_t *stride;       IN: Hyperslab stride
10372
        const hsize_t count[];       IN: Number of blocks included in hyperslab
10373
        const hsize_t *block;        IN: Size of block in hyperslab
10374
        H5S_t **new_space;           OUT: The new dataspace to store the selection result
10375
 RETURNS
10376
    Non-negative on success/Negative on failure
10377
 DESCRIPTION
10378
    Combines a hyperslab selection with the current selection for a dataspace.
10379
    If STRIDE or BLOCK is NULL, they are assumed to be set to all '1'.
10380
 GLOBAL VARIABLES
10381
 COMMENTS, BUGS, ASSUMPTIONS
10382
    In some cases, copying the whole span tree from old_space to new_space
10383
    can be avoided.  Deal with such cases directly, otherwise this function
10384
    is equivalent to:
10385
        1. Copy the whole span tree from old_space into new_space
10386
        2. Call H5S_select_hyperslab with the new_space.
10387
 EXAMPLES
10388
 REVISION LOG
10389
--------------------------------------------------------------------------*/
10390
herr_t
10391
H5S_combine_hyperslab(const H5S_t *old_space, H5S_seloper_t op, const hsize_t start[], const hsize_t *stride,
10392
                      const hsize_t count[], const hsize_t *block, H5S_t **new_space)
10393
0
{
10394
0
    unsigned u;                   /* Local index variable */
10395
0
    herr_t   ret_value = SUCCEED; /* Return value */
10396
10397
0
    FUNC_ENTER_NOAPI(FAIL)
10398
10399
    /* Check args */
10400
0
    assert(old_space);
10401
0
    assert(start);
10402
0
    assert(count);
10403
0
    assert(op >= H5S_SELECT_SET && op <= H5S_SELECT_NOTA);
10404
0
    assert(new_space);
10405
0
    assert(*new_space == NULL);
10406
10407
    /* Point to the correct stride values */
10408
0
    if (stride == NULL)
10409
0
        stride = H5S_hyper_ones_g;
10410
10411
    /* Point to the correct block values */
10412
0
    if (block == NULL)
10413
0
        block = H5S_hyper_ones_g;
10414
10415
    /* Check new selection. */
10416
0
    for (u = 0; u < old_space->extent.rank; u++) {
10417
        /* Check for overlapping hyperslab blocks in new selection. */
10418
0
        if (count[u] > 1 && stride[u] < block[u])
10419
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab blocks overlap");
10420
10421
        /* Detect zero-sized hyperslabs in new selection */
10422
0
        if (count[u] == 0 || block[u] == 0) {
10423
0
            switch (op) {
10424
0
                case H5S_SELECT_AND:  /* Binary "and" operation for hyperslabs */
10425
0
                case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */
10426
                    /* Convert to "none" selection */
10427
                    /* Copy the first dataspace without sharing the list of spans */
10428
0
                    if (NULL == ((*new_space) = H5S_copy(old_space, true, true)))
10429
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy dataspace");
10430
0
                    if (H5S_select_none((*new_space)) < 0)
10431
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection");
10432
0
                    HGOTO_DONE(SUCCEED);
10433
10434
0
                case H5S_SELECT_OR:   /* Binary "or" operation for hyperslabs */
10435
0
                case H5S_SELECT_XOR:  /* Binary "xor" operation for hyperslabs */
10436
0
                case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */
10437
                    /* Copy the first dataspace with sharing the list of spans */
10438
0
                    if (NULL == ((*new_space) = H5S_copy(old_space, false, true)))
10439
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy dataspace");
10440
0
                    HGOTO_DONE(SUCCEED); /* Selection stays same */
10441
10442
0
                case H5S_SELECT_NOOP:
10443
0
                case H5S_SELECT_SET:
10444
0
                case H5S_SELECT_APPEND:
10445
0
                case H5S_SELECT_PREPEND:
10446
0
                case H5S_SELECT_INVALID:
10447
0
                default:
10448
0
                    HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
10449
0
            } /* end switch */
10450
0
        }     /* end if */
10451
0
    }         /* end for */
10452
10453
0
    if (H5S_GET_SELECT_TYPE(old_space) == H5S_SEL_HYPERSLABS) {
10454
0
        hsize_t *old_low_bounds; /* Pointer to old space's low & high bounds */
10455
0
        hsize_t *old_high_bounds;
10456
0
        hsize_t  new_low_bounds[H5S_MAX_RANK]; /* New space's low & high bounds */
10457
0
        hsize_t  new_high_bounds[H5S_MAX_RANK];
10458
0
        bool     overlapped = false;
10459
10460
        /* Set up old space's low & high bounds */
10461
0
        if (old_space->select.sel_info.hslab->span_lst) {
10462
0
            old_low_bounds  = old_space->select.sel_info.hslab->span_lst->low_bounds;
10463
0
            old_high_bounds = old_space->select.sel_info.hslab->span_lst->high_bounds;
10464
0
        } /* end if */
10465
0
        else {
10466
0
            old_low_bounds  = old_space->select.sel_info.hslab->diminfo.low_bounds;
10467
0
            old_high_bounds = old_space->select.sel_info.hslab->diminfo.high_bounds;
10468
0
        } /* end else */
10469
10470
        /* Generate bounding box for hyperslab parameters */
10471
0
        for (u = 0; u < old_space->extent.rank; u++) {
10472
0
            new_low_bounds[u]  = start[u];
10473
0
            new_high_bounds[u] = start[u] + stride[u] * (count[u] - 1) + (block[u] - 1);
10474
0
        } /* end for */
10475
10476
        /* Check bound box of both spaces to see if they overlap */
10477
0
        if (H5_RANGE_OVERLAP(old_low_bounds[0], old_high_bounds[0], new_low_bounds[0], new_high_bounds[0]))
10478
0
            overlapped = true;
10479
10480
        /* Non-overlapping situations can be handled in special ways */
10481
0
        if (!overlapped) {
10482
0
            H5S_hyper_span_info_t *new_spans = NULL;
10483
0
            H5S_hyper_dim_t        new_hyper_diminfo[H5S_MAX_RANK];
10484
10485
0
            if (NULL == ((*new_space) = H5S_copy(old_space, true, true)))
10486
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy dataspace");
10487
0
            if (NULL != (*new_space)->select.sel_info.hslab->span_lst) {
10488
0
                old_space->select.sel_info.hslab->span_lst->count--;
10489
0
                (*new_space)->select.sel_info.hslab->span_lst = NULL;
10490
0
            } /* end if */
10491
10492
            /* Generate hyperslab info for new space */
10493
0
            switch (op) {
10494
0
                case H5S_SELECT_OR:
10495
0
                case H5S_SELECT_XOR:
10496
                    /* Add the new space to the space */
10497
0
                    if (NULL == (new_spans = H5S__hyper_make_spans(old_space->extent.rank, start, stride,
10498
0
                                                                   count, block)))
10499
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL,
10500
0
                                    "can't create hyperslab information");
10501
0
                    if (NULL != old_space->select.sel_info.hslab->span_lst)
10502
0
                        (*new_space)->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(
10503
0
                            old_space->select.sel_info.hslab->span_lst, old_space->extent.rank);
10504
0
                    if (H5S__hyper_add_disjoint_spans(*new_space, new_spans) < 0)
10505
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't append hyperslabs");
10506
10507
                    /* Build diminfo struct */
10508
0
                    for (u = 0; u < (*new_space)->extent.rank; u++) {
10509
0
                        new_hyper_diminfo[u].start  = start[u];
10510
0
                        new_hyper_diminfo[u].stride = stride[u];
10511
0
                        new_hyper_diminfo[u].count  = count[u];
10512
0
                        new_hyper_diminfo[u].block  = block[u];
10513
0
                    } /* end for */
10514
10515
                    /* Update space's dim info */
10516
0
                    if (H5S__hyper_update_diminfo(*new_space, op, new_hyper_diminfo) < 0)
10517
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't update hyperslab info");
10518
0
                    break;
10519
10520
0
                case H5S_SELECT_AND:
10521
0
                    if (H5S_select_none((*new_space)) < 0)
10522
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection");
10523
0
                    break;
10524
10525
0
                case H5S_SELECT_NOTB:
10526
0
                    if (NULL != old_space->select.sel_info.hslab->span_lst) {
10527
0
                        if (NULL == ((*new_space)->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(
10528
0
                                         old_space->select.sel_info.hslab->span_lst, old_space->extent.rank)))
10529
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy dataspace");
10530
0
                    } /* end if */
10531
0
                    else {
10532
0
                        if (H5S_select_none((*new_space)) < 0)
10533
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection");
10534
0
                    } /* end else */
10535
0
                    break;
10536
10537
0
                case H5S_SELECT_NOTA:
10538
0
                    if (H5S__set_regular_hyperslab(*new_space, start, stride, count, block, stride, count,
10539
0
                                                   block) < 0)
10540
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't set regular selection");
10541
0
                    break;
10542
10543
0
                case H5S_SELECT_NOOP:
10544
0
                case H5S_SELECT_SET:
10545
0
                case H5S_SELECT_APPEND:
10546
0
                case H5S_SELECT_PREPEND:
10547
0
                case H5S_SELECT_INVALID:
10548
0
                default:
10549
0
                    HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
10550
0
            } /* end switch */
10551
10552
0
            HGOTO_DONE(SUCCEED);
10553
0
        } /* end if(!overlapped) */
10554
0
    }     /* end if the selection of old space is H5S_SEL_HYPERSLABS */
10555
10556
    /* Copy the first dataspace with sharing the list of spans */
10557
0
    if (NULL == ((*new_space) = H5S_copy(old_space, true, true)))
10558
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy dataspace");
10559
10560
    /* Note: a little overhead in calling the function as some conditions are checked again */
10561
0
    if (H5S_select_hyperslab(*new_space, op, start, stride, count, block) < 0)
10562
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection");
10563
10564
0
done:
10565
0
    FUNC_LEAVE_NOAPI(ret_value)
10566
0
} /* end H5S_combine_hyperslab() */
10567
10568
/*-------------------------------------------------------------------------
10569
 * Function:    H5S__fill_in_select
10570
 *
10571
 * Purpose:    Combines two hyperslabs with an operation, putting the
10572
 *              result into a third hyperslab selection
10573
 *
10574
 * Return:    Non-negative on success/negative on failure
10575
 *
10576
 *-------------------------------------------------------------------------
10577
 */
10578
static herr_t
10579
H5S__fill_in_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2, H5S_t **result)
10580
0
{
10581
0
    bool   span2_owned;
10582
0
    bool   updated_spans;
10583
0
    herr_t ret_value = SUCCEED; /* Return value */
10584
10585
0
    FUNC_ENTER_PACKAGE
10586
10587
    /* Sanity check */
10588
0
    assert(space1);
10589
0
    assert(space2);
10590
0
    assert(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA);
10591
0
    assert(space1->extent.rank == space2->extent.rank);
10592
    /* The result is either a to-be-created space or an empty one */
10593
0
    assert(NULL == *result || *result == space1);
10594
0
    assert(space1->select.sel_info.hslab->span_lst);
10595
0
    assert(space2->select.sel_info.hslab->span_lst);
10596
10597
    /* Note: the offset of space2 is not considered here for bounding box */
10598
0
    if (H5S__fill_in_new_space(space1, op, space2->select.sel_info.hslab->span_lst, false, &span2_owned,
10599
0
                               &updated_spans, result) < 0)
10600
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't create the specified selection");
10601
10602
    /* Update diminfo if space2's diminfo was valid, otherwise just mark it as
10603
     * invalid if the spans were updated */
10604
0
    assert(result);
10605
0
    if (updated_spans) {
10606
0
        if (space2->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
10607
0
            if (H5S__hyper_update_diminfo(*result, op, space2->select.sel_info.hslab->diminfo.opt) < 0)
10608
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't update hyperslab info");
10609
0
        } /* end if */
10610
0
        else
10611
0
            (*result)->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
10612
0
    } /* end if */
10613
10614
0
done:
10615
0
    FUNC_LEAVE_NOAPI(ret_value)
10616
0
} /* end H5S__fill_in_select() */
10617
10618
/*--------------------------------------------------------------------------
10619
 NAME
10620
    H5Scombine_hyperslab
10621
 PURPOSE
10622
    Specify a hyperslab to combine with the current hyperslab selection and
10623
    return a new dataspace with the combined selection as the selection in the
10624
    new dataspace.
10625
 USAGE
10626
    hid_t H5Scombine_hyperslab(dsid, op, start, stride, count, block)
10627
        hid_t dsid;             IN: Dataspace ID of selection to use
10628
        H5S_seloper_t op;       IN: Operation to perform on current selection
10629
        const hsize_t *start;        IN: Offset of start of hyperslab
10630
        const hsize_t *stride;       IN: Hyperslab stride
10631
        const hsize_t *count;        IN: Number of blocks included in hyperslab
10632
        const hsize_t *block;        IN: Size of block in hyperslab
10633
 RETURNS
10634
    Dataspace ID on success / H5I_INVALID_HID on failure
10635
 DESCRIPTION
10636
    Combines a hyperslab selection with the current selection for a dataspace,
10637
    creating a new dataspace to return the generated selection.
10638
    If the current selection is not a hyperslab, it is freed and the hyperslab
10639
    parameters passed in are combined with the H5S_SEL_ALL hyperslab (ie. a
10640
    selection composing the entire current extent).  If STRIDE or BLOCK is
10641
    NULL, they are assumed to be set to all '1'.
10642
 GLOBAL VARIABLES
10643
 COMMENTS, BUGS, ASSUMPTIONS
10644
 EXAMPLES
10645
 REVISION LOG
10646
--------------------------------------------------------------------------*/
10647
hid_t
10648
H5Scombine_hyperslab(hid_t space_id, H5S_seloper_t op, const hsize_t start[], const hsize_t stride[],
10649
                     const hsize_t count[], const hsize_t block[])
10650
0
{
10651
0
    H5S_t *space;            /* Dataspace to modify selection of */
10652
0
    H5S_t *new_space = NULL; /* New dataspace created */
10653
0
    hid_t  ret_value;        /* Return value */
10654
10655
0
    FUNC_ENTER_API(H5I_INVALID_HID)
10656
10657
    /* Check args */
10658
0
    if (NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
10659
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not a dataspace");
10660
0
    if (start == NULL || count == NULL)
10661
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "hyperslab not specified");
10662
0
    if (!(op >= H5S_SELECT_SET && op <= H5S_SELECT_NOTA))
10663
0
        HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, H5I_INVALID_HID, "invalid selection operation");
10664
10665
    /* Generate new space, with combination of selections */
10666
0
    if (H5S_combine_hyperslab(space, op, start, stride, count, block, &new_space) < 0)
10667
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, H5I_INVALID_HID, "unable to set hyperslab selection");
10668
10669
    /* Register */
10670
0
    if ((ret_value = H5I_register(H5I_DATASPACE, new_space, true)) < 0)
10671
0
        HGOTO_ERROR(H5E_ID, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register dataspace ID");
10672
10673
0
done:
10674
0
    if (ret_value < 0 && new_space)
10675
0
        H5S_close(new_space);
10676
10677
0
    FUNC_LEAVE_API(ret_value)
10678
0
} /* end H5Scombine_hyperslab() */
10679
10680
/*-------------------------------------------------------------------------
10681
 * Function:    H5S__combine_select
10682
 *
10683
 * Purpose:     Internal version of H5Scombine_select().
10684
 *
10685
 * Return:      New dataspace on success/NULL on failure
10686
 *
10687
 *-------------------------------------------------------------------------
10688
 */
10689
static H5S_t *
10690
H5S__combine_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2)
10691
0
{
10692
0
    H5S_t *new_space = NULL; /* New dataspace generated */
10693
0
    H5S_t *ret_value = NULL; /* Return value */
10694
10695
0
    FUNC_ENTER_PACKAGE
10696
10697
    /* Check args */
10698
0
    assert(space1);
10699
0
    assert(space2);
10700
0
    assert(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA);
10701
10702
    /* Check if space1 selections has span trees */
10703
0
    if (NULL == space1->select.sel_info.hslab->span_lst)
10704
0
        if (H5S__hyper_generate_spans(space1) < 0)
10705
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, NULL, "dataspace does not have span tree");
10706
10707
0
    if (NULL == space2->select.sel_info.hslab->span_lst) {
10708
0
        hsize_t  tmp_start[H5S_MAX_RANK];
10709
0
        hsize_t  tmp_stride[H5S_MAX_RANK];
10710
0
        hsize_t  tmp_count[H5S_MAX_RANK];
10711
0
        hsize_t  tmp_block[H5S_MAX_RANK];
10712
0
        unsigned u;
10713
10714
0
        for (u = 0; u < space2->extent.rank; u++) {
10715
0
            tmp_start[u]  = space2->select.sel_info.hslab->diminfo.opt[u].start;
10716
0
            tmp_stride[u] = space2->select.sel_info.hslab->diminfo.opt[u].stride;
10717
0
            tmp_count[u]  = space2->select.sel_info.hslab->diminfo.opt[u].count;
10718
0
            tmp_block[u]  = space2->select.sel_info.hslab->diminfo.opt[u].block;
10719
0
        } /* end for */
10720
10721
        /* Combine hyperslab selection with regular selection directly */
10722
0
        if (H5S_combine_hyperslab(space1, op, tmp_start, tmp_stride, tmp_count, tmp_block, &new_space) < 0)
10723
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, NULL, "unable to set hyperslab selection");
10724
0
    } /* end if */
10725
0
    else {
10726
        /* Combine new_space (a copy of space 1) & space2, with the result in new_space */
10727
0
        if (H5S__fill_in_select(space1, op, space2, &new_space) < 0)
10728
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, NULL, "can't clip hyperslab information");
10729
0
    } /* end else */
10730
10731
    /* Set unlim_dim */
10732
0
    if (H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(new_space))
10733
0
        new_space->select.sel_info.hslab->unlim_dim = -1;
10734
10735
    /* Set return value */
10736
0
    ret_value = new_space;
10737
10738
0
done:
10739
0
    if (ret_value == NULL && new_space)
10740
0
        H5S_close(new_space);
10741
10742
0
    FUNC_LEAVE_NOAPI(ret_value)
10743
0
} /* end H5S__combine_select() */
10744
10745
/*--------------------------------------------------------------------------
10746
 NAME
10747
    H5Scombine_select
10748
 PURPOSE
10749
    Combine two hyperslab selections with an operation, returning a dataspace
10750
    with the resulting selection.
10751
 USAGE
10752
    hid_t H5Scombine_select(space1, op, space2)
10753
        hid_t space1;           IN: First Dataspace ID
10754
        H5S_seloper_t op;       IN: Selection operation
10755
        hid_t space2;           IN: Second Dataspace ID
10756
 RETURNS
10757
    Dataspace ID on success / H5I_INVALID_HID on failure
10758
 DESCRIPTION
10759
    Combine two existing hyperslab selections with an operation, returning
10760
    a new dataspace with the resulting selection.  The dataspace extent from
10761
    space1 is copied for the dataspace extent of the newly created dataspace.
10762
 GLOBAL VARIABLES
10763
 COMMENTS, BUGS, ASSUMPTIONS
10764
 EXAMPLES
10765
 REVISION LOG
10766
--------------------------------------------------------------------------*/
10767
hid_t
10768
H5Scombine_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id)
10769
0
{
10770
0
    H5S_t *space1;           /* First Dataspace */
10771
0
    H5S_t *space2;           /* Second Dataspace */
10772
0
    H5S_t *new_space = NULL; /* New Dataspace */
10773
0
    hid_t  ret_value;        /* Return value */
10774
10775
0
    FUNC_ENTER_API(H5I_INVALID_HID)
10776
10777
    /* Check args */
10778
0
    if (NULL == (space1 = (H5S_t *)H5I_object_verify(space1_id, H5I_DATASPACE)))
10779
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not a dataspace");
10780
0
    if (NULL == (space2 = (H5S_t *)H5I_object_verify(space2_id, H5I_DATASPACE)))
10781
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not a dataspace");
10782
0
    if (!(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA))
10783
0
        HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, H5I_INVALID_HID, "invalid selection operation");
10784
10785
    /* Check that both dataspaces have the same rank */
10786
0
    if (space1->extent.rank != space2->extent.rank)
10787
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "dataspaces not same rank");
10788
10789
        /* Note: currently, the offset of each dataspace is ignored */
10790
#if 0
10791
    /* Check that both dataspaces have the same offset */
10792
    /* Same note as in H5Smodify_select */
10793
    for(u=0; u<space1->extent.rank; u++) {
10794
        if(space1->select.offset[u] != space2->select.offset[u])
10795
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "dataspaces not same offset");
10796
    } /* end for */
10797
#endif
10798
10799
    /* Check that both dataspaces have hyperslab selections */
10800
0
    if (H5S_GET_SELECT_TYPE(space1) != H5S_SEL_HYPERSLABS ||
10801
0
        H5S_GET_SELECT_TYPE(space2) != H5S_SEL_HYPERSLABS)
10802
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "dataspaces don't have hyperslab selections");
10803
10804
    /* Go combine the dataspaces */
10805
0
    if (NULL == (new_space = H5S__combine_select(space1, op, space2)))
10806
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, H5I_INVALID_HID, "unable to create hyperslab selection");
10807
10808
    /* Register */
10809
0
    if ((ret_value = H5I_register(H5I_DATASPACE, new_space, true)) < 0)
10810
0
        HGOTO_ERROR(H5E_ID, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register dataspace ID");
10811
10812
0
done:
10813
0
    if (ret_value < 0 && new_space)
10814
0
        H5S_close(new_space);
10815
10816
0
    FUNC_LEAVE_API(ret_value)
10817
0
} /* end H5Scombine_select() */
10818
10819
/*-------------------------------------------------------------------------
10820
 * Function:    H5S__modify_select
10821
 *
10822
 * Purpose:     Internal version of H5Smodify_select().
10823
 *
10824
 * Return:      New dataspace on success/NULL on failure
10825
 *
10826
 *-------------------------------------------------------------------------
10827
 */
10828
herr_t
10829
H5S__modify_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2)
10830
0
{
10831
0
    herr_t ret_value = SUCCEED; /* Return value */
10832
10833
0
    FUNC_ENTER_PACKAGE
10834
10835
    /* Check args */
10836
0
    assert(space1);
10837
0
    assert(space2);
10838
0
    assert(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA);
10839
10840
    /* Check that the space selections both have span trees */
10841
0
    if (NULL == space1->select.sel_info.hslab->span_lst)
10842
0
        if (H5S__hyper_generate_spans(space1) < 0)
10843
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree");
10844
10845
    /* Set unlim_dim */
10846
0
    space1->select.sel_info.hslab->unlim_dim = -1;
10847
10848
0
    if (NULL == space2->select.sel_info.hslab->span_lst) {
10849
0
        hsize_t  tmp_start[H5S_MAX_RANK];
10850
0
        hsize_t  tmp_stride[H5S_MAX_RANK];
10851
0
        hsize_t  tmp_count[H5S_MAX_RANK];
10852
0
        hsize_t  tmp_block[H5S_MAX_RANK];
10853
0
        unsigned u;
10854
10855
0
        for (u = 0; u < space2->extent.rank; u++) {
10856
0
            tmp_start[u]  = space2->select.sel_info.hslab->diminfo.opt[u].start;
10857
0
            tmp_stride[u] = space2->select.sel_info.hslab->diminfo.opt[u].stride;
10858
0
            tmp_count[u]  = space2->select.sel_info.hslab->diminfo.opt[u].count;
10859
0
            tmp_block[u]  = space2->select.sel_info.hslab->diminfo.opt[u].block;
10860
0
        } /* end for */
10861
10862
        /* Call H5S_select_hyperslab directly */
10863
0
        if (H5S_select_hyperslab(space1, op, tmp_start, tmp_stride, tmp_count, tmp_block) < 0)
10864
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection");
10865
0
    } /* end if */
10866
0
    else
10867
        /* Combine spans from space1 & spans from space2, with the result in space1 */
10868
0
        if (H5S__fill_in_select(space1, op, space2, &space1) < 0)
10869
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't perform operation on two selections");
10870
10871
0
done:
10872
0
    FUNC_LEAVE_NOAPI(ret_value)
10873
0
} /* end H5S__modify_select() */
10874
10875
/*--------------------------------------------------------------------------
10876
 NAME
10877
    H5Smodify_select
10878
 PURPOSE
10879
    Refine a hyperslab selection with an operation using a second hyperslab
10880
    to modify it
10881
 USAGE
10882
    herr_t H5Smodify_select(space1, op, space2)
10883
        hid_t space1;           IN/OUT: First Dataspace ID
10884
        H5S_seloper_t op;       IN: Selection operation
10885
        hid_t space2;           IN: Second Dataspace ID
10886
 RETURNS
10887
    Non-negative on success/Negative on failure
10888
 DESCRIPTION
10889
    Refine an existing hyperslab selection with an operation, using a second
10890
    hyperslab.  The first selection is modified to contain the result of
10891
    space1 operated on by space2.
10892
 GLOBAL VARIABLES
10893
 COMMENTS, BUGS, ASSUMPTIONS
10894
 EXAMPLES
10895
 REVISION LOG
10896
--------------------------------------------------------------------------*/
10897
herr_t
10898
H5Smodify_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id)
10899
0
{
10900
0
    H5S_t *space1;              /* First Dataspace */
10901
0
    H5S_t *space2;              /* Second Dataspace */
10902
0
    herr_t ret_value = SUCCEED; /* Return value */
10903
10904
0
    FUNC_ENTER_API(FAIL)
10905
10906
    /* Check args */
10907
0
    if (NULL == (space1 = (H5S_t *)H5I_object_verify(space1_id, H5I_DATASPACE)))
10908
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace");
10909
0
    if (NULL == (space2 = (H5S_t *)H5I_object_verify(space2_id, H5I_DATASPACE)))
10910
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace");
10911
0
    if (!(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA))
10912
0
        HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
10913
10914
    /* Check that both dataspaces have the same rank */
10915
0
    if (space1->extent.rank != space2->extent.rank)
10916
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces not same rank");
10917
10918
        /* Check that both dataspaces have the same offset */
10919
        /** Note that this is a tricky part of this function. It's
10920
         *  possible that two dataspaces have different "offset". If the
10921
         *  space2 has smaller offset value than that of space1 in a
10922
         *  dimension, then the span elements of this dimension in
10923
         *  space2 could have negative "low" and "high" values relative
10924
         *  to the offset in space1. In other words, if the bounds of
10925
         *  span elements in space2 are adjusted relative to the offset
10926
         *  in space1, then every span element's bound is computed as
10927
         *  "origin_bound+offset2-offset1". Therefore, if offset2 (the
10928
         *  offset of space2) is smaller, then
10929
         *  "origin_bound+offset2-offset1" could be negative which is
10930
         *  not allowed by the bound type declaration as hsize_t!
10931
         *  As a result, if the op is an OR selection, then the final
10932
         *  result may contain span elements that have negative bound!
10933
         *  So right now, the difference in the offset is totally
10934
         *  ignored!!
10935
         */
10936
#if 0
10937
    for(u=0; u<space1->extent.rank; u++) {
10938
        if(space1->select.offset[u] != space2->select.offset[u])
10939
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces not same offset");
10940
    } /* end for */
10941
#endif
10942
10943
    /* Check that both dataspaces have hyperslab selections */
10944
0
    if (H5S_GET_SELECT_TYPE(space1) != H5S_SEL_HYPERSLABS ||
10945
0
        H5S_GET_SELECT_TYPE(space2) != H5S_SEL_HYPERSLABS)
10946
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces don't have hyperslab selections");
10947
10948
    /* Go refine the first selection */
10949
0
    if (H5S__modify_select(space1, op, space2) < 0)
10950
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to modify hyperslab selection");
10951
10952
0
done:
10953
0
    FUNC_LEAVE_API(ret_value)
10954
0
} /* end H5Smodify_select() */
10955
10956
/*--------------------------------------------------------------------------
10957
 NAME
10958
    H5S__hyper_proj_int_build_proj
10959
 PURPOSE
10960
    Secondary iteration routine for H5S__hyper_project_intersection
10961
 USAGE
10962
    herr_t H5S__hyper_proj_int_build_proj(udata)
10963
        H5S_hyper_project_intersect_ud_t *udata; IN/OUT: Persistent shared data for iteration
10964
 RETURNS
10965
    Non-negative on success/Negative on failure.
10966
 DESCRIPTION
10967
    Takes the skip and nelem amounts listed in udata and converts them to
10968
    span trees in the projected space, using the destination space.  This
10969
    is a non-recursive algorithm by necessity, it saves the current state
10970
    of iteration in udata and resumes in the same location on subsequent
10971
    calls.
10972
 GLOBAL VARIABLES
10973
 COMMENTS, BUGS, ASSUMPTIONS
10974
 EXAMPLES
10975
 REVISION LOG
10976
--------------------------------------------------------------------------*/
10977
static herr_t
10978
H5S__hyper_proj_int_build_proj(H5S_hyper_project_intersect_ud_t *udata)
10979
0
{
10980
0
    H5S_hyper_span_info_t *copied_span_info = NULL;    /* Temporary span info pointer */
10981
0
    herr_t                 ret_value        = SUCCEED; /* Return value */
10982
10983
0
    FUNC_ENTER_PACKAGE
10984
10985
0
    assert(udata->nelem > 0);
10986
10987
    /*
10988
     * Skip over skipped elements
10989
     */
10990
0
    if (udata->skip > 0) {
10991
        /* Work upwards, finishing each span tree before moving up */
10992
0
        assert(udata->ds_span[udata->depth]);
10993
0
        do {
10994
            /* Check for lowest dimension */
10995
0
            if (udata->ds_span[udata->depth]->down) {
10996
0
                if (udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high) {
10997
                    /* If we will run out of elements to skip in this span,
10998
                     * advance to the first not fully skipped span and break
10999
                     * out of this loop (start moving downwards) */
11000
0
                    if (udata->skip <
11001
0
                        H5S__hyper_spans_nelem_helper(udata->ds_span[udata->depth]->down, 0, udata->op_gen) *
11002
0
                            (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
11003
0
                        udata->ds_low[udata->depth] +=
11004
0
                            udata->skip / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
11005
0
                        udata->skip %= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
11006
0
                        break;
11007
0
                    } /* end if */
11008
11009
                    /* Skip over this entire span */
11010
0
                    udata->skip -= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts *
11011
0
                                   (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1);
11012
0
                } /* end if */
11013
0
            }     /* end if */
11014
0
            else {
11015
0
                assert(udata->ds_rank - udata->depth == 1);
11016
11017
                /* If we will run out of elements to skip in this span,
11018
                 * skip the remainder of the skipped elements and break out */
11019
0
                assert(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high);
11020
0
                if (udata->skip < (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
11021
0
                    udata->ds_low[udata->depth] += udata->skip;
11022
0
                    udata->skip = 0;
11023
0
                    break;
11024
0
                } /* end if */
11025
11026
                /* Skip over this entire span */
11027
0
                udata->skip -= udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1;
11028
0
            } /* end else */
11029
11030
            /* Advance to next span */
11031
0
            udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next;
11032
0
            if (udata->ds_span[udata->depth])
11033
0
                udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
11034
0
            else if (udata->depth > 0) {
11035
                /* If present, append this span tree to the higher dimension's,
11036
                 * and release ownership of it */
11037
0
                if (udata->ps_span_info[udata->depth]) {
11038
0
                    if (H5S__hyper_append_span(
11039
0
                            &udata->ps_span_info[udata->depth - 1], udata->ds_rank - udata->depth + 1,
11040
0
                            udata->ds_low[udata->depth - 1], udata->ds_low[udata->depth - 1],
11041
0
                            udata->ps_span_info[udata->depth]) < 0)
11042
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11043
0
                    if (H5S__hyper_free_span_info(udata->ps_span_info[udata->depth]) < 0)
11044
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11045
0
                    udata->ps_span_info[udata->depth] = NULL;
11046
0
                }
11047
11048
                /* Ran out of spans, move up one dimension */
11049
0
                udata->depth--;
11050
0
                assert(udata->ds_span[udata->depth]);
11051
0
                udata->ds_low[udata->depth]++;
11052
0
            }
11053
0
            else
11054
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL,
11055
0
                            "insufficient elements in destination selection");
11056
0
        } while ((udata->skip > 0) || (udata->ds_low[udata->depth] > udata->ds_span[udata->depth]->high));
11057
11058
        /* Work downwards until skip is 0 */
11059
0
        assert(udata->ds_span[udata->depth]);
11060
0
        while (udata->skip > 0) {
11061
0
            assert(udata->ds_span[udata->depth]->down);
11062
0
            udata->depth++;
11063
0
            udata->ds_span[udata->depth] = udata->ds_span[udata->depth - 1]->down->head;
11064
0
            udata->ds_low[udata->depth]  = udata->ds_span[udata->depth]->low;
11065
0
            if (udata->ds_span[udata->depth]->down) {
11066
0
                do {
11067
                    /* If we will run out of elements to skip in this span,
11068
                     * advance to the first not fully skipped span and
11069
                     * continue down */
11070
0
                    if (udata->skip <
11071
0
                        H5S__hyper_spans_nelem_helper(udata->ds_span[udata->depth]->down, 0, udata->op_gen) *
11072
0
                            (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
11073
0
                        udata->ds_low[udata->depth] +=
11074
0
                            udata->skip / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
11075
0
                        udata->skip %= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
11076
0
                        break;
11077
0
                    } /* end if */
11078
11079
                    /* Skip over this entire span */
11080
0
                    udata->skip -= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts *
11081
0
                                   (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1);
11082
11083
                    /* Advance to next span */
11084
0
                    udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next;
11085
0
                    assert(udata->ds_span[udata->depth]);
11086
0
                    udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
11087
0
                } while (udata->skip > 0);
11088
0
            } /* end if */
11089
0
            else {
11090
0
                do {
11091
                    /* If we will run out of elements to skip in this span,
11092
                     * skip the remainder of the skipped elements */
11093
0
                    if (udata->skip <
11094
0
                        (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
11095
0
                        udata->ds_low[udata->depth] += udata->skip;
11096
0
                        udata->skip = 0;
11097
0
                        break;
11098
0
                    } /* end if */
11099
11100
                    /* Skip over this entire span */
11101
0
                    udata->skip -= udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1;
11102
11103
                    /* Advance to next span */
11104
0
                    udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next;
11105
0
                    assert(udata->ds_span[udata->depth]);
11106
0
                    udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
11107
0
                } while (udata->skip > 0);
11108
0
            } /* end else */
11109
0
        }     /* end while */
11110
0
    }         /* end if */
11111
11112
    /*
11113
     * Add requested number of elements to projected space
11114
     */
11115
    /* Work upwards, adding all elements of each span tree until it can't fit
11116
     * all elements */
11117
0
    assert(udata->ds_span[udata->depth]);
11118
0
    do {
11119
        /* Check for lowest dimension */
11120
0
        if (udata->ds_span[udata->depth]->down) {
11121
0
            if (udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high) {
11122
                /* If we will run out of elements to add in this span, add
11123
                 * any complete spans, advance to the first not fully added
11124
                 * span, and break out of this loop (start moving downwards)
11125
                 */
11126
0
                if (udata->nelem <
11127
0
                    H5S__hyper_spans_nelem_helper(udata->ds_span[udata->depth]->down, 0, udata->op_gen) *
11128
0
                        (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
11129
0
                    if (udata->nelem >= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) {
11130
0
                        if (udata->share_selection) {
11131
0
                            if (H5S__hyper_append_span(
11132
0
                                    &udata->ps_span_info[udata->depth], udata->ds_rank - udata->depth,
11133
0
                                    udata->ds_low[udata->depth],
11134
0
                                    udata->ds_low[udata->depth] +
11135
0
                                        (udata->nelem /
11136
0
                                         udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) -
11137
0
                                        1,
11138
0
                                    udata->ds_span[udata->depth]->down) < 0)
11139
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
11140
0
                                            "can't allocate hyperslab span");
11141
0
                        }
11142
0
                        else {
11143
                            /* If we're not sharing the destination space's
11144
                             * spans, we must copy it first (then release it
11145
                             * afterwards) */
11146
0
                            if (NULL == (copied_span_info = H5S__hyper_copy_span_helper(
11147
0
                                             udata->ds_span[udata->depth]->down,
11148
0
                                             udata->ds_rank - udata->depth, 1, udata->op_gen)))
11149
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL,
11150
0
                                            "can't copy destination spans");
11151
0
                            if (H5S__hyper_append_span(
11152
0
                                    &udata->ps_span_info[udata->depth], udata->ds_rank - udata->depth,
11153
0
                                    udata->ds_low[udata->depth],
11154
0
                                    udata->ds_low[udata->depth] +
11155
0
                                        (udata->nelem /
11156
0
                                         udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) -
11157
0
                                        1,
11158
0
                                    copied_span_info) < 0)
11159
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
11160
0
                                            "can't allocate hyperslab span");
11161
0
                            if (H5S__hyper_free_span_info(copied_span_info) < 0)
11162
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11163
0
                            copied_span_info = NULL;
11164
0
                        }
11165
0
                        udata->ds_low[udata->depth] +=
11166
0
                            udata->nelem / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
11167
0
                        udata->nelem %= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
11168
0
                    } /* end if */
11169
0
                    break;
11170
0
                } /* end if */
11171
11172
                /* Append span tree for entire span */
11173
0
                if (udata->share_selection) {
11174
0
                    if (H5S__hyper_append_span(&udata->ps_span_info[udata->depth],
11175
0
                                               udata->ds_rank - udata->depth, udata->ds_low[udata->depth],
11176
0
                                               udata->ds_span[udata->depth]->high,
11177
0
                                               udata->ds_span[udata->depth]->down) < 0)
11178
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11179
0
                }
11180
0
                else {
11181
                    /* If we're not sharing the destination space's
11182
                     * spans, we must copy it first (then release it
11183
                     * afterwards) */
11184
0
                    if (NULL == (copied_span_info = H5S__hyper_copy_span_helper(
11185
0
                                     udata->ds_span[udata->depth]->down, udata->ds_rank - udata->depth, 1,
11186
0
                                     udata->op_gen)))
11187
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy destination spans");
11188
0
                    if (H5S__hyper_append_span(&udata->ps_span_info[udata->depth],
11189
0
                                               udata->ds_rank - udata->depth, udata->ds_low[udata->depth],
11190
0
                                               udata->ds_span[udata->depth]->high, copied_span_info) < 0)
11191
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11192
0
                    if (H5S__hyper_free_span_info(copied_span_info) < 0)
11193
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11194
0
                    copied_span_info = NULL;
11195
0
                }
11196
0
                udata->nelem -= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts *
11197
0
                                (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1);
11198
0
            } /* end if */
11199
0
        }     /* end if */
11200
0
        else {
11201
0
            assert(udata->ds_rank - udata->depth == 1);
11202
11203
            /* If we will run out of elements to add in this span, add the
11204
             * remainder of the elements and break out */
11205
0
            assert(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high);
11206
0
            if (udata->nelem < (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
11207
0
                if (H5S__hyper_append_span(&udata->ps_span_info[udata->depth], 1, udata->ds_low[udata->depth],
11208
0
                                           udata->ds_low[udata->depth] + udata->nelem - 1, NULL) < 0)
11209
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11210
0
                udata->ds_low[udata->depth] += udata->nelem;
11211
0
                udata->nelem = 0;
11212
0
                break;
11213
0
            } /* end if */
11214
11215
            /* Append span tree for entire span */
11216
0
            if (H5S__hyper_append_span(&udata->ps_span_info[udata->depth], 1, udata->ds_low[udata->depth],
11217
0
                                       udata->ds_span[udata->depth]->high, NULL) < 0)
11218
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11219
0
            udata->nelem -= udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1;
11220
0
        } /* end else */
11221
11222
        /* Advance to next span */
11223
0
        udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next;
11224
0
        if (udata->ds_span[udata->depth])
11225
0
            udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
11226
0
        else if (udata->depth > 0) {
11227
            /* Append this span tree to the higher dimension's, and release
11228
             * ownership of it */
11229
0
            assert(udata->ps_span_info[udata->depth]);
11230
0
            if (H5S__hyper_append_span(&udata->ps_span_info[udata->depth - 1],
11231
0
                                       udata->ds_rank - udata->depth + 1, udata->ds_low[udata->depth - 1],
11232
0
                                       udata->ds_low[udata->depth - 1],
11233
0
                                       udata->ps_span_info[udata->depth]) < 0)
11234
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11235
0
            if (H5S__hyper_free_span_info(udata->ps_span_info[udata->depth]) < 0)
11236
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11237
0
            udata->ps_span_info[udata->depth] = NULL;
11238
11239
            /* Ran out of spans, move up one dimension */
11240
0
            udata->depth--;
11241
0
            assert(udata->ds_span[udata->depth]);
11242
0
            udata->ds_low[udata->depth]++;
11243
0
        } /* end if */
11244
0
        else {
11245
            /* We have finished the entire destination span tree.  If there are
11246
             * still elements to add, issue an error. */
11247
0
            if (udata->nelem > 0)
11248
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL,
11249
0
                            "insufficient elements in destination selection");
11250
0
            break;
11251
0
        } /* end else */
11252
0
    } while ((udata->nelem > 0) || (udata->ds_low[udata->depth] > udata->ds_span[udata->depth]->high));
11253
11254
    /* Work downwards until nelem is 0 */
11255
0
    assert(udata->ds_span[udata->depth] || (udata->nelem == 0));
11256
0
    while (udata->nelem > 0) {
11257
0
        assert(udata->ds_span[udata->depth]->down);
11258
0
        udata->depth++;
11259
0
        udata->ds_span[udata->depth] = udata->ds_span[udata->depth - 1]->down->head;
11260
0
        udata->ds_low[udata->depth]  = udata->ds_span[udata->depth]->low;
11261
0
        if (udata->ds_span[udata->depth]->down) {
11262
0
            do {
11263
                /* If we will run out of elements to add in this span, add
11264
                 * any complete spans, advance to the first not fully added
11265
                 * span and continue down
11266
                 */
11267
0
                assert(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high);
11268
0
                if (udata->nelem <
11269
0
                    H5S__hyper_spans_nelem_helper(udata->ds_span[udata->depth]->down, 0, udata->op_gen) *
11270
0
                        (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
11271
0
                    if (udata->nelem >= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) {
11272
0
                        if (udata->share_selection) {
11273
0
                            if (H5S__hyper_append_span(
11274
0
                                    &udata->ps_span_info[udata->depth], udata->ds_rank - udata->depth,
11275
0
                                    udata->ds_low[udata->depth],
11276
0
                                    udata->ds_low[udata->depth] +
11277
0
                                        (udata->nelem /
11278
0
                                         udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) -
11279
0
                                        1,
11280
0
                                    udata->ds_span[udata->depth]->down) < 0)
11281
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
11282
0
                                            "can't allocate hyperslab span");
11283
0
                        }
11284
0
                        else {
11285
                            /* If we're not sharing the destination space's
11286
                             * spans, we must copy it first (then release it
11287
                             * afterwards) */
11288
0
                            if (NULL == (copied_span_info = H5S__hyper_copy_span_helper(
11289
0
                                             udata->ds_span[udata->depth]->down,
11290
0
                                             udata->ds_rank - udata->depth, 1, udata->op_gen)))
11291
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL,
11292
0
                                            "can't copy destination spans");
11293
0
                            if (H5S__hyper_append_span(
11294
0
                                    &udata->ps_span_info[udata->depth], udata->ds_rank - udata->depth,
11295
0
                                    udata->ds_low[udata->depth],
11296
0
                                    udata->ds_low[udata->depth] +
11297
0
                                        (udata->nelem /
11298
0
                                         udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) -
11299
0
                                        1,
11300
0
                                    copied_span_info) < 0)
11301
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
11302
0
                                            "can't allocate hyperslab span");
11303
0
                            if (H5S__hyper_free_span_info(copied_span_info) < 0)
11304
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11305
0
                            copied_span_info = NULL;
11306
0
                        }
11307
0
                        udata->ds_low[udata->depth] +=
11308
0
                            udata->nelem / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
11309
0
                        udata->nelem %= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
11310
0
                    } /* end if */
11311
0
                    break;
11312
0
                } /* end if */
11313
11314
                /* Append span tree for entire span */
11315
0
                if (udata->share_selection) {
11316
0
                    if (H5S__hyper_append_span(&udata->ps_span_info[udata->depth],
11317
0
                                               udata->ds_rank - udata->depth, udata->ds_low[udata->depth],
11318
0
                                               udata->ds_span[udata->depth]->high,
11319
0
                                               udata->ds_span[udata->depth]->down) < 0)
11320
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11321
0
                }
11322
0
                else {
11323
                    /* If we're not sharing the destination space's
11324
                     * spans, we must copy it first (then release it
11325
                     * afterwards) */
11326
0
                    if (NULL == (copied_span_info = H5S__hyper_copy_span_helper(
11327
0
                                     udata->ds_span[udata->depth]->down, udata->ds_rank - udata->depth, 1,
11328
0
                                     udata->op_gen)))
11329
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy destination spans");
11330
0
                    if (H5S__hyper_append_span(&udata->ps_span_info[udata->depth],
11331
0
                                               udata->ds_rank - udata->depth, udata->ds_low[udata->depth],
11332
0
                                               udata->ds_span[udata->depth]->high, copied_span_info) < 0)
11333
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11334
0
                    if (H5S__hyper_free_span_info(copied_span_info) < 0)
11335
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11336
0
                    copied_span_info = NULL;
11337
0
                }
11338
0
                udata->nelem -= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts *
11339
0
                                (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1);
11340
11341
                /* Advance to next span */
11342
0
                udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next;
11343
0
                assert(udata->ds_span[udata->depth]);
11344
0
                udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
11345
0
            } while (udata->nelem > 0);
11346
0
        } /* end if */
11347
0
        else {
11348
0
            assert(udata->ds_rank - udata->depth == 1);
11349
0
            do {
11350
                /* If we will run out of elements to add in this span, add
11351
                 * the remainder of the elements and break out */
11352
0
                assert(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high);
11353
0
                if (udata->nelem < (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
11354
0
                    if (H5S__hyper_append_span(&udata->ps_span_info[udata->depth], 1,
11355
0
                                               udata->ds_low[udata->depth],
11356
0
                                               udata->ds_low[udata->depth] + udata->nelem - 1, NULL) < 0)
11357
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11358
0
                    udata->ds_low[udata->depth] += udata->nelem;
11359
0
                    udata->nelem = 0;
11360
0
                    break;
11361
0
                } /* end if */
11362
11363
                /* Append span tree for entire span */
11364
0
                if (H5S__hyper_append_span(&udata->ps_span_info[udata->depth], 1, udata->ds_low[udata->depth],
11365
0
                                           udata->ds_span[udata->depth]->high, NULL) < 0)
11366
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11367
0
                udata->nelem -= udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1;
11368
11369
                /* Advance to next span */
11370
0
                udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next;
11371
0
                assert(udata->ds_span[udata->depth]);
11372
0
                udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
11373
0
            } while (udata->nelem > 0);
11374
0
        } /* end else */
11375
0
    }     /* end while */
11376
11377
0
    assert(udata->skip == 0);
11378
0
    assert(udata->nelem == 0);
11379
11380
    /* Mark projected space as changed (for all ranks) */
11381
0
    udata->ps_clean_bitmap = 0;
11382
11383
0
done:
11384
    /* Cleanup on failure */
11385
0
    if (copied_span_info) {
11386
0
        assert(ret_value < 0);
11387
0
        if (H5S__hyper_free_span_info(copied_span_info) < 0)
11388
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11389
0
        copied_span_info = NULL;
11390
0
    }
11391
11392
0
    FUNC_LEAVE_NOAPI(ret_value)
11393
0
} /* end H5S__hyper_proj_int_build_proj() */
11394
11395
/*--------------------------------------------------------------------------
11396
 NAME
11397
    H5S__hyper_proj_int_iterate
11398
 PURPOSE
11399
    Main iteration routine for H5S__hyper_project_intersection
11400
 USAGE
11401
    herr_t H5S__hyper_proj_int_iterate(ss_span_info,sis_span_info,count,depth,udata)
11402
        const H5S_hyper_span_info_t *ss_span_info; IN: Span tree for source selection
11403
        const H5S_hyper_span_info_t *sis_span_info; IN: Span tree for source intersect selection
11404
        hsize_t count;          IN: Number of times to compute the intersection of ss_span_info and
11405
sis_span_info unsigned depth;         IN: Depth of iteration (in terms of rank)
11406
        H5S_hyper_project_intersect_ud_t *udata; IN/OUT: Persistent shared data for iteration
11407
 RETURNS
11408
    Non-negative on success/Negative on failure.
11409
 DESCRIPTION
11410
    Computes the intersection of ss_span_info and sis_span_info and projects it
11411
    to the projected space (held in udata).  It accomplishes this by iterating
11412
    over both spaces and computing the number of elements to skip (in
11413
    ss_span_info) and the number of elements to add (the intersection) in a
11414
    sequential fashion (similar to run length encoding).  As necessary, this
11415
    function both recurses into lower dimensions and calls
11416
    H5S__hyper_proj_int_build_proj to convert the skip/nelem pairs to the
11417
    projected span tree.
11418
 GLOBAL VARIABLES
11419
 COMMENTS, BUGS, ASSUMPTIONS
11420
 EXAMPLES
11421
 REVISION LOG
11422
--------------------------------------------------------------------------*/
11423
static herr_t
11424
H5S__hyper_proj_int_iterate(H5S_hyper_span_info_t *ss_span_info, const H5S_hyper_span_info_t *sis_span_info,
11425
                            hsize_t count, unsigned depth, H5S_hyper_project_intersect_ud_t *udata)
11426
0
{
11427
0
    const H5S_hyper_span_t *ss_span;             /* Current span in source space */
11428
0
    const H5S_hyper_span_t *sis_span;            /* Current span in source intersect space */
11429
0
    hsize_t                 ss_low;              /* Current low bounds of source span */
11430
0
    hsize_t                 sis_low;             /* Current low bounds of source intersect span */
11431
0
    hsize_t                 high;                /* High bounds of current intersection */
11432
0
    hsize_t                 low;                 /* Low bounds of current intersection */
11433
0
    hsize_t                 old_skip;            /* Value of udata->skip before main loop */
11434
0
    hsize_t                 old_nelem;           /* Value of udata->nelem before main loop */
11435
0
    bool                    check_intersect;     /* Whether to check for intersecting elements */
11436
0
    unsigned                u;                   /* Local index variable */
11437
0
    herr_t                  ret_value = SUCCEED; /* Return value */
11438
11439
0
    FUNC_ENTER_PACKAGE
11440
11441
    /* Check for non-overlapping bounds */
11442
0
    check_intersect = true;
11443
0
    for (u = 0; u < (udata->ss_rank - depth); u++)
11444
0
        if (!H5_RANGE_OVERLAP(ss_span_info->low_bounds[u], ss_span_info->high_bounds[u],
11445
0
                              sis_span_info->low_bounds[u], sis_span_info->high_bounds[u])) {
11446
0
            check_intersect = false;
11447
0
            break;
11448
0
        } /* end if */
11449
11450
    /* Only enter main loop if there's something to do */
11451
0
    if (check_intersect) {
11452
        /* Set ps_clean_bitmap */
11453
0
        udata->ps_clean_bitmap |= (((uint32_t)1) << depth);
11454
11455
        /* Save old skip and nelem */
11456
0
        old_skip  = udata->skip;
11457
0
        old_nelem = udata->nelem;
11458
11459
        /* Intersect spaces once per count */
11460
0
        for (u = 0; u < count; u++) {
11461
0
            ss_span  = ss_span_info->head;
11462
0
            sis_span = sis_span_info->head;
11463
0
            assert(ss_span && sis_span);
11464
0
            ss_low  = ss_span->low;
11465
0
            sis_low = sis_span->low;
11466
11467
            /* Main loop */
11468
0
            do {
11469
                /* Check if spans overlap */
11470
0
                if (H5_RANGE_OVERLAP(ss_low, ss_span->high, sis_low, sis_span->high)) {
11471
0
                    high = MIN(ss_span->high, sis_span->high);
11472
0
                    if (ss_span->down) {
11473
                        /* Add skipped elements if there's a pre-gap */
11474
0
                        if (ss_low < sis_low) {
11475
0
                            low = sis_low;
11476
0
                            H5S_HYPER_PROJ_INT_ADD_SKIP(
11477
0
                                udata,
11478
0
                                H5S__hyper_spans_nelem_helper(ss_span->down, 0, udata->op_gen) *
11479
0
                                    (sis_low - ss_low),
11480
0
                                FAIL);
11481
0
                        } /* end if */
11482
0
                        else
11483
0
                            low = ss_low;
11484
11485
                        /* Recurse into next dimension down */
11486
0
                        if (H5S__hyper_proj_int_iterate(ss_span->down, sis_span->down, high - low + 1,
11487
0
                                                        depth + 1, udata) < 0)
11488
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOMPARE, FAIL,
11489
0
                                        "can't iterate over source selections");
11490
0
                    } /* end if */
11491
0
                    else {
11492
0
                        assert(depth == udata->ss_rank - 1);
11493
11494
                        /* Add skipped elements if there's a pre-gap */
11495
0
                        if (ss_low < sis_low) {
11496
0
                            low = sis_low;
11497
0
                            H5S_HYPER_PROJ_INT_ADD_SKIP(udata, sis_low - ss_low, FAIL);
11498
0
                        } /* end if */
11499
0
                        else
11500
0
                            low = ss_low;
11501
11502
                        /* Add overlapping elements */
11503
0
                        udata->nelem += high - low + 1;
11504
0
                    } /* end else */
11505
11506
                    /* Advance spans */
11507
0
                    if (ss_span->high == sis_span->high) {
11508
                        /* Advance both spans */
11509
0
                        ss_span = ss_span->next;
11510
0
                        if (ss_span)
11511
0
                            ss_low = ss_span->low;
11512
0
                        sis_span = sis_span->next;
11513
0
                        if (sis_span)
11514
0
                            sis_low = sis_span->low;
11515
0
                    } /* end if */
11516
0
                    else if (ss_span->high == high) {
11517
                        /* Advance source span */
11518
0
                        assert(ss_span->high < sis_span->high);
11519
0
                        sis_low = high + 1;
11520
0
                        ss_span = ss_span->next;
11521
0
                        if (ss_span)
11522
0
                            ss_low = ss_span->low;
11523
0
                    } /* end if */
11524
0
                    else {
11525
                        /* Advance source intersect span */
11526
0
                        assert(ss_span->high > sis_span->high);
11527
0
                        ss_low   = high + 1;
11528
0
                        sis_span = sis_span->next;
11529
0
                        if (sis_span)
11530
0
                            sis_low = sis_span->low;
11531
0
                    } /* end else */
11532
0
                }     /* end if */
11533
0
                else {
11534
                    /* Advance spans */
11535
0
                    if (ss_span->high < sis_low) {
11536
                        /* Add skipped elements */
11537
0
                        if (ss_span->down)
11538
0
                            H5S_HYPER_PROJ_INT_ADD_SKIP(
11539
0
                                udata,
11540
0
                                H5S__hyper_spans_nelem_helper(ss_span->down, 0, udata->op_gen) *
11541
0
                                    (ss_span->high - ss_low + 1),
11542
0
                                FAIL);
11543
0
                        else
11544
0
                            H5S_HYPER_PROJ_INT_ADD_SKIP(udata, ss_span->high - ss_low + 1, FAIL);
11545
11546
                        /* Advance source span */
11547
0
                        ss_span = ss_span->next;
11548
0
                        if (ss_span)
11549
0
                            ss_low = ss_span->low;
11550
0
                    } /* end if */
11551
0
                    else {
11552
                        /* Advance source intersect span */
11553
0
                        assert(ss_low > sis_span->high);
11554
0
                        sis_span = sis_span->next;
11555
0
                        if (sis_span)
11556
0
                            sis_low = sis_span->low;
11557
0
                    } /* end else */
11558
0
                }     /* end else */
11559
0
            } while (ss_span && sis_span);
11560
11561
0
            if (ss_span && !((depth == 0) && (u == count - 1))) {
11562
                /* Count remaining elements in ss_span_info */
11563
0
                if (ss_span->down) {
11564
0
                    H5S_HYPER_PROJ_INT_ADD_SKIP(
11565
0
                        udata,
11566
0
                        H5S__hyper_spans_nelem_helper(ss_span->down, 0, udata->op_gen) *
11567
0
                            (ss_span->high - ss_low + 1),
11568
0
                        FAIL);
11569
0
                    ss_span = ss_span->next;
11570
0
                    while (ss_span) {
11571
0
                        H5S_HYPER_PROJ_INT_ADD_SKIP(
11572
0
                            udata,
11573
0
                            H5S__hyper_spans_nelem_helper(ss_span->down, 0, udata->op_gen) *
11574
0
                                (ss_span->high - ss_span->low + 1),
11575
0
                            FAIL);
11576
0
                        ss_span = ss_span->next;
11577
0
                    } /* end while */
11578
0
                }     /* end if */
11579
0
                else {
11580
0
                    H5S_HYPER_PROJ_INT_ADD_SKIP(udata, ss_span->high - ss_low + 1, FAIL);
11581
0
                    ss_span = ss_span->next;
11582
0
                    while (ss_span) {
11583
0
                        H5S_HYPER_PROJ_INT_ADD_SKIP(udata, ss_span->high - ss_span->low + 1, FAIL);
11584
0
                        ss_span = ss_span->next;
11585
0
                    } /* end while */
11586
0
                }     /* end else */
11587
0
            }         /* end if */
11588
11589
            /* Check if the projected space was not changed since we started the
11590
             * first iteration of the loop, if so we do not need to continue
11591
             * looping and can just copy the result */
11592
0
            if (udata->ps_clean_bitmap & (((uint32_t)1) << depth)) {
11593
0
                assert(u == 0);
11594
0
                if (udata->skip == old_skip) {
11595
                    /* First case: algorithm added only elements */
11596
0
                    assert(udata->nelem >= old_nelem);
11597
0
                    udata->nelem += (count - 1) * (udata->nelem - old_nelem);
11598
0
                } /* end if */
11599
0
                else if (udata->nelem == 0) {
11600
                    /* Second case: algorithm added only skip.  In this case,
11601
                     * nelem must be 0 since otherwise adding skip would have
11602
                     * triggered a change in the projected space */
11603
0
                    assert(old_nelem == 0);
11604
0
                    assert(udata->skip > old_skip);
11605
0
                    udata->skip += (count - 1) * (udata->skip - old_skip);
11606
0
                } /* end if */
11607
0
                else {
11608
                    /* Third case: algorithm added skip and nelem (in that
11609
                     * order).  Add the same skip and nelem once for each item
11610
                     * remaining in count. */
11611
0
                    hsize_t skip_add;
11612
0
                    hsize_t nelem_add;
11613
11614
0
                    assert(udata->nelem > 0);
11615
0
                    assert(udata->skip > old_skip);
11616
0
                    assert(old_nelem == 0);
11617
11618
0
                    skip_add  = udata->skip - old_skip;
11619
0
                    nelem_add = udata->nelem - old_nelem;
11620
0
                    for (u = 1; u < count; u++) {
11621
0
                        H5S_HYPER_PROJ_INT_ADD_SKIP(udata, skip_add, FAIL);
11622
0
                        udata->nelem += nelem_add;
11623
0
                    } /* end for */
11624
0
                }     /* end else */
11625
11626
                /* End loop since we already took care of it */
11627
0
                break;
11628
0
            } /* end if */
11629
0
        }     /* end for */
11630
0
    }         /* end if */
11631
0
    else if (depth > 0)
11632
        /* Just count skipped elements */
11633
0
        H5S_HYPER_PROJ_INT_ADD_SKIP(
11634
0
            udata,
11635
0
            H5S__hyper_spans_nelem_helper((H5S_hyper_span_info_t *)ss_span_info, 0, udata->op_gen) * count,
11636
0
            FAIL);
11637
11638
    /* Clean up if we are done */
11639
0
    if (depth == 0) {
11640
        /* Add remaining elements */
11641
0
        if (udata->nelem > 0)
11642
0
            if (H5S__hyper_proj_int_build_proj(udata) < 0)
11643
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't add elements to projected selection");
11644
11645
        /* Append remaining span trees */
11646
0
        for (u = udata->ds_rank - 1; u > 0; u--)
11647
0
            if (udata->ps_span_info[u]) {
11648
0
                if (H5S__hyper_append_span(&udata->ps_span_info[u - 1], udata->ds_rank - u + 1,
11649
0
                                           udata->ds_low[u - 1], udata->ds_low[u - 1],
11650
0
                                           udata->ps_span_info[u]) < 0)
11651
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11652
0
                if (H5S__hyper_free_span_info(udata->ps_span_info[u]) < 0)
11653
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11654
0
                udata->ps_span_info[u] = NULL;
11655
0
            }
11656
0
    }
11657
11658
0
done:
11659
0
    FUNC_LEAVE_NOAPI(ret_value)
11660
0
} /* end H5S__hyper_proj_int_iterate() */
11661
11662
/*--------------------------------------------------------------------------
11663
 NAME
11664
    H5S__hyper_project_intersection
11665
 PURPOSE
11666
    Projects the intersection of of the selections of src_space and
11667
    src_intersect_space within the selection of src_space as a selection
11668
    within the selection of dst_space
11669
 USAGE
11670
    herr_t H5S__hyper_project_intersection(src_space,dst_space,src_intersect_space,proj_space,share_selection)
11671
        H5S_t *src_space;       IN: Selection that is mapped to dst_space, and intersected with
11672
src_intersect_space H5S_t *dst_space;       IN: Selection that is mapped to src_space, and which contains the
11673
result H5S_t *src_intersect_space; IN: Selection whose intersection with src_space is projected to dst_space
11674
to obtain the result H5S_t *proj_space;      OUT: Will contain the result (intersection of src_intersect_space
11675
and src_space projected from src_space to dst_space) after the operation bool share_selection; IN: Whether
11676
we are allowed to share structures inside dst_space with proj_space RETURNS Non-negative on success/Negative
11677
on failure. DESCRIPTION Projects the intersection of of the selections of src_space and src_intersect_space
11678
within the selection of src_space as a selection within the selection of dst_space.  The result is placed in
11679
the selection of proj_space.  Note src_space, dst_space, and src_intersect_space do not need to use hyperslab
11680
selections, but they cannot use point selections. The result is always a hyperslab or none selection.  Note
11681
also that proj_space can share some span trees with dst_space, so proj_space must not be subsequently modified
11682
if dst_space must be preserved. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG
11683
--------------------------------------------------------------------------*/
11684
herr_t
11685
H5S__hyper_project_intersection(H5S_t *src_space, H5S_t *dst_space, H5S_t *src_intersect_space,
11686
                                H5S_t *proj_space, bool share_selection)
11687
0
{
11688
0
    H5S_hyper_project_intersect_ud_t udata; /* User data for subroutines */
11689
0
    H5S_hyper_span_info_t           *ss_span_info;
11690
0
    const H5S_hyper_span_info_t     *ds_span_info;
11691
0
    H5S_hyper_span_info_t           *ss_span_info_buf = NULL;
11692
0
    H5S_hyper_span_info_t           *ds_span_info_buf = NULL;
11693
0
    herr_t                           ret_value        = SUCCEED; /* Return value */
11694
11695
0
    FUNC_ENTER_PACKAGE
11696
11697
    /* Check parameters */
11698
0
    assert(src_space);
11699
0
    assert(dst_space);
11700
0
    assert(src_intersect_space);
11701
0
    assert(proj_space);
11702
11703
    /* Assert that src_space and src_intersect_space have same rank and there
11704
     * are no point selections */
11705
0
    assert(H5S_GET_EXTENT_NDIMS(src_space) == H5S_GET_EXTENT_NDIMS(src_intersect_space));
11706
0
    assert(H5S_GET_SELECT_NPOINTS(src_space) == H5S_GET_SELECT_NPOINTS(dst_space));
11707
0
    assert(H5S_GET_SELECT_TYPE(src_space) != H5S_SEL_POINTS);
11708
0
    assert(H5S_GET_SELECT_TYPE(dst_space) != H5S_SEL_POINTS);
11709
0
    assert(H5S_GET_SELECT_TYPE(src_intersect_space) == H5S_SEL_HYPERSLABS);
11710
11711
    /* Set up ss_span_info */
11712
0
    if (H5S_GET_SELECT_TYPE(src_space) == H5S_SEL_HYPERSLABS) {
11713
        /* Make certain the selection has a span tree */
11714
0
        if (NULL == src_space->select.sel_info.hslab->span_lst)
11715
0
            if (H5S__hyper_generate_spans(src_space) < 0)
11716
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL,
11717
0
                            "can't construct span tree for source hyperslab selection");
11718
11719
        /* Simply point to existing span tree */
11720
0
        ss_span_info = src_space->select.sel_info.hslab->span_lst;
11721
0
    } /* end if */
11722
0
    else {
11723
        /* Create temporary span tree from all selection */
11724
0
        assert(H5S_GET_SELECT_TYPE(src_space) == H5S_SEL_ALL);
11725
11726
0
        if (NULL == (ss_span_info_buf =
11727
0
                         H5S__hyper_make_spans(H5S_GET_EXTENT_NDIMS(src_space), H5S_hyper_zeros_g,
11728
0
                                               H5S_hyper_zeros_g, H5S_hyper_ones_g, src_space->extent.size)))
11729
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't create span tree for ALL source space");
11730
0
        ss_span_info = ss_span_info_buf;
11731
0
    } /* end else */
11732
11733
    /* Set up ds_span_info */
11734
0
    if (H5S_GET_SELECT_TYPE(dst_space) == H5S_SEL_HYPERSLABS) {
11735
        /* Make certain the selection has a span tree */
11736
0
        if (NULL == dst_space->select.sel_info.hslab->span_lst)
11737
0
            if (H5S__hyper_generate_spans(dst_space) < 0)
11738
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL,
11739
0
                            "can't construct span tree for dsetination hyperslab selection");
11740
11741
        /* Simply point to existing span tree */
11742
0
        ds_span_info = dst_space->select.sel_info.hslab->span_lst;
11743
0
    } /* end if */
11744
0
    else {
11745
        /* Create temporary span tree from all selection */
11746
0
        assert(H5S_GET_SELECT_TYPE(dst_space) == H5S_SEL_ALL);
11747
11748
0
        if (NULL == (ds_span_info_buf =
11749
0
                         H5S__hyper_make_spans(H5S_GET_EXTENT_NDIMS(dst_space), H5S_hyper_zeros_g,
11750
0
                                               H5S_hyper_zeros_g, H5S_hyper_ones_g, dst_space->extent.size)))
11751
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL,
11752
0
                        "can't create span tree for ALL destination space");
11753
0
        ds_span_info = ds_span_info_buf;
11754
0
    } /* end else */
11755
11756
    /* Make certain the source intersect selection has a span tree */
11757
0
    if (NULL == src_intersect_space->select.sel_info.hslab->span_lst)
11758
0
        if (H5S__hyper_generate_spans(src_intersect_space) < 0)
11759
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL,
11760
0
                        "can't construct span tree for source intersect hyperslab selection");
11761
11762
    /* Initialize udata */
11763
    /* We will use op_info[0] for nelem and op_info[1] for copied spans */
11764
0
    memset(&udata, 0, sizeof(udata));
11765
0
    udata.ds_span[0]      = ds_span_info->head;
11766
0
    udata.ds_low[0]       = udata.ds_span[0]->low;
11767
0
    udata.ss_rank         = H5S_GET_EXTENT_NDIMS(src_space);
11768
0
    udata.ds_rank         = H5S_GET_EXTENT_NDIMS(dst_space);
11769
0
    udata.op_gen          = H5S__hyper_get_op_gen();
11770
0
    udata.share_selection = share_selection;
11771
11772
    /* Iterate over selections and build projected span tree */
11773
0
    if (H5S__hyper_proj_int_iterate(ss_span_info, src_intersect_space->select.sel_info.hslab->span_lst, 1, 0,
11774
0
                                    &udata) < 0)
11775
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOMPARE, FAIL, "selection iteration failed");
11776
11777
    /* Remove current selection from proj_space */
11778
0
    if (H5S_SELECT_RELEASE(proj_space) < 0)
11779
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection");
11780
11781
    /* Check for elements in projected space */
11782
0
    if (udata.ps_span_info[0]) {
11783
        /* Allocate space for the hyperslab selection information (note this sets
11784
         * diminfo_valid to false, diminfo arrays to 0, and span list to NULL) */
11785
0
        if (NULL == (proj_space->select.sel_info.hslab = H5FL_CALLOC(H5S_hyper_sel_t)))
11786
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab info");
11787
11788
        /* Set selection type */
11789
0
        proj_space->select.type = H5S_sel_hyper;
11790
11791
        /* Set unlim_dim */
11792
0
        proj_space->select.sel_info.hslab->unlim_dim = -1;
11793
11794
        /* Set span tree */
11795
0
        proj_space->select.sel_info.hslab->span_lst = udata.ps_span_info[0];
11796
0
        udata.ps_span_info[0]                       = NULL;
11797
11798
        /* Set the number of elements in current selection */
11799
0
        proj_space->select.num_elem = H5S__hyper_spans_nelem(proj_space->select.sel_info.hslab->span_lst);
11800
11801
        /* Attempt to build "optimized" start/stride/count/block information
11802
         * from resulting hyperslab span tree.
11803
         */
11804
0
        H5S__hyper_rebuild(proj_space);
11805
0
    } /* end if */
11806
0
    else
11807
        /* If we did not add anything to proj_space, select none instead */
11808
0
        if (H5S_select_none(proj_space) < 0)
11809
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection");
11810
11811
0
done:
11812
    /* Free ss_span_info_buf */
11813
0
    if (ss_span_info_buf) {
11814
0
        if (H5S__hyper_free_span_info(ss_span_info_buf) < 0)
11815
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11816
0
        ss_span_info_buf = NULL;
11817
0
    }
11818
11819
    /* Free ds_span_info_buf */
11820
0
    if (ds_span_info_buf) {
11821
0
        if (H5S__hyper_free_span_info(ds_span_info_buf) < 0)
11822
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11823
0
        ds_span_info_buf = NULL;
11824
0
    }
11825
11826
    /* Cleanup on error */
11827
0
    if (ret_value < 0) {
11828
0
        unsigned u;
11829
11830
        /* Free span trees */
11831
0
        for (u = 0; u < udata.ds_rank; u++)
11832
0
            if (udata.ps_span_info[u]) {
11833
0
                if (H5S__hyper_free_span_info(udata.ps_span_info[u]) < 0)
11834
0
                    HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11835
0
                udata.ps_span_info[u] = NULL;
11836
0
            }
11837
0
    }
11838
11839
#ifndef NDEBUG
11840
    /* Verify there are no more span trees */
11841
    {
11842
        unsigned u;
11843
11844
        for (u = 0; u < H5S_MAX_RANK; u++)
11845
            assert(!udata.ps_span_info[u]);
11846
    }
11847
#endif /* NDEBUG */
11848
11849
0
    FUNC_LEAVE_NOAPI(ret_value)
11850
0
} /* end H5S__hyper_project_intersection() */
11851
11852
/*--------------------------------------------------------------------------
11853
 NAME
11854
    H5S__hyper_get_clip_diminfo
11855
 PURPOSE
11856
    Calculates the count and block required to clip the specified
11857
    unlimited dimension to include clip_size.  The returned selection may
11858
    extent beyond clip_size.
11859
 USAGE
11860
    void H5S__hyper_get_clip_diminfo(start,stride,count,block,clip_size)
11861
        hsize_t start;          IN: Start of hyperslab in unlimited dimension
11862
        hsize_t stride;         IN: Stride of hyperslab in unlimited dimension
11863
        hsize_t *count;         IN/OUT: Count of hyperslab in unlimited dimension
11864
        hsize_t *block;         IN/OUT: Block of hyperslab in unlimited dimension
11865
        hsize_t clip_size;      IN: Extent that hyperslab will be clipped to
11866
 RETURNS
11867
    Non-negative on success/Negative on failure.
11868
 DESCRIPTION
11869
    This function recalculates the internal description of the hyperslab
11870
    to make the unlimited dimension extend to the specified extent.
11871
 GLOBAL VARIABLES
11872
 COMMENTS, BUGS, ASSUMPTIONS
11873
 EXAMPLES
11874
 REVISION LOG
11875
--------------------------------------------------------------------------*/
11876
static void
11877
H5S__hyper_get_clip_diminfo(hsize_t start, hsize_t stride, hsize_t *count, hsize_t *block, hsize_t clip_size)
11878
0
{
11879
0
    FUNC_ENTER_PACKAGE_NOERR
11880
11881
    /* Check for selection outside clip size */
11882
0
    if (start >= clip_size) {
11883
0
        if (*block == H5S_UNLIMITED)
11884
0
            *block = 0;
11885
0
        else
11886
0
            *count = 0;
11887
0
    } /* end if */
11888
    /* Check for single block in unlimited dimension */
11889
0
    else if ((*block == H5S_UNLIMITED) || (*block == stride)) {
11890
        /* Calculate actual block size for this clip size */
11891
0
        *block = clip_size - start;
11892
0
        *count = (hsize_t)1;
11893
0
    } /* end if */
11894
0
    else {
11895
0
        assert(*count == H5S_UNLIMITED);
11896
11897
        /* Calculate initial count (last block may be partial) */
11898
0
        *count = (clip_size - start + stride - (hsize_t)1) / stride;
11899
0
        assert(*count > (hsize_t)0);
11900
0
    } /* end else */
11901
11902
0
    FUNC_LEAVE_NOAPI_VOID
11903
0
} /* end H5S__hyper_get_clip_diminfo() */
11904
11905
/*--------------------------------------------------------------------------
11906
 NAME
11907
    H5S_hyper_clip_unlim
11908
 PURPOSE
11909
    Clips the unlimited dimension of the hyperslab selection to the
11910
    specified size
11911
 USAGE
11912
    void H5S_hyper_clip_unlim(space,clip_size)
11913
        H5S_t *space,           IN/OUT: Unlimited space to clip
11914
        hsize_t clip_size;      IN: Extent that hyperslab will be clipped to
11915
 RETURNS
11916
    Non-negative on success/Negative on failure.
11917
 DESCRIPTION
11918
    This function changes the unlimited selection into a fixed-dimension selection
11919
    with the extent of the formerly unlimited dimension specified by clip_size.
11920
 GLOBAL VARIABLES
11921
 COMMENTS, BUGS, ASSUMPTIONS
11922
    Note this function does not take the offset into account.
11923
 EXAMPLES
11924
 REVISION LOG
11925
--------------------------------------------------------------------------*/
11926
herr_t
11927
H5S_hyper_clip_unlim(H5S_t *space, hsize_t clip_size)
11928
0
{
11929
0
    H5S_hyper_sel_t *hslab = NULL;        /* Convenience pointer to hyperslab info */
11930
0
    hsize_t          orig_count;          /* Original count in unlimited dimension */
11931
0
    int              orig_unlim_dim;      /* Original unliminted dimension */
11932
0
    H5S_hyper_dim_t *diminfo   = NULL;    /* Convenience pointer to diminfo.opt in unlimited dimension */
11933
0
    herr_t           ret_value = SUCCEED; /* Return value */
11934
11935
0
    FUNC_ENTER_NOAPI(FAIL)
11936
11937
    /* Check parameters */
11938
0
    assert(space);
11939
0
    hslab = space->select.sel_info.hslab;
11940
0
    assert(hslab);
11941
0
    assert(hslab->unlim_dim >= 0);
11942
0
    assert(!hslab->span_lst);
11943
11944
    /* Save original unlimited dimension */
11945
0
    orig_unlim_dim = hslab->unlim_dim;
11946
11947
    /* Set up convenience pointer */
11948
0
    diminfo = &hslab->diminfo.opt[orig_unlim_dim];
11949
11950
    /* Save original count in unlimited dimension */
11951
0
    orig_count = diminfo->count;
11952
11953
    /* Get initial diminfo */
11954
0
    H5S__hyper_get_clip_diminfo(diminfo->start, diminfo->stride, &diminfo->count, &diminfo->block, clip_size);
11955
11956
    /* Selection is no longer unlimited */
11957
0
    space->select.sel_info.hslab->unlim_dim = -1;
11958
11959
    /* Check for nothing returned */
11960
0
    if ((diminfo->block == 0) || (diminfo->count == 0)) {
11961
        /* Convert to "none" selection */
11962
0
        if (H5S_select_none(space) < 0)
11963
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection");
11964
11965
        /* Reset the convenience pointers */
11966
0
        hslab   = NULL;
11967
0
        diminfo = NULL;
11968
0
    } /* end if */
11969
    /* Check for single block in unlimited dimension */
11970
0
    else if (orig_count == (hsize_t)1) {
11971
        /* Calculate number of elements */
11972
0
        space->select.num_elem = diminfo->block * hslab->num_elem_non_unlim;
11973
11974
        /* Mark that diminfo.opt is valid */
11975
0
        hslab->diminfo_valid = H5S_DIMINFO_VALID_YES;
11976
0
    } /* end if */
11977
0
    else {
11978
        /* Calculate number of elements */
11979
0
        space->select.num_elem = diminfo->count * diminfo->block * hslab->num_elem_non_unlim;
11980
11981
        /* Check if last block is partial.  If superset is set, just keep the
11982
         * last block complete to speed computation. */
11983
0
        assert(clip_size > diminfo->start);
11984
0
        if (((diminfo->stride * (diminfo->count - (hsize_t)1)) + diminfo->block) >
11985
0
            (clip_size - diminfo->start)) {
11986
0
            hsize_t  start[H5S_MAX_RANK];
11987
0
            hsize_t  block[H5S_MAX_RANK];
11988
0
            unsigned u;
11989
11990
            /* Last block is partial, need to construct compound selection */
11991
            /* Fill start with zeros */
11992
0
            memset(start, 0, sizeof(start));
11993
11994
            /* Set block to clip_size in unlimited dimension, H5S_MAX_SIZE in
11995
             * others so only unlimited dimension is clipped */
11996
0
            for (u = 0; u < space->extent.rank; u++)
11997
0
                if ((int)u == orig_unlim_dim)
11998
0
                    block[u] = clip_size;
11999
0
                else
12000
0
                    block[u] = H5S_MAX_SIZE;
12001
12002
            /* Generate span tree in selection */
12003
0
            if (!hslab->span_lst)
12004
0
                if (H5S__hyper_generate_spans(space) < 0)
12005
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to generate span tree");
12006
12007
            /* Indicate that the regular dimensions are no longer valid */
12008
0
            hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
12009
12010
            /* "And" selection with calculated block to perform clip operation */
12011
0
            if (H5S__generate_hyperslab(space, H5S_SELECT_AND, start, H5S_hyper_ones_g, H5S_hyper_ones_g,
12012
0
                                        block) < 0)
12013
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs");
12014
0
        } /* end if */
12015
0
        else
12016
            /* Last block is complete, simply mark that diminfo.opt is valid */
12017
0
            hslab->diminfo_valid = H5S_DIMINFO_VALID_YES;
12018
0
    } /* end else */
12019
12020
    /* Update the upper bound, if the diminfo is valid */
12021
0
    if (hslab && (H5S_DIMINFO_VALID_YES == hslab->diminfo_valid))
12022
0
        hslab->diminfo.high_bounds[orig_unlim_dim] =
12023
0
            hslab->diminfo.opt[orig_unlim_dim].start +
12024
0
            hslab->diminfo.opt[orig_unlim_dim].stride * (hslab->diminfo.opt[orig_unlim_dim].count - 1) +
12025
0
            (hslab->diminfo.opt[orig_unlim_dim].block - 1);
12026
12027
0
done:
12028
0
    FUNC_LEAVE_NOAPI(ret_value)
12029
0
} /* end H5S_hyper_clip_unlim() */
12030
12031
/*--------------------------------------------------------------------------
12032
 NAME
12033
    H5S__hyper_get_clip_extent_real
12034
 PURPOSE
12035
    Gets the extent a space should be clipped to in order to contain the
12036
    specified number of slices in the unlimited dimension
12037
 USAGE
12038
    hsize_t H5S__hyper_get_clip_extent_real(clip_space,num_slices,incl_trail)
12039
        const H5S_t *clip_space, IN: Space that clip size will be calculated based on
12040
        hsize_t num_slizes,     IN: Number of slices clip_space should contain when clipped
12041
        bool incl_trail;     IN: Whether to include trailing unselected space
12042
 RETURNS
12043
    Clip extent to match num_slices (never fails)
12044
 DESCRIPTION
12045
    Calculates and returns the extent that clip_space should be clipped to
12046
    (via H5S_hyper_clip_unlim) in order for it to contain num_slices
12047
    slices in the unlimited dimension.  If the clipped selection would end
12048
    immediately before a section of unselected space (i.e. at the end of a
12049
    block), then if incl_trail is true, the returned clip extent is
12050
    selected to include that trailing "blank" space, otherwise it is
12051
    selected to end at the end before the blank space.
12052
 GLOBAL VARIABLES
12053
 COMMENTS, BUGS, ASSUMPTIONS
12054
    Note this assumes the offset has been normalized.
12055
 EXAMPLES
12056
 REVISION LOG
12057
--------------------------------------------------------------------------*/
12058
static hsize_t
12059
H5S__hyper_get_clip_extent_real(const H5S_t *clip_space, hsize_t num_slices, bool incl_trail)
12060
0
{
12061
0
    const H5S_hyper_dim_t *diminfo; /* Convenience pointer to opt_unlim_diminfo in unlimited dimension */
12062
0
    hsize_t                count;
12063
0
    hsize_t                rem_slices;
12064
0
    hsize_t                ret_value = 0; /* Return value */
12065
12066
0
    FUNC_ENTER_PACKAGE_NOERR
12067
12068
    /* Check parameters */
12069
0
    assert(clip_space);
12070
0
    assert(clip_space->select.sel_info.hslab);
12071
0
    assert(clip_space->select.sel_info.hslab->unlim_dim >= 0);
12072
12073
0
    diminfo = &clip_space->select.sel_info.hslab->diminfo.opt[clip_space->select.sel_info.hslab->unlim_dim];
12074
12075
0
    if (num_slices == 0)
12076
0
        ret_value = incl_trail ? diminfo->start : 0;
12077
0
    else if ((diminfo->block == H5S_UNLIMITED) || (diminfo->block == diminfo->stride))
12078
        /* Unlimited block, just set the extent large enough for the block size
12079
         * to match num_slices */
12080
0
        ret_value = diminfo->start + num_slices;
12081
0
    else {
12082
        /* Unlimited count, need to match extent so a block (possibly) gets cut
12083
         * off so the number of slices matches num_slices */
12084
0
        assert(diminfo->count == H5S_UNLIMITED);
12085
12086
        /* Calculate number of complete blocks in clip_space */
12087
0
        count = num_slices / diminfo->block;
12088
12089
        /* Calculate slices remaining */
12090
0
        rem_slices = num_slices - (count * diminfo->block);
12091
12092
0
        if (rem_slices > 0)
12093
            /* Must end extent in middle of partial block (or beginning of empty
12094
             * block if include_trailing_space and rem_slices == 0) */
12095
0
            ret_value = diminfo->start + (count * diminfo->stride) + rem_slices;
12096
0
        else {
12097
0
            if (incl_trail)
12098
                /* End extent just before first missing block */
12099
0
                ret_value = diminfo->start + (count * diminfo->stride);
12100
0
            else
12101
                /* End extent at end of last block */
12102
0
                ret_value = diminfo->start + ((count - (hsize_t)1) * diminfo->stride) + diminfo->block;
12103
0
        } /* end else */
12104
0
    }     /* end else */
12105
12106
0
    FUNC_LEAVE_NOAPI(ret_value)
12107
0
} /* end H5S__hyper_get_clip_extent_real() */
12108
12109
/*--------------------------------------------------------------------------
12110
 NAME
12111
    H5S_hyper_get_clip_extent
12112
 PURPOSE
12113
    Gets the extent a space should be clipped to in order to contain the
12114
    same number of elements as another space
12115
 USAGE
12116
    hsize_t H5S__hyper_get_clip_extent(clip_space,match_space,incl_trail)
12117
        const H5S_t *clip_space, IN: Space that clip size will be calculated based on
12118
        const H5S_t *match_space, IN: Space containing the same number of elements as clip_space should after
12119
clipping bool incl_trail;     IN: Whether to include trailing unselected space RETURNS Calculated clip
12120
extent (never fails) DESCRIPTION Calculates and returns the extent that clip_space should be clipped to (via
12121
H5S_hyper_clip_unlim) in order for it to contain the same number of elements as match_space.  If the clipped
12122
selection would end immediately before a section of unselected space (i.e. at the end of a block), then if
12123
incl_trail is true, the returned clip extent is selected to include that trailing "blank" space, otherwise it
12124
is selected to end at the end before the blank space. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS Note this
12125
assumes the offset has been normalized. EXAMPLES REVISION LOG
12126
--------------------------------------------------------------------------*/
12127
hsize_t
12128
H5S_hyper_get_clip_extent(const H5S_t *clip_space, const H5S_t *match_space, bool incl_trail)
12129
0
{
12130
0
    hsize_t num_slices;    /* Number of slices in unlimited dimension */
12131
0
    hsize_t ret_value = 0; /* Return value */
12132
12133
0
    FUNC_ENTER_NOAPI(0)
12134
12135
    /* Check parameters */
12136
0
    assert(clip_space);
12137
0
    assert(match_space);
12138
0
    assert(clip_space->select.sel_info.hslab->unlim_dim >= 0);
12139
12140
    /* Check for "none" match space */
12141
0
    if (match_space->select.type->type == H5S_SEL_NONE)
12142
0
        num_slices = (hsize_t)0;
12143
0
    else {
12144
0
        assert(match_space->select.type->type == H5S_SEL_HYPERSLABS);
12145
0
        assert(match_space->select.sel_info.hslab);
12146
12147
        /* Calculate number of slices */
12148
0
        num_slices = match_space->select.num_elem / clip_space->select.sel_info.hslab->num_elem_non_unlim;
12149
0
        assert((match_space->select.num_elem % clip_space->select.sel_info.hslab->num_elem_non_unlim) == 0);
12150
0
    } /* end else */
12151
12152
    /* Call "real" get_clip_extent function */
12153
0
    ret_value = H5S__hyper_get_clip_extent_real(clip_space, num_slices, incl_trail);
12154
12155
0
done:
12156
0
    FUNC_LEAVE_NOAPI(ret_value)
12157
0
} /* end H5S_hyper_get_clip_extent() */
12158
12159
/*--------------------------------------------------------------------------
12160
 NAME
12161
    H5S_hyper_get_clip_extent_match
12162
 PURPOSE
12163
    Gets the extent a space should be clipped to in order to contain the
12164
    same number of elements as another unlimited space that has been
12165
    clipped to a different extent
12166
 USAGE
12167
    hsize_t H5S__hyper_get_clip_extent_match(clip_space,match_space,match_clip_size,incl_trail)
12168
        const H5S_t *clip_space, IN: Space that clip size will be calculated based on
12169
        const H5S_t *match_space, IN: Space that, after being clipped to match_clip_size, contains the same
12170
number of elements as clip_space should after clipping hsize_t match_clip_size, IN: Extent match_space would
12171
be clipped to to match the number of elements in clip_space bool incl_trail;     IN: Whether to include
12172
trailing unselected space RETURNS Calculated clip extent (never fails) DESCRIPTION Calculates and returns the
12173
extent that clip_space should be clipped to (via H5S_hyper_clip_unlim) in order for it to contain the same
12174
number of elements as match_space would have after being clipped to match_clip_size.  If the clipped selection
12175
would end immediately before a section of unselected space (i.e. at the end of a block), then if incl_trail is
12176
true, the returned clip extent is selected to include that trailing "blank" space, otherwise it is selected to
12177
end at the end before the blank space. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS Note this assumes the
12178
offset has been normalized. EXAMPLES REVISION LOG
12179
--------------------------------------------------------------------------*/
12180
hsize_t
12181
H5S_hyper_get_clip_extent_match(const H5S_t *clip_space, const H5S_t *match_space, hsize_t match_clip_size,
12182
                                bool incl_trail)
12183
0
{
12184
0
    const H5S_hyper_dim_t
12185
0
        *match_diminfo; /* Convenience pointer to opt_unlim_diminfo in unlimited dimension in match_space */
12186
0
    hsize_t count;      /* Temporary count */
12187
0
    hsize_t block;      /* Temporary block */
12188
0
    hsize_t num_slices; /* Number of slices in unlimited dimension */
12189
0
    hsize_t ret_value = 0; /* Return value */
12190
12191
0
    FUNC_ENTER_NOAPI(0)
12192
12193
    /* Check parameters */
12194
0
    assert(clip_space);
12195
0
    assert(match_space);
12196
0
    assert(clip_space->select.sel_info.hslab);
12197
0
    assert(match_space->select.sel_info.hslab);
12198
0
    assert(clip_space->select.sel_info.hslab->unlim_dim >= 0);
12199
0
    assert(match_space->select.sel_info.hslab->unlim_dim >= 0);
12200
0
    assert(clip_space->select.sel_info.hslab->num_elem_non_unlim ==
12201
0
           match_space->select.sel_info.hslab->num_elem_non_unlim);
12202
12203
0
    match_diminfo =
12204
0
        &match_space->select.sel_info.hslab->diminfo.opt[match_space->select.sel_info.hslab->unlim_dim];
12205
12206
    /* Get initial count and block */
12207
0
    count = match_diminfo->count;
12208
0
    block = match_diminfo->block;
12209
0
    H5S__hyper_get_clip_diminfo(match_diminfo->start, match_diminfo->stride, &count, &block, match_clip_size);
12210
12211
    /* Calculate number of slices */
12212
    /* Check for nothing returned */
12213
0
    if ((block == 0) || (count == 0))
12214
0
        num_slices = (hsize_t)0;
12215
    /* Check for single block in unlimited dimension */
12216
0
    else if (count == (hsize_t)1)
12217
0
        num_slices = block;
12218
0
    else {
12219
        /* Calculate initial num_slices */
12220
0
        num_slices = block * count;
12221
12222
        /* Check for partial last block */
12223
0
        assert(match_clip_size >= match_diminfo->start);
12224
0
        if (((match_diminfo->stride * (count - (hsize_t)1)) + block) >
12225
0
            (match_clip_size - match_diminfo->start)) {
12226
            /* Subtract slices missing from last block */
12227
0
            assert((((match_diminfo->stride * (count - (hsize_t)1)) + block) -
12228
0
                    (match_clip_size - match_diminfo->start)) < num_slices);
12229
0
            num_slices -= ((match_diminfo->stride * (count - (hsize_t)1)) + block) -
12230
0
                          (match_clip_size - match_diminfo->start);
12231
0
        } /* end if */
12232
0
    }     /* end else */
12233
12234
    /* Call "real" get_clip_extent function */
12235
0
    ret_value = H5S__hyper_get_clip_extent_real(clip_space, num_slices, incl_trail);
12236
12237
0
done:
12238
0
    FUNC_LEAVE_NOAPI(ret_value)
12239
0
} /* end H5S_hyper_get_clip_extent_match() */
12240
12241
/*--------------------------------------------------------------------------
12242
 NAME
12243
    H5S_hyper_get_unlim_block
12244
 PURPOSE
12245
    Get the nth block in the unlimited dimension
12246
 USAGE
12247
    H5S_t *H5S_hyper_get_unlim_block(space,block_index)
12248
        const H5S_t *space,     IN: Space with unlimited selection
12249
        hsize_t block_index,    IN: Index of block to return in unlimited dimension
12250
        bool incl_trail;     IN: Whether to include trailing unselected space
12251
 RETURNS
12252
    New space on success/NULL on failure.
12253
 DESCRIPTION
12254
    Returns a space containing only the block_indexth block in the
12255
    unlimited dimension on space.  All blocks in all other dimensions are
12256
    preserved.
12257
 GLOBAL VARIABLES
12258
 COMMENTS, BUGS, ASSUMPTIONS
12259
    Note this assumes the offset has been normalized.
12260
 EXAMPLES
12261
 REVISION LOG
12262
--------------------------------------------------------------------------*/
12263
H5S_t *
12264
H5S_hyper_get_unlim_block(const H5S_t *space, hsize_t block_index)
12265
0
{
12266
0
    H5S_hyper_sel_t *hslab;               /* Convenience pointer to hyperslab info */
12267
0
    H5S_t           *space_out = NULL;    /* Dataspace to return */
12268
0
    hsize_t          start[H5S_MAX_RANK]; /* Hyperslab selection info for unlim. selection */
12269
0
    hsize_t          stride[H5S_MAX_RANK];
12270
0
    hsize_t          count[H5S_MAX_RANK];
12271
0
    hsize_t          block[H5S_MAX_RANK];
12272
0
    unsigned         u;                /* Local index variable */
12273
0
    H5S_t           *ret_value = NULL; /* Return value */
12274
12275
0
    FUNC_ENTER_NOAPI(NULL)
12276
12277
    /* Check parameters */
12278
0
    assert(space);
12279
0
    hslab = space->select.sel_info.hslab;
12280
0
    assert(hslab);
12281
0
    assert(hslab->unlim_dim >= 0);
12282
0
    assert(hslab->diminfo.opt[hslab->unlim_dim].count == H5S_UNLIMITED);
12283
12284
    /* Set start to select block_indexth block in unlimited dimension and set
12285
     * count to 1 in that dimension to only select that block.  Copy all other
12286
     * diminfo parameters. */
12287
0
    for (u = 0; u < space->extent.rank; u++) {
12288
0
        if ((int)u == hslab->unlim_dim) {
12289
0
            start[u] = hslab->diminfo.opt[u].start + (block_index * hslab->diminfo.opt[u].stride);
12290
0
            count[u] = (hsize_t)1;
12291
0
        } /* end if */
12292
0
        else {
12293
0
            start[u] = hslab->diminfo.opt[u].start;
12294
0
            count[u] = hslab->diminfo.opt[u].count;
12295
0
        } /* end else */
12296
0
        stride[u] = hslab->diminfo.opt[u].stride;
12297
0
        block[u]  = hslab->diminfo.opt[u].block;
12298
0
    } /* end for */
12299
12300
    /* Create output space, copy extent */
12301
0
    if (NULL == (space_out = H5S_create(H5S_SIMPLE)))
12302
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, NULL, "unable to create output dataspace");
12303
0
    if (H5S__extent_copy_real(&space_out->extent, &space->extent, true) < 0)
12304
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, NULL, "unable to copy destination space extent");
12305
12306
    /* Select block as defined by start/stride/count/block computed above */
12307
0
    if (H5S_select_hyperslab(space_out, H5S_SELECT_SET, start, stride, count, block) < 0)
12308
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, NULL, "can't select hyperslab");
12309
12310
    /* Set return value */
12311
0
    ret_value = space_out;
12312
12313
0
done:
12314
    /* Free space on error */
12315
0
    if (!ret_value)
12316
0
        if (space_out && H5S_close(space_out) < 0)
12317
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, NULL, "unable to release dataspace");
12318
12319
0
    FUNC_LEAVE_NOAPI(ret_value)
12320
0
} /* end H5S_hyper_get_unlim_block */
12321
12322
/*--------------------------------------------------------------------------
12323
 NAME
12324
    H5S_hyper_get_first_inc_block
12325
 PURPOSE
12326
    Get the index of the first incomplete block in the specified extent
12327
 USAGE
12328
    hsize_t H5S_hyper_get_first_inc_block(space,clip_size,partial)
12329
        const H5S_t *space,     IN: Space with unlimited selection
12330
        hsize_t clip_size,      IN: Extent space would be clipped to
12331
        bool *partial;       OUT: Whether the ret_valueth block (first incomplete block) is partial
12332
 RETURNS
12333
    Index of first incomplete block in clip_size (never fails).
12334
 DESCRIPTION
12335
    Calculates and returns the index (as would be passed to
12336
    H5S_hyper_get_unlim_block()) of the first block in the unlimited
12337
    dimension of space which would be incomplete or missing when space is
12338
    clipped to clip_size.  partial is set to true if the first incomplete
12339
    block is partial, and false if the first incomplete block is missing.
12340
 GLOBAL VARIABLES
12341
 COMMENTS, BUGS, ASSUMPTIONS
12342
    Note this assumes the offset has been normalized.
12343
 EXAMPLES
12344
 REVISION LOG
12345
--------------------------------------------------------------------------*/
12346
hsize_t
12347
H5S_hyper_get_first_inc_block(const H5S_t *space, hsize_t clip_size, bool *partial)
12348
0
{
12349
0
    H5S_hyper_sel_t *hslab;   /* Convenience pointer to hyperslab info */
12350
0
    H5S_hyper_dim_t *diminfo; /* Convenience pointer to diminfo in unlimited dimension */
12351
0
    hsize_t          ret_value = 0;
12352
12353
0
    FUNC_ENTER_NOAPI(0)
12354
12355
    /* Check parameters */
12356
0
    assert(space);
12357
0
    hslab = space->select.sel_info.hslab;
12358
0
    assert(hslab);
12359
0
    assert(hslab->unlim_dim >= 0);
12360
0
    assert(hslab->diminfo.opt[hslab->unlim_dim].count == H5S_UNLIMITED);
12361
12362
0
    diminfo = &hslab->diminfo.opt[hslab->unlim_dim];
12363
12364
    /* Check for selection outside of clip_size */
12365
0
    if (diminfo->start >= clip_size) {
12366
0
        ret_value = 0;
12367
0
        if (partial)
12368
0
            *partial = false;
12369
0
    } /* end if */
12370
0
    else {
12371
        /* Calculate index of first incomplete block */
12372
0
        ret_value = (clip_size - diminfo->start + diminfo->stride - diminfo->block) / diminfo->stride;
12373
12374
0
        if (partial) {
12375
            /* Check for partial block */
12376
0
            if ((diminfo->stride * ret_value) < (clip_size - diminfo->start))
12377
0
                *partial = true;
12378
0
            else
12379
0
                *partial = false;
12380
0
        } /* end if */
12381
0
    }     /* end else */
12382
12383
0
done:
12384
0
    FUNC_LEAVE_NOAPI(ret_value)
12385
0
} /* end H5S_hyper_get_first_inc_block */
12386
12387
/*--------------------------------------------------------------------------
12388
 NAME
12389
    H5Sis_regular_hyperslab
12390
 PURPOSE
12391
    Determine if a hyperslab selection is regular
12392
 USAGE
12393
    htri_t H5Sis_regular_hyperslab(dsid)
12394
        hid_t dsid;             IN: Dataspace ID of hyperslab selection to query
12395
 RETURNS
12396
    true/false for hyperslab selection, FAIL on error or when querying other
12397
    selection types.
12398
 DESCRIPTION
12399
    If a hyperslab can be represented as a single call to H5Sselect_hyperslab,
12400
    with the H5S_SELECT_SET option, it is regular.  If the hyperslab selection
12401
    would require multiple calls to H5Sselect_hyperslab, it is irregular.
12402
 GLOBAL VARIABLES
12403
 COMMENTS, BUGS, ASSUMPTIONS
12404
 EXAMPLES
12405
 REVISION LOG
12406
--------------------------------------------------------------------------*/
12407
htri_t
12408
H5Sis_regular_hyperslab(hid_t spaceid)
12409
0
{
12410
0
    H5S_t *space;     /* Dataspace to query */
12411
0
    htri_t ret_value; /* Return value */
12412
12413
0
    FUNC_ENTER_API(FAIL)
12414
12415
    /* Check args */
12416
0
    if (NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE)))
12417
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace");
12418
0
    if (H5S_GET_SELECT_TYPE(space) != H5S_SEL_HYPERSLABS)
12419
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a hyperslab selection");
12420
12421
0
    ret_value = H5S__hyper_is_regular(space);
12422
12423
0
done:
12424
0
    FUNC_LEAVE_API(ret_value)
12425
0
} /* end H5Sis_regular_hyperslab() */
12426
12427
/*--------------------------------------------------------------------------
12428
 NAME
12429
    H5Sget_regular_hyperslab
12430
 PURPOSE
12431
    Retrieve a regular hyperslab selection
12432
 USAGE
12433
    herr_t H5Sget_regular_hyperslab(dsid, start, stride, block, count)
12434
        hid_t dsid;             IN: Dataspace ID of hyperslab selection to query
12435
        hsize_t start[];        OUT: Offset of start of hyperslab
12436
        hsize_t stride[];       OUT: Hyperslab stride
12437
        hsize_t count[];        OUT: Number of blocks included in hyperslab
12438
        hsize_t block[];        OUT: Size of block in hyperslab
12439
 RETURNS
12440
    Non-negative on success/Negative on failure.  (It is an error to query
12441
    the regular hyperslab selections for non-regular hyperslab selections)
12442
 DESCRIPTION
12443
    Retrieve the start/stride/count/block for a regular hyperslab selection.
12444
 GLOBAL VARIABLES
12445
 COMMENTS, BUGS, ASSUMPTIONS
12446
    Note that if a hyperslab is originally regular, then becomes irregular
12447
    through selection operations, and then becomes regular again, the new
12448
    final regular selection may be equivalent but not identical to the
12449
    original regular selection.
12450
 EXAMPLES
12451
 REVISION LOG
12452
--------------------------------------------------------------------------*/
12453
herr_t
12454
H5Sget_regular_hyperslab(hid_t spaceid, hsize_t start[] /*out*/, hsize_t stride[] /*out*/,
12455
                         hsize_t count[] /*out*/, hsize_t block[] /*out*/)
12456
0
{
12457
0
    H5S_t   *space;               /* Dataspace to query */
12458
0
    unsigned u;                   /* Local index variable */
12459
0
    herr_t   ret_value = SUCCEED; /* Return value */
12460
12461
0
    FUNC_ENTER_API(FAIL)
12462
12463
    /* Check args */
12464
0
    if (NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE)))
12465
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace");
12466
0
    if (H5S_GET_SELECT_TYPE(space) != H5S_SEL_HYPERSLABS)
12467
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a hyperslab selection");
12468
0
    if (true != H5S__hyper_is_regular(space))
12469
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a regular hyperslab selection");
12470
12471
    /* Retrieve hyperslab parameters */
12472
0
    if (start)
12473
0
        for (u = 0; u < space->extent.rank; u++)
12474
0
            start[u] = space->select.sel_info.hslab->diminfo.app[u].start;
12475
0
    if (stride)
12476
0
        for (u = 0; u < space->extent.rank; u++)
12477
0
            stride[u] = space->select.sel_info.hslab->diminfo.app[u].stride;
12478
0
    if (count)
12479
0
        for (u = 0; u < space->extent.rank; u++)
12480
0
            count[u] = space->select.sel_info.hslab->diminfo.app[u].count;
12481
0
    if (block)
12482
0
        for (u = 0; u < space->extent.rank; u++)
12483
0
            block[u] = space->select.sel_info.hslab->diminfo.app[u].block;
12484
12485
0
done:
12486
0
    FUNC_LEAVE_API(ret_value)
12487
0
} /* end H5Sget_regular_hyperslab() */