From 636b94a86ccd4d9545a8473319fca3a27d2011ac Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Thu, 10 Apr 2014 14:33:07 +0200 Subject: [PATCH] added HDF5File::listAttributes() and test --- include/vigra/hdf5impex.hxx | 54 ++++++++++++++++++++++++++++++++++--- include/vigra/threading.hxx | 2 +- src/impex/hdf5impex.cxx | 14 +++++++--- test/hdf5impex/test.cxx | 23 ++++++++++++++++ 4 files changed, 86 insertions(+), 7 deletions(-) diff --git a/include/vigra/hdf5impex.hxx b/include/vigra/hdf5impex.hxx index caf113739..652b98e62 100644 --- a/include/vigra/hdf5impex.hxx +++ b/include/vigra/hdf5impex.hxx @@ -864,6 +864,7 @@ void HDF5_ls_insert(void*, const std::string &); VIGRA_EXPORT H5O_type_t HDF5_get_type(hid_t, const char*); extern "C" VIGRA_EXPORT herr_t HDF5_ls_inserter_callback(hid_t, const char*, const H5L_info_t*, void*); +extern "C" VIGRA_EXPORT herr_t HDF5_listAttributes_inserter_callback(hid_t, const char*, const H5A_info_t*, void*); /********************************************************/ /* */ @@ -917,13 +918,14 @@ class HDF5File bool read_only_; - // helper class for ls() + // helper classes for ls() and listAttributes() struct ls_closure { virtual void insert(const std::string &) = 0; virtual ~ls_closure() {} }; - // datastructure to hold a list of dataset and group names + + // datastructure to hold a std::vector struct lsOpData : public ls_closure { std::vector & objects; @@ -933,7 +935,8 @@ class HDF5File objects.push_back(x); } }; - // (associative-)container closure + + // datastructure to hold an associative container template struct ls_container_data : public ls_closure { @@ -1433,6 +1436,51 @@ class HDF5File return HDF5Handle(openCreateGroup_(group_name), &H5Gclose, "Internal error"); } + // helper function for the various listAttributes() variants. + void ls_H5Aiterate(std::string const & group_or_dataset, ls_closure & data) const + { + H5O_type_t h5_type = get_object_type_(group_or_dataset); + vigra_precondition(h5_type == H5O_TYPE_GROUP || h5_type == H5O_TYPE_DATASET, + "HDF5File::listAttributes(): object \"" + group_or_dataset + "\" is neither a group nor a dataset."); + // get object handle + HDF5Handle object_handle(h5_type == H5O_TYPE_GROUP + ? const_cast(this)->openCreateGroup_(group_or_dataset) + : getDatasetHandle_(group_or_dataset), + h5_type == H5O_TYPE_GROUP + ? &H5Gclose + : &H5Dclose, + "HDF5File::listAttributes(): unable to open object."); + hsize_t n = 0; + H5Aiterate2(object_handle, H5_INDEX_NAME, H5_ITER_NATIVE, &n, + HDF5_listAttributes_inserter_callback, static_cast(&data)); + } + + /** \brief List the attribute names of the given group or dataset. + + If \a group_or_dataset is empty or "." (a dot), the command + refers to the current group of this file object. + */ + inline std::vector listAttributes(std::string const & group_or_dataset) const + { + std::vector list; + lsOpData data(list); + ls_H5Aiterate(group_or_dataset, data); + return list; + } + + /** \brief Insert the attribute names of the given group or dataset into the given + \a container by calling container.insert(std::string). + + If \a group_or_dataset is empty or "." (a dot), the command + refers to the current group of this file object. + */ + template + void listAttributes(std::string const & group_or_dataset, Container & container) const + { + ls_container_data data(container); + ls_H5Aiterate(group_or_dataset, data); + } + /** \brief Obtain the HDF5 handle of a attribute. */ HDF5Handle getAttributeHandle(std::string dataset_name, std::string attribute_name) const diff --git a/include/vigra/threading.hxx b/include/vigra/threading.hxx index 8de688cab..96acb9dac 100644 --- a/include/vigra/threading.hxx +++ b/include/vigra/threading.hxx @@ -63,7 +63,7 @@ # if BOOST_VERSION >= 105300 # include # define VIGRA_HAS_ATOMIC 1 -#endif +# endif # define VIGRA_THREADING_NAMESPACE boost #else # include diff --git a/src/impex/hdf5impex.cxx b/src/impex/hdf5impex.cxx index 6900accfa..45b8c2961 100644 --- a/src/impex/hdf5impex.cxx +++ b/src/impex/hdf5impex.cxx @@ -194,9 +194,8 @@ void HDF5_ls_insert(void* operator_data, const std::string & x) { static_cast(operator_data)->insert(x); } -// callback function for ls(), called via HDF5File::H5Literate() -// see http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2 -// for as to why. + +// callback function for ls(), called via HDF5File::ls_H5Literate() extern "C" herr_t HDF5_ls_inserter_callback(hid_t loc_id, const char* name, const H5L_info_t*, void* operator_data) @@ -214,6 +213,15 @@ herr_t HDF5_ls_inserter_callback(hid_t loc_id, const char* name, return 0; } +// callback function for listAttributes(), called via HDF5File::ls_H5Literate() +extern "C" +herr_t HDF5_listAttributes_inserter_callback(hid_t loc_id, const char* name, + const H5A_info_t*, void* operator_data) +{ + HDF5_ls_insert(operator_data, name); + return 0; +} + } // namespace vigra #endif // HasHDF5 diff --git a/test/hdf5impex/test.cxx b/test/hdf5impex/test.cxx index 5a7cf0ef7..629eda58f 100644 --- a/test/hdf5impex/test.cxx +++ b/test/hdf5impex/test.cxx @@ -37,6 +37,7 @@ #include #include #include +#include #include "vigra/stdimage.hxx" #include "vigra/unittest.hxx" #include "vigra/hdf5impex.hxx" @@ -733,6 +734,10 @@ class HDF5ExportImportTest file.writeAttribute("/string/dataset","tinyvector attribute", out_attr_3); file.writeAttribute("/string/dataset","rgb attribute", out_attr_4); + std::vector attr = file.listAttributes("/double/dataset"); + shouldEqual(attr.size(), 2); + shouldEqual(attr[0], "int attribute"); + shouldEqual(attr[1], "string attribute"); // read attributes MultiArray<2,int> in_attr_1(MultiArrayShape<2>::type(2,3)); @@ -775,6 +780,24 @@ class HDF5ExportImportTest file.writeAttribute("attrset","set_string",std::string("abc").c_str()); file.writeAttribute("attrset","set_string2",std::string("abcdef")); + std::set many_attr; + file.listAttributes("attrset", many_attr); + shouldEqual(many_attr.size(), 14); + should(many_attr.find("set_char") != many_attr.end()); + should(many_attr.find("set_int8") != many_attr.end()); + should(many_attr.find("set_int16") != many_attr.end()); + should(many_attr.find("set_int32") != many_attr.end()); + should(many_attr.find("set_int64") != many_attr.end()); + should(many_attr.find("set_uint8") != many_attr.end()); + should(many_attr.find("set_uint16") != many_attr.end()); + should(many_attr.find("set_uint32") != many_attr.end()); + should(many_attr.find("set_uint64") != many_attr.end()); + should(many_attr.find("set_float") != many_attr.end()); + should(many_attr.find("set_double") != many_attr.end()); + should(many_attr.find("set_longdouble") != many_attr.end()); + should(many_attr.find("set_string") != many_attr.end()); + should(many_attr.find("set_string2") != many_attr.end()); + char read_char = 0; file.readAttribute("attrset","set_char",read_char); should(read_char=='A');