[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)
This commit is contained in:
Binh-Minh Ribler 2016-01-15 10:53:33 -05:00
parent c09393ed0a
commit 0d68aa89ce
9 changed files with 407 additions and 57 deletions

View File

@ -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) {

View File

@ -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();
}
//--------------------------------------------------------------------------
@ -110,26 +92,68 @@ ArrayType::ArrayType(const DataType& base_type, int ndims, const hsize_t* dims)
dimensions[i] = dims[i];
}
//--------------------------------------------------------------------------
// 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);
}
//--------------------------------------------------------------------------

View File

@ -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();

View File

@ -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());

View File

@ -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

View File

@ -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();

312
c++/test/tarray.cpp Normal file
View File

@ -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

View File

@ -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);

View File

@ -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