diff --git a/CMakeLists.txt b/CMakeLists.txt index 4319cc7..378f1eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,9 @@ option(HIGHFIVE_VERBOSE "Set logging level to verbose." OFF) option(HIGHFIVE_HAS_FRIEND_DECLARATIONS "Enable additional friend declarations. Certain compiler require this On, others Off." OFF) mark_as_advanced(HIGHFIVE_HAS_FRIEND_DECLARATIONS) +option(HIGHFIVE_USE_STRING_VIEW "Use std::string_view instead of std::string has H5 objects keys." OFF) +mark_as_advanced(HIGHFIVE_HAS_STRING_VIEW_NAMES) + option(HIGHFIVE_FIND_HDF5 "Find and link with HDF5." On) set(HIGHFIVE_CMAKE_INSTALL_DIR "lib/cmake/HighFive" CACHE STRING @@ -100,6 +103,12 @@ if(CMAKE_CXX_STANDARD EQUAL 98 OR CMAKE_CXX_STANDARD LESS ${HIGHFIVE_CXX_STANDAR message(FATAL_ERROR "HighFive needs to be compiled with at least C++${HIGHFIVE_CXX_STANDARD_DEFAULT}") endif() +if(HIGHFIVE_USE_STRING_VIEW) + if(CMAKE_CXX_STANDARD LESS 17) + message(FATAL_ERROR "HighFive needs to be compiled with at least C++17 to use std::string_view as keys") + endif() +endif() + if(HIGHFIVE_TEST_MDSPAN AND CMAKE_CXX_STANDARD LESS 23) message(FATAL_ERROR "HIGHFIVE_TEST_MDSPAN requires C++23 or newer, but CMAKE_CXX_STANDARD is ${CMAKE_CXX_STANDARD}") endif() diff --git a/cmake/HighFiveFlags.cmake b/cmake/HighFiveFlags.cmake index 33be65e..2343993 100644 --- a/cmake/HighFiveFlags.cmake +++ b/cmake/HighFiveFlags.cmake @@ -24,6 +24,10 @@ if(HIGHFIVE_HAS_FRIEND_DECLARATIONS) target_compile_definitions(HighFiveFlags INTERFACE -DHIGHFIVE_HAS_FRIEND_DECLARATIONS=1) endif() +if(HIGHFIVE_USE_STRING_VIEW) + target_compile_definitions(HighFiveFlags INTERFACE -DHIGHFIVE_USE_STRING_VIEW=1) +endif() + if(HIGHFIVE_SANITIZER) target_compile_options(HighFiveFlags INTERFACE -fsanitize=${HIGHFIVE_SANITIZER}) target_link_options(HighFiveFlags INTERFACE -fsanitize=${HIGHFIVE_SANITIZER}) diff --git a/include/highfive/H5File.hpp b/include/highfive/H5File.hpp index 3ed1cd4..419f122 100644 --- a/include/highfive/H5File.hpp +++ b/include/highfive/H5File.hpp @@ -13,12 +13,12 @@ #include "H5Object.hpp" #include "H5PropertyList.hpp" +#include "H5Label.hpp" #include "bits/H5Annotate_traits.hpp" #include "bits/H5Node_traits.hpp" namespace HighFive { - /// /// \brief File class /// @@ -68,7 +68,7 @@ class File: public Object, public NodeTraits, public AnnotateTraits /// \param fileAccessProps: the file access properties /// /// Open or create a new HDF5 file - explicit File(const std::string& filename, + explicit File(const H5Label& filename, AccessMode openFlags = ReadOnly, const FileAccessProps& fileAccessProps = FileAccessProps::Default()); @@ -80,7 +80,7 @@ class File: public Object, public NodeTraits, public AnnotateTraits /// \param fileAccessProps: the file access properties /// /// Open or create a new HDF5 file - File(const std::string& filename, + File(const H5Label& filename, AccessMode access_mode, const FileCreateProps& fileCreateProps, const FileAccessProps& fileAccessProps = FileAccessProps::Default()); diff --git a/include/highfive/H5Label.hpp b/include/highfive/H5Label.hpp new file mode 100644 index 0000000..4beff32 --- /dev/null +++ b/include/highfive/H5Label.hpp @@ -0,0 +1,66 @@ +/* + * Copyright (c), 2026, Alain Miniussi + * + * 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 + +#if HIGHFIVE_USE_STRING_VIEW +# ifndef __cpp_lib_string_view +# error "std::string_view not available in this standard librarie +# include +# endif +#endif + +namespace HighFive { +/// \brief Build a path composed of all parameter separated with a "/". +/// \param s can be a std::string, a std::string_view (if supposrted) or a const char*. +/// \return The build path +inline std::string path(std::string s) { return s; } +/// \overload +template inline std::string path(std::string first, S... s); + +#if HIGHFIVE_USE_STRING_VIEW +using H5Label = std::string_view; + +/// \overload +inline std::string path(std::string_view s) { return std::string{s}; } +/// \overload +inline std::string path(char const* s) { return std::string{s}; } +/// \overload +template std::string path(std::string_view first, S... s); +template std::string path(char const* first, S... s); + +#else // !HIGHFIVE_USE_STRING_VIEW + +using H5Label = std::string; + +#endif // HIGHFIVE_USE_STRING_VIEW + +template +inline +std::string path(std::string first, S... s) { + return first + "/" + path(s...); +} + +#if HIGHFIVE_USE_STRING_VIEW + +template +inline +std::string path(std::string_view first, S... s) { + return std::string{first} + "/" + path(s...); +} + +template +inline +std::string path(char const* first, S... s) { + return std::string{first} + "/" + path(s...); +} + +#endif +} diff --git a/include/highfive/bits/H5Annotate_traits.hpp b/include/highfive/bits/H5Annotate_traits.hpp index 375b535..cd35c25 100644 --- a/include/highfive/bits/H5Annotate_traits.hpp +++ b/include/highfive/bits/H5Annotate_traits.hpp @@ -10,6 +10,7 @@ #include +#include "../H5Label.hpp" #include "../H5Attribute.hpp" namespace HighFive { @@ -24,7 +25,7 @@ class AnnotateTraits { /// \param type /// \return the attribute object /// - Attribute createAttribute(const std::string& attribute_name, + Attribute createAttribute(const H5Label& attribute_name, const DataSpace& space, const DataType& type); @@ -36,7 +37,7 @@ class AnnotateTraits { /// informations /// \return Attribute Object template - Attribute createAttribute(const std::string& attribute_name, const DataSpace& space); + Attribute createAttribute(const H5Label& attribute_name, const DataSpace& space); /// /// \brief createAttribute create a new attribute on the current dataset and @@ -47,18 +48,18 @@ class AnnotateTraits { /// \return Attribute Object /// template - Attribute createAttribute(const std::string& attribute_name, const T& data); + Attribute createAttribute(const H5Label& attribute_name, const T& data); /// /// \brief deleteAttribute let you delete an attribute by its name. /// \param attribute_name identifier of the attribute - void deleteAttribute(const std::string& attribute_name); + void deleteAttribute(const H5Label& attribute_name); /// /// \brief open an existing attribute with the name attribute_name /// \param attribute_name identifier of the attribute /// \return the attribute object - Attribute getAttribute(const std::string& attribute_name) const; + Attribute getAttribute(const H5Label& attribute_name) const; /// /// \brief return the number of attributes of the node / group @@ -73,7 +74,7 @@ class AnnotateTraits { /// /// \brief checks an attribute exists /// \return number of attributes - bool hasAttribute(const std::string& attr_name) const; + bool hasAttribute(const H5Label& attr_name) const; private: using derivate_type = Derivate; diff --git a/include/highfive/bits/H5Annotate_traits_misc.hpp b/include/highfive/bits/H5Annotate_traits_misc.hpp index bf2be8a..6039cf6 100644 --- a/include/highfive/bits/H5Annotate_traits_misc.hpp +++ b/include/highfive/bits/H5Annotate_traits_misc.hpp @@ -21,11 +21,11 @@ namespace HighFive { template -inline Attribute AnnotateTraits::createAttribute(const std::string& attribute_name, +inline Attribute AnnotateTraits::createAttribute(const H5Label& attribute_name, const DataSpace& space, const DataType& dtype) { auto attr_id = detail::h5a_create2(static_cast(this)->getId(), - attribute_name.c_str(), + std::string{attribute_name}.c_str(), dtype.getId(), space.getId(), H5P_DEFAULT, @@ -35,14 +35,14 @@ inline Attribute AnnotateTraits::createAttribute(const std::string& at template template -inline Attribute AnnotateTraits::createAttribute(const std::string& attribute_name, +inline Attribute AnnotateTraits::createAttribute(const H5Label& attribute_name, const DataSpace& space) { return createAttribute(attribute_name, space, create_and_check_datatype()); } template template -inline Attribute AnnotateTraits::createAttribute(const std::string& attribute_name, +inline Attribute AnnotateTraits::createAttribute(const H5Label& attribute_name, const T& data) { Attribute att = createAttribute(attribute_name, @@ -53,14 +53,14 @@ inline Attribute AnnotateTraits::createAttribute(const std::string& at } template -inline void AnnotateTraits::deleteAttribute(const std::string& attribute_name) { - detail::h5a_delete(static_cast(this)->getId(), attribute_name.c_str()); +inline void AnnotateTraits::deleteAttribute(const H5Label& attribute_name) { + detail::h5a_delete(static_cast(this)->getId(), std::string{attribute_name}.c_str()); } template -inline Attribute AnnotateTraits::getAttribute(const std::string& attribute_name) const { +inline Attribute AnnotateTraits::getAttribute(const H5Label& attribute_name) const { const auto attr_id = detail::h5a_open(static_cast(this)->getId(), - attribute_name.c_str(), + std::string{attribute_name}.c_str(), H5P_DEFAULT); return detail::make_attribute(attr_id); } @@ -90,8 +90,8 @@ inline std::vector AnnotateTraits::listAttributeNames() c } template -inline bool AnnotateTraits::hasAttribute(const std::string& attr_name) const { - return detail::h5a_exists(static_cast(this)->getId(), attr_name.c_str()) > 0; +inline bool AnnotateTraits::hasAttribute(const H5Label& attr_name) const { + return detail::h5a_exists(static_cast(this)->getId(), std::string{attr_name}.c_str()) > 0; } } // namespace HighFive diff --git a/include/highfive/bits/H5File_misc.hpp b/include/highfive/bits/H5File_misc.hpp index b6a8454..45f9770 100644 --- a/include/highfive/bits/H5File_misc.hpp +++ b/include/highfive/bits/H5File_misc.hpp @@ -47,13 +47,13 @@ inline unsigned convert_open_flag(File::AccessMode openFlags) { } } // namespace -inline File::File(const std::string& filename, +inline File::File(const H5Label& filename, AccessMode openFlags, const FileAccessProps& fileAccessProps) : File(filename, openFlags, FileCreateProps::Default(), fileAccessProps) {} -inline File::File(const std::string& filename, +inline File::File(const H5Label& filename, AccessMode access_mode, const FileCreateProps& fileCreateProps, const FileAccessProps& fileAccessProps) { @@ -76,7 +76,7 @@ inline File::File(const std::string& filename, silencer = std::make_unique(); } - _hid = detail::nothrow::h5f_open(filename.c_str(), openMode, fileAccessProps.getId()); + _hid = detail::nothrow::h5f_open(std::string{filename}.c_str(), openMode, fileAccessProps.getId()); if (isValid()) { return; // Done @@ -87,13 +87,13 @@ inline File::File(const std::string& filename, createMode = H5F_ACC_EXCL; } else { HDF5ErrMapper::ToException( - std::string("Unable to open file " + filename)); + std::string("Unable to open file " + std::string{filename})); } } auto fcpl = fileCreateProps.getId(); auto fapl = fileAccessProps.getId(); - _hid = detail::h5f_create(filename.c_str(), createMode, fcpl, fapl); + _hid = detail::h5f_create(std::string{filename}.c_str(), createMode, fcpl, fapl); } inline const std::string& File::getName() const { diff --git a/include/highfive/bits/H5Node_traits.hpp b/include/highfive/bits/H5Node_traits.hpp index db2ea94..89fbed2 100644 --- a/include/highfive/bits/H5Node_traits.hpp +++ b/include/highfive/bits/H5Node_traits.hpp @@ -9,7 +9,7 @@ #pragma once #include - +#include "../H5Label.hpp" #include "../H5PropertyList.hpp" #include "H5_definitions.hpp" #include "H5Converter_misc.hpp" @@ -37,7 +37,7 @@ class NodeTraits { /// \param accessProps A property list with data set access properties /// \param parents Create intermediate groups if needed. Default: true. /// \return DataSet Object - DataSet createDataSet(const std::string& dataset_name, + DataSet createDataSet(const H5Label& dataset_name, const DataSpace& space, const DataType& type, const DataSetCreateProps& createProps = DataSetCreateProps::Default(), @@ -54,7 +54,7 @@ class NodeTraits { /// \param parents Create intermediate groups if needed. Default: true. /// \return DataSet Object template - DataSet createDataSet(const std::string& dataset_name, + DataSet createDataSet(const H5Label& dataset_name, const DataSpace& space, const DataSetCreateProps& createProps = DataSetCreateProps::Default(), const DataSetAccessProps& accessProps = DataSetAccessProps::Default(), @@ -71,7 +71,7 @@ class NodeTraits { /// \param parents Create intermediate groups if needed. Default: true. /// \return DataSet Object template - DataSet createDataSet(const std::string& dataset_name, + DataSet createDataSet(const H5Label& dataset_name, const T& data, const DataSetCreateProps& createProps = DataSetCreateProps::Default(), const DataSetAccessProps& accessProps = DataSetAccessProps::Default(), @@ -83,7 +83,7 @@ class NodeTraits { /// \param dataset_name /// \param accessProps property list to configure dataset chunk cache /// \return return the named dataset, or throw exception if not found - DataSet getDataSet(const std::string& dataset_name, + DataSet getDataSet(const H5Label& dataset_name, const DataSetAccessProps& accessProps = DataSetAccessProps::Default()) const; /// @@ -91,7 +91,7 @@ class NodeTraits { /// \param group_name /// \param parents Create intermediate groups if needed. Default: true. /// \return the group object - Group createGroup(const std::string& group_name, bool parents = true); + Group createGroup(const H5Label& group_name, bool parents = true); /// /// \brief create a new group, and eventually intermediate groups @@ -99,7 +99,7 @@ class NodeTraits { /// \param createProps A property list with group creation properties /// \param parents Create intermediate groups if needed. Default: true. /// \return the group object - Group createGroup(const std::string& group_name, + Group createGroup(const H5Label& group_name, const GroupCreateProps& createProps, bool parents = true); @@ -107,14 +107,14 @@ class NodeTraits { /// \brief open an existing group with the name group_name /// \param group_name /// \return the group object - Group getGroup(const std::string& group_name) const; + Group getGroup(const H5Label& group_name) const; /// /// \brief open a commited datatype with the name type_name /// \param type_name /// \return the datatype object DataType getDataType( - const std::string& type_name, + const H5Label& type_name, const DataTypeAccessProps& accessProps = DataTypeAccessProps::Default()) const; /// @@ -133,8 +133,8 @@ class NodeTraits { /// \param dst_path new relative path of the object to current File/Group /// \param parents Create intermediate groups if needed. Default: true. /// \return boolean that is true if the move was successful - bool rename(const std::string& src_path, - const std::string& dst_path, + bool rename(const H5Label& src_path, + const H5Label& dst_path, bool parents = true) const; /// @@ -149,28 +149,28 @@ class NodeTraits { /// \brief check a dataset or group exists in the current node / group /// \param node_path dataset/group name to check /// \return true if a dataset/group with the associated name exists, or false - bool exist(const std::string& node_path) const; + bool exist(const H5Label& node_path) const; /// /// \brief unlink the given dataset or group /// \param node_path dataset/group name to unlink - void unlink(const std::string& node_path) const; + void unlink(const H5Label& node_path) const; /// /// \brief Returns the kind of link of the given name (soft, hard...) /// \param node_path The entry to check, path relative to the current group - LinkType getLinkType(const std::string& node_path) const; + LinkType getLinkType(const H5Label& node_path) const; /// /// \brief A shorthand to get the kind of object pointed to (group, dataset, type...) /// \param node_path The entry to check, path relative to the current group - ObjectType getObjectType(const std::string& node_path) const; + ObjectType getObjectType(const H5Label& node_path) const; /// /// \brief A shorthand to create softlink to any object which provides `getPath` /// The link will be created with default properties along with required parent groups template - void createSoftLink(const std::string& linkName, const T& obj) { + void createSoftLink(const H5Label& linkName, const T& obj) { static_assert(!std::is_same::value, "hdf5 doesn't support soft links to Attributes"); createSoftLink(linkName, obj.getPath()); @@ -183,15 +183,15 @@ class NodeTraits { /// \param linkCreateProps A Link_Create property list. Notice "parents=true" overrides /// \param linkAccessProps The Link_Access property list /// \param parents Whether parent groups should be created: Default: true - void createSoftLink(const std::string& link_name, - const std::string& obj_path, + void createSoftLink(const H5Label& link_name, + const H5Label& obj_path, LinkCreateProps linkCreateProps = LinkCreateProps(), const LinkAccessProps& linkAccessProps = LinkAccessProps(), bool parents = true); - void createExternalLink(const std::string& link_name, - const std::string& h5_file, - const std::string& obj_path, + void createExternalLink(const H5Label& link_name, + const H5Label& h5_file, + const H5Label& obj_path, LinkCreateProps linkCreateProps = LinkCreateProps(), const LinkAccessProps& linkAccessProps = LinkAccessProps(), bool parents = true); @@ -204,7 +204,7 @@ class NodeTraits { /// \param linkAccessProps The Link_Access property list /// \param parents Whether parent groups should be created: Default: true template - void createHardLink(const std::string& link_name, + void createHardLink(const H5Label& link_name, const T& target_obj, LinkCreateProps linkCreateProps = LinkCreateProps(), const LinkAccessProps& linkAccessProps = LinkAccessProps(), @@ -216,7 +216,7 @@ class NodeTraits { // A wrapper over the low-level H5Lexist // It makes behavior consistent among versions and by default transforms // errors to exceptions - bool _exist(const std::string& node_path, bool raise_errors = true) const; + bool _exist(const H5Label& node_path, bool raise_errors = true) const; }; diff --git a/include/highfive/bits/H5Node_traits_misc.hpp b/include/highfive/bits/H5Node_traits_misc.hpp index 224d18a..933cc28 100644 --- a/include/highfive/bits/H5Node_traits_misc.hpp +++ b/include/highfive/bits/H5Node_traits_misc.hpp @@ -34,7 +34,7 @@ namespace HighFive { template -inline DataSet NodeTraits::createDataSet(const std::string& dataset_name, +inline DataSet NodeTraits::createDataSet(const H5Label& dataset_name, const DataSpace& space, const DataType& dtype, const DataSetCreateProps& createProps, @@ -43,7 +43,7 @@ inline DataSet NodeTraits::createDataSet(const std::string& dataset_na LinkCreateProps lcpl; lcpl.add(CreateIntermediateGroup(parents)); return DataSet(detail::h5d_create2(static_cast(this)->getId(), - dataset_name.c_str(), + std::string{dataset_name}.c_str(), dtype.getId(), space.getId(), lcpl.getId(), @@ -53,7 +53,7 @@ inline DataSet NodeTraits::createDataSet(const std::string& dataset_na template template -inline DataSet NodeTraits::createDataSet(const std::string& dataset_name, +inline DataSet NodeTraits::createDataSet(const H5Label& dataset_name, const DataSpace& space, const DataSetCreateProps& createProps, const DataSetAccessProps& accessProps, @@ -64,7 +64,7 @@ inline DataSet NodeTraits::createDataSet(const std::string& dataset_na template template -inline DataSet NodeTraits::createDataSet(const std::string& dataset_name, +inline DataSet NodeTraits::createDataSet(const H5Label& dataset_name, const T& data, const DataSetCreateProps& createProps, const DataSetAccessProps& accessProps, @@ -81,49 +81,49 @@ inline DataSet NodeTraits::createDataSet(const std::string& dataset_na } template -inline DataSet NodeTraits::getDataSet(const std::string& dataset_name, +inline DataSet NodeTraits::getDataSet(const H5Label& dataset_name, const DataSetAccessProps& accessProps) const { return DataSet(detail::h5d_open2(static_cast(this)->getId(), - dataset_name.c_str(), + std::string{dataset_name}.c_str(), accessProps.getId())); } template -inline Group NodeTraits::createGroup(const std::string& group_name, bool parents) { +inline Group NodeTraits::createGroup(const H5Label& group_name, bool parents) { LinkCreateProps lcpl; lcpl.add(CreateIntermediateGroup(parents)); return detail::make_group(detail::h5g_create2(static_cast(this)->getId(), - group_name.c_str(), + std::string{group_name}.c_str(), lcpl.getId(), H5P_DEFAULT, H5P_DEFAULT)); } template -inline Group NodeTraits::createGroup(const std::string& group_name, +inline Group NodeTraits::createGroup(const H5Label& group_name, const GroupCreateProps& createProps, bool parents) { LinkCreateProps lcpl; lcpl.add(CreateIntermediateGroup(parents)); return detail::make_group(detail::h5g_create2(static_cast(this)->getId(), - group_name.c_str(), + std::string{group_name}.c_str(), lcpl.getId(), createProps.getId(), H5P_DEFAULT)); } template -inline Group NodeTraits::getGroup(const std::string& group_name) const { +inline Group NodeTraits::getGroup(const H5Label& group_name) const { return detail::make_group(detail::h5g_open2(static_cast(this)->getId(), - group_name.c_str(), + std::string{group_name}.c_str(), H5P_DEFAULT)); } template -inline DataType NodeTraits::getDataType(const std::string& type_name, +inline DataType NodeTraits::getDataType(const H5Label& type_name, const DataTypeAccessProps& accessProps) const { return DataType(detail::h5t_open2(static_cast(this)->getId(), - type_name.c_str(), + std::string{type_name}.c_str(), accessProps.getId())); } @@ -149,15 +149,15 @@ inline std::string NodeTraits::getObjectName(size_t index) const { } template -inline bool NodeTraits::rename(const std::string& src_path, - const std::string& dst_path, +inline bool NodeTraits::rename(const H5Label& src_path, + const H5Label& dst_path, bool parents) const { LinkCreateProps lcpl; lcpl.add(CreateIntermediateGroup(parents)); herr_t err = detail::h5l_move(static_cast(this)->getId(), - src_path.c_str(), + std::string{src_path}.c_str(), static_cast(this)->getId(), - dst_path.c_str(), + std::string{dst_path}.c_str(), lcpl.getId(), H5P_DEFAULT); @@ -182,10 +182,10 @@ inline std::vector NodeTraits::listObjectNames(IndexType } template -inline bool NodeTraits::_exist(const std::string& node_path, bool raise_errors) const { +inline bool NodeTraits::_exist(const H5Label& node_path, bool raise_errors) const { SilenceHDF5 silencer{}; const auto val = detail::nothrow::h5l_exists(static_cast(this)->getId(), - node_path.c_str(), + std::string{node_path}.c_str(), H5P_DEFAULT); if (val < 0) { if (raise_errors) { @@ -202,7 +202,7 @@ inline bool NodeTraits::_exist(const std::string& node_path, bool rais } template -inline bool NodeTraits::exist(const std::string& node_path) const { +inline bool NodeTraits::exist(const H5Label& node_path) const { // When there are slashes, first check everything is fine // so that subsequent errors are only due to missing intermediate groups if (node_path.find('/') != std::string::npos) { @@ -215,8 +215,8 @@ inline bool NodeTraits::exist(const std::string& node_path) const { template -inline void NodeTraits::unlink(const std::string& node_path) const { - detail::h5l_delete(static_cast(this)->getId(), node_path.c_str(), H5P_DEFAULT); +inline void NodeTraits::unlink(const H5Label& node_path) const { + detail::h5l_delete(static_cast(this)->getId(), std::string{node_path}.c_str(), H5P_DEFAULT); } @@ -238,24 +238,24 @@ static inline LinkType _convert_link_type(const H5L_type_t& ltype) noexcept { } template -inline LinkType NodeTraits::getLinkType(const std::string& node_path) const { +inline LinkType NodeTraits::getLinkType(const H5Label& node_path) const { H5L_info_t linkinfo; detail::h5l_get_info(static_cast(this)->getId(), - node_path.c_str(), + std::string{node_path}.c_str(), &linkinfo, H5P_DEFAULT); if (linkinfo.type == H5L_TYPE_ERROR) { - HDF5ErrMapper::ToException(std::string("Link type of \"") + node_path + + HDF5ErrMapper::ToException("Link type of \"" + std::string{node_path} + "\" is H5L_TYPE_ERROR"); } return _convert_link_type(linkinfo.type); } template -inline ObjectType NodeTraits::getObjectType(const std::string& node_path) const { +inline ObjectType NodeTraits::getObjectType(const H5Label& node_path) const { const auto id = detail::h5o_open(static_cast(this)->getId(), - node_path.c_str(), + std::string{node_path}.c_str(), H5P_DEFAULT); auto object_type = _convert_object_type(detail::h5i_get_type(id)); detail::h5o_close(id); @@ -264,43 +264,43 @@ inline ObjectType NodeTraits::getObjectType(const std::string& node_pa template -inline void NodeTraits::createSoftLink(const std::string& link_name, - const std::string& obj_path, +inline void NodeTraits::createSoftLink(const H5Label& link_name, + const H5Label& obj_path, LinkCreateProps linkCreateProps, const LinkAccessProps& linkAccessProps, const bool parents) { if (parents) { linkCreateProps.add(CreateIntermediateGroup{}); } - detail::h5l_create_soft(obj_path.c_str(), + detail::h5l_create_soft(std::string{obj_path}.c_str(), static_cast(this)->getId(), - link_name.c_str(), + std::string{link_name}.c_str(), linkCreateProps.getId(), linkAccessProps.getId()); } template -inline void NodeTraits::createExternalLink(const std::string& link_name, - const std::string& h5_file, - const std::string& obj_path, +inline void NodeTraits::createExternalLink(const H5Label& link_name, + const H5Label& h5_file, + const H5Label& obj_path, LinkCreateProps linkCreateProps, const LinkAccessProps& linkAccessProps, const bool parents) { if (parents) { linkCreateProps.add(CreateIntermediateGroup{}); } - detail::h5l_create_external(h5_file.c_str(), - obj_path.c_str(), + detail::h5l_create_external(std::string{h5_file}.c_str(), + std::string{obj_path}.c_str(), static_cast(this)->getId(), - link_name.c_str(), + std::string{link_name}.c_str(), linkCreateProps.getId(), linkAccessProps.getId()); } template template -inline void NodeTraits::createHardLink(const std::string& link_name, +inline void NodeTraits::createHardLink(const H5Label& link_name, const T& target_obj, LinkCreateProps linkCreateProps, const LinkAccessProps& linkAccessProps, @@ -313,7 +313,7 @@ inline void NodeTraits::createHardLink(const std::string& link_name, detail::h5l_create_hard(target_obj.getId(), ".", static_cast(this)->getId(), - link_name.c_str(), + std::string{link_name}.c_str(), linkCreateProps.getId(), linkAccessProps.getId()); } diff --git a/tests/unit/tests_high_five_base.cpp b/tests/unit/tests_high_five_base.cpp index 42a22ca..21c2118 100644 --- a/tests/unit/tests_high_five_base.cpp +++ b/tests/unit/tests_high_five_base.cpp @@ -381,27 +381,35 @@ void check_invalid_hid_NodeTraits(T& obj, const U& linkable) { auto data = std::vector{1.0, 2.0, 3.0}; auto gcpl = GroupCreateProps(); - CHECK_THROWS(obj.createDataSet("foo", data_space, data_type)); - CHECK_THROWS(obj.template createDataSet("foo", data_space)); - CHECK_THROWS(obj.createDataSet("foo", data)); - - CHECK_THROWS(obj.getDataSet("foo")); - CHECK_THROWS(obj.createGroup("foo")); - CHECK_THROWS(obj.createGroup("foo", gcpl)); - CHECK_THROWS(obj.getGroup("foo")); - CHECK_THROWS(obj.getDataType("foo")); - CHECK_THROWS(obj.getNumberObjects()); - CHECK_THROWS(obj.getObjectName(0)); - CHECK_THROWS(obj.rename("foo", "bar")); - CHECK_THROWS(obj.listObjectNames()); - CHECK_THROWS(obj.exist("foo")); - CHECK_THROWS(obj.unlink("foo")); - CHECK_THROWS(obj.getLinkType("foo")); - CHECK_THROWS(obj.getObjectType("foo")); - CHECK_THROWS(obj.createSoftLink("foo", linkable)); - CHECK_THROWS(obj.createSoftLink("foo", "bar")); - CHECK_THROWS(obj.createExternalLink("foo", "bar", "baz")); - CHECK_THROWS(obj.createHardLink("foo", linkable)); + auto test = [&](auto group_name, auto dataset_name, auto new_name) { + CHECK_THROWS(obj.createDataSet(dataset_name, data_space, data_type)); + CHECK_THROWS(obj.template createDataSet(dataset_name, data_space)); + CHECK_THROWS(obj.createDataSet(dataset_name, data)); + + CHECK_THROWS(obj.getDataSet(dataset_name)); + CHECK_THROWS(obj.createGroup(group_name)); + CHECK_THROWS(obj.createGroup(group_name, gcpl)); + CHECK_THROWS(obj.getGroup(group_name)); + CHECK_THROWS(obj.getDataType(dataset_name)); + CHECK_THROWS(obj.getNumberObjects()); + CHECK_THROWS(obj.getObjectName(0)); + CHECK_THROWS(obj.rename(group_name, new_name)); + CHECK_THROWS(obj.listObjectNames()); + CHECK_THROWS(obj.exist(group_name)); + CHECK_THROWS(obj.unlink(group_name)); + CHECK_THROWS(obj.getLinkType(group_name)); + CHECK_THROWS(obj.getObjectType(group_name)); + CHECK_THROWS(obj.createSoftLink(group_name, linkable)); + CHECK_THROWS(obj.createSoftLink(group_name, new_name)); + CHECK_THROWS(obj.createExternalLink(group_name, new_name, "baz")); + CHECK_THROWS(obj.createHardLink(group_name, linkable)); + }; + test("foo","foo", "bar"); + test(std::string{"foo"}, std::string{"foo"}, std::string{"bar"}); +#if HIGHFIVE_USE_STRING_VIEW + test(std::string_view{"foo"}, std::string_view{"foo"}, std::string_view{"bar"}); + test(std::string_view{"foo"}, std::string{"foo"}, "bar"); +#endif } template @@ -455,21 +463,29 @@ void check_invalid_hid_PathTraits(T& obj) { template void check_invalid_hid_AnnotateTraits(T& obj) { - auto silence = SilenceHDF5(); - - auto space = DataSpace{3}; - auto data = std::vector{1.0, 2.0, 3.0}; - auto type = create_datatype(); - - CHECK_THROWS(obj.createAttribute("foo", space, type)); - CHECK_THROWS(obj.template createAttribute("foo", space)); - CHECK_THROWS(obj.createAttribute("foo", data)); - - CHECK_THROWS(obj.deleteAttribute("foo")); - CHECK_THROWS(obj.getAttribute("foo")); - CHECK_THROWS(obj.getNumberAttributes()); - CHECK_THROWS(obj.listAttributeNames()); - CHECK_THROWS(obj.hasAttribute("foo")); + auto test = [&](auto attribute_name) { + auto silence = SilenceHDF5(); + + auto space = DataSpace{3}; + auto data = std::vector{1.0, 2.0, 3.0}; + auto type = create_datatype(); + + CHECK_THROWS(obj.createAttribute(attribute_name, space, type)); + CHECK_THROWS(obj.template createAttribute(attribute_name, space)); + CHECK_THROWS(obj.createAttribute(attribute_name, data)); + + CHECK_THROWS(obj.deleteAttribute(attribute_name)); + CHECK_THROWS(obj.getAttribute(attribute_name)); + CHECK_THROWS(obj.getNumberAttributes()); + CHECK_THROWS(obj.listAttributeNames()); + CHECK_THROWS(obj.hasAttribute(attribute_name)); + }; + test("foo"); + test(std::string{"foo"}); +#if HIGHFIVE_USE_STRING_VIEW + std::array attribute_name_data = { 'f', 'o', 'o' }; + test(std::string_view{attribute_name_data.data(), attribute_name_data.size()}); +#endif } template @@ -510,99 +526,122 @@ TEST_CASE("Test default Group constructor") { TEST_CASE("Test groups and datasets") { - const std::string file_name("h5_group_test.h5"); - const std::string dataset_name("dset"); - const std::string chunked_dataset_name("chunked_dset"); - const std::string chunked_dataset_small_name("chunked_dset_small"); - const std::string group_name_1("/group1"); - const std::string group_name_2("group2"); - const std::string group_nested_name("group_nested"); - - { - // Create a new file using the default property lists. - File file(file_name, File::ReadWrite | File::Create | File::Truncate); - - // absolute group - file.createGroup(group_name_1); - // nested group absolute - file.createGroup(group_name_1 + "/" + group_nested_name); - // relative group - Group g1 = file.createGroup(group_name_2); - // relative group - Group nested = g1.createGroup(group_nested_name); - - // Create the data space for the dataset. - std::vector dims{4, 6}; - - DataSpace dataspace(dims); - - DataSet dataset_absolute = file.createDataSet(group_name_1 + "/" + group_nested_name + "/" + - dataset_name, - dataspace, - AtomicType()); - - DataSet dataset_relative = - nested.createDataSet(dataset_name, dataspace, AtomicType()); - - DataSetCreateProps goodChunking; - goodChunking.add(Chunking(std::vector{2, 2})); - DataSetAccessProps cacheConfig; - cacheConfig.add(Caching(13, 1024, 0.5)); - - // will fail because exceeds dimensions - DataSetCreateProps badChunking0; - badChunking0.add(Chunking(std::vector{10, 10})); - - DataSetCreateProps badChunking1; - badChunking1.add(Chunking(std::vector{1, 1, 1})); - + auto check = [](auto file_name, + auto dataset_name, + auto chunked_dataset_name, + auto chunked_dataset_small_name, + auto group_name_1, + auto group_name_2, + auto group_nested_name) { { - SilenceHDF5 silencer; - CHECK_THROWS_AS(file.createDataSet(chunked_dataset_name, - dataspace, - AtomicType(), - badChunking0), - DataSetException); - - CHECK_THROWS_AS(file.createDataSet(chunked_dataset_name, - dataspace, - AtomicType(), - badChunking1), - DataSetException); + // Create a new file using the default property lists. + File file(file_name, File::ReadWrite | File::Create | File::Truncate); + + // absolute group + file.createGroup(group_name_1); + // nested group absolute + file.createGroup(path(group_name_1, group_nested_name)); + // relative group + Group g1 = file.createGroup(group_name_2); + // relative group + Group nested = g1.createGroup(group_nested_name); + + // Create the data space for the dataset. + std::vector dims{4, 6}; + + DataSpace dataspace(dims); + + DataSet dataset_absolute = file.createDataSet(path(group_name_1, group_nested_name, dataset_name), + dataspace, + AtomicType()); + + DataSet dataset_relative = + nested.createDataSet(dataset_name, dataspace, AtomicType()); + + DataSetCreateProps goodChunking; + goodChunking.add(Chunking(std::vector{2, 2})); + DataSetAccessProps cacheConfig; + cacheConfig.add(Caching(13, 1024, 0.5)); + + // will fail because exceeds dimensions + DataSetCreateProps badChunking0; + badChunking0.add(Chunking(std::vector{10, 10})); + + DataSetCreateProps badChunking1; + badChunking1.add(Chunking(std::vector{1, 1, 1})); + + { + SilenceHDF5 silencer; + CHECK_THROWS_AS(file.createDataSet(chunked_dataset_name, + dataspace, + AtomicType(), + badChunking0), + DataSetException); + + CHECK_THROWS_AS(file.createDataSet(chunked_dataset_name, + dataspace, + AtomicType(), + badChunking1), + DataSetException); + } + + // here we use the other signature + DataSet dataset_chunked = + file.createDataSet(chunked_dataset_name, dataspace, goodChunking, cacheConfig); + + // Here we resize to smaller than the chunking size + DataSet dataset_chunked_small = + file.createDataSet(chunked_dataset_small_name, dataspace, goodChunking); + + dataset_chunked_small.resize({1, 1}); } + // read it back + { + File file(file_name, File::ReadOnly); + Group g1 = file.getGroup(group_name_1); + Group g2 = file.getGroup(group_name_2); + Group nested_group2 = g2.getGroup(group_nested_name); + + DataSet dataset_absolute = file.getDataSet(path(group_name_1, group_nested_name, dataset_name)); + CHECK(4 == dataset_absolute.getSpace().getDimensions()[0]); + + DataSet dataset_relative = nested_group2.getDataSet(dataset_name); + CHECK(4 == dataset_relative.getSpace().getDimensions()[0]); + + DataSetAccessProps accessProps; + accessProps.add(Caching(13, 1024, 0.5)); + DataSet dataset_chunked = file.getDataSet(chunked_dataset_name, accessProps); + CHECK(4 == dataset_chunked.getSpace().getDimensions()[0]); + + DataSet dataset_chunked_small = file.getDataSet(chunked_dataset_small_name); + CHECK(1 == dataset_chunked_small.getSpace().getDimensions()[0]); + } + }; + // Check different types of labels + check(/*file_name*/ std::string{"h5_group_test.h5"}, + /*dataset_name*/ std::string{"dset"}, + /*chunked_dataset_name*/ std::string{"chunked_dset"}, + /*chunked_dataset_small_name*/ std::string{"chunked_dset_small"}, + /*group_name_1*/ std::string{"/group1"}, + /*group_name_2*/ std::string{"group2"}, + /*group_nested_name*/ std::string{"group_nested"} ); + + check(/*file_name*/ "h5_group_test.h5", + /*dataset_name*/ "dset", + /*chunked_dataset_name*/ "chunked_dset", + /*chunked_dataset_small_name*/ "chunked_dset_small", + /*group_name_1*/ "/group1", + /*group_name_2*/ "group2", + /*group_nested_name*/ "group_nested" ); +#if HIGHFIVE_USE_STRING_VIEW + check(/*file_name*/ std::string_view{"h5_group_test.h5"}, + /*dataset_name*/ std::string_view{"dset"}, + /*chunked_dataset_name*/ std::string_view{"chunked_dset"}, + /*chunked_dataset_small_name*/ std::string_view{"chunked_dset_small"}, + /*group_name_1*/ std::string_view{"/group1"}, + /*group_name_2*/ std::string_view{"group2"}, + /*group_nested_name*/ std::string_view{"group_nested"} ); - // here we use the other signature - DataSet dataset_chunked = - file.createDataSet(chunked_dataset_name, dataspace, goodChunking, cacheConfig); - - // Here we resize to smaller than the chunking size - DataSet dataset_chunked_small = - file.createDataSet(chunked_dataset_small_name, dataspace, goodChunking); - - dataset_chunked_small.resize({1, 1}); - } - // read it back - { - File file(file_name, File::ReadOnly); - Group g1 = file.getGroup(group_name_1); - Group g2 = file.getGroup(group_name_2); - Group nested_group2 = g2.getGroup(group_nested_name); - - DataSet dataset_absolute = file.getDataSet(group_name_1 + "/" + group_nested_name + "/" + - dataset_name); - CHECK(4 == dataset_absolute.getSpace().getDimensions()[0]); - - DataSet dataset_relative = nested_group2.getDataSet(dataset_name); - CHECK(4 == dataset_relative.getSpace().getDimensions()[0]); - - DataSetAccessProps accessProps; - accessProps.add(Caching(13, 1024, 0.5)); - DataSet dataset_chunked = file.getDataSet(chunked_dataset_name, accessProps); - CHECK(4 == dataset_chunked.getSpace().getDimensions()[0]); - - DataSet dataset_chunked_small = file.getDataSet(chunked_dataset_small_name); - CHECK(1 == dataset_chunked_small.getSpace().getDimensions()[0]); - } } TEST_CASE("FileSpace") { @@ -717,7 +756,7 @@ TEST_CASE("Test extensible datasets") { { File file(file_name, File::ReadOnly); - DataSet dataset_absolute = file.getDataSet("/" + dataset_name); + DataSet dataset_absolute = file.getDataSet("/" + std::string{dataset_name}); const auto dims = dataset_absolute.getSpace().getDimensions(); long double values[4][6]; dataset_absolute.read(values);