|
10 | 10 | #include "H5Sall.hpp" |
11 | 11 | #include "H5capi.hpp" |
12 | 12 |
|
| 13 | +// Return-type macro for h5::create<T>(parent, path, ...). |
| 14 | +// Real compile: the SFINAE-constrained h5::impl::attr_parent_t<hid_t> |
| 15 | +// alias — only parents that can carry attributes (file, group, |
| 16 | +// dataset, opaque object, committed datatype) participate in overload |
| 17 | +// resolution. |
| 18 | +// Doxygen : collapses to plain h5::at_t so the rendered signature |
| 19 | +// reads cleanly without leaking the std::enable_if_t<...> machinery |
| 20 | +// into the headline. Gated on H5CPP_DOXYGEN from doxy/Doxyfile. |
| 21 | +#ifdef H5CPP_DOXYGEN |
| 22 | +# define H5CPP_ATTR_CREATE_RET(hid_t) h5::at_t |
| 23 | +#else |
| 24 | +# define H5CPP_ATTR_CREATE_RET(hid_t) h5::impl::attr_parent_t<hid_t> |
| 25 | +#endif |
13 | 26 |
|
14 | 27 | namespace h5 { |
15 | 28 | namespace impl { |
16 | | - /*this template defines what HDF5 object types may have attributes */ |
17 | 29 | template <class H, class T=void> using is_valid_attr = |
18 | 30 | std::bool_constant<std::is_same_v<H, ::hid_t> || |
19 | 31 | std::is_same_v<H, h5::gr_t> || std::is_same_v<H, h5::ds_t> || |
20 | 32 | std::is_same_v<H, h5::ob_t> || std::is_same_v<H, h5::dt_t<T>>>; |
21 | 33 | /*template <class H, class T=void> using is_valid_attr = |
22 | 34 | std::bool_constant<std::is_same_v<H, h5::ds_t>>;*/ |
| 35 | + |
| 36 | + template <class hid_t> |
| 37 | + using attr_parent_t = std::enable_if_t<is_valid_attr<hid_t>::value, h5::at_t>; |
23 | 38 | } |
24 | 39 |
|
25 | | - template<class T, class HID_T, class... args_t> |
26 | | - inline std::enable_if_t<h5::impl::is_valid_attr<HID_T>::value, |
27 | | - h5::at_t> create( const HID_T& parent, const std::string& path, args_t&&... args ){ |
| 40 | + /** |
| 41 | + * \func_attr_hdr |
| 42 | + * @brief Create a new attribute of element type `T` on a parent HDF5 object. |
| 43 | + * |
| 44 | + * Attributes are small named metadata items attached to a parent object (file, group, dataset, opaque object, or committed datatype). |
| 45 | + * `h5::create` allocates the on-disk slot — the value itself is later deposited with `h5::awrite(parent, path, value)` or read back with |
| 46 | + * `h5::aread<T>(parent, path)`. The element type `T` follows the same dispatch as the dataset API (see @ref link_base_template_types |
| 47 | + * "Supported Types"): elementary scalar, registered compound, fixed or variable-length string, etc. Attributes do not chunk and do not |
| 48 | + * support partial I/O, so neither `h5::chunk{}` nor offset/stride/count apply here. |
| 49 | + * |
| 50 | + * @param parent open parent handle: raw `::hid_t`, `h5::gr_t`, `h5::ds_t`, `h5::ob_t`, or `h5::dt_t<T>` — enforced at compile |
| 51 | + * time via `h5::impl::is_valid_attr`. Note: typed `h5::fd_t` is **not** accepted directly; pass `static_cast<::hid_t>(fd)` |
| 52 | + * to attach an attribute to the file root. |
| 53 | + * @param path attribute name (UTF-8); resolved relative to `parent`. |
| 54 | + * \par_args_attr |
| 55 | + * \tpar_T |
| 56 | + * @tparam hid_t deduced from the `parent` argument; must satisfy `h5::impl::is_valid_attr<hid_t>::value`. |
| 57 | + * @return `h5::at_t` RAII handle owning the new attribute id; closes |
| 58 | + * automatically via `H5Aclose` on scope exit. Throws on failure. |
| 59 | + * |
| 60 | + * The optional arguments are context-sensitive and may be passed in any order. By default the attribute is created with an empty |
| 61 | + * (rank-0) shape and the default attribute creation property list: |
| 62 | + * |
| 63 | + * \par_current_dims |
| 64 | + * Defaults to `{0}` — a scalar attribute. Pass a non-trivial extent for an array-valued attribute (e.g. `h5::current_dims{8}` for an |
| 65 | + * 8-element vector attribute). |
| 66 | + * |
| 67 | + * @param acpl attribute creation property list (`h5::acpl_t`); defaults to `H5P_ATTRIBUTE_CREATE`. |
| 68 | + * |
| 69 | + * @throws h5::error::io::attribute::create on `H5Acreate2` failure (parent does not exist, attribute already exists, type |
| 70 | + * conversion error, etc.). |
| 71 | + * @throws h5::error::property_list::misc when an invalid acpl is supplied. |
| 72 | + * |
| 73 | + * <br/><b>example:</b> explicit pre-allocation — useful when the shape |
| 74 | + * is non-default or you want the attribute slot to exist before any |
| 75 | + * value is written. Most call sites skip `h5::create<T>` and let |
| 76 | + * `h5::awrite` create-on-demand instead. |
| 77 | + * @code |
| 78 | + * h5::fd_t fd = h5::open("file.h5", H5F_ACC_RDWR); |
| 79 | + * h5::ds_t ds = h5::open(fd, "/grid/data"); |
| 80 | + * |
| 81 | + * // rank-1 of 3 floats; deposit the value later with h5::awrite. |
| 82 | + * h5::create<float>(ds, "spacing", h5::current_dims{3}); |
| 83 | + * |
| 84 | + * // Scalar attribute on the file root — fd_t needs an explicit cast |
| 85 | + * // (h5::fd_t is not in is_valid_attr; raw ::hid_t is). |
| 86 | + * h5::create<double>(static_cast<::hid_t>(fd), "schema_version"); |
| 87 | + * |
| 88 | + * // Round-trip with h5::awrite / h5::aread: |
| 89 | + * h5::awrite(ds, "spacing", std::vector<float>{0.5f, 0.5f, 1.0f}); |
| 90 | + * auto v = h5::aread<std::vector<float>>(ds, "spacing"); |
| 91 | + * @endcode |
| 92 | + * |
| 93 | + * \sa_h5cpp |
| 94 | + * \sa_hdf5 |
| 95 | + * @sa h5::aread h5::awrite @ref link_handle_reference |
| 96 | + * "Handles, Descriptors, and Property Lists" |
| 97 | + */ |
| 98 | + template<class T, class hid_t, class... args_t> |
| 99 | + inline H5CPP_ATTR_CREATE_RET(hid_t) |
| 100 | + create( const hid_t& parent, const std::string& path, args_t&&... args ){ |
28 | 101 | try { |
29 | 102 | h5::acpl_t default_acpl{ H5Pcreate(H5P_ATTRIBUTE_CREATE) }; |
30 | 103 | const h5::acpl_t& acpl = arg::get(default_acpl, args...); |
31 | 104 |
|
32 | 105 | H5CPP_CHECK_PROP( acpl, h5::error::property_list::misc, "invalid attribute create property" ); |
33 | 106 |
|
34 | 107 | // and dimensions |
35 | | - h5::current_dims_t current_dims_default{0}; // if no current dims_present |
| 108 | + h5::current_dims_t current_dims_default{0}; // if no current dims_present |
36 | 109 | // this mutable value will be referenced |
37 | 110 | const h5::current_dims_t& current_dims = arg::get(current_dims_default, args...); |
38 | 111 | // no partial IO or chunks |
39 | 112 | h5::sp_t space = h5::create_simple( current_dims ); |
40 | 113 | using element_t = typename meta::decay<T>::type; |
41 | 114 | h5::dt_t<element_t> type; |
42 | | - hid_t id = H5I_UNINIT; |
43 | | - H5CPP_CHECK_NZ( (id = H5Acreate2( static_cast<hid_t>( parent ), path.c_str(), |
44 | | - static_cast<hid_t>(type), static_cast<hid_t>( space ), static_cast<hid_t>( acpl ), H5P_DEFAULT )), |
| 115 | + ::hid_t id = H5I_UNINIT; |
| 116 | + H5CPP_CHECK_NZ( (id = H5Acreate2( static_cast<::hid_t>( parent ), path.c_str(), |
| 117 | + static_cast<::hid_t>(type), static_cast<::hid_t>( space ), static_cast<::hid_t>( acpl ), H5P_DEFAULT )), |
45 | 118 | h5::error::io::attribute::create, "couldn't create attribute"); |
46 | 119 | return h5::at_t{id}; |
47 | 120 | } catch( const std::runtime_error& err ) { |
|
0 commit comments