poet/include/highfive/H5Attribute.hpp

296 lines
10 KiB
C++

/*
* Copyright (c), 2017, Ali Can Demiralp <ali.demiralp@rwth-aachen.de>
*
* 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 <vector>
#include <H5Apublic.h>
#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<class Derived>
/// friend class SomeCRTP<Derived>;
///
/// \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<Attribute> {
public:
const static ObjectType type = ObjectType::Attribute;
/// \brief Get the name of the current Attribute.
/// \code{.cpp}
/// auto attr = dset.createAttribute<std::string>("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<int>("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<int>("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<int>("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<int> value = attr.read<std::vector<int>>();
/// \endcode
/// \since 2.5.0
template <typename T>
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<int> value(3);
/// file.getAttribute("foo").read(value);
/// \endcode
/// \since 1.0
template <typename T>
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 <typename T>
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 <typename T>
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<int>{1, 2, 3});
///
/// // To overwrite the value:
/// std::vector<int> value{4, 5, 6};
/// dset.getAttribute<int>("foo").write(value);
/// \endcode
/// \since 1.0
template <typename T>
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<int>("foo", DataSpace(2, 3));
///
/// // Simulate the application creating `value` and only exposing access
/// // to the raw pointer `ptr`.
/// std::vector<std::array<int, 3>> value{{1, 2, 3}, {4, 5, 6}};
/// int * ptr = (int*) value.data();
///
/// // Simply write the bytes to disk.
/// attr.write(ptr, AtomicType<int>());
/// \endcode
/// \since 2.2.2
template <typename T>
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<std::array<int, 3>> 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 <typename T>
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<AttributeCreateProps>(*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<size_t>& 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<size_t>& dims) const;
protected:
using Object::Object;
private:
DataSpace _mem_space;
#if HIGHFIVE_HAS_FRIEND_DECLARATIONS
template <typename Derivate>
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