Coverage Report

Created: 2025-06-20 06:08

/src/c-blosc2/blosc/b2nd_utils.c
Line
Count
Source (jump to first uncovered line)
1
/*********************************************************************
2
  Blosc - Blocked Shuffling and Compression Library
3
4
  Copyright (c) 2021  Blosc Development Team <blosc@blosc.org>
5
  https://blosc.org
6
  License: BSD 3-Clause (see LICENSE.txt)
7
8
  See LICENSE.txt for details about copyright and rights to use.
9
**********************************************************************/
10
11
#include "b2nd.h"
12
13
#include <stdint.h>
14
15
// copyNdim where N = {2-8} - specializations of copy loops to be used by b2nd_copy_buffer
16
// since we don't have c++ templates, substitute manual specializations for up to known B2ND_MAX_DIM (8)
17
// it's not pretty, but it substantially reduces overhead vs. the generic method
18
void copy8dim(const int32_t itemsize,
19
              const int64_t *copy_shape,
20
              const uint8_t *bsrc, const int64_t *src_strides,
21
0
              uint8_t *bdst, const int64_t *dst_strides) {
22
0
  int64_t copy_nbytes = copy_shape[7] * itemsize;
23
0
  int64_t copy_start[7] = {0};
24
0
  do {
25
0
    do {
26
0
      do {
27
0
        do {
28
0
          do {
29
0
            do {
30
0
              do {
31
0
                int64_t src_copy_start = 0;
32
0
                int64_t dst_copy_start = 0;
33
0
                for (int j = 0; j < 7; ++j) {
34
0
                  src_copy_start += copy_start[j] * src_strides[j];
35
0
                  dst_copy_start += copy_start[j] * dst_strides[j];
36
0
                }
37
0
                memcpy(&bdst[dst_copy_start * itemsize], &bsrc[src_copy_start * itemsize], copy_nbytes);
38
0
                ++copy_start[6];
39
0
              } while (copy_start[6] < copy_shape[6]);
40
0
              ++copy_start[5];
41
0
              copy_start[6] = 0;
42
0
            } while (copy_start[5] < copy_shape[5]);
43
0
            ++copy_start[4];
44
0
            copy_start[5] = 0;
45
0
          } while (copy_start[4] < copy_shape[4]);
46
0
          ++copy_start[3];
47
0
          copy_start[4] = 0;
48
0
        } while (copy_start[3] < copy_shape[3]);
49
0
        ++copy_start[2];
50
0
        copy_start[3] = 0;
51
0
      } while (copy_start[2] < copy_shape[2]);
52
0
      ++copy_start[1];
53
0
      copy_start[2] = 0;
54
0
    } while (copy_start[1] < copy_shape[1]);
55
0
    ++copy_start[0];
56
0
    copy_start[1] = 0;
57
0
  } while (copy_start[0] < copy_shape[0]);
58
0
}
59
60
void copy7dim(const int32_t itemsize,
61
              const int64_t *copy_shape,
62
              const uint8_t *bsrc, const int64_t *src_strides,
63
0
              uint8_t *bdst, const int64_t *dst_strides) {
64
0
  int64_t copy_nbytes = copy_shape[6] * itemsize;
65
0
  int64_t copy_start[6] = {0};
66
0
  do {
67
0
    do {
68
0
      do {
69
0
        do {
70
0
          do {
71
0
            do {
72
0
              int64_t src_copy_start = 0;
73
0
              int64_t dst_copy_start = 0;
74
0
              for (int j = 0; j < 6; ++j) {
75
0
                src_copy_start += copy_start[j] * src_strides[j];
76
0
                dst_copy_start += copy_start[j] * dst_strides[j];
77
0
              }
78
0
              memcpy(&bdst[dst_copy_start * itemsize], &bsrc[src_copy_start * itemsize], copy_nbytes);
79
0
              ++copy_start[5];
80
0
            } while (copy_start[5] < copy_shape[5]);
81
0
            ++copy_start[4];
82
0
            copy_start[5] = 0;
83
0
          } while (copy_start[4] < copy_shape[4]);
84
0
          ++copy_start[3];
85
0
          copy_start[4] = 0;
86
0
        } while (copy_start[3] < copy_shape[3]);
87
0
        ++copy_start[2];
88
0
        copy_start[3] = 0;
89
0
      } while (copy_start[2] < copy_shape[2]);
90
0
      ++copy_start[1];
91
0
      copy_start[2] = 0;
92
0
    } while (copy_start[1] < copy_shape[1]);
93
0
    ++copy_start[0];
94
0
    copy_start[1] = 0;
95
0
  } while (copy_start[0] < copy_shape[0]);
96
0
}
97
98
void copy6dim(const int32_t itemsize,
99
              const int64_t *copy_shape,
100
              const uint8_t *bsrc, const int64_t *src_strides,
101
0
              uint8_t *bdst, const int64_t *dst_strides) {
102
0
  int64_t copy_nbytes = copy_shape[5] * itemsize;
103
0
  int64_t copy_start[5] = {0};
104
0
  do {
105
0
    do {
106
0
      do {
107
0
        do {
108
0
          do {
109
0
            int64_t src_copy_start = 0;
110
0
            int64_t dst_copy_start = 0;
111
0
            for (int j = 0; j < 5; ++j) {
112
0
              src_copy_start += copy_start[j] * src_strides[j];
113
0
              dst_copy_start += copy_start[j] * dst_strides[j];
114
0
            }
115
0
            memcpy(&bdst[dst_copy_start * itemsize], &bsrc[src_copy_start * itemsize], copy_nbytes);
116
0
            ++copy_start[4];
117
0
          } while (copy_start[4] < copy_shape[4]);
118
0
          ++copy_start[3];
119
0
          copy_start[4] = 0;
120
0
        } while (copy_start[3] < copy_shape[3]);
121
0
        ++copy_start[2];
122
0
        copy_start[3] = 0;
123
0
      } while (copy_start[2] < copy_shape[2]);
124
0
      ++copy_start[1];
125
0
      copy_start[2] = 0;
126
0
    } while (copy_start[1] < copy_shape[1]);
127
0
    ++copy_start[0];
128
0
    copy_start[1] = 0;
129
0
  } while (copy_start[0] < copy_shape[0]);
130
0
}
131
132
void copy5dim(const int32_t itemsize,
133
              const int64_t *copy_shape,
134
              const uint8_t *bsrc, const int64_t *src_strides,
135
0
              uint8_t *bdst, const int64_t *dst_strides) {
136
0
  int64_t copy_nbytes = copy_shape[4] * itemsize;
137
0
  int64_t copy_start[4] = {0};
138
0
  do {
139
0
    do {
140
0
      do {
141
0
        do {
142
0
          int64_t src_copy_start = 0;
143
0
          int64_t dst_copy_start = 0;
144
0
          for (int j = 0; j < 4; ++j) {
145
0
            src_copy_start += copy_start[j] * src_strides[j];
146
0
            dst_copy_start += copy_start[j] * dst_strides[j];
147
0
          }
148
0
          memcpy(&bdst[dst_copy_start * itemsize], &bsrc[src_copy_start * itemsize], copy_nbytes);
149
0
          ++copy_start[3];
150
0
        } while (copy_start[3] < copy_shape[3]);
151
0
        ++copy_start[2];
152
0
        copy_start[3] = 0;
153
0
      } while (copy_start[2] < copy_shape[2]);
154
0
      ++copy_start[1];
155
0
      copy_start[2] = 0;
156
0
    } while (copy_start[1] < copy_shape[1]);
157
0
    ++copy_start[0];
158
0
    copy_start[1] = 0;
159
0
  } while (copy_start[0] < copy_shape[0]);
160
0
}
161
162
void copy4dim(const int32_t itemsize,
163
              const int64_t *copy_shape,
164
              const uint8_t *bsrc, const int64_t *src_strides,
165
0
              uint8_t *bdst, const int64_t *dst_strides) {
166
0
  int64_t copy_nbytes = copy_shape[3] * itemsize;
167
0
  int64_t copy_start[3] = {0};
168
0
  do {
169
0
    do {
170
0
      do {
171
0
        int64_t src_copy_start = 0;
172
0
        int64_t dst_copy_start = 0;
173
0
        for (int j = 0; j < 3; ++j) {
174
0
          src_copy_start += copy_start[j] * src_strides[j];
175
0
          dst_copy_start += copy_start[j] * dst_strides[j];
176
0
        }
177
0
        memcpy(&bdst[dst_copy_start * itemsize], &bsrc[src_copy_start * itemsize], copy_nbytes);
178
0
        ++copy_start[2];
179
0
      } while (copy_start[2] < copy_shape[2]);
180
0
      ++copy_start[1];
181
0
      copy_start[2] = 0;
182
0
    } while (copy_start[1] < copy_shape[1]);
183
0
    ++copy_start[0];
184
0
    copy_start[1] = 0;
185
0
  } while (copy_start[0] < copy_shape[0]);
186
0
}
187
188
void copy3dim(const int32_t itemsize,
189
              const int64_t *copy_shape,
190
              const uint8_t *bsrc, const int64_t *src_strides,
191
0
              uint8_t *bdst, const int64_t *dst_strides) {
192
0
  int64_t copy_nbytes = copy_shape[2] * itemsize;
193
0
  int64_t copy_start[2] = {0};
194
0
  do {
195
0
    do {
196
0
      int64_t src_copy_start = 0;
197
0
      int64_t dst_copy_start = 0;
198
0
      for (int j = 0; j < 2; ++j) {
199
0
        src_copy_start += copy_start[j] * src_strides[j];
200
0
        dst_copy_start += copy_start[j] * dst_strides[j];
201
0
      }
202
0
      memcpy(&bdst[dst_copy_start * itemsize], &bsrc[src_copy_start * itemsize], copy_nbytes);
203
0
      ++copy_start[1];
204
0
    } while (copy_start[1] < copy_shape[1]);
205
0
    ++copy_start[0];
206
0
    copy_start[1] = 0;
207
0
  } while (copy_start[0] < copy_shape[0]);
208
0
}
209
210
void copy2dim(const int32_t itemsize,
211
              const int64_t *copy_shape,
212
              const uint8_t *bsrc, const int64_t *src_strides,
213
0
              uint8_t *bdst, const int64_t *dst_strides) {
214
0
  int64_t copy_nbytes = copy_shape[1] * itemsize;
215
0
  int64_t copy_start = 0;
216
0
  do {
217
0
    int64_t src_copy_start = copy_start * src_strides[0];
218
0
    int64_t dst_copy_start = copy_start * dst_strides[0];
219
0
    memcpy(&bdst[dst_copy_start * itemsize], &bsrc[src_copy_start * itemsize], copy_nbytes);
220
0
    ++copy_start;
221
0
  } while (copy_start < copy_shape[0]);
222
0
}
223
224
225
void copy_ndim_fallback(const int8_t ndim,
226
                        const int32_t itemsize,
227
                        int64_t *copy_shape,
228
                        const uint8_t *bsrc, int64_t *src_strides,
229
0
                        uint8_t *bdst, int64_t *dst_strides) {
230
0
  int64_t copy_nbytes = copy_shape[ndim - 1] * itemsize;
231
0
  int64_t number_of_copies = 1;
232
0
  for (int i = 0; i < ndim - 1; ++i) {
233
0
    number_of_copies *= copy_shape[i];
234
0
  }
235
0
  for (int ncopy = 0; ncopy < number_of_copies; ++ncopy) {
236
    // Compute the start of the copy
237
0
    int64_t copy_start[B2ND_MAX_DIM] = {0};
238
0
    blosc2_unidim_to_multidim((int8_t) (ndim - 1), copy_shape, ncopy, copy_start);
239
240
    // Translate this index to the src buffer
241
0
    int64_t src_copy_start;
242
0
    blosc2_multidim_to_unidim(copy_start, (int8_t) (ndim - 1), src_strides, &src_copy_start);
243
244
    // Translate this index to the dst buffer
245
0
    int64_t dst_copy_start;
246
0
    blosc2_multidim_to_unidim(copy_start, (int8_t) (ndim - 1), dst_strides, &dst_copy_start);
247
248
    // Perform the copy
249
0
    memcpy(&bdst[dst_copy_start * itemsize],
250
0
           &bsrc[src_copy_start * itemsize],
251
0
           copy_nbytes);
252
0
  }
253
0
}
254
255
int b2nd_copy_buffer2(int8_t ndim,
256
                      int32_t itemsize,
257
                      const void *src, const int64_t *src_pad_shape,
258
                      const int64_t *src_start, const int64_t *src_stop,
259
                      void *dst, const int64_t *dst_pad_shape,
260
0
                      const int64_t *dst_start) {
261
  // Compute the shape of the copy
262
0
  int64_t copy_shape[B2ND_MAX_DIM] = {0};
263
0
  for (int i = 0; i < ndim; ++i) {
264
0
    copy_shape[i] = src_stop[i] - src_start[i];
265
0
    if (copy_shape[i] == 0) {
266
0
      return BLOSC2_ERROR_SUCCESS;
267
0
    }
268
0
  }
269
270
  // Compute the strides
271
0
  int64_t src_strides[B2ND_MAX_DIM] = {0};
272
0
  src_strides[ndim - 1] = 1;
273
0
  for (int i = ndim - 2; i >= 0; --i) {
274
0
    src_strides[i] = src_strides[i + 1] * src_pad_shape[i + 1];
275
0
  }
276
277
0
  int64_t dst_strides[B2ND_MAX_DIM] = {0};
278
0
  dst_strides[ndim - 1] = 1;
279
0
  for (int i = ndim - 2; i >= 0; --i) {
280
0
    dst_strides[i] = dst_strides[i + 1] * dst_pad_shape[i + 1];
281
0
  }
282
283
  // Align the buffers removing unnecessary data
284
0
  int64_t src_start_n;
285
0
  blosc2_multidim_to_unidim(src_start, ndim, src_strides, &src_start_n);
286
0
  uint8_t *bsrc = (uint8_t *) src;
287
0
  bsrc = &bsrc[src_start_n * itemsize];
288
289
0
  int64_t dst_start_n;
290
0
  blosc2_multidim_to_unidim(dst_start, ndim, dst_strides, &dst_start_n);
291
0
  uint8_t *bdst = (uint8_t *) dst;
292
0
  bdst = &bdst[dst_start_n * itemsize];
293
294
0
  switch (ndim) {
295
0
    case 1:
296
0
      memcpy(&bdst[0], &bsrc[0], copy_shape[0] * itemsize);
297
0
      break;
298
0
    case 2:
299
0
      copy2dim(itemsize, copy_shape, bsrc, src_strides, bdst, dst_strides);
300
0
      break;
301
0
    case 3:
302
0
      copy3dim(itemsize, copy_shape, bsrc, src_strides, bdst, dst_strides);
303
0
      break;
304
0
    case 4:
305
0
      copy4dim(itemsize, copy_shape, bsrc, src_strides, bdst, dst_strides);
306
0
      break;
307
0
    case 5:
308
0
      copy5dim(itemsize, copy_shape, bsrc, src_strides, bdst, dst_strides);
309
0
      break;
310
0
    case 6:
311
0
      copy6dim(itemsize, copy_shape, bsrc, src_strides, bdst, dst_strides);
312
0
      break;
313
0
    case 7:
314
0
      copy7dim(itemsize, copy_shape, bsrc, src_strides, bdst, dst_strides);
315
0
      break;
316
0
    case 8:
317
0
      copy8dim(itemsize, copy_shape, bsrc, src_strides, bdst, dst_strides);
318
0
      break;
319
0
    default:
320
      // guard against potential future increase to B2ND_MAX_DIM
321
0
      copy_ndim_fallback(ndim, itemsize, copy_shape, bsrc, src_strides, bdst, dst_strides);
322
0
      break;
323
0
  }
324
325
0
  return BLOSC2_ERROR_SUCCESS;
326
0
}
327
328
329
// Keep the old signature for API compatibility
330
int b2nd_copy_buffer(int8_t ndim,
331
                     uint8_t itemsize,
332
                     const void *src, const int64_t *src_pad_shape,
333
                     const int64_t *src_start, const int64_t *src_stop,
334
                     void *dst, const int64_t *dst_pad_shape,
335
0
                     const int64_t *dst_start) {
336
  // Simply cast itemsize to int32_t and delegate
337
0
  return b2nd_copy_buffer2(ndim, (int32_t)itemsize, src, src_pad_shape,
338
0
                          src_start, src_stop, dst, dst_pad_shape, dst_start);
339
0
}