Coverage Report

Created: 2026-10-28 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hdf5/src/H5Shyper.c
Line
Count
Source
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
 * Copyright by The HDF Group.                                               *
3
 * All rights reserved.                                                      *
4
 *                                                                           *
5
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
6
 * terms governing use, modification, and redistribution, is contained in    *
7
 * the LICENSE file, which can be found at the root of the source code       *
8
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
9
 * If you do not have access to either file, you may request a copy from     *
10
 * help@hdfgroup.org.                                                        *
11
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13
/*
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
    /* A hyperslab selection is meaningless on a scalar/null dataspace. This
3993
     * state can arise if the extent is collapsed to a scalar after the
3994
     * selection was made, since changing the extent does not reset an
3995
     * existing hyperslab selection. */
3996
0
    if (0 == space->extent.rank)
3997
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL,
3998
0
                    "cannot serialize hyperslab selection with a rank of 0");
3999
4000
    /* Set some convenience values */
4001
0
    ndims   = space->extent.rank;
4002
0
    diminfo = space->select.sel_info.hslab->diminfo.opt;
4003
4004
    /* Calculate the # of blocks */
4005
0
    if (space->select.sel_info.hslab->unlim_dim < 0) /* ! H5S_UNLIMITED */
4006
0
        block_count = H5S__get_select_hyper_nblocks(space, false);
4007
4008
    /* Determine the version and the encoded size */
4009
0
    if (H5S__hyper_get_version_enc_size(space, block_count, &version, &enc_size) < 0)
4010
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't determine hyper version & enc_size");
4011
4012
0
    is_regular = H5S__hyper_is_regular(space);
4013
0
    if (is_regular && (version == H5S_HYPER_VERSION_2 || version == H5S_HYPER_VERSION_3))
4014
0
        flags |= H5S_HYPER_REGULAR;
4015
4016
    /* Store the preamble information */
4017
0
    UINT32ENCODE(pp, (uint32_t)H5S_GET_SELECT_TYPE(space)); /* Store the type of selection */
4018
0
    UINT32ENCODE(pp, version);                              /* Store the version number */
4019
4020
0
    if (version >= 3) {
4021
0
        *(pp)++ = flags;    /* Store the flags */
4022
0
        *(pp)++ = enc_size; /* Store size of offset info */
4023
0
    }                       /* end if */
4024
0
    else {
4025
0
        if (version == 2)
4026
0
            *(pp)++ = flags; /* Store the flags */
4027
0
        else
4028
0
            UINT32ENCODE(pp, (uint32_t)0); /* Store the un-used padding */
4029
0
        lenp = pp;                         /* keep the pointer to the length location for later */
4030
0
        pp += 4;                           /* skip over space for length */
4031
4032
0
        len += 4; /* ndims */
4033
0
    }             /* end else */
4034
4035
    /* Encode number of dimensions */
4036
0
    UINT32ENCODE(pp, (uint32_t)ndims);
4037
4038
0
    if (is_regular) {
4039
0
        if (version >= H5S_HYPER_VERSION_2) {
4040
0
            assert(H5S_UNLIMITED == HSIZE_UNDEF);
4041
4042
            /* Iterate over dimensions */
4043
            /* Encode start/stride/block/count */
4044
0
            switch (enc_size) {
4045
0
                case H5S_SELECT_INFO_ENC_SIZE_2:
4046
0
                    assert(version == H5S_HYPER_VERSION_3);
4047
0
                    for (u = 0; u < space->extent.rank; u++) {
4048
0
                        UINT16ENCODE(pp, diminfo[u].start);
4049
0
                        UINT16ENCODE(pp, diminfo[u].stride);
4050
0
                        if (diminfo[u].count == H5S_UNLIMITED)
4051
0
                            UINT16ENCODE(pp, H5S_UINT16_MAX);
4052
0
                        else
4053
0
                            UINT16ENCODE(pp, diminfo[u].count);
4054
0
                        if (diminfo[u].block == H5S_UNLIMITED)
4055
0
                            UINT16ENCODE(pp, H5S_UINT16_MAX);
4056
0
                        else
4057
0
                            UINT16ENCODE(pp, diminfo[u].block);
4058
0
                    } /* end for */
4059
0
                    break;
4060
4061
0
                case H5S_SELECT_INFO_ENC_SIZE_4:
4062
0
                    assert(version == H5S_HYPER_VERSION_3);
4063
0
                    for (u = 0; u < space->extent.rank; u++) {
4064
0
                        UINT32ENCODE(pp, diminfo[u].start);
4065
0
                        UINT32ENCODE(pp, diminfo[u].stride);
4066
0
                        if (diminfo[u].count == H5S_UNLIMITED)
4067
0
                            UINT32ENCODE(pp, H5S_UINT32_MAX);
4068
0
                        else
4069
0
                            UINT32ENCODE(pp, diminfo[u].count);
4070
0
                        if (diminfo[u].block == H5S_UNLIMITED)
4071
0
                            UINT32ENCODE(pp, H5S_UINT32_MAX);
4072
0
                        else
4073
0
                            UINT32ENCODE(pp, diminfo[u].block);
4074
0
                    } /* end for */
4075
0
                    break;
4076
4077
0
                case H5S_SELECT_INFO_ENC_SIZE_8:
4078
0
                    assert(version == H5S_HYPER_VERSION_2 || version == H5S_HYPER_VERSION_3);
4079
0
                    for (u = 0; u < space->extent.rank; u++) {
4080
0
                        UINT64ENCODE(pp, diminfo[u].start);
4081
0
                        UINT64ENCODE(pp, diminfo[u].stride);
4082
0
                        if (diminfo[u].count == H5S_UNLIMITED)
4083
0
                            UINT64ENCODE(pp, H5S_UINT64_MAX);
4084
0
                        else
4085
0
                            UINT64ENCODE(pp, diminfo[u].count);
4086
0
                        if (diminfo[u].block == H5S_UNLIMITED)
4087
0
                            UINT64ENCODE(pp, H5S_UINT64_MAX);
4088
0
                        else
4089
0
                            UINT64ENCODE(pp, diminfo[u].block);
4090
0
                    } /* end for */
4091
0
                    if (version == H5S_HYPER_VERSION_2)
4092
0
                        len += (4 * space->extent.rank * 8);
4093
0
                    break;
4094
0
                default:
4095
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL,
4096
0
                                "unknown offset info size for hyperslab");
4097
0
                    break;
4098
0
            } /* end switch */
4099
0
        }     /* end if */
4100
0
        else {
4101
0
            assert(version == H5S_HYPER_VERSION_1);
4102
4103
            /* Set some convenience values */
4104
0
            fast_dim = ndims - 1;
4105
4106
            /* Encode number of hyperslabs */
4107
0
            H5_CHECK_OVERFLOW(block_count, hsize_t, uint32_t);
4108
0
            UINT32ENCODE(pp, (uint32_t)block_count);
4109
0
            len += 4;
4110
4111
            /* Now serialize the information for the regular hyperslab */
4112
4113
            /* Build the tables of count sizes as well as the initial offset */
4114
0
            for (u = 0; u < ndims; u++) {
4115
0
                tmp_count[u] = diminfo[u].count;
4116
0
                offset[u]    = diminfo[u].start;
4117
0
            } /* end for */
4118
4119
            /* Go iterate over the hyperslabs */
4120
0
            while (complete == false) {
4121
                /* Iterate over the blocks in the fastest dimension */
4122
0
                while (tmp_count[fast_dim] > 0) {
4123
                    /* Add 8 bytes times the rank for each hyperslab selected */
4124
0
                    len += 8 * ndims;
4125
4126
                    /* Encode hyperslab starting location */
4127
0
                    for (u = 0; u < ndims; u++)
4128
0
                        UINT32ENCODE(pp, (uint32_t)offset[u]);
4129
4130
                    /* Encode hyperslab ending location */
4131
0
                    for (u = 0; u < ndims; u++)
4132
0
                        UINT32ENCODE(pp, (uint32_t)(offset[u] + (diminfo[u].block - 1)));
4133
4134
                    /* Move the offset to the next sequence to start */
4135
0
                    offset[fast_dim] += diminfo[fast_dim].stride;
4136
4137
                    /* Decrement the block count */
4138
0
                    tmp_count[fast_dim]--;
4139
0
                } /* end while */
4140
4141
                /* Work on other dimensions if necessary */
4142
0
                if (fast_dim > 0) {
4143
0
                    int temp_dim; /* Temporary rank holder */
4144
4145
                    /* Reset the block counts */
4146
0
                    tmp_count[fast_dim] = diminfo[fast_dim].count;
4147
4148
                    /* Bubble up the decrement to the slower changing dimensions */
4149
0
                    temp_dim = (int)fast_dim - 1;
4150
0
                    while (temp_dim >= 0 && complete == false) {
4151
                        /* Decrement the block count */
4152
0
                        tmp_count[temp_dim]--;
4153
4154
                        /* Check if we have more blocks left */
4155
0
                        if (tmp_count[temp_dim] > 0)
4156
0
                            break;
4157
4158
                        /* Check for getting out of iterator */
4159
0
                        if (temp_dim == 0)
4160
0
                            complete = true;
4161
4162
                        /* Reset the block count in this dimension */
4163
0
                        tmp_count[temp_dim] = diminfo[temp_dim].count;
4164
4165
                        /* Wrapped a dimension, go up to next dimension */
4166
0
                        temp_dim--;
4167
0
                    } /* end while */
4168
0
                }     /* end if */
4169
0
                else
4170
0
                    break; /* Break out now, for 1-D selections */
4171
4172
                /* Re-compute offset array */
4173
0
                for (u = 0; u < ndims; u++)
4174
0
                    offset[u] = diminfo[u].start + diminfo[u].stride * (diminfo[u].count - tmp_count[u]);
4175
0
            } /* end while */
4176
0
        }     /* end else */
4177
0
    }         /* end if */
4178
0
    else {    /* irregular */
4179
        /* Encode number of hyperslabs */
4180
0
        switch (enc_size) {
4181
0
            case H5S_SELECT_INFO_ENC_SIZE_2:
4182
0
                assert(version == H5S_HYPER_VERSION_3);
4183
0
                H5_CHECK_OVERFLOW(block_count, hsize_t, uint16_t);
4184
0
                UINT16ENCODE(pp, (uint16_t)block_count);
4185
0
                break;
4186
4187
0
            case H5S_SELECT_INFO_ENC_SIZE_4:
4188
0
                assert(version == H5S_HYPER_VERSION_1 || version == H5S_HYPER_VERSION_3);
4189
0
                H5_CHECK_OVERFLOW(block_count, hsize_t, uint32_t);
4190
0
                UINT32ENCODE(pp, (uint32_t)block_count);
4191
0
                break;
4192
4193
0
            case H5S_SELECT_INFO_ENC_SIZE_8:
4194
0
                assert(version == H5S_HYPER_VERSION_3);
4195
0
                UINT64ENCODE(pp, block_count);
4196
0
                break;
4197
4198
0
            default:
4199
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unknown offset info size for hyperslab");
4200
0
                break;
4201
0
        } /* end switch */
4202
4203
0
        if (version == H5S_HYPER_VERSION_1) {
4204
0
            len += 4; /* block_count */
4205
4206
            /* Add 8 bytes times the rank for each hyperslab selected */
4207
0
            H5_CHECK_OVERFLOW((8 * ndims * block_count), hsize_t, size_t);
4208
0
            len += (uint32_t)(8 * ndims * block_count);
4209
0
        } /* end if */
4210
4211
0
        H5S__hyper_serialize_helper(space->select.sel_info.hslab->span_lst, start, end, (hsize_t)0, enc_size,
4212
0
                                    &pp);
4213
0
    } /* end else */
4214
4215
    /* Encode length */
4216
0
    if (version <= H5S_HYPER_VERSION_2)
4217
0
        UINT32ENCODE(lenp, (uint32_t)len); /* Store the length of the extra information */
4218
4219
    /* Update encoding pointer */
4220
0
    *p = pp;
4221
4222
0
done:
4223
0
    FUNC_LEAVE_NOAPI(ret_value)
4224
0
} /* end H5S__hyper_serialize() */
4225
4226
/*--------------------------------------------------------------------------
4227
 NAME
4228
    H5S__hyper_deserialize
4229
 PURPOSE
4230
    Deserialize the current selection from a user-provided buffer.
4231
 USAGE
4232
    herr_t H5S__hyper_deserialize(space, p)
4233
        H5S_t **space;          IN/OUT: Dataspace pointer to place
4234
                                selection into
4235
        uint8 **p;              OUT: Pointer to buffer holding serialized
4236
                                selection.  Will be advanced to end of
4237
                                serialized selection.
4238
 RETURNS
4239
    Non-negative on success/Negative on failure
4240
 DESCRIPTION
4241
    Deserializes the current selection into a buffer.  (Primarily for retrieving
4242
    from disk).
4243
 GLOBAL VARIABLES
4244
 COMMENTS, BUGS, ASSUMPTIONS
4245
 EXAMPLES
4246
 REVISION LOG
4247
--------------------------------------------------------------------------*/
4248
static herr_t
4249
H5S__hyper_deserialize(H5S_t **space, const uint8_t **p, const size_t p_size, bool skip)
4250
0
{
4251
0
    H5S_t *tmp_space = NULL;            /* Pointer to actual dataspace to use,
4252
                                           either *space or a newly allocated one */
4253
0
    hsize_t        dims[H5S_MAX_RANK];  /* Dimension sizes */
4254
0
    hsize_t        start[H5S_MAX_RANK]; /* hyperslab start information */
4255
0
    hsize_t        block[H5S_MAX_RANK]; /* hyperslab block information */
4256
0
    uint32_t       version;             /* Version number */
4257
0
    uint8_t        flags    = 0;        /* Flags */
4258
0
    uint8_t        enc_size = 0;        /* Encoded size of selection info */
4259
0
    unsigned       rank;                /* rank of points */
4260
0
    const uint8_t *pp;                  /* Local pointer for decoding */
4261
0
    unsigned       u;                   /* Local counting variable */
4262
0
    herr_t         ret_value = FAIL;    /* return value */
4263
0
    const uint8_t *p_end;
4264
4265
0
    FUNC_ENTER_PACKAGE
4266
4267
    /* Check args */
4268
0
    assert(p);
4269
0
    pp = (*p);
4270
0
    assert(pp);
4271
4272
0
    if (skip)
4273
0
        p_end = *p;
4274
0
    else if (p_size == 0)
4275
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL, "empty hyperslab selection buffer");
4276
0
    else
4277
0
        p_end = *p + p_size - 1; /* Pointer to last valid byte in buffer */
4278
4279
    /* As part of the efforts to push all selection-type specific coding
4280
       to the callbacks, the coding for the allocation of a null dataspace
4281
       is moved from H5S_select_deserialize() in H5Sselect.c to here.
4282
       This is needed for decoding virtual layout in H5O__layout_decode() */
4283
    /* Allocate space if not provided */
4284
0
    if (!*space) {
4285
0
        if (NULL == (tmp_space = H5S_create(H5S_SIMPLE)))
4286
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create dataspace");
4287
0
    } /* end if */
4288
0
    else
4289
0
        tmp_space = *space;
4290
4291
    /* Decode version */
4292
0
    if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, sizeof(uint32_t), p_end))
4293
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL, "buffer overflow while decoding selection version");
4294
0
    UINT32DECODE(pp, version);
4295
4296
0
    if (version < H5S_HYPER_VERSION_1 || version > H5S_HYPER_VERSION_LATEST)
4297
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "bad version number for hyperslab selection");
4298
4299
0
    if (version >= (uint32_t)H5S_HYPER_VERSION_2) {
4300
        /* Decode flags */
4301
0
        if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, 1, p_end))
4302
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL, "buffer overflow while decoding selection flags");
4303
0
        flags = *(pp)++;
4304
4305
0
        if (version >= (uint32_t)H5S_HYPER_VERSION_3) {
4306
            /* decode size of offset info */
4307
0
            if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, 1, p_end))
4308
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4309
0
                            "buffer overflow while decoding selection encoding size");
4310
0
            enc_size = *(pp)++;
4311
0
        }
4312
0
        else {
4313
            /* Skip over the remainder of the header */
4314
0
            if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, 4, p_end))
4315
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4316
0
                            "buffer overflow while decoding selection header");
4317
0
            pp += 4;
4318
0
            enc_size = H5S_SELECT_INFO_ENC_SIZE_8;
4319
0
        } /* end else */
4320
4321
        /* Check for unknown flags */
4322
0
        if (flags & ~H5S_SELECT_FLAG_BITS)
4323
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTLOAD, FAIL, "unknown flag for selection");
4324
0
    }
4325
0
    else {
4326
        /* Skip over the remainder of the header */
4327
0
        if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, 8, p_end))
4328
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL, "buffer overflow while decoding selection header");
4329
0
        pp += 8;
4330
0
        enc_size = H5S_SELECT_INFO_ENC_SIZE_4;
4331
0
    } /* end else */
4332
4333
    /* Check encoded */
4334
0
    if (enc_size & ~H5S_SELECT_INFO_ENC_SIZE_BITS)
4335
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTLOAD, FAIL, "unknown size of point/offset info for selection");
4336
4337
    /* Decode the rank of the point selection */
4338
0
    if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, sizeof(uint32_t), p_end))
4339
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL, "buffer overflow while decoding selection rank");
4340
0
    UINT32DECODE(pp, rank);
4341
0
    if (0 == rank || rank > H5S_MAX_RANK)
4342
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "invalid rank (%u) for serialized hyperslab selection",
4343
0
                    rank);
4344
4345
0
    if (!*space) {
4346
        /* Patch the rank of the allocated dataspace */
4347
0
        memset(dims, 0, (size_t)rank * sizeof(dims[0]));
4348
0
        if (H5S_set_extent_simple(tmp_space, rank, dims, NULL) < 0)
4349
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't set dimensions");
4350
0
    } /* end if */
4351
0
    else
4352
        /* Verify the rank of the provided dataspace */
4353
0
        if (rank != tmp_space->extent.rank)
4354
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL,
4355
0
                        "rank of serialized selection does not match dataspace");
4356
4357
0
    if (flags & H5S_HYPER_REGULAR) {
4358
0
        hsize_t stride[H5S_MAX_RANK]; /* Hyperslab stride information */
4359
0
        hsize_t count[H5S_MAX_RANK];  /* Hyperslab count information */
4360
4361
        /* Sanity checks */
4362
0
        assert(H5S_UNLIMITED == HSIZE_UNDEF);
4363
0
        assert(version >= H5S_HYPER_VERSION_2);
4364
4365
        /* Decode start/stride/block/count */
4366
0
        switch (enc_size) {
4367
0
            case H5S_SELECT_INFO_ENC_SIZE_2:
4368
0
                for (u = 0; u < tmp_space->extent.rank; u++) {
4369
0
                    if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, 4 * sizeof(uint16_t), p_end))
4370
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4371
0
                                    "buffer overflow while decoding selection ranks");
4372
4373
0
                    UINT16DECODE(pp, start[u]);
4374
0
                    UINT16DECODE(pp, stride[u]);
4375
4376
0
                    UINT16DECODE(pp, count[u]);
4377
0
                    if ((uint16_t)count[u] == H5S_UINT16_MAX)
4378
0
                        count[u] = H5S_UNLIMITED;
4379
4380
0
                    UINT16DECODE(pp, block[u]);
4381
0
                    if ((uint16_t)block[u] == H5S_UINT16_MAX)
4382
0
                        block[u] = H5S_UNLIMITED;
4383
0
                } /* end for */
4384
0
                break;
4385
4386
0
            case H5S_SELECT_INFO_ENC_SIZE_4:
4387
0
                for (u = 0; u < tmp_space->extent.rank; u++) {
4388
0
                    if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, 4 * sizeof(uint32_t), p_end))
4389
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4390
0
                                    "buffer overflow while decoding selection ranks");
4391
4392
0
                    UINT32DECODE(pp, start[u]);
4393
0
                    UINT32DECODE(pp, stride[u]);
4394
4395
0
                    UINT32DECODE(pp, count[u]);
4396
0
                    if ((uint32_t)count[u] == H5S_UINT32_MAX)
4397
0
                        count[u] = H5S_UNLIMITED;
4398
4399
0
                    UINT32DECODE(pp, block[u]);
4400
0
                    if ((uint32_t)block[u] == H5S_UINT32_MAX)
4401
0
                        block[u] = H5S_UNLIMITED;
4402
0
                } /* end for */
4403
0
                break;
4404
4405
0
            case H5S_SELECT_INFO_ENC_SIZE_8:
4406
0
                for (u = 0; u < tmp_space->extent.rank; u++) {
4407
0
                    if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, 4 * sizeof(uint64_t), p_end))
4408
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4409
0
                                    "buffer overflow while decoding selection ranks");
4410
4411
0
                    UINT64DECODE(pp, start[u]);
4412
0
                    UINT64DECODE(pp, stride[u]);
4413
4414
0
                    UINT64DECODE(pp, count[u]);
4415
0
                    if ((uint64_t)count[u] == H5S_UINT64_MAX)
4416
0
                        count[u] = H5S_UNLIMITED;
4417
4418
0
                    UINT64DECODE(pp, block[u]);
4419
0
                    if ((uint64_t)block[u] == H5S_UINT64_MAX)
4420
0
                        block[u] = H5S_UNLIMITED;
4421
0
                } /* end for */
4422
0
                break;
4423
4424
0
            default:
4425
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unknown offset info size for hyperslab");
4426
0
                break;
4427
0
        } /* end switch */
4428
4429
        /* Select the hyperslab to the current selection */
4430
0
        if ((ret_value = H5S_select_hyperslab(tmp_space, H5S_SELECT_SET, start, stride, count, block)) < 0)
4431
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't change selection");
4432
0
    } /* end if */
4433
0
    else {
4434
0
        const hsize_t *stride;            /* Hyperslab stride information */
4435
0
        const hsize_t *count;             /* Hyperslab count information */
4436
0
        hsize_t        end[H5S_MAX_RANK]; /* Hyperslab end information */
4437
0
        hsize_t       *tstart;            /* Temporary hyperslab pointers */
4438
0
        hsize_t       *tend;              /* Temporary hyperslab pointers */
4439
0
        hsize_t       *tblock;            /* Temporary hyperslab pointers */
4440
0
        size_t         num_elem;          /* Number of elements in selection */
4441
0
        unsigned       v;                 /* Local counting variable */
4442
4443
        /* Decode the number of blocks */
4444
0
        switch (enc_size) {
4445
0
            case H5S_SELECT_INFO_ENC_SIZE_2:
4446
0
                if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, sizeof(uint16_t), p_end))
4447
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4448
0
                                "buffer overflow while decoding number of selection blocks");
4449
0
                UINT16DECODE(pp, num_elem);
4450
0
                break;
4451
4452
0
            case H5S_SELECT_INFO_ENC_SIZE_4:
4453
0
                if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, sizeof(uint32_t), p_end))
4454
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4455
0
                                "buffer overflow while decoding number of selection blocks");
4456
0
                UINT32DECODE(pp, num_elem);
4457
0
                break;
4458
4459
0
            case H5S_SELECT_INFO_ENC_SIZE_8:
4460
0
                if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, sizeof(uint64_t), p_end))
4461
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4462
0
                                "buffer overflow while decoding number of selection blocks");
4463
0
                UINT64DECODE(pp, num_elem);
4464
0
                break;
4465
4466
0
            default:
4467
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unknown offset info size for hyperslab");
4468
0
                break;
4469
0
        } /* end switch */
4470
4471
        /* Set the count & stride for all blocks */
4472
0
        stride = count = H5S_hyper_ones_g;
4473
4474
        /* Retrieve the coordinates from the buffer */
4475
0
        for (u = 0; u < num_elem; u++) {
4476
            /* Decode the starting and ending points */
4477
0
            switch (enc_size) {
4478
0
                case H5S_SELECT_INFO_ENC_SIZE_2:
4479
0
                    if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, rank * 2 * sizeof(uint16_t), p_end))
4480
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4481
0
                                    "buffer overflow while decoding selection coordinates");
4482
4483
0
                    for (tstart = start, v = 0; v < rank; v++, tstart++)
4484
0
                        UINT16DECODE(pp, *tstart);
4485
0
                    for (tend = end, v = 0; v < rank; v++, tend++)
4486
0
                        UINT16DECODE(pp, *tend);
4487
0
                    break;
4488
4489
0
                case H5S_SELECT_INFO_ENC_SIZE_4:
4490
0
                    if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, rank * 2 * sizeof(uint32_t), p_end))
4491
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4492
0
                                    "buffer overflow while decoding selection coordinates");
4493
4494
0
                    for (tstart = start, v = 0; v < rank; v++, tstart++)
4495
0
                        UINT32DECODE(pp, *tstart);
4496
0
                    for (tend = end, v = 0; v < rank; v++, tend++)
4497
0
                        UINT32DECODE(pp, *tend);
4498
0
                    break;
4499
4500
0
                case H5S_SELECT_INFO_ENC_SIZE_8:
4501
0
                    if (H5_IS_KNOWN_BUFFER_OVERFLOW(skip, pp, rank * 2 * sizeof(uint64_t), p_end))
4502
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_OVERFLOW, FAIL,
4503
0
                                    "buffer overflow while decoding selection coordinates");
4504
4505
0
                    for (tstart = start, v = 0; v < rank; v++, tstart++)
4506
0
                        UINT64DECODE(pp, *tstart);
4507
0
                    for (tend = end, v = 0; v < rank; v++, tend++)
4508
0
                        UINT64DECODE(pp, *tend);
4509
0
                    break;
4510
4511
0
                default:
4512
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL,
4513
0
                                "unknown offset info size for hyperslab");
4514
0
                    break;
4515
0
            } /* end switch */
4516
4517
            /* Change the ending points into blocks */
4518
0
            for (tblock = block, tstart = start, tend = end, v = 0; v < rank; v++, tstart++, tend++, tblock++)
4519
0
                *tblock = (*tend - *tstart) + 1;
4520
4521
            /* Select or add the hyperslab to the current selection */
4522
0
            if ((ret_value = H5S_select_hyperslab(tmp_space, (u == 0 ? H5S_SELECT_SET : H5S_SELECT_OR), start,
4523
0
                                                  stride, count, block)) < 0)
4524
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't change selection");
4525
0
        } /* end for */
4526
0
    }     /* end else */
4527
4528
    /* Update decoding pointer */
4529
0
    *p = pp;
4530
4531
    /* Return space to the caller if allocated */
4532
0
    if (!*space)
4533
0
        *space = tmp_space;
4534
4535
0
done:
4536
    /* Free temporary space if not passed to caller (only happens on error) */
4537
0
    if (!*space && tmp_space)
4538
0
        if (H5S_close(tmp_space) < 0)
4539
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't close dataspace");
4540
4541
0
    FUNC_LEAVE_NOAPI(ret_value)
4542
0
} /* end H5S__hyper_deserialize() */
4543
4544
/*--------------------------------------------------------------------------
4545
 NAME
4546
    H5S__hyper_span_blocklist
4547
 PURPOSE
4548
    Get a list of hyperslab blocks currently selected
4549
 USAGE
4550
    herr_t H5S__hyper_span_blocklist(spans, start, end, rank, startblock, numblocks, buf)
4551
        H5S_hyper_span_info_t *spans;   IN: Dataspace pointer of selection to query
4552
        hsize_t start[];       IN/OUT: Accumulated start points
4553
        hsize_t end[];         IN/OUT: Accumulated end points
4554
        hsize_t rank;           IN: Rank of dataspace
4555
        hsize_t *startblock;    IN/OUT: Hyperslab block to start with
4556
        hsize_t *numblocks;     IN/OUT: Number of hyperslab blocks to get
4557
        hsize_t **buf;          OUT: List of hyperslab blocks selected
4558
 RETURNS
4559
    Non-negative on success/Negative on failure
4560
 DESCRIPTION
4561
        Puts a list of the hyperslab blocks into the user's buffer.  The blocks
4562
    start with the '*startblock'th block in the list of blocks and put
4563
    '*numblocks' number of blocks into the user's buffer (or until the end of
4564
    the list of blocks, whichever happens first)
4565
        The block coordinates have the same dimensionality (rank) as the
4566
    dataspace they are located within.  The list of blocks is formatted as
4567
    follows: <"start" coordinate> immediately followed by <"opposite" corner
4568
    coordinate>, followed by the next "start" and "opposite" coordinate, etc.
4569
    until all the block information requested has been put into the user's
4570
    buffer.
4571
        No guarantee of any order of the blocks is implied.
4572
 GLOBAL VARIABLES
4573
 COMMENTS, BUGS, ASSUMPTIONS
4574
 EXAMPLES
4575
 REVISION LOG
4576
--------------------------------------------------------------------------*/
4577
static herr_t
4578
H5S__hyper_span_blocklist(const H5S_hyper_span_info_t *spans, hsize_t start[], hsize_t end[], hsize_t rank,
4579
                          hsize_t *startblock, hsize_t *numblocks, hsize_t **buf)
4580
0
{
4581
0
    const H5S_hyper_span_t *curr;                /* Pointer to current hyperslab span */
4582
0
    herr_t                  ret_value = SUCCEED; /* return value */
4583
4584
0
    FUNC_ENTER_PACKAGE
4585
4586
    /* Sanity checks */
4587
0
    assert(spans);
4588
0
    assert(rank < H5S_MAX_RANK);
4589
0
    assert(start);
4590
0
    assert(end);
4591
0
    assert(startblock);
4592
0
    assert(numblocks && *numblocks > 0);
4593
0
    assert(buf && *buf);
4594
4595
    /* Walk through the list of spans, recursing or outputting them */
4596
0
    curr = spans->head;
4597
0
    while (curr != NULL && *numblocks > 0) {
4598
        /* Recurse if this node has down spans */
4599
0
        if (curr->down != NULL) {
4600
            /* Add the starting and ending points for this span to the list */
4601
0
            start[rank] = curr->low;
4602
0
            end[rank]   = curr->high;
4603
4604
            /* Recurse down to the next dimension */
4605
0
            if (H5S__hyper_span_blocklist(curr->down, start, end, (rank + 1), startblock, numblocks, buf) < 0)
4606
0
                HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans");
4607
0
        } /* end if */
4608
0
        else {
4609
            /* Skip this block if we haven't skipped all the startblocks yet */
4610
0
            if (*startblock > 0) {
4611
                /* Decrement the starting block */
4612
0
                (*startblock)--;
4613
0
            } /* end if */
4614
            /* Process this block */
4615
0
            else {
4616
                /* Encode all the previous dimensions starting & ending points */
4617
4618
                /* Copy previous starting points */
4619
0
                H5MM_memcpy(*buf, start, rank * sizeof(hsize_t));
4620
0
                (*buf) += rank;
4621
4622
                /* Copy starting point for this span */
4623
0
                **buf = curr->low;
4624
0
                (*buf)++;
4625
4626
                /* Copy previous ending points */
4627
0
                H5MM_memcpy(*buf, end, rank * sizeof(hsize_t));
4628
0
                (*buf) += rank;
4629
4630
                /* Copy ending point for this span */
4631
0
                **buf = curr->high;
4632
0
                (*buf)++;
4633
4634
                /* Decrement the number of blocks processed */
4635
0
                (*numblocks)--;
4636
0
            } /* end else */
4637
0
        }     /* end else */
4638
4639
        /* Advance to next node */
4640
0
        curr = curr->next;
4641
0
    } /* end while */
4642
4643
0
done:
4644
0
    FUNC_LEAVE_NOAPI(ret_value)
4645
0
} /* end H5S__hyper_span_blocklist() */
4646
4647
/*--------------------------------------------------------------------------
4648
 NAME
4649
    H5S__get_select_hyper_blocklist
4650
 PURPOSE
4651
    Get the list of hyperslab blocks currently selected
4652
 USAGE
4653
    herr_t H5S__get_select_hyper_blocklist(space, startblock, numblocks, buf)
4654
        H5S_t *space;           IN: Dataspace pointer of selection to query
4655
        hsize_t startblock;     IN: Hyperslab block to start with
4656
        hsize_t numblocks;      IN: Number of hyperslab blocks to get
4657
        hsize_t *buf;           OUT: List of hyperslab blocks selected
4658
 RETURNS
4659
    Non-negative on success, negative on failure
4660
 DESCRIPTION
4661
        Puts a list of the hyperslab blocks into the user's buffer.  The blocks
4662
    start with the 'startblock'th block in the list of blocks and put
4663
    'numblocks' number of blocks into the user's buffer (or until the end of
4664
    the list of blocks, whichever happens first)
4665
        The block coordinates have the same dimensionality (rank) as the
4666
    dataspace they are located within.  The list of blocks is formatted as
4667
    follows: <"start" coordinate> immediately followed by <"opposite" corner
4668
    coordinate>, followed by the next "start" and "opposite" coordinate, etc.
4669
    until all the block information requested has been put into the user's
4670
    buffer.
4671
        No guarantee of any order of the blocks is implied.
4672
 GLOBAL VARIABLES
4673
 COMMENTS, BUGS, ASSUMPTIONS
4674
 EXAMPLES
4675
 REVISION LOG
4676
--------------------------------------------------------------------------*/
4677
static herr_t
4678
H5S__get_select_hyper_blocklist(H5S_t *space, hsize_t startblock, hsize_t numblocks, hsize_t *buf)
4679
0
{
4680
0
    herr_t ret_value = SUCCEED; /* Return value */
4681
4682
0
    FUNC_ENTER_PACKAGE
4683
4684
0
    assert(space);
4685
0
    assert(buf);
4686
0
    assert(space->select.sel_info.hslab->unlim_dim < 0);
4687
4688
0
    if (space->extent.rank == 0)
4689
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL,
4690
0
                    "dataspace has invalid extent for hyperslab selection");
4691
4692
    /* Attempt to rebuild diminfo if it is invalid and has not been confirmed
4693
     * to be impossible.
4694
     */
4695
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO)
4696
0
        H5S__hyper_rebuild(space);
4697
4698
    /* Check for a "regular" hyperslab selection */
4699
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
4700
0
        const H5S_hyper_dim_t *diminfo;                 /* Alias for dataspace's diminfo information */
4701
0
        hsize_t                tmp_count[H5S_MAX_RANK]; /* Temporary hyperslab counts */
4702
0
        hsize_t                offset[H5S_MAX_RANK];    /* Offset of element in dataspace */
4703
0
        hsize_t                end[H5S_MAX_RANK];       /* End of elements in dataspace */
4704
0
        unsigned               fast_dim; /* Rank of the fastest changing dimension for the dataspace */
4705
0
        unsigned               ndims;    /* Rank of the dataspace */
4706
0
        bool                   done;     /* Whether we are done with the iteration */
4707
0
        unsigned               u;        /* Counter */
4708
4709
        /* Set some convenience values */
4710
0
        ndims    = space->extent.rank;
4711
0
        fast_dim = ndims - 1;
4712
4713
        /* Check which set of dimension information to use */
4714
0
        if (space->select.sel_info.hslab->unlim_dim >= 0)
4715
            /*
4716
             * There is an unlimited dimension so we must use diminfo.opt as
4717
             * it has been "clipped" to the current extent.
4718
             */
4719
0
            diminfo = space->select.sel_info.hslab->diminfo.opt;
4720
0
        else
4721
            /*
4722
             * Use the "application dimension information" to pass back to
4723
             * the user the blocks they set, not the optimized, internal
4724
             * information.
4725
             */
4726
0
            diminfo = space->select.sel_info.hslab->diminfo.app;
4727
4728
        /* Build the tables of count sizes as well as the initial offset */
4729
0
        for (u = 0; u < ndims; u++) {
4730
0
            tmp_count[u] = diminfo[u].count;
4731
0
            offset[u]    = diminfo[u].start;
4732
0
            end[u]       = diminfo[u].start + (diminfo[u].block - 1);
4733
0
        } /* end for */
4734
4735
        /* We're not done with the iteration */
4736
0
        done = false;
4737
4738
        /* Go iterate over the hyperslabs */
4739
0
        while (!done && numblocks > 0) {
4740
            /* Skip over initial blocks */
4741
0
            if (startblock > 0) {
4742
                /* Skip all blocks in row */
4743
0
                if (startblock >= tmp_count[fast_dim]) {
4744
0
                    startblock -= tmp_count[fast_dim];
4745
0
                    tmp_count[fast_dim] = 0;
4746
0
                } /* end if */
4747
0
                else {
4748
                    /* Move the offset to the next sequence to start */
4749
0
                    offset[fast_dim] += diminfo[fast_dim].stride * startblock;
4750
0
                    end[fast_dim] += diminfo[fast_dim].stride * startblock;
4751
4752
                    /* Decrement the block count */
4753
0
                    tmp_count[fast_dim] -= startblock;
4754
4755
                    /* Done with starting blocks */
4756
0
                    startblock = 0;
4757
0
                } /* end else */
4758
0
            }     /* end if */
4759
4760
            /* Iterate over the blocks in the fastest dimension */
4761
0
            while (tmp_count[fast_dim] > 0 && numblocks > 0) {
4762
                /* Sanity check */
4763
0
                assert(startblock == 0);
4764
4765
                /* Copy the starting location */
4766
0
                H5MM_memcpy(buf, offset, sizeof(hsize_t) * ndims);
4767
0
                buf += ndims;
4768
4769
                /* Compute the ending location */
4770
0
                H5MM_memcpy(buf, end, sizeof(hsize_t) * ndims);
4771
0
                buf += ndims;
4772
4773
                /* Decrement the number of blocks to retrieve */
4774
0
                numblocks--;
4775
4776
                /* Move the offset to the next sequence to start */
4777
0
                offset[fast_dim] += diminfo[fast_dim].stride;
4778
0
                end[fast_dim] += diminfo[fast_dim].stride;
4779
4780
                /* Decrement the block count */
4781
0
                tmp_count[fast_dim]--;
4782
0
            } /* end while */
4783
4784
            /* Work on other dimensions if necessary */
4785
0
            if (fast_dim > 0 && numblocks > 0) {
4786
0
                int temp_dim; /* Temporary rank holder */
4787
4788
                /* Reset the block counts */
4789
0
                tmp_count[fast_dim] = diminfo[fast_dim].count;
4790
4791
                /* Bubble up the decrement to the slower changing dimensions */
4792
0
                temp_dim = (int)(fast_dim - 1);
4793
0
                while (temp_dim >= 0 && !done) {
4794
                    /* Decrement the block count */
4795
0
                    tmp_count[temp_dim]--;
4796
4797
                    /* Check if we have more blocks left */
4798
0
                    if (tmp_count[temp_dim] > 0)
4799
0
                        break;
4800
4801
                    /* Reset the block count in this dimension */
4802
0
                    tmp_count[temp_dim] = diminfo[temp_dim].count;
4803
4804
                    /* Check for getting out of iterator */
4805
0
                    if (temp_dim == 0)
4806
0
                        done = true;
4807
4808
                    /* Wrapped a dimension, go up to next dimension */
4809
0
                    temp_dim--;
4810
0
                } /* end while */
4811
0
            }     /* end if */
4812
4813
            /* Re-compute offset & end arrays */
4814
0
            if (!done)
4815
0
                for (u = 0; u < ndims; u++) {
4816
0
                    offset[u] = diminfo[u].start + diminfo[u].stride * (diminfo[u].count - tmp_count[u]);
4817
0
                    end[u]    = offset[u] + (diminfo[u].block - 1);
4818
0
                } /* end for */
4819
0
        }         /* end while */
4820
0
    }             /* end if */
4821
0
    else {
4822
0
        hsize_t start[H5S_MAX_RANK]; /* Location of start of hyperslab */
4823
0
        hsize_t end[H5S_MAX_RANK];   /* Location of end of hyperslab */
4824
4825
0
        ret_value = H5S__hyper_span_blocklist(space->select.sel_info.hslab->span_lst, start, end, (hsize_t)0,
4826
0
                                              &startblock, &numblocks, &buf);
4827
0
    } /* end else */
4828
4829
0
done:
4830
0
    FUNC_LEAVE_NOAPI(ret_value)
4831
0
} /* end H5S__get_select_hyper_blocklist() */
4832
4833
/*--------------------------------------------------------------------------
4834
 NAME
4835
    H5Sget_select_hyper_blocklist
4836
 PURPOSE
4837
    Get the list of hyperslab blocks currently selected
4838
 USAGE
4839
    herr_t H5Sget_select_hyper_blocklist(dsid, startblock, numblocks, buf)
4840
        hid_t dsid;             IN: Dataspace ID of selection to query
4841
        hsize_t startblock;     IN: Hyperslab block to start with
4842
        hsize_t numblocks;      IN: Number of hyperslab blocks to get
4843
        hsize_t buf[];          OUT: List of hyperslab blocks selected
4844
 RETURNS
4845
    Non-negative on success, negative on failure
4846
 DESCRIPTION
4847
        Puts a list of the hyperslab blocks into the user's buffer.  The blocks
4848
    start with the 'startblock'th block in the list of blocks and put
4849
    'numblocks' number of blocks into the user's buffer (or until the end of
4850
    the list of blocks, whichever happen first)
4851
        The block coordinates have the same dimensionality (rank) as the
4852
    dataspace they are located within.  The list of blocks is formatted as
4853
    follows: <"start" coordinate> immediately followed by <"opposite" corner
4854
    coordinate>, followed by the next "start" and "opposite" coordinate, etc.
4855
    until all the block information requested has been put into the user's
4856
    buffer.
4857
        No guarantee of any order of the blocks is implied.
4858
 GLOBAL VARIABLES
4859
 COMMENTS, BUGS, ASSUMPTIONS
4860
 EXAMPLES
4861
 REVISION LOG
4862
--------------------------------------------------------------------------*/
4863
herr_t
4864
H5Sget_select_hyper_blocklist(hid_t spaceid, hsize_t startblock, hsize_t numblocks,
4865
                              hsize_t buf[/*numblocks*/] /*out*/)
4866
0
{
4867
0
    H5S_t *space;     /* Dataspace to modify selection of */
4868
0
    herr_t ret_value; /* return value */
4869
4870
0
    FUNC_ENTER_API(FAIL)
4871
4872
    /* Check args */
4873
0
    if (buf == NULL)
4874
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid pointer");
4875
0
    if (NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE)))
4876
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace");
4877
0
    if (H5S_GET_SELECT_TYPE(space) != H5S_SEL_HYPERSLABS)
4878
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a hyperslab selection");
4879
0
    if (space->select.sel_info.hslab->unlim_dim >= 0)
4880
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot get blocklist for unlimited selection");
4881
4882
    /* Go get the correct number of blocks */
4883
0
    if (numblocks > 0)
4884
0
        ret_value = H5S__get_select_hyper_blocklist(space, startblock, numblocks, buf);
4885
0
    else
4886
0
        ret_value = SUCCEED; /* Successfully got 0 blocks... */
4887
4888
0
done:
4889
0
    FUNC_LEAVE_API(ret_value)
4890
0
} /* end H5Sget_select_hyper_blocklist() */
4891
4892
/*--------------------------------------------------------------------------
4893
 NAME
4894
    H5S__hyper_bounds
4895
 PURPOSE
4896
    Gets the bounding box containing the selection.
4897
 USAGE
4898
    herr_t H5S__hyper_bounds(space, hsize_t *start, hsize_t *end)
4899
        H5S_t *space;           IN: Dataspace pointer of selection to query
4900
        hsize_t *start;         OUT: Starting coordinate of bounding box
4901
        hsize_t *end;           OUT: Opposite coordinate of bounding box
4902
 RETURNS
4903
    Non-negative on success, negative on failure
4904
 DESCRIPTION
4905
    Retrieves the bounding box containing the current selection and places
4906
    it into the user's buffers.  The start and end buffers must be large
4907
    enough to hold the dataspace rank number of coordinates.  The bounding box
4908
    exactly contains the selection, ie. if a 2-D element selection is currently
4909
    defined with the following points: (4,5), (6,8) (10,7), the bounding box
4910
    with be (4, 5), (10, 8).
4911
        The bounding box calculations _does_ include the current offset of the
4912
    selection within the dataspace extent.
4913
 GLOBAL VARIABLES
4914
 COMMENTS, BUGS, ASSUMPTIONS
4915
 EXAMPLES
4916
 REVISION LOG
4917
--------------------------------------------------------------------------*/
4918
static herr_t
4919
H5S__hyper_bounds(const H5S_t *space, hsize_t *start, hsize_t *end)
4920
0
{
4921
0
    const hsize_t *low_bounds, *high_bounds; /* Pointers to the correct pair of low & high bounds */
4922
0
    herr_t         ret_value = SUCCEED;      /* Return value */
4923
4924
0
    FUNC_ENTER_PACKAGE
4925
4926
    /* Sanity check */
4927
0
    assert(space);
4928
0
    assert(start);
4929
0
    assert(end);
4930
4931
    /* Check which set of low & high bounds we should be using */
4932
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
4933
0
        low_bounds  = space->select.sel_info.hslab->diminfo.low_bounds;
4934
0
        high_bounds = space->select.sel_info.hslab->diminfo.high_bounds;
4935
0
    } /* end if */
4936
0
    else {
4937
0
        low_bounds  = space->select.sel_info.hslab->span_lst->low_bounds;
4938
0
        high_bounds = space->select.sel_info.hslab->span_lst->high_bounds;
4939
0
    } /* end else */
4940
4941
    /* Check for offset set */
4942
0
    if (space->select.offset_changed) {
4943
0
        unsigned u; /* Local index variable */
4944
4945
        /* Loop over dimensions */
4946
0
        for (u = 0; u < space->extent.rank; u++) {
4947
            /* Sanity check */
4948
0
            assert(low_bounds[u] <= high_bounds[u]);
4949
4950
            /* Check for offset moving selection negative */
4951
0
            if (((hssize_t)low_bounds[u] + space->select.offset[u]) < 0)
4952
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds");
4953
4954
            /* Set the low & high bounds in this dimension */
4955
0
            start[u] = (hsize_t)((hssize_t)low_bounds[u] + space->select.offset[u]);
4956
0
            if ((int)u == space->select.sel_info.hslab->unlim_dim)
4957
0
                end[u] = H5S_UNLIMITED;
4958
0
            else
4959
0
                end[u] = (hsize_t)((hssize_t)high_bounds[u] + space->select.offset[u]);
4960
0
        } /* end for */
4961
0
    }     /* end if */
4962
0
    else {
4963
        /* Offset vector is still zeros, just copy low & high bounds */
4964
0
        H5MM_memcpy(start, low_bounds, sizeof(hsize_t) * space->extent.rank);
4965
0
        H5MM_memcpy(end, high_bounds, sizeof(hsize_t) * space->extent.rank);
4966
0
    } /* end else */
4967
4968
0
done:
4969
0
    FUNC_LEAVE_NOAPI(ret_value)
4970
0
} /* end H5S__hyper_bounds() */
4971
4972
/*--------------------------------------------------------------------------
4973
 NAME
4974
    H5S__hyper_offset
4975
 PURPOSE
4976
    Gets the linear offset of the first element for the selection.
4977
 USAGE
4978
    herr_t H5S__hyper_offset(space, offset)
4979
        const H5S_t *space;     IN: Dataspace pointer of selection to query
4980
        hsize_t *offset;        OUT: Linear offset of first element in selection
4981
 RETURNS
4982
    Non-negative on success, negative on failure
4983
 DESCRIPTION
4984
    Retrieves the linear offset (in "units" of elements) of the first element
4985
    selected within the dataspace.
4986
 GLOBAL VARIABLES
4987
 COMMENTS, BUGS, ASSUMPTIONS
4988
    Calling this function on a "none" selection returns fail.
4989
 EXAMPLES
4990
 REVISION LOG
4991
--------------------------------------------------------------------------*/
4992
static herr_t
4993
H5S__hyper_offset(const H5S_t *space, hsize_t *offset)
4994
0
{
4995
0
    const hssize_t *sel_offset;          /* Pointer to the selection's offset */
4996
0
    const hsize_t  *dim_size;            /* Pointer to a dataspace's extent */
4997
0
    hsize_t         accum;               /* Accumulator for dimension sizes */
4998
0
    unsigned        rank;                /* Dataspace rank */
4999
0
    int             i;                   /* index variable */
5000
0
    herr_t          ret_value = SUCCEED; /* Return value */
5001
5002
0
    FUNC_ENTER_PACKAGE
5003
5004
0
    assert(space && space->extent.rank > 0);
5005
0
    assert(offset);
5006
5007
    /* Start at linear offset 0 */
5008
0
    *offset = 0;
5009
5010
    /* Set up pointers to arrays of values */
5011
0
    rank       = space->extent.rank;
5012
0
    sel_offset = space->select.offset;
5013
0
    dim_size   = space->extent.size;
5014
5015
    /* Check for a "regular" hyperslab selection */
5016
    /* (No need to rebuild the dimension info yet -QAK) */
5017
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
5018
0
        const H5S_hyper_dim_t *diminfo =
5019
0
            space->select.sel_info.hslab->diminfo.opt; /* Local alias for diminfo */
5020
5021
        /* Loop through starting coordinates, calculating the linear offset */
5022
0
        accum = 1;
5023
0
        for (i = (int)(rank - 1); i >= 0; i--) {
5024
0
            hssize_t hyp_offset =
5025
0
                (hssize_t)diminfo[i].start + sel_offset[i]; /* Hyperslab's offset in this dimension */
5026
5027
            /* Check for offset moving selection out of the dataspace */
5028
0
            if (hyp_offset < 0 || (hsize_t)hyp_offset >= dim_size[i])
5029
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds");
5030
5031
            /* Add the hyperslab's offset in this dimension to the total linear offset */
5032
0
            *offset += (hsize_t)(hyp_offset * (hssize_t)accum);
5033
5034
            /* Increase the accumulator */
5035
0
            accum *= dim_size[i];
5036
0
        } /* end for */
5037
0
    }     /* end if */
5038
0
    else {
5039
0
        const H5S_hyper_span_t *span;                    /* Hyperslab span node */
5040
0
        hsize_t                 dim_accum[H5S_MAX_RANK]; /* Accumulators, for each dimension */
5041
5042
        /* Calculate the accumulator for each dimension */
5043
0
        accum = 1;
5044
0
        for (i = (int)(rank - 1); i >= 0; i--) {
5045
            /* Set the accumulator for this dimension */
5046
0
            dim_accum[i] = accum;
5047
5048
            /* Increase the accumulator */
5049
0
            accum *= dim_size[i];
5050
0
        } /* end for */
5051
5052
        /* Get information for the first span, in the slowest changing dimension */
5053
0
        span = space->select.sel_info.hslab->span_lst->head;
5054
5055
        /* Work down the spans, computing the linear offset */
5056
0
        i = 0;
5057
0
        while (span) {
5058
0
            hssize_t hyp_offset =
5059
0
                (hssize_t)span->low + sel_offset[i]; /* Hyperslab's offset in this dimension */
5060
5061
            /* Check for offset moving selection out of the dataspace */
5062
0
            if (hyp_offset < 0 || (hsize_t)hyp_offset >= dim_size[i])
5063
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds");
5064
5065
            /* Add the hyperslab's offset in this dimension to the total linear offset */
5066
0
            *offset += (hsize_t)(hyp_offset * (hssize_t)dim_accum[i]);
5067
5068
            /* Advance to first span in "down" dimension */
5069
0
            if (span->down) {
5070
0
                assert(span->down->head);
5071
0
                span = span->down->head;
5072
0
            } /* end if */
5073
0
            else
5074
0
                span = NULL;
5075
0
            i++;
5076
0
        } /* end while */
5077
0
    }     /* end else */
5078
5079
0
done:
5080
0
    FUNC_LEAVE_NOAPI(ret_value)
5081
0
} /* end H5S__hyper_offset() */
5082
5083
/*--------------------------------------------------------------------------
5084
 NAME
5085
    H5S__hyper_unlim_dim
5086
 PURPOSE
5087
    Return unlimited dimension of selection, or -1 if none
5088
 USAGE
5089
    int H5S__hyper_unlim_dim(space)
5090
        H5S_t *space;           IN: Dataspace pointer to check
5091
 RETURNS
5092
    Unlimited dimension of selection, or -1 if none (never fails).
5093
 DESCRIPTION
5094
    Returns the index of the unlimited dimension of the selection, or -1
5095
    if the selection has no unlimited dimension.
5096
 GLOBAL VARIABLES
5097
 COMMENTS, BUGS, ASSUMPTIONS
5098
 EXAMPLES
5099
 REVISION LOG
5100
--------------------------------------------------------------------------*/
5101
static int
5102
H5S__hyper_unlim_dim(const H5S_t *space)
5103
0
{
5104
0
    FUNC_ENTER_PACKAGE_NOERR
5105
5106
0
    FUNC_LEAVE_NOAPI(space->select.sel_info.hslab->unlim_dim)
5107
0
} /* end H5S__hyper_unlim_dim() */
5108
5109
/*--------------------------------------------------------------------------
5110
 NAME
5111
    H5S__hyper_num_elem_non_unlim
5112
 PURPOSE
5113
    Return number of elements in the non-unlimited dimensions
5114
 USAGE
5115
    herr_t H5S__hyper_num_elem_non_unlim(space,num_elem_non_unlim)
5116
        H5S_t *space;           IN: Dataspace pointer to check
5117
        hsize_t *num_elem_non_unlim; OUT: Number of elements in the non-unlimited dimensions
5118
 RETURNS
5119
    Non-negative on success/Negative on failure
5120
 DESCRIPTION
5121
    Returns the number of elements in a slice through the non-unlimited
5122
    dimensions of the selection.  Fails if the selection has no unlimited
5123
    dimension.
5124
 GLOBAL VARIABLES
5125
 COMMENTS, BUGS, ASSUMPTIONS
5126
 EXAMPLES
5127
 REVISION LOG
5128
--------------------------------------------------------------------------*/
5129
static herr_t
5130
H5S__hyper_num_elem_non_unlim(const H5S_t *space, hsize_t *num_elem_non_unlim)
5131
0
{
5132
0
    herr_t ret_value = SUCCEED;
5133
5134
0
    FUNC_ENTER_PACKAGE
5135
5136
    /* Sanity check */
5137
0
    assert(space);
5138
0
    assert(num_elem_non_unlim);
5139
5140
    /* Get number of elements in the non-unlimited dimensions */
5141
0
    if (space->select.sel_info.hslab->unlim_dim >= 0)
5142
0
        *num_elem_non_unlim = space->select.sel_info.hslab->num_elem_non_unlim;
5143
0
    else
5144
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "selection has no unlimited dimension");
5145
5146
0
done:
5147
0
    FUNC_LEAVE_NOAPI(ret_value)
5148
0
} /* end H5S__hyper_num_elem_non_unlim() */
5149
5150
/*--------------------------------------------------------------------------
5151
 NAME
5152
    H5S__hyper_is_contiguous
5153
 PURPOSE
5154
    Check if a hyperslab selection is contiguous within the dataspace extent.
5155
 USAGE
5156
    htri_t H5S__hyper_is_contiguous(space)
5157
        H5S_t *space;           IN: Dataspace pointer to check
5158
 RETURNS
5159
    true/false/FAIL
5160
 DESCRIPTION
5161
    Checks to see if the current selection in the dataspace is contiguous.
5162
    This is primarily used for reading the entire selection in one swoop.
5163
 GLOBAL VARIABLES
5164
 COMMENTS, BUGS, ASSUMPTIONS
5165
 EXAMPLES
5166
 REVISION LOG
5167
--------------------------------------------------------------------------*/
5168
static H5_ATTR_PURE htri_t
5169
H5S__hyper_is_contiguous(const H5S_t *space)
5170
0
{
5171
0
    bool small_contiguous,      /* Flag for small contiguous block */
5172
0
        large_contiguous;       /* Flag for large contiguous block */
5173
0
    unsigned u;                 /* index variable */
5174
0
    htri_t   ret_value = false; /* Return value */
5175
5176
0
    FUNC_ENTER_PACKAGE_NOERR
5177
5178
0
    assert(space);
5179
5180
    /* Check for a "regular" hyperslab selection */
5181
    /* (No need to rebuild the dimension info yet -QAK) */
5182
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
5183
0
        const H5S_hyper_dim_t *diminfo =
5184
0
            space->select.sel_info.hslab->diminfo.opt; /* local alias for diminfo */
5185
5186
        /*
5187
         * For a regular hyperslab to be contiguous, it must have only one
5188
         * block (i.e. count==1 in all dimensions) and the block size must be
5189
         * the same as the dataspace extent's in all but the slowest changing
5190
         * dimension. (dubbed "large contiguous" block)
5191
         *
5192
         * OR
5193
         *
5194
         * The selection must have only one block (i.e. count==1) in all
5195
         * dimensions and the block size must be 1 in all but the fastest
5196
         * changing dimension. (dubbed "small contiguous" block)
5197
         */
5198
5199
        /* Initialize flags */
5200
0
        large_contiguous = true;  /* assume true and reset if the dimensions don't match */
5201
0
        small_contiguous = false; /* assume false initially */
5202
5203
        /* Check for a "large contiguous" block */
5204
0
        for (u = 0; u < space->extent.rank; u++) {
5205
0
            if (diminfo[u].count > 1) {
5206
0
                large_contiguous = false;
5207
0
                break;
5208
0
            } /* end if */
5209
0
            if (u > 0 && diminfo[u].block != space->extent.size[u]) {
5210
0
                large_contiguous = false;
5211
0
                break;
5212
0
            } /* end if */
5213
0
        }     /* end for */
5214
5215
        /* If we didn't find a large contiguous block, check for a small one */
5216
0
        if (!large_contiguous) {
5217
0
            small_contiguous = true;
5218
0
            for (u = 0; u < space->extent.rank; u++) {
5219
0
                if (diminfo[u].count > 1) {
5220
0
                    small_contiguous = false;
5221
0
                    break;
5222
0
                } /* end if */
5223
0
                if (u < (space->extent.rank - 1) && diminfo[u].block != 1) {
5224
0
                    small_contiguous = false;
5225
0
                    break;
5226
0
                } /* end if */
5227
0
            }     /* end for */
5228
0
        }         /* end if */
5229
5230
        /* Indicate true if it's either a large or small contiguous block */
5231
0
        if (large_contiguous || small_contiguous)
5232
0
            ret_value = true;
5233
0
    } /* end if */
5234
0
    else {
5235
0
        H5S_hyper_span_info_t *spans; /* Hyperslab span info node */
5236
0
        H5S_hyper_span_t      *span;  /* Hyperslab span node */
5237
5238
        /*
5239
         * For a hyperslab to be contiguous, it must have only one block and
5240
         * either it's size must be the same as the dataspace extent's in all
5241
         *      but the slowest changing dimension
5242
         *   OR
5243
         *      block size must be 1 in all but the fastest changing dimension.
5244
         */
5245
        /* Initialize flags */
5246
0
        large_contiguous = true;  /* assume true and reset if the dimensions don't match */
5247
0
        small_contiguous = false; /* assume false initially */
5248
5249
        /* Get information for slowest changing information */
5250
0
        spans = space->select.sel_info.hslab->span_lst;
5251
0
        span  = spans->head;
5252
5253
        /* If there are multiple spans in the slowest changing dimension, the selection isn't contiguous */
5254
0
        if (span->next != NULL)
5255
0
            large_contiguous = false;
5256
0
        else {
5257
            /* Now check the rest of the dimensions */
5258
0
            if (span->down != NULL) {
5259
0
                u = 1; /* Current dimension working on */
5260
5261
                /* Get the span information for the next fastest dimension */
5262
0
                spans = span->down;
5263
5264
                /* Cycle down the spans until we run out of down spans or find a non-contiguous span */
5265
0
                while (spans != NULL) {
5266
0
                    span = spans->head;
5267
5268
                    /* Check that this is the only span and it spans the entire dimension */
5269
0
                    if (span->next != NULL) {
5270
0
                        large_contiguous = false;
5271
0
                        break;
5272
0
                    } /* end if */
5273
0
                    else {
5274
                        /* If this span doesn't cover the entire dimension, then this selection isn't
5275
                         * contiguous */
5276
0
                        if (((span->high - span->low) + 1) != space->extent.size[u]) {
5277
0
                            large_contiguous = false;
5278
0
                            break;
5279
0
                        } /* end if */
5280
0
                        else {
5281
                            /* Walk down to the next span */
5282
0
                            spans = span->down;
5283
5284
                            /* Increment dimension */
5285
0
                            u++;
5286
0
                        } /* end else */
5287
0
                    }     /* end else */
5288
0
                }         /* end while */
5289
0
            }             /* end if */
5290
0
        }                 /* end else */
5291
5292
        /* If we didn't find a large contiguous block, check for a small one */
5293
0
        if (!large_contiguous) {
5294
0
            small_contiguous = true;
5295
5296
            /* Get information for slowest changing information */
5297
0
            spans = space->select.sel_info.hslab->span_lst;
5298
0
            span  = spans->head;
5299
5300
            /* Current dimension working on */
5301
0
            u = 0;
5302
5303
            /* Cycle down the spans until we run out of down spans or find a non-contiguous span */
5304
0
            while (spans != NULL) {
5305
0
                span = spans->head;
5306
5307
                /* Check that this is the only span and it spans the entire dimension */
5308
0
                if (span->next != NULL) {
5309
0
                    small_contiguous = false;
5310
0
                    break;
5311
0
                } /* end if */
5312
0
                else {
5313
                    /* If this span doesn't cover the entire dimension, then this selection isn't contiguous
5314
                     */
5315
0
                    if (u < (space->extent.rank - 1) && ((span->high - span->low) + 1) != 1) {
5316
0
                        small_contiguous = false;
5317
0
                        break;
5318
0
                    } /* end if */
5319
0
                    else {
5320
                        /* Walk down to the next span */
5321
0
                        spans = span->down;
5322
5323
                        /* Increment dimension */
5324
0
                        u++;
5325
0
                    } /* end else */
5326
0
                }     /* end else */
5327
0
            }         /* end while */
5328
0
        }             /* end if */
5329
5330
        /* Indicate true if it's either a large or small contiguous block */
5331
0
        if (large_contiguous || small_contiguous)
5332
0
            ret_value = true;
5333
0
    } /* end else */
5334
5335
0
    FUNC_LEAVE_NOAPI(ret_value)
5336
0
} /* end H5S__hyper_is_contiguous() */
5337
5338
/*--------------------------------------------------------------------------
5339
 NAME
5340
    H5S__hyper_is_single
5341
 PURPOSE
5342
    Check if a hyperslab selection is a single block within the dataspace extent.
5343
 USAGE
5344
    htri_t H5S__hyper_is_single(space)
5345
        H5S_t *space;           IN: Dataspace pointer to check
5346
 RETURNS
5347
    true/false/FAIL
5348
 DESCRIPTION
5349
    Checks to see if the current selection in the dataspace is a single block.
5350
    This is primarily used for reading the entire selection in one swoop.
5351
 GLOBAL VARIABLES
5352
 COMMENTS, BUGS, ASSUMPTIONS
5353
 EXAMPLES
5354
 REVISION LOG
5355
--------------------------------------------------------------------------*/
5356
static H5_ATTR_PURE htri_t
5357
H5S__hyper_is_single(const H5S_t *space)
5358
0
{
5359
0
    htri_t ret_value = true; /* return value */
5360
5361
0
    FUNC_ENTER_PACKAGE_NOERR
5362
5363
0
    assert(space);
5364
5365
    /* Check for a "single" hyperslab selection */
5366
    /* (No need to rebuild the dimension info yet, since the span-tree
5367
     *  algorithm is fast -QAK)
5368
     */
5369
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
5370
0
        unsigned u; /* index variable */
5371
5372
        /*
5373
         * For a regular hyperslab to be single, it must have only one
5374
         * block (i.e. count==1 in all dimensions)
5375
         */
5376
5377
        /* Check for a single block */
5378
0
        for (u = 0; u < space->extent.rank; u++)
5379
0
            if (space->select.sel_info.hslab->diminfo.opt[u].count > 1)
5380
0
                HGOTO_DONE(false);
5381
0
    } /* end if */
5382
0
    else {
5383
0
        H5S_hyper_span_info_t *spans; /* Hyperslab span info node */
5384
5385
        /*
5386
         * For a region to be single, it must have only one block
5387
         */
5388
        /* Get information for slowest changing information */
5389
0
        spans = space->select.sel_info.hslab->span_lst;
5390
5391
        /* Cycle down the spans until we run out of down spans or find a non-contiguous span */
5392
0
        while (spans != NULL) {
5393
0
            H5S_hyper_span_t *span; /* Hyperslab span node */
5394
5395
0
            span = spans->head;
5396
5397
            /* Check that this is the only span and it spans the entire dimension */
5398
0
            if (span->next != NULL)
5399
0
                HGOTO_DONE(false);
5400
0
            else
5401
                /* Walk down to the next span */
5402
0
                spans = span->down;
5403
0
        } /* end while */
5404
0
    }     /* end else */
5405
5406
0
done:
5407
0
    FUNC_LEAVE_NOAPI(ret_value)
5408
0
} /* end H5S__hyper_is_single() */
5409
5410
/*--------------------------------------------------------------------------
5411
 NAME
5412
    H5S__hyper_is_regular
5413
 PURPOSE
5414
    Check if a hyperslab selection is "regular"
5415
 USAGE
5416
    htri_t H5S__hyper_is_regular(space)
5417
        H5S_t *space;     IN: Dataspace pointer to check
5418
 RETURNS
5419
    true/false/FAIL
5420
 DESCRIPTION
5421
    Checks to see if the current selection in a dataspace is the a regular
5422
    pattern.
5423
    This is primarily used for reading the entire selection in one swoop.
5424
 GLOBAL VARIABLES
5425
 COMMENTS, BUGS, ASSUMPTIONS
5426
 EXAMPLES
5427
 REVISION LOG
5428
--------------------------------------------------------------------------*/
5429
static htri_t
5430
H5S__hyper_is_regular(H5S_t *space)
5431
0
{
5432
0
    htri_t ret_value = FAIL; /* return value */
5433
5434
0
    FUNC_ENTER_PACKAGE_NOERR
5435
5436
    /* Check args */
5437
0
    assert(space);
5438
5439
    /* Attempt to rebuild diminfo if it is invalid and has not been confirmed
5440
     * to be impossible.
5441
     */
5442
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO)
5443
0
        H5S__hyper_rebuild(space);
5444
5445
    /* Only simple check for regular hyperslabs for now... */
5446
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES)
5447
0
        ret_value = true;
5448
0
    else
5449
0
        ret_value = false;
5450
5451
0
    FUNC_LEAVE_NOAPI(ret_value)
5452
0
} /* end H5S__hyper_is_regular() */
5453
5454
/*--------------------------------------------------------------------------
5455
 NAME
5456
    H5S__hyper_spans_shape_same_helper
5457
 PURPOSE
5458
    Helper routine to check if two hyperslab span trees are the same shape
5459
 USAGE
5460
    bool H5S__hyper_spans_shape_same_helper(span1, span2, offset, rest_zeros)
5461
        H5S_hyper_span_info_t *span_info1;      IN: First span tree to compare
5462
        H5S_hyper_span_info_t *span_info2;      IN: Second span tree to compare
5463
        hssize_t offset[];                      IN: Offset between the span trees
5464
        bool rest_zeros[];                   IN: Array of flags which indicate
5465
                                                    the rest of the offset[] array
5466
                                                    is zero values.
5467
 RETURNS
5468
    true (1) or false (0) on success, can't fail
5469
 DESCRIPTION
5470
    Compare two hyperslab span trees to determine if they refer to a selection
5471
    with the same shape, with a possible (constant) offset between their
5472
    elements.  Very similar to H5S__hyper_cmp_spans, except the selected
5473
    elements can be offset by a vector.
5474
 GLOBAL VARIABLES
5475
 COMMENTS, BUGS, ASSUMPTIONS
5476
 EXAMPLES
5477
 REVISION LOG
5478
--------------------------------------------------------------------------*/
5479
static H5_ATTR_PURE bool
5480
H5S__hyper_spans_shape_same_helper(const H5S_hyper_span_info_t *span_info1,
5481
                                   const H5S_hyper_span_info_t *span_info2, hssize_t offset[],
5482
                                   bool rest_zeros[])
5483
0
{
5484
0
    bool ret_value = true; /* Return value */
5485
5486
0
    FUNC_ENTER_PACKAGE_NOERR
5487
5488
    /* Sanity checks */
5489
0
    assert(span_info1);
5490
0
    assert(span_info2);
5491
0
    assert(offset);
5492
0
    assert(rest_zeros);
5493
5494
    /* Compare low & high bounds for this span list */
5495
    /* (Could compare lower dimensions also, but not certain if
5496
     *      that's worth it. - QAK, 2019/01/23)
5497
     */
5498
0
    if ((hsize_t)((hssize_t)span_info1->low_bounds[0] + offset[0]) != span_info2->low_bounds[0])
5499
0
        HGOTO_DONE(false);
5500
0
    else if ((hsize_t)((hssize_t)span_info1->high_bounds[0] + offset[0]) != span_info2->high_bounds[0])
5501
0
        HGOTO_DONE(false);
5502
0
    else {
5503
0
        const H5S_hyper_span_t *span1;
5504
0
        const H5S_hyper_span_t *span2;
5505
5506
        /* Get the pointers to the actual lists of spans */
5507
0
        span1 = span_info1->head;
5508
0
        span2 = span_info2->head;
5509
5510
        /* Sanity checking */
5511
0
        assert(span1);
5512
0
        assert(span2);
5513
5514
        /* infinite loop which must be broken out of */
5515
0
        while (1) {
5516
            /* Check for both spans being NULL */
5517
0
            if (span1 == NULL && span2 == NULL)
5518
0
                HGOTO_DONE(true);
5519
5520
            /* Check for one span being NULL */
5521
0
            if (span1 == NULL || span2 == NULL)
5522
0
                HGOTO_DONE(false);
5523
5524
            /* Check if the actual low & high span information is the same */
5525
0
            if ((hsize_t)((hssize_t)span1->low + offset[0]) != span2->low ||
5526
0
                (hsize_t)((hssize_t)span1->high + offset[0]) != span2->high)
5527
0
                HGOTO_DONE(false);
5528
5529
            /* Check for down tree for this span */
5530
0
            if (span1->down != NULL || span2->down != NULL) {
5531
                /* If the rest of the span trees have a zero offset, use the faster comparison routine */
5532
0
                if (rest_zeros[0]) {
5533
0
                    if (!H5S__hyper_cmp_spans(span1->down, span2->down))
5534
0
                        HGOTO_DONE(false);
5535
0
                    else {
5536
                        /* Keep going... */
5537
0
                    } /* end else */
5538
0
                }     /* end if */
5539
0
                else {
5540
0
                    if (!H5S__hyper_spans_shape_same_helper(span1->down, span2->down, &offset[1],
5541
0
                                                            &rest_zeros[1]))
5542
0
                        HGOTO_DONE(false);
5543
0
                    else {
5544
                        /* Keep going... */
5545
0
                    } /* end else */
5546
0
                }     /* end else */
5547
0
            }         /* end if */
5548
0
            else {
5549
                /* Keep going... */
5550
0
            } /* end else */
5551
5552
            /* Advance to the next nodes in the span list */
5553
0
            span1 = span1->next;
5554
0
            span2 = span2->next;
5555
0
        } /* end while */
5556
0
    }     /* end else */
5557
5558
    /* Fall through, with default return value of 'true' if spans were already visited */
5559
5560
0
done:
5561
0
    FUNC_LEAVE_NOAPI(ret_value)
5562
0
} /* end H5S__hyper_spans_shape_same_helper() */
5563
5564
/*--------------------------------------------------------------------------
5565
 NAME
5566
    H5S__hyper_spans_shape_same
5567
 PURPOSE
5568
    Check if two hyperslab span trees are the same shape
5569
 USAGE
5570
    bool H5S__hyper_spans_shape_same(span1, span2)
5571
        H5S_hyper_span_info_t *span_info1;      IN: First span tree to compare
5572
        H5S_hyper_span_info_t *span_info2;      IN: Second span tree to compare
5573
 RETURNS
5574
    true (1) or false (0) on success, can't fail
5575
 DESCRIPTION
5576
    Compare two hyperslab span trees to determine if they refer to a selection
5577
    with the same shape.  Very similar to H5S__hyper_cmp_spans, except the
5578
    selected elements can be offset by a vector.
5579
 GLOBAL VARIABLES
5580
 COMMENTS, BUGS, ASSUMPTIONS
5581
 EXAMPLES
5582
 REVISION LOG
5583
--------------------------------------------------------------------------*/
5584
static H5_ATTR_PURE bool
5585
H5S__hyper_spans_shape_same(const H5S_hyper_span_info_t *span_info1, const H5S_hyper_span_info_t *span_info2,
5586
                            unsigned ndims)
5587
0
{
5588
0
    const H5S_hyper_span_t *span1;                /* Pointer to spans in first span tree */
5589
0
    const H5S_hyper_span_t *span2;                /* Pointer to spans in second span tree */
5590
0
    hssize_t                offset[H5S_MAX_RANK]; /* Offset vector for selections */
5591
0
    bool     rest_zeros[H5S_MAX_RANK]; /* Vector of flags to indicate when remaining offset is all zero */
5592
0
    bool     zero_offset;              /* Whether the two selections have a non-zero offset */
5593
0
    unsigned u;                        /* Local index variable */
5594
0
    bool     ret_value = true;         /* Return value */
5595
5596
0
    FUNC_ENTER_PACKAGE_NOERR
5597
5598
    /* Sanity check */
5599
0
    assert(span_info1);
5600
0
    assert(span_info2);
5601
0
    assert(ndims > 0);
5602
5603
    /* Initialize arrays */
5604
0
    memset(offset, 0, sizeof(offset));
5605
0
    memset(rest_zeros, 0, sizeof(rest_zeros));
5606
5607
    /* Check for an offset between the two selections */
5608
0
    span1       = span_info1->head;
5609
0
    span2       = span_info2->head;
5610
0
    zero_offset = true;
5611
0
    for (u = 0; u < ndims; u++) {
5612
        /* Check for offset in this dimension */
5613
0
        if (span1->low != span2->low) {
5614
0
            offset[u] = (hssize_t)span2->low - (hssize_t)span1->low;
5615
5616
            /* Indicate that the offset vector is not all zeros */
5617
0
            if (zero_offset)
5618
0
                zero_offset = false;
5619
0
        } /* end if */
5620
5621
        /* Sanity check */
5622
        /* (Both span trees must have the same depth) */
5623
0
        assert((span1->down && span2->down) || (NULL == span1->down && NULL == span2->down));
5624
5625
        /* Advance to next dimension */
5626
0
        if (span1->down) {
5627
0
            span1 = span1->down->head;
5628
0
            span2 = span2->down->head;
5629
0
        } /* end if */
5630
0
    }     /* end for */
5631
5632
    /* Check if there's a "tail" of all zeros in a non-zero offset vector */
5633
0
    if (!zero_offset) {
5634
0
        int i; /* Local index variable */
5635
5636
        /* Find first non-zero offset, from the fastest dimension up */
5637
0
        for (i = (int)(ndims - 1); i >= 0; i--)
5638
0
            if (offset[i]) {
5639
0
                rest_zeros[i] = true;
5640
0
                break;
5641
0
            } /* end if */
5642
5643
        /* Sanity check */
5644
        /* (Must eventually have found a non-zero offset) */
5645
0
        assert(i >= 0);
5646
0
    } /* end if */
5647
5648
    /* If the offset vector is all zero, we can use the faster span tree
5649
     *  comparison routine.  Otherwise, use a generalized version of that
5650
     *  routine.
5651
     */
5652
0
    if (zero_offset)
5653
0
        ret_value = H5S__hyper_cmp_spans(span_info1, span_info2);
5654
0
    else
5655
0
        ret_value = H5S__hyper_spans_shape_same_helper(span_info1, span_info2, offset, rest_zeros);
5656
5657
0
    FUNC_LEAVE_NOAPI(ret_value)
5658
0
} /* end H5S__hyper_spans_shape_same() */
5659
5660
/*--------------------------------------------------------------------------
5661
 NAME
5662
    H5S__hyper_shape_same
5663
 PURPOSE
5664
    Check if a two hyperslab selections are the same shape
5665
 USAGE
5666
    htri_t H5S__hyper_shape_same(space1, space2)
5667
        H5S_t *space1;           IN: First dataspace to check
5668
        H5S_t *space2;           IN: Second dataspace to check
5669
 RETURNS
5670
    true / false / FAIL
5671
 DESCRIPTION
5672
    Checks to see if the current selection in each dataspace are the same
5673
    shape.
5674
 GLOBAL VARIABLES
5675
 COMMENTS, BUGS, ASSUMPTIONS
5676
    Handles when both are regular in an efficient way, otherwise converts
5677
    both to span tree form (if necessary) and compares efficiently them in
5678
    that form.
5679
5680
    Rank of space1 must always be >= to rank of space2.
5681
 EXAMPLES
5682
 REVISION LOG
5683
--------------------------------------------------------------------------*/
5684
static htri_t
5685
H5S__hyper_shape_same(H5S_t *space1, H5S_t *space2)
5686
0
{
5687
0
    unsigned space1_rank;      /* Number of dimensions of first dataspace */
5688
0
    unsigned space2_rank;      /* Number of dimensions of second dataspace */
5689
0
    htri_t   ret_value = true; /* Return value */
5690
5691
0
    FUNC_ENTER_PACKAGE
5692
5693
    /* Check args */
5694
0
    assert(space1);
5695
0
    assert(space2);
5696
5697
    /* Get dataspace ranks */
5698
0
    space1_rank = space1->extent.rank;
5699
0
    space2_rank = space2->extent.rank;
5700
5701
    /* Sanity check */
5702
0
    assert(space1_rank >= space2_rank);
5703
0
    assert(space2_rank > 0);
5704
5705
    /* Rebuild diminfo if it is invalid and has not been confirmed to be
5706
     * impossible */
5707
0
    if (space1->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO)
5708
0
        H5S__hyper_rebuild(space1);
5709
0
    if (space2->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO)
5710
0
        H5S__hyper_rebuild(space2);
5711
5712
    /* If both are regular hyperslabs, compare their diminfo values */
5713
0
    if (space1->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES &&
5714
0
        space2->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
5715
0
        int space1_dim; /* Current dimension in first dataspace */
5716
0
        int space2_dim; /* Current dimension in second dataspace */
5717
5718
        /* Initialize dimensions */
5719
0
        space1_dim = (int)space1_rank - 1;
5720
0
        space2_dim = (int)space2_rank - 1;
5721
5722
        /* Check that the shapes are the same in the common dimensions, and that
5723
         * block == 1 in all dimensions that appear only in space1.
5724
         */
5725
0
        while (space2_dim >= 0) {
5726
0
            if (space1->select.sel_info.hslab->diminfo.opt[space1_dim].stride !=
5727
0
                space2->select.sel_info.hslab->diminfo.opt[space2_dim].stride)
5728
0
                HGOTO_DONE(false);
5729
5730
0
            if (space1->select.sel_info.hslab->diminfo.opt[space1_dim].count !=
5731
0
                space2->select.sel_info.hslab->diminfo.opt[space2_dim].count)
5732
0
                HGOTO_DONE(false);
5733
5734
0
            if (space1->select.sel_info.hslab->diminfo.opt[space1_dim].block !=
5735
0
                space2->select.sel_info.hslab->diminfo.opt[space2_dim].block)
5736
0
                HGOTO_DONE(false);
5737
5738
0
            space1_dim--;
5739
0
            space2_dim--;
5740
0
        } /* end while */
5741
5742
0
        while (space1_dim >= 0) {
5743
0
            if (space1->select.sel_info.hslab->diminfo.opt[space1_dim].block != 1)
5744
0
                HGOTO_DONE(false);
5745
5746
0
            space1_dim--;
5747
0
        } /* end while */
5748
0
    }     /* end if */
5749
    /* If both aren't regular, use fast irregular comparison */
5750
0
    else {
5751
0
        H5S_hyper_span_info_t *spans1; /* Hyperslab spans for first dataspace */
5752
5753
        /* Make certain that both selections have span trees */
5754
0
        if (NULL == space1->select.sel_info.hslab->span_lst)
5755
0
            if (H5S__hyper_generate_spans(space1) < 0)
5756
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL,
5757
0
                            "can't construct span tree for hyperslab selection");
5758
0
        if (NULL == space2->select.sel_info.hslab->span_lst)
5759
0
            if (H5S__hyper_generate_spans(space2) < 0)
5760
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL,
5761
0
                            "can't construct span tree for hyperslab selection");
5762
5763
        /* If rank of space A is different (guaranteed greater) than
5764
         *      rank of space B, walk down the span tree, verifying
5765
         *      that the block size is 1 on the way down.
5766
         */
5767
0
        if (space1_rank > space2_rank) {
5768
0
            unsigned diff_rank = space1_rank - space2_rank; /* Difference in ranks */
5769
5770
            /* Walk down the dimensions */
5771
0
            spans1 = space1->select.sel_info.hslab->span_lst;
5772
0
            while (diff_rank > 0) {
5773
0
                H5S_hyper_span_t *span; /* Span for this dimension */
5774
5775
                /* Get pointer to first span in tree */
5776
0
                span = spans1->head;
5777
5778
                /* Check for more spans in this dimension */
5779
0
                if (span->next)
5780
0
                    HGOTO_DONE(false);
5781
5782
                /* Check for span size > 1 element */
5783
0
                if (span->low != span->high)
5784
0
                    HGOTO_DONE(false);
5785
5786
                /* Walk down to the next dimension */
5787
0
                spans1 = span->down;
5788
0
                diff_rank--;
5789
0
            } /* end while */
5790
5791
            /* Sanity check */
5792
0
            assert(spans1);
5793
0
        } /* end if */
5794
0
        else
5795
0
            spans1 = space1->select.sel_info.hslab->span_lst;
5796
5797
        /* Compare the span trees */
5798
0
        ret_value = H5S__hyper_spans_shape_same(spans1, space2->select.sel_info.hslab->span_lst, space2_rank);
5799
0
    } /* end else */
5800
5801
    /* Fall through with 'true' value, if not set earlier */
5802
5803
0
done:
5804
0
    FUNC_LEAVE_NOAPI(ret_value)
5805
0
} /* end H5S__hyper_shape_same() */
5806
5807
/*--------------------------------------------------------------------------
5808
 NAME
5809
    H5S__hyper_release
5810
 PURPOSE
5811
    Release hyperslab selection information for a dataspace
5812
 USAGE
5813
    herr_t H5S__hyper_release(space)
5814
        H5S_t *space;       IN: Pointer to dataspace
5815
 RETURNS
5816
    Non-negative on success/Negative on failure
5817
 DESCRIPTION
5818
    Releases all hyperslab selection information for a dataspace
5819
 GLOBAL VARIABLES
5820
 COMMENTS, BUGS, ASSUMPTIONS
5821
 EXAMPLES
5822
 REVISION LOG
5823
--------------------------------------------------------------------------*/
5824
static herr_t
5825
H5S__hyper_release(H5S_t *space)
5826
0
{
5827
0
    herr_t ret_value = SUCCEED;
5828
5829
0
    FUNC_ENTER_PACKAGE
5830
5831
    /* Check args */
5832
0
    assert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space));
5833
5834
    /* Reset the number of points selected */
5835
0
    space->select.num_elem = 0;
5836
5837
    /* Release irregular hyperslab information */
5838
0
    if (space->select.sel_info.hslab) {
5839
0
        if (space->select.sel_info.hslab->span_lst != NULL)
5840
0
            if (H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst) < 0)
5841
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "unable to free span info");
5842
5843
        /* Release space for the hyperslab selection information */
5844
0
        space->select.sel_info.hslab = H5FL_FREE(H5S_hyper_sel_t, space->select.sel_info.hslab);
5845
0
    }
5846
5847
0
done:
5848
0
    FUNC_LEAVE_NOAPI(ret_value)
5849
0
} /* end H5S__hyper_release() */
5850
5851
/*--------------------------------------------------------------------------
5852
 NAME
5853
    H5S__hyper_coord_to_span
5854
 PURPOSE
5855
    Create a span tree for a single element
5856
 USAGE
5857
    H5S_hyper_span_t *H5S__hyper_coord_to_span(rank, coords)
5858
        unsigned rank;                  IN: Number of dimensions of coordinate
5859
        hsize_t *coords;               IN: Location of element
5860
 RETURNS
5861
    Non-NULL pointer to new span tree on success, NULL on failure
5862
 DESCRIPTION
5863
    Create a span tree for a single element
5864
 GLOBAL VARIABLES
5865
 COMMENTS, BUGS, ASSUMPTIONS
5866
 EXAMPLES
5867
 REVISION LOG
5868
--------------------------------------------------------------------------*/
5869
static H5S_hyper_span_t *
5870
H5S__hyper_coord_to_span(unsigned rank, const hsize_t *coords)
5871
0
{
5872
0
    H5S_hyper_span_t      *new_span;         /* Pointer to new span tree for coordinate */
5873
0
    H5S_hyper_span_info_t *down      = NULL; /* Pointer to new span tree for next level down */
5874
0
    H5S_hyper_span_t      *ret_value = NULL; /* Return value */
5875
5876
0
    FUNC_ENTER_PACKAGE
5877
5878
0
    assert(rank > 0);
5879
0
    assert(coords);
5880
5881
    /* Search for location to insert new element in tree */
5882
0
    if (rank > 1) {
5883
        /* Allocate a span info node for coordinates below this one */
5884
0
        if (NULL == (down = H5S__hyper_new_span_info(rank - 1)))
5885
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
5886
5887
        /* Set the low & high bounds for this span info node */
5888
0
        H5MM_memcpy(down->low_bounds, &coords[1], (rank - 1) * sizeof(hsize_t));
5889
0
        H5MM_memcpy(down->high_bounds, &coords[1], (rank - 1) * sizeof(hsize_t));
5890
5891
        /* Build span tree for coordinates below this one */
5892
0
        if (NULL == (down->head = H5S__hyper_coord_to_span(rank - 1, &coords[1])))
5893
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
5894
5895
        /* Update the tail pointer of the down dimension, and it's a single span element */
5896
0
        down->tail = down->head;
5897
0
    } /* end if */
5898
5899
    /* Build span for this coordinate */
5900
0
    if (NULL == (new_span = H5S__hyper_new_span(coords[0], coords[0], down, NULL)))
5901
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
5902
5903
    /* Set return value */
5904
0
    ret_value = new_span;
5905
5906
0
done:
5907
0
    if (ret_value == NULL && down != NULL)
5908
0
        if (H5S__hyper_free_span_info(down) < 0)
5909
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, NULL, "unable to free span info");
5910
5911
0
    FUNC_LEAVE_NOAPI(ret_value)
5912
0
} /* end H5S__hyper_coord_to_span() */
5913
5914
/*--------------------------------------------------------------------------
5915
 NAME
5916
    H5S__hyper_add_span_element_helper
5917
 PURPOSE
5918
    Helper routine to add a single element to a span tree
5919
 USAGE
5920
    herr_t H5S__hyper_add_span_element_helper(span_tree, rank, coords, first_dim_modified)
5921
        H5S_hyper_span_info_t *span_tree;  IN/OUT: Pointer to span tree to append to
5922
        unsigned rank;                  IN: Number of dimensions of coordinates
5923
        hsize_t *coords;                IN: Location of element to add to span tree
5924
        int *first_dim_modified;        IN: Index of the first dimension modified
5925
 RETURNS
5926
    Non-negative on success, negative on failure
5927
 DESCRIPTION
5928
    Add a single element to an existing span tree.
5929
 GLOBAL VARIABLES
5930
 COMMENTS, BUGS, ASSUMPTIONS
5931
    Assumes that the element is not already covered by the span tree
5932
 EXAMPLES
5933
 REVISION LOG
5934
--------------------------------------------------------------------------*/
5935
static herr_t
5936
H5S__hyper_add_span_element_helper(H5S_hyper_span_info_t *span_tree, unsigned rank, const hsize_t *coords,
5937
                                   int *first_dim_modified)
5938
0
{
5939
0
    H5S_hyper_span_t *tail_span;           /* Pointer to the tail span of one dimension */
5940
0
    herr_t            ret_value = SUCCEED; /* Return value */
5941
5942
0
    FUNC_ENTER_PACKAGE
5943
5944
    /* Sanity check */
5945
0
    assert(span_tree);
5946
0
    assert(rank > 0);
5947
0
    assert(coords);
5948
0
    assert(first_dim_modified);
5949
5950
    /* Get pointer to last span in span tree */
5951
0
    tail_span = span_tree->tail;
5952
5953
    /* Determine if tail span includes a portion of the coordinate */
5954
    /* (Should never happen with the lowest level in the span tree) */
5955
0
    if (coords[0] >= tail_span->low && coords[0] <= tail_span->high) {
5956
0
        H5S_hyper_span_t *prev_down_tail_span;      /* Pointer to previous down spans' tail pointer */
5957
0
        hsize_t           prev_down_tail_span_high; /* Value of previous down spans' tail's high value */
5958
5959
        /* Retain into about down spans' tail */
5960
0
        prev_down_tail_span      = tail_span->down->tail;
5961
0
        prev_down_tail_span_high = tail_span->down->tail->high;
5962
5963
        /* Drop down a dimension */
5964
0
        assert(rank > 1);
5965
0
        if (H5S__hyper_add_span_element_helper(tail_span->down, rank - 1, &coords[1], first_dim_modified) < 0)
5966
0
            HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "can't insert coordinate into span tree");
5967
5968
        /* Check & update high bounds for lower dimensions */
5969
0
        if (*first_dim_modified >= 0) {
5970
0
            unsigned first_dim;             /* First dimension modified, relative to this span tree */
5971
0
            bool     first_dim_set = false; /* Whether first dimension modified is set */
5972
0
            unsigned u;                     /* Local index variable */
5973
5974
            /* Adjust first dimension modified to be relative to this span tree */
5975
0
            first_dim = (unsigned)(*first_dim_modified + 1);
5976
5977
            /* Reset modified dimension, in case no bounds in this span tree change */
5978
0
            *first_dim_modified = -1;
5979
5980
            /* Iterate through coordinates */
5981
0
            for (u = first_dim; u < rank; u++) {
5982
                /* Check if coordinate is outside the bounds for this span tree */
5983
0
                if (coords[u] > span_tree->high_bounds[u]) {
5984
                    /* Update high bounds for this tree */
5985
0
                    span_tree->high_bounds[u] = coords[u];
5986
5987
                    /* Need to signal to higher dimensions if high bounds changed */
5988
0
                    if (!first_dim_set) {
5989
0
                        *first_dim_modified = (int)u;
5990
0
                        first_dim_set       = true;
5991
0
                    } /* end if */
5992
0
                }     /* end if */
5993
0
            }         /* end for */
5994
0
        }             /* end if */
5995
5996
        /* Check if previous tail span in down spans is different than current
5997
         * tail span, or if its high value changed, in which case we should
5998
         * check if the updated node can share down spans with other nodes.
5999
         */
6000
0
        if (tail_span->down->tail != prev_down_tail_span ||
6001
0
            prev_down_tail_span_high != tail_span->down->tail->high) {
6002
0
            H5S_hyper_span_t *stop_span; /* Pointer to span to stop at */
6003
0
            H5S_hyper_span_t *tmp_span;  /* Temporary pointer to a span */
6004
0
            uint64_t          op_gen;    /* Operation generation value */
6005
6006
            /* Determine which span to stop at */
6007
0
            if (tail_span->down->tail != prev_down_tail_span) {
6008
                /* Sanity check */
6009
0
                assert(prev_down_tail_span->next == tail_span->down->tail);
6010
6011
                /* Set the span to stop at */
6012
0
                stop_span = prev_down_tail_span;
6013
0
            } /* end if */
6014
0
            else {
6015
                /* Sanity check */
6016
0
                assert(prev_down_tail_span_high != tail_span->down->tail->high);
6017
6018
                /* Set the span to stop at */
6019
0
                stop_span = tail_span->down->tail;
6020
0
            } /* end else */
6021
6022
            /* Acquire an operation generation value for this operation */
6023
0
            op_gen = H5S__hyper_get_op_gen();
6024
6025
            /* Check if the 'stop' span in the "down tree" is equal to any other
6026
             * spans in the list of spans in the span tree.
6027
             *
6028
             * If so, release last span information and make last span merge into
6029
             * previous span (if possible), or at least share their "down tree"
6030
             * information.
6031
             */
6032
0
            tmp_span = tail_span->down->head;
6033
0
            while (tmp_span != stop_span) {
6034
0
                bool attempt_merge_spans = false; /* Whether to merge spans */
6035
6036
                /* Different tests for when to run the 'merge' algorithm,
6037
                 * depending whether there's "down trees" or not.
6038
                 */
6039
0
                if (NULL == tmp_span->down) {
6040
                    /* Spin through spans until we find the one before the 'stop' span */
6041
0
                    if (tmp_span->next == stop_span)
6042
0
                        attempt_merge_spans = true;
6043
0
                } /* end if */
6044
0
                else {
6045
                    /* Check if we've compared the 'stop' span's "down tree" to
6046
                     *      this span's "down tree" already.
6047
                     */
6048
0
                    if (tmp_span->down->op_info[0].op_gen != op_gen) {
6049
0
                        if (H5S__hyper_cmp_spans(tmp_span->down, stop_span->down))
6050
0
                            attempt_merge_spans = true;
6051
6052
                        /* Remember that we visited this span's "down tree" already */
6053
                        /* (Because it wasn't the same as the 'stop' span's down tree
6054
                         *      and we don't need to compare it again)
6055
                         */
6056
0
                        tmp_span->down->op_info[0].op_gen = op_gen;
6057
0
                    } /* end if */
6058
0
                }     /* end else */
6059
6060
                /* Check for merging into previous span */
6061
0
                if (attempt_merge_spans) {
6062
0
                    if (tmp_span->high + 1 == stop_span->low) {
6063
                        /* Increase size of previous span */
6064
0
                        tmp_span->high++;
6065
6066
                        /* Update pointers appropriately */
6067
0
                        if (stop_span == prev_down_tail_span) {
6068
                            /* Sanity check */
6069
0
                            assert(stop_span->next == tail_span->down->tail);
6070
6071
0
                            tmp_span->next = stop_span->next;
6072
0
                        } /* end if */
6073
0
                        else {
6074
                            /* Sanity check */
6075
0
                            assert(tmp_span->next == tail_span->down->tail);
6076
6077
0
                            tmp_span->next        = NULL;
6078
0
                            tail_span->down->tail = tmp_span;
6079
0
                        } /* end else */
6080
6081
                        /* Release last span created */
6082
0
                        if (H5S__hyper_free_span(stop_span) < 0)
6083
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span");
6084
0
                    }
6085
                    /* Span is disjoint, but has the same "down tree" selection */
6086
                    /* (If it has a "down tree") */
6087
0
                    else if (stop_span->down) {
6088
                        /* Release "down tree" information */
6089
0
                        if (H5S__hyper_free_span_info(stop_span->down) < 0)
6090
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
6091
6092
                        /* Point at earlier span's "down tree" */
6093
0
                        stop_span->down = tmp_span->down;
6094
6095
                        /* Increment reference count on shared "down tree" */
6096
0
                        stop_span->down->count++;
6097
0
                    } /* end else */
6098
6099
                    /* Found span to merge into, break out now */
6100
0
                    break;
6101
0
                } /* end if */
6102
6103
                /* Advance to next span to check */
6104
0
                tmp_span = tmp_span->next;
6105
0
            } /* end while */
6106
0
        }     /* end if */
6107
0
    }         /* end if */
6108
0
    else {
6109
0
        unsigned u; /* Local index variable */
6110
6111
        /* Check if we made it all the way to the bottom span list in the tree
6112
         *      and the new coordinate adjoins the current tail span.
6113
         */
6114
0
        if (rank == 1 && (tail_span->high + 1) == coords[0])
6115
            /* Append element to current tail span */
6116
0
            tail_span->high++;
6117
0
        else {
6118
0
            H5S_hyper_span_t *new_span; /* New span created for element */
6119
6120
            /* Make span tree for current coordinate(s) */
6121
0
            if (NULL == (new_span = H5S__hyper_coord_to_span(rank, coords)))
6122
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL,
6123
0
                            "can't allocate hyperslab spans for coordinate");
6124
6125
            /* Add new span to span tree list */
6126
0
            tail_span->next = new_span;
6127
0
            span_tree->tail = new_span;
6128
0
        } /* end else */
6129
6130
        /* Update high bound for current span tree */
6131
0
        assert(coords[0] > span_tree->high_bounds[0]);
6132
0
        span_tree->high_bounds[0] = coords[0];
6133
6134
        /* Update high bounds for dimensions below this one */
6135
0
        for (u = 1; u < rank; u++)
6136
0
            if (coords[u] > span_tree->high_bounds[u])
6137
0
                span_tree->high_bounds[u] = coords[u];
6138
6139
        /* Need to signal to higher dimensions that high bounds changed */
6140
0
        *first_dim_modified = 0;
6141
0
    } /* end else */
6142
6143
0
done:
6144
0
    FUNC_LEAVE_NOAPI(ret_value)
6145
0
} /* end H5S__hyper_add_span_element_helper() */
6146
6147
/*--------------------------------------------------------------------------
6148
 NAME
6149
    H5S_hyper_add_span_element
6150
 PURPOSE
6151
    Add a single element to a span tree
6152
 USAGE
6153
    herr_t H5S_hyper_add_span_element(space, span_tree, rank, coords)
6154
        H5S_t *space;           IN/OUT: Pointer to dataspace to add coordinate to
6155
        unsigned rank;          IN: Number of dimensions of coordinates
6156
        hsize_t *coords;       IN: Location of element to add to span tree
6157
 RETURNS
6158
    Non-negative on success, negative on failure
6159
 DESCRIPTION
6160
    Add a single element to an existing span tree.
6161
 GLOBAL VARIABLES
6162
 COMMENTS, BUGS, ASSUMPTIONS
6163
    Assumes that the element is not already in the dataspace's selection
6164
6165
    NOTE: There's also an assumption about the context of this function call -
6166
        This function is only called is only being called from H5D_chunk_mem_cb
6167
        in src/H5Dchunk.c, when the library is iterating over a memory
6168
        selection, so the coordinates passed to H5S_hyper_add_span_element will
6169
        always be in increasing order (according to a row-major (i.e. C, not
6170
        FORTRAN) scan) over the dataset. Therefore, for every input of
6171
        coordinates, only the last span element (i.e., the tail pointer) in
6172
        one dimension is checked against the input.
6173
6174
    NOTE: This algorithm is definitely "correct" and tries to conserve memory
6175
        as much as possible, but it's doing a _lot_ of work that might be
6176
        better spent running a similar algorithm to "condense" the span tree
6177
        (possibly even back into a regular selection) just before the selection
6178
        is used for I/O on the chunk.  I'm not going to spend the time on this
6179
        currently, but it does sound like a good direction to explore.
6180
        QAK, 2019/01/24
6181
6182
 EXAMPLES
6183
 REVISION LOG
6184
--------------------------------------------------------------------------*/
6185
herr_t
6186
H5S_hyper_add_span_element(H5S_t *space, unsigned rank, const hsize_t *coords)
6187
0
{
6188
0
    H5S_hyper_span_info_t *head      = NULL;    /* Pointer to new head of span tree */
6189
0
    herr_t                 ret_value = SUCCEED; /* Return value */
6190
6191
0
    FUNC_ENTER_NOAPI(FAIL)
6192
6193
0
    assert(space);
6194
0
    assert(rank > 0);
6195
0
    assert(coords);
6196
0
    assert(space->extent.rank == rank);
6197
6198
    /* Check if this is the first element in the selection */
6199
0
    if (NULL == space->select.sel_info.hslab) {
6200
        /* Allocate a span info node */
6201
0
        if (NULL == (head = H5S__hyper_new_span_info(rank)))
6202
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span info");
6203
6204
        /* Set the low & high bounds for this span info node */
6205
0
        H5MM_memcpy(head->low_bounds, coords, rank * sizeof(hsize_t));
6206
0
        H5MM_memcpy(head->high_bounds, coords, rank * sizeof(hsize_t));
6207
6208
        /* Set the reference count */
6209
0
        head->count = 1;
6210
6211
        /* Build span tree for this coordinate */
6212
0
        if (NULL == (head->head = H5S__hyper_coord_to_span(rank, coords)))
6213
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab spans for coordinate");
6214
6215
        /* Update the tail pointer of this newly created span in dimension "rank" */
6216
0
        head->tail = head->head;
6217
6218
        /* Allocate selection info */
6219
0
        if (NULL == (space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t)))
6220
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab selection");
6221
6222
        /* Set the selection to the new span tree */
6223
0
        space->select.sel_info.hslab->span_lst = head;
6224
6225
        /* Set selection type */
6226
0
        space->select.type = H5S_sel_hyper;
6227
6228
        /* Reset "regular" hyperslab flag */
6229
0
        space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
6230
6231
        /* Set unlim_dim */
6232
0
        space->select.sel_info.hslab->unlim_dim = -1;
6233
6234
        /* Set # of elements in selection */
6235
0
        space->select.num_elem = 1;
6236
0
    } /* end if */
6237
0
    else {
6238
0
        int first_dim_modified = -1; /* Index of first dimension modified */
6239
6240
        /* Add the element to the current set of spans */
6241
0
        if (H5S__hyper_add_span_element_helper(space->select.sel_info.hslab->span_lst, rank, coords,
6242
0
                                               &first_dim_modified) < 0)
6243
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert coordinate into span tree");
6244
6245
        /* Increment # of elements in selection */
6246
0
        space->select.num_elem++;
6247
0
    } /* end else */
6248
6249
0
done:
6250
0
    if (ret_value < 0)
6251
0
        if (head)
6252
0
            if (H5S__hyper_free_span_info(head) < 0)
6253
0
                HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
6254
6255
0
    FUNC_LEAVE_NOAPI(ret_value)
6256
0
} /* end H5S_hyper_add_span_element() */
6257
6258
/*--------------------------------------------------------------------------
6259
 NAME
6260
    H5S__hyper_intersect_block_helper
6261
 PURPOSE
6262
    Helper routine to detect intersections in span trees
6263
 USAGE
6264
    bool H5S__hyper_intersect_block_helper(spans, rank, start, end, op_info_i, op_gen)
6265
        H5S_hyper_span_info_t *spans;     IN: First span tree to operate with
6266
        unsigned rank;     IN: Number of dimensions for span tree
6267
        hsize_t *start;    IN: Starting coordinate for block
6268
        hsize_t *end;      IN: Ending coordinate for block
6269
        unsigned op_info_i;             IN: Index of op info to use
6270
        uint64_t op_gen;   IN: Operation generation
6271
 RETURN
6272
    Non-negative (true/false) on success, can't fail
6273
 DESCRIPTION
6274
    Quickly detect intersections between span tree and block
6275
 GLOBAL VARIABLES
6276
 COMMENTS, BUGS, ASSUMPTIONS
6277
 EXAMPLES
6278
 REVISION LOG
6279
--------------------------------------------------------------------------*/
6280
static bool
6281
H5S__hyper_intersect_block_helper(H5S_hyper_span_info_t *spans, unsigned rank, const hsize_t *start,
6282
                                  const hsize_t *end, unsigned op_info_i, uint64_t op_gen)
6283
0
{
6284
0
    bool ret_value = false; /* Return value */
6285
6286
0
    FUNC_ENTER_PACKAGE_NOERR
6287
6288
    /* Sanity check */
6289
0
    assert(spans);
6290
0
    assert(start);
6291
0
    assert(end);
6292
6293
    /* Check if we've already visited this span tree */
6294
0
    if (spans->op_info[op_info_i].op_gen != op_gen) {
6295
0
        H5S_hyper_span_t *curr; /* Pointer to current span in 1st span tree */
6296
0
        unsigned          u;    /* Local index variable */
6297
6298
        /* Verify that there is a possibility of an overlap by checking the block
6299
         *  against the low & high bounds for the span tree.
6300
         */
6301
0
        for (u = 0; u < rank; u++)
6302
0
            if (start[u] > spans->high_bounds[u] || end[u] < spans->low_bounds[u])
6303
0
                HGOTO_DONE(false);
6304
6305
        /* Get the span list for spans in this tree */
6306
0
        curr = spans->head;
6307
6308
        /* Iterate over the spans in the tree */
6309
0
        while (curr != NULL) {
6310
            /* Check for span entirely before block */
6311
0
            if (curr->high < *start)
6312
                /* Advance to next span in this dimension */
6313
0
                curr = curr->next;
6314
            /* If this span is past the end of the block, then we're done in this dimension */
6315
0
            else if (curr->low > *end)
6316
0
                HGOTO_DONE(false);
6317
            /* block & span overlap */
6318
0
            else {
6319
                /* If this is the bottom dimension, then the span tree overlaps the block */
6320
0
                if (curr->down == NULL)
6321
0
                    HGOTO_DONE(true);
6322
                /* Recursively check spans in next dimension down */
6323
0
                else {
6324
                    /* If there is an intersection in the "down" dimensions,
6325
                     * the span trees overlap.
6326
                     */
6327
0
                    if (H5S__hyper_intersect_block_helper(curr->down, rank - 1, start + 1, end + 1, op_info_i,
6328
0
                                                          op_gen))
6329
0
                        HGOTO_DONE(true);
6330
6331
                    /* No intersection in down dimensions, advance to next span */
6332
0
                    curr = curr->next;
6333
0
                } /* end else */
6334
0
            }     /* end else */
6335
0
        }         /* end while */
6336
6337
        /* Set the tree's operation generation */
6338
0
        spans->op_info[op_info_i].op_gen = op_gen;
6339
0
    } /* end if */
6340
6341
    /* Fall through with 'false' return value */
6342
6343
0
done:
6344
0
    FUNC_LEAVE_NOAPI(ret_value)
6345
0
} /* end H5S__hyper_intersect_block_helper() */
6346
6347
/*--------------------------------------------------------------------------
6348
 NAME
6349
    H5S__hyper_intersect_block
6350
 PURPOSE
6351
    Detect intersections of selection with block
6352
 USAGE
6353
    htri_t H5S__hyper_intersect_block(space, start, end)
6354
        H5S_t *space;           IN: Dataspace with selection to use
6355
        const hsize_t *start;   IN: Starting coordinate for block
6356
        const hsize_t *end;     IN: Ending coordinate for block
6357
 RETURNS
6358
    Non-negative true / false on success, negative on failure
6359
 DESCRIPTION
6360
    Quickly detect intersections between both regular hyperslabs and span trees
6361
    with a block
6362
 GLOBAL VARIABLES
6363
 COMMENTS, BUGS, ASSUMPTIONS
6364
    Does not use selection offset.
6365
 EXAMPLES
6366
 REVISION LOG
6367
--------------------------------------------------------------------------*/
6368
static htri_t
6369
H5S__hyper_intersect_block(H5S_t *space, const hsize_t *start, const hsize_t *end)
6370
0
{
6371
0
    htri_t ret_value = FAIL; /* Return value */
6372
6373
0
    FUNC_ENTER_PACKAGE_NOERR
6374
6375
    /* Sanity check */
6376
0
    assert(space);
6377
0
    assert(H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space));
6378
0
    assert(start);
6379
0
    assert(end);
6380
6381
    /* Attempt to rebuild diminfo if it is invalid and has not been confirmed
6382
     * to be impossible.
6383
     */
6384
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO)
6385
0
        H5S__hyper_rebuild(space);
6386
6387
    /* Check for regular hyperslab intersection */
6388
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
6389
0
        bool     single_block; /* Whether the regular selection is a single block */
6390
0
        unsigned u;            /* Local index variable */
6391
6392
        /* Check for a single block */
6393
        /* For a regular hyperslab to be single, it must have only one block
6394
         * (i.e. count == 1 in all dimensions).
6395
         */
6396
0
        single_block = true;
6397
0
        for (u = 0; u < space->extent.rank; u++)
6398
0
            if (space->select.sel_info.hslab->diminfo.opt[u].count > 1)
6399
0
                single_block = false;
6400
6401
        /* Single blocks have already been "compared" above, in the low / high
6402
         * bound checking, so just return true if we've reached here - they
6403
         * would have been rejected earlier, if they didn't intersect.
6404
         */
6405
0
        if (single_block)
6406
0
            HGOTO_DONE(true);
6407
0
        else {
6408
            /* Loop over the dimensions, checking for an intersection */
6409
0
            for (u = 0; u < space->extent.rank; u++) {
6410
                /* If the block's start is <= the hyperslab start, they intersect */
6411
                /* (So, if the start is > the hyperslab start, check more conditions) */
6412
0
                if (start[u] > space->select.sel_info.hslab->diminfo.opt[u].start) {
6413
0
                    hsize_t adj_start; /* Start coord, adjusted for hyperslab selection parameters */
6414
0
                    hsize_t nstride;   /* Number of strides into the selection */
6415
6416
                    /* Adjust start coord for selection's 'start' offset */
6417
0
                    adj_start = start[u] - space->select.sel_info.hslab->diminfo.opt[u].start;
6418
6419
                    /* Compute # of strides into the selection */
6420
0
                    if (space->select.sel_info.hslab->diminfo.opt[u].count > 1)
6421
0
                        nstride = adj_start / space->select.sel_info.hslab->diminfo.opt[u].stride;
6422
0
                    else
6423
0
                        nstride = 0;
6424
6425
                    /* Sanity check */
6426
0
                    assert(nstride <= space->select.sel_info.hslab->diminfo.opt[u].count);
6427
6428
                    /* "Rebase" the adjusted start coord into the same range
6429
                     *      range of values as the selections's first block.
6430
                     */
6431
0
                    adj_start -= nstride * space->select.sel_info.hslab->diminfo.opt[u].stride;
6432
6433
                    /* If the adjusted start doesn't fall within the first hyperslab
6434
                     *  span, check for the block overlapping with the next one.
6435
                     */
6436
0
                    if (adj_start >= space->select.sel_info.hslab->diminfo.opt[u].block) {
6437
0
                        hsize_t adj_end; /* End coord, adjusted for hyperslab selection parameters */
6438
6439
                        /* Adjust end coord for selection's 'start' offset */
6440
0
                        adj_end = end[u] - space->select.sel_info.hslab->diminfo.opt[u].start;
6441
6442
                        /* "Rebase" the adjusted end coord into the same range
6443
                         *      range of values as the selections's first block.
6444
                         */
6445
0
                        adj_end -= nstride * space->select.sel_info.hslab->diminfo.opt[u].stride;
6446
6447
                        /* If block doesn't extend over beginning of next span,
6448
                         *  it doesn't intersect.
6449
                         */
6450
0
                        if (adj_end < space->select.sel_info.hslab->diminfo.opt[u].stride)
6451
0
                            HGOTO_DONE(false);
6452
0
                    } /* end if */
6453
0
                }     /* end if */
6454
0
            }         /* end for */
6455
6456
            /* If we've looped through all dimensions and none of them didn't
6457
             *  overlap, then all of them do, so we report true.
6458
             */
6459
0
            HGOTO_DONE(true);
6460
0
        } /* end else */
6461
0
    }     /* end if */
6462
0
    else {
6463
0
        uint64_t op_gen; /* Operation generation value */
6464
6465
        /* Acquire an operation generation value for this operation */
6466
0
        op_gen = H5S__hyper_get_op_gen();
6467
6468
        /* Perform the span-by-span intersection check */
6469
        /* Always use op_info[0] since we own this op_info, so there can be no
6470
         * simultaneous operations */
6471
0
        ret_value = H5S__hyper_intersect_block_helper(space->select.sel_info.hslab->span_lst,
6472
0
                                                      space->extent.rank, start, end, 0, op_gen);
6473
0
    } /* end else */
6474
6475
0
done:
6476
0
    FUNC_LEAVE_NOAPI(ret_value)
6477
0
} /* end H5S__hyper_intersect_block() */
6478
6479
/*--------------------------------------------------------------------------
6480
 NAME
6481
    H5S__hyper_adjust_u_helper
6482
 PURPOSE
6483
    Helper routine to adjust offsets in span trees
6484
 USAGE
6485
    void H5S__hyper_adjust_u_helper(spans, rank, offset, op_info_i, op_gen)
6486
        H5S_hyper_span_info_t *spans;   IN: Span tree to operate with
6487
        unsigned rank;                  IN: Number of dimensions for span tree
6488
        const hsize_t *offset;          IN: Offset to subtract
6489
        unsigned op_info_i;             IN: Index of op info to use
6490
        uint64_t op_gen;                IN: Operation generation
6491
 RETURNS
6492
    None
6493
 DESCRIPTION
6494
    Adjust the location of the spans in a span tree by subtracting an offset
6495
 GLOBAL VARIABLES
6496
 COMMENTS, BUGS, ASSUMPTIONS
6497
 EXAMPLES
6498
 REVISION LOG
6499
--------------------------------------------------------------------------*/
6500
static void
6501
H5S__hyper_adjust_u_helper(H5S_hyper_span_info_t *spans, unsigned rank, const hsize_t *offset,
6502
                           unsigned op_info_i, uint64_t op_gen)
6503
0
{
6504
0
    FUNC_ENTER_PACKAGE_NOERR
6505
6506
    /* Sanity checks */
6507
0
    assert(spans);
6508
0
    assert(offset);
6509
6510
    /* Check if we've already set this span tree */
6511
0
    if (spans->op_info[op_info_i].op_gen != op_gen) {
6512
0
        H5S_hyper_span_t *span; /* Pointer to current span in span tree */
6513
0
        unsigned          u;    /* Local index variable */
6514
6515
        /* Adjust the span tree's low & high bounds */
6516
0
        for (u = 0; u < rank; u++) {
6517
0
            assert(spans->low_bounds[u] >= offset[u]);
6518
0
            spans->low_bounds[u] -= offset[u];
6519
0
            spans->high_bounds[u] -= offset[u];
6520
0
        } /* end for */
6521
6522
        /* Iterate over the spans in tree */
6523
0
        span = spans->head;
6524
0
        while (span != NULL) {
6525
            /* Adjust span offset */
6526
0
            assert(span->low >= *offset);
6527
0
            span->low -= *offset;
6528
0
            span->high -= *offset;
6529
6530
            /* Recursively adjust spans in next dimension down */
6531
0
            if (span->down != NULL)
6532
0
                H5S__hyper_adjust_u_helper(span->down, rank - 1, offset + 1, op_info_i, op_gen);
6533
6534
            /* Advance to next span in this dimension */
6535
0
            span = span->next;
6536
0
        } /* end while */
6537
6538
        /* Set the tree's operation generation */
6539
0
        spans->op_info[op_info_i].op_gen = op_gen;
6540
0
    } /* end if */
6541
6542
0
    FUNC_LEAVE_NOAPI_VOID
6543
0
} /* end H5S__hyper_adjust_u_helper() */
6544
6545
/*--------------------------------------------------------------------------
6546
 NAME
6547
    H5S__hyper_adjust_u
6548
 PURPOSE
6549
    Adjust a hyperslab selection by subtracting an offset
6550
 USAGE
6551
    void H5S__hyper_adjust_u(space,offset)
6552
        H5S_t *space;           IN/OUT: Pointer to dataspace to adjust
6553
        const hsize_t *offset; IN: Offset to subtract
6554
 RETURNS
6555
    Non-negative on success, negative on failure
6556
 DESCRIPTION
6557
    Moves a hyperslab selection by subtracting an offset from it.
6558
 GLOBAL VARIABLES
6559
 COMMENTS, BUGS, ASSUMPTIONS
6560
 EXAMPLES
6561
 REVISION LOG
6562
--------------------------------------------------------------------------*/
6563
static herr_t
6564
H5S__hyper_adjust_u(H5S_t *space, const hsize_t *offset)
6565
0
{
6566
0
    bool     non_zero_offset = false; /* Whether any offset is non-zero */
6567
0
    unsigned u;                       /* Local index variable */
6568
6569
0
    FUNC_ENTER_PACKAGE_NOERR
6570
6571
    /* Sanity check */
6572
0
    assert(space);
6573
0
    assert(offset);
6574
6575
    /* Check for an all-zero offset vector */
6576
0
    for (u = 0; u < space->extent.rank; u++)
6577
0
        if (0 != offset[u]) {
6578
0
            non_zero_offset = true;
6579
0
            break;
6580
0
        }
6581
6582
    /* Only perform operation if the offset is non-zero */
6583
0
    if (non_zero_offset) {
6584
        /* Subtract the offset from the "regular" coordinates, if they exist */
6585
        /* (No need to rebuild the dimension info yet -QAK) */
6586
0
        if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
6587
0
            for (u = 0; u < space->extent.rank; u++) {
6588
0
                assert(space->select.sel_info.hslab->diminfo.opt[u].start >= offset[u]);
6589
0
                space->select.sel_info.hslab->diminfo.opt[u].start -= offset[u];
6590
6591
                /* Adjust the low & high bounds */
6592
0
                assert(space->select.sel_info.hslab->diminfo.low_bounds[u] >= offset[u]);
6593
0
                space->select.sel_info.hslab->diminfo.low_bounds[u] -= offset[u];
6594
0
                space->select.sel_info.hslab->diminfo.high_bounds[u] -= offset[u];
6595
0
            } /* end for */
6596
0
        }     /* end if */
6597
6598
        /* Subtract the offset from the span tree coordinates, if they exist */
6599
0
        if (space->select.sel_info.hslab->span_lst) {
6600
0
            uint64_t op_gen; /* Operation generation value */
6601
6602
            /* Acquire an operation generation value for this operation */
6603
0
            op_gen = H5S__hyper_get_op_gen();
6604
6605
            /* Perform adjustment */
6606
            /* Always use op_info[0] since we own this op_info, so there can be no
6607
             * simultaneous operations */
6608
0
            H5S__hyper_adjust_u_helper(space->select.sel_info.hslab->span_lst, space->extent.rank, offset, 0,
6609
0
                                       op_gen);
6610
0
        } /* end if */
6611
0
    }     /* end if */
6612
6613
0
    FUNC_LEAVE_NOAPI(SUCCEED)
6614
0
} /* end H5S__hyper_adjust_u() */
6615
6616
/*-------------------------------------------------------------------------
6617
 * Function:    H5S__hyper_project_scalar
6618
 *
6619
 * Purpose:    Projects a single element hyperslab selection into a scalar
6620
 *              dataspace
6621
 *
6622
 * Return:    Non-negative on success, negative on failure.
6623
 *
6624
 *-------------------------------------------------------------------------
6625
 */
6626
static herr_t
6627
H5S__hyper_project_scalar(const H5S_t *space, hsize_t *offset)
6628
0
{
6629
0
    hsize_t block[H5S_MAX_RANK]; /* Block selected in base dataspace */
6630
6631
0
    FUNC_ENTER_PACKAGE_NOERR
6632
6633
    /* Check args */
6634
0
    assert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space));
6635
0
    assert(offset);
6636
6637
    /* Check for a "regular" hyperslab selection */
6638
    /* (No need to rebuild the dimension info yet -QAK) */
6639
0
    if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
6640
0
        const H5S_hyper_dim_t *diminfo =
6641
0
            space->select.sel_info.hslab->diminfo.opt; /* Alias for dataspace's diminfo information */
6642
0
        unsigned u;                                    /* Counter */
6643
6644
        /* Build the table of the initial offset */
6645
0
        for (u = 0; u < space->extent.rank; u++) {
6646
            /* Sanity check diminfo */
6647
0
            assert(1 == diminfo[u].count);
6648
0
            assert(1 == diminfo[u].block);
6649
6650
            /* Sanity check bounds, while we're here */
6651
0
            assert(diminfo[u].start == space->select.sel_info.hslab->diminfo.low_bounds[u]);
6652
6653
            /* Keep the offset for later */
6654
0
            block[u] = diminfo[u].start;
6655
0
        } /* end for */
6656
0
    }     /* end if */
6657
0
    else {
6658
0
        const H5S_hyper_span_t *curr;     /* Pointer to current hyperslab span */
6659
0
        unsigned                curr_dim; /* Current dimension being operated on */
6660
6661
        /* Advance down selected spans */
6662
0
        curr     = space->select.sel_info.hslab->span_lst->head;
6663
0
        curr_dim = 0;
6664
0
        while (1) {
6665
            /* Sanity checks */
6666
0
            assert(NULL == curr->next);
6667
0
            assert(curr->low == curr->high);
6668
0
            assert(curr_dim < space->extent.rank);
6669
6670
            /* Save the location of the selection in current dimension */
6671
0
            block[curr_dim] = curr->low;
6672
6673
            /* Advance down to next dimension */
6674
0
            if (curr->down) {
6675
0
                curr = curr->down->head;
6676
0
                curr_dim++;
6677
0
            } /* end if */
6678
0
            else
6679
0
                break;
6680
0
        } /* end while */
6681
0
    }     /* end else */
6682
6683
    /* Calculate offset of selection in projected buffer */
6684
0
    *offset = H5VM_array_offset(space->extent.rank, space->extent.size, block);
6685
6686
0
    FUNC_LEAVE_NOAPI(SUCCEED)
6687
0
} /* end H5S__hyper_project_scalar() */
6688
6689
/*-------------------------------------------------------------------------
6690
 * Function:    H5S__hyper_project_simple_lower
6691
 *
6692
 * Purpose:    Projects a hyperslab selection onto/into a simple dataspace
6693
 *              of a lower rank
6694
 *
6695
 * Return:    Non-negative on success, negative on failure.
6696
 *
6697
 *-------------------------------------------------------------------------
6698
 */
6699
static herr_t
6700
H5S__hyper_project_simple_lower(const H5S_t *base_space, H5S_t *new_space)
6701
0
{
6702
0
    H5S_hyper_span_info_t *down;                /* Pointer to list of spans */
6703
0
    unsigned               curr_dim;            /* Current dimension being operated on */
6704
0
    herr_t                 ret_value = SUCCEED; /* Return value */
6705
6706
0
    FUNC_ENTER_PACKAGE
6707
6708
    /* Check args */
6709
0
    assert(base_space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(base_space));
6710
0
    assert(new_space);
6711
0
    assert(new_space->extent.rank < base_space->extent.rank);
6712
6713
    /* Walk down the span tree until we reach the selection to project */
6714
0
    down     = base_space->select.sel_info.hslab->span_lst;
6715
0
    curr_dim = 0;
6716
0
    while (down && curr_dim < (base_space->extent.rank - new_space->extent.rank)) {
6717
        /* Sanity check */
6718
0
        assert(NULL == down->head->next);
6719
6720
        /* Advance down to next dimension */
6721
0
        down = down->head->down;
6722
0
        curr_dim++;
6723
0
    } /* end while */
6724
0
    if (NULL == down)
6725
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "NULL span list pointer");
6726
6727
    /* Share the underlying hyperslab span information */
6728
0
    new_space->select.sel_info.hslab->span_lst = down;
6729
0
    new_space->select.sel_info.hslab->span_lst->count++;
6730
6731
0
done:
6732
0
    FUNC_LEAVE_NOAPI(ret_value)
6733
0
} /* end H5S__hyper_project_simple_lower() */
6734
6735
/*-------------------------------------------------------------------------
6736
 * Function:    H5S__hyper_project_simple_higher
6737
 *
6738
 * Purpose:    Projects a hyperslab selection onto/into a simple dataspace
6739
 *              of a higher rank
6740
 *
6741
 * Return:    Non-negative on success, negative on failure.
6742
 *
6743
 *-------------------------------------------------------------------------
6744
 */
6745
static herr_t
6746
H5S__hyper_project_simple_higher(const H5S_t *base_space, H5S_t *new_space)
6747
0
{
6748
0
    H5S_hyper_span_t *prev_span = NULL;    /* Pointer to previous list of spans */
6749
0
    unsigned          delta_rank;          /* Difference in dataspace ranks */
6750
0
    unsigned          curr_dim;            /* Current dimension being operated on */
6751
0
    unsigned          u;                   /* Local index variable */
6752
0
    herr_t            ret_value = SUCCEED; /* Return value */
6753
6754
0
    FUNC_ENTER_PACKAGE
6755
6756
    /* Check args */
6757
0
    assert(base_space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(base_space));
6758
0
    assert(new_space);
6759
0
    assert(new_space->extent.rank > base_space->extent.rank);
6760
6761
    /* Create nodes until reaching the correct # of dimensions */
6762
0
    new_space->select.sel_info.hslab->span_lst = NULL;
6763
0
    curr_dim                                   = 0;
6764
0
    delta_rank                                 = (new_space->extent.rank - base_space->extent.rank);
6765
0
    while (curr_dim < delta_rank) {
6766
0
        H5S_hyper_span_info_t *new_span_info; /* Pointer to list of spans */
6767
0
        H5S_hyper_span_t      *new_span;      /* Temporary hyperslab span */
6768
6769
        /* Allocate a new span_info node */
6770
0
        if (NULL == (new_span_info = H5S__hyper_new_span_info(new_space->extent.rank))) {
6771
0
            if (prev_span)
6772
0
                (void)H5S__hyper_free_span(prev_span);
6773
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span info");
6774
0
        }
6775
6776
        /* Check for linking into higher span */
6777
0
        if (prev_span)
6778
0
            prev_span->down = new_span_info;
6779
6780
        /* Allocate a new node */
6781
0
        if (NULL == (new_span = H5S__hyper_new_span((hsize_t)0, (hsize_t)0, NULL, NULL))) {
6782
0
            assert(new_span_info);
6783
0
            if (!prev_span)
6784
0
                (void)H5FL_ARR_FREE(hbounds_t, new_span_info);
6785
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span");
6786
0
        } /* end if */
6787
6788
        /* Set the span_info information */
6789
0
        new_span_info->count = 1;
6790
0
        new_span_info->head  = new_span;
6791
0
        new_span_info->tail  = new_span;
6792
6793
        /* Set the bounding box */
6794
0
        for (u = 0; u < delta_rank; u++) {
6795
0
            new_span_info->low_bounds[u]  = 0;
6796
0
            new_span_info->high_bounds[u] = 0;
6797
0
        } /* end for */
6798
0
        for (; u < new_space->extent.rank; u++) {
6799
0
            new_span_info->low_bounds[u] =
6800
0
                base_space->select.sel_info.hslab->span_lst->low_bounds[u - delta_rank];
6801
0
            new_span_info->high_bounds[u] =
6802
0
                base_space->select.sel_info.hslab->span_lst->high_bounds[u - delta_rank];
6803
0
        } /* end for */
6804
6805
        /* Attach to new space, if top span info */
6806
0
        if (NULL == new_space->select.sel_info.hslab->span_lst)
6807
0
            new_space->select.sel_info.hslab->span_lst = new_span_info;
6808
6809
        /* Remember previous span info */
6810
0
        prev_span = new_span;
6811
6812
        /* Advance to next dimension */
6813
0
        curr_dim++;
6814
0
    } /* end while */
6815
0
    if (NULL == new_space->select.sel_info.hslab->span_lst)
6816
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "NULL span list pointer");
6817
0
    assert(prev_span);
6818
6819
    /* Share the underlying hyperslab span information */
6820
0
    prev_span->down = base_space->select.sel_info.hslab->span_lst;
6821
0
    prev_span->down->count++;
6822
6823
0
done:
6824
0
    if (ret_value < 0 && new_space->select.sel_info.hslab->span_lst) {
6825
0
        if (new_space->select.sel_info.hslab->span_lst->head)
6826
0
            if (H5S__hyper_free_span(new_space->select.sel_info.hslab->span_lst->head) < 0)
6827
0
                HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span");
6828
6829
0
        new_space->select.sel_info.hslab->span_lst =
6830
0
            (H5S_hyper_span_info_t *)H5FL_ARR_FREE(hbounds_t, new_space->select.sel_info.hslab->span_lst);
6831
0
    }
6832
6833
0
    FUNC_LEAVE_NOAPI(ret_value)
6834
0
} /* end H5S__hyper_project_simple_higher() */
6835
6836
/*-------------------------------------------------------------------------
6837
 * Function:    H5S__hyper_project_simple
6838
 *
6839
 * Purpose:    Projects a hyperslab selection onto/into a simple dataspace
6840
 *              of a different rank
6841
 *
6842
 * Return:    Non-negative on success, negative on failure.
6843
 *
6844
 *-------------------------------------------------------------------------
6845
 */
6846
static herr_t
6847
H5S__hyper_project_simple(const H5S_t *base_space, H5S_t *new_space, hsize_t *offset)
6848
0
{
6849
0
    herr_t ret_value = SUCCEED; /* Return value */
6850
6851
0
    FUNC_ENTER_PACKAGE
6852
6853
    /* Check args */
6854
0
    assert(base_space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(base_space));
6855
0
    assert(new_space);
6856
0
    assert(offset);
6857
6858
    /* We are setting a new selection, remove any current selection in new dataspace */
6859
0
    if (H5S_SELECT_RELEASE(new_space) < 0)
6860
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection");
6861
6862
    /* Allocate space for the hyperslab selection information */
6863
0
    if (NULL == (new_space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t)))
6864
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab info");
6865
6866
    /* Set unlim_dim */
6867
0
    new_space->select.sel_info.hslab->unlim_dim = -1;
6868
6869
    /* Check for a "regular" hyperslab selection */
6870
    /* (No need to rebuild the dimension info yet -QAK) */
6871
0
    if (base_space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
6872
0
        unsigned base_space_dim; /* Current dimension in the base dataspace */
6873
0
        unsigned new_space_dim;  /* Current dimension in the new dataspace */
6874
0
        unsigned u;              /* Local index variable */
6875
6876
        /* Check if the new space's rank is < or > base space's rank */
6877
0
        if (new_space->extent.rank < base_space->extent.rank) {
6878
0
            const H5S_hyper_dim_t *opt_diminfo = base_space->select.sel_info.hslab->diminfo
6879
0
                                                     .opt; /* Alias for dataspace's diminfo information */
6880
0
            hsize_t block[H5S_MAX_RANK];                   /* Block selected in base dataspace */
6881
6882
            /* Compute the offset for the down-projection */
6883
0
            memset(block, 0, sizeof(block));
6884
0
            for (u = 0; u < (base_space->extent.rank - new_space->extent.rank); u++)
6885
0
                block[u] = opt_diminfo[u].start;
6886
0
            *offset = H5VM_array_offset(base_space->extent.rank, base_space->extent.size, block);
6887
6888
            /* Set the correct dimensions for the base & new spaces */
6889
0
            base_space_dim = base_space->extent.rank - new_space->extent.rank;
6890
0
            new_space_dim  = 0;
6891
0
        } /* end if */
6892
0
        else {
6893
0
            assert(new_space->extent.rank > base_space->extent.rank);
6894
6895
            /* The offset is zero when projected into higher dimensions */
6896
0
            *offset = 0;
6897
6898
            /* Set the diminfo information for the higher dimensions */
6899
0
            for (new_space_dim = 0; new_space_dim < (new_space->extent.rank - base_space->extent.rank);
6900
0
                 new_space_dim++) {
6901
0
                new_space->select.sel_info.hslab->diminfo.app[new_space_dim].start  = 0;
6902
0
                new_space->select.sel_info.hslab->diminfo.app[new_space_dim].stride = 1;
6903
0
                new_space->select.sel_info.hslab->diminfo.app[new_space_dim].count  = 1;
6904
0
                new_space->select.sel_info.hslab->diminfo.app[new_space_dim].block  = 1;
6905
6906
0
                new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].start  = 0;
6907
0
                new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].stride = 1;
6908
0
                new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].count  = 1;
6909
0
                new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].block  = 1;
6910
0
            } /* end for */
6911
6912
            /* Start at beginning of base space's dimension info */
6913
0
            base_space_dim = 0;
6914
0
        } /* end else */
6915
6916
        /* Copy the diminfo */
6917
0
        while (base_space_dim < base_space->extent.rank) {
6918
0
            new_space->select.sel_info.hslab->diminfo.app[new_space_dim].start =
6919
0
                base_space->select.sel_info.hslab->diminfo.app[base_space_dim].start;
6920
0
            new_space->select.sel_info.hslab->diminfo.app[new_space_dim].stride =
6921
0
                base_space->select.sel_info.hslab->diminfo.app[base_space_dim].stride;
6922
0
            new_space->select.sel_info.hslab->diminfo.app[new_space_dim].count =
6923
0
                base_space->select.sel_info.hslab->diminfo.app[base_space_dim].count;
6924
0
            new_space->select.sel_info.hslab->diminfo.app[new_space_dim].block =
6925
0
                base_space->select.sel_info.hslab->diminfo.app[base_space_dim].block;
6926
6927
0
            new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].start =
6928
0
                base_space->select.sel_info.hslab->diminfo.opt[base_space_dim].start;
6929
0
            new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].stride =
6930
0
                base_space->select.sel_info.hslab->diminfo.opt[base_space_dim].stride;
6931
0
            new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].count =
6932
0
                base_space->select.sel_info.hslab->diminfo.opt[base_space_dim].count;
6933
0
            new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].block =
6934
0
                base_space->select.sel_info.hslab->diminfo.opt[base_space_dim].block;
6935
6936
            /* Advance to next dimensions */
6937
0
            base_space_dim++;
6938
0
            new_space_dim++;
6939
0
        } /* end for */
6940
6941
        /* Update the bounding box */
6942
0
        for (u = 0; u < new_space->extent.rank; u++) {
6943
0
            new_space->select.sel_info.hslab->diminfo.low_bounds[u] =
6944
0
                new_space->select.sel_info.hslab->diminfo.opt[u].start;
6945
0
            new_space->select.sel_info.hslab->diminfo.high_bounds[u] =
6946
0
                new_space->select.sel_info.hslab->diminfo.low_bounds[u] +
6947
0
                new_space->select.sel_info.hslab->diminfo.opt[u].stride *
6948
0
                    (new_space->select.sel_info.hslab->diminfo.opt[u].count - 1) +
6949
0
                (new_space->select.sel_info.hslab->diminfo.opt[u].block - 1);
6950
0
        } /* end for */
6951
6952
        /* Indicate that the dimension information is valid */
6953
0
        new_space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_YES;
6954
6955
        /* Indicate that there's no slab information */
6956
0
        new_space->select.sel_info.hslab->span_lst = NULL;
6957
0
    } /* end if */
6958
0
    else {
6959
        /* Check if the new space's rank is < or > base space's rank */
6960
0
        if (new_space->extent.rank < base_space->extent.rank) {
6961
0
            const H5S_hyper_span_t *curr;                /* Pointer to current hyperslab span */
6962
0
            hsize_t                 block[H5S_MAX_RANK]; /* Block selected in base dataspace */
6963
0
            unsigned                curr_dim;            /* Current dimension being operated on */
6964
6965
            /* Clear the block buffer */
6966
0
            memset(block, 0, sizeof(block));
6967
6968
            /* Advance down selected spans */
6969
0
            curr     = base_space->select.sel_info.hslab->span_lst->head;
6970
0
            curr_dim = 0;
6971
0
            while (curr && curr_dim < (base_space->extent.rank - new_space->extent.rank)) {
6972
                /* Save the location of the selection in current dimension */
6973
0
                block[curr_dim] = curr->low;
6974
6975
                /* Advance down to next dimension */
6976
0
                curr = curr->down->head;
6977
0
                curr_dim++;
6978
0
            } /* end while */
6979
6980
            /* Compute the offset for the down-projection */
6981
0
            *offset = H5VM_array_offset(base_space->extent.rank, base_space->extent.size, block);
6982
6983
            /* Project the base space's selection down in less dimensions */
6984
0
            if (H5S__hyper_project_simple_lower(base_space, new_space) < 0)
6985
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL,
6986
0
                            "can't project hyperslab selection into less dimensions");
6987
0
        } /* end if */
6988
0
        else {
6989
0
            assert(new_space->extent.rank > base_space->extent.rank);
6990
6991
            /* The offset is zero when projected into higher dimensions */
6992
0
            *offset = 0;
6993
6994
            /* Project the base space's selection down in more dimensions */
6995
0
            if (H5S__hyper_project_simple_higher(base_space, new_space) < 0)
6996
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL,
6997
0
                            "can't project hyperslab selection into less dimensions");
6998
0
        } /* end else */
6999
7000
        /* Copy the status of the dimension information */
7001
0
        new_space->select.sel_info.hslab->diminfo_valid = base_space->select.sel_info.hslab->diminfo_valid;
7002
0
    } /* end else */
7003
7004
    /* Number of elements selected will be the same */
7005
0
    new_space->select.num_elem = base_space->select.num_elem;
7006
7007
    /* Set selection type */
7008
0
    new_space->select.type = H5S_sel_hyper;
7009
7010
0
done:
7011
0
    FUNC_LEAVE_NOAPI(ret_value)
7012
0
} /* end H5S__hyper_project_simple() */
7013
7014
/*--------------------------------------------------------------------------
7015
 NAME
7016
    H5S__hyper_adjust_s_helper
7017
 PURPOSE
7018
    Helper routine to adjust offsets in span trees
7019
 USAGE
7020
    void H5S__hyper_adjust_s_helper(spans, rank, offset, op_info_i, op_gen)
7021
        H5S_hyper_span_info_t *spans;   IN: Span tree to operate with
7022
        unsigned rank;                  IN: Number of dimensions for span tree
7023
        const hssize_t *offset;         IN: Offset to subtract
7024
        unsigned op_info_i;             IN: Index of op info to use
7025
        uint64_t op_gen;                IN: Operation generation
7026
 RETURNS
7027
    None
7028
 DESCRIPTION
7029
    Adjust the location of the spans in a span tree by subtracting an offset
7030
 GLOBAL VARIABLES
7031
 COMMENTS, BUGS, ASSUMPTIONS
7032
 EXAMPLES
7033
 REVISION LOG
7034
--------------------------------------------------------------------------*/
7035
static void
7036
H5S__hyper_adjust_s_helper(H5S_hyper_span_info_t *spans, unsigned rank, const hssize_t *offset,
7037
                           unsigned op_info_i, uint64_t op_gen)
7038
0
{
7039
0
    FUNC_ENTER_PACKAGE_NOERR
7040
7041
    /* Sanity checks */
7042
0
    assert(spans);
7043
0
    assert(offset);
7044
7045
    /* Check if we've already set this span tree */
7046
0
    if (spans->op_info[op_info_i].op_gen != op_gen) {
7047
0
        H5S_hyper_span_t *span; /* Pointer to current span in span tree */
7048
0
        unsigned          u;    /* Local index variable */
7049
7050
        /* Adjust the span tree's low & high bounds */
7051
0
        for (u = 0; u < rank; u++) {
7052
0
            assert((hssize_t)spans->low_bounds[u] >= offset[u]);
7053
0
            spans->low_bounds[u]  = (hsize_t)((hssize_t)spans->low_bounds[u] - offset[u]);
7054
0
            spans->high_bounds[u] = (hsize_t)((hssize_t)spans->high_bounds[u] - offset[u]);
7055
0
        } /* end for */
7056
7057
        /* Iterate over the spans in tree */
7058
0
        span = spans->head;
7059
0
        while (span != NULL) {
7060
            /* Adjust span offset */
7061
0
            assert((hssize_t)span->low >= *offset);
7062
0
            span->low  = (hsize_t)((hssize_t)span->low - *offset);
7063
0
            span->high = (hsize_t)((hssize_t)span->high - *offset);
7064
7065
            /* Recursively adjust spans in next dimension down */
7066
0
            if (span->down != NULL)
7067
0
                H5S__hyper_adjust_s_helper(span->down, rank - 1, offset + 1, op_info_i, op_gen);
7068
7069
            /* Advance to next span in this dimension */
7070
0
            span = span->next;
7071
0
        } /* end while */
7072
7073
        /* Set the tree's operation generation */
7074
0
        spans->op_info[op_info_i].op_gen = op_gen;
7075
0
    } /* end if */
7076
7077
0
    FUNC_LEAVE_NOAPI_VOID
7078
0
} /* end H5S__hyper_adjust_s_helper() */
7079
7080
/*--------------------------------------------------------------------------
7081
 NAME
7082
    H5S__hyper_adjust_s
7083
 PURPOSE
7084
    Adjust a hyperslab selection by subtracting an offset
7085
 USAGE
7086
    herr_t H5S__hyper_adjust_s(space,offset)
7087
        H5S_t *space;           IN/OUT: Pointer to dataspace to adjust
7088
        const hssize_t *offset; IN: Offset to subtract
7089
 RETURNS
7090
    Non-negative on success, negative on failure
7091
 DESCRIPTION
7092
    Moves a hyperslab selection by subtracting an offset from it.
7093
 GLOBAL VARIABLES
7094
 COMMENTS, BUGS, ASSUMPTIONS
7095
 EXAMPLES
7096
 REVISION LOG
7097
--------------------------------------------------------------------------*/
7098
static herr_t
7099
H5S__hyper_adjust_s(H5S_t *space, const hssize_t *offset)
7100
0
{
7101
0
    bool     non_zero_offset = false; /* Whether any offset is non-zero */
7102
0
    unsigned u;                       /* Local index variable */
7103
7104
0
    FUNC_ENTER_PACKAGE_NOERR
7105
7106
    /* Sanity checks */
7107
0
    assert(space);
7108
0
    assert(offset);
7109
7110
    /* Check for an all-zero offset vector */
7111
0
    for (u = 0; u < space->extent.rank; u++)
7112
0
        if (0 != offset[u]) {
7113
0
            non_zero_offset = true;
7114
0
            break;
7115
0
        } /* end if */
7116
7117
    /* Only perform operation if the offset is non-zero */
7118
0
    if (non_zero_offset) {
7119
        /* Subtract the offset from the "regular" coordinates, if they exist */
7120
        /* (No need to rebuild the dimension info yet -QAK) */
7121
0
        if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
7122
0
            for (u = 0; u < space->extent.rank; u++) {
7123
0
                assert((hssize_t)space->select.sel_info.hslab->diminfo.opt[u].start >= offset[u]);
7124
0
                space->select.sel_info.hslab->diminfo.opt[u].start =
7125
0
                    (hsize_t)((hssize_t)space->select.sel_info.hslab->diminfo.opt[u].start - offset[u]);
7126
7127
                /* Adjust the low & high bounds */
7128
0
                assert((hssize_t)space->select.sel_info.hslab->diminfo.low_bounds[u] >= offset[u]);
7129
0
                space->select.sel_info.hslab->diminfo.low_bounds[u] =
7130
0
                    (hsize_t)((hssize_t)space->select.sel_info.hslab->diminfo.low_bounds[u] - offset[u]);
7131
0
                space->select.sel_info.hslab->diminfo.high_bounds[u] =
7132
0
                    (hsize_t)((hssize_t)space->select.sel_info.hslab->diminfo.high_bounds[u] - offset[u]);
7133
0
            } /* end for */
7134
0
        }     /* end if */
7135
7136
        /* Subtract the offset from the span tree coordinates, if they exist */
7137
0
        if (space->select.sel_info.hslab->span_lst) {
7138
0
            uint64_t op_gen; /* Operation generation value */
7139
7140
            /* Acquire an operation generation value for this operation */
7141
0
            op_gen = H5S__hyper_get_op_gen();
7142
7143
            /* Perform the adjustment */
7144
            /* Always use op_info[0] since we own this op_info, so there can be no
7145
             * simultaneous operations */
7146
0
            H5S__hyper_adjust_s_helper(space->select.sel_info.hslab->span_lst, space->extent.rank, offset, 0,
7147
0
                                       op_gen);
7148
0
        } /* end if */
7149
0
    }
7150
7151
0
    FUNC_LEAVE_NOAPI(SUCCEED)
7152
0
} /* end H5S__hyper_adjust_s() */
7153
7154
/*--------------------------------------------------------------------------
7155
 NAME
7156
    H5S_hyper_normalize_offset
7157
 PURPOSE
7158
    "Normalize" a hyperslab selection by adjusting it's coordinates by the
7159
    amount of the selection offset.
7160
 USAGE
7161
    htri_t H5S_hyper_normalize_offset(space, old_offset)
7162
        H5S_t *space;           IN/OUT: Pointer to dataspace to move
7163
        hssize_t *old_offset;   OUT: Pointer to space to store old offset
7164
 RETURNS
7165
    true/false for hyperslab selection, FAIL on error
7166
 DESCRIPTION
7167
    Copies the current selection offset into the array provided, then
7168
    inverts the selection offset, subtracts the offset from the hyperslab
7169
    selection and resets the offset to zero.
7170
 GLOBAL VARIABLES
7171
 COMMENTS, BUGS, ASSUMPTIONS
7172
 EXAMPLES
7173
 REVISION LOG
7174
--------------------------------------------------------------------------*/
7175
htri_t
7176
H5S_hyper_normalize_offset(H5S_t *space, hssize_t *old_offset)
7177
0
{
7178
0
    htri_t ret_value = false; /* Return value */
7179
7180
0
    FUNC_ENTER_NOAPI(FAIL)
7181
7182
    /* Sanity checks */
7183
0
    assert(space);
7184
0
    assert(old_offset);
7185
7186
    /* Check for hyperslab selection & offset changed */
7187
0
    if (H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS && space->select.offset_changed) {
7188
0
        unsigned u; /* Local index variable */
7189
7190
        /* Copy & invert the selection offset */
7191
0
        for (u = 0; u < space->extent.rank; u++) {
7192
0
            old_offset[u]           = space->select.offset[u];
7193
0
            space->select.offset[u] = -space->select.offset[u];
7194
0
        } /* end for */
7195
7196
        /* Call the 'adjust' routine */
7197
0
        if (H5S__hyper_adjust_s(space, space->select.offset) < 0)
7198
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't adjust selection");
7199
7200
        /* Zero out the selection offset */
7201
0
        memset(space->select.offset, 0, sizeof(hssize_t) * space->extent.rank);
7202
7203
        /* Indicate that the offset was normalized */
7204
0
        ret_value = true;
7205
0
    } /* end if */
7206
7207
0
done:
7208
0
    FUNC_LEAVE_NOAPI(ret_value)
7209
0
} /* end H5S_hyper_normalize_offset() */
7210
7211
/*--------------------------------------------------------------------------
7212
 NAME
7213
    H5S_hyper_denormalize_offset
7214
 PURPOSE
7215
    "Denormalize" a hyperslab selection by reverse adjusting it's coordinates
7216
    by the amount of the former selection offset.
7217
 USAGE
7218
    herr_t H5S_hyper_denormalize_offset(space, old_offset)
7219
        H5S_t *space;           IN/OUT: Pointer to dataspace to move
7220
        hssize_t *old_offset;   IN: Pointer to old offset array
7221
 RETURNS
7222
    Non-negative on success, negative on failure
7223
 DESCRIPTION
7224
    Subtracts the old offset from the current selection (canceling out the
7225
    effect of the "normalize" routine), then restores the old offset into
7226
    the dataspace.
7227
 GLOBAL VARIABLES
7228
 COMMENTS, BUGS, ASSUMPTIONS
7229
 EXAMPLES
7230
 REVISION LOG
7231
--------------------------------------------------------------------------*/
7232
herr_t
7233
H5S_hyper_denormalize_offset(H5S_t *space, const hssize_t *old_offset)
7234
0
{
7235
0
    herr_t ret_value = SUCCEED; /* Return value */
7236
7237
0
    FUNC_ENTER_NOAPI(FAIL)
7238
7239
    /* Sanity checks */
7240
0
    assert(space);
7241
0
    assert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS);
7242
7243
    /* Call the 'adjust' routine */
7244
0
    if (H5S__hyper_adjust_s(space, old_offset) < 0)
7245
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't adjust selection");
7246
7247
    /* Copy the selection offset over */
7248
0
    H5MM_memcpy(space->select.offset, old_offset, sizeof(hssize_t) * space->extent.rank);
7249
7250
0
done:
7251
0
    FUNC_LEAVE_NOAPI(ret_value)
7252
0
} /* end H5S_hyper_denormalize_offset() */
7253
7254
/*--------------------------------------------------------------------------
7255
 NAME
7256
    H5S__hyper_append_span
7257
 PURPOSE
7258
    Create a new span and append to span list
7259
 USAGE
7260
    herr_t H5S__hyper_append_span(span_tree, ndims, low, high, down)
7261
        H5S_hyper_span_info_t **span_tree;  IN/OUT: Pointer to span tree to append to
7262
        unsigned ndims;                  IN: Number of dimension for span
7263
        hsize_t low, high;               IN: Low and high bounds for new span node
7264
        H5S_hyper_span_info_t *down;     IN: Down span tree for new node
7265
 RETURNS
7266
    Non-negative on success, negative on failure
7267
 DESCRIPTION
7268
    Create a new span node and append to a span list.  Update the previous
7269
    span in the list also.
7270
 GLOBAL VARIABLES
7271
 COMMENTS, BUGS, ASSUMPTIONS
7272
 EXAMPLES
7273
 REVISION LOG
7274
--------------------------------------------------------------------------*/
7275
static herr_t
7276
H5S__hyper_append_span(H5S_hyper_span_info_t **span_tree, unsigned ndims, hsize_t low, hsize_t high,
7277
                       H5S_hyper_span_info_t *down)
7278
0
{
7279
0
    H5S_hyper_span_t *new_span  = NULL;
7280
0
    herr_t            ret_value = SUCCEED; /* Return value */
7281
7282
0
    FUNC_ENTER_PACKAGE
7283
7284
    /* Sanity checks */
7285
0
    assert(span_tree);
7286
7287
    /* Check for adding first node to merged spans */
7288
0
    if (*span_tree == NULL) {
7289
        /* Allocate new span node to append to list */
7290
0
        if (NULL == (new_span = H5S__hyper_new_span(low, high, down, NULL)))
7291
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span");
7292
7293
        /* Make new span the first node in span list */
7294
7295
        /* Allocate a new span_info node */
7296
0
        if (NULL == (*span_tree = H5S__hyper_new_span_info(ndims)))
7297
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span");
7298
7299
        /* Set the span tree's basic information */
7300
0
        (*span_tree)->count = 1;
7301
0
        (*span_tree)->head  = new_span;
7302
0
        (*span_tree)->tail  = new_span;
7303
7304
        /* Set low & high bounds for new span tree */
7305
0
        (*span_tree)->low_bounds[0]  = low;
7306
0
        (*span_tree)->high_bounds[0] = high;
7307
0
        if (down) {
7308
            /* Sanity check */
7309
0
            assert(ndims > 1);
7310
7311
0
            H5MM_memcpy(&((*span_tree)->low_bounds[1]), down->low_bounds, sizeof(hsize_t) * (ndims - 1));
7312
0
            H5MM_memcpy(&((*span_tree)->high_bounds[1]), down->high_bounds, sizeof(hsize_t) * (ndims - 1));
7313
0
        } /* end if */
7314
0
    }     /* end if */
7315
    /* Merge or append to existing merged spans list */
7316
0
    else {
7317
0
        htri_t down_cmp = (-1); /* Comparison value for down spans */
7318
7319
        /* Check if span can just extend the previous merged span */
7320
0
        if ((((*span_tree)->tail->high + 1) == low) &&
7321
0
            (down_cmp = H5S__hyper_cmp_spans(down, (*span_tree)->tail->down))) {
7322
            /* Extend previous merged span to include new high bound */
7323
0
            (*span_tree)->tail->high = high;
7324
7325
            /* Extend span tree's high bound in this dimension */
7326
            /* (No need to update lower dimensions, since this span shares them with previous span) */
7327
0
            (*span_tree)->high_bounds[0] = high;
7328
0
        } /* end if */
7329
0
        else {
7330
0
            H5S_hyper_span_info_t *new_down; /* Down pointer for new span node */
7331
7332
            /* Sanity check */
7333
            /* (If down_cmp was set to true above, we won't be in this branch) */
7334
0
            assert(down_cmp != true);
7335
7336
            /* Check if there is actually a down span */
7337
0
            if (down) {
7338
                /* Check if the down spans for the new span node are the same as the previous span node */
7339
                /* (Uses the 'down span comparison' from earlier, if already computed) */
7340
0
                if (down_cmp < 0 && (down_cmp = H5S__hyper_cmp_spans(down, (*span_tree)->tail->down)))
7341
                    /* Share the previous span's down span tree */
7342
0
                    new_down = (*span_tree)->tail->down;
7343
0
                else
7344
0
                    new_down = down;
7345
0
            } /* end if */
7346
0
            else
7347
0
                new_down = NULL;
7348
7349
            /* Allocate new span node to append to list */
7350
0
            if (NULL == (new_span = H5S__hyper_new_span(low, high, new_down, NULL)))
7351
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span");
7352
7353
            /* Update the high bounds for current dimension */
7354
0
            (*span_tree)->high_bounds[0] = high;
7355
7356
            /* Update low & high bounds in lower dimensions, if there are any */
7357
0
            if (down) {
7358
                /* Sanity checks */
7359
0
                assert(ndims > 1);
7360
0
                assert(down_cmp >= 0);
7361
7362
                /* Check if we are sharing down spans with a previous node */
7363
                /* (Only need to check for bounds changing if down spans aren't shared) */
7364
0
                if (down_cmp == false) {
7365
0
                    unsigned u; /* Local index variable */
7366
7367
                    /* Loop over lower dimensions, checking & updating low & high bounds */
7368
0
                    for (u = 0; u < (ndims - 1); u++) {
7369
0
                        if (down->low_bounds[u] < (*span_tree)->low_bounds[u + 1])
7370
0
                            (*span_tree)->low_bounds[u + 1] = down->low_bounds[u];
7371
0
                        if (down->high_bounds[u] > (*span_tree)->high_bounds[u + 1])
7372
0
                            (*span_tree)->high_bounds[u + 1] = down->high_bounds[u];
7373
0
                    } /* end for */
7374
0
                }     /* end if */
7375
0
            }         /* end if */
7376
7377
            /* Append to end of merged spans list */
7378
0
            (*span_tree)->tail->next = new_span;
7379
0
            (*span_tree)->tail       = new_span;
7380
0
        } /* end else */
7381
0
    }     /* end else */
7382
7383
0
done:
7384
0
    if (ret_value < 0)
7385
0
        if (new_span)
7386
0
            if (H5S__hyper_free_span(new_span) < 0)
7387
0
                HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span");
7388
7389
0
    FUNC_LEAVE_NOAPI(ret_value)
7390
0
} /* end H5S__hyper_append_span() */
7391
7392
/*--------------------------------------------------------------------------
7393
 NAME
7394
    H5S__hyper_clip_spans
7395
 PURPOSE
7396
    Clip a new span tree against the current spans in the hyperslab selection
7397
 USAGE
7398
    herr_t H5S__hyper_clip_spans(span_a, span_b, selector, curr_dim, dim_size,
7399
                                span_a_b_bounds[4], all_clips_bound,
7400
                                a_not_b, a_and_b, b_not_a)
7401
        H5S_hyper_span_t *a_spans;    IN: Span tree 'a' to clip with.
7402
        H5S_hyper_span_t *b_spans;    IN: Span tree 'b' to clip with.
7403
        unsigned selector;            IN: The parameter deciding which output is needed
7404
                                          (only considering the last three bits ABC:
7405
                                           If A is set, then a_not_b is needed;
7406
                                           If B is set, then a_and_b is needed;
7407
                                           If C is set, then b_not_a is needed;
7408
                                           )
7409
        unsigned ndims;               IN: Number of dimensions of this span tree
7410
        H5S_hyper_span_t **a_not_b;  OUT: Span tree of 'a' hyperslab spans which
7411
                                            doesn't overlap with 'b' hyperslab
7412
                                            spans.
7413
        H5S_hyper_span_t **a_and_b;  OUT: Span tree of 'a' hyperslab spans which
7414
                                            overlaps with 'b' hyperslab spans.
7415
        H5S_hyper_span_t **b_not_a;  OUT: Span tree of 'b' hyperslab spans which
7416
                                            doesn't overlap with 'a' hyperslab
7417
                                            spans.
7418
 RETURNS
7419
    non-negative on success, negative on failure
7420
 DESCRIPTION
7421
    Clip one span tree ('a') against another span tree ('b').  Creates span
7422
    trees for the area defined by the 'a' span tree which does not overlap the
7423
    'b' span tree ("a not b"), the area defined by the overlap of the 'a'
7424
    hyperslab span tree and the 'b' span tree ("a and b"), and the area defined
7425
    by the 'b' hyperslab span tree which does not overlap the 'a' span
7426
    tree ("b not a").
7427
 GLOBAL VARIABLES
7428
 COMMENTS, BUGS, ASSUMPTIONS
7429
 EXAMPLES
7430
 REVISION LOG
7431
--------------------------------------------------------------------------*/
7432
static herr_t
7433
H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_spans, unsigned selector,
7434
                      unsigned ndims, H5S_hyper_span_info_t **a_not_b, H5S_hyper_span_info_t **a_and_b,
7435
                      H5S_hyper_span_info_t **b_not_a)
7436
0
{
7437
0
    bool   need_a_not_b;        /* Whether to generate a_not_b list */
7438
0
    bool   need_a_and_b;        /* Whether to generate a_and_b list */
7439
0
    bool   need_b_not_a;        /* Whether to generate b_not_a list */
7440
0
    herr_t ret_value = SUCCEED; /* Return value */
7441
7442
0
    FUNC_ENTER_PACKAGE
7443
7444
    /* Check args */
7445
0
    assert(a_spans);
7446
0
    assert(b_spans);
7447
0
    assert(a_not_b);
7448
0
    assert(a_and_b);
7449
0
    assert(b_not_a);
7450
7451
    /* Set which list(s) to be generated, based on selector */
7452
0
    need_a_not_b = ((selector & H5S_HYPER_COMPUTE_A_NOT_B) != 0);
7453
0
    need_a_and_b = ((selector & H5S_HYPER_COMPUTE_A_AND_B) != 0);
7454
0
    need_b_not_a = ((selector & H5S_HYPER_COMPUTE_B_NOT_A) != 0);
7455
7456
    /* Check if both span trees are not defined */
7457
0
    if (a_spans == NULL && b_spans == NULL) {
7458
0
        *a_not_b = NULL;
7459
0
        *a_and_b = NULL;
7460
0
        *b_not_a = NULL;
7461
0
    } /* end if */
7462
    /* If span 'a' is not defined, but 'b' is, copy 'b' and set the other return span trees to empty */
7463
0
    else if (a_spans == NULL) {
7464
0
        *a_not_b = NULL;
7465
0
        *a_and_b = NULL;
7466
0
        if (need_b_not_a) {
7467
0
            if (NULL == (*b_not_a = H5S__hyper_copy_span(b_spans, ndims)))
7468
0
                HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree");
7469
0
        } /* end if */
7470
0
        else
7471
0
            *b_not_a = NULL;
7472
0
    } /* end if */
7473
    /* If span 'b' is not defined, but 'a' is, copy 'a' and set the other return span trees to empty */
7474
0
    else if (b_spans == NULL) {
7475
0
        *a_and_b = NULL;
7476
0
        *b_not_a = NULL;
7477
0
        if (need_a_not_b) {
7478
0
            if (NULL == (*a_not_b = H5S__hyper_copy_span(a_spans, ndims)))
7479
0
                HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree");
7480
0
        } /* end if */
7481
0
        else
7482
0
            *a_not_b = NULL;
7483
0
    } /* end if */
7484
    /* If span 'a' and 'b' are both defined, calculate the proper span trees */
7485
0
    else {
7486
        /* Check if both span trees completely overlap */
7487
0
        if (H5S__hyper_cmp_spans(a_spans, b_spans)) {
7488
0
            *a_not_b = NULL;
7489
0
            *b_not_a = NULL;
7490
0
            if (need_a_and_b) {
7491
0
                if (NULL == (*a_and_b = H5S__hyper_copy_span(a_spans, ndims)))
7492
0
                    HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree");
7493
0
            } /* end if */
7494
0
            else
7495
0
                *a_and_b = NULL;
7496
0
        } /* end if */
7497
0
        else {
7498
0
            H5S_hyper_span_t *span_a;               /* Pointer to a node in span tree 'a' */
7499
0
            H5S_hyper_span_t *span_b;               /* Pointer to a node in span tree 'b' */
7500
0
            bool              recover_a, recover_b; /* Flags to indicate when to recover temporary spans */
7501
7502
            /* Get the pointers to the new and old span lists */
7503
0
            span_a = a_spans->head;
7504
0
            span_b = b_spans->head;
7505
7506
            /* No spans to recover yet */
7507
0
            recover_a = recover_b = false;
7508
7509
            /* Work through the list of spans in the new list */
7510
0
            while (span_a != NULL && span_b != NULL) {
7511
0
                H5S_hyper_span_info_t *down_a_not_b; /* Temporary pointer to a_not_b span tree of down spans
7512
                                                        for overlapping nodes */
7513
0
                H5S_hyper_span_info_t *down_a_and_b; /* Temporary pointer to a_and_b span tree of down spans
7514
                                                        for overlapping nodes */
7515
0
                H5S_hyper_span_info_t *down_b_not_a; /* Temporary pointer to b_and_a span tree of down spans
7516
                                                        for overlapping nodes */
7517
0
                H5S_hyper_span_t *tmp_span;          /* Temporary pointer to new span */
7518
7519
                /* Check if span 'a' is completely before span 'b' */
7520
                /*    AAAAAAA                            */
7521
                /* <-----------------------------------> */
7522
                /*             BBBBBBBBBB                */
7523
0
                if (span_a->high < span_b->low) {
7524
                    /* Copy span 'a' and add to a_not_b list */
7525
7526
                    /* Merge/add span 'a' with/to a_not_b list */
7527
0
                    if (need_a_not_b)
7528
0
                        if (H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_a->high, span_a->down) <
7529
0
                            0)
7530
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
7531
7532
                    /* Advance span 'a', leave span 'b' */
7533
0
                    H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, FAIL);
7534
0
                } /* end if */
7535
                /* Check if span 'a' overlaps only the lower bound */
7536
                /*  of span 'b' , up to the upper bound of span 'b' */
7537
                /*    AAAAAAAAAAAA                       */
7538
                /* <-----------------------------------> */
7539
                /*             BBBBBBBBBB                */
7540
0
                else if (span_a->low < span_b->low &&
7541
0
                         (span_a->high >= span_b->low && span_a->high <= span_b->high)) {
7542
                    /* Split span 'a' into two parts at the low bound of span 'b' */
7543
7544
                    /* Merge/add lower part of span 'a' with/to a_not_b list */
7545
0
                    if (need_a_not_b)
7546
0
                        if (H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_b->low - 1,
7547
0
                                                   span_a->down) < 0)
7548
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
7549
7550
                    /* Check for overlaps between upper part of span 'a' and lower part of span 'b' */
7551
7552
                    /* Make certain both spans either have a down span or both don't have one */
7553
0
                    assert((span_a->down != NULL && span_b->down != NULL) ||
7554
0
                           (span_a->down == NULL && span_b->down == NULL));
7555
7556
                    /* If there are no down spans, just add the overlapping area to the a_and_b list */
7557
0
                    if (span_a->down == NULL) {
7558
                        /* Merge/add overlapped part with/to a_and_b list */
7559
0
                        if (need_a_and_b)
7560
0
                            if (H5S__hyper_append_span(a_and_b, ndims, span_b->low, span_a->high, NULL) < 0)
7561
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7562
0
                                            "can't allocate hyperslab span");
7563
0
                    } /* end if */
7564
                    /* If there are down spans, check for the overlap in them and add to each appropriate list
7565
                     */
7566
0
                    else {
7567
                        /* NULL out the temporary pointers to clipped areas in down spans */
7568
0
                        down_a_not_b = NULL;
7569
0
                        down_a_and_b = NULL;
7570
0
                        down_b_not_a = NULL;
7571
7572
                        /* Check for overlaps in the 'down spans' of span 'a' & 'b' */
7573
                        /** Note: since the bound box of remaining dimensions
7574
                         *  has been updated in the following clip function (via
7575
                         *  all_clips_bounds), there's no need updating the bound box
7576
                         *  after each append call in the following codes */
7577
0
                        if (H5S__hyper_clip_spans(span_a->down, span_b->down, selector, ndims - 1,
7578
0
                                                  &down_a_not_b, &down_a_and_b, &down_b_not_a) < 0)
7579
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL,
7580
0
                                        "can't clip hyperslab information");
7581
7582
                        /* Check for additions to the a_not_b list */
7583
0
                        if (down_a_not_b) {
7584
0
                            assert(need_a_not_b == true);
7585
7586
                            /* Merge/add overlapped part with/to a_not_b list */
7587
0
                            if (H5S__hyper_append_span(a_not_b, ndims, span_b->low, span_a->high,
7588
0
                                                       down_a_not_b) < 0)
7589
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7590
0
                                            "can't allocate hyperslab span");
7591
7592
                            /* Release the down span tree generated */
7593
0
                            if (H5S__hyper_free_span_info(down_a_not_b) < 0)
7594
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7595
0
                        }
7596
7597
                        /* Check for additions to the a_and_b list */
7598
0
                        if (down_a_and_b) {
7599
0
                            assert(need_a_and_b == true);
7600
7601
                            /* Merge/add overlapped part with/to a_and_b list */
7602
0
                            if (H5S__hyper_append_span(a_and_b, ndims, span_b->low, span_a->high,
7603
0
                                                       down_a_and_b) < 0)
7604
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7605
0
                                            "can't allocate hyperslab span");
7606
7607
                            /* Release the down span tree generated */
7608
0
                            if (H5S__hyper_free_span_info(down_a_and_b) < 0)
7609
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7610
0
                        }
7611
7612
                        /* Check for additions to the b_not_a list */
7613
0
                        if (down_b_not_a) {
7614
0
                            assert(need_b_not_a == true);
7615
7616
                            /* Merge/add overlapped part with/to b_not_a list */
7617
0
                            if (H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_a->high,
7618
0
                                                       down_b_not_a) < 0)
7619
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7620
0
                                            "can't allocate hyperslab span");
7621
7622
                            /* Release the down span tree generated */
7623
0
                            if (H5S__hyper_free_span_info(down_b_not_a) < 0)
7624
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7625
0
                        }
7626
0
                    } /* end else */
7627
7628
                    /* Split off upper part of span 'b' at upper span of span 'a' */
7629
7630
                    /* Check if there is actually an upper part of span 'b' to split off */
7631
0
                    if (span_a->high < span_b->high) {
7632
                        /* Allocate new span node for upper part of span 'b' */
7633
0
                        if (NULL == (tmp_span = H5S__hyper_new_span(span_a->high + 1, span_b->high,
7634
0
                                                                    span_b->down, span_b->next)))
7635
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span");
7636
7637
                        /* Advance span 'a' */
7638
0
                        H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, FAIL);
7639
7640
                        /* Make upper part of span 'b' into new span 'b' */
7641
0
                        H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, tmp_span, FAIL);
7642
0
                        recover_b = true;
7643
0
                    } /* end if */
7644
                    /* No upper part of span 'b' to split */
7645
0
                    else {
7646
                        /* Advance both 'a' and 'b' */
7647
0
                        H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, FAIL);
7648
0
                        H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, FAIL);
7649
0
                    } /* end else */
7650
0
                }     /* end if */
7651
                /* Check if span 'a' overlaps the lower & upper bound */
7652
                /*  of span 'b' */
7653
                /*    AAAAAAAAAAAAAAAAAAAAA              */
7654
                /* <-----------------------------------> */
7655
                /*             BBBBBBBBBB                */
7656
0
                else if (span_a->low < span_b->low && span_a->high > span_b->high) {
7657
                    /* Split off lower part of span 'a' at lower span of span 'b' */
7658
7659
                    /* Merge/add lower part of span 'a' with/to a_not_b list */
7660
0
                    if (need_a_not_b)
7661
0
                        if (H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_b->low - 1,
7662
0
                                                   span_a->down) < 0)
7663
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
7664
7665
                    /* Check for overlaps between middle part of span 'a' and span 'b' */
7666
7667
                    /* Make certain both spans either have a down span or both don't have one */
7668
0
                    assert((span_a->down != NULL && span_b->down != NULL) ||
7669
0
                           (span_a->down == NULL && span_b->down == NULL));
7670
7671
                    /* If there are no down spans, just add the overlapping area to the a_and_b list */
7672
0
                    if (span_a->down == NULL) {
7673
                        /* Merge/add overlapped part with/to a_and_b list */
7674
0
                        if (need_a_and_b)
7675
0
                            if (H5S__hyper_append_span(a_and_b, ndims, span_b->low, span_b->high, NULL) < 0)
7676
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7677
0
                                            "can't allocate hyperslab span");
7678
0
                    } /* end if */
7679
                    /* If there are down spans, check for the overlap in them and add to each appropriate list
7680
                     */
7681
0
                    else {
7682
                        /* NULL out the temporary pointers to clipped areas in down spans */
7683
0
                        down_a_not_b = NULL;
7684
0
                        down_a_and_b = NULL;
7685
0
                        down_b_not_a = NULL;
7686
7687
                        /* Check for overlaps in the 'down spans' of span 'a' & 'b' */
7688
0
                        if (H5S__hyper_clip_spans(span_a->down, span_b->down, selector, ndims - 1,
7689
0
                                                  &down_a_not_b, &down_a_and_b, &down_b_not_a) < 0)
7690
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL,
7691
0
                                        "can't clip hyperslab information");
7692
7693
                        /* Check for additions to the a_not_b list */
7694
0
                        if (down_a_not_b) {
7695
0
                            assert(need_a_not_b == true);
7696
7697
                            /* Merge/add overlapped part with/to a_not_b list */
7698
0
                            if (H5S__hyper_append_span(a_not_b, ndims, span_b->low, span_b->high,
7699
0
                                                       down_a_not_b) < 0)
7700
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7701
0
                                            "can't allocate hyperslab span");
7702
7703
                            /* Release the down span tree generated */
7704
0
                            if (H5S__hyper_free_span_info(down_a_not_b) < 0)
7705
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7706
0
                        }
7707
7708
                        /* Check for additions to the a_and_b list */
7709
0
                        if (down_a_and_b) {
7710
0
                            assert(need_a_and_b == true);
7711
7712
                            /* Merge/add overlapped part with/to a_and_b list */
7713
0
                            if (H5S__hyper_append_span(a_and_b, ndims, span_b->low, span_b->high,
7714
0
                                                       down_a_and_b) < 0)
7715
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7716
0
                                            "can't allocate hyperslab span");
7717
7718
                            /* Release the down span tree generated */
7719
0
                            if (H5S__hyper_free_span_info(down_a_and_b) < 0)
7720
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7721
0
                        }
7722
7723
                        /* Check for additions to the b_not_a list */
7724
0
                        if (down_b_not_a) {
7725
0
                            assert(need_b_not_a == true);
7726
7727
                            /* Merge/add overlapped part with/to b_not_a list */
7728
0
                            if (H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_b->high,
7729
0
                                                       down_b_not_a) < 0)
7730
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7731
0
                                            "can't allocate hyperslab span");
7732
7733
                            /* Release the down span tree generated */
7734
0
                            if (H5S__hyper_free_span_info(down_b_not_a) < 0)
7735
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7736
0
                        }
7737
0
                    } /* end else */
7738
7739
                    /* Split off upper part of span 'a' at upper span of span 'b' */
7740
7741
                    /* Allocate new span node for upper part of span 'a' */
7742
0
                    if (NULL == (tmp_span = H5S__hyper_new_span(span_b->high + 1, span_a->high, span_a->down,
7743
0
                                                                span_a->next)))
7744
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span");
7745
7746
                    /* Make upper part of span 'a' the new span 'a' */
7747
0
                    H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, tmp_span, FAIL);
7748
0
                    recover_a = true;
7749
7750
                    /* Advance span 'b' */
7751
0
                    H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, FAIL);
7752
0
                } /* end if */
7753
                /* Check if span 'a' is entirely within span 'b' */
7754
                /*                AAAAA                  */
7755
                /* <-----------------------------------> */
7756
                /*             BBBBBBBBBB                */
7757
0
                else if (span_a->low >= span_b->low && span_a->high <= span_b->high) {
7758
                    /* Split off lower part of span 'b' at lower span of span 'a' */
7759
7760
                    /* Check if there is actually a lower part of span 'b' to split off */
7761
0
                    if (span_a->low > span_b->low) {
7762
                        /* Merge/add lower part of span 'b' with/to b_not_a list */
7763
0
                        if (need_b_not_a)
7764
0
                            if (H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_a->low - 1,
7765
0
                                                       span_b->down) < 0)
7766
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7767
0
                                            "can't allocate hyperslab span");
7768
0
                    } /* end if */
7769
0
                    else {
7770
                        /* Keep going, nothing to split off */
7771
0
                    } /* end else */
7772
7773
                    /* Check for overlaps between span 'a' and middle of span 'b' */
7774
7775
                    /* Make certain both spans either have a down span or both don't have one */
7776
0
                    assert((span_a->down != NULL && span_b->down != NULL) ||
7777
0
                           (span_a->down == NULL && span_b->down == NULL));
7778
7779
                    /* If there are no down spans, just add the overlapping area to the a_and_b list */
7780
0
                    if (span_a->down == NULL) {
7781
                        /* Merge/add overlapped part with/to a_and_b list */
7782
0
                        if (need_a_and_b)
7783
0
                            if (H5S__hyper_append_span(a_and_b, ndims, span_a->low, span_a->high, NULL) < 0)
7784
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7785
0
                                            "can't allocate hyperslab span");
7786
0
                    } /* end if */
7787
                    /* If there are down spans, check for the overlap in them and add to each appropriate list
7788
                     */
7789
0
                    else {
7790
                        /* NULL out the temporary pointers to clipped areas in down spans */
7791
0
                        down_a_not_b = NULL;
7792
0
                        down_a_and_b = NULL;
7793
0
                        down_b_not_a = NULL;
7794
7795
                        /* Check for overlaps in the 'down spans' of span 'a' & 'b' */
7796
0
                        if (H5S__hyper_clip_spans(span_a->down, span_b->down, selector, ndims - 1,
7797
0
                                                  &down_a_not_b, &down_a_and_b, &down_b_not_a) < 0)
7798
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL,
7799
0
                                        "can't clip hyperslab information");
7800
7801
                        /* Check for additions to the a_not_b list */
7802
0
                        if (down_a_not_b) {
7803
0
                            assert(need_a_not_b == true);
7804
7805
                            /* Merge/add overlapped part with/to a_not_b list */
7806
0
                            if (H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_a->high,
7807
0
                                                       down_a_not_b) < 0)
7808
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7809
0
                                            "can't allocate hyperslab span");
7810
7811
                            /* Release the down span tree generated */
7812
0
                            if (H5S__hyper_free_span_info(down_a_not_b) < 0)
7813
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7814
0
                        }
7815
7816
                        /* Check for additions to the a_and_b list */
7817
0
                        if (down_a_and_b) {
7818
0
                            assert(need_a_and_b == true);
7819
7820
                            /* Merge/add overlapped part with/to a_and_b list */
7821
0
                            if (H5S__hyper_append_span(a_and_b, ndims, span_a->low, span_a->high,
7822
0
                                                       down_a_and_b) < 0)
7823
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7824
0
                                            "can't allocate hyperslab span");
7825
7826
                            /* Release the down span tree generated */
7827
0
                            if (H5S__hyper_free_span_info(down_a_and_b) < 0)
7828
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7829
0
                        }
7830
7831
                        /* Check for additions to the b_not_a list */
7832
0
                        if (down_b_not_a) {
7833
0
                            assert(need_b_not_a == true);
7834
7835
                            /* Merge/add overlapped part with/to b_not_a list */
7836
0
                            if (H5S__hyper_append_span(b_not_a, ndims, span_a->low, span_a->high,
7837
0
                                                       down_b_not_a) < 0)
7838
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7839
0
                                            "can't allocate hyperslab span");
7840
7841
                            /* Release the down span tree generated */
7842
0
                            if (H5S__hyper_free_span_info(down_b_not_a) < 0)
7843
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7844
0
                        }
7845
0
                    } /* end else */
7846
7847
                    /* Check if there is actually an upper part of span 'b' to split off */
7848
0
                    if (span_a->high < span_b->high) {
7849
                        /* Split off upper part of span 'b' at upper span of span 'a' */
7850
7851
                        /* Allocate new span node for upper part of spans 'a' */
7852
0
                        if (NULL == (tmp_span = H5S__hyper_new_span(span_a->high + 1, span_b->high,
7853
0
                                                                    span_b->down, span_b->next)))
7854
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span");
7855
7856
                        /* And advance span 'a' */
7857
0
                        H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, FAIL);
7858
7859
                        /* Make upper part of span 'b' the new span 'b' */
7860
0
                        H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, tmp_span, FAIL);
7861
0
                        recover_b = true;
7862
0
                    } /* end if */
7863
0
                    else {
7864
                        /* Advance both span 'a' & span 'b' */
7865
0
                        H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, FAIL);
7866
0
                        H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, FAIL);
7867
0
                    } /* end else */
7868
0
                }     /* end if */
7869
                /* Check if span 'a' overlaps only the upper bound */
7870
                /*  of span 'b' */
7871
                /*                AAAAAAAAAA             */
7872
                /* <-----------------------------------> */
7873
                /*             BBBBBBBBBB                */
7874
0
                else if ((span_a->low >= span_b->low && span_a->low <= span_b->high) &&
7875
0
                         span_a->high > span_b->high) {
7876
                    /* Check if there is actually a lower part of span 'b' to split off */
7877
0
                    if (span_a->low > span_b->low) {
7878
                        /* Split off lower part of span 'b' at lower span of span 'a' */
7879
7880
                        /* Merge/add lower part of span 'b' with/to b_not_a list */
7881
0
                        if (need_b_not_a)
7882
0
                            if (H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_a->low - 1,
7883
0
                                                       span_b->down) < 0)
7884
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7885
0
                                            "can't allocate hyperslab span");
7886
0
                    } /* end if */
7887
0
                    else {
7888
                        /* Keep going, nothing to split off */
7889
0
                    } /* end else */
7890
7891
                    /* Check for overlaps between lower part of span 'a' and upper part of span 'b' */
7892
7893
                    /* Make certain both spans either have a down span or both don't have one */
7894
0
                    assert((span_a->down != NULL && span_b->down != NULL) ||
7895
0
                           (span_a->down == NULL && span_b->down == NULL));
7896
7897
                    /* If there are no down spans, just add the overlapping area to the a_and_b list */
7898
0
                    if (span_a->down == NULL) {
7899
                        /* Merge/add overlapped part with/to a_and_b list */
7900
0
                        if (need_a_and_b)
7901
0
                            if (H5S__hyper_append_span(a_and_b, ndims, span_a->low, span_b->high, NULL) < 0)
7902
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7903
0
                                            "can't allocate hyperslab span");
7904
0
                    } /* end if */
7905
                    /* If there are down spans, check for the overlap in them and add to each appropriate list
7906
                     */
7907
0
                    else {
7908
                        /* NULL out the temporary pointers to clipped areas in down spans */
7909
0
                        down_a_not_b = NULL;
7910
0
                        down_a_and_b = NULL;
7911
0
                        down_b_not_a = NULL;
7912
7913
                        /* Check for overlaps in the 'down spans' of span 'a' & 'b' */
7914
0
                        if (H5S__hyper_clip_spans(span_a->down, span_b->down, selector, ndims - 1,
7915
0
                                                  &down_a_not_b, &down_a_and_b, &down_b_not_a) < 0)
7916
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL,
7917
0
                                        "can't clip hyperslab information");
7918
7919
                        /* Check for additions to the a_not_b list */
7920
0
                        if (down_a_not_b) {
7921
0
                            assert(need_a_not_b == true);
7922
7923
                            /* Merge/add overlapped part with/to a_not_b list */
7924
0
                            if (H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_b->high,
7925
0
                                                       down_a_not_b) < 0)
7926
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7927
0
                                            "can't allocate hyperslab span");
7928
7929
                            /* Release the down span tree generated */
7930
0
                            if (H5S__hyper_free_span_info(down_a_not_b) < 0)
7931
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7932
0
                        }
7933
7934
                        /* Check for additions to the a_and_b list */
7935
0
                        if (down_a_and_b) {
7936
0
                            assert(need_a_and_b == true);
7937
7938
                            /* Merge/add overlapped part with/to a_and_b list */
7939
0
                            if (H5S__hyper_append_span(a_and_b, ndims, span_a->low, span_b->high,
7940
0
                                                       down_a_and_b) < 0)
7941
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7942
0
                                            "can't allocate hyperslab span");
7943
7944
                            /* Release the down span tree generated */
7945
0
                            if (H5S__hyper_free_span_info(down_a_and_b) < 0)
7946
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7947
0
                        }
7948
7949
                        /* Check for additions to the b_not_a list */
7950
0
                        if (down_b_not_a) {
7951
0
                            assert(need_b_not_a == true);
7952
7953
                            /* Merge/add overlapped part with/to b_not_a list */
7954
0
                            if (H5S__hyper_append_span(b_not_a, ndims, span_a->low, span_b->high,
7955
0
                                                       down_b_not_a) < 0)
7956
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
7957
0
                                            "can't allocate hyperslab span");
7958
7959
                            /* Release the down span tree generated */
7960
0
                            if (H5S__hyper_free_span_info(down_b_not_a) < 0)
7961
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
7962
0
                        }
7963
0
                    } /* end else */
7964
7965
                    /* Split off upper part of span 'a' at upper span of span 'b' */
7966
7967
                    /* Allocate new span node for upper part of span 'a' */
7968
0
                    if (NULL == (tmp_span = H5S__hyper_new_span(span_b->high + 1, span_a->high, span_a->down,
7969
0
                                                                span_a->next)))
7970
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span");
7971
7972
                    /* Make upper part of span 'a' into new span 'a' */
7973
0
                    H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, tmp_span, FAIL);
7974
0
                    recover_a = true;
7975
7976
                    /* Advance span 'b' */
7977
0
                    H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, FAIL);
7978
0
                } /* end if */
7979
                /* span 'a' must be entirely above span 'b' */
7980
                /*                         AAAAA         */
7981
                /* <-----------------------------------> */
7982
                /*             BBBBBBBBBB                */
7983
0
                else {
7984
                    /* Copy span 'b' and add to b_not_a list */
7985
7986
                    /* Merge/add span 'b' with/to b_not_a list */
7987
0
                    if (need_b_not_a)
7988
0
                        if (H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_b->high, span_b->down) <
7989
0
                            0)
7990
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
7991
7992
                    /* Advance span 'b', leave span 'a' */
7993
0
                    H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, FAIL);
7994
0
                } /* end else */
7995
0
            }     /* end while */
7996
7997
            /* Clean up 'a' spans which haven't been covered yet */
7998
0
            if (span_a != NULL && span_b == NULL) {
7999
                /* Check if need to merge/add 'a' spans with/to a_not_b list */
8000
0
                if (need_a_not_b) {
8001
                    /* (This loop, and the similar one below for 'b' spans,
8002
                     *  could be replaced with an optimized routine that quickly
8003
                     *  appended the remaining spans to the 'not' list, but
8004
                     *  until it looks like it's taking a lot of time for an
8005
                     *  important use case, it's been left generic, and similar
8006
                     *  to other code above. -QAK, 2019/02/01)
8007
                     */
8008
0
                    while (span_a != NULL) {
8009
                        /* Copy span 'a' and add to a_not_b list */
8010
0
                        if (H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_a->high, span_a->down) <
8011
0
                            0)
8012
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
8013
8014
                        /* Advance to the next 'a' span */
8015
0
                        H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, FAIL);
8016
0
                    } /* end while */
8017
0
                }     /* end if */
8018
0
                else {
8019
                    /* Free the span, if it's generated */
8020
0
                    if (recover_a)
8021
0
                        if (H5S__hyper_free_span(span_a) < 0)
8022
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span");
8023
0
                } /* end else */
8024
0
            }     /* end if */
8025
            /* Clean up 'b' spans which haven't been covered yet */
8026
0
            else if (span_a == NULL && span_b != NULL) {
8027
                /* Check if need to merge/add 'b' spans with/to b_not_a list */
8028
0
                if (need_b_not_a) {
8029
                    /* (This loop, and the similar one above for 'a' spans,
8030
                     *  could be replaced with an optimized routine that quickly
8031
                     *  appended the remaining spans to the 'not' list, but
8032
                     *  until it looks like it's taking a lot of time for an
8033
                     *  important use case, it's been left generic, and similar
8034
                     *  to other code above. -QAK, 2019/02/01)
8035
                     */
8036
0
                    while (span_b != NULL) {
8037
                        /* Copy span 'b' and add to b_not_a list */
8038
0
                        if (H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_b->high, span_b->down) <
8039
0
                            0)
8040
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
8041
8042
                        /* Advance to the next 'b' span */
8043
0
                        H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, FAIL);
8044
0
                    } /* end while */
8045
0
                }     /* end if */
8046
0
                else {
8047
                    /* Free the span, if it's generated */
8048
0
                    if (recover_b)
8049
0
                        if (H5S__hyper_free_span(span_b) < 0)
8050
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span");
8051
0
                } /* end else */
8052
0
            }     /* end if */
8053
0
            else
8054
                /* Sanity check */
8055
0
                assert(span_a == NULL && span_b == NULL);
8056
0
        } /* end else */
8057
0
    }     /* end else */
8058
8059
0
done:
8060
0
    FUNC_LEAVE_NOAPI(ret_value)
8061
0
} /* end H5S__hyper_clip_spans() */
8062
8063
/*--------------------------------------------------------------------------
8064
 NAME
8065
    H5S__hyper_merge_spans_helper
8066
 PURPOSE
8067
    Merge two hyperslab span tree together
8068
 USAGE
8069
    H5S_hyper_span_info_t *H5S__hyper_merge_spans_helper(a_spans, b_spans)
8070
        H5S_hyper_span_info_t *a_spans; IN: First hyperslab spans to merge
8071
                                                together
8072
        H5S_hyper_span_info_t *b_spans; IN: Second hyperslab spans to merge
8073
                                                together
8074
        unsigned ndims;                 IN: Number of dimensions of this span tree
8075
 RETURNS
8076
    Pointer to span tree containing the merged spans on success, NULL on failure
8077
 DESCRIPTION
8078
    Merge two sets of hyperslab spans together and return the span tree from
8079
    the merged set.
8080
 GLOBAL VARIABLES
8081
 COMMENTS, BUGS, ASSUMPTIONS
8082
    Handles merging span trees that overlap.
8083
 EXAMPLES
8084
 REVISION LOG
8085
--------------------------------------------------------------------------*/
8086
static H5S_hyper_span_info_t *
8087
H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_spans, unsigned ndims)
8088
0
{
8089
0
    H5S_hyper_span_info_t *merged_spans = NULL; /* Pointer to the merged span tree */
8090
0
    H5S_hyper_span_info_t *ret_value    = NULL; /* Return value */
8091
8092
0
    FUNC_ENTER_PACKAGE
8093
8094
    /* Make certain both 'a' & 'b' spans have down span trees or neither does */
8095
0
    assert((a_spans != NULL && b_spans != NULL) || (a_spans == NULL && b_spans == NULL));
8096
8097
    /* Check if the span trees for the 'a' span and the 'b' span are the same */
8098
0
    if (H5S__hyper_cmp_spans(a_spans, b_spans)) {
8099
0
        if (a_spans == NULL)
8100
0
            merged_spans = NULL;
8101
0
        else {
8102
            /* Copy one of the span trees to return */
8103
0
            if (NULL == (merged_spans = H5S__hyper_copy_span(a_spans, ndims)))
8104
0
                HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, NULL, "can't copy hyperslab span tree");
8105
0
        } /* end else */
8106
0
    }     /* end if */
8107
0
    else {
8108
0
        H5S_hyper_span_t *span_a;               /* Pointer to current span 'a' working on */
8109
0
        H5S_hyper_span_t *span_b;               /* Pointer to current span 'b' working on */
8110
0
        bool              recover_a, recover_b; /* Flags to indicate when to recover temporary spans */
8111
8112
        /* Get the pointers to the 'a' and 'b' span lists */
8113
0
        span_a = a_spans->head;
8114
0
        span_b = b_spans->head;
8115
8116
        /* No spans to recover yet */
8117
0
        recover_a = recover_b = false;
8118
8119
        /* Work through the list of spans in the new list */
8120
0
        while (span_a != NULL && span_b != NULL) {
8121
0
            H5S_hyper_span_info_t *tmp_spans; /* Pointer to temporary new span tree */
8122
0
            H5S_hyper_span_t      *tmp_span;  /* Pointer to temporary new span */
8123
8124
            /* Check if the 'a' span is completely before 'b' span */
8125
            /*    AAAAAAA                            */
8126
            /* <-----------------------------------> */
8127
            /*             BBBBBBBBBB                */
8128
0
            if (span_a->high < span_b->low) {
8129
                /* Merge/add span 'a' with/to the merged spans */
8130
0
                if (H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_a->high, span_a->down) < 0)
8131
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8132
8133
                /* Advance span 'a' */
8134
0
                H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, NULL);
8135
0
            } /* end if */
8136
            /* Check if span 'a' overlaps only the lower bound */
8137
            /*  of span 'b', up to the upper bound of span 'b' */
8138
            /*    AAAAAAAAAAAA                       */
8139
            /* <-----------------------------------> */
8140
            /*             BBBBBBBBBB                */
8141
0
            else if (span_a->low < span_b->low &&
8142
0
                     (span_a->high >= span_b->low && span_a->high <= span_b->high)) {
8143
                /* Check if span 'a' and span 'b' down spans are equal */
8144
0
                if (H5S__hyper_cmp_spans(span_a->down, span_b->down)) {
8145
                    /* Merge/add copy of span 'a' with/to merged spans */
8146
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_a->high,
8147
0
                                               span_a->down) < 0)
8148
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8149
0
                }
8150
0
                else {
8151
                    /* Merge/add lower part of span 'a' with/to merged spans */
8152
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_b->low - 1,
8153
0
                                               span_a->down) < 0)
8154
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8155
8156
                    /* Get merged span tree for overlapped section */
8157
0
                    tmp_spans = H5S__hyper_merge_spans_helper(span_a->down, span_b->down, ndims - 1);
8158
8159
                    /* Merge/add overlapped section to merged spans */
8160
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_a->high, tmp_spans) <
8161
0
                        0)
8162
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8163
8164
                    /* Release merged span tree for overlapped section */
8165
0
                    if (H5S__hyper_free_span_info(tmp_spans) < 0)
8166
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, NULL, "unable to free span info");
8167
0
                }
8168
8169
                /* Check if there is an upper part of span 'b' */
8170
0
                if (span_a->high < span_b->high) {
8171
                    /* Copy upper part of span 'b' as new span 'b' */
8172
8173
                    /* Allocate new span node to append to list */
8174
0
                    if (NULL == (tmp_span = H5S__hyper_new_span(span_a->high + 1, span_b->high, span_b->down,
8175
0
                                                                span_b->next)))
8176
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
8177
8178
                    /* Advance span 'a' */
8179
0
                    H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, NULL);
8180
8181
                    /* Set new span 'b' to tmp_span */
8182
0
                    H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, tmp_span, NULL);
8183
0
                    recover_b = true;
8184
0
                } /* end if */
8185
0
                else {
8186
                    /* Advance both span 'a' & 'b' */
8187
0
                    H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, NULL);
8188
0
                    H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, NULL);
8189
0
                } /* end else */
8190
0
            }     /* end if */
8191
            /* Check if span 'a' overlaps the lower & upper bound */
8192
            /*  of span 'b' */
8193
            /*    AAAAAAAAAAAAAAAAAAAAA              */
8194
            /* <-----------------------------------> */
8195
            /*             BBBBBBBBBB                */
8196
0
            else if (span_a->low < span_b->low && span_a->high > span_b->high) {
8197
                /* Check if span 'a' and span 'b' down spans are equal */
8198
0
                if (H5S__hyper_cmp_spans(span_a->down, span_b->down)) {
8199
                    /* Merge/add copy of lower & middle parts of span 'a' to merged spans */
8200
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_b->high,
8201
0
                                               span_a->down) < 0)
8202
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8203
0
                }
8204
0
                else {
8205
                    /* Merge/add lower part of span 'a' to merged spans */
8206
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_b->low - 1,
8207
0
                                               span_a->down) < 0)
8208
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8209
8210
                    /* Get merged span tree for overlapped section */
8211
0
                    tmp_spans = H5S__hyper_merge_spans_helper(span_a->down, span_b->down, ndims - 1);
8212
8213
                    /* Merge/add overlapped section to merged spans */
8214
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_b->high, tmp_spans) <
8215
0
                        0)
8216
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8217
8218
                    /* Release merged span tree for overlapped section */
8219
0
                    if (H5S__hyper_free_span_info(tmp_spans) < 0)
8220
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, NULL, "unable to free span info");
8221
0
                }
8222
8223
                /* Copy upper part of span 'a' as new span 'a' (remember to free) */
8224
8225
                /* Allocate new span node to append to list */
8226
0
                if (NULL == (tmp_span = H5S__hyper_new_span(span_b->high + 1, span_a->high, span_a->down,
8227
0
                                                            span_a->next)))
8228
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
8229
8230
                /* Set new span 'a' to tmp_span */
8231
0
                H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, tmp_span, NULL);
8232
0
                recover_a = true;
8233
8234
                /* Advance span 'b' */
8235
0
                H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, NULL);
8236
0
            } /* end if */
8237
            /* Check if span 'a' is entirely within span 'b' */
8238
            /*                AAAAA                  */
8239
            /* <-----------------------------------> */
8240
            /*             BBBBBBBBBB                */
8241
0
            else if (span_a->low >= span_b->low && span_a->high <= span_b->high) {
8242
                /* Check if span 'a' and span 'b' down spans are equal */
8243
0
                if (H5S__hyper_cmp_spans(span_a->down, span_b->down)) {
8244
                    /* Merge/add copy of lower & middle parts of span 'b' to merged spans */
8245
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_a->high,
8246
0
                                               span_a->down) < 0)
8247
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8248
0
                }
8249
0
                else {
8250
                    /* Check if there is a lower part of span 'b' */
8251
0
                    if (span_a->low > span_b->low) {
8252
                        /* Merge/add lower part of span 'b' to merged spans */
8253
0
                        if (H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_a->low - 1,
8254
0
                                                   span_b->down) < 0)
8255
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8256
0
                    } /* end if */
8257
0
                    else {
8258
                        /* No lower part of span 'b' , keep going... */
8259
0
                    } /* end else */
8260
8261
                    /* Get merged span tree for overlapped section */
8262
0
                    tmp_spans = H5S__hyper_merge_spans_helper(span_a->down, span_b->down, ndims - 1);
8263
8264
                    /* Merge/add overlapped section to merged spans */
8265
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_a->high, tmp_spans) <
8266
0
                        0)
8267
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8268
8269
                    /* Release merged span tree for overlapped section */
8270
0
                    if (H5S__hyper_free_span_info(tmp_spans) < 0)
8271
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, NULL, "unable to free span info");
8272
0
                }
8273
8274
                /* Check if there is an upper part of span 'b' */
8275
0
                if (span_a->high < span_b->high) {
8276
                    /* Copy upper part of span 'b' as new span 'b' (remember to free) */
8277
8278
                    /* Allocate new span node to append to list */
8279
0
                    if (NULL == (tmp_span = H5S__hyper_new_span(span_a->high + 1, span_b->high, span_b->down,
8280
0
                                                                span_b->next)))
8281
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
8282
8283
                    /* Advance span 'a' */
8284
0
                    H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, NULL);
8285
8286
                    /* Set new span 'b' to tmp_span */
8287
0
                    H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, tmp_span, NULL);
8288
0
                    recover_b = true;
8289
0
                } /* end if */
8290
0
                else {
8291
                    /* Advance both spans */
8292
0
                    H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, NULL);
8293
0
                    H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, NULL);
8294
0
                } /* end else */
8295
0
            }     /* end if */
8296
            /* Check if span 'a' overlaps only the upper bound */
8297
            /*  of span 'b' */
8298
            /*                AAAAAAAAAA             */
8299
            /* <-----------------------------------> */
8300
            /*             BBBBBBBBBB                */
8301
0
            else if ((span_a->low >= span_b->low && span_a->low <= span_b->high) &&
8302
0
                     span_a->high > span_b->high) {
8303
                /* Check if span 'a' and span 'b' down spans are equal */
8304
0
                if (H5S__hyper_cmp_spans(span_a->down, span_b->down)) {
8305
                    /* Merge/add copy of span 'b' to merged spans if so */
8306
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_b->high,
8307
0
                                               span_b->down) < 0)
8308
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8309
0
                }
8310
0
                else {
8311
                    /* Check if there is a lower part of span 'b' */
8312
0
                    if (span_a->low > span_b->low) {
8313
                        /* Merge/add lower part of span 'b' to merged spans */
8314
0
                        if (H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_a->low - 1,
8315
0
                                                   span_b->down) < 0)
8316
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8317
0
                    } /* end if */
8318
0
                    else {
8319
                        /* No lower part of span 'b' , keep going... */
8320
0
                    } /* end else */
8321
8322
                    /* Get merged span tree for overlapped section */
8323
0
                    tmp_spans = H5S__hyper_merge_spans_helper(span_a->down, span_b->down, ndims - 1);
8324
8325
                    /* Merge/add overlapped section to merged spans */
8326
0
                    if (H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_b->high, tmp_spans) <
8327
0
                        0)
8328
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8329
8330
                    /* Release merged span tree for overlapped section */
8331
0
                    if (H5S__hyper_free_span_info(tmp_spans) < 0)
8332
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, NULL, "unable to free span info");
8333
0
                }
8334
8335
                /* Copy upper part of span 'a' as new span 'a' */
8336
8337
                /* Allocate new span node to append to list */
8338
0
                if (NULL == (tmp_span = H5S__hyper_new_span(span_b->high + 1, span_a->high, span_a->down,
8339
0
                                                            span_a->next)))
8340
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
8341
8342
                /* Set new span 'a' to tmp_span */
8343
0
                H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, tmp_span, NULL);
8344
0
                recover_a = true;
8345
8346
                /* Advance span 'b' */
8347
0
                H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, NULL);
8348
0
            } /* end if */
8349
            /* Span 'a' must be entirely above span 'b' */
8350
            /*                         AAAAA         */
8351
            /* <-----------------------------------> */
8352
            /*             BBBBBBBBBB                */
8353
0
            else {
8354
                /* Merge/add span 'b' with the merged spans */
8355
0
                if (H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_b->high, span_b->down) < 0)
8356
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8357
8358
                /* Advance span 'b' */
8359
0
                H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, NULL);
8360
0
            } /* end else */
8361
0
        }     /* end while */
8362
8363
        /* Clean up 'a' spans which haven't been added to the list of merged spans */
8364
0
        if (span_a != NULL && span_b == NULL) {
8365
0
            while (span_a != NULL) {
8366
                /* Merge/add all 'a' spans into the merged spans */
8367
0
                if (H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_a->high, span_a->down) < 0)
8368
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8369
8370
                /* Advance to next 'a' span, until all processed */
8371
0
                H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next, NULL);
8372
0
            } /* end while */
8373
0
        }     /* end if */
8374
8375
        /* Clean up 'b' spans which haven't been added to the list of merged spans */
8376
0
        if (span_a == NULL && span_b != NULL) {
8377
0
            while (span_b != NULL) {
8378
                /* Merge/add all 'b' spans into the merged spans */
8379
0
                if (H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_b->high, span_b->down) < 0)
8380
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span");
8381
8382
                /* Advance to next 'b' span, until all processed */
8383
0
                H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next, NULL);
8384
0
            } /* end while */
8385
0
        }     /* end if */
8386
0
    }         /* end else */
8387
8388
    /* Set return value */
8389
0
    ret_value = merged_spans;
8390
8391
0
done:
8392
0
    if (ret_value == NULL)
8393
0
        if (merged_spans)
8394
0
            if (H5S__hyper_free_span_info(merged_spans) < 0)
8395
0
                HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, NULL, "unable to free span info");
8396
8397
0
    FUNC_LEAVE_NOAPI(ret_value)
8398
0
} /* end H5S__hyper_merge_spans_helper() */
8399
8400
/*--------------------------------------------------------------------------
8401
 NAME
8402
    H5S__hyper_merge_spans
8403
 PURPOSE
8404
    Merge new hyperslab spans to existing hyperslab selection
8405
 USAGE
8406
    herr_t H5S__hyper_merge_spans(space, new_spans, can_own)
8407
        H5S_t *space;             IN: Dataspace to add new spans to hyperslab
8408
                                        selection.
8409
        H5S_hyper_span_t *new_spans;    IN: Span tree of new spans to add to
8410
                                            hyperslab selection
8411
 RETURNS
8412
    non-negative on success, negative on failure
8413
 DESCRIPTION
8414
    Add a set of hyperslab spans to an existing hyperslab selection.
8415
 GLOBAL VARIABLES
8416
 COMMENTS, BUGS, ASSUMPTIONS
8417
 EXAMPLES
8418
 REVISION LOG
8419
--------------------------------------------------------------------------*/
8420
static herr_t
8421
H5S__hyper_merge_spans(H5S_t *space, H5S_hyper_span_info_t *new_spans)
8422
0
{
8423
0
    herr_t ret_value = SUCCEED; /* Return value */
8424
8425
0
    FUNC_ENTER_PACKAGE
8426
8427
    /* Sanity checks */
8428
0
    assert(space);
8429
0
    assert(new_spans);
8430
8431
    /* If this is the first span tree in the hyperslab selection, just use it */
8432
0
    if (space->select.sel_info.hslab->span_lst == NULL) {
8433
0
        space->select.sel_info.hslab->span_lst = new_spans;
8434
0
        space->select.sel_info.hslab->span_lst->count++;
8435
0
    } /* end if */
8436
0
    else {
8437
0
        H5S_hyper_span_info_t *merged_spans;
8438
8439
        /* Get the merged spans */
8440
0
        if (NULL == (merged_spans = H5S__hyper_merge_spans_helper(space->select.sel_info.hslab->span_lst,
8441
0
                                                                  new_spans, space->extent.rank)))
8442
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTMERGE, FAIL, "can't merge hyperslab spans");
8443
8444
        /* Free the previous spans */
8445
0
        if (H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst) < 0)
8446
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
8447
8448
        /* Point to the new merged spans */
8449
0
        space->select.sel_info.hslab->span_lst = merged_spans;
8450
0
    } /* end else */
8451
8452
0
done:
8453
0
    FUNC_LEAVE_NOAPI(ret_value)
8454
0
} /* end H5S__hyper_merge_spans() */
8455
8456
/*--------------------------------------------------------------------------
8457
 NAME
8458
    H5S__hyper_spans_nelem_helper
8459
 PURPOSE
8460
    Count the number of elements in a span tree
8461
 USAGE
8462
    hsize_t H5S__hyper_spans_nelem_helper(spans, op_info_i, op_gen)
8463
        const H5S_hyper_span_info_t *spans; IN: Hyperslan span tree to count elements of
8464
        unsigned op_info_i;             IN: Index of op info to use
8465
        uint64_t op_gen;                IN: Operation generation
8466
 RETURNS
8467
    Number of elements in span tree on success; negative on failure
8468
 DESCRIPTION
8469
    Counts the number of elements described by the spans in a span tree.
8470
 GLOBAL VARIABLES
8471
 COMMENTS, BUGS, ASSUMPTIONS
8472
 EXAMPLES
8473
 REVISION LOG
8474
--------------------------------------------------------------------------*/
8475
static hsize_t
8476
H5S__hyper_spans_nelem_helper(H5S_hyper_span_info_t *spans, unsigned op_info_i, uint64_t op_gen)
8477
0
{
8478
0
    hsize_t ret_value = 0; /* Return value */
8479
8480
0
    FUNC_ENTER_PACKAGE_NOERR
8481
8482
    /* Sanity check */
8483
0
    assert(spans);
8484
8485
    /* Check if the span tree was already counted */
8486
0
    if (spans->op_info[op_info_i].op_gen == op_gen)
8487
        /* Just return the # of elements in the already counted span tree */
8488
0
        ret_value = spans->op_info[op_info_i].u.nelmts;
8489
0
    else {                            /* Count the number of elements in the span tree */
8490
0
        const H5S_hyper_span_t *span; /* Hyperslab span */
8491
8492
0
        span = spans->head;
8493
0
        if (NULL == span->down) {
8494
0
            while (span != NULL) {
8495
                /* Compute # of elements covered */
8496
0
                ret_value += (span->high - span->low) + 1;
8497
8498
                /* Advance to next span */
8499
0
                span = span->next;
8500
0
            } /* end while */
8501
0
        }     /* end if */
8502
0
        else {
8503
0
            while (span != NULL) {
8504
0
                hsize_t nelmts; /* # of elements covered by current span */
8505
8506
                /* Compute # of elements covered */
8507
0
                nelmts = (span->high - span->low) + 1;
8508
8509
                /* Multiply the size of this span by the total down span elements */
8510
0
                ret_value += nelmts * H5S__hyper_spans_nelem_helper(span->down, op_info_i, op_gen);
8511
8512
                /* Advance to next span */
8513
0
                span = span->next;
8514
0
            } /* end while */
8515
0
        }     /* end else */
8516
8517
        /* Set the operation generation for this span tree, to avoid re-computing */
8518
0
        spans->op_info[op_info_i].op_gen = op_gen;
8519
8520
        /* Hold a copy of the # of elements */
8521
0
        spans->op_info[op_info_i].u.nelmts = ret_value;
8522
0
    } /* end else */
8523
8524
0
    FUNC_LEAVE_NOAPI(ret_value)
8525
0
} /* end H5S__hyper_spans_nelem_helper() */
8526
8527
/*--------------------------------------------------------------------------
8528
 NAME
8529
    H5S__hyper_spans_nelem
8530
 PURPOSE
8531
    Count the number of elements in a span tree
8532
 USAGE
8533
    hsize_t H5S__hyper_spans_nelem(spans)
8534
        const H5S_hyper_span_info_t *spans; IN: Hyperslan span tree to count elements of
8535
 RETURNS
8536
    Number of elements in span tree on success; negative on failure
8537
 DESCRIPTION
8538
    Counts the number of elements described by the spans in a span tree.
8539
 GLOBAL VARIABLES
8540
 COMMENTS, BUGS, ASSUMPTIONS
8541
 EXAMPLES
8542
 REVISION LOG
8543
--------------------------------------------------------------------------*/
8544
static hsize_t
8545
H5S__hyper_spans_nelem(H5S_hyper_span_info_t *spans)
8546
0
{
8547
0
    uint64_t op_gen;        /* Operation generation value */
8548
0
    hsize_t  ret_value = 0; /* Return value */
8549
8550
0
    FUNC_ENTER_PACKAGE_NOERR
8551
8552
    /* Sanity check */
8553
0
    assert(spans);
8554
8555
    /* Acquire an operation generation value for this operation */
8556
0
    op_gen = H5S__hyper_get_op_gen();
8557
8558
    /* Count the number of elements in the span tree */
8559
    /* Always use op_info[0] since we own this op_info, so there can be no
8560
     * simultaneous operations */
8561
0
    ret_value = H5S__hyper_spans_nelem_helper(spans, 0, op_gen);
8562
8563
0
    FUNC_LEAVE_NOAPI(ret_value)
8564
0
} /* end H5S__hyper_spans_nelem() */
8565
8566
/*--------------------------------------------------------------------------
8567
 NAME
8568
    H5S__hyper_add_disjoint_spans
8569
 PURPOSE
8570
    Add new hyperslab spans to existing hyperslab selection in the case the
8571
    new hyperslab spans don't overlap with the existing hyperslab selection
8572
 USAGE
8573
    herr_t H5S__hyper_add_disjoint_spans(space, new_spans)
8574
        H5S_t *space;             IN: Dataspace to add new spans to hyperslab
8575
                                        selection.
8576
        H5S_hyper_span_t *new_spans;    IN: Span tree of new spans to add to
8577
                                            hyperslab selection
8578
 RETURNS
8579
    Non-negative on success, negative on failure
8580
 DESCRIPTION
8581
    Add a set of hyperslab spans to an existing hyperslab selection.  The
8582
    new spans are required not to overlap with the existing spans in the
8583
    dataspace's current hyperslab selection in terms of bound box.
8584
 GLOBAL VARIABLES
8585
 COMMENTS, BUGS, ASSUMPTIONS
8586
 EXAMPLES
8587
 REVISION LOG
8588
--------------------------------------------------------------------------*/
8589
static herr_t
8590
H5S__hyper_add_disjoint_spans(H5S_t *space, H5S_hyper_span_info_t *new_spans)
8591
0
{
8592
0
    herr_t ret_value = SUCCEED; /* Return value */
8593
8594
0
    FUNC_ENTER_PACKAGE
8595
8596
    /* Check args */
8597
0
    assert(space);
8598
0
    assert(new_spans);
8599
8600
    /* Update the number of elements in the selection */
8601
0
    space->select.num_elem += H5S__hyper_spans_nelem(new_spans);
8602
8603
    /* Add the new spans to the existing selection in the dataspace */
8604
0
    if (H5S__hyper_merge_spans(space, new_spans) < 0)
8605
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't merge hyperslabs");
8606
8607
    /* Free the memory space for new spans */
8608
0
    if (H5S__hyper_free_span_info(new_spans) < 0)
8609
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
8610
8611
0
done:
8612
0
    FUNC_LEAVE_NOAPI(ret_value)
8613
0
} /* end H5S__hyper_add_disjoint_spans */
8614
8615
/*--------------------------------------------------------------------------
8616
 NAME
8617
    H5S__hyper_make_spans
8618
 PURPOSE
8619
    Create a span tree
8620
 USAGE
8621
    H5S_hyper_span_t *H5S__hyper_make_spans(rank, start, stride, count, block)
8622
        unsigned rank;          IN: # of dimensions of the space
8623
        const hsize_t *start;   IN: Starting location of the hyperslabs
8624
        const hsize_t *stride;  IN: Stride from the beginning of one block to
8625
                                        the next
8626
        const hsize_t *count;   IN: Number of blocks
8627
        const hsize_t *block;   IN: Size of hyperslab block
8628
 RETURNS
8629
    Pointer to new span tree on success, NULL on failure
8630
 DESCRIPTION
8631
    Generates a new span tree for the hyperslab parameters specified.
8632
    Each span tree has a list of the elements spanned in each dimension, with
8633
    each span node containing a pointer to the list of spans in the next
8634
    dimension down.
8635
 GLOBAL VARIABLES
8636
 COMMENTS, BUGS, ASSUMPTIONS
8637
 EXAMPLES
8638
 REVISION LOG
8639
--------------------------------------------------------------------------*/
8640
static H5S_hyper_span_info_t *
8641
H5S__hyper_make_spans(unsigned rank, const hsize_t *start, const hsize_t *stride, const hsize_t *count,
8642
                      const hsize_t *block)
8643
0
{
8644
0
    H5S_hyper_span_info_t *down = NULL;      /* Pointer to spans in next dimension down */
8645
0
    H5S_hyper_span_t      *last_span;        /* Current position in hyperslab span list */
8646
0
    H5S_hyper_span_t      *head = NULL;      /* Head of new hyperslab span list */
8647
0
    int                    i;                /* Counters */
8648
0
    H5S_hyper_span_info_t *ret_value = NULL; /* Return value */
8649
8650
0
    FUNC_ENTER_PACKAGE
8651
8652
    /* Check args */
8653
0
    assert(start);
8654
0
    assert(stride);
8655
0
    assert(count);
8656
0
    assert(block);
8657
8658
0
    if (rank == 0)
8659
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, NULL, "dataspace has invalid extent");
8660
8661
    /* Start creating spans in fastest changing dimension */
8662
0
    for (i = (int)(rank - 1); i >= 0; i--) {
8663
0
        hsize_t  curr_low, curr_high; /* Current low & high values */
8664
0
        hsize_t  dim_stride;          /* Current dim's stride */
8665
0
        unsigned u;                   /* Local index variable */
8666
8667
        /* Sanity check */
8668
0
        if (0 == count[i])
8669
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, NULL, "count == 0 is invalid");
8670
8671
        /* Start a new list in this dimension */
8672
0
        head      = NULL;
8673
0
        last_span = NULL;
8674
8675
        /* Generate all the span segments for this dimension */
8676
0
        curr_low   = start[i];
8677
0
        curr_high  = start[i] + (block[i] - 1);
8678
0
        dim_stride = stride[i];
8679
0
        for (u = 0; u < count[i]; u++, curr_low += dim_stride, curr_high += dim_stride) {
8680
0
            H5S_hyper_span_t *span; /* New hyperslab span */
8681
8682
            /* Allocate a span node */
8683
0
            if (NULL == (span = H5FL_MALLOC(H5S_hyper_span_t)))
8684
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
8685
8686
            /* Set the span's basic information */
8687
0
            span->low  = curr_low;
8688
0
            span->high = curr_high;
8689
0
            span->next = NULL;
8690
8691
            /* Set the information for the next dimension down's spans */
8692
            /* (Will be NULL for fastest changing dimension) */
8693
0
            span->down = down;
8694
8695
            /* Append to the list of spans in this dimension */
8696
0
            if (head == NULL)
8697
0
                head = span;
8698
0
            else
8699
0
                last_span->next = span;
8700
8701
            /* Move current pointer */
8702
0
            last_span = span;
8703
0
        } /* end for */
8704
8705
        /* Increment ref. count of shared span */
8706
0
        if (down != NULL)
8707
0
            down->count = (unsigned)count[i];
8708
8709
        /* Allocate a span info node */
8710
0
        if (NULL == (down = H5S__hyper_new_span_info(rank)))
8711
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span");
8712
8713
        /* Keep the pointer to the next dimension down's completed list */
8714
0
        down->head = head;
8715
8716
        /* Keep the tail pointer to the next dimension down's completed list */
8717
0
        down->tail = last_span;
8718
8719
        /* Set the low & high bounds for this dimension */
8720
0
        down->low_bounds[0]  = down->head->low;
8721
0
        down->high_bounds[0] = down->tail->high;
8722
8723
        /* Copy bounds from lower dimensions */
8724
        /* (head & tail pointers share lower dimensions, so using either is OK) */
8725
0
        if (head->down) {
8726
0
            H5MM_memcpy(&down->low_bounds[1], &head->down->low_bounds[0],
8727
0
                        sizeof(hsize_t) * ((rank - 1) - (unsigned)i));
8728
0
            H5MM_memcpy(&down->high_bounds[1], &head->down->high_bounds[0],
8729
0
                        sizeof(hsize_t) * ((rank - 1) - (unsigned)i));
8730
0
        } /* end if */
8731
0
    }     /* end for */
8732
8733
    /* Indicate that there is a pointer to this tree */
8734
0
    if (down)
8735
0
        down->count = 1;
8736
8737
    /* Success!  Return the head of the list in the slowest changing dimension */
8738
0
    ret_value = down;
8739
8740
0
done:
8741
    /* cleanup if error (ret_value will be NULL) */
8742
0
    if (!ret_value) {
8743
0
        if (head || down) {
8744
0
            if (head && down)
8745
0
                if (down->head != head)
8746
0
                    down = NULL;
8747
8748
0
            do {
8749
0
                if (down) {
8750
0
                    head = down->head;
8751
0
                    down = (H5S_hyper_span_info_t *)H5FL_ARR_FREE(hbounds_t, down);
8752
0
                } /* end if */
8753
0
                down = head->down;
8754
8755
0
                while (head) {
8756
0
                    last_span = head->next;
8757
0
                    head      = H5FL_FREE(H5S_hyper_span_t, head);
8758
0
                    head      = last_span;
8759
0
                } /* end while */
8760
0
            } while (down);
8761
0
        } /* end if */
8762
0
    }     /* end if */
8763
8764
0
    FUNC_LEAVE_NOAPI(ret_value)
8765
0
} /* end H5S__hyper_make_spans() */
8766
8767
/*--------------------------------------------------------------------------
8768
 NAME
8769
    H5S__hyper_update_diminfo
8770
 PURPOSE
8771
    Attempt to update optimized hyperslab information quickly.  (It can be
8772
    recovered with regular selection).  If this algorithm cannot determine
8773
    the optimized dimension info quickly, this function will simply mark it
8774
    as invalid and unknown if it can be built (H5S_DIMINFO_VALID_NO), so
8775
    H5S__hyper_rebuild can be run later to determine for sure.
8776
 USAGE
8777
    herr_t H5S__hyper_update_diminfo(space, op, new_hyper_diminfo)
8778
        H5S_t *space;       IN: Dataspace to check
8779
        H5S_seloper_t op;   IN: The operation being performed on the
8780
                                selection
8781
        const H5S_hyper_dim_t new_hyper_diminfo; IN: The new selection that
8782
                                                     is being combined with
8783
                                                     the current
8784
 RETURNS
8785
    >=0 on success, <0 on failure
8786
 DESCRIPTION
8787
    Examine the span tree for a hyperslab selection and rebuild
8788
    the start/stride/count/block information for the selection, if possible.
8789
8790
 GLOBAL VARIABLES
8791
 COMMENTS, BUGS, ASSUMPTIONS
8792
 EXAMPLES
8793
 REVISION LOG
8794
--------------------------------------------------------------------------*/
8795
static herr_t
8796
H5S__hyper_update_diminfo(H5S_t *space, H5S_seloper_t op, const H5S_hyper_dim_t *new_hyper_diminfo)
8797
0
{
8798
0
    herr_t ret_value = SUCCEED; /* Return value */
8799
8800
0
    FUNC_ENTER_PACKAGE_NOERR
8801
8802
    /* Check args */
8803
0
    assert(space);
8804
0
    assert(new_hyper_diminfo);
8805
8806
    /* Check for conditions that prevent us from using the fast algorithm here */
8807
    /* (and instead require H5S__hyper_rebuild) */
8808
0
    if (!((op == H5S_SELECT_OR) || (op == H5S_SELECT_XOR)) ||
8809
0
        space->select.sel_info.hslab->diminfo_valid != H5S_DIMINFO_VALID_YES ||
8810
0
        !space->select.sel_info.hslab->span_lst->head)
8811
0
        space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
8812
0
    else {
8813
0
        H5S_hyper_dim_t tmp_diminfo[H5S_MAX_RANK]; /* Temporary dimension info */
8814
0
        bool            found_nonidentical_dim = false;
8815
0
        unsigned        curr_dim;
8816
8817
        /* Copy current diminfo.opt values */
8818
0
        H5MM_memcpy(tmp_diminfo, space->select.sel_info.hslab->diminfo.opt, sizeof(tmp_diminfo));
8819
8820
        /* Loop over dimensions */
8821
0
        for (curr_dim = 0; curr_dim < space->extent.rank; curr_dim++) {
8822
            /* Check for this being identical */
8823
0
            if ((tmp_diminfo[curr_dim].start != new_hyper_diminfo[curr_dim].start) ||
8824
0
                (tmp_diminfo[curr_dim].stride != new_hyper_diminfo[curr_dim].stride) ||
8825
0
                (tmp_diminfo[curr_dim].count != new_hyper_diminfo[curr_dim].count) ||
8826
0
                (tmp_diminfo[curr_dim].block != new_hyper_diminfo[curr_dim].block)) {
8827
0
                hsize_t high_start, high_count,
8828
0
                    high_block; /* The start, count & block values for the higher block */
8829
8830
                /* Dimension is not identical */
8831
                /* Check if we already found a nonidentical dim - only one is
8832
                 * allowed */
8833
0
                if (found_nonidentical_dim) {
8834
0
                    space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
8835
0
                    break;
8836
0
                } /* end if */
8837
8838
                /* Check that strides are the same, or count is 1 for one of the
8839
                 * slabs */
8840
0
                if ((tmp_diminfo[curr_dim].stride != new_hyper_diminfo[curr_dim].stride) &&
8841
0
                    (tmp_diminfo[curr_dim].count > 1) && (new_hyper_diminfo[curr_dim].count > 1)) {
8842
0
                    space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
8843
0
                    break;
8844
0
                } /* end if */
8845
8846
                /* Patch tmp_diminfo.stride if its count is 1 */
8847
0
                if ((tmp_diminfo[curr_dim].count == 1) && (new_hyper_diminfo[curr_dim].count > 1))
8848
0
                    tmp_diminfo[curr_dim].stride = new_hyper_diminfo[curr_dim].stride;
8849
8850
                /* Determine lowest start, and set tmp_diminfo.start, count and
8851
                 *  block to use the lowest, and high_start, high_count and
8852
                 *  high_block to use the highest
8853
                 */
8854
0
                if (tmp_diminfo[curr_dim].start < new_hyper_diminfo[curr_dim].start) {
8855
0
                    high_start = new_hyper_diminfo[curr_dim].start;
8856
0
                    high_count = new_hyper_diminfo[curr_dim].count;
8857
0
                    high_block = new_hyper_diminfo[curr_dim].block;
8858
0
                } /* end if */
8859
0
                else {
8860
0
                    high_start                  = tmp_diminfo[curr_dim].start;
8861
0
                    tmp_diminfo[curr_dim].start = new_hyper_diminfo[curr_dim].start;
8862
0
                    high_count                  = tmp_diminfo[curr_dim].count;
8863
0
                    tmp_diminfo[curr_dim].count = new_hyper_diminfo[curr_dim].count;
8864
0
                    high_block                  = tmp_diminfo[curr_dim].block;
8865
0
                    tmp_diminfo[curr_dim].block = new_hyper_diminfo[curr_dim].block;
8866
0
                } /* end else */
8867
8868
                /* If count is 1 for both slabs, take different actions */
8869
0
                if ((tmp_diminfo[curr_dim].count == 1) && (high_count == 1)) {
8870
                    /* Check for overlap */
8871
0
                    if ((tmp_diminfo[curr_dim].start + tmp_diminfo[curr_dim].block) > high_start) {
8872
                        /* Check operation type */
8873
0
                        if (op == H5S_SELECT_OR)
8874
                            /* Merge blocks */
8875
0
                            tmp_diminfo[curr_dim].block =
8876
0
                                ((high_start + high_block) >=
8877
0
                                 (tmp_diminfo[curr_dim].start + tmp_diminfo[curr_dim].block))
8878
0
                                    ? (high_start + high_block - tmp_diminfo[curr_dim].start)
8879
0
                                    : tmp_diminfo[curr_dim].block;
8880
0
                        else {
8881
                            /* Block values must be the same */
8882
0
                            if (tmp_diminfo[curr_dim].block != high_block) {
8883
0
                                space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
8884
0
                                break;
8885
0
                            } /* end if */
8886
8887
                            /* XOR - overlap creates 2 blocks */
8888
0
                            tmp_diminfo[curr_dim].stride = high_block;
8889
0
                            tmp_diminfo[curr_dim].count  = 2;
8890
0
                            tmp_diminfo[curr_dim].block  = high_start - tmp_diminfo[curr_dim].start;
8891
0
                        } /* end else */
8892
0
                    }     /* end if */
8893
0
                    else if ((tmp_diminfo[curr_dim].start + tmp_diminfo[curr_dim].block) == high_start)
8894
                        /* Blocks border, merge them */
8895
0
                        tmp_diminfo[curr_dim].block += high_block;
8896
0
                    else {
8897
                        /* Distinct blocks */
8898
                        /* Block values must be the same */
8899
0
                        if (tmp_diminfo[curr_dim].block != high_block) {
8900
0
                            space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
8901
0
                            break;
8902
0
                        } /* end if */
8903
8904
                        /* Create strided selection */
8905
0
                        tmp_diminfo[curr_dim].stride = high_start - tmp_diminfo[curr_dim].start;
8906
0
                        tmp_diminfo[curr_dim].count  = 2;
8907
0
                    } /* end else */
8908
0
                }     /* end if */
8909
0
                else {
8910
                    /* Check if block values are the same */
8911
0
                    if (tmp_diminfo[curr_dim].block != high_block) {
8912
0
                        space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
8913
0
                        break;
8914
0
                    } /* end if */
8915
8916
                    /* Check phase of strides */
8917
0
                    if ((tmp_diminfo[curr_dim].start % tmp_diminfo[curr_dim].stride) !=
8918
0
                        (high_start % tmp_diminfo[curr_dim].stride)) {
8919
0
                        space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
8920
0
                        break;
8921
0
                    } /* end if */
8922
8923
                    /* Check operation type */
8924
0
                    if (op == H5S_SELECT_OR) {
8925
                        /* Make sure the slabs border or overlap */
8926
0
                        if (high_start > (tmp_diminfo[curr_dim].start +
8927
0
                                          (tmp_diminfo[curr_dim].count * tmp_diminfo[curr_dim].stride))) {
8928
0
                            space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
8929
0
                            break;
8930
0
                        } /* end if */
8931
0
                    }     /* end if */
8932
0
                    else
8933
                        /* XOR: Make sure the slabs border */
8934
0
                        if (high_start != (tmp_diminfo[curr_dim].start +
8935
0
                                           (tmp_diminfo[curr_dim].count * tmp_diminfo[curr_dim].stride))) {
8936
0
                            space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
8937
0
                            break;
8938
0
                        } /* end if */
8939
8940
                    /* Set count for combined selection */
8941
0
                    tmp_diminfo[curr_dim].count =
8942
0
                        ((high_start - tmp_diminfo[curr_dim].start) / tmp_diminfo[curr_dim].stride) +
8943
0
                        high_count;
8944
0
                } /* end else */
8945
8946
                /* Indicate that we found a nonidentical dim */
8947
0
                found_nonidentical_dim = true;
8948
0
            } /* end if */
8949
0
        }     /* end for */
8950
8951
        /* Check if we succeeded, if so, set the new diminfo values */
8952
0
        if (space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES)
8953
0
            for (curr_dim = 0; curr_dim < space->extent.rank; curr_dim++) {
8954
0
                hsize_t tmp_high_bound;
8955
8956
                /* Set the new diminfo values */
8957
0
                space->select.sel_info.hslab->diminfo.app[curr_dim].start =
8958
0
                    space->select.sel_info.hslab->diminfo.opt[curr_dim].start = tmp_diminfo[curr_dim].start;
8959
0
                assert(tmp_diminfo[curr_dim].stride > 0);
8960
0
                space->select.sel_info.hslab->diminfo.app[curr_dim].stride =
8961
0
                    space->select.sel_info.hslab->diminfo.opt[curr_dim].stride = tmp_diminfo[curr_dim].stride;
8962
0
                assert(tmp_diminfo[curr_dim].count > 0);
8963
0
                space->select.sel_info.hslab->diminfo.app[curr_dim].count =
8964
0
                    space->select.sel_info.hslab->diminfo.opt[curr_dim].count = tmp_diminfo[curr_dim].count;
8965
0
                assert(tmp_diminfo[curr_dim].block > 0);
8966
0
                space->select.sel_info.hslab->diminfo.app[curr_dim].block =
8967
0
                    space->select.sel_info.hslab->diminfo.opt[curr_dim].block = tmp_diminfo[curr_dim].block;
8968
8969
                /* Check for updating the low & high bounds */
8970
0
                if (tmp_diminfo[curr_dim].start < space->select.sel_info.hslab->diminfo.low_bounds[curr_dim])
8971
0
                    space->select.sel_info.hslab->diminfo.low_bounds[curr_dim] = tmp_diminfo[curr_dim].start;
8972
0
                tmp_high_bound = tmp_diminfo[curr_dim].start + (tmp_diminfo[curr_dim].block - 1) +
8973
0
                                 (tmp_diminfo[curr_dim].stride * (tmp_diminfo[curr_dim].count - 1));
8974
0
                if (tmp_high_bound > space->select.sel_info.hslab->diminfo.low_bounds[curr_dim])
8975
0
                    space->select.sel_info.hslab->diminfo.high_bounds[curr_dim] = tmp_high_bound;
8976
0
            } /* end for */
8977
0
    }         /* end else */
8978
8979
0
    FUNC_LEAVE_NOAPI(ret_value)
8980
0
} /* end H5S__hyper_update_diminfo() */
8981
8982
/*--------------------------------------------------------------------------
8983
 NAME
8984
    H5S__hyper_rebuild_helper
8985
 PURPOSE
8986
    Helper routine to rebuild optimized hyperslab information if possible.
8987
    (It can be recovered with regular selection)
8988
 USAGE
8989
    herr_t H5S__hyper_rebuild_helper(space)
8990
        const H5S_hyper_span_t *spans;  IN: Portion of span tree to check
8991
        H5S_hyper_dim_t span_slab_info[]; OUT: Rebuilt section of hyperslab description
8992
 RETURNS
8993
    true/false for hyperslab selection rebuilt
8994
 DESCRIPTION
8995
    Examine the span tree for a hyperslab selection and rebuild
8996
    the start/stride/count/block information for the selection, if possible.
8997
 GLOBAL VARIABLES
8998
 COMMENTS, BUGS, ASSUMPTIONS
8999
    To be able to recover the optimized information, the span tree must conform
9000
    to span tree able to be generated from a single H5S_SELECT_SET operation.
9001
 EXAMPLES
9002
 REVISION LOG
9003
    KY, 2005/9/22
9004
--------------------------------------------------------------------------*/
9005
static bool
9006
H5S__hyper_rebuild_helper(const H5S_hyper_span_info_t *spans, H5S_hyper_dim_t span_slab_info[])
9007
0
{
9008
0
    const H5S_hyper_span_t *span;             /* Hyperslab span */
9009
0
    const H5S_hyper_span_t *prev_span;        /* Previous span in list */
9010
0
    hsize_t                 start;            /* Starting element for this dimension */
9011
0
    hsize_t                 stride;           /* Stride for this dimension */
9012
0
    hsize_t                 block;            /* Block size for this dimension */
9013
0
    hsize_t                 prev_low;         /* Low bound for previous span */
9014
0
    size_t                  spancount;        /* Number of spans encountered in this dimension */
9015
0
    bool                    ret_value = true; /* Return value */
9016
9017
0
    FUNC_ENTER_PACKAGE_NOERR
9018
9019
    /* Sanity check */
9020
0
    assert(spans);
9021
9022
    /* Initialization */
9023
0
    span      = spans->head;
9024
0
    stride    = 1;
9025
0
    prev_low  = 0;
9026
0
    spancount = 0;
9027
9028
    /* Get "canonical" down span information */
9029
0
    if (span->down)
9030
        /* Go to the next down span and check whether the selection can be rebuilt */
9031
0
        if (!H5S__hyper_rebuild_helper(span->down, &span_slab_info[1]))
9032
0
            HGOTO_DONE(false);
9033
9034
    /* Assign the initial starting point & block size for this dimension */
9035
0
    start = span->low;
9036
0
    block = (span->high - span->low) + 1;
9037
9038
    /* Loop the spans */
9039
0
    prev_span = NULL;
9040
0
    while (span) {
9041
0
        if (spancount > 0) {
9042
0
            hsize_t curr_stride; /* Current stride from previous span */
9043
0
            hsize_t curr_block;  /* Block size of current span */
9044
9045
            /* Sanity check */
9046
0
            assert(prev_span);
9047
9048
            /* Check that down spans match current slab info */
9049
            /* (Can skip check if previous span's down pointer is same as current one) */
9050
0
            if (span->down && prev_span->down != span->down)
9051
0
                if (!H5S__hyper_cmp_spans(span->down, prev_span->down))
9052
0
                    HGOTO_DONE(false);
9053
9054
            /* Obtain values for stride and block */
9055
0
            curr_stride = span->low - prev_low;
9056
0
            curr_block  = (span->high - span->low) + 1;
9057
9058
            /* Compare stride and block for this span.  To compare stride,
9059
             * three spans are needed.  Account for the first two spans.
9060
             */
9061
0
            if (curr_block != block)
9062
0
                HGOTO_DONE(false);
9063
0
            if (spancount > 1) {
9064
0
                if (stride != curr_stride)
9065
0
                    HGOTO_DONE(false);
9066
0
            } /* end if */
9067
0
            else
9068
0
                stride = curr_stride;
9069
0
        } /* end if */
9070
9071
        /* Keep current starting point */
9072
0
        prev_low = span->low;
9073
9074
        /* Advance to next span */
9075
0
        prev_span = span;
9076
0
        span      = span->next;
9077
0
        spancount++;
9078
0
    } /* end while */
9079
9080
    /* Save the span information. */
9081
0
    span_slab_info[0].start  = start;
9082
0
    span_slab_info[0].count  = spancount;
9083
0
    span_slab_info[0].block  = block;
9084
0
    span_slab_info[0].stride = stride;
9085
9086
0
done:
9087
0
    FUNC_LEAVE_NOAPI(ret_value)
9088
0
} /* end H5S__hyper_rebuild_helper() */
9089
9090
/*--------------------------------------------------------------------------
9091
 NAME
9092
    H5S__hyper_rebuild
9093
 PURPOSE
9094
    Rebuild optimized hyperslab information if possible.
9095
    (It can be recovered with regular selection)
9096
 USAGE
9097
    void H5S__hyper_rebuild(space)
9098
        H5S_t *space;     IN: Dataspace to check
9099
 RETURNS
9100
    None
9101
 DESCRIPTION
9102
    Examine the span tree for a hyperslab selection and rebuild a regular
9103
    start/stride/count/block hyperslab selection, if possible.
9104
 GLOBAL VARIABLES
9105
 COMMENTS, BUGS, ASSUMPTIONS
9106
    To be able to recover the optimized information, the span tree must conform
9107
    to span tree able to be generated from a single H5S_SELECT_SET operation.
9108
 EXAMPLES
9109
 REVISION LOG
9110
--------------------------------------------------------------------------*/
9111
void
9112
H5S__hyper_rebuild(H5S_t *space)
9113
0
{
9114
0
    H5S_hyper_dim_t rebuilt_slab_info[H5S_MAX_RANK];
9115
9116
0
    FUNC_ENTER_PACKAGE_NOERR
9117
9118
    /* Check args */
9119
0
    assert(space);
9120
0
    assert(space->select.sel_info.hslab->span_lst);
9121
9122
    /* Check whether the slab can be rebuilt */
9123
    /* (Only regular selection can be rebuilt. If yes, fill in correct values) */
9124
0
    if (false == H5S__hyper_rebuild_helper(space->select.sel_info.hslab->span_lst, rebuilt_slab_info))
9125
0
        space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_IMPOSSIBLE;
9126
0
    else {
9127
        /* Set the dimension info & bounds for the dataspace, from the rebuilt info */
9128
0
        H5MM_memcpy(space->select.sel_info.hslab->diminfo.app, rebuilt_slab_info, sizeof(rebuilt_slab_info));
9129
0
        H5MM_memcpy(space->select.sel_info.hslab->diminfo.opt, rebuilt_slab_info, sizeof(rebuilt_slab_info));
9130
0
        H5MM_memcpy(space->select.sel_info.hslab->diminfo.low_bounds,
9131
0
                    space->select.sel_info.hslab->span_lst->low_bounds, sizeof(hsize_t) * space->extent.rank);
9132
0
        H5MM_memcpy(space->select.sel_info.hslab->diminfo.high_bounds,
9133
0
                    space->select.sel_info.hslab->span_lst->high_bounds,
9134
0
                    sizeof(hsize_t) * space->extent.rank);
9135
9136
0
        space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_YES;
9137
0
    } /* end else */
9138
9139
0
    FUNC_LEAVE_NOAPI_VOID
9140
0
} /* end H5S__hyper_rebuild() */
9141
9142
/*--------------------------------------------------------------------------
9143
 NAME
9144
    H5S__hyper_generate_spans
9145
 PURPOSE
9146
    Create span tree for a regular hyperslab selection
9147
 USAGE
9148
    herr_t H5S__hyper_generate_spans(space)
9149
        H5S_t *space;           IN/OUT: Pointer to dataspace
9150
 RETURNS
9151
    Non-negative on success, negative on failure
9152
 DESCRIPTION
9153
    Create a span tree representation of a regular hyperslab selection and
9154
    add it to the information for the hyperslab selection.
9155
 GLOBAL VARIABLES
9156
 COMMENTS, BUGS, ASSUMPTIONS
9157
 EXAMPLES
9158
 REVISION LOG
9159
--------------------------------------------------------------------------*/
9160
static herr_t
9161
H5S__hyper_generate_spans(H5S_t *space)
9162
0
{
9163
0
    hsize_t  tmp_start[H5S_MAX_RANK];  /* Temporary start information */
9164
0
    hsize_t  tmp_stride[H5S_MAX_RANK]; /* Temporary stride information */
9165
0
    hsize_t  tmp_count[H5S_MAX_RANK];  /* Temporary count information */
9166
0
    hsize_t  tmp_block[H5S_MAX_RANK];  /* Temporary block information */
9167
0
    unsigned u;                        /* Local index variable */
9168
0
    herr_t   ret_value = SUCCEED;      /* Return value */
9169
9170
0
    FUNC_ENTER_PACKAGE
9171
9172
0
    assert(space);
9173
0
    assert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS);
9174
9175
    /* Get the diminfo */
9176
0
    for (u = 0; u < space->extent.rank; u++) {
9177
        /* Check for unlimited dimension and return error */
9178
        /* These should be able to be converted to assertions once everything
9179
         * that calls this function checks for unlimited selections first
9180
         * (especially the new hyperslab API)  -NAF */
9181
0
        if (space->select.sel_info.hslab->diminfo.opt[u].count == H5S_UNLIMITED)
9182
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "can't generate spans with unlimited count");
9183
0
        if (space->select.sel_info.hslab->diminfo.opt[u].block == H5S_UNLIMITED)
9184
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "can't generate spans with unlimited block");
9185
9186
0
        tmp_start[u]  = space->select.sel_info.hslab->diminfo.opt[u].start;
9187
0
        tmp_stride[u] = space->select.sel_info.hslab->diminfo.opt[u].stride;
9188
0
        tmp_count[u]  = space->select.sel_info.hslab->diminfo.opt[u].count;
9189
0
        tmp_block[u]  = space->select.sel_info.hslab->diminfo.opt[u].block;
9190
0
    } /* end for */
9191
9192
    /* Build the hyperslab information also */
9193
0
    if (H5S__generate_hyperslab(space, H5S_SELECT_SET, tmp_start, tmp_stride, tmp_count, tmp_block) < 0)
9194
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs");
9195
9196
0
done:
9197
0
    FUNC_LEAVE_NOAPI(ret_value)
9198
0
} /* end H5S__hyper_generate_spans() */
9199
9200
/*--------------------------------------------------------------------------
9201
 NAME
9202
    H5S__check_spans_overlap
9203
 PURPOSE
9204
    Check if two selections' bounds overlap.
9205
 USAGE
9206
    bool H5S__check_spans_overlap(spans1, spans2)
9207
        const H5S_hyper_span_info_t *spans1;  IN: Second span list
9208
        const H5S_hyper_span_info_t *spans2;  IN: Second span list
9209
 RETURNS
9210
    true for overlap, false for no overlap
9211
 PROGRAMMER
9212
 GLOBAL VARIABLES
9213
 COMMENTS, BUGS, ASSUMPTIONS
9214
 EXAMPLES
9215
 REVISION LOG
9216
--------------------------------------------------------------------------*/
9217
static H5_ATTR_PURE bool
9218
H5S__check_spans_overlap(const H5S_hyper_span_info_t *spans1, const H5S_hyper_span_info_t *spans2)
9219
0
{
9220
0
    bool ret_value = false; /* Return value */
9221
9222
0
    FUNC_ENTER_PACKAGE_NOERR
9223
9224
    /* Sanity checks */
9225
0
    assert(spans1);
9226
0
    assert(spans2);
9227
9228
    /* Use low & high bounds to try to avoid spinning through the span lists */
9229
0
    if (H5_RANGE_OVERLAP(spans1->low_bounds[0], spans1->high_bounds[0], spans2->low_bounds[0],
9230
0
                         spans2->high_bounds[0])) {
9231
0
        H5S_hyper_span_t *span1, *span2; /* Hyperslab spans */
9232
9233
        /* Walk over spans, comparing them for overlap */
9234
0
        span1 = spans1->head;
9235
0
        span2 = spans2->head;
9236
0
        while (span1 && span2) {
9237
            /* Check current two spans for overlap */
9238
0
            if (H5_RANGE_OVERLAP(span1->low, span1->high, span2->low, span2->high)) {
9239
                /* Check for spans in lowest dimension already */
9240
0
                if (span1->down) {
9241
                    /* Sanity check */
9242
0
                    assert(span2->down);
9243
9244
                    /* Check lower dimensions for overlap */
9245
0
                    if (H5S__check_spans_overlap(span1->down, span2->down))
9246
0
                        HGOTO_DONE(true);
9247
0
                } /* end if */
9248
0
                else
9249
0
                    HGOTO_DONE(true);
9250
0
            } /* end if */
9251
9252
            /* Advance one of the spans */
9253
0
            if (span1->high <= span2->high) {
9254
                /* Advance span1, unless it would be off the list and span2 has more nodes */
9255
0
                if (NULL == span1->next && NULL != span2->next)
9256
0
                    span2 = span2->next;
9257
0
                else
9258
0
                    span1 = span1->next;
9259
0
            } /* end if */
9260
0
            else {
9261
                /* Advance span2, unless it would be off the list and span1 has more nodes */
9262
0
                if (NULL == span2->next && NULL != span1->next)
9263
0
                    span1 = span1->next;
9264
0
                else
9265
0
                    span2 = span2->next;
9266
0
            } /* end else */
9267
0
        }     /* end while */
9268
9269
        /* Make certain we've exhausted our comparisons */
9270
0
        assert((NULL == span1 && (NULL != span2 && NULL == span2->next)) ||
9271
0
               ((NULL != span1 && NULL == span1->next) && NULL == span2));
9272
0
    } /* end of */
9273
9274
0
done:
9275
0
    FUNC_LEAVE_NOAPI(ret_value)
9276
0
} /* end H5S__check_spans_overlap() */
9277
9278
/*--------------------------------------------------------------------------
9279
 NAME
9280
    H5S__fill_in_new_space
9281
 PURPOSE
9282
    Combine two span lists, one from an existing dataspace and the
9283
    other from input arguments, into a new selection depending on the
9284
    selection operator. The new selection is put into a resulting dataspace
9285
    which could be allocated inside the function.
9286
 USAGE
9287
    herr_t H5S__fill_in_new_space(space1, op, space2_span_lst, can_own_span2,
9288
                                span2_owned, result)
9289
        H5S_t *space1;           IN: Dataspace containing the first span list
9290
        H5S_seloper_t op;        IN: Selection operation
9291
        H5S_hyper_span_info_t *space2_span_lst; IN: Second span list
9292
        bool can_own_span2;   IN: Indicates whether the 2nd span list could be
9293
                                     owned by the result. If not, the 2nd span list
9294
                                     has to be copied.
9295
        bool *span2_owned;  OUT: Indicates if the 2nd span list is actually owned
9296
        H5S_t **result;  OUT: The dataspace containing the new selection. It
9297
                              could be same with the 1st dataspace.
9298
 RETURNS
9299
    Non-negative on success, negative on failure
9300
 PROGRAMMER
9301
    Chao Mei July 8, 2011
9302
 GLOBAL VARIABLES
9303
 COMMENTS, BUGS, ASSUMPTIONS
9304
 EXAMPLES
9305
 REVISION LOG
9306
--------------------------------------------------------------------------*/
9307
static herr_t
9308
H5S__fill_in_new_space(H5S_t *space1, H5S_seloper_t op, H5S_hyper_span_info_t *space2_span_lst,
9309
                       bool can_own_span2, bool *span2_owned, bool *updated_spans, H5S_t **result)
9310
0
{
9311
0
    H5S_hyper_span_info_t *a_not_b =
9312
0
        NULL; /* Span tree for hyperslab spans in old span tree and not in new span tree */
9313
0
    H5S_hyper_span_info_t *a_and_b = NULL; /* Span tree for hyperslab spans in both old and new span trees */
9314
0
    H5S_hyper_span_info_t *b_not_a =
9315
0
        NULL; /* Span tree for hyperslab spans in new span tree and not in old span tree */
9316
0
    bool   overlapped    = false; /* Whether selections overlap */
9317
0
    bool   is_result_new = false;
9318
0
    herr_t ret_value     = SUCCEED; /* Return value */
9319
9320
0
    FUNC_ENTER_PACKAGE
9321
9322
0
    assert(space1);
9323
0
    assert(space2_span_lst);
9324
0
    assert(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA);
9325
    /* The result is either a to-be-created space or an empty one */
9326
0
    assert(*result == NULL || *result == space1);
9327
0
    assert(space1->select.sel_info.hslab->span_lst);
9328
0
    assert(span2_owned);
9329
9330
    /* Reset flags to return */
9331
0
    *span2_owned   = false;
9332
0
    *updated_spans = false;
9333
9334
    /* The result shares the same info from space1 */
9335
0
    if (*result == NULL) {
9336
0
        if (NULL == ((*result) = H5S_copy(space1, true, true)))
9337
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy dataspace");
9338
0
        space1->select.sel_info.hslab->span_lst->count--;
9339
0
        (*result)->select.sel_info.hslab->span_lst = NULL;
9340
0
        is_result_new                              = true;
9341
0
    } /* end if */
9342
9343
    /* Check both spaces to see if they overlap */
9344
0
    overlapped = H5S__check_spans_overlap(space1->select.sel_info.hslab->span_lst, space2_span_lst);
9345
9346
0
    if (!overlapped) {
9347
0
        switch (op) {
9348
0
            case H5S_SELECT_OR:
9349
0
            case H5S_SELECT_XOR:
9350
                /* Add the new disjoint spans to the space */
9351
                /* Copy of space1's spans to *result, and another copy of space2's spans */
9352
0
                if (is_result_new)
9353
0
                    (*result)->select.sel_info.hslab->span_lst =
9354
0
                        H5S__hyper_copy_span(space1->select.sel_info.hslab->span_lst, space1->extent.rank);
9355
0
                if (!can_own_span2) {
9356
0
                    b_not_a = H5S__hyper_copy_span(space2_span_lst, space1->extent.rank);
9357
0
                    if (H5S__hyper_add_disjoint_spans(*result, b_not_a) < 0)
9358
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't append hyperslabs");
9359
9360
                    /* The new_spans are now owned by 'space', so they should not be released */
9361
0
                    b_not_a = NULL;
9362
0
                } /* end if */
9363
0
                else {
9364
0
                    if (H5S__hyper_add_disjoint_spans(*result, space2_span_lst) < 0)
9365
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't append hyperslabs");
9366
0
                    *span2_owned = true;
9367
0
                } /* end else */
9368
9369
                /* Indicate that the spans changed */
9370
0
                *updated_spans = true;
9371
0
                break;
9372
9373
0
            case H5S_SELECT_AND:
9374
                /* Convert *result to "none" selection */
9375
0
                if (H5S_select_none(*result) < 0)
9376
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection");
9377
0
                HGOTO_DONE(SUCCEED);
9378
9379
0
            case H5S_SELECT_NOTB:
9380
                /* Copy space1's spans to *result */
9381
0
                if (is_result_new)
9382
0
                    (*result)->select.sel_info.hslab->span_lst =
9383
0
                        H5S__hyper_copy_span(space1->select.sel_info.hslab->span_lst, space1->extent.rank);
9384
9385
                /* Indicate that the spans changed */
9386
0
                *updated_spans = true;
9387
0
                break;
9388
9389
0
            case H5S_SELECT_NOTA:
9390
0
                if (!is_result_new) {
9391
0
                    assert(space1 == *result);
9392
9393
                    /* Free the current selection */
9394
0
                    if (H5S__hyper_free_span_info(space1->select.sel_info.hslab->span_lst) < 0)
9395
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
9396
0
                    space1->select.sel_info.hslab->span_lst = NULL;
9397
0
                }
9398
9399
                /* Copy space2's spans to *result */
9400
0
                if (!can_own_span2)
9401
0
                    (*result)->select.sel_info.hslab->span_lst =
9402
0
                        H5S__hyper_copy_span(space2_span_lst, space1->extent.rank);
9403
0
                else {
9404
0
                    (*result)->select.sel_info.hslab->span_lst = space2_span_lst;
9405
0
                    *span2_owned                               = true;
9406
0
                }
9407
9408
                /* Reset the number of items in selection */
9409
0
                (*result)->select.num_elem = H5S__hyper_spans_nelem(space2_span_lst);
9410
9411
                /* Indicate that the spans changed */
9412
0
                *updated_spans = true;
9413
0
                break;
9414
9415
0
            case H5S_SELECT_NOOP:
9416
0
            case H5S_SELECT_SET:
9417
0
            case H5S_SELECT_APPEND:
9418
0
            case H5S_SELECT_PREPEND:
9419
0
            case H5S_SELECT_INVALID:
9420
0
            default:
9421
0
                HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
9422
0
        } /* end switch */
9423
0
    }     /* end if */
9424
0
    else {
9425
0
        unsigned selector = 0; /* Select which clipping spans to generate */
9426
9427
        /* Generate mask for clip operation depending on the op */
9428
0
        switch (op) {
9429
0
            case H5S_SELECT_OR: /* a + b_not_a */
9430
0
                selector = H5S_HYPER_COMPUTE_B_NOT_A;
9431
0
                break;
9432
9433
0
            case H5S_SELECT_XOR: /* a_not_b + b_not_a */
9434
0
                selector = H5S_HYPER_COMPUTE_A_NOT_B | H5S_HYPER_COMPUTE_B_NOT_A;
9435
0
                break;
9436
9437
0
            case H5S_SELECT_AND: /* a_and_b */
9438
0
                selector = H5S_HYPER_COMPUTE_A_AND_B;
9439
0
                break;
9440
9441
0
            case H5S_SELECT_NOTB: /* a_not_b */
9442
0
                selector = H5S_HYPER_COMPUTE_A_NOT_B;
9443
0
                break;
9444
9445
0
            case H5S_SELECT_NOTA: /* b_not_a */
9446
0
                selector = H5S_HYPER_COMPUTE_B_NOT_A;
9447
0
                break;
9448
9449
0
            case H5S_SELECT_NOOP:
9450
0
            case H5S_SELECT_SET:
9451
0
            case H5S_SELECT_APPEND:
9452
0
            case H5S_SELECT_PREPEND:
9453
0
            case H5S_SELECT_INVALID:
9454
0
            default:
9455
0
                HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
9456
0
        } /* end switch */
9457
9458
        /* Generate lists of spans which overlap and don't overlap */
9459
0
        if (H5S__hyper_clip_spans(space1->select.sel_info.hslab->span_lst, space2_span_lst, selector,
9460
0
                                  space1->extent.rank, &a_not_b, &a_and_b, &b_not_a) < 0)
9461
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information");
9462
0
        switch (op) {
9463
0
            case H5S_SELECT_OR:
9464
0
                if (is_result_new)
9465
0
                    (*result)->select.sel_info.hslab->span_lst =
9466
0
                        H5S__hyper_copy_span(space1->select.sel_info.hslab->span_lst, space1->extent.rank);
9467
0
                break;
9468
9469
0
            case H5S_SELECT_AND:
9470
0
            case H5S_SELECT_XOR:
9471
0
            case H5S_SELECT_NOTB:
9472
0
            case H5S_SELECT_NOTA:
9473
0
                if (!is_result_new) {
9474
0
                    assert(space1 == *result);
9475
9476
                    /* Free the current selection */
9477
0
                    if (H5S__hyper_free_span_info(space1->select.sel_info.hslab->span_lst) < 0)
9478
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
9479
0
                    space1->select.sel_info.hslab->span_lst = NULL;
9480
0
                }
9481
9482
                /* Reset the number of items in selection */
9483
                /* (Will be set below) */
9484
0
                (*result)->select.num_elem = 0;
9485
0
                break;
9486
9487
0
            case H5S_SELECT_NOOP:
9488
0
            case H5S_SELECT_SET:
9489
0
            case H5S_SELECT_APPEND:
9490
0
            case H5S_SELECT_PREPEND:
9491
0
            case H5S_SELECT_INVALID:
9492
0
            default:
9493
0
                HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
9494
0
        } /* end switch */
9495
9496
        /* Check if there are any non-overlapped selections */
9497
0
        if (a_not_b) {
9498
            /* Other than OR, the span_lst is set to NULL. And in OR,
9499
             *      a_not_b is not needed
9500
             */
9501
0
            assert(NULL == (*result)->select.sel_info.hslab->span_lst);
9502
9503
            /* The results dataspace takes ownership of the spans */
9504
            /* (Since it must be NULL) */
9505
0
            (*result)->select.sel_info.hslab->span_lst = a_not_b;
9506
9507
            /* Update the number of elements in current selection */
9508
0
            (*result)->select.num_elem = H5S__hyper_spans_nelem(a_not_b);
9509
9510
            /* Indicate that the spans were updated */
9511
0
            *updated_spans = true;
9512
9513
            /* Indicate that the a_not_b spans are owned */
9514
0
            a_not_b = NULL;
9515
0
        } /* end if */
9516
9517
0
        if (a_and_b) {
9518
            /**
9519
             * 1. Other than OR, the span_lst is set to NULL. And in OR,
9520
             *      a_and_b is not needed
9521
             * 2. a_not_b will never be computed together with a_and_b
9522
             *      because merging these two equals to a.
9523
             */
9524
0
            assert(NULL == (*result)->select.sel_info.hslab->span_lst);
9525
9526
            /* The results dataspace takes ownership of the spans */
9527
            /* (Since it must be NULL) */
9528
0
            (*result)->select.sel_info.hslab->span_lst = a_and_b;
9529
9530
            /* Update the number of elements in current selection */
9531
0
            (*result)->select.num_elem = H5S__hyper_spans_nelem(a_and_b);
9532
9533
            /* Indicate that the spans were updated */
9534
0
            *updated_spans = true;
9535
9536
            /* Indicate that the a_and_b spans are owned */
9537
0
            a_and_b = NULL;
9538
0
        } /* end if */
9539
9540
0
        if (b_not_a) {
9541
            /* Merge the b_not_a spans into the result dataspace */
9542
0
            if (H5S__hyper_merge_spans(*result, b_not_a) < 0)
9543
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs");
9544
9545
            /* Update the number of elements in current selection */
9546
0
            (*result)->select.num_elem += H5S__hyper_spans_nelem(b_not_a);
9547
9548
            /* Indicate that the spans were updated */
9549
0
            *updated_spans = true;
9550
0
        } /* end if */
9551
0
    }     /* end else for the case the new span overlaps with the old (i.e. space) */
9552
9553
    /* Check if the spans weren't updated, and reset selection if so */
9554
0
    if (!*updated_spans) {
9555
        /* If updated_spans remains false as in this branch, it means the
9556
         *  result has been cleared in XOR / AND / NOTB / NOTA cases, and the
9557
         *  result is a copy of the dataspace in the OR case.
9558
         *
9559
         *  If two dataspaces have generated any of the three clipped
9560
         *  span trees (i.e. a_not_b, a_and_b, and b_not_a), the
9561
         *  updated_spans must be true.
9562
         */
9563
0
        if (H5S_SELECT_OR != op) {
9564
            /* Convert *result to "none" selection */
9565
0
            if (H5S_select_none(*result) < 0)
9566
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection");
9567
0
        }
9568
0
    }
9569
9570
0
done:
9571
    /* Free resources */
9572
0
    if (a_not_b)
9573
0
        if (H5S__hyper_free_span_info(a_not_b) < 0)
9574
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
9575
0
    if (a_and_b)
9576
0
        if (H5S__hyper_free_span_info(a_and_b) < 0)
9577
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
9578
0
    if (b_not_a)
9579
0
        if (H5S__hyper_free_span_info(b_not_a) < 0)
9580
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
9581
9582
0
    FUNC_LEAVE_NOAPI(ret_value)
9583
0
} /* end H5S__fill_in_new_space() */
9584
9585
/*-------------------------------------------------------------------------
9586
 * Function:    H5S__generate_hyperlab
9587
 *
9588
 * Purpose:     Generate hyperslab information from H5S_select_hyperslab()
9589
 *
9590
 * Return:      Non-negative on success/Negative on failure
9591
 *
9592
 *-------------------------------------------------------------------------
9593
 */
9594
static herr_t
9595
H5S__generate_hyperslab(H5S_t *space, H5S_seloper_t op, const hsize_t start[], const hsize_t stride[],
9596
                        const hsize_t count[], const hsize_t block[])
9597
0
{
9598
0
    H5S_hyper_span_info_t *new_spans = NULL;    /* Span tree for new hyperslab */
9599
0
    herr_t                 ret_value = SUCCEED; /* Return value */
9600
9601
0
    FUNC_ENTER_PACKAGE
9602
9603
    /* Check args */
9604
0
    assert(space);
9605
0
    assert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID);
9606
0
    assert(start);
9607
0
    assert(stride);
9608
0
    assert(count);
9609
0
    assert(block);
9610
9611
    /* Generate span tree for new hyperslab information */
9612
0
    if (NULL == (new_spans = H5S__hyper_make_spans(space->extent.rank, start, stride, count, block)))
9613
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't create hyperslab information");
9614
9615
    /* Generate list of blocks to add/remove based on selection operation */
9616
0
    if (op == H5S_SELECT_SET) {
9617
        /* Free current selection */
9618
0
        if (NULL != space->select.sel_info.hslab->span_lst)
9619
0
            if (H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst) < 0)
9620
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
9621
9622
        /* Set the hyperslab selection to the new span tree */
9623
0
        space->select.sel_info.hslab->span_lst = new_spans;
9624
9625
        /* Set the number of elements in current selection */
9626
0
        space->select.num_elem = H5S__hyper_spans_nelem(new_spans);
9627
9628
        /* Indicate that the new_spans are owned */
9629
0
        new_spans = NULL;
9630
0
    }
9631
0
    else {
9632
0
        bool new_spans_owned = false;
9633
0
        bool updated_spans   = false;
9634
9635
        /* Generate new spans for space */
9636
0
        if (H5S__fill_in_new_space(space, op, new_spans, true, &new_spans_owned, &updated_spans, &space) < 0)
9637
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't generate the specified hyperslab");
9638
9639
        /* Check if the spans were updated by H5S__fill_in_new_space */
9640
0
        if (updated_spans) {
9641
0
            H5S_hyper_dim_t new_hyper_diminfo[H5S_MAX_RANK];
9642
0
            unsigned        u; /* Local index variable */
9643
9644
            /* Sanity check */
9645
0
            assert(space->select.sel_info.hslab->span_lst->head);
9646
9647
            /* Build diminfo struct */
9648
0
            for (u = 0; u < space->extent.rank; u++) {
9649
0
                new_hyper_diminfo[u].start  = start[u];
9650
0
                new_hyper_diminfo[u].stride = stride[u];
9651
0
                new_hyper_diminfo[u].count  = count[u];
9652
0
                new_hyper_diminfo[u].block  = block[u];
9653
0
            } /* end for */
9654
9655
            /* Update space's dim info */
9656
0
            if (H5S__hyper_update_diminfo(space, op, new_hyper_diminfo) < 0)
9657
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't update hyperslab info");
9658
0
        } /* end if */
9659
9660
        /* Indicate that the new_spans are owned, there's no need to free */
9661
0
        if (new_spans_owned)
9662
0
            new_spans = NULL;
9663
0
    }
9664
9665
0
done:
9666
0
    if (new_spans)
9667
0
        if (H5S__hyper_free_span_info(new_spans) < 0)
9668
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
9669
9670
0
    FUNC_LEAVE_NOAPI(ret_value)
9671
0
} /* end H5S__generate_hyperslab() */
9672
9673
/*-------------------------------------------------------------------------
9674
 * Function:    H5S__set_regular_hyperslab
9675
 *
9676
 * Purpose:    Set a regular hyperslab
9677
 *
9678
 * Return:    Non-negative on success/Negative on failure
9679
 *
9680
 *-------------------------------------------------------------------------
9681
 */
9682
herr_t
9683
H5S__set_regular_hyperslab(H5S_t *space, const hsize_t start[], const hsize_t *app_stride,
9684
                           const hsize_t app_count[], const hsize_t *app_block, const hsize_t *opt_stride,
9685
                           const hsize_t opt_count[], const hsize_t *opt_block)
9686
0
{
9687
0
    unsigned u;                   /* Local index variable */
9688
0
    herr_t   ret_value = SUCCEED; /* Return value */
9689
9690
0
    FUNC_ENTER_PACKAGE
9691
9692
    /* Check args */
9693
0
    assert(space);
9694
0
    assert(start);
9695
0
    assert(app_stride);
9696
0
    assert(app_count);
9697
0
    assert(app_block);
9698
0
    assert(opt_stride);
9699
0
    assert(opt_count);
9700
0
    assert(opt_block);
9701
9702
    /* If we are setting a new selection, remove current selection first */
9703
0
    if (H5S_SELECT_RELEASE(space) < 0)
9704
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection");
9705
9706
    /* Allocate space for the hyperslab selection information */
9707
0
    if (NULL == (space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t)))
9708
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab info");
9709
9710
    /* Set the diminfo */
9711
0
    space->select.num_elem                  = 1;
9712
0
    space->select.sel_info.hslab->unlim_dim = -1;
9713
0
    for (u = 0; u < space->extent.rank; u++) {
9714
        /* Set application and optimized hyperslab info */
9715
0
        space->select.sel_info.hslab->diminfo.app[u].start  = start[u];
9716
0
        space->select.sel_info.hslab->diminfo.app[u].stride = app_stride[u];
9717
0
        space->select.sel_info.hslab->diminfo.app[u].count  = app_count[u];
9718
0
        space->select.sel_info.hslab->diminfo.app[u].block  = app_block[u];
9719
9720
0
        space->select.sel_info.hslab->diminfo.opt[u].start  = start[u];
9721
0
        space->select.sel_info.hslab->diminfo.opt[u].stride = opt_stride[u];
9722
0
        space->select.sel_info.hslab->diminfo.opt[u].count  = opt_count[u];
9723
0
        space->select.sel_info.hslab->diminfo.opt[u].block  = opt_block[u];
9724
9725
        /* Update # of elements selected */
9726
0
        space->select.num_elem *= (opt_count[u] * opt_block[u]);
9727
9728
        /* Set low bound of bounding box for the hyperslab selection */
9729
0
        space->select.sel_info.hslab->diminfo.low_bounds[u] = start[u];
9730
9731
        /* Check for unlimited dimension & set high bound */
9732
0
        if ((app_count[u] == H5S_UNLIMITED) || (app_block[u] == H5S_UNLIMITED)) {
9733
0
            space->select.sel_info.hslab->unlim_dim              = (int)u;
9734
0
            space->select.sel_info.hslab->diminfo.high_bounds[u] = H5S_UNLIMITED;
9735
0
        } /* end if */
9736
0
        else
9737
0
            space->select.sel_info.hslab->diminfo.high_bounds[u] =
9738
0
                start[u] + opt_stride[u] * (opt_count[u] - 1) + (opt_block[u] - 1);
9739
0
    } /* end for */
9740
9741
    /* Handle unlimited selections */
9742
0
    if (space->select.sel_info.hslab->unlim_dim >= 0) {
9743
        /* Calculate num_elem_non_unlim */
9744
0
        space->select.sel_info.hslab->num_elem_non_unlim = (hsize_t)1;
9745
0
        for (u = 0; u < space->extent.rank; u++)
9746
0
            if ((int)u != space->select.sel_info.hslab->unlim_dim)
9747
0
                space->select.sel_info.hslab->num_elem_non_unlim *= (opt_count[u] * opt_block[u]);
9748
9749
        /* Update num_elem */
9750
0
        space->select.num_elem = H5S_UNLIMITED;
9751
0
    } /* end if */
9752
9753
    /* Indicate that the dimension information is valid */
9754
0
    space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_YES;
9755
9756
    /* Indicate that there's no slab information */
9757
0
    space->select.sel_info.hslab->span_lst = NULL;
9758
9759
    /* Set selection type */
9760
0
    space->select.type = H5S_sel_hyper;
9761
9762
0
done:
9763
0
    FUNC_LEAVE_NOAPI(ret_value)
9764
0
} /* end H5S__set_regular_hyperslab() */
9765
9766
/*-------------------------------------------------------------------------
9767
 * Function:    H5S__hyper_regular_and_single_block
9768
 *
9769
 * Purpose:    Optimized routine to perform "AND" operation of a single
9770
 *        block against a regular hyperslab selection.
9771
 *
9772
 * Note:    This algorithm is invoked when constructing the chunk map
9773
 *              and a regular hyperslab is selected in the file's dataspace.
9774
 *
9775
 * Return:    Non-negative on success / Negative on failure
9776
 *
9777
 *-------------------------------------------------------------------------
9778
 */
9779
static herr_t
9780
H5S__hyper_regular_and_single_block(H5S_t *space, const hsize_t start[], const hsize_t block[])
9781
0
{
9782
0
    hsize_t  select_end, block_end; /* End of block & selection */
9783
0
    bool     single_block;          /* Whether the selection is a single block */
9784
0
    bool     overlap;               /* Whether block & selection overlap */
9785
0
    unsigned u;                     /* Local index variable */
9786
0
    herr_t   ret_value = SUCCEED;   /* Return value */
9787
9788
0
    FUNC_ENTER_PACKAGE
9789
9790
    /* Check args */
9791
0
    assert(space);
9792
0
    assert(start);
9793
0
    assert(block);
9794
9795
    /* Check for single block selection in dataspace */
9796
0
    single_block = true;
9797
0
    for (u = 0; u < space->extent.rank; u++)
9798
0
        if (1 != space->select.sel_info.hslab->diminfo.opt[u].count) {
9799
0
            single_block = false;
9800
0
            break;
9801
0
        } /* end if */
9802
9803
    /* Perform different optimizations, based on type of regular selection */
9804
0
    if (single_block) {
9805
0
        hsize_t new_start[H5S_MAX_RANK]; /* New starting coordinate */
9806
0
        hsize_t new_block[H5S_MAX_RANK]; /* New block size */
9807
9808
        /* Check for overlap and compute new start offset & block sizes */
9809
0
        overlap = true;
9810
0
        for (u = 0; u < space->extent.rank; u++) {
9811
            /* Compute the end of the selection & block in this dimension */
9812
0
            select_end = space->select.sel_info.hslab->diminfo.high_bounds[u];
9813
0
            block_end  = (start[u] + block[u]) - 1;
9814
9815
            /* Check for overlap */
9816
0
            if (!H5_RANGE_OVERLAP(space->select.sel_info.hslab->diminfo.opt[u].start, select_end, start[u],
9817
0
                                  block_end)) {
9818
0
                overlap = false;
9819
0
                break;
9820
0
            } /* end if */
9821
9822
            /* Set new start & block size in this dimension */
9823
0
            new_start[u] = MAX(space->select.sel_info.hslab->diminfo.opt[u].start, start[u]);
9824
0
            new_block[u] = (MIN(select_end, block_end) - new_start[u]) + 1;
9825
0
        } /* end for */
9826
9827
        /* Check for overlap of selection & block */
9828
0
        if (overlap) {
9829
            /* Set selection to regular hyperslab */
9830
0
            if (H5S__set_regular_hyperslab(space, new_start, H5S_hyper_ones_g, H5S_hyper_ones_g, new_block,
9831
0
                                           H5S_hyper_ones_g, H5S_hyper_ones_g, new_block) < 0)
9832
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't set regular hyperslab selection");
9833
0
        } /* end if */
9834
0
        else
9835
            /* Selection & block don't overlap, set to "none" selection */
9836
0
            if (H5S_select_none(space) < 0)
9837
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection");
9838
0
    } /* end if */
9839
0
    else {
9840
0
        hsize_t new_start[H5S_MAX_RANK]; /* New start for hyperslab selection */
9841
0
        hsize_t new_count[H5S_MAX_RANK]; /* New count for hyperslab selection */
9842
0
        hsize_t stride[H5S_MAX_RANK];    /* Stride for hyperslab selection */
9843
0
        hsize_t new_block[H5S_MAX_RANK]; /* New block for hyperslab selection */
9844
0
        bool    partial_first_span;      /* Whether first span in intersection is partial */
9845
0
        bool    partial_last_span;       /* Whether last span in intersection is partial */
9846
9847
        /* Iterate over selection, checking for overlap and computing first / last
9848
         *      span that intersects with the block.
9849
         */
9850
0
        overlap            = true;
9851
0
        partial_first_span = false;
9852
0
        partial_last_span  = false;
9853
0
        for (u = 0; u < space->extent.rank; u++) {
9854
0
            hsize_t first_span_start, first_span_end; /* Start / end of first span */
9855
0
            hsize_t last_span_start, last_span_end;   /* Start / end of last span */
9856
0
            hsize_t nstride;                          /* Number of strides into the selection */
9857
9858
            /* Compute the end of the selection & block in this dimension */
9859
0
            select_end = space->select.sel_info.hslab->diminfo.high_bounds[u];
9860
0
            block_end  = (start[u] + block[u]) - 1;
9861
9862
            /* Check for overlap */
9863
0
            if (!H5_RANGE_OVERLAP(space->select.sel_info.hslab->diminfo.opt[u].start, select_end, start[u],
9864
0
                                  block_end)) {
9865
0
                overlap = false;
9866
0
                break;
9867
0
            } /* end if */
9868
9869
            /* Find first span that is before or overlaps with start of block */
9870
0
            if (space->select.sel_info.hslab->diminfo.opt[u].start >= start[u]) {
9871
                /* Calculate start & end of first span */
9872
0
                first_span_start = space->select.sel_info.hslab->diminfo.opt[u].start;
9873
0
                first_span_end = (first_span_start + space->select.sel_info.hslab->diminfo.opt[u].block) - 1;
9874
9875
                /* Check if first span overlaps _end_ of block */
9876
0
                if (block_end >= first_span_start && block_end <= first_span_end)
9877
0
                    partial_first_span = true;
9878
0
            } /* end if */
9879
0
            else {
9880
0
                hsize_t adj_start; /* Start coord, adjusted for hyperslab selection parameters */
9881
9882
                /* Adjust start coord for selection's 'start' offset */
9883
0
                adj_start = start[u] - space->select.sel_info.hslab->diminfo.opt[u].start;
9884
9885
                /* Compute # of strides into the selection */
9886
0
                if (space->select.sel_info.hslab->diminfo.opt[u].count > 1)
9887
0
                    nstride = adj_start / space->select.sel_info.hslab->diminfo.opt[u].stride;
9888
0
                else
9889
0
                    nstride = 0;
9890
9891
                /* Calculate start & end of first span */
9892
0
                first_span_start = space->select.sel_info.hslab->diminfo.opt[u].start +
9893
0
                                   (nstride * space->select.sel_info.hslab->diminfo.opt[u].stride);
9894
0
                first_span_end = (first_span_start + space->select.sel_info.hslab->diminfo.opt[u].block) - 1;
9895
9896
                /* Check if first span overlaps start of block */
9897
0
                if (first_span_start < start[u] && first_span_end >= start[u])
9898
0
                    partial_first_span = true;
9899
9900
                /* Advance first span to start higher than block's start,
9901
                 *      if it's not partial.
9902
                 */
9903
0
                if (first_span_end < start[u]) {
9904
0
                    first_span_start += space->select.sel_info.hslab->diminfo.opt[u].stride;
9905
0
                    first_span_end += space->select.sel_info.hslab->diminfo.opt[u].stride;
9906
0
                } /* end if */
9907
0
            }     /* end else */
9908
9909
            /* Find last span that is before or overlaps with end of block */
9910
0
            if (select_end < block_end) {
9911
                /* Calculate start & end of last span */
9912
0
                last_span_start = (select_end - space->select.sel_info.hslab->diminfo.opt[u].block) + 1;
9913
0
                last_span_end   = select_end;
9914
9915
                /* Check if last span overlaps _start_ of block */
9916
0
                if (start[u] >= last_span_start && start[u] <= last_span_end)
9917
0
                    partial_last_span = true;
9918
0
            } /* end if */
9919
0
            else {
9920
0
                hsize_t adj_end; /* End coord, adjusted for hyperslab selection parameters */
9921
9922
                /* Adjust end coord for selection's 'start' offset */
9923
0
                adj_end = block_end - space->select.sel_info.hslab->diminfo.opt[u].start;
9924
9925
                /* Compute # of strides into the selection */
9926
0
                if (space->select.sel_info.hslab->diminfo.opt[u].count > 1)
9927
0
                    nstride = adj_end / space->select.sel_info.hslab->diminfo.opt[u].stride;
9928
0
                else
9929
0
                    nstride = 0;
9930
9931
                /* Calculate start & end of last span */
9932
0
                last_span_start = space->select.sel_info.hslab->diminfo.opt[u].start +
9933
0
                                  (nstride * space->select.sel_info.hslab->diminfo.opt[u].stride);
9934
0
                last_span_end = (last_span_start + space->select.sel_info.hslab->diminfo.opt[u].block) - 1;
9935
9936
                /* Check if last span overlaps end of block */
9937
0
                if (block_end >= last_span_start && block_end <= last_span_end)
9938
0
                    partial_last_span = true;
9939
0
            } /* end else */
9940
9941
            /* Check if no spans are inside block */
9942
            /* (Can happen when block falls in "gap" between spans) */
9943
0
            if (last_span_end < start[u]) {
9944
0
                overlap = false;
9945
0
                break;
9946
0
            } /* end if */
9947
9948
            /* Sanity check */
9949
0
            assert(first_span_start <= last_span_start);
9950
9951
            /* Compute new start / count / block values */
9952
0
            new_start[u] = first_span_start;
9953
0
            if (last_span_start != first_span_start)
9954
0
                new_count[u] = ((last_span_start - first_span_start) /
9955
0
                                space->select.sel_info.hslab->diminfo.opt[u].stride) +
9956
0
                               1;
9957
0
            else
9958
0
                new_count[u] = 1;
9959
0
            new_block[u] = space->select.sel_info.hslab->diminfo.opt[u].block;
9960
9961
            /* Keep same stride */
9962
0
            stride[u] = space->select.sel_info.hslab->diminfo.opt[u].stride;
9963
0
        } /* end for */
9964
9965
        /* Check for overlap of selection & block */
9966
0
        if (overlap) {
9967
            /* Set selection to regular hyperslab */
9968
0
            if (H5S__set_regular_hyperslab(space, new_start, stride, new_count, new_block, stride, new_count,
9969
0
                                           new_block) < 0)
9970
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't set regular hyperslab selection");
9971
9972
            /* If there's a partial first or last span, have to 'AND' against selection */
9973
0
            if (partial_first_span || partial_last_span) {
9974
                /* Generate span tree for regular selection */
9975
0
                if (H5S__hyper_generate_spans(space) < 0)
9976
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree");
9977
9978
                /* 'AND' against block */
9979
0
                if (H5S__generate_hyperslab(space, H5S_SELECT_AND, start, H5S_hyper_ones_g, H5S_hyper_ones_g,
9980
0
                                            block) < 0)
9981
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs");
9982
0
            } /* end if */
9983
0
        }     /* end if */
9984
0
        else {
9985
            /* Selection & block don't overlap, set to "none" selection */
9986
0
            if (H5S_select_none(space) < 0)
9987
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection");
9988
0
        } /* end else */
9989
0
    }     /* end else */
9990
9991
0
done:
9992
0
    FUNC_LEAVE_NOAPI(ret_value)
9993
0
} /* end H5S__hyper_regular_and_single_block() */
9994
9995
/*-------------------------------------------------------------------------
9996
 * Function:    H5S_select_hyperslab
9997
 *
9998
 * Purpose:     Internal version of H5Sselect_hyperslab().
9999
 *
10000
 * Return:      Non-negative on success/Negative on failure
10001
 *
10002
 *-------------------------------------------------------------------------
10003
 */
10004
herr_t
10005
H5S_select_hyperslab(H5S_t *space, H5S_seloper_t op, const hsize_t start[], const hsize_t *stride,
10006
                     const hsize_t count[], const hsize_t *block)
10007
0
{
10008
0
    hsize_t        int_stride[H5S_MAX_RANK]; /* Internal storage for stride information */
10009
0
    hsize_t        int_count[H5S_MAX_RANK];  /* Internal storage for count information */
10010
0
    hsize_t        int_block[H5S_MAX_RANK];  /* Internal storage for block information */
10011
0
    const hsize_t *opt_stride;               /* Optimized stride information */
10012
0
    const hsize_t *opt_count;                /* Optimized count information */
10013
0
    const hsize_t *opt_block;                /* Optimized block information */
10014
0
    int            unlim_dim = -1;           /* Unlimited dimension in selection, of -1 if none */
10015
0
    unsigned       u;                        /* Local index variable */
10016
0
    herr_t         ret_value = SUCCEED;      /* Return value */
10017
10018
0
    FUNC_ENTER_NOAPI(FAIL)
10019
10020
    /* Check args */
10021
0
    assert(space);
10022
0
    assert(start);
10023
0
    assert(count);
10024
0
    assert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID);
10025
10026
    /* Point to the correct stride values */
10027
0
    if (stride == NULL)
10028
0
        stride = H5S_hyper_ones_g;
10029
10030
    /* Point to the correct block values */
10031
0
    if (block == NULL)
10032
0
        block = H5S_hyper_ones_g;
10033
10034
    /* Check new selection */
10035
0
    for (u = 0; u < space->extent.rank; u++) {
10036
        /* Check for overlapping hyperslab blocks in new selection. */
10037
0
        if (count[u] > 1 && stride[u] < block[u])
10038
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab blocks overlap");
10039
10040
        /* Detect zero-sized hyperslabs in new selection */
10041
0
        if (count[u] == 0 || block[u] == 0) {
10042
0
            switch (op) {
10043
0
                case H5S_SELECT_SET:  /* Select "set" operation */
10044
0
                case H5S_SELECT_AND:  /* Binary "and" operation for hyperslabs */
10045
0
                case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */
10046
                    /* Convert to "none" selection */
10047
0
                    if (H5S_select_none(space) < 0)
10048
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection");
10049
0
                    HGOTO_DONE(SUCCEED);
10050
10051
0
                case H5S_SELECT_OR:      /* Binary "or" operation for hyperslabs */
10052
0
                case H5S_SELECT_XOR:     /* Binary "xor" operation for hyperslabs */
10053
0
                case H5S_SELECT_NOTB:    /* Binary "A not B" operation for hyperslabs */
10054
0
                    HGOTO_DONE(SUCCEED); /* Selection stays same */
10055
10056
0
                case H5S_SELECT_NOOP:
10057
0
                case H5S_SELECT_APPEND:
10058
0
                case H5S_SELECT_PREPEND:
10059
0
                case H5S_SELECT_INVALID:
10060
0
                default:
10061
0
                    HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
10062
0
            } /* end switch */
10063
0
        }     /* end if */
10064
10065
        /* Check for unlimited dimension */
10066
0
        if ((count[u] == H5S_UNLIMITED) || (block[u] == H5S_UNLIMITED)) {
10067
0
            if (unlim_dim >= 0)
10068
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL,
10069
0
                            "cannot have more than one unlimited dimension in selection");
10070
0
            else {
10071
0
                if (count[u] == block[u]) /* Both are H5S_UNLIMITED */
10072
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL,
10073
0
                                "count and block cannot both be unlimited");
10074
0
                unlim_dim = (int)u;
10075
0
            } /* end else */
10076
0
        }     /* end if */
10077
0
    }         /* end for */
10078
10079
    /* Optimize hyperslab parameters to merge contiguous blocks, etc. */
10080
0
    if (stride == H5S_hyper_ones_g && block == H5S_hyper_ones_g) {
10081
        /* Point to existing arrays */
10082
0
        opt_stride = H5S_hyper_ones_g;
10083
0
        opt_count  = H5S_hyper_ones_g;
10084
0
        opt_block  = count;
10085
0
    } /* end if */
10086
0
    else {
10087
        /* Point to local arrays */
10088
0
        opt_stride = int_stride;
10089
0
        opt_count  = int_count;
10090
0
        opt_block  = int_block;
10091
0
        for (u = 0; u < space->extent.rank; u++) {
10092
            /* contiguous hyperslabs have the block size equal to the stride */
10093
0
            if ((stride[u] == block[u]) && (count[u] != H5S_UNLIMITED)) {
10094
0
                int_count[u]  = 1;
10095
0
                int_stride[u] = 1;
10096
0
                if (block[u] == 1)
10097
0
                    int_block[u] = count[u];
10098
0
                else
10099
0
                    int_block[u] = block[u] * count[u];
10100
0
            } /* end if */
10101
0
            else {
10102
0
                if (count[u] == 1)
10103
0
                    int_stride[u] = 1;
10104
0
                else {
10105
0
                    assert((stride[u] > block[u]) ||
10106
0
                           ((stride[u] == block[u]) && (count[u] == H5S_UNLIMITED)));
10107
0
                    int_stride[u] = stride[u];
10108
0
                } /* end else */
10109
0
                int_count[u] = count[u];
10110
0
                int_block[u] = block[u];
10111
0
            } /* end else */
10112
0
        }     /* end for */
10113
0
    }         /* end else */
10114
10115
    /* Check for operating on unlimited selection */
10116
0
    if ((H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS) &&
10117
0
        (space->select.sel_info.hslab->unlim_dim >= 0) && (op != H5S_SELECT_SET)) {
10118
        /* Check for invalid operation */
10119
0
        if (unlim_dim >= 0)
10120
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL,
10121
0
                        "cannot modify unlimited selection with another unlimited selection");
10122
0
        if (!((op == H5S_SELECT_AND) || (op == H5S_SELECT_NOTA)))
10123
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unsupported operation on unlimited selection");
10124
0
        assert(space->select.sel_info.hslab->diminfo_valid);
10125
10126
        /* Clip unlimited selection to include new selection */
10127
0
        if (H5S_hyper_clip_unlim(space,
10128
0
                                 start[space->select.sel_info.hslab->unlim_dim] +
10129
0
                                     ((opt_count[space->select.sel_info.hslab->unlim_dim] - (hsize_t)1) *
10130
0
                                      opt_stride[space->select.sel_info.hslab->unlim_dim]) +
10131
0
                                     opt_block[space->select.sel_info.hslab->unlim_dim]) < 0)
10132
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection");
10133
10134
        /* If an empty space was returned it must be "none" */
10135
0
        assert((space->select.num_elem > (hsize_t)0) || (space->select.type->type == H5S_SEL_NONE));
10136
0
    } /* end if */
10137
10138
    /* Fixup operation for non-hyperslab selections */
10139
0
    switch (H5S_GET_SELECT_TYPE(space)) {
10140
0
        case H5S_SEL_NONE: /* No elements selected in dataspace */
10141
0
            switch (op) {
10142
0
                case H5S_SELECT_SET: /* Select "set" operation */
10143
                    /* Change "none" selection to hyperslab selection */
10144
0
                    break;
10145
10146
0
                case H5S_SELECT_OR:      /* Binary "or" operation for hyperslabs */
10147
0
                case H5S_SELECT_XOR:     /* Binary "xor" operation for hyperslabs */
10148
0
                case H5S_SELECT_NOTA:    /* Binary "B not A" operation for hyperslabs */
10149
0
                    op = H5S_SELECT_SET; /* Maps to "set" operation when applied to "none" selection */
10150
0
                    break;
10151
10152
0
                case H5S_SELECT_AND:     /* Binary "and" operation for hyperslabs */
10153
0
                case H5S_SELECT_NOTB:    /* Binary "A not B" operation for hyperslabs */
10154
0
                    HGOTO_DONE(SUCCEED); /* Selection stays "none" */
10155
10156
0
                case H5S_SELECT_NOOP:
10157
0
                case H5S_SELECT_APPEND:
10158
0
                case H5S_SELECT_PREPEND:
10159
0
                case H5S_SELECT_INVALID:
10160
0
                default:
10161
0
                    HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
10162
0
            } /* end switch */
10163
0
            break;
10164
10165
0
        case H5S_SEL_ALL: /* All elements selected in dataspace */
10166
0
            switch (op) {
10167
0
                case H5S_SELECT_SET: /* Select "set" operation */
10168
                    /* Change "all" selection to hyperslab selection */
10169
0
                    break;
10170
10171
0
                case H5S_SELECT_OR:      /* Binary "or" operation for hyperslabs */
10172
0
                    HGOTO_DONE(SUCCEED); /* Selection stays "all" */
10173
10174
0
                case H5S_SELECT_AND:     /* Binary "and" operation for hyperslabs */
10175
0
                    op = H5S_SELECT_SET; /* Maps to "set" operation when applied to "none" selection */
10176
0
                    break;
10177
10178
0
                case H5S_SELECT_XOR:  /* Binary "xor" operation for hyperslabs */
10179
0
                case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */
10180
                    /* Convert current "all" selection to "real" hyperslab selection */
10181
                    /* Then allow operation to proceed */
10182
0
                    {
10183
0
                        const hsize_t *tmp_start;  /* Temporary start information */
10184
0
                        const hsize_t *tmp_stride; /* Temporary stride information */
10185
0
                        const hsize_t *tmp_count;  /* Temporary count information */
10186
0
                        const hsize_t *tmp_block;  /* Temporary block information */
10187
10188
                        /* Set up temporary information for the dimensions */
10189
0
                        tmp_start  = H5S_hyper_zeros_g;
10190
0
                        tmp_stride = tmp_count = H5S_hyper_ones_g;
10191
0
                        tmp_block              = space->extent.size;
10192
10193
                        /* Convert to hyperslab selection */
10194
0
                        if (H5S_select_hyperslab(space, H5S_SELECT_SET, tmp_start, tmp_stride, tmp_count,
10195
0
                                                 tmp_block) < 0)
10196
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection");
10197
0
                    } /* end case */
10198
0
                    break;
10199
10200
0
                case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */
10201
                    /* Convert to "none" selection */
10202
0
                    if (H5S_select_none(space) < 0)
10203
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection");
10204
0
                    HGOTO_DONE(SUCCEED);
10205
10206
0
                case H5S_SELECT_NOOP:
10207
0
                case H5S_SELECT_APPEND:
10208
0
                case H5S_SELECT_PREPEND:
10209
0
                case H5S_SELECT_INVALID:
10210
0
                default:
10211
0
                    HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
10212
0
            } /* end switch */
10213
0
            break;
10214
10215
0
        case H5S_SEL_HYPERSLABS:
10216
            /* Hyperslab operation on hyperslab selection, OK */
10217
0
            break;
10218
10219
0
        case H5S_SEL_POINTS:          /* Can't combine hyperslab operations and point selections currently */
10220
0
            if (op == H5S_SELECT_SET) /* Allow only "set" operation to proceed */
10221
0
                break;
10222
            /* FALLTHROUGH (to error) */
10223
0
            H5_ATTR_FALLTHROUGH
10224
10225
0
        case H5S_SEL_ERROR:
10226
0
        case H5S_SEL_N:
10227
0
        default:
10228
0
            HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
10229
0
    } /* end switch */
10230
10231
0
    if (op == H5S_SELECT_SET) {
10232
        /* Set selection to regular hyperslab */
10233
0
        if (H5S__set_regular_hyperslab(space, start, stride, count, block, opt_stride, opt_count, opt_block) <
10234
0
            0)
10235
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't set regular hyperslab selection");
10236
0
    } /* end if */
10237
0
    else if (op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA) {
10238
0
        bool single_block; /* Whether the selection is a single block */
10239
10240
        /* Sanity check */
10241
0
        assert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS);
10242
10243
        /* Handle unlimited selections */
10244
0
        if (unlim_dim >= 0) {
10245
0
            hsize_t bounds_start[H5S_MAX_RANK];
10246
0
            hsize_t bounds_end[H5S_MAX_RANK];
10247
0
            hsize_t tmp_count = opt_count[unlim_dim];
10248
0
            hsize_t tmp_block = opt_block[unlim_dim];
10249
10250
            /* Check for invalid operation */
10251
0
            if (space->select.sel_info.hslab->unlim_dim >= 0)
10252
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL,
10253
0
                            "cannot modify unlimited selection with another unlimited selection");
10254
0
            if (!((op == H5S_SELECT_AND) || (op == H5S_SELECT_NOTB)))
10255
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL,
10256
0
                            "unsupported operation with unlimited selection");
10257
10258
            /* Get bounds of existing selection */
10259
0
            if (H5S__hyper_bounds(space, bounds_start, bounds_end) < 0)
10260
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get selection bounds");
10261
10262
            /* Patch count and block to remove unlimited and include the
10263
             * existing selection.
10264
             */
10265
0
            H5S__hyper_get_clip_diminfo(start[unlim_dim], opt_stride[unlim_dim], &tmp_count, &tmp_block,
10266
0
                                        bounds_end[unlim_dim] + (hsize_t)1);
10267
0
            assert((tmp_count == 1) || (opt_count != H5S_hyper_ones_g));
10268
0
            assert((tmp_block == 1) || (opt_block != H5S_hyper_ones_g));
10269
0
            if (opt_count != H5S_hyper_ones_g) {
10270
0
                assert(opt_count == int_count);
10271
0
                int_count[unlim_dim] = tmp_count;
10272
0
            } /* end if */
10273
0
            if (opt_block != H5S_hyper_ones_g) {
10274
0
                assert(opt_block == int_block);
10275
0
                int_block[unlim_dim] = tmp_block;
10276
0
            } /* end if */
10277
0
        }     /* end if */
10278
10279
        /* Check for a single block selected */
10280
0
        single_block = true;
10281
0
        for (u = 0; u < space->extent.rank; u++)
10282
0
            if (1 != opt_count[u]) {
10283
0
                single_block = false;
10284
0
                break;
10285
0
            } /* end if */
10286
10287
        /* Check for single block "AND" operation on a regular hyperslab, which
10288
         *      is used for constructing chunk maps and can be optimized for.
10289
         */
10290
0
        if (H5S_SELECT_AND == op && single_block &&
10291
0
            space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
10292
0
            if (H5S__hyper_regular_and_single_block(space, start, opt_block) < 0)
10293
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTOPERATE, FAIL,
10294
0
                            "can't 'AND' single block against regular hyperslab");
10295
0
        } /* end if */
10296
0
        else {
10297
            /* Check if there's no hyperslab span information currently */
10298
0
            if (NULL == space->select.sel_info.hslab->span_lst)
10299
0
                if (H5S__hyper_generate_spans(space) < 0)
10300
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree");
10301
10302
            /* Set selection type */
10303
0
            space->select.type = H5S_sel_hyper;
10304
10305
            /* Add in the new hyperslab information */
10306
0
            if (H5S__generate_hyperslab(space, op, start, opt_stride, opt_count, opt_block) < 0)
10307
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs");
10308
0
        } /* end else */
10309
0
    }     /* end if */
10310
0
    else
10311
0
        HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
10312
10313
0
done:
10314
0
    FUNC_LEAVE_NOAPI(ret_value)
10315
0
} /* end H5S_select_hyperslab() */
10316
10317
/*--------------------------------------------------------------------------
10318
 NAME
10319
    H5Sselect_hyperslab
10320
 PURPOSE
10321
    Specify a hyperslab to combine with the current hyperslab selection
10322
 USAGE
10323
    herr_t H5Sselect_hyperslab(dsid, op, start, stride, count, block)
10324
        hid_t dsid;             IN: Dataspace ID of selection to modify
10325
        H5S_seloper_t op;       IN: Operation to perform on current selection
10326
        const hsize_t *start;        IN: Offset of start of hyperslab
10327
        const hsize_t *stride;       IN: Hyperslab stride
10328
        const hsize_t *count;        IN: Number of blocks included in hyperslab
10329
        const hsize_t *block;        IN: Size of block in hyperslab
10330
 RETURNS
10331
    Non-negative on success/Negative on failure
10332
 DESCRIPTION
10333
    Combines a hyperslab selection with the current selection for a dataspace.
10334
    If the current selection is not a hyperslab, it is freed and the hyperslab
10335
    parameters passed in are combined with the H5S_SEL_ALL hyperslab (ie. a
10336
    selection composing the entire current extent).  If STRIDE or BLOCK is
10337
    NULL, they are assumed to be set to all '1'.
10338
 GLOBAL VARIABLES
10339
 COMMENTS, BUGS, ASSUMPTIONS
10340
 EXAMPLES
10341
 REVISION LOG
10342
--------------------------------------------------------------------------*/
10343
herr_t
10344
H5Sselect_hyperslab(hid_t space_id, H5S_seloper_t op, const hsize_t start[], const hsize_t stride[],
10345
                    const hsize_t count[], const hsize_t block[])
10346
0
{
10347
0
    H5S_t *space;               /* Dataspace to modify selection of */
10348
0
    herr_t ret_value = SUCCEED; /* Return value */
10349
10350
0
    FUNC_ENTER_API(FAIL)
10351
10352
    /* Check args */
10353
0
    if (NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
10354
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace");
10355
0
    if (H5S_SCALAR == H5S_GET_EXTENT_TYPE(space))
10356
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hyperslab doesn't support H5S_SCALAR space");
10357
0
    if (H5S_NULL == H5S_GET_EXTENT_TYPE(space))
10358
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hyperslab doesn't support H5S_NULL space");
10359
0
    if (start == NULL || count == NULL)
10360
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab not specified");
10361
0
    if (!(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID))
10362
0
        HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
10363
0
    if (stride != NULL) {
10364
0
        unsigned u; /* Local index variable */
10365
10366
        /* Check for 0-sized strides */
10367
0
        for (u = 0; u < space->extent.rank; u++)
10368
0
            if (stride[u] == 0)
10369
0
                HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid stride==0 value");
10370
0
    } /* end if */
10371
10372
0
    if (H5S_select_hyperslab(space, op, start, stride, count, block) < 0)
10373
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection");
10374
10375
0
done:
10376
0
    FUNC_LEAVE_API(ret_value)
10377
0
} /* end H5Sselect_hyperslab() */
10378
10379
/*--------------------------------------------------------------------------
10380
 NAME
10381
    H5S_combine_hyperslab
10382
 PURPOSE
10383
    Specify a hyperslab to combine with the current hyperslab selection, and
10384
    store the result in the new hyperslab selection.
10385
 USAGE
10386
    herr_t H5S_combine_hyperslab(old_space, op, start, stride, count, block, new_space)
10387
        H5S_t *old_space;            IN: The old space the selection is performed on
10388
        H5S_seloper_t op;            IN: Operation to perform on current selection
10389
        const hsize_t start[];       IN: Offset of start of hyperslab
10390
        const hsize_t *stride;       IN: Hyperslab stride
10391
        const hsize_t count[];       IN: Number of blocks included in hyperslab
10392
        const hsize_t *block;        IN: Size of block in hyperslab
10393
        H5S_t **new_space;           OUT: The new dataspace to store the selection result
10394
 RETURNS
10395
    Non-negative on success/Negative on failure
10396
 DESCRIPTION
10397
    Combines a hyperslab selection with the current selection for a dataspace.
10398
    If STRIDE or BLOCK is NULL, they are assumed to be set to all '1'.
10399
 GLOBAL VARIABLES
10400
 COMMENTS, BUGS, ASSUMPTIONS
10401
    In some cases, copying the whole span tree from old_space to new_space
10402
    can be avoided.  Deal with such cases directly, otherwise this function
10403
    is equivalent to:
10404
        1. Copy the whole span tree from old_space into new_space
10405
        2. Call H5S_select_hyperslab with the new_space.
10406
 EXAMPLES
10407
 REVISION LOG
10408
--------------------------------------------------------------------------*/
10409
herr_t
10410
H5S_combine_hyperslab(const H5S_t *old_space, H5S_seloper_t op, const hsize_t start[], const hsize_t *stride,
10411
                      const hsize_t count[], const hsize_t *block, H5S_t **new_space)
10412
0
{
10413
0
    unsigned u;                   /* Local index variable */
10414
0
    herr_t   ret_value = SUCCEED; /* Return value */
10415
10416
0
    FUNC_ENTER_NOAPI(FAIL)
10417
10418
    /* Check args */
10419
0
    assert(old_space);
10420
0
    assert(start);
10421
0
    assert(count);
10422
0
    assert(op >= H5S_SELECT_SET && op <= H5S_SELECT_NOTA);
10423
0
    assert(new_space);
10424
0
    assert(*new_space == NULL);
10425
10426
    /* Point to the correct stride values */
10427
0
    if (stride == NULL)
10428
0
        stride = H5S_hyper_ones_g;
10429
10430
    /* Point to the correct block values */
10431
0
    if (block == NULL)
10432
0
        block = H5S_hyper_ones_g;
10433
10434
    /* Check new selection. */
10435
0
    for (u = 0; u < old_space->extent.rank; u++) {
10436
        /* Check for overlapping hyperslab blocks in new selection. */
10437
0
        if (count[u] > 1 && stride[u] < block[u])
10438
0
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab blocks overlap");
10439
10440
        /* Detect zero-sized hyperslabs in new selection */
10441
0
        if (count[u] == 0 || block[u] == 0) {
10442
0
            switch (op) {
10443
0
                case H5S_SELECT_AND:  /* Binary "and" operation for hyperslabs */
10444
0
                case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */
10445
                    /* Convert to "none" selection */
10446
                    /* Copy the first dataspace without sharing the list of spans */
10447
0
                    if (NULL == ((*new_space) = H5S_copy(old_space, true, true)))
10448
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy dataspace");
10449
0
                    if (H5S_select_none((*new_space)) < 0)
10450
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection");
10451
0
                    HGOTO_DONE(SUCCEED);
10452
10453
0
                case H5S_SELECT_OR:   /* Binary "or" operation for hyperslabs */
10454
0
                case H5S_SELECT_XOR:  /* Binary "xor" operation for hyperslabs */
10455
0
                case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */
10456
                    /* Copy the first dataspace with sharing the list of spans */
10457
0
                    if (NULL == ((*new_space) = H5S_copy(old_space, false, true)))
10458
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy dataspace");
10459
0
                    HGOTO_DONE(SUCCEED); /* Selection stays same */
10460
10461
0
                case H5S_SELECT_NOOP:
10462
0
                case H5S_SELECT_SET:
10463
0
                case H5S_SELECT_APPEND:
10464
0
                case H5S_SELECT_PREPEND:
10465
0
                case H5S_SELECT_INVALID:
10466
0
                default:
10467
0
                    HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
10468
0
            } /* end switch */
10469
0
        }     /* end if */
10470
0
    }         /* end for */
10471
10472
0
    if (H5S_GET_SELECT_TYPE(old_space) == H5S_SEL_HYPERSLABS) {
10473
0
        hsize_t *old_low_bounds; /* Pointer to old space's low & high bounds */
10474
0
        hsize_t *old_high_bounds;
10475
0
        hsize_t  new_low_bounds[H5S_MAX_RANK]; /* New space's low & high bounds */
10476
0
        hsize_t  new_high_bounds[H5S_MAX_RANK];
10477
0
        bool     overlapped = false;
10478
10479
        /* Set up old space's low & high bounds */
10480
0
        if (old_space->select.sel_info.hslab->span_lst) {
10481
0
            old_low_bounds  = old_space->select.sel_info.hslab->span_lst->low_bounds;
10482
0
            old_high_bounds = old_space->select.sel_info.hslab->span_lst->high_bounds;
10483
0
        } /* end if */
10484
0
        else {
10485
0
            old_low_bounds  = old_space->select.sel_info.hslab->diminfo.low_bounds;
10486
0
            old_high_bounds = old_space->select.sel_info.hslab->diminfo.high_bounds;
10487
0
        } /* end else */
10488
10489
        /* Generate bounding box for hyperslab parameters */
10490
0
        for (u = 0; u < old_space->extent.rank; u++) {
10491
0
            new_low_bounds[u]  = start[u];
10492
0
            new_high_bounds[u] = start[u] + stride[u] * (count[u] - 1) + (block[u] - 1);
10493
0
        } /* end for */
10494
10495
        /* Check bound box of both spaces to see if they overlap */
10496
0
        if (H5_RANGE_OVERLAP(old_low_bounds[0], old_high_bounds[0], new_low_bounds[0], new_high_bounds[0]))
10497
0
            overlapped = true;
10498
10499
        /* Non-overlapping situations can be handled in special ways */
10500
0
        if (!overlapped) {
10501
0
            H5S_hyper_span_info_t *new_spans = NULL;
10502
0
            H5S_hyper_dim_t        new_hyper_diminfo[H5S_MAX_RANK];
10503
10504
0
            if (NULL == ((*new_space) = H5S_copy(old_space, true, true)))
10505
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy dataspace");
10506
0
            if (NULL != (*new_space)->select.sel_info.hslab->span_lst) {
10507
0
                old_space->select.sel_info.hslab->span_lst->count--;
10508
0
                (*new_space)->select.sel_info.hslab->span_lst = NULL;
10509
0
            } /* end if */
10510
10511
            /* Generate hyperslab info for new space */
10512
0
            switch (op) {
10513
0
                case H5S_SELECT_OR:
10514
0
                case H5S_SELECT_XOR:
10515
                    /* Add the new space to the space */
10516
0
                    if (NULL == (new_spans = H5S__hyper_make_spans(old_space->extent.rank, start, stride,
10517
0
                                                                   count, block)))
10518
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL,
10519
0
                                    "can't create hyperslab information");
10520
0
                    if (NULL != old_space->select.sel_info.hslab->span_lst)
10521
0
                        (*new_space)->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(
10522
0
                            old_space->select.sel_info.hslab->span_lst, old_space->extent.rank);
10523
0
                    if (H5S__hyper_add_disjoint_spans(*new_space, new_spans) < 0)
10524
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't append hyperslabs");
10525
10526
                    /* Build diminfo struct */
10527
0
                    for (u = 0; u < (*new_space)->extent.rank; u++) {
10528
0
                        new_hyper_diminfo[u].start  = start[u];
10529
0
                        new_hyper_diminfo[u].stride = stride[u];
10530
0
                        new_hyper_diminfo[u].count  = count[u];
10531
0
                        new_hyper_diminfo[u].block  = block[u];
10532
0
                    } /* end for */
10533
10534
                    /* Update space's dim info */
10535
0
                    if (H5S__hyper_update_diminfo(*new_space, op, new_hyper_diminfo) < 0)
10536
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't update hyperslab info");
10537
0
                    break;
10538
10539
0
                case H5S_SELECT_AND:
10540
0
                    if (H5S_select_none((*new_space)) < 0)
10541
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection");
10542
0
                    break;
10543
10544
0
                case H5S_SELECT_NOTB:
10545
0
                    if (NULL != old_space->select.sel_info.hslab->span_lst) {
10546
0
                        if (NULL == ((*new_space)->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(
10547
0
                                         old_space->select.sel_info.hslab->span_lst, old_space->extent.rank)))
10548
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy dataspace");
10549
0
                    } /* end if */
10550
0
                    else {
10551
0
                        if (H5S_select_none((*new_space)) < 0)
10552
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection");
10553
0
                    } /* end else */
10554
0
                    break;
10555
10556
0
                case H5S_SELECT_NOTA:
10557
0
                    if (H5S__set_regular_hyperslab(*new_space, start, stride, count, block, stride, count,
10558
0
                                                   block) < 0)
10559
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't set regular selection");
10560
0
                    break;
10561
10562
0
                case H5S_SELECT_NOOP:
10563
0
                case H5S_SELECT_SET:
10564
0
                case H5S_SELECT_APPEND:
10565
0
                case H5S_SELECT_PREPEND:
10566
0
                case H5S_SELECT_INVALID:
10567
0
                default:
10568
0
                    HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
10569
0
            } /* end switch */
10570
10571
0
            HGOTO_DONE(SUCCEED);
10572
0
        } /* end if(!overlapped) */
10573
0
    }     /* end if the selection of old space is H5S_SEL_HYPERSLABS */
10574
10575
    /* Copy the first dataspace with sharing the list of spans */
10576
0
    if (NULL == ((*new_space) = H5S_copy(old_space, true, true)))
10577
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy dataspace");
10578
10579
    /* Note: a little overhead in calling the function as some conditions are checked again */
10580
0
    if (H5S_select_hyperslab(*new_space, op, start, stride, count, block) < 0)
10581
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection");
10582
10583
0
done:
10584
0
    FUNC_LEAVE_NOAPI(ret_value)
10585
0
} /* end H5S_combine_hyperslab() */
10586
10587
/*-------------------------------------------------------------------------
10588
 * Function:    H5S__fill_in_select
10589
 *
10590
 * Purpose:    Combines two hyperslabs with an operation, putting the
10591
 *              result into a third hyperslab selection
10592
 *
10593
 * Return:    Non-negative on success/negative on failure
10594
 *
10595
 *-------------------------------------------------------------------------
10596
 */
10597
static herr_t
10598
H5S__fill_in_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2, H5S_t **result)
10599
0
{
10600
0
    bool   span2_owned;
10601
0
    bool   updated_spans;
10602
0
    herr_t ret_value = SUCCEED; /* Return value */
10603
10604
0
    FUNC_ENTER_PACKAGE
10605
10606
    /* Sanity check */
10607
0
    assert(space1);
10608
0
    assert(space2);
10609
0
    assert(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA);
10610
0
    assert(space1->extent.rank == space2->extent.rank);
10611
    /* The result is either a to-be-created space or an empty one */
10612
0
    assert(NULL == *result || *result == space1);
10613
0
    assert(space1->select.sel_info.hslab->span_lst);
10614
0
    assert(space2->select.sel_info.hslab->span_lst);
10615
10616
    /* Note: the offset of space2 is not considered here for bounding box */
10617
0
    if (H5S__fill_in_new_space(space1, op, space2->select.sel_info.hslab->span_lst, false, &span2_owned,
10618
0
                               &updated_spans, result) < 0)
10619
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't create the specified selection");
10620
10621
    /* Update diminfo if space2's diminfo was valid, otherwise just mark it as
10622
     * invalid if the spans were updated */
10623
0
    assert(result);
10624
0
    if (updated_spans) {
10625
0
        if (space2->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
10626
0
            if (H5S__hyper_update_diminfo(*result, op, space2->select.sel_info.hslab->diminfo.opt) < 0)
10627
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't update hyperslab info");
10628
0
        } /* end if */
10629
0
        else
10630
0
            (*result)->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
10631
0
    } /* end if */
10632
10633
0
done:
10634
0
    FUNC_LEAVE_NOAPI(ret_value)
10635
0
} /* end H5S__fill_in_select() */
10636
10637
/*--------------------------------------------------------------------------
10638
 NAME
10639
    H5Scombine_hyperslab
10640
 PURPOSE
10641
    Specify a hyperslab to combine with the current hyperslab selection and
10642
    return a new dataspace with the combined selection as the selection in the
10643
    new dataspace.
10644
 USAGE
10645
    hid_t H5Scombine_hyperslab(dsid, op, start, stride, count, block)
10646
        hid_t dsid;             IN: Dataspace ID of selection to use
10647
        H5S_seloper_t op;       IN: Operation to perform on current selection
10648
        const hsize_t *start;        IN: Offset of start of hyperslab
10649
        const hsize_t *stride;       IN: Hyperslab stride
10650
        const hsize_t *count;        IN: Number of blocks included in hyperslab
10651
        const hsize_t *block;        IN: Size of block in hyperslab
10652
 RETURNS
10653
    Dataspace ID on success / H5I_INVALID_HID on failure
10654
 DESCRIPTION
10655
    Combines a hyperslab selection with the current selection for a dataspace,
10656
    creating a new dataspace to return the generated selection.
10657
    If the current selection is not a hyperslab, it is freed and the hyperslab
10658
    parameters passed in are combined with the H5S_SEL_ALL hyperslab (ie. a
10659
    selection composing the entire current extent).  If STRIDE or BLOCK is
10660
    NULL, they are assumed to be set to all '1'.
10661
 GLOBAL VARIABLES
10662
 COMMENTS, BUGS, ASSUMPTIONS
10663
 EXAMPLES
10664
 REVISION LOG
10665
--------------------------------------------------------------------------*/
10666
hid_t
10667
H5Scombine_hyperslab(hid_t space_id, H5S_seloper_t op, const hsize_t start[], const hsize_t stride[],
10668
                     const hsize_t count[], const hsize_t block[])
10669
0
{
10670
0
    H5S_t *space;            /* Dataspace to modify selection of */
10671
0
    H5S_t *new_space = NULL; /* New dataspace created */
10672
0
    hid_t  ret_value;        /* Return value */
10673
10674
0
    FUNC_ENTER_API(H5I_INVALID_HID)
10675
10676
    /* Check args */
10677
0
    if (NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
10678
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not a dataspace");
10679
0
    if (start == NULL || count == NULL)
10680
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "hyperslab not specified");
10681
0
    if (!(op >= H5S_SELECT_SET && op <= H5S_SELECT_NOTA))
10682
0
        HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, H5I_INVALID_HID, "invalid selection operation");
10683
10684
    /* Generate new space, with combination of selections */
10685
0
    if (H5S_combine_hyperslab(space, op, start, stride, count, block, &new_space) < 0)
10686
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, H5I_INVALID_HID, "unable to set hyperslab selection");
10687
10688
    /* Register */
10689
0
    if ((ret_value = H5I_register(H5I_DATASPACE, new_space, true)) < 0)
10690
0
        HGOTO_ERROR(H5E_ID, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register dataspace ID");
10691
10692
0
done:
10693
0
    if (ret_value < 0 && new_space)
10694
0
        H5S_close(new_space);
10695
10696
0
    FUNC_LEAVE_API(ret_value)
10697
0
} /* end H5Scombine_hyperslab() */
10698
10699
/*-------------------------------------------------------------------------
10700
 * Function:    H5S__combine_select
10701
 *
10702
 * Purpose:     Internal version of H5Scombine_select().
10703
 *
10704
 * Return:      New dataspace on success/NULL on failure
10705
 *
10706
 *-------------------------------------------------------------------------
10707
 */
10708
static H5S_t *
10709
H5S__combine_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2)
10710
0
{
10711
0
    H5S_t *new_space = NULL; /* New dataspace generated */
10712
0
    H5S_t *ret_value = NULL; /* Return value */
10713
10714
0
    FUNC_ENTER_PACKAGE
10715
10716
    /* Check args */
10717
0
    assert(space1);
10718
0
    assert(space2);
10719
0
    assert(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA);
10720
10721
    /* Check if space1 selections has span trees */
10722
0
    if (NULL == space1->select.sel_info.hslab->span_lst)
10723
0
        if (H5S__hyper_generate_spans(space1) < 0)
10724
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, NULL, "dataspace does not have span tree");
10725
10726
0
    if (NULL == space2->select.sel_info.hslab->span_lst) {
10727
0
        hsize_t  tmp_start[H5S_MAX_RANK];
10728
0
        hsize_t  tmp_stride[H5S_MAX_RANK];
10729
0
        hsize_t  tmp_count[H5S_MAX_RANK];
10730
0
        hsize_t  tmp_block[H5S_MAX_RANK];
10731
0
        unsigned u;
10732
10733
0
        for (u = 0; u < space2->extent.rank; u++) {
10734
0
            tmp_start[u]  = space2->select.sel_info.hslab->diminfo.opt[u].start;
10735
0
            tmp_stride[u] = space2->select.sel_info.hslab->diminfo.opt[u].stride;
10736
0
            tmp_count[u]  = space2->select.sel_info.hslab->diminfo.opt[u].count;
10737
0
            tmp_block[u]  = space2->select.sel_info.hslab->diminfo.opt[u].block;
10738
0
        } /* end for */
10739
10740
        /* Combine hyperslab selection with regular selection directly */
10741
0
        if (H5S_combine_hyperslab(space1, op, tmp_start, tmp_stride, tmp_count, tmp_block, &new_space) < 0)
10742
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, NULL, "unable to set hyperslab selection");
10743
0
    } /* end if */
10744
0
    else {
10745
        /* Combine new_space (a copy of space 1) & space2, with the result in new_space */
10746
0
        if (H5S__fill_in_select(space1, op, space2, &new_space) < 0)
10747
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, NULL, "can't clip hyperslab information");
10748
0
    } /* end else */
10749
10750
    /* Set unlim_dim */
10751
0
    if (H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(new_space))
10752
0
        new_space->select.sel_info.hslab->unlim_dim = -1;
10753
10754
    /* Set return value */
10755
0
    ret_value = new_space;
10756
10757
0
done:
10758
0
    if (ret_value == NULL && new_space)
10759
0
        H5S_close(new_space);
10760
10761
0
    FUNC_LEAVE_NOAPI(ret_value)
10762
0
} /* end H5S__combine_select() */
10763
10764
/*--------------------------------------------------------------------------
10765
 NAME
10766
    H5Scombine_select
10767
 PURPOSE
10768
    Combine two hyperslab selections with an operation, returning a dataspace
10769
    with the resulting selection.
10770
 USAGE
10771
    hid_t H5Scombine_select(space1, op, space2)
10772
        hid_t space1;           IN: First Dataspace ID
10773
        H5S_seloper_t op;       IN: Selection operation
10774
        hid_t space2;           IN: Second Dataspace ID
10775
 RETURNS
10776
    Dataspace ID on success / H5I_INVALID_HID on failure
10777
 DESCRIPTION
10778
    Combine two existing hyperslab selections with an operation, returning
10779
    a new dataspace with the resulting selection.  The dataspace extent from
10780
    space1 is copied for the dataspace extent of the newly created dataspace.
10781
 GLOBAL VARIABLES
10782
 COMMENTS, BUGS, ASSUMPTIONS
10783
 EXAMPLES
10784
 REVISION LOG
10785
--------------------------------------------------------------------------*/
10786
hid_t
10787
H5Scombine_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id)
10788
0
{
10789
0
    H5S_t *space1;           /* First Dataspace */
10790
0
    H5S_t *space2;           /* Second Dataspace */
10791
0
    H5S_t *new_space = NULL; /* New Dataspace */
10792
0
    hid_t  ret_value;        /* Return value */
10793
10794
0
    FUNC_ENTER_API(H5I_INVALID_HID)
10795
10796
    /* Check args */
10797
0
    if (NULL == (space1 = (H5S_t *)H5I_object_verify(space1_id, H5I_DATASPACE)))
10798
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not a dataspace");
10799
0
    if (NULL == (space2 = (H5S_t *)H5I_object_verify(space2_id, H5I_DATASPACE)))
10800
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not a dataspace");
10801
0
    if (!(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA))
10802
0
        HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, H5I_INVALID_HID, "invalid selection operation");
10803
10804
    /* Check that both dataspaces have the same rank */
10805
0
    if (space1->extent.rank != space2->extent.rank)
10806
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "dataspaces not same rank");
10807
10808
        /* Note: currently, the offset of each dataspace is ignored */
10809
#if 0
10810
    /* Check that both dataspaces have the same offset */
10811
    /* Same note as in H5Smodify_select */
10812
    for(u=0; u<space1->extent.rank; u++) {
10813
        if(space1->select.offset[u] != space2->select.offset[u])
10814
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "dataspaces not same offset");
10815
    } /* end for */
10816
#endif
10817
10818
    /* Check that both dataspaces have hyperslab selections */
10819
0
    if (H5S_GET_SELECT_TYPE(space1) != H5S_SEL_HYPERSLABS ||
10820
0
        H5S_GET_SELECT_TYPE(space2) != H5S_SEL_HYPERSLABS)
10821
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "dataspaces don't have hyperslab selections");
10822
10823
    /* Go combine the dataspaces */
10824
0
    if (NULL == (new_space = H5S__combine_select(space1, op, space2)))
10825
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, H5I_INVALID_HID, "unable to create hyperslab selection");
10826
10827
    /* Register */
10828
0
    if ((ret_value = H5I_register(H5I_DATASPACE, new_space, true)) < 0)
10829
0
        HGOTO_ERROR(H5E_ID, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register dataspace ID");
10830
10831
0
done:
10832
0
    if (ret_value < 0 && new_space)
10833
0
        H5S_close(new_space);
10834
10835
0
    FUNC_LEAVE_API(ret_value)
10836
0
} /* end H5Scombine_select() */
10837
10838
/*-------------------------------------------------------------------------
10839
 * Function:    H5S__modify_select
10840
 *
10841
 * Purpose:     Internal version of H5Smodify_select().
10842
 *
10843
 * Return:      New dataspace on success/NULL on failure
10844
 *
10845
 *-------------------------------------------------------------------------
10846
 */
10847
herr_t
10848
H5S__modify_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2)
10849
0
{
10850
0
    herr_t ret_value = SUCCEED; /* Return value */
10851
10852
0
    FUNC_ENTER_PACKAGE
10853
10854
    /* Check args */
10855
0
    assert(space1);
10856
0
    assert(space2);
10857
0
    assert(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA);
10858
10859
    /* Check that the space selections both have span trees */
10860
0
    if (NULL == space1->select.sel_info.hslab->span_lst)
10861
0
        if (H5S__hyper_generate_spans(space1) < 0)
10862
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree");
10863
10864
    /* Set unlim_dim */
10865
0
    space1->select.sel_info.hslab->unlim_dim = -1;
10866
10867
0
    if (NULL == space2->select.sel_info.hslab->span_lst) {
10868
0
        hsize_t  tmp_start[H5S_MAX_RANK];
10869
0
        hsize_t  tmp_stride[H5S_MAX_RANK];
10870
0
        hsize_t  tmp_count[H5S_MAX_RANK];
10871
0
        hsize_t  tmp_block[H5S_MAX_RANK];
10872
0
        unsigned u;
10873
10874
0
        for (u = 0; u < space2->extent.rank; u++) {
10875
0
            tmp_start[u]  = space2->select.sel_info.hslab->diminfo.opt[u].start;
10876
0
            tmp_stride[u] = space2->select.sel_info.hslab->diminfo.opt[u].stride;
10877
0
            tmp_count[u]  = space2->select.sel_info.hslab->diminfo.opt[u].count;
10878
0
            tmp_block[u]  = space2->select.sel_info.hslab->diminfo.opt[u].block;
10879
0
        } /* end for */
10880
10881
        /* Call H5S_select_hyperslab directly */
10882
0
        if (H5S_select_hyperslab(space1, op, tmp_start, tmp_stride, tmp_count, tmp_block) < 0)
10883
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection");
10884
0
    } /* end if */
10885
0
    else
10886
        /* Combine spans from space1 & spans from space2, with the result in space1 */
10887
0
        if (H5S__fill_in_select(space1, op, space2, &space1) < 0)
10888
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't perform operation on two selections");
10889
10890
0
done:
10891
0
    FUNC_LEAVE_NOAPI(ret_value)
10892
0
} /* end H5S__modify_select() */
10893
10894
/*--------------------------------------------------------------------------
10895
 NAME
10896
    H5Smodify_select
10897
 PURPOSE
10898
    Refine a hyperslab selection with an operation using a second hyperslab
10899
    to modify it
10900
 USAGE
10901
    herr_t H5Smodify_select(space1, op, space2)
10902
        hid_t space1;           IN/OUT: First Dataspace ID
10903
        H5S_seloper_t op;       IN: Selection operation
10904
        hid_t space2;           IN: Second Dataspace ID
10905
 RETURNS
10906
    Non-negative on success/Negative on failure
10907
 DESCRIPTION
10908
    Refine an existing hyperslab selection with an operation, using a second
10909
    hyperslab.  The first selection is modified to contain the result of
10910
    space1 operated on by space2.
10911
 GLOBAL VARIABLES
10912
 COMMENTS, BUGS, ASSUMPTIONS
10913
 EXAMPLES
10914
 REVISION LOG
10915
--------------------------------------------------------------------------*/
10916
herr_t
10917
H5Smodify_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id)
10918
0
{
10919
0
    H5S_t *space1;              /* First Dataspace */
10920
0
    H5S_t *space2;              /* Second Dataspace */
10921
0
    herr_t ret_value = SUCCEED; /* Return value */
10922
10923
0
    FUNC_ENTER_API(FAIL)
10924
10925
    /* Check args */
10926
0
    if (NULL == (space1 = (H5S_t *)H5I_object_verify(space1_id, H5I_DATASPACE)))
10927
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace");
10928
0
    if (NULL == (space2 = (H5S_t *)H5I_object_verify(space2_id, H5I_DATASPACE)))
10929
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace");
10930
0
    if (!(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA))
10931
0
        HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
10932
10933
    /* Check that both dataspaces have the same rank */
10934
0
    if (space1->extent.rank != space2->extent.rank)
10935
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces not same rank");
10936
10937
        /* Check that both dataspaces have the same offset */
10938
        /** Note that this is a tricky part of this function. It's
10939
         *  possible that two dataspaces have different "offset". If the
10940
         *  space2 has smaller offset value than that of space1 in a
10941
         *  dimension, then the span elements of this dimension in
10942
         *  space2 could have negative "low" and "high" values relative
10943
         *  to the offset in space1. In other words, if the bounds of
10944
         *  span elements in space2 are adjusted relative to the offset
10945
         *  in space1, then every span element's bound is computed as
10946
         *  "origin_bound+offset2-offset1". Therefore, if offset2 (the
10947
         *  offset of space2) is smaller, then
10948
         *  "origin_bound+offset2-offset1" could be negative which is
10949
         *  not allowed by the bound type declaration as hsize_t!
10950
         *  As a result, if the op is an OR selection, then the final
10951
         *  result may contain span elements that have negative bound!
10952
         *  So right now, the difference in the offset is totally
10953
         *  ignored!!
10954
         */
10955
#if 0
10956
    for(u=0; u<space1->extent.rank; u++) {
10957
        if(space1->select.offset[u] != space2->select.offset[u])
10958
            HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces not same offset");
10959
    } /* end for */
10960
#endif
10961
10962
    /* Check that both dataspaces have hyperslab selections */
10963
0
    if (H5S_GET_SELECT_TYPE(space1) != H5S_SEL_HYPERSLABS ||
10964
0
        H5S_GET_SELECT_TYPE(space2) != H5S_SEL_HYPERSLABS)
10965
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces don't have hyperslab selections");
10966
10967
    /* Go refine the first selection */
10968
0
    if (H5S__modify_select(space1, op, space2) < 0)
10969
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to modify hyperslab selection");
10970
10971
0
done:
10972
0
    FUNC_LEAVE_API(ret_value)
10973
0
} /* end H5Smodify_select() */
10974
10975
/*--------------------------------------------------------------------------
10976
 NAME
10977
    H5S__hyper_proj_int_build_proj
10978
 PURPOSE
10979
    Secondary iteration routine for H5S__hyper_project_intersection
10980
 USAGE
10981
    herr_t H5S__hyper_proj_int_build_proj(udata)
10982
        H5S_hyper_project_intersect_ud_t *udata; IN/OUT: Persistent shared data for iteration
10983
 RETURNS
10984
    Non-negative on success/Negative on failure.
10985
 DESCRIPTION
10986
    Takes the skip and nelem amounts listed in udata and converts them to
10987
    span trees in the projected space, using the destination space.  This
10988
    is a non-recursive algorithm by necessity, it saves the current state
10989
    of iteration in udata and resumes in the same location on subsequent
10990
    calls.
10991
 GLOBAL VARIABLES
10992
 COMMENTS, BUGS, ASSUMPTIONS
10993
 EXAMPLES
10994
 REVISION LOG
10995
--------------------------------------------------------------------------*/
10996
static herr_t
10997
H5S__hyper_proj_int_build_proj(H5S_hyper_project_intersect_ud_t *udata)
10998
0
{
10999
0
    H5S_hyper_span_info_t *copied_span_info = NULL;    /* Temporary span info pointer */
11000
0
    herr_t                 ret_value        = SUCCEED; /* Return value */
11001
11002
0
    FUNC_ENTER_PACKAGE
11003
11004
0
    assert(udata->nelem > 0);
11005
11006
    /*
11007
     * Skip over skipped elements
11008
     */
11009
0
    if (udata->skip > 0) {
11010
        /* Work upwards, finishing each span tree before moving up */
11011
0
        assert(udata->ds_span[udata->depth]);
11012
0
        do {
11013
            /* Check for lowest dimension */
11014
0
            if (udata->ds_span[udata->depth]->down) {
11015
0
                if (udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high) {
11016
                    /* If we will run out of elements to skip in this span,
11017
                     * advance to the first not fully skipped span and break
11018
                     * out of this loop (start moving downwards) */
11019
0
                    if (udata->skip <
11020
0
                        H5S__hyper_spans_nelem_helper(udata->ds_span[udata->depth]->down, 0, udata->op_gen) *
11021
0
                            (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
11022
0
                        udata->ds_low[udata->depth] +=
11023
0
                            udata->skip / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
11024
0
                        udata->skip %= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
11025
0
                        break;
11026
0
                    } /* end if */
11027
11028
                    /* Skip over this entire span */
11029
0
                    udata->skip -= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts *
11030
0
                                   (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1);
11031
0
                } /* end if */
11032
0
            }     /* end if */
11033
0
            else {
11034
0
                assert(udata->ds_rank - udata->depth == 1);
11035
11036
                /* If we will run out of elements to skip in this span,
11037
                 * skip the remainder of the skipped elements and break out */
11038
0
                assert(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high);
11039
0
                if (udata->skip < (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
11040
0
                    udata->ds_low[udata->depth] += udata->skip;
11041
0
                    udata->skip = 0;
11042
0
                    break;
11043
0
                } /* end if */
11044
11045
                /* Skip over this entire span */
11046
0
                udata->skip -= udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1;
11047
0
            } /* end else */
11048
11049
            /* Advance to next span */
11050
0
            udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next;
11051
0
            if (udata->ds_span[udata->depth])
11052
0
                udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
11053
0
            else if (udata->depth > 0) {
11054
                /* If present, append this span tree to the higher dimension's,
11055
                 * and release ownership of it */
11056
0
                if (udata->ps_span_info[udata->depth]) {
11057
0
                    if (H5S__hyper_append_span(
11058
0
                            &udata->ps_span_info[udata->depth - 1], udata->ds_rank - udata->depth + 1,
11059
0
                            udata->ds_low[udata->depth - 1], udata->ds_low[udata->depth - 1],
11060
0
                            udata->ps_span_info[udata->depth]) < 0)
11061
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11062
0
                    if (H5S__hyper_free_span_info(udata->ps_span_info[udata->depth]) < 0)
11063
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11064
0
                    udata->ps_span_info[udata->depth] = NULL;
11065
0
                }
11066
11067
                /* Ran out of spans, move up one dimension */
11068
0
                udata->depth--;
11069
0
                assert(udata->ds_span[udata->depth]);
11070
0
                udata->ds_low[udata->depth]++;
11071
0
            }
11072
0
            else
11073
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL,
11074
0
                            "insufficient elements in destination selection");
11075
0
        } while ((udata->skip > 0) || (udata->ds_low[udata->depth] > udata->ds_span[udata->depth]->high));
11076
11077
        /* Work downwards until skip is 0 */
11078
0
        assert(udata->ds_span[udata->depth]);
11079
0
        while (udata->skip > 0) {
11080
0
            assert(udata->ds_span[udata->depth]->down);
11081
0
            udata->depth++;
11082
0
            udata->ds_span[udata->depth] = udata->ds_span[udata->depth - 1]->down->head;
11083
0
            udata->ds_low[udata->depth]  = udata->ds_span[udata->depth]->low;
11084
0
            if (udata->ds_span[udata->depth]->down) {
11085
0
                do {
11086
                    /* If we will run out of elements to skip in this span,
11087
                     * advance to the first not fully skipped span and
11088
                     * continue down */
11089
0
                    if (udata->skip <
11090
0
                        H5S__hyper_spans_nelem_helper(udata->ds_span[udata->depth]->down, 0, udata->op_gen) *
11091
0
                            (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
11092
0
                        udata->ds_low[udata->depth] +=
11093
0
                            udata->skip / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
11094
0
                        udata->skip %= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
11095
0
                        break;
11096
0
                    } /* end if */
11097
11098
                    /* Skip over this entire span */
11099
0
                    udata->skip -= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts *
11100
0
                                   (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1);
11101
11102
                    /* Advance to next span */
11103
0
                    udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next;
11104
0
                    assert(udata->ds_span[udata->depth]);
11105
0
                    udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
11106
0
                } while (udata->skip > 0);
11107
0
            } /* end if */
11108
0
            else {
11109
0
                do {
11110
                    /* If we will run out of elements to skip in this span,
11111
                     * skip the remainder of the skipped elements */
11112
0
                    if (udata->skip <
11113
0
                        (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
11114
0
                        udata->ds_low[udata->depth] += udata->skip;
11115
0
                        udata->skip = 0;
11116
0
                        break;
11117
0
                    } /* end if */
11118
11119
                    /* Skip over this entire span */
11120
0
                    udata->skip -= udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1;
11121
11122
                    /* Advance to next span */
11123
0
                    udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next;
11124
0
                    assert(udata->ds_span[udata->depth]);
11125
0
                    udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
11126
0
                } while (udata->skip > 0);
11127
0
            } /* end else */
11128
0
        }     /* end while */
11129
0
    }         /* end if */
11130
11131
    /*
11132
     * Add requested number of elements to projected space
11133
     */
11134
    /* Work upwards, adding all elements of each span tree until it can't fit
11135
     * all elements */
11136
0
    assert(udata->ds_span[udata->depth]);
11137
0
    do {
11138
        /* Check for lowest dimension */
11139
0
        if (udata->ds_span[udata->depth]->down) {
11140
0
            if (udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high) {
11141
                /* If we will run out of elements to add in this span, add
11142
                 * any complete spans, advance to the first not fully added
11143
                 * span, and break out of this loop (start moving downwards)
11144
                 */
11145
0
                if (udata->nelem <
11146
0
                    H5S__hyper_spans_nelem_helper(udata->ds_span[udata->depth]->down, 0, udata->op_gen) *
11147
0
                        (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
11148
0
                    if (udata->nelem >= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) {
11149
0
                        if (udata->share_selection) {
11150
0
                            if (H5S__hyper_append_span(
11151
0
                                    &udata->ps_span_info[udata->depth], udata->ds_rank - udata->depth,
11152
0
                                    udata->ds_low[udata->depth],
11153
0
                                    udata->ds_low[udata->depth] +
11154
0
                                        (udata->nelem /
11155
0
                                         udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) -
11156
0
                                        1,
11157
0
                                    udata->ds_span[udata->depth]->down) < 0)
11158
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
11159
0
                                            "can't allocate hyperslab span");
11160
0
                        }
11161
0
                        else {
11162
                            /* If we're not sharing the destination space's
11163
                             * spans, we must copy it first (then release it
11164
                             * afterwards) */
11165
0
                            if (NULL == (copied_span_info = H5S__hyper_copy_span_helper(
11166
0
                                             udata->ds_span[udata->depth]->down,
11167
0
                                             udata->ds_rank - udata->depth, 1, udata->op_gen)))
11168
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL,
11169
0
                                            "can't copy destination spans");
11170
0
                            if (H5S__hyper_append_span(
11171
0
                                    &udata->ps_span_info[udata->depth], udata->ds_rank - udata->depth,
11172
0
                                    udata->ds_low[udata->depth],
11173
0
                                    udata->ds_low[udata->depth] +
11174
0
                                        (udata->nelem /
11175
0
                                         udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) -
11176
0
                                        1,
11177
0
                                    copied_span_info) < 0)
11178
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
11179
0
                                            "can't allocate hyperslab span");
11180
0
                            if (H5S__hyper_free_span_info(copied_span_info) < 0)
11181
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11182
0
                            copied_span_info = NULL;
11183
0
                        }
11184
0
                        udata->ds_low[udata->depth] +=
11185
0
                            udata->nelem / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
11186
0
                        udata->nelem %= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
11187
0
                    } /* end if */
11188
0
                    break;
11189
0
                } /* end if */
11190
11191
                /* Append span tree for entire span */
11192
0
                if (udata->share_selection) {
11193
0
                    if (H5S__hyper_append_span(&udata->ps_span_info[udata->depth],
11194
0
                                               udata->ds_rank - udata->depth, udata->ds_low[udata->depth],
11195
0
                                               udata->ds_span[udata->depth]->high,
11196
0
                                               udata->ds_span[udata->depth]->down) < 0)
11197
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11198
0
                }
11199
0
                else {
11200
                    /* If we're not sharing the destination space's
11201
                     * spans, we must copy it first (then release it
11202
                     * afterwards) */
11203
0
                    if (NULL == (copied_span_info = H5S__hyper_copy_span_helper(
11204
0
                                     udata->ds_span[udata->depth]->down, udata->ds_rank - udata->depth, 1,
11205
0
                                     udata->op_gen)))
11206
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy destination spans");
11207
0
                    if (H5S__hyper_append_span(&udata->ps_span_info[udata->depth],
11208
0
                                               udata->ds_rank - udata->depth, udata->ds_low[udata->depth],
11209
0
                                               udata->ds_span[udata->depth]->high, copied_span_info) < 0)
11210
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11211
0
                    if (H5S__hyper_free_span_info(copied_span_info) < 0)
11212
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11213
0
                    copied_span_info = NULL;
11214
0
                }
11215
0
                udata->nelem -= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts *
11216
0
                                (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1);
11217
0
            } /* end if */
11218
0
        }     /* end if */
11219
0
        else {
11220
0
            assert(udata->ds_rank - udata->depth == 1);
11221
11222
            /* If we will run out of elements to add in this span, add the
11223
             * remainder of the elements and break out */
11224
0
            assert(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high);
11225
0
            if (udata->nelem < (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
11226
0
                if (H5S__hyper_append_span(&udata->ps_span_info[udata->depth], 1, udata->ds_low[udata->depth],
11227
0
                                           udata->ds_low[udata->depth] + udata->nelem - 1, NULL) < 0)
11228
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11229
0
                udata->ds_low[udata->depth] += udata->nelem;
11230
0
                udata->nelem = 0;
11231
0
                break;
11232
0
            } /* end if */
11233
11234
            /* Append span tree for entire span */
11235
0
            if (H5S__hyper_append_span(&udata->ps_span_info[udata->depth], 1, udata->ds_low[udata->depth],
11236
0
                                       udata->ds_span[udata->depth]->high, NULL) < 0)
11237
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11238
0
            udata->nelem -= udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1;
11239
0
        } /* end else */
11240
11241
        /* Advance to next span */
11242
0
        udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next;
11243
0
        if (udata->ds_span[udata->depth])
11244
0
            udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
11245
0
        else if (udata->depth > 0) {
11246
            /* Append this span tree to the higher dimension's, and release
11247
             * ownership of it */
11248
0
            assert(udata->ps_span_info[udata->depth]);
11249
0
            if (H5S__hyper_append_span(&udata->ps_span_info[udata->depth - 1],
11250
0
                                       udata->ds_rank - udata->depth + 1, udata->ds_low[udata->depth - 1],
11251
0
                                       udata->ds_low[udata->depth - 1],
11252
0
                                       udata->ps_span_info[udata->depth]) < 0)
11253
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11254
0
            if (H5S__hyper_free_span_info(udata->ps_span_info[udata->depth]) < 0)
11255
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11256
0
            udata->ps_span_info[udata->depth] = NULL;
11257
11258
            /* Ran out of spans, move up one dimension */
11259
0
            udata->depth--;
11260
0
            assert(udata->ds_span[udata->depth]);
11261
0
            udata->ds_low[udata->depth]++;
11262
0
        } /* end if */
11263
0
        else {
11264
            /* We have finished the entire destination span tree.  If there are
11265
             * still elements to add, issue an error. */
11266
0
            if (udata->nelem > 0)
11267
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL,
11268
0
                            "insufficient elements in destination selection");
11269
0
            break;
11270
0
        } /* end else */
11271
0
    } while ((udata->nelem > 0) || (udata->ds_low[udata->depth] > udata->ds_span[udata->depth]->high));
11272
11273
    /* Work downwards until nelem is 0 */
11274
0
    assert(udata->ds_span[udata->depth] || (udata->nelem == 0));
11275
0
    while (udata->nelem > 0) {
11276
0
        assert(udata->ds_span[udata->depth]->down);
11277
0
        udata->depth++;
11278
0
        udata->ds_span[udata->depth] = udata->ds_span[udata->depth - 1]->down->head;
11279
0
        udata->ds_low[udata->depth]  = udata->ds_span[udata->depth]->low;
11280
0
        if (udata->ds_span[udata->depth]->down) {
11281
0
            do {
11282
                /* If we will run out of elements to add in this span, add
11283
                 * any complete spans, advance to the first not fully added
11284
                 * span and continue down
11285
                 */
11286
0
                assert(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high);
11287
0
                if (udata->nelem <
11288
0
                    H5S__hyper_spans_nelem_helper(udata->ds_span[udata->depth]->down, 0, udata->op_gen) *
11289
0
                        (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
11290
0
                    if (udata->nelem >= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) {
11291
0
                        if (udata->share_selection) {
11292
0
                            if (H5S__hyper_append_span(
11293
0
                                    &udata->ps_span_info[udata->depth], udata->ds_rank - udata->depth,
11294
0
                                    udata->ds_low[udata->depth],
11295
0
                                    udata->ds_low[udata->depth] +
11296
0
                                        (udata->nelem /
11297
0
                                         udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) -
11298
0
                                        1,
11299
0
                                    udata->ds_span[udata->depth]->down) < 0)
11300
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
11301
0
                                            "can't allocate hyperslab span");
11302
0
                        }
11303
0
                        else {
11304
                            /* If we're not sharing the destination space's
11305
                             * spans, we must copy it first (then release it
11306
                             * afterwards) */
11307
0
                            if (NULL == (copied_span_info = H5S__hyper_copy_span_helper(
11308
0
                                             udata->ds_span[udata->depth]->down,
11309
0
                                             udata->ds_rank - udata->depth, 1, udata->op_gen)))
11310
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL,
11311
0
                                            "can't copy destination spans");
11312
0
                            if (H5S__hyper_append_span(
11313
0
                                    &udata->ps_span_info[udata->depth], udata->ds_rank - udata->depth,
11314
0
                                    udata->ds_low[udata->depth],
11315
0
                                    udata->ds_low[udata->depth] +
11316
0
                                        (udata->nelem /
11317
0
                                         udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) -
11318
0
                                        1,
11319
0
                                    copied_span_info) < 0)
11320
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL,
11321
0
                                            "can't allocate hyperslab span");
11322
0
                            if (H5S__hyper_free_span_info(copied_span_info) < 0)
11323
0
                                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11324
0
                            copied_span_info = NULL;
11325
0
                        }
11326
0
                        udata->ds_low[udata->depth] +=
11327
0
                            udata->nelem / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
11328
0
                        udata->nelem %= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
11329
0
                    } /* end if */
11330
0
                    break;
11331
0
                } /* end if */
11332
11333
                /* Append span tree for entire span */
11334
0
                if (udata->share_selection) {
11335
0
                    if (H5S__hyper_append_span(&udata->ps_span_info[udata->depth],
11336
0
                                               udata->ds_rank - udata->depth, udata->ds_low[udata->depth],
11337
0
                                               udata->ds_span[udata->depth]->high,
11338
0
                                               udata->ds_span[udata->depth]->down) < 0)
11339
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11340
0
                }
11341
0
                else {
11342
                    /* If we're not sharing the destination space's
11343
                     * spans, we must copy it first (then release it
11344
                     * afterwards) */
11345
0
                    if (NULL == (copied_span_info = H5S__hyper_copy_span_helper(
11346
0
                                     udata->ds_span[udata->depth]->down, udata->ds_rank - udata->depth, 1,
11347
0
                                     udata->op_gen)))
11348
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy destination spans");
11349
0
                    if (H5S__hyper_append_span(&udata->ps_span_info[udata->depth],
11350
0
                                               udata->ds_rank - udata->depth, udata->ds_low[udata->depth],
11351
0
                                               udata->ds_span[udata->depth]->high, copied_span_info) < 0)
11352
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11353
0
                    if (H5S__hyper_free_span_info(copied_span_info) < 0)
11354
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11355
0
                    copied_span_info = NULL;
11356
0
                }
11357
0
                udata->nelem -= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts *
11358
0
                                (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1);
11359
11360
                /* Advance to next span */
11361
0
                udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next;
11362
0
                assert(udata->ds_span[udata->depth]);
11363
0
                udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
11364
0
            } while (udata->nelem > 0);
11365
0
        } /* end if */
11366
0
        else {
11367
0
            assert(udata->ds_rank - udata->depth == 1);
11368
0
            do {
11369
                /* If we will run out of elements to add in this span, add
11370
                 * the remainder of the elements and break out */
11371
0
                assert(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high);
11372
0
                if (udata->nelem < (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
11373
0
                    if (H5S__hyper_append_span(&udata->ps_span_info[udata->depth], 1,
11374
0
                                               udata->ds_low[udata->depth],
11375
0
                                               udata->ds_low[udata->depth] + udata->nelem - 1, NULL) < 0)
11376
0
                        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11377
0
                    udata->ds_low[udata->depth] += udata->nelem;
11378
0
                    udata->nelem = 0;
11379
0
                    break;
11380
0
                } /* end if */
11381
11382
                /* Append span tree for entire span */
11383
0
                if (H5S__hyper_append_span(&udata->ps_span_info[udata->depth], 1, udata->ds_low[udata->depth],
11384
0
                                           udata->ds_span[udata->depth]->high, NULL) < 0)
11385
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11386
0
                udata->nelem -= udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1;
11387
11388
                /* Advance to next span */
11389
0
                udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next;
11390
0
                assert(udata->ds_span[udata->depth]);
11391
0
                udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
11392
0
            } while (udata->nelem > 0);
11393
0
        } /* end else */
11394
0
    }     /* end while */
11395
11396
0
    assert(udata->skip == 0);
11397
0
    assert(udata->nelem == 0);
11398
11399
    /* Mark projected space as changed (for all ranks) */
11400
0
    udata->ps_clean_bitmap = 0;
11401
11402
0
done:
11403
    /* Cleanup on failure */
11404
0
    if (copied_span_info) {
11405
0
        assert(ret_value < 0);
11406
0
        if (H5S__hyper_free_span_info(copied_span_info) < 0)
11407
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11408
0
        copied_span_info = NULL;
11409
0
    }
11410
11411
0
    FUNC_LEAVE_NOAPI(ret_value)
11412
0
} /* end H5S__hyper_proj_int_build_proj() */
11413
11414
/*--------------------------------------------------------------------------
11415
 NAME
11416
    H5S__hyper_proj_int_iterate
11417
 PURPOSE
11418
    Main iteration routine for H5S__hyper_project_intersection
11419
 USAGE
11420
    herr_t H5S__hyper_proj_int_iterate(ss_span_info,sis_span_info,count,depth,udata)
11421
        const H5S_hyper_span_info_t *ss_span_info; IN: Span tree for source selection
11422
        const H5S_hyper_span_info_t *sis_span_info; IN: Span tree for source intersect selection
11423
        hsize_t count;          IN: Number of times to compute the intersection of ss_span_info and
11424
sis_span_info unsigned depth;         IN: Depth of iteration (in terms of rank)
11425
        H5S_hyper_project_intersect_ud_t *udata; IN/OUT: Persistent shared data for iteration
11426
 RETURNS
11427
    Non-negative on success/Negative on failure.
11428
 DESCRIPTION
11429
    Computes the intersection of ss_span_info and sis_span_info and projects it
11430
    to the projected space (held in udata).  It accomplishes this by iterating
11431
    over both spaces and computing the number of elements to skip (in
11432
    ss_span_info) and the number of elements to add (the intersection) in a
11433
    sequential fashion (similar to run length encoding).  As necessary, this
11434
    function both recurses into lower dimensions and calls
11435
    H5S__hyper_proj_int_build_proj to convert the skip/nelem pairs to the
11436
    projected span tree.
11437
 GLOBAL VARIABLES
11438
 COMMENTS, BUGS, ASSUMPTIONS
11439
 EXAMPLES
11440
 REVISION LOG
11441
--------------------------------------------------------------------------*/
11442
static herr_t
11443
H5S__hyper_proj_int_iterate(H5S_hyper_span_info_t *ss_span_info, const H5S_hyper_span_info_t *sis_span_info,
11444
                            hsize_t count, unsigned depth, H5S_hyper_project_intersect_ud_t *udata)
11445
0
{
11446
0
    const H5S_hyper_span_t *ss_span;             /* Current span in source space */
11447
0
    const H5S_hyper_span_t *sis_span;            /* Current span in source intersect space */
11448
0
    hsize_t                 ss_low;              /* Current low bounds of source span */
11449
0
    hsize_t                 sis_low;             /* Current low bounds of source intersect span */
11450
0
    hsize_t                 high;                /* High bounds of current intersection */
11451
0
    hsize_t                 low;                 /* Low bounds of current intersection */
11452
0
    hsize_t                 old_skip;            /* Value of udata->skip before main loop */
11453
0
    hsize_t                 old_nelem;           /* Value of udata->nelem before main loop */
11454
0
    bool                    check_intersect;     /* Whether to check for intersecting elements */
11455
0
    unsigned                u;                   /* Local index variable */
11456
0
    herr_t                  ret_value = SUCCEED; /* Return value */
11457
11458
0
    FUNC_ENTER_PACKAGE
11459
11460
    /* Check for non-overlapping bounds */
11461
0
    check_intersect = true;
11462
0
    for (u = 0; u < (udata->ss_rank - depth); u++)
11463
0
        if (!H5_RANGE_OVERLAP(ss_span_info->low_bounds[u], ss_span_info->high_bounds[u],
11464
0
                              sis_span_info->low_bounds[u], sis_span_info->high_bounds[u])) {
11465
0
            check_intersect = false;
11466
0
            break;
11467
0
        } /* end if */
11468
11469
    /* Only enter main loop if there's something to do */
11470
0
    if (check_intersect) {
11471
        /* Set ps_clean_bitmap */
11472
0
        udata->ps_clean_bitmap |= (((uint32_t)1) << depth);
11473
11474
        /* Save old skip and nelem */
11475
0
        old_skip  = udata->skip;
11476
0
        old_nelem = udata->nelem;
11477
11478
        /* Intersect spaces once per count */
11479
0
        for (u = 0; u < count; u++) {
11480
0
            ss_span  = ss_span_info->head;
11481
0
            sis_span = sis_span_info->head;
11482
0
            assert(ss_span && sis_span);
11483
0
            ss_low  = ss_span->low;
11484
0
            sis_low = sis_span->low;
11485
11486
            /* Main loop */
11487
0
            do {
11488
                /* Check if spans overlap */
11489
0
                if (H5_RANGE_OVERLAP(ss_low, ss_span->high, sis_low, sis_span->high)) {
11490
0
                    high = MIN(ss_span->high, sis_span->high);
11491
0
                    if (ss_span->down) {
11492
                        /* Add skipped elements if there's a pre-gap */
11493
0
                        if (ss_low < sis_low) {
11494
0
                            low = sis_low;
11495
0
                            H5S_HYPER_PROJ_INT_ADD_SKIP(
11496
0
                                udata,
11497
0
                                H5S__hyper_spans_nelem_helper(ss_span->down, 0, udata->op_gen) *
11498
0
                                    (sis_low - ss_low),
11499
0
                                FAIL);
11500
0
                        } /* end if */
11501
0
                        else
11502
0
                            low = ss_low;
11503
11504
                        /* Recurse into next dimension down */
11505
0
                        if (H5S__hyper_proj_int_iterate(ss_span->down, sis_span->down, high - low + 1,
11506
0
                                                        depth + 1, udata) < 0)
11507
0
                            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOMPARE, FAIL,
11508
0
                                        "can't iterate over source selections");
11509
0
                    } /* end if */
11510
0
                    else {
11511
0
                        assert(depth == udata->ss_rank - 1);
11512
11513
                        /* Add skipped elements if there's a pre-gap */
11514
0
                        if (ss_low < sis_low) {
11515
0
                            low = sis_low;
11516
0
                            H5S_HYPER_PROJ_INT_ADD_SKIP(udata, sis_low - ss_low, FAIL);
11517
0
                        } /* end if */
11518
0
                        else
11519
0
                            low = ss_low;
11520
11521
                        /* Add overlapping elements */
11522
0
                        udata->nelem += high - low + 1;
11523
0
                    } /* end else */
11524
11525
                    /* Advance spans */
11526
0
                    if (ss_span->high == sis_span->high) {
11527
                        /* Advance both spans */
11528
0
                        ss_span = ss_span->next;
11529
0
                        if (ss_span)
11530
0
                            ss_low = ss_span->low;
11531
0
                        sis_span = sis_span->next;
11532
0
                        if (sis_span)
11533
0
                            sis_low = sis_span->low;
11534
0
                    } /* end if */
11535
0
                    else if (ss_span->high == high) {
11536
                        /* Advance source span */
11537
0
                        assert(ss_span->high < sis_span->high);
11538
0
                        sis_low = high + 1;
11539
0
                        ss_span = ss_span->next;
11540
0
                        if (ss_span)
11541
0
                            ss_low = ss_span->low;
11542
0
                    } /* end if */
11543
0
                    else {
11544
                        /* Advance source intersect span */
11545
0
                        assert(ss_span->high > sis_span->high);
11546
0
                        ss_low   = high + 1;
11547
0
                        sis_span = sis_span->next;
11548
0
                        if (sis_span)
11549
0
                            sis_low = sis_span->low;
11550
0
                    } /* end else */
11551
0
                }     /* end if */
11552
0
                else {
11553
                    /* Advance spans */
11554
0
                    if (ss_span->high < sis_low) {
11555
                        /* Add skipped elements */
11556
0
                        if (ss_span->down)
11557
0
                            H5S_HYPER_PROJ_INT_ADD_SKIP(
11558
0
                                udata,
11559
0
                                H5S__hyper_spans_nelem_helper(ss_span->down, 0, udata->op_gen) *
11560
0
                                    (ss_span->high - ss_low + 1),
11561
0
                                FAIL);
11562
0
                        else
11563
0
                            H5S_HYPER_PROJ_INT_ADD_SKIP(udata, ss_span->high - ss_low + 1, FAIL);
11564
11565
                        /* Advance source span */
11566
0
                        ss_span = ss_span->next;
11567
0
                        if (ss_span)
11568
0
                            ss_low = ss_span->low;
11569
0
                    } /* end if */
11570
0
                    else {
11571
                        /* Advance source intersect span */
11572
0
                        assert(ss_low > sis_span->high);
11573
0
                        sis_span = sis_span->next;
11574
0
                        if (sis_span)
11575
0
                            sis_low = sis_span->low;
11576
0
                    } /* end else */
11577
0
                }     /* end else */
11578
0
            } while (ss_span && sis_span);
11579
11580
0
            if (ss_span && !((depth == 0) && (u == count - 1))) {
11581
                /* Count remaining elements in ss_span_info */
11582
0
                if (ss_span->down) {
11583
0
                    H5S_HYPER_PROJ_INT_ADD_SKIP(
11584
0
                        udata,
11585
0
                        H5S__hyper_spans_nelem_helper(ss_span->down, 0, udata->op_gen) *
11586
0
                            (ss_span->high - ss_low + 1),
11587
0
                        FAIL);
11588
0
                    ss_span = ss_span->next;
11589
0
                    while (ss_span) {
11590
0
                        H5S_HYPER_PROJ_INT_ADD_SKIP(
11591
0
                            udata,
11592
0
                            H5S__hyper_spans_nelem_helper(ss_span->down, 0, udata->op_gen) *
11593
0
                                (ss_span->high - ss_span->low + 1),
11594
0
                            FAIL);
11595
0
                        ss_span = ss_span->next;
11596
0
                    } /* end while */
11597
0
                }     /* end if */
11598
0
                else {
11599
0
                    H5S_HYPER_PROJ_INT_ADD_SKIP(udata, ss_span->high - ss_low + 1, FAIL);
11600
0
                    ss_span = ss_span->next;
11601
0
                    while (ss_span) {
11602
0
                        H5S_HYPER_PROJ_INT_ADD_SKIP(udata, ss_span->high - ss_span->low + 1, FAIL);
11603
0
                        ss_span = ss_span->next;
11604
0
                    } /* end while */
11605
0
                }     /* end else */
11606
0
            }         /* end if */
11607
11608
            /* Check if the projected space was not changed since we started the
11609
             * first iteration of the loop, if so we do not need to continue
11610
             * looping and can just copy the result */
11611
0
            if (udata->ps_clean_bitmap & (((uint32_t)1) << depth)) {
11612
0
                assert(u == 0);
11613
0
                if (udata->skip == old_skip) {
11614
                    /* First case: algorithm added only elements */
11615
0
                    assert(udata->nelem >= old_nelem);
11616
0
                    udata->nelem += (count - 1) * (udata->nelem - old_nelem);
11617
0
                } /* end if */
11618
0
                else if (udata->nelem == 0) {
11619
                    /* Second case: algorithm added only skip.  In this case,
11620
                     * nelem must be 0 since otherwise adding skip would have
11621
                     * triggered a change in the projected space */
11622
0
                    assert(old_nelem == 0);
11623
0
                    assert(udata->skip > old_skip);
11624
0
                    udata->skip += (count - 1) * (udata->skip - old_skip);
11625
0
                } /* end if */
11626
0
                else {
11627
                    /* Third case: algorithm added skip and nelem (in that
11628
                     * order).  Add the same skip and nelem once for each item
11629
                     * remaining in count. */
11630
0
                    hsize_t skip_add;
11631
0
                    hsize_t nelem_add;
11632
11633
0
                    assert(udata->nelem > 0);
11634
0
                    assert(udata->skip > old_skip);
11635
0
                    assert(old_nelem == 0);
11636
11637
0
                    skip_add  = udata->skip - old_skip;
11638
0
                    nelem_add = udata->nelem - old_nelem;
11639
0
                    for (u = 1; u < count; u++) {
11640
0
                        H5S_HYPER_PROJ_INT_ADD_SKIP(udata, skip_add, FAIL);
11641
0
                        udata->nelem += nelem_add;
11642
0
                    } /* end for */
11643
0
                }     /* end else */
11644
11645
                /* End loop since we already took care of it */
11646
0
                break;
11647
0
            } /* end if */
11648
0
        }     /* end for */
11649
0
    }         /* end if */
11650
0
    else if (depth > 0)
11651
        /* Just count skipped elements */
11652
0
        H5S_HYPER_PROJ_INT_ADD_SKIP(
11653
0
            udata,
11654
0
            H5S__hyper_spans_nelem_helper((H5S_hyper_span_info_t *)ss_span_info, 0, udata->op_gen) * count,
11655
0
            FAIL);
11656
11657
    /* Clean up if we are done */
11658
0
    if (depth == 0) {
11659
        /* Add remaining elements */
11660
0
        if (udata->nelem > 0)
11661
0
            if (H5S__hyper_proj_int_build_proj(udata) < 0)
11662
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't add elements to projected selection");
11663
11664
        /* Append remaining span trees */
11665
0
        for (u = udata->ds_rank - 1; u > 0; u--)
11666
0
            if (udata->ps_span_info[u]) {
11667
0
                if (H5S__hyper_append_span(&udata->ps_span_info[u - 1], udata->ds_rank - u + 1,
11668
0
                                           udata->ds_low[u - 1], udata->ds_low[u - 1],
11669
0
                                           udata->ps_span_info[u]) < 0)
11670
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span");
11671
0
                if (H5S__hyper_free_span_info(udata->ps_span_info[u]) < 0)
11672
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11673
0
                udata->ps_span_info[u] = NULL;
11674
0
            }
11675
0
    }
11676
11677
0
done:
11678
0
    FUNC_LEAVE_NOAPI(ret_value)
11679
0
} /* end H5S__hyper_proj_int_iterate() */
11680
11681
/*--------------------------------------------------------------------------
11682
 NAME
11683
    H5S__hyper_project_intersection
11684
 PURPOSE
11685
    Projects the intersection of of the selections of src_space and
11686
    src_intersect_space within the selection of src_space as a selection
11687
    within the selection of dst_space
11688
 USAGE
11689
    herr_t H5S__hyper_project_intersection(src_space,dst_space,src_intersect_space,proj_space,share_selection)
11690
        H5S_t *src_space;       IN: Selection that is mapped to dst_space, and intersected with
11691
src_intersect_space H5S_t *dst_space;       IN: Selection that is mapped to src_space, and which contains the
11692
result H5S_t *src_intersect_space; IN: Selection whose intersection with src_space is projected to dst_space
11693
to obtain the result H5S_t *proj_space;      OUT: Will contain the result (intersection of src_intersect_space
11694
and src_space projected from src_space to dst_space) after the operation bool share_selection; IN: Whether
11695
we are allowed to share structures inside dst_space with proj_space RETURNS Non-negative on success/Negative
11696
on failure. DESCRIPTION Projects the intersection of of the selections of src_space and src_intersect_space
11697
within the selection of src_space as a selection within the selection of dst_space.  The result is placed in
11698
the selection of proj_space.  Note src_space, dst_space, and src_intersect_space do not need to use hyperslab
11699
selections, but they cannot use point selections. The result is always a hyperslab or none selection.  Note
11700
also that proj_space can share some span trees with dst_space, so proj_space must not be subsequently modified
11701
if dst_space must be preserved. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG
11702
--------------------------------------------------------------------------*/
11703
herr_t
11704
H5S__hyper_project_intersection(H5S_t *src_space, H5S_t *dst_space, H5S_t *src_intersect_space,
11705
                                H5S_t *proj_space, bool share_selection)
11706
0
{
11707
0
    H5S_hyper_project_intersect_ud_t udata; /* User data for subroutines */
11708
0
    H5S_hyper_span_info_t           *ss_span_info;
11709
0
    const H5S_hyper_span_info_t     *ds_span_info;
11710
0
    H5S_hyper_span_info_t           *ss_span_info_buf = NULL;
11711
0
    H5S_hyper_span_info_t           *ds_span_info_buf = NULL;
11712
0
    herr_t                           ret_value        = SUCCEED; /* Return value */
11713
11714
0
    FUNC_ENTER_PACKAGE
11715
11716
    /* Check parameters */
11717
0
    assert(src_space);
11718
0
    assert(dst_space);
11719
0
    assert(src_intersect_space);
11720
0
    assert(proj_space);
11721
11722
    /* Assert that src_space and src_intersect_space have same rank and there
11723
     * are no point selections */
11724
0
    assert(H5S_GET_EXTENT_NDIMS(src_space) == H5S_GET_EXTENT_NDIMS(src_intersect_space));
11725
0
    assert(H5S_GET_SELECT_NPOINTS(src_space) == H5S_GET_SELECT_NPOINTS(dst_space));
11726
0
    assert(H5S_GET_SELECT_TYPE(src_space) != H5S_SEL_POINTS);
11727
0
    assert(H5S_GET_SELECT_TYPE(dst_space) != H5S_SEL_POINTS);
11728
0
    assert(H5S_GET_SELECT_TYPE(src_intersect_space) == H5S_SEL_HYPERSLABS);
11729
11730
    /* Set up ss_span_info */
11731
0
    if (H5S_GET_SELECT_TYPE(src_space) == H5S_SEL_HYPERSLABS) {
11732
        /* Make certain the selection has a span tree */
11733
0
        if (NULL == src_space->select.sel_info.hslab->span_lst)
11734
0
            if (H5S__hyper_generate_spans(src_space) < 0)
11735
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL,
11736
0
                            "can't construct span tree for source hyperslab selection");
11737
11738
        /* Simply point to existing span tree */
11739
0
        ss_span_info = src_space->select.sel_info.hslab->span_lst;
11740
0
    } /* end if */
11741
0
    else {
11742
        /* Create temporary span tree from all selection */
11743
0
        assert(H5S_GET_SELECT_TYPE(src_space) == H5S_SEL_ALL);
11744
11745
0
        if (NULL == (ss_span_info_buf =
11746
0
                         H5S__hyper_make_spans(H5S_GET_EXTENT_NDIMS(src_space), H5S_hyper_zeros_g,
11747
0
                                               H5S_hyper_zeros_g, H5S_hyper_ones_g, src_space->extent.size)))
11748
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't create span tree for ALL source space");
11749
0
        ss_span_info = ss_span_info_buf;
11750
0
    } /* end else */
11751
11752
    /* Set up ds_span_info */
11753
0
    if (H5S_GET_SELECT_TYPE(dst_space) == H5S_SEL_HYPERSLABS) {
11754
        /* Make certain the selection has a span tree */
11755
0
        if (NULL == dst_space->select.sel_info.hslab->span_lst)
11756
0
            if (H5S__hyper_generate_spans(dst_space) < 0)
11757
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL,
11758
0
                            "can't construct span tree for dsetination hyperslab selection");
11759
11760
        /* Simply point to existing span tree */
11761
0
        ds_span_info = dst_space->select.sel_info.hslab->span_lst;
11762
0
    } /* end if */
11763
0
    else {
11764
        /* Create temporary span tree from all selection */
11765
0
        assert(H5S_GET_SELECT_TYPE(dst_space) == H5S_SEL_ALL);
11766
11767
0
        if (NULL == (ds_span_info_buf =
11768
0
                         H5S__hyper_make_spans(H5S_GET_EXTENT_NDIMS(dst_space), H5S_hyper_zeros_g,
11769
0
                                               H5S_hyper_zeros_g, H5S_hyper_ones_g, dst_space->extent.size)))
11770
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL,
11771
0
                        "can't create span tree for ALL destination space");
11772
0
        ds_span_info = ds_span_info_buf;
11773
0
    } /* end else */
11774
11775
    /* Make certain the source intersect selection has a span tree */
11776
0
    if (NULL == src_intersect_space->select.sel_info.hslab->span_lst)
11777
0
        if (H5S__hyper_generate_spans(src_intersect_space) < 0)
11778
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL,
11779
0
                        "can't construct span tree for source intersect hyperslab selection");
11780
11781
    /* Initialize udata */
11782
    /* We will use op_info[0] for nelem and op_info[1] for copied spans */
11783
0
    memset(&udata, 0, sizeof(udata));
11784
0
    udata.ds_span[0]      = ds_span_info->head;
11785
0
    udata.ds_low[0]       = udata.ds_span[0]->low;
11786
0
    udata.ss_rank         = H5S_GET_EXTENT_NDIMS(src_space);
11787
0
    udata.ds_rank         = H5S_GET_EXTENT_NDIMS(dst_space);
11788
0
    udata.op_gen          = H5S__hyper_get_op_gen();
11789
0
    udata.share_selection = share_selection;
11790
11791
    /* Iterate over selections and build projected span tree */
11792
0
    if (H5S__hyper_proj_int_iterate(ss_span_info, src_intersect_space->select.sel_info.hslab->span_lst, 1, 0,
11793
0
                                    &udata) < 0)
11794
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOMPARE, FAIL, "selection iteration failed");
11795
11796
    /* Remove current selection from proj_space */
11797
0
    if (H5S_SELECT_RELEASE(proj_space) < 0)
11798
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection");
11799
11800
    /* Check for elements in projected space */
11801
0
    if (udata.ps_span_info[0]) {
11802
        /* Allocate space for the hyperslab selection information (note this sets
11803
         * diminfo_valid to false, diminfo arrays to 0, and span list to NULL) */
11804
0
        if (NULL == (proj_space->select.sel_info.hslab = H5FL_CALLOC(H5S_hyper_sel_t)))
11805
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab info");
11806
11807
        /* Set selection type */
11808
0
        proj_space->select.type = H5S_sel_hyper;
11809
11810
        /* Set unlim_dim */
11811
0
        proj_space->select.sel_info.hslab->unlim_dim = -1;
11812
11813
        /* Set span tree */
11814
0
        proj_space->select.sel_info.hslab->span_lst = udata.ps_span_info[0];
11815
0
        udata.ps_span_info[0]                       = NULL;
11816
11817
        /* Set the number of elements in current selection */
11818
0
        proj_space->select.num_elem = H5S__hyper_spans_nelem(proj_space->select.sel_info.hslab->span_lst);
11819
11820
        /* Attempt to build "optimized" start/stride/count/block information
11821
         * from resulting hyperslab span tree.
11822
         */
11823
0
        H5S__hyper_rebuild(proj_space);
11824
0
    } /* end if */
11825
0
    else
11826
        /* If we did not add anything to proj_space, select none instead */
11827
0
        if (H5S_select_none(proj_space) < 0)
11828
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection");
11829
11830
0
done:
11831
    /* Free ss_span_info_buf */
11832
0
    if (ss_span_info_buf) {
11833
0
        if (H5S__hyper_free_span_info(ss_span_info_buf) < 0)
11834
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11835
0
        ss_span_info_buf = NULL;
11836
0
    }
11837
11838
    /* Free ds_span_info_buf */
11839
0
    if (ds_span_info_buf) {
11840
0
        if (H5S__hyper_free_span_info(ds_span_info_buf) < 0)
11841
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11842
0
        ds_span_info_buf = NULL;
11843
0
    }
11844
11845
    /* Cleanup on error */
11846
0
    if (ret_value < 0) {
11847
0
        unsigned u;
11848
11849
        /* Free span trees */
11850
0
        for (u = 0; u < udata.ds_rank; u++)
11851
0
            if (udata.ps_span_info[u]) {
11852
0
                if (H5S__hyper_free_span_info(udata.ps_span_info[u]) < 0)
11853
0
                    HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "unable to free span info");
11854
0
                udata.ps_span_info[u] = NULL;
11855
0
            }
11856
0
    }
11857
11858
#ifndef NDEBUG
11859
    /* Verify there are no more span trees */
11860
    {
11861
        unsigned u;
11862
11863
        for (u = 0; u < H5S_MAX_RANK; u++)
11864
            assert(!udata.ps_span_info[u]);
11865
    }
11866
#endif /* NDEBUG */
11867
11868
0
    FUNC_LEAVE_NOAPI(ret_value)
11869
0
} /* end H5S__hyper_project_intersection() */
11870
11871
/*--------------------------------------------------------------------------
11872
 NAME
11873
    H5S__hyper_get_clip_diminfo
11874
 PURPOSE
11875
    Calculates the count and block required to clip the specified
11876
    unlimited dimension to include clip_size.  The returned selection may
11877
    extent beyond clip_size.
11878
 USAGE
11879
    void H5S__hyper_get_clip_diminfo(start,stride,count,block,clip_size)
11880
        hsize_t start;          IN: Start of hyperslab in unlimited dimension
11881
        hsize_t stride;         IN: Stride of hyperslab in unlimited dimension
11882
        hsize_t *count;         IN/OUT: Count of hyperslab in unlimited dimension
11883
        hsize_t *block;         IN/OUT: Block of hyperslab in unlimited dimension
11884
        hsize_t clip_size;      IN: Extent that hyperslab will be clipped to
11885
 RETURNS
11886
    Non-negative on success/Negative on failure.
11887
 DESCRIPTION
11888
    This function recalculates the internal description of the hyperslab
11889
    to make the unlimited dimension extend to the specified extent.
11890
 GLOBAL VARIABLES
11891
 COMMENTS, BUGS, ASSUMPTIONS
11892
 EXAMPLES
11893
 REVISION LOG
11894
--------------------------------------------------------------------------*/
11895
static void
11896
H5S__hyper_get_clip_diminfo(hsize_t start, hsize_t stride, hsize_t *count, hsize_t *block, hsize_t clip_size)
11897
0
{
11898
0
    FUNC_ENTER_PACKAGE_NOERR
11899
11900
    /* Check for selection outside clip size */
11901
0
    if (start >= clip_size) {
11902
0
        if (*block == H5S_UNLIMITED)
11903
0
            *block = 0;
11904
0
        else
11905
0
            *count = 0;
11906
0
    } /* end if */
11907
    /* Check for single block in unlimited dimension */
11908
0
    else if ((*block == H5S_UNLIMITED) || (*block == stride)) {
11909
        /* Calculate actual block size for this clip size */
11910
0
        *block = clip_size - start;
11911
0
        *count = (hsize_t)1;
11912
0
    } /* end if */
11913
0
    else {
11914
0
        assert(*count == H5S_UNLIMITED);
11915
11916
        /* Calculate initial count (last block may be partial) */
11917
0
        *count = (clip_size - start + stride - (hsize_t)1) / stride;
11918
0
        assert(*count > (hsize_t)0);
11919
0
    } /* end else */
11920
11921
0
    FUNC_LEAVE_NOAPI_VOID
11922
0
} /* end H5S__hyper_get_clip_diminfo() */
11923
11924
/*--------------------------------------------------------------------------
11925
 NAME
11926
    H5S_hyper_clip_unlim
11927
 PURPOSE
11928
    Clips the unlimited dimension of the hyperslab selection to the
11929
    specified size
11930
 USAGE
11931
    void H5S_hyper_clip_unlim(space,clip_size)
11932
        H5S_t *space,           IN/OUT: Unlimited space to clip
11933
        hsize_t clip_size;      IN: Extent that hyperslab will be clipped to
11934
 RETURNS
11935
    Non-negative on success/Negative on failure.
11936
 DESCRIPTION
11937
    This function changes the unlimited selection into a fixed-dimension selection
11938
    with the extent of the formerly unlimited dimension specified by clip_size.
11939
 GLOBAL VARIABLES
11940
 COMMENTS, BUGS, ASSUMPTIONS
11941
    Note this function does not take the offset into account.
11942
 EXAMPLES
11943
 REVISION LOG
11944
--------------------------------------------------------------------------*/
11945
herr_t
11946
H5S_hyper_clip_unlim(H5S_t *space, hsize_t clip_size)
11947
0
{
11948
0
    H5S_hyper_sel_t *hslab = NULL;        /* Convenience pointer to hyperslab info */
11949
0
    hsize_t          orig_count;          /* Original count in unlimited dimension */
11950
0
    int              orig_unlim_dim;      /* Original unliminted dimension */
11951
0
    H5S_hyper_dim_t *diminfo   = NULL;    /* Convenience pointer to diminfo.opt in unlimited dimension */
11952
0
    herr_t           ret_value = SUCCEED; /* Return value */
11953
11954
0
    FUNC_ENTER_NOAPI(FAIL)
11955
11956
    /* Check parameters */
11957
0
    assert(space);
11958
0
    hslab = space->select.sel_info.hslab;
11959
0
    assert(hslab);
11960
0
    assert(hslab->unlim_dim >= 0);
11961
0
    assert(!hslab->span_lst);
11962
11963
    /* Save original unlimited dimension */
11964
0
    orig_unlim_dim = hslab->unlim_dim;
11965
11966
    /* Set up convenience pointer */
11967
0
    diminfo = &hslab->diminfo.opt[orig_unlim_dim];
11968
11969
    /* Save original count in unlimited dimension */
11970
0
    orig_count = diminfo->count;
11971
11972
    /* Get initial diminfo */
11973
0
    H5S__hyper_get_clip_diminfo(diminfo->start, diminfo->stride, &diminfo->count, &diminfo->block, clip_size);
11974
11975
    /* Selection is no longer unlimited */
11976
0
    space->select.sel_info.hslab->unlim_dim = -1;
11977
11978
    /* Check for nothing returned */
11979
0
    if ((diminfo->block == 0) || (diminfo->count == 0)) {
11980
        /* Convert to "none" selection */
11981
0
        if (H5S_select_none(space) < 0)
11982
0
            HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection");
11983
11984
        /* Reset the convenience pointers */
11985
0
        hslab   = NULL;
11986
0
        diminfo = NULL;
11987
0
    } /* end if */
11988
    /* Check for single block in unlimited dimension */
11989
0
    else if (orig_count == (hsize_t)1) {
11990
        /* Calculate number of elements */
11991
0
        space->select.num_elem = diminfo->block * hslab->num_elem_non_unlim;
11992
11993
        /* Mark that diminfo.opt is valid */
11994
0
        hslab->diminfo_valid = H5S_DIMINFO_VALID_YES;
11995
0
    } /* end if */
11996
0
    else {
11997
        /* Calculate number of elements */
11998
0
        space->select.num_elem = diminfo->count * diminfo->block * hslab->num_elem_non_unlim;
11999
12000
        /* Check if last block is partial.  If superset is set, just keep the
12001
         * last block complete to speed computation. */
12002
0
        assert(clip_size > diminfo->start);
12003
0
        if (((diminfo->stride * (diminfo->count - (hsize_t)1)) + diminfo->block) >
12004
0
            (clip_size - diminfo->start)) {
12005
0
            hsize_t  start[H5S_MAX_RANK];
12006
0
            hsize_t  block[H5S_MAX_RANK];
12007
0
            unsigned u;
12008
12009
            /* Last block is partial, need to construct compound selection */
12010
            /* Fill start with zeros */
12011
0
            memset(start, 0, sizeof(start));
12012
12013
            /* Set block to clip_size in unlimited dimension, H5S_MAX_SIZE in
12014
             * others so only unlimited dimension is clipped */
12015
0
            for (u = 0; u < space->extent.rank; u++)
12016
0
                if ((int)u == orig_unlim_dim)
12017
0
                    block[u] = clip_size;
12018
0
                else
12019
0
                    block[u] = H5S_MAX_SIZE;
12020
12021
            /* Generate span tree in selection */
12022
0
            if (!hslab->span_lst)
12023
0
                if (H5S__hyper_generate_spans(space) < 0)
12024
0
                    HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to generate span tree");
12025
12026
            /* Indicate that the regular dimensions are no longer valid */
12027
0
            hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
12028
12029
            /* "And" selection with calculated block to perform clip operation */
12030
0
            if (H5S__generate_hyperslab(space, H5S_SELECT_AND, start, H5S_hyper_ones_g, H5S_hyper_ones_g,
12031
0
                                        block) < 0)
12032
0
                HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs");
12033
0
        } /* end if */
12034
0
        else
12035
            /* Last block is complete, simply mark that diminfo.opt is valid */
12036
0
            hslab->diminfo_valid = H5S_DIMINFO_VALID_YES;
12037
0
    } /* end else */
12038
12039
    /* Update the upper bound, if the diminfo is valid */
12040
0
    if (hslab && (H5S_DIMINFO_VALID_YES == hslab->diminfo_valid))
12041
0
        hslab->diminfo.high_bounds[orig_unlim_dim] =
12042
0
            hslab->diminfo.opt[orig_unlim_dim].start +
12043
0
            hslab->diminfo.opt[orig_unlim_dim].stride * (hslab->diminfo.opt[orig_unlim_dim].count - 1) +
12044
0
            (hslab->diminfo.opt[orig_unlim_dim].block - 1);
12045
12046
0
done:
12047
0
    FUNC_LEAVE_NOAPI(ret_value)
12048
0
} /* end H5S_hyper_clip_unlim() */
12049
12050
/*--------------------------------------------------------------------------
12051
 NAME
12052
    H5S__hyper_get_clip_extent_real
12053
 PURPOSE
12054
    Gets the extent a space should be clipped to in order to contain the
12055
    specified number of slices in the unlimited dimension
12056
 USAGE
12057
    hsize_t H5S__hyper_get_clip_extent_real(clip_space,num_slices,incl_trail)
12058
        const H5S_t *clip_space, IN: Space that clip size will be calculated based on
12059
        hsize_t num_slizes,     IN: Number of slices clip_space should contain when clipped
12060
        bool incl_trail;     IN: Whether to include trailing unselected space
12061
 RETURNS
12062
    Clip extent to match num_slices (never fails)
12063
 DESCRIPTION
12064
    Calculates and returns the extent that clip_space should be clipped to
12065
    (via H5S_hyper_clip_unlim) in order for it to contain num_slices
12066
    slices in the unlimited dimension.  If the clipped selection would end
12067
    immediately before a section of unselected space (i.e. at the end of a
12068
    block), then if incl_trail is true, the returned clip extent is
12069
    selected to include that trailing "blank" space, otherwise it is
12070
    selected to end at the end before the blank space.
12071
 GLOBAL VARIABLES
12072
 COMMENTS, BUGS, ASSUMPTIONS
12073
    Note this assumes the offset has been normalized.
12074
 EXAMPLES
12075
 REVISION LOG
12076
--------------------------------------------------------------------------*/
12077
static hsize_t
12078
H5S__hyper_get_clip_extent_real(const H5S_t *clip_space, hsize_t num_slices, bool incl_trail)
12079
0
{
12080
0
    const H5S_hyper_dim_t *diminfo; /* Convenience pointer to opt_unlim_diminfo in unlimited dimension */
12081
0
    hsize_t                count;
12082
0
    hsize_t                rem_slices;
12083
0
    hsize_t                ret_value = 0; /* Return value */
12084
12085
0
    FUNC_ENTER_PACKAGE_NOERR
12086
12087
    /* Check parameters */
12088
0
    assert(clip_space);
12089
0
    assert(clip_space->select.sel_info.hslab);
12090
0
    assert(clip_space->select.sel_info.hslab->unlim_dim >= 0);
12091
12092
0
    diminfo = &clip_space->select.sel_info.hslab->diminfo.opt[clip_space->select.sel_info.hslab->unlim_dim];
12093
12094
0
    if (num_slices == 0)
12095
0
        ret_value = incl_trail ? diminfo->start : 0;
12096
0
    else if ((diminfo->block == H5S_UNLIMITED) || (diminfo->block == diminfo->stride))
12097
        /* Unlimited block, just set the extent large enough for the block size
12098
         * to match num_slices */
12099
0
        ret_value = diminfo->start + num_slices;
12100
0
    else {
12101
        /* Unlimited count, need to match extent so a block (possibly) gets cut
12102
         * off so the number of slices matches num_slices */
12103
0
        assert(diminfo->count == H5S_UNLIMITED);
12104
12105
        /* Calculate number of complete blocks in clip_space */
12106
0
        count = num_slices / diminfo->block;
12107
12108
        /* Calculate slices remaining */
12109
0
        rem_slices = num_slices - (count * diminfo->block);
12110
12111
0
        if (rem_slices > 0)
12112
            /* Must end extent in middle of partial block (or beginning of empty
12113
             * block if include_trailing_space and rem_slices == 0) */
12114
0
            ret_value = diminfo->start + (count * diminfo->stride) + rem_slices;
12115
0
        else {
12116
0
            if (incl_trail)
12117
                /* End extent just before first missing block */
12118
0
                ret_value = diminfo->start + (count * diminfo->stride);
12119
0
            else
12120
                /* End extent at end of last block */
12121
0
                ret_value = diminfo->start + ((count - (hsize_t)1) * diminfo->stride) + diminfo->block;
12122
0
        } /* end else */
12123
0
    }     /* end else */
12124
12125
0
    FUNC_LEAVE_NOAPI(ret_value)
12126
0
} /* end H5S__hyper_get_clip_extent_real() */
12127
12128
/*--------------------------------------------------------------------------
12129
 NAME
12130
    H5S_hyper_get_clip_extent
12131
 PURPOSE
12132
    Gets the extent a space should be clipped to in order to contain the
12133
    same number of elements as another space
12134
 USAGE
12135
    hsize_t H5S__hyper_get_clip_extent(clip_space,match_space,incl_trail)
12136
        const H5S_t *clip_space, IN: Space that clip size will be calculated based on
12137
        const H5S_t *match_space, IN: Space containing the same number of elements as clip_space should after
12138
clipping bool incl_trail;     IN: Whether to include trailing unselected space RETURNS Calculated clip
12139
extent (never fails) DESCRIPTION Calculates and returns the extent that clip_space should be clipped to (via
12140
H5S_hyper_clip_unlim) in order for it to contain the same number of elements as match_space.  If the clipped
12141
selection would end immediately before a section of unselected space (i.e. at the end of a block), then if
12142
incl_trail is true, the returned clip extent is selected to include that trailing "blank" space, otherwise it
12143
is selected to end at the end before the blank space. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS Note this
12144
assumes the offset has been normalized. EXAMPLES REVISION LOG
12145
--------------------------------------------------------------------------*/
12146
hsize_t
12147
H5S_hyper_get_clip_extent(const H5S_t *clip_space, const H5S_t *match_space, bool incl_trail)
12148
0
{
12149
0
    hsize_t num_slices;    /* Number of slices in unlimited dimension */
12150
0
    hsize_t ret_value = 0; /* Return value */
12151
12152
0
    FUNC_ENTER_NOAPI(0)
12153
12154
    /* Check parameters */
12155
0
    assert(clip_space);
12156
0
    assert(match_space);
12157
0
    assert(clip_space->select.sel_info.hslab->unlim_dim >= 0);
12158
12159
    /* Check for "none" match space */
12160
0
    if (match_space->select.type->type == H5S_SEL_NONE)
12161
0
        num_slices = (hsize_t)0;
12162
0
    else {
12163
0
        assert(match_space->select.type->type == H5S_SEL_HYPERSLABS);
12164
0
        assert(match_space->select.sel_info.hslab);
12165
12166
        /* Calculate number of slices */
12167
0
        num_slices = match_space->select.num_elem / clip_space->select.sel_info.hslab->num_elem_non_unlim;
12168
0
        assert((match_space->select.num_elem % clip_space->select.sel_info.hslab->num_elem_non_unlim) == 0);
12169
0
    } /* end else */
12170
12171
    /* Call "real" get_clip_extent function */
12172
0
    ret_value = H5S__hyper_get_clip_extent_real(clip_space, num_slices, incl_trail);
12173
12174
0
done:
12175
0
    FUNC_LEAVE_NOAPI(ret_value)
12176
0
} /* end H5S_hyper_get_clip_extent() */
12177
12178
/*--------------------------------------------------------------------------
12179
 NAME
12180
    H5S_hyper_get_clip_extent_match
12181
 PURPOSE
12182
    Gets the extent a space should be clipped to in order to contain the
12183
    same number of elements as another unlimited space that has been
12184
    clipped to a different extent
12185
 USAGE
12186
    hsize_t H5S__hyper_get_clip_extent_match(clip_space,match_space,match_clip_size,incl_trail)
12187
        const H5S_t *clip_space, IN: Space that clip size will be calculated based on
12188
        const H5S_t *match_space, IN: Space that, after being clipped to match_clip_size, contains the same
12189
number of elements as clip_space should after clipping hsize_t match_clip_size, IN: Extent match_space would
12190
be clipped to to match the number of elements in clip_space bool incl_trail;     IN: Whether to include
12191
trailing unselected space RETURNS Calculated clip extent (never fails) DESCRIPTION Calculates and returns the
12192
extent that clip_space should be clipped to (via H5S_hyper_clip_unlim) in order for it to contain the same
12193
number of elements as match_space would have after being clipped to match_clip_size.  If the clipped selection
12194
would end immediately before a section of unselected space (i.e. at the end of a block), then if incl_trail is
12195
true, the returned clip extent is selected to include that trailing "blank" space, otherwise it is selected to
12196
end at the end before the blank space. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS Note this assumes the
12197
offset has been normalized. EXAMPLES REVISION LOG
12198
--------------------------------------------------------------------------*/
12199
hsize_t
12200
H5S_hyper_get_clip_extent_match(const H5S_t *clip_space, const H5S_t *match_space, hsize_t match_clip_size,
12201
                                bool incl_trail)
12202
0
{
12203
0
    const H5S_hyper_dim_t
12204
0
        *match_diminfo; /* Convenience pointer to opt_unlim_diminfo in unlimited dimension in match_space */
12205
0
    hsize_t count;      /* Temporary count */
12206
0
    hsize_t block;      /* Temporary block */
12207
0
    hsize_t num_slices; /* Number of slices in unlimited dimension */
12208
0
    hsize_t ret_value = 0; /* Return value */
12209
12210
0
    FUNC_ENTER_NOAPI(0)
12211
12212
    /* Check parameters */
12213
0
    assert(clip_space);
12214
0
    assert(match_space);
12215
0
    assert(clip_space->select.sel_info.hslab);
12216
0
    assert(match_space->select.sel_info.hslab);
12217
0
    assert(clip_space->select.sel_info.hslab->unlim_dim >= 0);
12218
0
    assert(match_space->select.sel_info.hslab->unlim_dim >= 0);
12219
0
    assert(clip_space->select.sel_info.hslab->num_elem_non_unlim ==
12220
0
           match_space->select.sel_info.hslab->num_elem_non_unlim);
12221
12222
0
    match_diminfo =
12223
0
        &match_space->select.sel_info.hslab->diminfo.opt[match_space->select.sel_info.hslab->unlim_dim];
12224
12225
    /* Get initial count and block */
12226
0
    count = match_diminfo->count;
12227
0
    block = match_diminfo->block;
12228
0
    H5S__hyper_get_clip_diminfo(match_diminfo->start, match_diminfo->stride, &count, &block, match_clip_size);
12229
12230
    /* Calculate number of slices */
12231
    /* Check for nothing returned */
12232
0
    if ((block == 0) || (count == 0))
12233
0
        num_slices = (hsize_t)0;
12234
    /* Check for single block in unlimited dimension */
12235
0
    else if (count == (hsize_t)1)
12236
0
        num_slices = block;
12237
0
    else {
12238
        /* Calculate initial num_slices */
12239
0
        num_slices = block * count;
12240
12241
        /* Check for partial last block */
12242
0
        assert(match_clip_size >= match_diminfo->start);
12243
0
        if (((match_diminfo->stride * (count - (hsize_t)1)) + block) >
12244
0
            (match_clip_size - match_diminfo->start)) {
12245
            /* Subtract slices missing from last block */
12246
0
            assert((((match_diminfo->stride * (count - (hsize_t)1)) + block) -
12247
0
                    (match_clip_size - match_diminfo->start)) < num_slices);
12248
0
            num_slices -= ((match_diminfo->stride * (count - (hsize_t)1)) + block) -
12249
0
                          (match_clip_size - match_diminfo->start);
12250
0
        } /* end if */
12251
0
    }     /* end else */
12252
12253
    /* Call "real" get_clip_extent function */
12254
0
    ret_value = H5S__hyper_get_clip_extent_real(clip_space, num_slices, incl_trail);
12255
12256
0
done:
12257
0
    FUNC_LEAVE_NOAPI(ret_value)
12258
0
} /* end H5S_hyper_get_clip_extent_match() */
12259
12260
/*--------------------------------------------------------------------------
12261
 NAME
12262
    H5S_hyper_get_unlim_block
12263
 PURPOSE
12264
    Get the nth block in the unlimited dimension
12265
 USAGE
12266
    H5S_t *H5S_hyper_get_unlim_block(space,block_index)
12267
        const H5S_t *space,     IN: Space with unlimited selection
12268
        hsize_t block_index,    IN: Index of block to return in unlimited dimension
12269
        bool incl_trail;     IN: Whether to include trailing unselected space
12270
 RETURNS
12271
    New space on success/NULL on failure.
12272
 DESCRIPTION
12273
    Returns a space containing only the block_indexth block in the
12274
    unlimited dimension on space.  All blocks in all other dimensions are
12275
    preserved.
12276
 GLOBAL VARIABLES
12277
 COMMENTS, BUGS, ASSUMPTIONS
12278
    Note this assumes the offset has been normalized.
12279
 EXAMPLES
12280
 REVISION LOG
12281
--------------------------------------------------------------------------*/
12282
H5S_t *
12283
H5S_hyper_get_unlim_block(const H5S_t *space, hsize_t block_index)
12284
0
{
12285
0
    H5S_hyper_sel_t *hslab;               /* Convenience pointer to hyperslab info */
12286
0
    H5S_t           *space_out = NULL;    /* Dataspace to return */
12287
0
    hsize_t          start[H5S_MAX_RANK]; /* Hyperslab selection info for unlim. selection */
12288
0
    hsize_t          stride[H5S_MAX_RANK];
12289
0
    hsize_t          count[H5S_MAX_RANK];
12290
0
    hsize_t          block[H5S_MAX_RANK];
12291
0
    unsigned         u;                /* Local index variable */
12292
0
    H5S_t           *ret_value = NULL; /* Return value */
12293
12294
0
    FUNC_ENTER_NOAPI(NULL)
12295
12296
    /* Check parameters */
12297
0
    assert(space);
12298
0
    hslab = space->select.sel_info.hslab;
12299
0
    assert(hslab);
12300
0
    assert(hslab->unlim_dim >= 0);
12301
0
    assert(hslab->diminfo.opt[hslab->unlim_dim].count == H5S_UNLIMITED);
12302
12303
    /* Set start to select block_indexth block in unlimited dimension and set
12304
     * count to 1 in that dimension to only select that block.  Copy all other
12305
     * diminfo parameters. */
12306
0
    for (u = 0; u < space->extent.rank; u++) {
12307
0
        if ((int)u == hslab->unlim_dim) {
12308
0
            start[u] = hslab->diminfo.opt[u].start + (block_index * hslab->diminfo.opt[u].stride);
12309
0
            count[u] = (hsize_t)1;
12310
0
        } /* end if */
12311
0
        else {
12312
0
            start[u] = hslab->diminfo.opt[u].start;
12313
0
            count[u] = hslab->diminfo.opt[u].count;
12314
0
        } /* end else */
12315
0
        stride[u] = hslab->diminfo.opt[u].stride;
12316
0
        block[u]  = hslab->diminfo.opt[u].block;
12317
0
    } /* end for */
12318
12319
    /* Create output space, copy extent */
12320
0
    if (NULL == (space_out = H5S_create(H5S_SIMPLE)))
12321
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, NULL, "unable to create output dataspace");
12322
0
    if (H5S__extent_copy_real(&space_out->extent, &space->extent, true) < 0)
12323
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, NULL, "unable to copy destination space extent");
12324
12325
    /* Select block as defined by start/stride/count/block computed above */
12326
0
    if (H5S_select_hyperslab(space_out, H5S_SELECT_SET, start, stride, count, block) < 0)
12327
0
        HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, NULL, "can't select hyperslab");
12328
12329
    /* Set return value */
12330
0
    ret_value = space_out;
12331
12332
0
done:
12333
    /* Free space on error */
12334
0
    if (!ret_value)
12335
0
        if (space_out && H5S_close(space_out) < 0)
12336
0
            HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, NULL, "unable to release dataspace");
12337
12338
0
    FUNC_LEAVE_NOAPI(ret_value)
12339
0
} /* end H5S_hyper_get_unlim_block */
12340
12341
/*--------------------------------------------------------------------------
12342
 NAME
12343
    H5S_hyper_get_first_inc_block
12344
 PURPOSE
12345
    Get the index of the first incomplete block in the specified extent
12346
 USAGE
12347
    hsize_t H5S_hyper_get_first_inc_block(space,clip_size,partial)
12348
        const H5S_t *space,     IN: Space with unlimited selection
12349
        hsize_t clip_size,      IN: Extent space would be clipped to
12350
        bool *partial;       OUT: Whether the ret_valueth block (first incomplete block) is partial
12351
 RETURNS
12352
    Index of first incomplete block in clip_size (never fails).
12353
 DESCRIPTION
12354
    Calculates and returns the index (as would be passed to
12355
    H5S_hyper_get_unlim_block()) of the first block in the unlimited
12356
    dimension of space which would be incomplete or missing when space is
12357
    clipped to clip_size.  partial is set to true if the first incomplete
12358
    block is partial, and false if the first incomplete block is missing.
12359
 GLOBAL VARIABLES
12360
 COMMENTS, BUGS, ASSUMPTIONS
12361
    Note this assumes the offset has been normalized.
12362
 EXAMPLES
12363
 REVISION LOG
12364
--------------------------------------------------------------------------*/
12365
hsize_t
12366
H5S_hyper_get_first_inc_block(const H5S_t *space, hsize_t clip_size, bool *partial)
12367
0
{
12368
0
    H5S_hyper_sel_t *hslab;   /* Convenience pointer to hyperslab info */
12369
0
    H5S_hyper_dim_t *diminfo; /* Convenience pointer to diminfo in unlimited dimension */
12370
0
    hsize_t          ret_value = 0;
12371
12372
0
    FUNC_ENTER_NOAPI(0)
12373
12374
    /* Check parameters */
12375
0
    assert(space);
12376
0
    hslab = space->select.sel_info.hslab;
12377
0
    assert(hslab);
12378
0
    assert(hslab->unlim_dim >= 0);
12379
0
    assert(hslab->diminfo.opt[hslab->unlim_dim].count == H5S_UNLIMITED);
12380
12381
0
    diminfo = &hslab->diminfo.opt[hslab->unlim_dim];
12382
12383
    /* Check for selection outside of clip_size */
12384
0
    if (diminfo->start >= clip_size) {
12385
0
        ret_value = 0;
12386
0
        if (partial)
12387
0
            *partial = false;
12388
0
    } /* end if */
12389
0
    else {
12390
        /* Calculate index of first incomplete block */
12391
0
        ret_value = (clip_size - diminfo->start + diminfo->stride - diminfo->block) / diminfo->stride;
12392
12393
0
        if (partial) {
12394
            /* Check for partial block */
12395
0
            if ((diminfo->stride * ret_value) < (clip_size - diminfo->start))
12396
0
                *partial = true;
12397
0
            else
12398
0
                *partial = false;
12399
0
        } /* end if */
12400
0
    }     /* end else */
12401
12402
0
done:
12403
0
    FUNC_LEAVE_NOAPI(ret_value)
12404
0
} /* end H5S_hyper_get_first_inc_block */
12405
12406
/*--------------------------------------------------------------------------
12407
 NAME
12408
    H5Sis_regular_hyperslab
12409
 PURPOSE
12410
    Determine if a hyperslab selection is regular
12411
 USAGE
12412
    htri_t H5Sis_regular_hyperslab(dsid)
12413
        hid_t dsid;             IN: Dataspace ID of hyperslab selection to query
12414
 RETURNS
12415
    true/false for hyperslab selection, FAIL on error or when querying other
12416
    selection types.
12417
 DESCRIPTION
12418
    If a hyperslab can be represented as a single call to H5Sselect_hyperslab,
12419
    with the H5S_SELECT_SET option, it is regular.  If the hyperslab selection
12420
    would require multiple calls to H5Sselect_hyperslab, it is irregular.
12421
 GLOBAL VARIABLES
12422
 COMMENTS, BUGS, ASSUMPTIONS
12423
 EXAMPLES
12424
 REVISION LOG
12425
--------------------------------------------------------------------------*/
12426
htri_t
12427
H5Sis_regular_hyperslab(hid_t spaceid)
12428
0
{
12429
0
    H5S_t *space;     /* Dataspace to query */
12430
0
    htri_t ret_value; /* Return value */
12431
12432
0
    FUNC_ENTER_API(FAIL)
12433
12434
    /* Check args */
12435
0
    if (NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE)))
12436
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace");
12437
0
    if (H5S_GET_SELECT_TYPE(space) != H5S_SEL_HYPERSLABS)
12438
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a hyperslab selection");
12439
12440
0
    ret_value = H5S__hyper_is_regular(space);
12441
12442
0
done:
12443
0
    FUNC_LEAVE_API(ret_value)
12444
0
} /* end H5Sis_regular_hyperslab() */
12445
12446
/*--------------------------------------------------------------------------
12447
 NAME
12448
    H5Sget_regular_hyperslab
12449
 PURPOSE
12450
    Retrieve a regular hyperslab selection
12451
 USAGE
12452
    herr_t H5Sget_regular_hyperslab(dsid, start, stride, block, count)
12453
        hid_t dsid;             IN: Dataspace ID of hyperslab selection to query
12454
        hsize_t start[];        OUT: Offset of start of hyperslab
12455
        hsize_t stride[];       OUT: Hyperslab stride
12456
        hsize_t count[];        OUT: Number of blocks included in hyperslab
12457
        hsize_t block[];        OUT: Size of block in hyperslab
12458
 RETURNS
12459
    Non-negative on success/Negative on failure.  (It is an error to query
12460
    the regular hyperslab selections for non-regular hyperslab selections)
12461
 DESCRIPTION
12462
    Retrieve the start/stride/count/block for a regular hyperslab selection.
12463
 GLOBAL VARIABLES
12464
 COMMENTS, BUGS, ASSUMPTIONS
12465
    Note that if a hyperslab is originally regular, then becomes irregular
12466
    through selection operations, and then becomes regular again, the new
12467
    final regular selection may be equivalent but not identical to the
12468
    original regular selection.
12469
 EXAMPLES
12470
 REVISION LOG
12471
--------------------------------------------------------------------------*/
12472
herr_t
12473
H5Sget_regular_hyperslab(hid_t spaceid, hsize_t start[] /*out*/, hsize_t stride[] /*out*/,
12474
                         hsize_t count[] /*out*/, hsize_t block[] /*out*/)
12475
0
{
12476
0
    H5S_t   *space;               /* Dataspace to query */
12477
0
    unsigned u;                   /* Local index variable */
12478
0
    herr_t   ret_value = SUCCEED; /* Return value */
12479
12480
0
    FUNC_ENTER_API(FAIL)
12481
12482
    /* Check args */
12483
0
    if (NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE)))
12484
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace");
12485
0
    if (H5S_GET_SELECT_TYPE(space) != H5S_SEL_HYPERSLABS)
12486
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a hyperslab selection");
12487
0
    if (true != H5S__hyper_is_regular(space))
12488
0
        HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a regular hyperslab selection");
12489
12490
    /* Retrieve hyperslab parameters */
12491
0
    if (start)
12492
0
        for (u = 0; u < space->extent.rank; u++)
12493
0
            start[u] = space->select.sel_info.hslab->diminfo.app[u].start;
12494
0
    if (stride)
12495
0
        for (u = 0; u < space->extent.rank; u++)
12496
0
            stride[u] = space->select.sel_info.hslab->diminfo.app[u].stride;
12497
0
    if (count)
12498
0
        for (u = 0; u < space->extent.rank; u++)
12499
0
            count[u] = space->select.sel_info.hslab->diminfo.app[u].count;
12500
0
    if (block)
12501
0
        for (u = 0; u < space->extent.rank; u++)
12502
0
            block[u] = space->select.sel_info.hslab->diminfo.app[u].block;
12503
12504
0
done:
12505
    FUNC_LEAVE_API(ret_value)
12506
0
} /* end H5Sget_regular_hyperslab() */