/* * Copyright (c), 2017, Ali Can Demiralp * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * */ #pragma once #include #include #include "H5DataType.hpp" #include "H5DataSpace.hpp" #include "H5Object.hpp" #include "bits/H5Friends.hpp" #include "bits/H5Path_traits.hpp" namespace HighFive { class DataSpace; namespace detail { /// \brief Internal hack to create an `Attribute` from an ID. /// /// WARNING: Creating an Attribute from an ID has implications w.r.t. the lifetime of the object /// that got passed via its ID. Using this method careless opens up the suite of issues /// related to C-style resource management, including the analog of double free, dangling /// pointers, etc. /// /// NOTE: This is not part of the API and only serves to work around a compiler issue in GCC which /// prevents us from using `friend`s instead. This function should only be used for internal /// purposes. The problematic construct is: /// /// template /// friend class SomeCRTP; /// /// \private Attribute make_attribute(hid_t hid); } // namespace detail /// \brief Class representing an Attribute of a DataSet or Group /// /// \sa AnnotateTraits::createAttribute, AnnotateTraits::getAttribute, AnnotateTraits::listAttributeNames, AnnotateTraits::hasAttribute, AnnotateTraits::deleteAttribute for create, get, list, check or delete Attribute class Attribute: public Object, public PathTraits { public: const static ObjectType type = ObjectType::Attribute; /// \brief Get the name of the current Attribute. /// \code{.cpp} /// auto attr = dset.createAttribute("my_attribute", DataSpace::From(string_list)); /// std::cout << attr.getName() << std::endl; // Will print "my_attribute" /// \endcode /// \since 2.2.2 std::string getName() const; /// \brief The number of bytes required to store the attribute in the HDF5 file. /// \code{.cpp} /// size_t size = dset.createAttribute("foo", DataSpace(1, 2)).getStorageSize(); /// \endcode /// \since 1.0 size_t getStorageSize() const; /// \brief Get the DataType of the Attribute. /// \code{.cpp} /// Attribute attr = dset.createAttribute("foo", DataSpace(1, 2)); /// auto dtype = attr.getDataType(); // Will be an hdf5 type deduced from int /// \endcode /// \since 1.0 DataType getDataType() const; /// \brief Get a copy of the DataSpace of the current Attribute. /// \code{.cpp} /// Attribute attr = dset.createAttribute("foo", DataSpace(1, 2)); /// auto dspace = attr.getSpace(); // This will be a DataSpace of dimension 1 * 2 /// \endcode /// \since 1.0 DataSpace getSpace() const; /// \brief Get the memory DataSpace of the current Attribute. /// /// HDF5 attributes don't support selections. Therefore, there's no need /// for a memory dataspace. However, HighFive supports allocating arrays /// and checking dimensions, this requires the dimensions of the memspace. /// /// \since 1.0 DataSpace getMemSpace() const; /// \brief Get the value of the Attribute. /// \code{.cpp} /// Attribute attr = dset.getAttribute("foo"); /// // The value will contains what have been written in the attribute /// std::vector value = attr.read>(); /// \endcode /// \since 2.5.0 template T read() const; /// \brief Get the value of the Attribute in a buffer. /// /// Read the attribute into an existing object. Only available for /// supported types `T`. If `array` has preallocated the correct amount of /// memory, then this routine should not trigger reallocation. Otherwise, /// if supported, the object will be resized. /// /// An exception is raised if the numbers of dimension of the buffer and of /// the attribute are different. /// /// \code{.cpp} /// // Will read into `value` avoiding memory allocation if the dimensions /// // match, i.e. if the attribute `"foo"` has three element. /// std::vector value(3); /// file.getAttribute("foo").read(value); /// \endcode /// \since 1.0 template void read(T& array) const; /// \brief Read the attribute into a pre-allocated buffer. /// \param array A pointer to the first byte of sufficient pre-allocated memory. /// \param mem_datatype The DataType of the array. /// /// \note This is the shallowest wrapper around `H5Aread`. If possible /// prefer either Attribute::read() const or Attribute::read(T&) const. /// /// \code{.cpp} /// auto attr = file.getAttribute("foo"); /// /// // Simulate custom allocation by the application. /// size_t n_elements = attr.getSpace().getElementCount(); /// int * ptr = (int*) malloc(n_elements*sizeof(int)); /// /// // Read into the pre-allocated memory. /// attr.read(ptr, mem_datatype); /// \endcode /// \since 2.2.2 template void read_raw(T* array, const DataType& mem_datatype) const; /// \brief Read the attribute into a buffer. /// Behaves like Attribute::read(T*, const DataType&) const but /// additionally this overload deduces the memory datatype from `T`. /// /// \param array Pointer to the first byte of pre-allocated memory. /// /// \note If possible prefer either Attribute::read() const or Attribute::read(T&) const. /// /// \code{.cpp} /// auto attr = file.getAttribute("foo"); /// /// // Simulate custom allocation by the application. /// size_t n_elements = attr.getSpace().getElementCount(); /// int * ptr = (int*) malloc(n_elements*sizeof(int)); /// /// // Read into the pre-allocated memory. /// attr.read(ptr); /// \endcode /// \since 2.2.2 template void read_raw(T* array) const; /// \brief Write the value into the Attribute. /// /// Write the value to the attribute. For supported types `T`, this overload /// will write the value to the attribute. The datatype and dataspace are /// deduced automatically. However, since the attribute has already been /// created, the dimensions of `value` must match those of the attribute. /// /// \code{.cpp} /// // Prefer the fused version if creating and writing the attribute /// // at the same time. /// dset.createAttribute("foo", std::vector{1, 2, 3}); /// /// // To overwrite the value: /// std::vector value{4, 5, 6}; /// dset.getAttribute("foo").write(value); /// \endcode /// \since 1.0 template void write(const T& value); /// \brief Write from a raw pointer. /// /// Values that have been correctly arranged memory, can be written directly /// by passing a raw pointer. /// /// \param buffer Pointer to the first byte of the value. /// \param mem_datatype The DataType of the buffer. /// /// \note This is the shallowest wrapper around `H5Awrite`. It's useful /// if you need full control. If possible prefer Attribute::write. /// /// \code{.cpp} /// Attribute attr = dset.createAttribute("foo", DataSpace(2, 3)); /// /// // Simulate the application creating `value` and only exposing access /// // to the raw pointer `ptr`. /// std::vector> value{{1, 2, 3}, {4, 5, 6}}; /// int * ptr = (int*) value.data(); /// /// // Simply write the bytes to disk. /// attr.write(ptr, AtomicType()); /// \endcode /// \since 2.2.2 template void write_raw(const T* buffer, const DataType& mem_datatype); /// \brief Write from a raw pointer. /// /// Much like Attribute::write_raw(const T*, const DataType&). /// Additionally, this overload attempts to automatically deduce the /// datatype of the buffer. Note, that the file datatype is already set. /// /// \param buffer Pointer to the first byte. /// /// \note If possible prefer Attribute::write. /// /// \code{.cpp} /// // Simulate the application creating `value` and only exposing access /// // to the raw pointer `ptr`. /// std::vector> value{{1, 2, 3}, {4, 5, 6}}; /// int * ptr = (int*) value.data(); /// /// // Simply write the bytes to disk. /// attr.write(ptr); /// \endcode /// \since 2.2.2 template void write_raw(const T* buffer); /// \brief The create property list used for this attribute. /// /// Some of HDF5 properties/setting of an attribute are defined by a /// create property list. This method returns a copy of the create /// property list used during creation of the attribute. /// /// \code{.cpp} /// auto acpl = attr.getCreatePropertyList(); /// /// // For example to create another attribute with the same properties. /// file.createAttribute("foo", 42, acpl); /// \endcode /// \since 2.5.0 AttributeCreateProps getCreatePropertyList() const { return details::get_plist(*this, H5Aget_create_plist); } // No empty attributes Attribute() = delete; /// /// \brief Return an `Attribute` with `axes` squeezed from the memspace. /// /// Returns an `Attribute` in which the memspace has been modified /// to not include the axes listed in `axes`. /// /// Throws if any axis to be squeezes has a dimension other than `1`. /// /// \since 3.0 Attribute squeezeMemSpace(const std::vector& axes) const; /// /// \brief Return a `Attribute` with a simple memspace with `dims`. /// /// Returns a `Attribute` in which the memspace has been modified /// to be a simple dataspace with dimensions `dims`. /// /// Throws if the number of elements changes. /// /// \since 3.0 Attribute reshapeMemSpace(const std::vector& dims) const; protected: using Object::Object; private: DataSpace _mem_space; #if HIGHFIVE_HAS_FRIEND_DECLARATIONS template friend class ::HighFive::AnnotateTraits; #endif friend Attribute detail::make_attribute(hid_t); }; namespace detail { inline Attribute make_attribute(hid_t hid) { return Attribute(hid); } } // namespace detail } // namespace HighFive