diff options
author | Binh-Minh Ribler <bmribler@hdfgroup.org> | 2016-01-15 15:53:33 (GMT) |
---|---|---|
committer | Binh-Minh Ribler <bmribler@hdfgroup.org> | 2016-01-15 15:53:33 (GMT) |
commit | 0d68aa89cede07df85eca611510a6271fbbb1d8a (patch) | |
tree | bdef31cdbdb77168e26bd4e2ed0eb12665dada44 | |
parent | c09393ed0a2624cc04556249ef5549c2485efe8f (diff) | |
download | hdf5-0d68aa89cede07df85eca611510a6271fbbb1d8a.zip hdf5-0d68aa89cede07df85eca611510a6271fbbb1d8a.tar.gz hdf5-0d68aa89cede07df85eca611510a6271fbbb1d8a.tar.bz2 |
[svn-r28905] Purpose: Fix user reported problem
Description:
User Adam Rosenberger reported a failure when using the member function
AbstractDs::getArrayType(). This problem was caused by missing
initialization of the ArrayType's members in some cases.
Solution:
- Added ArrayType::setArrayInfo() to retrieve rank and dimensions of
an array and store them in memory for easy access.
- Re-factored a few functions to use the new function.
- We'll give him 1.8.16 patch
Platforms tested:
Linux/32 2.6 (jam)
Linux/64 (platypus)
Darwin (osx1010test)
-rw-r--r-- | c++/src/H5AbstractDs.cpp | 3 | ||||
-rw-r--r-- | c++/src/H5ArrayType.cpp | 123 | ||||
-rw-r--r-- | c++/src/H5ArrayType.h | 3 | ||||
-rw-r--r-- | c++/src/H5CompType.cpp | 11 | ||||
-rw-r--r-- | c++/test/Makefile.am | 7 | ||||
-rw-r--r-- | c++/test/h5cpputil.h | 2 | ||||
-rw-r--r-- | c++/test/tarray.cpp | 312 | ||||
-rw-r--r-- | c++/test/testhdf5.cpp | 2 | ||||
-rw-r--r-- | c++/test/ttypes.cpp | 1 |
9 files changed, 407 insertions, 57 deletions
diff --git a/c++/src/H5AbstractDs.cpp b/c++/src/H5AbstractDs.cpp index 06b3e22..4e9a4d5 100644 --- a/c++/src/H5AbstractDs.cpp +++ b/c++/src/H5AbstractDs.cpp @@ -141,8 +141,11 @@ ArrayType AbstractDs::getArrayType() const // depending on which object invokes getArrayType. Then, create and // return the ArrayType object try { + // Create ArrayType and set values this way to work around the + // problem described in the JIRA issue HDFFV-7947 ArrayType arraytype; f_DataType_setId(&arraytype, p_get_type()); + arraytype.setArrayInfo(); return(arraytype); } catch (DataSetIException E) { diff --git a/c++/src/H5ArrayType.cpp b/c++/src/H5ArrayType.cpp index 85340f8..0f09631 100644 --- a/c++/src/H5ArrayType.cpp +++ b/c++/src/H5ArrayType.cpp @@ -35,12 +35,7 @@ namespace H5 { ///\brief Default constructor: Creates a stub ArrayType // Programmer Binh-Minh Ribler - May 2004 //-------------------------------------------------------------------------- -ArrayType::ArrayType() : DataType() -{ - // Initialize members - rank = -1; - dimensions = NULL; -} +ArrayType::ArrayType() : DataType(), rank(-1), dimensions(NULL) {} //-------------------------------------------------------------------------- // Function: ArrayType overloaded constructor @@ -51,20 +46,7 @@ ArrayType::ArrayType() : DataType() //-------------------------------------------------------------------------- ArrayType::ArrayType( const hid_t existing_id ) : DataType( existing_id ) { - // Get the rank of the existing array and store it in this array - rank = H5Tget_array_ndims(existing_id); - if (rank < 0) - { - throw DataTypeIException("ArrayType constructor (existing id)", "H5Tget_array_ndims failed"); - } - - // Allocate space for the dimensions - dimensions = new hsize_t[rank]; - - // Get the dimensions of the existing array and store it in this array - int ret_value = H5Tget_array_dims2(id, dimensions); - if (ret_value < 0) - throw DataTypeIException("ArrayType constructor (existing id)", "H5Tget_array_dims2 failed"); + setArrayInfo(); } //-------------------------------------------------------------------------- @@ -111,25 +93,67 @@ ArrayType::ArrayType(const DataType& base_type, int ndims, const hsize_t* dims) } //-------------------------------------------------------------------------- +// Function: ArrayType::setArrayInfo +///\brief Retrieves the rank and dimensions from the array datatype +/// and store the info in this ArrayType object. +///\exception H5::DataTypeIException +// Programmer Binh-Minh Ribler - January 2016 +//-------------------------------------------------------------------------- +void ArrayType::setArrayInfo() +{ + // Get the rank of the array type specified by id from the C API + int ndims = H5Tget_array_ndims(id); + if (ndims < 0) + { + throw DataTypeIException("ArrayType::setArrayInfo", "H5Tget_array_ndims failed"); + } + + // Get the dimensions from the C API + hsize_t* dims; + dims = new hsize_t[ndims]; + if (dims != NULL) + { + // Get the dimensions + ndims = H5Tget_array_dims2(id, dims); + if (ndims < 0) + throw DataTypeIException("ArrayType::setArrayInfo", "H5Tget_array_dims2 failed"); + + // Store the array's info in memory + rank = ndims; + dimensions = new hsize_t[rank]; + for (int i = 0; i < rank; i++) + dimensions[i] = dims[i]; + delete []dims; + } +} // setArrayInfo + +//-------------------------------------------------------------------------- // Function: ArrayType::getArrayNDims ///\brief Returns the number of dimensions for an array datatype. ///\return Number of dimensions ///\exception H5::DataTypeIException // Programmer Binh-Minh Ribler - May 2004 +// Modification +// Modified to use setArrayInfo(). +// If rank is positive, return rank +// If rank is invalid but object has a valid identifier, obtain the +// rank and dimensions, store them in the object, and return rank +// Otherwise, i.e., rank is invalid and object doesn't have a +// valid identifier, throw an exception //-------------------------------------------------------------------------- int ArrayType::getArrayNDims() { - // If the array's rank has not been stored, i.e. rank is init to -1, - // retrieve it via the C API - if (rank < 0) - { - rank = H5Tget_array_ndims(id); - if (rank < 0) - { - throw DataTypeIException("ArrayType::getArrayNDims", "H5Tget_array_ndims failed"); - } - } - return(rank); + // Validate the id first, this object could be a default object + if (!p_valid_id(id)) + throw DataTypeIException("ArrayType::getArrayNDims", "ArrayType object is not a valid array type."); + + // If the array's info has not been stored, i.e. "rank" still has its + // initial value, -1, and "dimensions" is still NULL, retrieve rank and + // dimensions via the C API and store them in this ArrayType object. + if (rank < 0 && dimensions == NULL) + setArrayInfo(); + + return(rank); } //-------------------------------------------------------------------------- @@ -139,25 +163,30 @@ int ArrayType::getArrayNDims() ///\return Number of dimensions ///\exception H5::DataTypeIException // Programmer Binh-Minh Ribler - May 2004 +// Modification +// Jan, 2016 +// Modified to use setArrayInfo(). +// If the array information has not been stored, retrieve rank and +// dimensions of the array type identified by "id" via the C API. +// Copy "dimensions" to the user's buffer //-------------------------------------------------------------------------- int ArrayType::getArrayDims(hsize_t* dims) { - // If the array's dimensions have not been stored, retrieve them via C API - if (dimensions == NULL) - { - int ndims = H5Tget_array_dims2(id, dims); - if (ndims < 0) - throw DataTypeIException("ArrayType::getArrayDims", "H5Tget_array_dims2 failed"); - // Store the array's info in memory - rank = ndims; - dimensions = new hsize_t[rank]; - for (int i = 0; i < rank; i++) - dimensions[i] = dims[i]; - } - // Otherwise, simply copy what's in 'dimensions' to 'dims' - for (int i = 0; i < rank; i++) - dims[i] = dimensions[i]; - return(rank); + // Validate the id first, this object could be a default object + if (!p_valid_id(id)) + throw DataTypeIException("ArrayType::getArrayDims", "ArrayType object is not a valid array type."); + + // If the array's info has not been stored, i.e. "rank" still has its + // initial value, -1, and "dimensions" is still NULL, retrieve rank and + // dimensions via the C API and store them in this ArrayType object. + if (rank < 0 && dimensions == NULL) + setArrayInfo(); + + // Copy what's in "dimensions" to user's buffer "dims" + for (int i = 0; i < rank; i++) + dims[i] = dimensions[i]; + + return(rank); } //-------------------------------------------------------------------------- diff --git a/c++/src/H5ArrayType.h b/c++/src/H5ArrayType.h index 6577a6e..c0f4b38 100644 --- a/c++/src/H5ArrayType.h +++ b/c++/src/H5ArrayType.h @@ -31,6 +31,9 @@ class H5_DLLCPP ArrayType : public DataType { // specified base type. ArrayType(const DataType& base_type, int ndims, const hsize_t* dims); + // Stores the rank and dimensions in memory. + void setArrayInfo(); + // Returns the number of dimensions of this array datatype. int getArrayNDims(); diff --git a/c++/src/H5CompType.cpp b/c++/src/H5CompType.cpp index 6d31a68..82575d6 100644 --- a/c++/src/H5CompType.cpp +++ b/c++/src/H5CompType.cpp @@ -228,12 +228,12 @@ hid_t CompType::p_get_member_type(unsigned member_num) const DataType CompType::getMemberDataType( unsigned member_num ) const { try { - DataType datatype; + DataType datatype; f_DataType_setId(&datatype, p_get_member_type(member_num)); - return(datatype); + return(datatype); } catch (DataTypeIException E) { - throw DataTypeIException("CompType::getMemberDataType", E.getDetailMsg()); + throw DataTypeIException("CompType::getMemberDataType", E.getDetailMsg()); } } @@ -249,9 +249,10 @@ DataType CompType::getMemberDataType( unsigned member_num ) const ArrayType CompType::getMemberArrayType( unsigned member_num ) const { try { - ArrayType arraytype(p_get_member_type(member_num)); + ArrayType arraytype; f_DataType_setId(&arraytype, p_get_member_type(member_num)); - return(arraytype); + arraytype.setArrayInfo(); + return(arraytype); } catch (DataTypeIException E) { throw DataTypeIException("CompType::getMemberArrayType", E.getDetailMsg()); diff --git a/c++/test/Makefile.am b/c++/test/Makefile.am index 705ec72..07fe533 100644 --- a/c++/test/Makefile.am +++ b/c++/test/Makefile.am @@ -31,9 +31,10 @@ check_PROGRAMS=$(TEST_PROG) # The tests depend on the hdf5 library, test library, and the c++ library LDADD=$(LIBH5TEST) $(LIBH5CPP) $(LIBHDF5) -testhdf5_SOURCES=testhdf5.cpp dsets.cpp tattr.cpp tcompound.cpp \ - tdspl.cpp tfile.cpp tfilter.cpp th5s.cpp tlinks.cpp tobject.cpp \ - trefer.cpp ttypes.cpp tvlstr.cpp h5cpputil.cpp +testhdf5_SOURCES=testhdf5.cpp dsets.cpp tattr.cpp tarray.cpp \ + tcompound.cpp tdspl.cpp tfile.cpp tfilter.cpp th5s.cpp \ + tlinks.cpp tobject.cpp trefer.cpp ttypes.cpp tvlstr.cpp \ + h5cpputil.cpp # Tell conclude.am that these are C++ tests. CXX_API=yes diff --git a/c++/test/h5cpputil.h b/c++/test/h5cpputil.h index 8625213..b615194 100644 --- a/c++/test/h5cpputil.h +++ b/c++/test/h5cpputil.h @@ -132,6 +132,7 @@ template <class Type1, class Type2> #ifdef __cplusplus extern "C" { #endif +void test_array(); void test_attr(); void test_compound(); void test_dsproplist(); @@ -146,6 +147,7 @@ void test_vlstrings(); void test_dset(); /* Prototypes for the cleanup routines */ +void cleanup_array(); void cleanup_attr(); void cleanup_compound(); void cleanup_dsproplist(); diff --git a/c++/test/tarray.cpp b/c++/test/tarray.cpp new file mode 100644 index 0000000..69b4438 --- /dev/null +++ b/c++/test/tarray.cpp @@ -0,0 +1,312 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/***************************************************************************** + FILE + tarray.cpp - HDF5 C++ testing the array datatype functionality + + ***************************************************************************/ + +#ifdef OLD_HEADER_FILENAME +#include <iostream.h> +#else +#include <iostream> +#endif +#include <string> + +#ifndef H5_NO_NAMESPACE +#ifndef H5_NO_STD + using std::cerr; + using std::endl; +#endif // H5_NO_STD +#endif + +#include "H5Cpp.h" // C++ API header file + +#ifndef H5_NO_NAMESPACE + using namespace H5; +#endif + +#include "h5cpputil.h" // C++ utilility header file + +const H5std_string FILENAME("tarray.h5"); +const hsize_t SPACE1_RANK = 1; +const hsize_t SPACE1_DIM1 = 4; +const hsize_t ARRAY1_RANK = 1; +const hsize_t ARRAY1_DIM1 = 4; + +typedef enum flt_t { + FLT_FLOAT, FLT_DOUBLE, FLT_LDOUBLE, FLT_OTHER +} flt_t; + +typedef enum int_t { + INT_CHAR, INT_UCHAR, INT_SHORT, INT_USHORT, INT_INT, INT_UINT, + INT_LONG, INT_ULONG, INT_LLONG, INT_ULLONG, INT_OTHER +} int_t; + + +/*------------------------------------------------------------------------- + * Function: test_array_compound_array + * + * Purpose: Tests 1-D array of compound datatypes (with array fields) + * + * Return: None. + * + * Programmer: Binh-Minh Ribler (using C version) + * January, 2016 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static void test_array_compound_array() +{ + SUBTEST("ArrayType::getArrayNDims & ArrayType::getArrayDims"); + typedef struct { // Typedef for compound datatype */ + int i; + float f[ARRAY1_DIM1]; + } s1_t; + s1_t wdata[SPACE1_DIM1][ARRAY1_DIM1]; // Information to write + s1_t rdata[SPACE1_DIM1][ARRAY1_DIM1]; // Information read in + hsize_t sdims1[] = {SPACE1_DIM1}; + hsize_t tdims1[] = {ARRAY1_DIM1}; + int nmemb; // Number of compound members + int ii, jj, kk; // counting variables + H5T_class_t mclass; // Datatype class for field + + // Initialize array data to write + for (ii =0; ii < SPACE1_DIM1; ii++) + for (jj = 0; jj < ARRAY1_DIM1; jj++) { + wdata[ii][jj].i = ii * 10 + jj; + for(kk = 0; kk < ARRAY1_DIM1; kk++) + wdata[ii][jj].f[kk]=(float)(ii * 10.0F + jj * 2.5F + kk); + } // end for + + try { + // Create File + H5File file1(FILENAME, H5F_ACC_TRUNC); + + // Create dataspace for datasets + DataSpace space(SPACE1_RANK, sdims1, NULL); + + /* + * Create an array datatype of compounds, arrtype. Each compound + * datatype, comptype, contains an integer and an array of floats, + * arrfltype. + */ + + // Create a compound datatype + CompType comptype(sizeof(s1_t)); + + // Insert integer field + comptype.insertMember("i", HOFFSET(s1_t, i), PredType::NATIVE_INT); + + // Create an array of floats datatype + ArrayType arrfltype(PredType::NATIVE_FLOAT, ARRAY1_RANK, tdims1); + + // Insert float array field + comptype.insertMember("f", HOFFSET(s1_t, f), arrfltype); + + // Close array of floats field datatype + arrfltype.close(); + + // Create an array datatype of the compound datatype + ArrayType arrtype(comptype, ARRAY1_RANK, tdims1); + + // Close compound datatype comptype + comptype.close(); + + // Create a dataset + DataSet dataset = file1.createDataSet("Dataset1", arrtype, space); + + // Write dataset to disk + dataset.write(wdata, arrtype); + + // Close all + dataset.close(); + arrtype.close(); + space.close(); + file1.close(); + + // Re-open file + file1.openFile(FILENAME, H5F_ACC_RDONLY); + + // Open the dataset + dataset = file1.openDataSet("Dataset1"); + + /* + * Check the datatype array of compounds + */ + + // Verify that it is an array of compounds + DataType dstype = dataset.getDataType(); + mclass = dstype.getClass(); + verify_val(mclass, H5T_ARRAY, "f2_type.getClass", __LINE__, __FILE__); + dstype.close(); + + // Get the array datatype to check + ArrayType atype_check = dataset.getArrayType(); + + // Check the array rank + int ndims = atype_check.getArrayNDims(); + verify_val(ndims, ARRAY1_RANK, "atype_check.getArrayNDims", __LINE__, __FILE__); + + // Get the array dimensions + hsize_t rdims1[H5S_MAX_RANK]; + atype_check.getArrayDims(rdims1); + + // Check the array dimensions + for (ii =0; ii <ndims; ii++) + if (rdims1[ii]!=tdims1[ii]) { + TestErrPrintf("Array dimension information doesn't match!, rdims1[%d]=%d, tdims1[%d]=%d\n", (int)ii, (int)rdims1[ii], (int)ii, (int)tdims1[ii]); + continue; + } // end if + + // Test ArrayType::ArrayType(const hid_t existing_id) + ArrayType new_arrtype(atype_check.getId()); + + // Check the array rank + ndims = new_arrtype.getArrayNDims(); + verify_val(ndims, ARRAY1_RANK, "new_arrtype.getArrayNDims", __LINE__, __FILE__); + + // Get the array dimensions + new_arrtype.getArrayDims(rdims1); + + // Check the array dimensions + for (ii = 0; ii < ndims; ii++) + if (rdims1[ii] != tdims1[ii]) { + TestErrPrintf("Array dimension information doesn't match!, rdims1[%d]=%d, tdims1[%d]=%d\n", (int)ii, (int)rdims1[ii], (int)ii, (int)tdims1[ii]); + continue; + } // end if + + /* + * Check the compound datatype and the array of floats datatype + * in the compound. + */ + // Get the compound datatype, which is the base datatype of the + // array datatype atype_check. + DataType base_type = atype_check.getSuper(); + mclass = base_type.getClass(); + verify_val(mclass, H5T_COMPOUND, "atype_check.getClass", __LINE__, __FILE__); + + // Verify the compound datatype info + CompType ctype_check(base_type.getId()); + base_type.close(); + + // Check the number of members + nmemb = ctype_check.getNmembers(); + verify_val(nmemb, 2, "ctype_check.getNmembers", __LINE__, __FILE__); + + // Check the 2nd field's name + H5std_string field2_name = ctype_check.getMemberName(1); + if (HDstrcmp(field2_name.c_str(),"f") != 0) + TestErrPrintf("Compound field name doesn't match!, field2_name=%s\n",field2_name.c_str()); + + // Get the 2nd field's datatype + DataType f2_type = ctype_check.getMemberDataType(1); + + // Get the 2nd field's class, this 2nd field should have an array type + mclass = f2_type.getClass(); + verify_val(mclass, H5T_ARRAY, "f2_type.getClass", __LINE__, __FILE__); + f2_type.close(); + + // Get the 2nd field, array of floats datatype, to check + ArrayType f2_atype_check = ctype_check.getMemberArrayType(1); + + // Check the array rank + ndims = f2_atype_check.getArrayNDims(); + verify_val(ndims, ARRAY1_RANK, "f2_atype_check.getArrayNDims", __LINE__, __FILE__); + + // Get the array dimensions + HDmemset(rdims1, 0, H5S_MAX_RANK); + f2_atype_check.getArrayDims(rdims1); + + // Check the array dimensions + for (ii = 0; ii < ndims; ii++) + if (rdims1[ii] != tdims1[ii]) { + TestErrPrintf("Array dimension information doesn't match!, rdims1[%d]=%d, tdims1[%d]=%d\n",(int)ii, (int)rdims1[ii], (int)ii, (int)tdims1[ii]); + continue; + } // end if + + // Close done datatypes + f2_atype_check.close(); + ctype_check.close(); + + // Read dataset from disk + dataset.read(rdata, atype_check); + + // Compare data read in + for (ii = 0; ii < SPACE1_DIM1; ii++) { + for (jj = 0; jj < ARRAY1_DIM1; jj++) { + if (wdata[ii][jj].i != rdata[ii][jj].i) { + TestErrPrintf("Array data information doesn't match!, wdata[%d][%d].i=%d, rdata[%d][%d].i=%d\n",(int)ii,(int)jj,(int)wdata[ii][jj].i,(int)ii,(int)jj,(int)rdata[ii][jj].i); + continue; + } // end if + } // end for + } // end for + + // Close all + atype_check.close(); + dataset.close(); + file1.close(); + PASSED(); + } // end of try block + catch (Exception E) { + issue_fail_msg("test_array_compound_array", __LINE__, __FILE__, E.getCDetailMsg()); + } + +} // end test_array_compound_array() + + +/**************************************************************** +** +** test_array(): Main datatypes testing routine. +** +****************************************************************/ +#ifdef __cplusplus +extern "C" +#endif +void test_array() +{ + // Output message about test being performed + MESSAGE(5, ("Testing Array Datatypes\n")); + + // Test array of compounds with array field + test_array_compound_array(); + +} // test_array() + + +/*------------------------------------------------------------------------- + * Function: cleanup_array + * + * Purpose: Cleanup temporary test files + * + * Return: none + * + * Programmer: Binh-Minh Ribler (using C version) + * January, 2016 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +#ifdef __cplusplus +extern "C" +#endif +void cleanup_array() +{ + HDremove(FILENAME.c_str()); +} // cleanup_array diff --git a/c++/test/testhdf5.cpp b/c++/test/testhdf5.cpp index 59b16cf..b29c6fb 100644 --- a/c++/test/testhdf5.cpp +++ b/c++/test/testhdf5.cpp @@ -91,6 +91,7 @@ main(int argc, char *argv[]) // testing variable-length strings in tvlstr.cpp AddTest("tvlstr", test_vlstrings, cleanup_vlstrings, "Variable-Length Strings", NULL); AddTest("ttypes", test_types, cleanup_types, "Generic Data Types", NULL); + AddTest("tarray", test_array, cleanup_array, "Array Datatypes", NULL); AddTest("tcompound", test_compound, cleanup_compound, "Compound Data Types", NULL); AddTest("tdspl", test_dsproplist, cleanup_dsproplist, "Dataset Property List", NULL); AddTest("tfilter", test_filters, cleanup_filters, "Various Filters", NULL); @@ -100,7 +101,6 @@ main(int argc, char *argv[]) AddTest("time", test_time, cleanup_time, "Time Datatypes", NULL); AddTest("vltypes", test_vltypes, cleanup_vltypes, "Variable-Length Datatypes", NULL); AddTest("iterate", test_iterate, cleanup_iterate, "Group & Attribute Iteration", NULL); - AddTest("array", test_array, cleanup_array, "Array Datatypes", NULL); AddTest("genprop", test_genprop, cleanup_genprop, "Generic Properties", NULL); AddTest("id", test_ids, NULL, "User-Created Identifiers", NULL); diff --git a/c++/test/ttypes.cpp b/c++/test/ttypes.cpp index aae5d86..971a06f 100644 --- a/c++/test/ttypes.cpp +++ b/c++/test/ttypes.cpp @@ -549,7 +549,6 @@ extern "C" void test_types() { // Output message about test being performed - //MESSAGE("Testing Generic Data Types\n"); MESSAGE(5, ("Testing Generic Data Types\n")); // Test basic datatypes |