From 4a4ec03dfdbc98835d601f1ce0005e68a8a076e4 Mon Sep 17 00:00:00 2001 From: Binh-Minh Ribler Date: Thu, 14 Feb 2019 15:35:04 -0600 Subject: Adding a C++ wrapper Description: - Added a wrapper for H5Ovisit2 to class H5Object // Recursively visit elements reachable from this object. void visit(H5_index_t idx_type, H5_iter_order_t order, visit_operator_t user_op, void *op_data, unsigned int fields); - Fixed various typos in documentation Platforms tested: Linux/64 (jelly) Linux/64 (platypus) Darwin (osx1011test) --- c++/src/H5LaccProp.h | 11 ++-- c++/src/H5LcreatProp.h | 11 ++-- c++/src/H5Object.cpp | 69 ++++++++++++++++++++-- c++/src/H5Object.h | 26 +++++++-- c++/test/tlinks.cpp | 156 +++++++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 238 insertions(+), 35 deletions(-) diff --git a/c++/src/H5LaccProp.h b/c++/src/H5LaccProp.h index 70890b3..ec5e54f 100644 --- a/c++/src/H5LaccProp.h +++ b/c++/src/H5LaccProp.h @@ -12,9 +12,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -// Class LinkAccPropList represents the HDF5 file access property list and -// inherits from DataType. - #ifndef __H5LinkAccPropList_H #define __H5LinkAccPropList_H @@ -22,15 +19,15 @@ namespace H5 { /*! \class LinkAccPropList \brief Class LinkAccPropList inherits from PropList and provides - wrappers for the HDF5 file access property list. + wrappers for the HDF5 link access property list. */ // Inheritance: PropList -> IdComponent class H5_DLLCPP LinkAccPropList : public PropList { public: - ///\brief Default file access property list. + ///\brief Default link access property list. static const LinkAccPropList& DEFAULT; - // Creates a file access property list. + // Creates a link access property list. LinkAccPropList(); ///\brief Returns this class name. @@ -39,7 +36,7 @@ class H5_DLLCPP LinkAccPropList : public PropList { // Copy constructor: same as the original LinkAccPropList. LinkAccPropList(const LinkAccPropList& original); - // Creates a copy of an existing file access property list + // Creates a copy of an existing link access property list // using the property list id. LinkAccPropList (const hid_t plist_id); diff --git a/c++/src/H5LcreatProp.h b/c++/src/H5LcreatProp.h index 12cb479..f6e10bf 100644 --- a/c++/src/H5LcreatProp.h +++ b/c++/src/H5LcreatProp.h @@ -12,9 +12,6 @@ * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -// Class LinkCreatPropList represents the HDF5 file access property list and -// inherits from DataType. - #ifndef __H5LinkCreatPropList_H #define __H5LinkCreatPropList_H @@ -22,15 +19,15 @@ namespace H5 { /*! \class LinkCreatPropList \brief Class LinkCreatPropList inherits from PropList and provides - wrappers for the HDF5 file access property list. + wrappers for the HDF5 link creation property list. */ // Inheritance: PropList -> IdComponent class H5_DLLCPP LinkCreatPropList : public PropList { public: - ///\brief Default file access property list. + ///\brief Default link creation property list. static const LinkCreatPropList& DEFAULT; - // Creates a file access property list. + // Creates a link creation property list. LinkCreatPropList(); ///\brief Returns this class name. @@ -39,7 +36,7 @@ class H5_DLLCPP LinkCreatPropList : public PropList { // Copy constructor: same as the original LinkCreatPropList. LinkCreatPropList(const LinkCreatPropList& original); - // Creates a copy of an existing file access property list + // Creates a copy of an existing link creation property list // using the property list id. LinkCreatPropList (const hid_t plist_id); diff --git a/c++/src/H5Object.cpp b/c++/src/H5Object.cpp index 1c22efe..03558e9 100644 --- a/c++/src/H5Object.cpp +++ b/c++/src/H5Object.cpp @@ -12,6 +12,8 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include +#include +using namespace std; #include "H5private.h" // for HDmemset #include "H5Include.h" @@ -40,9 +42,8 @@ namespace H5 { #ifndef DOXYGEN_SHOULD_SKIP_THIS -// userAttrOpWrpr simply interfaces between the user's function and the -// C library function H5Aiterate2; used to resolve the different prototype -// problem. May be moved to Iterator later. +// userAttrOpWrpr interfaces between the user's function and the +// C library function H5Aiterate2 extern "C" herr_t userAttrOpWrpr(hid_t loc_id, const char *attr_name, const H5A_info_t *ainfo, void *op_data) { @@ -52,6 +53,17 @@ extern "C" herr_t userAttrOpWrpr(hid_t loc_id, const char *attr_name, return 0; } +// userVisitOpWrpr interfaces between the user's function and the +// C library function H5Ovisit2 +extern "C" herr_t userVisitOpWrpr(hid_t obj_id, const char *attr_name, + const H5O_info_t *obj_info, void *op_data) +{ + H5std_string s_attr_name = H5std_string(attr_name); + UserData4Visit* myData = reinterpret_cast (op_data); + int status = myData->op(*myData->obj, s_attr_name, obj_info, myData->opData); + return status; +} + //-------------------------------------------------------------------------- // Function: H5Object default constructor (protected) // Programmer Binh-Minh Ribler - 2000 @@ -197,8 +209,6 @@ Attribute H5Object::openAttribute(const unsigned int idx) const ///\par Description /// The signature of user_op is /// void (*)(H5::H5Location&, H5std_string, void*). -/// For information, please refer to the H5Aiterate2 API in -/// the HDF5 C Reference Manual. // Programmer Binh-Minh Ribler - 2000 //-------------------------------------------------------------------------- int H5Object::iterateAttrs(attr_operator_t user_op, unsigned *_idx, void *op_data) @@ -228,6 +238,55 @@ int H5Object::iterateAttrs(attr_operator_t user_op, unsigned *_idx, void *op_dat } //-------------------------------------------------------------------------- +// Function: H5Object::visit +///\brief Recursively visits all HDF5 objects accessible from this object. +///\param idx_type - IN: Type of index; valid values include: +/// \li \c H5_INDEX_NAME +/// \li \c H5_INDEX_CRT_ORDER +///\param order - IN: Order in which index is traversed; valid values include: +/// \li \c H5_ITER_DEC +/// \li \c H5_ITER_INC +/// \li \c H5_ITER_NATIVE +///\param user_op - IN: Callback function passing data regarding the +/// object to the calling application +///\param *op_data - IN: User-defined pointer to data required by the +/// application for its processing of the object +///\param fields - IN: Flags specifying the fields to be retrieved +/// to the callback op +///\return +/// \li On success: +/// \li the return value of the first operator that returns a positive value +/// \li zero if all members were processed with no operator returning non-zero +/// \li On failure: +/// \li an exception Exception will be thrown if something went +/// wrong within the library or the operator failed +///\exception H5::Exception +///\par Description +/// For information, please refer to the H5Ovisit2 API in the HDF5 +/// C Reference Manual. +// Programmer Binh-Minh Ribler - Feb, 2019 +//-------------------------------------------------------------------------- +void H5Object::visit(H5_index_t idx_type, H5_iter_order_t order, visit_operator_t user_op, void *op_data, unsigned int fields) +{ + // Store the user's function and data + UserData4Visit* userData = new UserData4Visit; + userData->opData = op_data; + userData->op = user_op; + userData->obj = this; + + // Call the C API passing in op wrapper and info + herr_t ret_value = H5Ovisit2(getId(), idx_type, order, userVisitOpWrpr, static_cast(userData), fields); + + // Release memory + delete userData; + + // Throw exception if H5Ovisit2 failed, which could be a failure in + // the library or in the call back operator + if (ret_value < 0) + throw Exception(inMemFunc("visit"), "H5Ovisit2 failed"); +} + +//-------------------------------------------------------------------------- // Function: H5Object::objVersion ///\brief Returns the header version of this HDF5 object. ///\return Object version, which can have the following values: diff --git a/c++/src/H5Object.h b/c++/src/H5Object.h index 10b3865..4a4e909 100644 --- a/c++/src/H5Object.h +++ b/c++/src/H5Object.h @@ -40,16 +40,30 @@ namespace H5 { // Inheritance: H5Location -> IdComponent // Define the operator function pointer for H5Aiterate(). -typedef void (*attr_operator_t)(H5Object& loc/*in*/, - const H5std_string attr_name/*in*/, - void *operator_data/*in,out*/); +typedef void (*attr_operator_t)(H5Object& loc, + const H5std_string attr_name, + void *operator_data); + +// Define the operator function pointer for H5Ovisit2(). +typedef int (*visit_operator_t)(H5Object& obj, + const H5std_string attr_name, + const H5O_info_t *oinfo, + void *operator_data); // User data for attribute iteration class UserData4Aiterate { public: attr_operator_t op; void* opData; - H5Object* location; + H5Object* location; // Consider changing to H5Location +}; + +// User data for visit iteration +class UserData4Visit { + public: + visit_operator_t op; + void* opData; + H5Object* obj; }; class H5_DLLCPP H5Object : public H5Location { @@ -71,6 +85,9 @@ class H5_DLLCPP H5Object : public H5Location { // Iterate user's function over the attributes of this object. int iterateAttrs(attr_operator_t user_op, unsigned* idx = NULL, void* op_data = NULL); + // Recursively visit elements reachable from this object. + void visit(H5_index_t idx_type, H5_iter_order_t order, visit_operator_t user_op, void *op_data, unsigned int fields); + // Returns the object header version of an object unsigned objVersion() const; @@ -98,6 +115,7 @@ class H5_DLLCPP H5Object : public H5Location { ssize_t getObjName(H5std_string& obj_name, size_t len = 0) const; H5std_string getObjName() const; + #ifndef DOXYGEN_SHOULD_SKIP_THIS protected: diff --git a/c++/test/tlinks.cpp b/c++/test/tlinks.cpp index 6e990c9..c8bf8e6 100644 --- a/c++/test/tlinks.cpp +++ b/c++/test/tlinks.cpp @@ -33,17 +33,6 @@ using namespace H5; // A lot of the definition inherited from C test links.c is left here until // the H5L API is implemented and tests are completed - BMR 10/19/2009 -/* - * This file needs to access private information from the H5G package. - * This file also needs to access the group testing code. - */ -//#define H5G_FRIEND -//#define H5G_TESTING - -//#include "h5test.h" -//#include "H5Gpkg.h" /* Groups */ -//#include "H5Iprivate.h" /* IDs */ -//#include "H5Lprivate.h" /* Links */ /* File for external link test. Created with gen_udlinks.c */ #define LINKED_FILE "be_extlink2.h5" @@ -95,6 +84,7 @@ const char *FILENAME[] = { "extlinks19A", /* 42: */ "extlinks19B", /* 43: */ "extlinks20", /* 44: */ + "visit", /* 45: */ NULL }; @@ -230,12 +220,15 @@ typedef struct { const link_visit_t *info; /* Pointer to the link visit structure to use */ } lvisit_ud_t; +#endif /* Object visit structs */ typedef struct { const char *path; /* Path to object */ H5O_type_t type; /* Type of object */ } obj_visit_t; + +#if 0 static const obj_visit_t ovisit0_old[] = { {".", H5O_TYPE_GROUP}, {"Dataset_zero", H5O_TYPE_DATASET}, @@ -302,17 +295,18 @@ static const obj_visit_t ovisit2_new[] = { {"hard_zero/Group1/Type_one", H5O_TYPE_NAMED_DATATYPE}, {"hard_zero/Type_zero", H5O_TYPE_NAMED_DATATYPE} }; +#endif typedef struct { unsigned idx; /* Index in object visit structure */ const obj_visit_t *info; /* Pointer to the object visit structure to use */ } ovisit_ud_t; -#endif static const char *FILENAME[] = { "link0", "link1.h5", "link2.h5", + "visit", NULL }; @@ -842,6 +836,138 @@ static void test_num_links(hid_t fapl_id, hbool_t new_format) } // test_num_links +static const obj_visit_t file_visit[] = { + {".", H5O_TYPE_GROUP}, + {"Data", H5O_TYPE_GROUP}, + {"Data/Compressed_Data", H5O_TYPE_DATASET}, + {"Data/Float_Data", H5O_TYPE_DATASET}, +}; + +static const obj_visit_t group_visit[] = { + {".", H5O_TYPE_GROUP}, + {"Compressed_Data", H5O_TYPE_DATASET}, + {"Float_Data", H5O_TYPE_DATASET}, +}; + +const H5std_string FILE_NAME("tvisit.h5"); +const H5std_string GROUP_NAME("/Data"); +const H5std_string DSET1_NAME("/Data/Compressed_Data"); +const H5std_string DSET2_NAME("/Data/Float_Data"); +const int RANK = 2; +const int DIM1 = 2; + +// Operator function +static int visit_obj_cb(H5Object& obj, const H5std_string name, const H5O_info_t *oinfo, void *_op_data) +{ + ovisit_ud_t *op_data = static_cast (_op_data); + + // Check for correct object information + if(strcmp(op_data->info[op_data->idx].path, name.c_str())) return(H5_ITER_ERROR); + if(op_data->info[op_data->idx].type != oinfo->type) return(H5_ITER_ERROR); + + // Advance to next location + op_data->idx++; + + return(H5_ITER_CONT); +} + +/*------------------------------------------------------------------------- + * Function: test_visit + * + * Purpose Test H5Object::visit + * + * Return Success: 0 + * Failure: -1 + * + * February 8, 2019 + *------------------------------------------------------------------------- + */ +static void test_visit(hid_t fapl_id, hbool_t new_format) +{ + hsize_t dims[2]; + hsize_t cdims[2]; + char filename[NAME_BUF_SIZE]; + + if(new_format) + SUBTEST("H5Object::visit (w/new group format)") + else + SUBTEST("H5Object::visit") + + try + { + // Use the file access template id to create a file access prop. list + FileAccPropList fapl(fapl_id); + + // Build the hdf5 file name and create the file + h5_fixname(FILENAME[3], fapl_id, filename, sizeof filename); + H5File *file = new H5File(filename, H5F_ACC_TRUNC, FileCreatPropList::DEFAULT, fapl); + + // Create a group + Group* group = new Group(file->createGroup(GROUP_NAME)); + + // Create a chunked/compressed dataset within this group specified by path + dims[0] = 20; + dims[1] = 2; + cdims[0] = 2; + cdims[1] = 2; + DataSpace *dataspace = new DataSpace(RANK, dims); // create new dspace + DSetCreatPropList ds_creatplist; // create dataset creation prop list + ds_creatplist.setChunk(2, cdims); // then modify it for compression + ds_creatplist.setDeflate(6); + + DataSet* dataset = new DataSet(file->createDataSet(DSET1_NAME, + PredType::NATIVE_INT, *dataspace, ds_creatplist)); + + delete dataset; + delete dataspace; + + // Create another dataset + dims[0] = 5; + dims[1] = 2; + dataspace = new DataSpace(RANK, dims); // create second dspace + dataset = new DataSet(file->createDataSet(DSET2_NAME, + PredType::NATIVE_FLOAT, *dataspace)); + + // Close everything + delete dataset; + delete dataspace; + delete group; + delete file; + + // Reopen the file and group in the file. + file = new H5File(filename, H5F_ACC_RDWR); + group = new Group(file->openGroup("Data")); + + // Open the group + dataset = new DataSet(group->openDataSet(DSET2_NAME)); + delete dataset; + + // Visit objects in the file + ovisit_ud_t udata; /* User-data for visiting */ + udata.idx = 0; + udata.info = file_visit; + + file->visit(H5_INDEX_NAME, H5_ITER_INC, visit_obj_cb, &udata, H5O_INFO_BASIC); + + // Visit objects in the group + udata.idx = 0; + udata.info = group_visit; + + group->visit(H5_INDEX_NAME, H5_ITER_INC, visit_obj_cb, &udata, H5O_INFO_BASIC); + + // Close the group and file. + delete group; + delete file; + + PASSED(); + } // end of try block + catch (Exception& E) + { + issue_fail_msg("test_visit()", __LINE__, __FILE__, E.getCDetailMsg()); + } +} // test_visit + + /*------------------------------------------------------------------------- * Function: test_links * @@ -857,6 +983,11 @@ void test_links() { hid_t fapl_id, fapl2_id; /* File access property lists */ unsigned new_format; /* Whether to use the new format or not */ + const char *envval; + + envval = HDgetenv("HDF5_DRIVER"); + if(envval == NULL) + envval = "nomatch"; fapl_id = h5_fileaccess(); @@ -891,6 +1022,7 @@ void test_links() test_move(my_fapl_id, new_format); test_copy(my_fapl_id, new_format); test_lcpl(my_fapl_id, new_format); + test_visit(my_fapl_id, new_format); } /* end for */ /* Close 2nd FAPL */ -- cgit v0.12