1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
/**
* .. _asdf/core/ndarray.h:
*
* Minimalistic prototype implementation of the
* :ref:`stsci.edu/asdf/core/ndarray-1.1.0` schema
*
* Support is not yet fully complete. What is implemented:
*
* * ASDF internal block sources
* * All int and most float data types (other data types can be read but are
* not fully implemented)
* * :c:member:`shape <asdf_ndarray_t.shape>`,
* :c:member:`byteorder <asdf_ndarray_t.byteorder>`, and
* :c:member:`offset <asdf_ndarray_t.offset>`
* * :c:member:`strides <asdf_ndarray_t.strides>` are partially supported
*
* It can provide direct access to the raw data of an ndarray (via a
* ``void *``); users must use
* the metadata provided in the `asdf_ndarray_t` struct to interpret the data.
* However, data can also be copied as tiles using the
* `asdf_ndarray_read_tile_ndim` and `asdf_ndarray_read_tile_2d` functions.
*
*
* What is not yet supported:
*
* * Shape containing '*'
* * Reading ``complex64`` or ``complex128`` datatypes
* * Reading string datatypes (``ascii`` or ``ucs4``)
* * Reading structured datatypes (the datatypes are parsed but there is are
* no APIs yet for interpreting structured array data)
* * Reading arbitrarily strided data
* * Masks are not parsed or used at all, whether simple mask values or mask
* arrays (though if present a warning is logged indicating lack of support)
*
* The current limitations are purely artificial--it is so that we can rapidly
* develop the minimal viable product needed to make ASDF ndarray data
* available in common use cases.
*
* Complete ndarray support will follow gradually.
*/
//
/**
* .. _ndarray-types:
*
* Types
* -----
*/
/**
* Error codes returned by some functions that read ndarray data
*/
typedef enum asdf_ndarray_err_t;
/**
* Public definition of the `asdf_ndarray_t` type
*
* This is the main object through which ndarrays are used. They can be
* retrieved via `asdf_get_ndarray` and `asdf_value_as_ndarray`. The library
* allocates memory for this data structure which must be freed by the user with
* `asdf_ndarray_destroy` when no-longer needed.
*
* For convenience some basic fields are made public for now, though this may
* not be ABI-stable in future releases.
*/
typedef struct asdf_ndarray_t;
typedef struct asdf_ndarray asdf_ndarray_t;
/**
* .. _ndarray-get:
*
* Getting ndarrays
* ----------------
*/
// NOTE: For now I don't see any good way to generate docstrings for functions
// generated by ASDF_DECLARE_EXTENSION, so we just insert them manually for
// now. Should be possible with a custom extension to Sphinx (or Hawkmoth)
// but not worth the effort short-term.
//
// clang-format off
/**
* .. c:function:: asdf_value_err_t asdf_get_ndarray(asdf_file_t *file, const char *path, asdf_ndarray_t **out)
*
* Get an `asdf_ndarray_t *` out of the ASDF tree
*
* :param file: The `asdf_file_t *` for the file
* :param path: The :ref:`yaml-pointer` to the ndarray
* :param out: An `asdf_ndarray_t **` into which to return the `asdf_ndarray_t *`
*
* :return: `ASDF_VALUE_OK` if the value exists and is an ndarray, otherwise
* `ASDF_VALUE_ERR_NOT_FOUND` or `ASDF_VALUE_ERR_TYPE_MISMATCH`.
*/
/**
* .. c:function:: asdf_value_err_t asdf_set_ndarray(asdf_file_t *file, const char *path, asdf_ndarray_t *ndarray)
*
* Set an `asdf_ndarray_t *` to a path in the ASDF tree
*
* This is used to add a new ndarray to the file at a given path. If the
* ndarray has data allocated for it and is set to internal storage (see
* `asdf_ndarray_storage_set`, a new binary block will be allocated for its
* data when writing the file.
*
* :param file: The `asdf_file_t *` for the file
* :param path: The :ref:`yaml-pointer` for the ndarray
* :param ndarray: An `asdf_ndarray_t *` to store
*
* :return: `ASDF_VALUE_OK` if the value exists and is an ndarray, otherwise
* an error if an inconsistency in the `asdf_ndarray_t` struct prevents
* serialization.
*/
/**
* .. c:function:: asdf_value_err_t asdf_value_as_ndarray(asdf_value_t *value, asdf_ndarray_t **out)
*
* Cast a generic `asdf_value_t *` as an ndarray value, if possible
*
* :param value: The `asdf_value_t *` handle
* :param out: An `asdf_ndarray_t **` into which to return the `asdf_ndarray_t *`
*
* :return: `ASDF_VALUE_OK` if the value is an ndarray, otherwise
* `ASDF_VALUE_ERR_TYPE_MISMATCH`.
*/
/**
* .. c:function:: asdf_value_t *asdf_value_of_ndarray(asdf_file_t *file, const asdf_ndarray_t *ndarray)
*
* Create a generic `asdf_value_t *` from an ndarray
*
* This serializes ``ndarray`` into a value belonging to ``file`` (as
* `asdf_set_ndarray` does before placing it in the tree), which can then be
* assigned into the tree with `asdf_set_value` or nested inside another value.
* As with `asdf_set_ndarray`, assigning the ndarray this way transfers
* ownership of its data to ``file``.
*
* :param file: The `asdf_file_t *` for the file
* :param ndarray: The `asdf_ndarray_t *` to serialize
*
* :return: A new `asdf_value_t *`, or ``NULL`` on failure
*/
/**
* .. c:function:: void asdf_ndarray_destroy(asdf_ndarray_t *ndarray)
*
* Release datastructures and memory allocated for an `asdf_ndarray_t`
*
* :param ndarray: The `asdf_ndarray_t *`
*/
/**
* .. c:function:: asdf_ndarray_t *asdf_ndarray_copy(asdf_file_t *file, const asdf_ndarray_t *src)
*
* Make an independent deep copy of an ndarray
*
* The copy duplicates ``src``'s metadata (shape, strides, and datatype) and
* its data: an inline array clones its inline data, while a block-backed array
* copies its block into a new block managed for ``file`` (preserving
* compression). Because the copy is fully independent of ``src`` and its
* file, ``file`` may differ from the source's file, and the returned ndarray
* can be assigned (`asdf_set_ndarray`) and written like any other.
*
* The returned `asdf_ndarray_t *` is owned by the caller and must be released
* with `asdf_ndarray_destroy` (unless assigned to a file, which then takes
* ownership of its data).
*
* :param file: The `asdf_file_t *` that will manage the copy's data
* :param src: The `asdf_ndarray_t *` to copy
* :return: A newly allocated `asdf_ndarray_t *`, or ``NULL`` on failure
*/
// clang-format on
;
/**
* .. _ndarray-data-access:
*
* Data access
* -----------
*/
/**
* Return a pointer to the ndarray's element data
*
* If the array is stored in a compressed block a buffer containing the
* decompressed data is returned (see also :ref:`compression`).
* The data is presented in the array's source datatype and byte order;
* use `asdf_ndarray_read_all` or the ``asdf_ndarray_read_tile_*``
* functions to read it converted to a host datatype and native byte order.
*
* The returned pointer is owned by ``ndarray`` and remains valid until the
* ndarray (or its file) is destroyed; the caller must not free it.
*
* :param ndarray: An `asdf_ndarray_t *`
* :param size: If non-``NULL``, receives the size of the data in bytes
* :return: A pointer to the (decompressed) data, or ``NULL`` on error -- for
* example if the array has no associated data block (such as an inline
* array) or if decompression failed
*/
ASDF_EXPORT const void *;
/**
* Return a pointer to the raw ndarray data, without decompressing it
*
* For arrays stored in a compressed block this returns the still-compressed
* bytes exactly as they appear in the file. For uncompressed arrays it is
* equivalent to `asdf_ndarray_data`.
*
* As with `asdf_ndarray_data`, the returned pointer is owned by ``ndarray``
* and must not be freed by the caller.
*
* :param ndarray: An `asdf_ndarray_t *`
* :param size: If non-``NULL``, receives the size of the raw data in bytes
* :return: A pointer to the raw data, or ``NULL`` on error
*/
ASDF_EXPORT const void *;
/**
* Return the total number of elements (not bytes) in the ndarray
*
* :param ndarray: An `asdf_ndarray_t *`
* :return: Total number of elements in the array (just the product of its
* shape)
*/
ASDF_EXPORT uint64_t ;
/**
* Return the total number of bytes in the ndarray data
*
* :param ndarray: An `asdf_ndarray_t *`
* :return: The byte size of the ndarray (this is just its size times the
* datatype nbytes)
*/
ASDF_EXPORT uint64_t ;
/**
* .. _ndarray-alloc:
*
* Allocating data buffers
* -----------------------
*/
/**
* Allocate heap memory large enough to store the data for the ndarray
*
* Every call to this function should have a corresponding
* `asdf_ndarray_data_dealloc` to free the allocated memory when it is
* no longer needed (such as after writing the file). The memory is not
* automatically freed.
*
* :param ndarray: An `asdf_ndarray_t *`
* :return: A `void *` to the allocated memory or `NULL` if the memory
* could not be allocated; subsequent calls on the same ndarray will
* return the same memory
*/
ASDF_EXPORT void *;
/**
* Free ndarray data allocated with `asdf_ndarray_data_alloc`
*
* If the ndarray never had data allocated this is a no-op but does produce
* a debug log message if logging is enabled.
*
* :param ndarray: An `asdf_ndarray_t *`
*/
ASDF_EXPORT void ;
/**
* Allocate the ndarray's data buffer and copy its contents from a source buffer
*
* A convenience over `asdf_ndarray_data_alloc` for the common case of building
* an ndarray whose data you already have: it allocates a buffer sized for the
* array's shape and datatype (exactly as `asdf_ndarray_data_alloc`) and copies
* `asdf_ndarray_nbytes` bytes into it from ``src``. This computes the byte
* count for you, avoiding error-prone manual size arithmetic.
*
* The caller is responsible for ensuring ``src`` points to at least
* `asdf_ndarray_nbytes` bytes; a smaller source buffer results in an over-read.
*
* :param ndarray: An `asdf_ndarray_t *` whose shape and datatype are set
* :param src: The source buffer to copy the array data from
* :return: `ASDF_NDARRAY_OK` on success, `ASDF_NDARRAY_ERR_INVAL` if an argument
* is ``NULL``, or `ASDF_NDARRAY_ERR_OOM` if the buffer could not be allocated
*/
ASDF_EXPORT asdf_ndarray_err_t ;
/**
* .. _ndarray-storage:
*
* Storage and compression
* -----------------------
*/
/**
* Set the compression method to use for the ndarray data when writing
*
* See also `asdf_block_compression_set` for which this is a shortcut (applies
* to the block created for holding this ndarray's data).
*
* :param ndarray: An `asdf_ndarray_t *` handle
* :param compression: String representing the compressor to use (e.g. "bzp2")
* if any, or NULL or the empty string to set no compression
* :return: Non-zero if the compression could not be set (e.g. invalid/unknown
* compressor); use `asdf_error` to check the error code
*/
ASDF_EXPORT int ;
/**
* Return the storage mode that will be used when the ndarray is written.
*
* If the ndarray was read from a file this reflects how it was originally
* stored. For a newly constructed ndarray this reflects whatever was last
* passed to `asdf_ndarray_storage_set`, or ``ASDF_ARRAY_STORAGE_INTERNAL``
* if the storage was never explicitly set.
*
* :param ndarray: An `asdf_ndarray_t *`
* :return: The `asdf_array_storage_t` for this ndarray.
*/
ASDF_EXPORT asdf_array_storage_t ;
/**
* Set the storage mode used when the ndarray is written.
*
* ``ASDF_ARRAY_STORAGE_INLINE`` serializes the data as a nested YAML
* sequence under the ``data`` key. A warning is logged if the number of
* elements exceeds the configured threshold (see
* ``asdf_emitter_cfg_t.inline_ndarray_warning_thresh``).
*
* ``ASDF_ARRAY_STORAGE_INTERNAL`` writes the data in a binary block (the
* default when no storage mode is set).
*
* ``ASDF_ARRAY_STORAGE_EXTERNAL`` is not yet supported; calling this function
* with that value logs an error and leaves the storage mode unchanged.
*
* :param ndarray: An `asdf_ndarray_t *`
* :param storage: The desired `asdf_array_storage_t`
*/
ASDF_EXPORT void ;
/**
* Get the pointer to the open `asdf_block_t` associated with the ndarray
*
* This is mostly for debugging/low-level inspection and is not needed for
* typical use cases.
*
* :param ndarray: An `asdf_ndarray_t *`
* :return: A constant pointer to the `asdf_block_t` structure representing
* the binary block underlying the array, if any. This will be `NULL`, for
* example, if the ndarray used inline data.
*/
ASDF_EXPORT asdf_block_t *;
/**
* .. _ndarray-read:
*
* Reading array data
* ------------------
*/
/**
* Read the full ndarray, copying into the provided buffer (or allocating a
* destination buffer if ``dst = NULL``)
*
* This is like `asdf_ndarray_read_tile_ndim` but with a default "tile" size
* of the full array. Like `asdf_ndarray_read_tile_ndim` it will also convert
* the data to the host native byte order if necessary, and can convert it to a
* different numeric type than the source array.
*
* :param ndarray: The `asdf_ndarray_t *` handle to the ndarray
* :param dst_t: An `asdf_scalar_datatype_t` to convert to, or
* `ASDF_DATATYPE_SOURCE` to keep the original source datatype
* :param dst: Pointer to a destination `void *` already allocated to receive
* the exact number of bytes in the source ndarray, or `NULL` to indicate
* that a buffer should be allocated. In the latter case the caller is
* responsible for releasing the allocated buffer with `asdf_free`.
* :return: An `asdf_ndarray_err_t`; either `ASDF_NDARRAY_OK` if the data read
* successfully; otherwise the relevant error code.
*/
ASDF_EXPORT ;
/**
* Read tiles of up to N-dimensions out of N-D arrays
*
* Tiles can be slices of any number of dimenions <= N and of any shape so long
* as they don't go past the bounds of the array (otherwise
* `ASDF_NDARRAY_ERR_OUT_OF_BOUNDS` is returned).
*
* :param ndarray: The `asdf_ndarray_t *` handle to the ndarray
* :param origin: The indices of the first pixel of the tile--an array of size
* :c:member:`ndim <asdf_ndarray_t.ndim>`
* :param shape: The shape of the tile to read--an array of size
* :c:member:`ndim <asdf_ndarray_t.ndim>`
* :param dst_t: The output datatype, if conversion from the source array's
* datatype to the output datatype is possible
*
* Currently, if no conversion is possible it will just copy the tile data
* without conversion--this may change in the future to become an error.
* You can pass the special value `ASDF_DATATYPE_SOURCE` to indicate that
* the output datatype is the source datatype.
* :param dst: Pointer to a destination `void *` already allocated to receive
* the exact number of bytes in the output tile based on shape and datatype,
* or `NULL` to indicate that a buffer should be allocated. In the latter
* case the caller is responsible for releasing the allocated buffer with
* `asdf_free`.
* :return: An `asdf_ndarray_err_t`; either `ASDF_NDARRAY_OK` if the data read
* successfully; otherwise the relevant error code.
*/
ASDF_EXPORT asdf_ndarray_err_t ;
/**
* Like `asdf_ndarray_read_tile_ndim` but with conveniences for the common 2-D
* case
*
* :param ndarray: The `asdf_ndarray_t *` handle to the ndarray
* :param x: The x coordinate of the tile origin
* :param y: The y coordinate of the tile origin
* :param width: The width of the tile in the x direction
* :param height: The height of the tile in the y direction
* :param plane_origin: If the source array is greater than 2-dimensional, the
* ``ndim - 2`` array of plane coordinates--may be `NULL` if either the source
* array is 2-D or otherwise the outer-most plane is used
* :param dst_t: The output datatype, if conversion from the source array's
* datatype to the output datatype is possible
*
* Currently, if no conversion is possible it will just copy the tile data
* without conversion--this may change in the future to become an error.
* You can pass the special value `ASDF_DATATYPE_SOURCE` to indicate that
* the output datatype is the source datatype.
* :param dst: Pointer to a destination `void *` already allocated to receive
* the exact number of bytes in the output tile based on shape and datatype,
* or `NULL` to indicate that a buffer should be allocated. In the latter
* case the caller is responsible for releasing the allocated buffer with
* `asdf_free`.
* :return: An `asdf_ndarray_err_t`; either `ASDF_NDARRAY_OK` if the data read
* successfully; otherwise the relevant error code.
*/
ASDF_EXPORT asdf_ndarray_err_t ;
// Forward-declaration for documentation; the real implementations of
// asdf_read_at and asdf_read_at_err are later in this file.
/**
* Read the element at the given indices, converted to ``type``
*
* ``type`` must be one of the C scalar types named by the
* ``asdf_ndarray_read_<type>_at`` functions. The number of indices is taken
* from the number of arguments, and must equal the array's
* :c:member:`ndim <asdf_ndarray_t.ndim>`. At least one index is required::
*
* double value = asdf_ndarray_at(ndarray, double, 3, 7);
*
* Errors are not reported: on any error the value is zero, which is
* indistinguishable from an element whose value is zero. Use
* `asdf_ndarray_at_err` where that matters.
*
* This is a macro and is unavailable in C++; use the
* ``asdf_ndarray_read_<type>_at`` functions instead.
*
* :param ndarray: The `asdf_ndarray_t *` handle to the ndarray
* :param type: The C scalar type to convert the element to
* :param ...: The indices of the element to read
* :return: The element converted to ``type``, or zero on error
*/
/**
* Like `asdf_ndarray_at` but reporting errors through ``err``
*
* The indices are given as a variadic argument list after ``err``::
*
* asdf_ndarray_err_t err = ASDF_NDARRAY_OK;
* double value = asdf_ndarray_at_err(ndarray, double, &err, 3, 7);
*
* :param ndarray: The `asdf_ndarray_t *` handle to the ndarray
* :param type: The C scalar type to convert the element to
* :param err: An `asdf_ndarray_err_t *` receiving the error code, or ``NULL``
* :param ...: The indices of the element to read
* :return: The element converted to ``type``, or zero on error
*/
/**
* Read a single element of the ndarray, converting it as `asdf_ndarray_read_all`
* does
*
* The element is copied into ``dst``, which must have room for one value of
* ``dst_t``. ``dst`` need not be aligned for its type.
*
* For C code the `asdf_ndarray_at` and `asdf_ndarray_at_err` macros are more
* convenient.
*
* .. note::
*
* If reading many elements of an array in a loop this call is inefficient;
* it is better to read multiple elements in a single pass using
* `asdf_ndarray_read_tile_ndim`, `asdf_ndarray_read_tile_2d` or
* `asdf_ndarray_read_all` depending on the use case. This method can still
* be useful for a few incidental single-element reads.
*
* ``indices`` must have :c:member:`ndim <asdf_ndarray_t.ndim>` entries; that
* many are read from it.
*
* :param ndarray: The `asdf_ndarray_t *` handle to the ndarray
* :param indices: The indices of the element to read--an array of size
* :c:member:`ndim <asdf_ndarray_t.ndim>`
* :param dst_t: An `asdf_scalar_datatype_t` to convert to, or
* `ASDF_DATATYPE_SOURCE` to keep the original source datatype
* :param dst: Pointer to storage receiving the element
* :return: An `asdf_ndarray_err_t`; `ASDF_NDARRAY_OK` if the element was read
* successfully, `ASDF_NDARRAY_ERR_OUT_OF_BOUNDS` if any index is outside the
* array's shape; otherwise the relevant error code.
*/
ASDF_EXPORT asdf_ndarray_err_t ;
/**
* Read a single element of the ndarray, converted to the named type
*
* These are the same as `asdf_ndarray_read_at` with ``dst_t`` fixed by the
* function name, except that the element is returned rather than copied into
* ``dst``. On error the returned value is zero and, if ``err`` is not
* ``NULL``, the error code is stored in it.
*
* The `asdf_ndarray_at` and `asdf_ndarray_at_err` macros select among these
* automatically and are usually easier to read. They are unavailable in C++,
* which must call these directly.
*
* ``indices`` must have :c:member:`ndim <asdf_ndarray_t.ndim>` entries; that
* many are read from it.
*
* :param ndarray: The `asdf_ndarray_t *` handle to the ndarray
* :param indices: The indices of the element to read--an array of size
* :c:member:`ndim <asdf_ndarray_t.ndim>`
* :param err: Optional `asdf_ndarray_err_t *` receiving the error code, or
* ``NULL`` to ignore errors
* :return: The element converted to the function's type, or zero on error
*/
ASDF_EXPORT int8_t ;
/** See `asdf_ndarray_read_int8_at` */
ASDF_EXPORT uint8_t ;
/** See `asdf_ndarray_read_int8_at` */
ASDF_EXPORT int16_t ;
/** See `asdf_ndarray_read_int8_at` */
ASDF_EXPORT uint16_t ;
/** See `asdf_ndarray_read_int8_at` */
ASDF_EXPORT int32_t ;
/** See `asdf_ndarray_read_int8_at` */
ASDF_EXPORT uint32_t ;
/** See `asdf_ndarray_read_int8_at` */
ASDF_EXPORT int64_t ;
/** See `asdf_ndarray_read_int8_at` */
ASDF_EXPORT uint64_t ;
/** See `asdf_ndarray_read_int8_at`; declared only if ``ASDF_HAVE_FLOAT16`` */
ASDF_EXPORT _Float16 ;
/** See `asdf_ndarray_read_int8_at` */
ASDF_EXPORT float ;
/** See `asdf_ndarray_read_int8_at` */
ASDF_EXPORT double ;
/* Selects the asdf_ndarray_read_<type>_at function for a C scalar type */
// clang-format off
// clang-format on
/* The indices appear twice, but the operand of sizeof is not evaluated */
/*
* The read functions take ndim indices, so passing the wrong number of them
* would read past the end of the array built above. Substitute NULL in that
* case, which the read functions reject with ASDF_NDARRAY_ERR_INVAL.
*/
/* Implementation of asdf_ndarray_at; see documentation further up */
/* Implementation of asdf_ndarray_at_err; see documentation further up */
/* __cplusplus */
/* ASDF_CORE_NDARRAY_H */