2003-04-01 01:59:04 +08:00
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
|
|
|
* 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://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have *
|
|
|
|
|
* access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. *
|
|
|
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
2000-04-06 04:51:44 +08:00
|
|
|
|
|
|
|
|
|
/***********************************************************
|
|
|
|
|
*
|
|
|
|
|
* Test program: titerate
|
|
|
|
|
*
|
|
|
|
|
* Test the Group & Attribute functionality
|
|
|
|
|
*
|
|
|
|
|
*************************************************************/
|
|
|
|
|
|
2001-04-04 02:09:16 +08:00
|
|
|
|
#include "testhdf5.h"
|
2000-04-06 04:51:44 +08:00
|
|
|
|
|
2001-04-04 02:09:16 +08:00
|
|
|
|
#include "hdf5.h"
|
2000-04-06 04:51:44 +08:00
|
|
|
|
|
2001-04-01 11:25:53 +08:00
|
|
|
|
#define DATAFILE "titerate.h5"
|
2000-04-06 04:51:44 +08:00
|
|
|
|
|
|
|
|
|
/* Number of datasets for group iteration test */
|
|
|
|
|
#define NDATASETS 50
|
|
|
|
|
|
2003-06-23 21:25:06 +08:00
|
|
|
|
/* Number of attributes for attribute iteration test */
|
2000-04-06 04:51:44 +08:00
|
|
|
|
#define NATTR 50
|
|
|
|
|
|
2000-04-12 23:44:48 +08:00
|
|
|
|
/* Number of groups for second group iteration test */
|
2002-08-10 05:55:44 +08:00
|
|
|
|
#define ITER_NGROUPS 150
|
2000-04-12 23:44:48 +08:00
|
|
|
|
|
2000-04-06 04:51:44 +08:00
|
|
|
|
/* General maximum length of names used */
|
|
|
|
|
#define NAMELEN 80
|
|
|
|
|
|
2000-04-12 23:44:48 +08:00
|
|
|
|
/* 1-D dataset with fixed dimensions */
|
|
|
|
|
#define SPACE1_NAME "Space1"
|
|
|
|
|
#define SPACE1_RANK 1
|
|
|
|
|
#define SPACE1_DIM1 4
|
|
|
|
|
|
2001-09-26 01:46:32 +08:00
|
|
|
|
typedef enum {
|
|
|
|
|
RET_ZERO,
|
2003-06-23 21:25:06 +08:00
|
|
|
|
RET_TWO,
|
2001-09-26 01:46:32 +08:00
|
|
|
|
RET_CHANGE
|
|
|
|
|
} iter_enum;
|
|
|
|
|
|
2000-04-06 04:51:44 +08:00
|
|
|
|
/* Custom group iteration callback data */
|
|
|
|
|
typedef struct {
|
2000-04-12 23:44:48 +08:00
|
|
|
|
char name[NAMELEN]; /* The name of the object */
|
|
|
|
|
int type; /* The type of the object */
|
2001-09-26 01:46:32 +08:00
|
|
|
|
iter_enum command; /* The type of return value */
|
2000-04-06 04:51:44 +08:00
|
|
|
|
} iter_info;
|
|
|
|
|
|
|
|
|
|
/* Local functions */
|
|
|
|
|
int iter_strcmp(const void *s1, const void *s2);
|
2000-04-12 23:44:48 +08:00
|
|
|
|
int iter_strcmp2(const void *s1, const void *s2);
|
2000-04-06 04:51:44 +08:00
|
|
|
|
herr_t giter_cb(hid_t group, const char *name, void *op_data);
|
2000-04-12 23:44:48 +08:00
|
|
|
|
herr_t giter_cb2(hid_t group, const char *name, void *op_data);
|
2000-04-06 04:51:44 +08:00
|
|
|
|
herr_t aiter_cb(hid_t loc_id, const char *name, void *op_data);
|
|
|
|
|
|
|
|
|
|
/****************************************************************
|
|
|
|
|
**
|
|
|
|
|
** iter_strcmp(): String comparison routine for qsort
|
|
|
|
|
**
|
|
|
|
|
****************************************************************/
|
|
|
|
|
int iter_strcmp(const void *s1, const void *s2)
|
|
|
|
|
{
|
2002-02-17 10:51:21 +08:00
|
|
|
|
return(strcmp(*(const char * const *)s1,*(const char * const *)s2));
|
2000-04-06 04:51:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************
|
|
|
|
|
**
|
|
|
|
|
** giter_cb(): Custom group iteration callback routine.
|
|
|
|
|
**
|
|
|
|
|
****************************************************************/
|
|
|
|
|
herr_t giter_cb(hid_t UNUSED group, const char *name, void *op_data)
|
|
|
|
|
{
|
|
|
|
|
iter_info *info=(iter_info *)op_data;
|
|
|
|
|
static int count=0;
|
|
|
|
|
|
|
|
|
|
strcpy(info->name,name);
|
|
|
|
|
|
|
|
|
|
switch(info->command) {
|
|
|
|
|
case RET_ZERO:
|
|
|
|
|
return(0);
|
|
|
|
|
|
2003-06-23 21:25:06 +08:00
|
|
|
|
case RET_TWO:
|
|
|
|
|
return(2);
|
2000-04-06 04:51:44 +08:00
|
|
|
|
|
|
|
|
|
case RET_CHANGE:
|
|
|
|
|
count++;
|
|
|
|
|
return(count>10 ? 1: 0);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
printf("invalid iteration command");
|
|
|
|
|
return(-1);
|
|
|
|
|
} /* end switch */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************
|
|
|
|
|
**
|
|
|
|
|
** test_iter_group(): Test group iteration functionality
|
|
|
|
|
**
|
|
|
|
|
****************************************************************/
|
|
|
|
|
static void test_iter_group(void)
|
|
|
|
|
{
|
|
|
|
|
hid_t file; /* File ID */
|
|
|
|
|
hid_t dataset; /* Dataset ID */
|
|
|
|
|
hid_t datatype; /* Common datatype ID */
|
|
|
|
|
hid_t filespace; /* Common dataspace ID */
|
2002-11-26 01:59:14 +08:00
|
|
|
|
hid_t root_group,grp; /* Root group ID */
|
2000-04-06 04:51:44 +08:00
|
|
|
|
int i; /* counting variable */
|
|
|
|
|
int idx; /* Index in the group */
|
|
|
|
|
char name[NAMELEN]; /* temporary name buffer */
|
|
|
|
|
char *dnames[NDATASETS];/* Names of the datasets created */
|
2003-08-27 02:35:37 +08:00
|
|
|
|
char dataset_name[NAMELEN]; /* dataset name */
|
2000-04-06 04:51:44 +08:00
|
|
|
|
iter_info info; /* Custom iteration information */
|
2002-11-26 01:59:14 +08:00
|
|
|
|
hsize_t num_membs; /* Number of group members */
|
|
|
|
|
herr_t ret; /* Generic return value */
|
2000-04-06 04:51:44 +08:00
|
|
|
|
|
|
|
|
|
/* Output message about test being performed */
|
|
|
|
|
MESSAGE(5, ("Testing Group Iteration Functionality\n"));
|
|
|
|
|
|
|
|
|
|
/* Create the test file with the datasets */
|
2001-04-01 11:25:53 +08:00
|
|
|
|
file = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
|
2000-04-06 04:51:44 +08:00
|
|
|
|
CHECK(file, FAIL, "H5Fcreate");
|
|
|
|
|
|
2003-06-23 21:25:06 +08:00
|
|
|
|
/* Test iterating over empty group */
|
|
|
|
|
info.command=RET_ZERO;
|
|
|
|
|
idx=0;
|
|
|
|
|
ret=H5Giterate(file,"/",&idx,giter_cb,&info);
|
|
|
|
|
VERIFY(ret, SUCCEED, "H5Giterate");
|
|
|
|
|
|
2000-04-06 04:51:44 +08:00
|
|
|
|
datatype = H5Tcopy(H5T_NATIVE_INT);
|
|
|
|
|
CHECK(datatype, FAIL, "H5Tcopy");
|
|
|
|
|
|
|
|
|
|
filespace=H5Screate(H5S_SCALAR);
|
|
|
|
|
CHECK(filespace, FAIL, "H5Screate");
|
|
|
|
|
|
|
|
|
|
for(i=0; i< NDATASETS; i++) {
|
|
|
|
|
sprintf(name,"Dataset %d",i);
|
|
|
|
|
dataset = H5Dcreate(file, name, datatype, filespace, H5P_DEFAULT);
|
|
|
|
|
CHECK(dataset, FAIL, "H5Dcreate");
|
|
|
|
|
|
|
|
|
|
/* Keep a copy of the dataset names around for later */
|
2001-06-29 23:27:15 +08:00
|
|
|
|
dnames[i]=HDstrdup(name);
|
2000-04-06 04:51:44 +08:00
|
|
|
|
CHECK(dnames[i], NULL, "strdup");
|
|
|
|
|
|
|
|
|
|
ret=H5Dclose(dataset);
|
|
|
|
|
CHECK(ret, FAIL, "H5Dclose");
|
|
|
|
|
}
|
|
|
|
|
|
2002-11-26 01:59:14 +08:00
|
|
|
|
/* Create a group and named datatype under root group for testing
|
|
|
|
|
* H5Gget_objtype_by_idx.
|
|
|
|
|
*/
|
|
|
|
|
grp = H5Gcreate(file, "grp", 0);
|
|
|
|
|
CHECK(ret, FAIL, "H5Gcreate");
|
|
|
|
|
|
|
|
|
|
ret = H5Tcommit(file, "dtype", datatype);
|
|
|
|
|
CHECK(ret, FAIL, "H5Tcommit");
|
|
|
|
|
|
2000-04-06 04:51:44 +08:00
|
|
|
|
/* Close everything up */
|
|
|
|
|
ret=H5Tclose(datatype);
|
|
|
|
|
CHECK(ret, FAIL, "H5Tclose");
|
2002-11-26 01:59:14 +08:00
|
|
|
|
|
|
|
|
|
ret=H5Gclose(grp);
|
|
|
|
|
CHECK(ret, FAIL, "H5Gclose");
|
|
|
|
|
|
2000-04-06 04:51:44 +08:00
|
|
|
|
ret=H5Sclose(filespace);
|
|
|
|
|
CHECK(ret, FAIL, "H5Sclose");
|
|
|
|
|
|
|
|
|
|
ret=H5Fclose(file);
|
|
|
|
|
CHECK(ret, FAIL, "H5Fclose");
|
|
|
|
|
|
|
|
|
|
/* Sort the dataset names */
|
2004-01-10 09:41:13 +08:00
|
|
|
|
HDqsort(dnames,NDATASETS,sizeof(char *),iter_strcmp);
|
2000-04-06 04:51:44 +08:00
|
|
|
|
|
2002-11-26 01:59:14 +08:00
|
|
|
|
|
2000-04-06 04:51:44 +08:00
|
|
|
|
/* Iterate through the datasets in the root group in various ways */
|
2001-04-01 11:25:53 +08:00
|
|
|
|
file=H5Fopen(DATAFILE, H5F_ACC_RDONLY, H5P_DEFAULT);
|
2000-04-06 04:51:44 +08:00
|
|
|
|
CHECK(file, FAIL, "H5Fopen");
|
|
|
|
|
|
2003-06-23 21:25:06 +08:00
|
|
|
|
/* These two functions, H5Gget_num_objs and H5Gget_objname_by_idx, actually
|
2002-11-26 01:59:14 +08:00
|
|
|
|
* iterate through B-tree for group members in internal library design.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
root_group = H5Gopen(file, "/");
|
|
|
|
|
CHECK(root_group, FAIL, "H5Gopen");
|
|
|
|
|
|
|
|
|
|
ret = H5Gget_num_objs(root_group, &num_membs);
|
|
|
|
|
CHECK(ret, FAIL, "H5Gget_num_objs");
|
|
|
|
|
VERIFY(num_membs,NDATASETS+2,"H5Gget_num_objs");
|
|
|
|
|
|
2002-12-02 21:15:36 +08:00
|
|
|
|
for(i=0; i< (int)num_membs; i++) {
|
2003-07-08 03:02:46 +08:00
|
|
|
|
H5G_obj_t obj_type; /* Type of object in file */
|
|
|
|
|
|
2004-04-18 12:10:09 +08:00
|
|
|
|
ret = (herr_t)H5Gget_objname_by_idx(root_group, (hsize_t)i, dataset_name, NAMELEN);
|
2003-08-27 02:35:37 +08:00
|
|
|
|
CHECK(ret, FAIL, "H5Gget_objname_by_idx");
|
2002-11-26 01:59:14 +08:00
|
|
|
|
|
2003-07-08 03:02:46 +08:00
|
|
|
|
obj_type = H5Gget_objtype_by_idx(root_group, (hsize_t)i);
|
2003-08-27 02:35:37 +08:00
|
|
|
|
CHECK(obj_type, H5G_UNKNOWN, "H5Gget_objtype_by_idx");
|
2002-11-26 01:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
H5E_BEGIN_TRY {
|
2003-08-27 02:35:37 +08:00
|
|
|
|
ret = (herr_t)H5Gget_objname_by_idx(root_group, (hsize_t)(NDATASETS+3), dataset_name, NAMELEN);
|
2002-11-26 01:59:14 +08:00
|
|
|
|
} H5E_END_TRY;
|
2003-08-27 02:35:37 +08:00
|
|
|
|
VERIFY(ret, FAIL, "H5Gget_objname_by_idx");
|
2002-11-26 01:59:14 +08:00
|
|
|
|
|
|
|
|
|
ret = H5Gclose(root_group);
|
|
|
|
|
CHECK(ret, FAIL, "H5Gclose");
|
|
|
|
|
}
|
|
|
|
|
|
2003-08-22 21:50:01 +08:00
|
|
|
|
/* These two functions, H5Gget_num_objs and H5Gget_objname_by_idx, actually
|
|
|
|
|
* iterate through B-tree for group members in internal library design.
|
|
|
|
|
* (Same as test above, but with the file ID instead of opening the root group)
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
ret = H5Gget_num_objs(file, &num_membs);
|
|
|
|
|
CHECK(ret, FAIL, "H5Gget_num_objs");
|
|
|
|
|
VERIFY(num_membs,NDATASETS+2,"H5Gget_num_objs");
|
|
|
|
|
|
|
|
|
|
for(i=0; i< (int)num_membs; i++) {
|
|
|
|
|
H5G_obj_t obj_type; /* Type of object in file */
|
|
|
|
|
|
2004-04-18 12:10:09 +08:00
|
|
|
|
ret = (herr_t)H5Gget_objname_by_idx(file, (hsize_t)i, dataset_name, NAMELEN);
|
2003-08-27 02:35:37 +08:00
|
|
|
|
CHECK(ret, FAIL, "H5Gget_objname_by_idx");
|
2003-08-22 21:50:01 +08:00
|
|
|
|
|
|
|
|
|
obj_type = H5Gget_objtype_by_idx(file, (hsize_t)i);
|
2003-08-27 02:35:37 +08:00
|
|
|
|
CHECK(obj_type, H5G_UNKNOWN, "H5Gget_objtype_by_idx");
|
2003-08-22 21:50:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
H5E_BEGIN_TRY {
|
2003-08-27 02:35:37 +08:00
|
|
|
|
ret = (herr_t)H5Gget_objname_by_idx(file, (hsize_t)(NDATASETS+3), dataset_name, NAMELEN);
|
2003-08-22 21:50:01 +08:00
|
|
|
|
} H5E_END_TRY;
|
2003-08-27 02:35:37 +08:00
|
|
|
|
VERIFY(ret, FAIL, "H5Gget_objname_by_idx");
|
2003-08-22 21:50:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
2003-06-23 21:25:06 +08:00
|
|
|
|
/* Test invalid indices for starting iteration */
|
|
|
|
|
info.command=RET_ZERO;
|
|
|
|
|
idx=-1;
|
|
|
|
|
H5E_BEGIN_TRY {
|
|
|
|
|
ret=H5Giterate(file,"/",&idx,giter_cb,&info);
|
|
|
|
|
} H5E_END_TRY;
|
|
|
|
|
VERIFY(ret, FAIL, "H5Giterate");
|
|
|
|
|
|
|
|
|
|
/* Test skipping exactly as many entries as in the group */
|
|
|
|
|
idx=NDATASETS+2;
|
|
|
|
|
H5E_BEGIN_TRY {
|
|
|
|
|
ret=H5Giterate(file,"/",&idx,giter_cb,&info);
|
|
|
|
|
} H5E_END_TRY;
|
|
|
|
|
VERIFY(ret, FAIL, "H5Giterate");
|
|
|
|
|
|
|
|
|
|
/* Test skipping more entries than are in the group */
|
|
|
|
|
idx=NDATASETS+3;
|
|
|
|
|
H5E_BEGIN_TRY {
|
|
|
|
|
ret=H5Giterate(file,"/",&idx,giter_cb,&info);
|
|
|
|
|
} H5E_END_TRY;
|
|
|
|
|
VERIFY(ret, FAIL, "H5Giterate");
|
|
|
|
|
|
2000-04-06 04:51:44 +08:00
|
|
|
|
/* Test all objects in group, when callback always returns 0 */
|
|
|
|
|
info.command=RET_ZERO;
|
|
|
|
|
idx=0;
|
2004-01-10 09:41:13 +08:00
|
|
|
|
if((ret=H5Giterate(file,"/",&idx,giter_cb,&info))>0)
|
|
|
|
|
TestErrPrintf("Group iteration function didn't return zero correctly!\n");
|
2000-04-06 04:51:44 +08:00
|
|
|
|
|
|
|
|
|
/* Test all objects in group, when callback always returns 1 */
|
|
|
|
|
/* This also tests the "restarting" ability, because the index changes */
|
2003-06-23 21:25:06 +08:00
|
|
|
|
info.command=RET_TWO;
|
2000-04-06 04:51:44 +08:00
|
|
|
|
idx=i=0;
|
2003-06-23 21:25:06 +08:00
|
|
|
|
while((ret=H5Giterate(file,"/",&idx,giter_cb,&info))>0) {
|
|
|
|
|
/* Verify return value from iterator gets propagated correctly */
|
|
|
|
|
VERIFY(ret,2,"H5Giterate");
|
|
|
|
|
|
2000-04-06 04:51:44 +08:00
|
|
|
|
/* Increment the number of times "1" is returned */
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
|
|
/* Verify that the index is the correct value */
|
|
|
|
|
VERIFY(idx,i,"H5Giterate");
|
|
|
|
|
|
|
|
|
|
/* Verify that the correct name is retrieved */
|
2003-06-23 21:25:06 +08:00
|
|
|
|
if(idx<=NDATASETS) {
|
2004-01-10 09:41:13 +08:00
|
|
|
|
if(HDstrcmp(info.name,dnames[idx-1])!=0)
|
|
|
|
|
TestErrPrintf("Group iteration function didn't return one correctly for dataset #%d!\n",idx);
|
2003-06-23 21:25:06 +08:00
|
|
|
|
} /* end if */
|
|
|
|
|
else if(idx==(NDATASETS+1)) {
|
2004-01-10 09:41:13 +08:00
|
|
|
|
if(HDstrcmp(info.name,"dtype")!=0)
|
|
|
|
|
TestErrPrintf("Group iteration function didn't return one correctly for group!\n");
|
2000-04-06 04:51:44 +08:00
|
|
|
|
} /* end if */
|
2003-06-23 21:25:06 +08:00
|
|
|
|
else if(idx==(NDATASETS+2)) {
|
2004-01-10 09:41:13 +08:00
|
|
|
|
if(HDstrcmp(info.name,"grp")!=0)
|
|
|
|
|
TestErrPrintf("Group iteration function didn't return one correctly for group!\n");
|
2003-06-23 21:25:06 +08:00
|
|
|
|
} /* end if */
|
2004-01-10 09:41:13 +08:00
|
|
|
|
else
|
|
|
|
|
TestErrPrintf("Group iteration function walked too far!\n");
|
2000-04-06 04:51:44 +08:00
|
|
|
|
}
|
2003-06-23 21:25:06 +08:00
|
|
|
|
VERIFY(ret,-1,"H5Giterate");
|
|
|
|
|
|
2004-01-10 09:41:13 +08:00
|
|
|
|
if(i!=(NDATASETS+2))
|
|
|
|
|
TestErrPrintf("Group iteration function didn't perform multiple iterations correctly!\n");
|
2000-04-06 04:51:44 +08:00
|
|
|
|
|
|
|
|
|
/* Test all objects in group, when callback changes return value */
|
|
|
|
|
/* This also tests the "restarting" ability, because the index changes */
|
|
|
|
|
info.command=RET_CHANGE;
|
|
|
|
|
idx=i=0;
|
2003-06-23 21:25:06 +08:00
|
|
|
|
while((ret=H5Giterate(file,"/",&idx,giter_cb,&info))>=0) {
|
|
|
|
|
/* Verify return value from iterator gets propagated correctly */
|
|
|
|
|
VERIFY(ret,1,"H5Giterate");
|
|
|
|
|
|
2000-04-06 04:51:44 +08:00
|
|
|
|
/* Increment the number of times "1" is returned */
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
|
|
/* Verify that the index is the correct value */
|
|
|
|
|
VERIFY(idx,i+10,"H5Giterate");
|
|
|
|
|
|
|
|
|
|
/* Verify that the correct name is retrieved */
|
2003-06-23 21:25:06 +08:00
|
|
|
|
if(idx<=NDATASETS) {
|
2004-01-10 09:41:13 +08:00
|
|
|
|
if(HDstrcmp(info.name,dnames[idx-1])!=0)
|
|
|
|
|
TestErrPrintf("Group iteration function didn't return one correctly for dataset #%d!\n",idx);
|
2003-06-23 21:25:06 +08:00
|
|
|
|
} /* end if */
|
|
|
|
|
else if(idx==(NDATASETS+1)) {
|
2004-01-10 09:41:13 +08:00
|
|
|
|
if(HDstrcmp(info.name,"dtype")!=0)
|
|
|
|
|
TestErrPrintf("Group iteration function didn't return one correctly for group!\n");
|
2000-04-06 04:51:44 +08:00
|
|
|
|
} /* end if */
|
2003-06-23 21:25:06 +08:00
|
|
|
|
else if(idx==(NDATASETS+2)) {
|
2004-01-10 09:41:13 +08:00
|
|
|
|
if(HDstrcmp(info.name,"grp")!=0)
|
|
|
|
|
TestErrPrintf("Group iteration function didn't return one correctly for group!\n");
|
2003-06-23 21:25:06 +08:00
|
|
|
|
} /* end if */
|
2004-01-10 09:41:13 +08:00
|
|
|
|
else
|
|
|
|
|
TestErrPrintf("Group iteration function walked too far!\n");
|
2000-04-06 04:51:44 +08:00
|
|
|
|
}
|
2003-06-23 21:25:06 +08:00
|
|
|
|
VERIFY(ret,-1,"H5Giterate");
|
|
|
|
|
|
2004-01-10 09:41:13 +08:00
|
|
|
|
if(i!=42 || idx!=52)
|
|
|
|
|
TestErrPrintf("Group iteration function didn't perform multiple iterations correctly!\n");
|
2000-04-06 04:51:44 +08:00
|
|
|
|
|
|
|
|
|
ret=H5Fclose(file);
|
|
|
|
|
CHECK(ret, FAIL, "H5Fclose");
|
|
|
|
|
|
|
|
|
|
/* Free the dataset names */
|
|
|
|
|
for(i=0; i< NDATASETS; i++)
|
2004-01-10 09:41:13 +08:00
|
|
|
|
HDfree(dnames[i]);
|
2000-04-06 04:51:44 +08:00
|
|
|
|
|
|
|
|
|
} /* test_iter_group() */
|
|
|
|
|
|
|
|
|
|
/****************************************************************
|
|
|
|
|
**
|
|
|
|
|
** aiter_cb(): Custom group iteration callback routine.
|
|
|
|
|
**
|
|
|
|
|
****************************************************************/
|
|
|
|
|
herr_t aiter_cb(hid_t UNUSED group, const char *name, void *op_data)
|
|
|
|
|
{
|
|
|
|
|
iter_info *info=(iter_info *)op_data;
|
|
|
|
|
static int count=0;
|
|
|
|
|
|
|
|
|
|
strcpy(info->name,name);
|
|
|
|
|
|
|
|
|
|
switch(info->command) {
|
|
|
|
|
case RET_ZERO:
|
|
|
|
|
return(0);
|
|
|
|
|
|
2003-06-23 21:25:06 +08:00
|
|
|
|
case RET_TWO:
|
|
|
|
|
return(2);
|
2000-04-06 04:51:44 +08:00
|
|
|
|
|
|
|
|
|
case RET_CHANGE:
|
|
|
|
|
count++;
|
|
|
|
|
return(count>10 ? 1: 0);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
printf("invalid iteration command");
|
|
|
|
|
return(-1);
|
|
|
|
|
} /* end switch */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************
|
|
|
|
|
**
|
|
|
|
|
** test_iter_attr(): Test attribute iteration functionality
|
|
|
|
|
**
|
|
|
|
|
****************************************************************/
|
|
|
|
|
static void test_iter_attr(void)
|
|
|
|
|
{
|
|
|
|
|
hid_t file; /* File ID */
|
|
|
|
|
hid_t dataset; /* Common Dataset ID */
|
|
|
|
|
hid_t datatype; /* Common datatype ID */
|
|
|
|
|
hid_t filespace; /* Common dataspace ID */
|
|
|
|
|
hid_t attribute; /* Attribute ID */
|
|
|
|
|
int i; /* counting variable */
|
|
|
|
|
unsigned idx; /* Index in the attribute list */
|
|
|
|
|
char name[NAMELEN]; /* temporary name buffer */
|
|
|
|
|
char *anames[NATTR]; /* Names of the attributes created */
|
|
|
|
|
iter_info info; /* Custom iteration information */
|
|
|
|
|
herr_t ret; /* Generic return value */
|
|
|
|
|
|
|
|
|
|
/* Output message about test being performed */
|
|
|
|
|
MESSAGE(5, ("Testing Attribute Iteration Functionality\n"));
|
|
|
|
|
|
|
|
|
|
/* Create the test file with the datasets */
|
2001-04-01 11:25:53 +08:00
|
|
|
|
file = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
|
2000-04-06 04:51:44 +08:00
|
|
|
|
CHECK(file, FAIL, "H5Fcreate");
|
|
|
|
|
|
|
|
|
|
datatype = H5Tcopy(H5T_NATIVE_INT);
|
|
|
|
|
CHECK(datatype, FAIL, "H5Tcopy");
|
|
|
|
|
|
|
|
|
|
filespace=H5Screate(H5S_SCALAR);
|
|
|
|
|
CHECK(filespace, FAIL, "H5Screate");
|
|
|
|
|
|
|
|
|
|
dataset = H5Dcreate(file, "Dataset", datatype, filespace, H5P_DEFAULT);
|
|
|
|
|
CHECK(dataset, FAIL, "H5Dcreate");
|
|
|
|
|
|
2003-06-23 21:25:06 +08:00
|
|
|
|
for(i=0; i< NATTR; i++) {
|
2000-04-06 04:51:44 +08:00
|
|
|
|
sprintf(name,"Attribute %d",i);
|
|
|
|
|
attribute = H5Acreate(dataset, name, datatype, filespace, H5P_DEFAULT);
|
|
|
|
|
CHECK(attribute, FAIL, "H5Acreate");
|
|
|
|
|
|
|
|
|
|
/* Keep a copy of the attribute names around for later */
|
2001-06-29 23:27:15 +08:00
|
|
|
|
anames[i]=HDstrdup(name);
|
2000-04-06 04:51:44 +08:00
|
|
|
|
CHECK(anames[i], NULL, "strdup");
|
|
|
|
|
|
|
|
|
|
ret=H5Aclose(attribute);
|
|
|
|
|
CHECK(ret, FAIL, "H5Aclose");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Close everything up */
|
|
|
|
|
ret=H5Dclose(dataset);
|
|
|
|
|
CHECK(ret, FAIL, "H5Dclose");
|
|
|
|
|
|
|
|
|
|
ret=H5Tclose(datatype);
|
|
|
|
|
CHECK(ret, FAIL, "H5Tclose");
|
|
|
|
|
|
|
|
|
|
ret=H5Sclose(filespace);
|
|
|
|
|
CHECK(ret, FAIL, "H5Sclose");
|
|
|
|
|
|
|
|
|
|
ret=H5Fclose(file);
|
|
|
|
|
CHECK(ret, FAIL, "H5Fclose");
|
|
|
|
|
|
|
|
|
|
/* Iterate through the attributes on the dataset in various ways */
|
2001-04-01 11:25:53 +08:00
|
|
|
|
file=H5Fopen(DATAFILE, H5F_ACC_RDONLY, H5P_DEFAULT);
|
2000-04-06 04:51:44 +08:00
|
|
|
|
CHECK(file, FAIL, "H5Fopen");
|
|
|
|
|
|
|
|
|
|
dataset=H5Dopen(file, "Dataset");
|
|
|
|
|
CHECK(dataset, FAIL, "H5Dopen");
|
|
|
|
|
|
2003-06-23 21:25:06 +08:00
|
|
|
|
/* Test invalid indices for starting iteration */
|
|
|
|
|
info.command=RET_ZERO;
|
|
|
|
|
|
|
|
|
|
/* Test skipping exactly as many attributes as there are */
|
|
|
|
|
idx=NATTR;
|
|
|
|
|
H5E_BEGIN_TRY {
|
|
|
|
|
ret=H5Aiterate(dataset,&idx,aiter_cb,&info);
|
|
|
|
|
} H5E_END_TRY;
|
|
|
|
|
VERIFY(ret, FAIL, "H5Aiterate");
|
|
|
|
|
|
|
|
|
|
/* Test skipping more attributes than there are */
|
|
|
|
|
idx=NATTR+1;
|
|
|
|
|
H5E_BEGIN_TRY {
|
|
|
|
|
ret=H5Aiterate(dataset,&idx,aiter_cb,&info);
|
|
|
|
|
} H5E_END_TRY;
|
|
|
|
|
VERIFY(ret, FAIL, "H5Aiterate");
|
|
|
|
|
|
2000-04-06 04:51:44 +08:00
|
|
|
|
/* Test all attributes on dataset, when callback always returns 0 */
|
|
|
|
|
info.command=RET_ZERO;
|
|
|
|
|
idx=0;
|
2004-01-10 09:41:13 +08:00
|
|
|
|
if((ret=H5Aiterate(dataset,&idx,aiter_cb,&info))>0)
|
|
|
|
|
TestErrPrintf("Attribute iteration function didn't return zero correctly!\n");
|
2000-04-06 04:51:44 +08:00
|
|
|
|
|
|
|
|
|
/* Test all attributes on dataset, when callback always returns 1 */
|
|
|
|
|
/* This also tests the "restarting" ability, because the index changes */
|
2003-06-23 21:25:06 +08:00
|
|
|
|
info.command=RET_TWO;
|
2000-04-06 04:51:44 +08:00
|
|
|
|
idx=i=0;
|
2003-06-23 21:25:06 +08:00
|
|
|
|
while((ret=H5Aiterate(dataset,&idx,aiter_cb,&info))>0) {
|
|
|
|
|
/* Verify return value from iterator gets propagated correctly */
|
|
|
|
|
VERIFY(ret,2,"H5Aiterate");
|
|
|
|
|
|
2000-04-06 04:51:44 +08:00
|
|
|
|
/* Increment the number of times "1" is returned */
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
|
|
/* Verify that the index is the correct value */
|
|
|
|
|
VERIFY(idx,(unsigned)i,"H5Aiterate");
|
|
|
|
|
|
|
|
|
|
/* Verify that the correct name is retrieved */
|
2004-01-10 09:41:13 +08:00
|
|
|
|
if(HDstrcmp(info.name,anames[idx-1])!=0)
|
|
|
|
|
TestErrPrintf("Attribute iteration function didn't return one correctly!\n");
|
2000-04-06 04:51:44 +08:00
|
|
|
|
}
|
2003-06-23 21:25:06 +08:00
|
|
|
|
VERIFY(ret,-1,"H5Aiterate");
|
2004-01-10 09:41:13 +08:00
|
|
|
|
if(i!=50 || idx!=50)
|
|
|
|
|
TestErrPrintf("Group iteration function didn't perform multiple iterations correctly!\n");
|
2003-06-23 21:25:06 +08:00
|
|
|
|
|
2000-04-06 04:51:44 +08:00
|
|
|
|
|
|
|
|
|
/* Test all attributes on dataset, when callback changes return value */
|
|
|
|
|
/* This also tests the "restarting" ability, because the index changes */
|
|
|
|
|
info.command=RET_CHANGE;
|
|
|
|
|
idx=i=0;
|
2003-06-23 21:25:06 +08:00
|
|
|
|
while((ret=H5Aiterate(dataset,&idx,aiter_cb,&info))>0) {
|
|
|
|
|
/* Verify return value from iterator gets propagated correctly */
|
|
|
|
|
VERIFY(ret,1,"H5Aiterate");
|
|
|
|
|
|
2000-04-06 04:51:44 +08:00
|
|
|
|
/* Increment the number of times "1" is returned */
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
|
|
/* Verify that the index is the correct value */
|
|
|
|
|
VERIFY(idx,(unsigned)i+10,"H5Aiterate");
|
|
|
|
|
|
|
|
|
|
/* Verify that the correct name is retrieved */
|
2004-01-10 09:41:13 +08:00
|
|
|
|
if(HDstrcmp(info.name,anames[idx-1])!=0)
|
|
|
|
|
TestErrPrintf("Attribute iteration function didn't return changing correctly!\n");
|
2000-04-06 04:51:44 +08:00
|
|
|
|
}
|
2003-06-23 21:25:06 +08:00
|
|
|
|
VERIFY(ret,-1,"H5Aiterate");
|
2004-01-10 09:41:13 +08:00
|
|
|
|
if(i!=40 || idx!=50)
|
|
|
|
|
TestErrPrintf("Group iteration function didn't perform multiple iterations correctly!\n");
|
2000-04-06 04:51:44 +08:00
|
|
|
|
|
|
|
|
|
ret=H5Fclose(file);
|
|
|
|
|
CHECK(ret, FAIL, "H5Fclose");
|
|
|
|
|
|
|
|
|
|
ret=H5Dclose(dataset);
|
|
|
|
|
CHECK(ret, FAIL, "H5Dclose");
|
|
|
|
|
|
|
|
|
|
/* Free the attribute names */
|
|
|
|
|
for(i=0; i< NATTR; i++)
|
2004-01-10 09:41:13 +08:00
|
|
|
|
HDfree(anames[i]);
|
2000-04-06 04:51:44 +08:00
|
|
|
|
|
|
|
|
|
} /* test_iter_attr() */
|
|
|
|
|
|
2000-04-12 23:44:48 +08:00
|
|
|
|
/****************************************************************
|
|
|
|
|
**
|
|
|
|
|
** iter_strcmp2(): String comparison routine for qsort
|
|
|
|
|
**
|
|
|
|
|
****************************************************************/
|
|
|
|
|
int iter_strcmp2(const void *s1, const void *s2)
|
|
|
|
|
{
|
|
|
|
|
return(strcmp((const char *)s1,(const char *)s2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************
|
|
|
|
|
**
|
|
|
|
|
** giter_cb2(): Custom group iteration callback routine.
|
|
|
|
|
**
|
|
|
|
|
****************************************************************/
|
|
|
|
|
herr_t giter_cb2(hid_t loc_id, const char *name, void *opdata)
|
|
|
|
|
{
|
|
|
|
|
const iter_info *test_info=(const iter_info *)opdata;
|
|
|
|
|
herr_t ret; /* Generic return value */
|
|
|
|
|
H5G_stat_t statbuf;
|
|
|
|
|
|
2004-01-10 09:41:13 +08:00
|
|
|
|
if(HDstrcmp(name,test_info->name)) {
|
|
|
|
|
TestErrPrintf("name=%s, test_info=%s\n",name,test_info->name);
|
2000-04-12 23:44:48 +08:00
|
|
|
|
return(-1);
|
|
|
|
|
} /* end if */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get type of the object and check it.
|
|
|
|
|
*/
|
|
|
|
|
ret=H5Gget_objinfo(loc_id, name, FALSE, &statbuf);
|
|
|
|
|
CHECK(ret, FAIL, "H5Gget_objinfo");
|
|
|
|
|
|
|
|
|
|
if(test_info->type!=statbuf.type) {
|
2004-01-10 09:41:13 +08:00
|
|
|
|
TestErrPrintf("test_info->type=%d, statbuf.type=%d\n",test_info->type,statbuf.type);
|
2000-04-12 23:44:48 +08:00
|
|
|
|
return(-1);
|
|
|
|
|
} /* end if */
|
|
|
|
|
|
|
|
|
|
return(1);
|
|
|
|
|
} /* giter_cb2() */
|
|
|
|
|
|
|
|
|
|
/****************************************************************
|
|
|
|
|
**
|
|
|
|
|
** test_iter_group_large(): Test group iteration functionality
|
|
|
|
|
** for groups with large #'s of objects
|
|
|
|
|
**
|
|
|
|
|
****************************************************************/
|
|
|
|
|
static void test_iter_group_large(void)
|
|
|
|
|
{
|
|
|
|
|
hid_t file; /* HDF5 File IDs */
|
|
|
|
|
hid_t dataset; /* Dataset ID */
|
|
|
|
|
hid_t group; /* Group ID */
|
|
|
|
|
hid_t sid; /* Dataspace ID */
|
|
|
|
|
hid_t tid; /* Datatype ID */
|
|
|
|
|
hsize_t dims[] = {SPACE1_DIM1};
|
|
|
|
|
herr_t ret; /* Generic return value */
|
|
|
|
|
char gname[20]; /* Temporary group name */
|
2002-08-10 05:55:44 +08:00
|
|
|
|
iter_info names[ITER_NGROUPS+2]; /* Names of objects in the root group */
|
2000-04-12 23:44:48 +08:00
|
|
|
|
iter_info *curr_name; /* Pointer to the current name in the root group */
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* Compound datatype */
|
|
|
|
|
typedef struct s1_t {
|
|
|
|
|
unsigned int a;
|
|
|
|
|
unsigned int b;
|
|
|
|
|
float c;
|
|
|
|
|
} s1_t;
|
|
|
|
|
|
2000-05-19 00:40:20 +08:00
|
|
|
|
memset(names, 0, sizeof names);
|
|
|
|
|
|
2000-04-12 23:44:48 +08:00
|
|
|
|
/* Output message about test being performed */
|
|
|
|
|
MESSAGE(5, ("Testing Large Group Iteration Functionality\n"));
|
|
|
|
|
|
|
|
|
|
/* Create file */
|
2001-04-01 11:25:53 +08:00
|
|
|
|
file = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
|
2000-04-12 23:44:48 +08:00
|
|
|
|
CHECK(file, FAIL, "H5Fcreate");
|
|
|
|
|
|
|
|
|
|
/* Create dataspace for datasets */
|
|
|
|
|
sid = H5Screate_simple(SPACE1_RANK, dims, NULL);
|
|
|
|
|
CHECK(sid, FAIL, "H5Screate_simple");
|
|
|
|
|
|
|
|
|
|
/* Create a bunch of groups */
|
2002-08-10 05:55:44 +08:00
|
|
|
|
for (i=0; i<ITER_NGROUPS; i++) {
|
2000-04-12 23:44:48 +08:00
|
|
|
|
sprintf(gname, "Group_%d", i);
|
|
|
|
|
|
|
|
|
|
/* Add the name to the list of objects in the root group */
|
|
|
|
|
strcpy(names[i].name,gname);
|
|
|
|
|
names[i].type=H5G_GROUP;
|
|
|
|
|
|
|
|
|
|
/* Create a group */
|
|
|
|
|
group=H5Gcreate(file,gname,0);
|
|
|
|
|
CHECK(group, FAIL, "H5Gcreate");
|
|
|
|
|
|
|
|
|
|
/* Close a group */
|
|
|
|
|
ret = H5Gclose(group);
|
|
|
|
|
CHECK(ret, FAIL, "H5Gclose");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Create a dataset */
|
|
|
|
|
dataset=H5Dcreate(file,"Dataset1",H5T_STD_U32LE,sid,H5P_DEFAULT);
|
|
|
|
|
CHECK(dataset, FAIL, "H5Dcreate");
|
|
|
|
|
|
|
|
|
|
/* Add the name to the list of objects in the root group */
|
2002-08-10 05:55:44 +08:00
|
|
|
|
strcpy(names[ITER_NGROUPS].name,"Dataset1");
|
|
|
|
|
names[ITER_NGROUPS].type=H5G_DATASET;
|
2000-04-12 23:44:48 +08:00
|
|
|
|
|
|
|
|
|
/* Close Dataset */
|
|
|
|
|
ret = H5Dclose(dataset);
|
|
|
|
|
CHECK(ret, FAIL, "H5Dclose");
|
|
|
|
|
|
|
|
|
|
/* Close Dataspace */
|
|
|
|
|
ret = H5Sclose(sid);
|
|
|
|
|
CHECK(ret, FAIL, "H5Sclose");
|
|
|
|
|
|
|
|
|
|
/* Create a datatype */
|
|
|
|
|
tid = H5Tcreate (H5T_COMPOUND, sizeof(s1_t));
|
|
|
|
|
CHECK(tid, FAIL, "H5Tcreate");
|
|
|
|
|
|
|
|
|
|
/* Insert fields */
|
|
|
|
|
ret=H5Tinsert (tid, "a", HOFFSET(s1_t,a), H5T_NATIVE_INT);
|
|
|
|
|
CHECK(ret, FAIL, "H5Tinsert");
|
|
|
|
|
|
|
|
|
|
ret=H5Tinsert (tid, "b", HOFFSET(s1_t,b), H5T_NATIVE_INT);
|
|
|
|
|
CHECK(ret, FAIL, "H5Tinsert");
|
|
|
|
|
|
|
|
|
|
ret=H5Tinsert (tid, "c", HOFFSET(s1_t,c), H5T_NATIVE_FLOAT);
|
|
|
|
|
CHECK(ret, FAIL, "H5Tinsert");
|
|
|
|
|
|
|
|
|
|
/* Save datatype for later */
|
|
|
|
|
ret=H5Tcommit (file, "Datatype1", tid);
|
|
|
|
|
CHECK(ret, FAIL, "H5Tcommit");
|
|
|
|
|
|
|
|
|
|
/* Add the name to the list of objects in the root group */
|
2002-08-10 05:55:44 +08:00
|
|
|
|
strcpy(names[ITER_NGROUPS+1].name,"Datatype1");
|
|
|
|
|
names[ITER_NGROUPS+1].type=H5G_TYPE;
|
2000-04-12 23:44:48 +08:00
|
|
|
|
|
|
|
|
|
/* Close datatype */
|
|
|
|
|
ret = H5Tclose(tid);
|
|
|
|
|
CHECK(ret, FAIL, "H5Tclose");
|
|
|
|
|
|
|
|
|
|
/* Need to sort the names in the root group, cause that's what the library does */
|
2002-08-10 05:55:44 +08:00
|
|
|
|
qsort(names,ITER_NGROUPS+2,sizeof(iter_info),iter_strcmp2);
|
2000-04-12 23:44:48 +08:00
|
|
|
|
|
|
|
|
|
/* Iterate through the file to see members of the root group */
|
|
|
|
|
curr_name=&names[0];
|
|
|
|
|
H5Giterate(file, "/", NULL, giter_cb2, curr_name);
|
|
|
|
|
for (i=1; i<100; ) {
|
|
|
|
|
curr_name=&names[i];
|
|
|
|
|
H5Giterate(file, "/", &i, giter_cb2, curr_name);
|
|
|
|
|
} /* end for */
|
|
|
|
|
|
|
|
|
|
/* Close file */
|
|
|
|
|
ret = H5Fclose(file);
|
|
|
|
|
CHECK(ret, FAIL, "H5Fclose");
|
|
|
|
|
} /* test_iterate_group_large() */
|
|
|
|
|
|
2002-11-26 01:59:14 +08:00
|
|
|
|
/****************************************************************
|
|
|
|
|
**
|
|
|
|
|
** test_grp_memb_funcs(): Test group member information
|
|
|
|
|
** functionality
|
|
|
|
|
**
|
|
|
|
|
****************************************************************/
|
|
|
|
|
static void test_grp_memb_funcs(void)
|
|
|
|
|
{
|
|
|
|
|
hid_t file; /* File ID */
|
|
|
|
|
hid_t dataset; /* Dataset ID */
|
|
|
|
|
hid_t datatype; /* Common datatype ID */
|
|
|
|
|
hid_t filespace; /* Common dataspace ID */
|
|
|
|
|
hid_t root_group,grp; /* Root group ID */
|
|
|
|
|
int i; /* counting variable */
|
|
|
|
|
char name[NAMELEN]; /* temporary name buffer */
|
|
|
|
|
char *dnames[NDATASETS+2];/* Names of the datasets created */
|
|
|
|
|
char *obj_names[NDATASETS+2];/* Names of the objects in group */
|
2003-08-27 02:35:37 +08:00
|
|
|
|
char dataset_name[NAMELEN]; /* dataset name */
|
|
|
|
|
ssize_t name_len; /* Length of object's name */
|
2002-11-26 01:59:14 +08:00
|
|
|
|
hsize_t num_membs; /* Number of group members */
|
|
|
|
|
herr_t ret; /* Generic return value */
|
|
|
|
|
|
|
|
|
|
/* Output message about test being performed */
|
|
|
|
|
MESSAGE(5, ("Testing Group Member Information Functionality\n"));
|
|
|
|
|
|
|
|
|
|
/* Create the test file with the datasets */
|
|
|
|
|
file = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
|
|
|
|
|
CHECK(file, FAIL, "H5Fcreate");
|
|
|
|
|
|
|
|
|
|
datatype = H5Tcopy(H5T_NATIVE_INT);
|
|
|
|
|
CHECK(datatype, FAIL, "H5Tcopy");
|
|
|
|
|
|
|
|
|
|
filespace=H5Screate(H5S_SCALAR);
|
|
|
|
|
CHECK(filespace, FAIL, "H5Screate");
|
|
|
|
|
|
|
|
|
|
for(i=0; i< NDATASETS; i++) {
|
|
|
|
|
sprintf(name,"Dataset %d",i);
|
|
|
|
|
dataset = H5Dcreate(file, name, datatype, filespace, H5P_DEFAULT);
|
|
|
|
|
CHECK(dataset, FAIL, "H5Dcreate");
|
|
|
|
|
|
|
|
|
|
/* Keep a copy of the dataset names around for later */
|
|
|
|
|
dnames[i]=HDstrdup(name);
|
|
|
|
|
CHECK(dnames[i], NULL, "strdup");
|
|
|
|
|
|
|
|
|
|
ret=H5Dclose(dataset);
|
|
|
|
|
CHECK(ret, FAIL, "H5Dclose");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Create a group and named datatype under root group for testing
|
|
|
|
|
* H5Gget_objtype_by_idx.
|
|
|
|
|
*/
|
|
|
|
|
grp = H5Gcreate(file, "grp", 0);
|
|
|
|
|
CHECK(ret, FAIL, "H5Gcreate");
|
|
|
|
|
|
|
|
|
|
dnames[NDATASETS]=HDstrdup("grp");
|
|
|
|
|
CHECK(dnames[NDATASETS], NULL, "strdup");
|
|
|
|
|
|
|
|
|
|
ret = H5Tcommit(file, "dtype", datatype);
|
|
|
|
|
CHECK(ret, FAIL, "H5Tcommit");
|
|
|
|
|
|
|
|
|
|
dnames[NDATASETS+1]=HDstrdup("dtype");
|
|
|
|
|
CHECK(dnames[NDATASETS], NULL, "strdup");
|
|
|
|
|
|
|
|
|
|
/* Close everything up */
|
|
|
|
|
ret=H5Tclose(datatype);
|
|
|
|
|
CHECK(ret, FAIL, "H5Tclose");
|
|
|
|
|
|
|
|
|
|
ret=H5Gclose(grp);
|
|
|
|
|
CHECK(ret, FAIL, "H5Gclose");
|
|
|
|
|
|
|
|
|
|
ret=H5Sclose(filespace);
|
|
|
|
|
CHECK(ret, FAIL, "H5Sclose");
|
|
|
|
|
|
|
|
|
|
ret=H5Fclose(file);
|
|
|
|
|
CHECK(ret, FAIL, "H5Fclose");
|
|
|
|
|
|
|
|
|
|
/* Sort the dataset names */
|
2004-07-17 04:48:40 +08:00
|
|
|
|
HDqsort(dnames,NDATASETS+2,sizeof(char *),iter_strcmp);
|
2002-11-26 01:59:14 +08:00
|
|
|
|
|
|
|
|
|
/* Iterate through the datasets in the root group in various ways */
|
|
|
|
|
file=H5Fopen(DATAFILE, H5F_ACC_RDONLY, H5P_DEFAULT);
|
|
|
|
|
CHECK(file, FAIL, "H5Fopen");
|
|
|
|
|
|
2004-06-23 05:08:56 +08:00
|
|
|
|
/* These two functions, H5Gget_num_objs and H5Gget_objname_by_idx, actually
|
2002-11-26 01:59:14 +08:00
|
|
|
|
* iterate through B-tree for group members in internal library design.
|
|
|
|
|
*/
|
|
|
|
|
root_group = H5Gopen(file, "/");
|
|
|
|
|
CHECK(root_group, FAIL, "H5Gopen");
|
|
|
|
|
|
|
|
|
|
ret = H5Gget_num_objs(root_group, &num_membs);
|
|
|
|
|
CHECK(ret, FAIL, "H5Gget_num_objs");
|
|
|
|
|
VERIFY(num_membs,NDATASETS+2,"H5Gget_num_objs");
|
|
|
|
|
|
2002-12-02 21:15:36 +08:00
|
|
|
|
for(i=0; i< (int)num_membs; i++) {
|
2003-07-08 03:02:46 +08:00
|
|
|
|
H5G_obj_t obj_type; /* Type of object in file */
|
|
|
|
|
|
2003-08-27 02:35:37 +08:00
|
|
|
|
/* Test with NULL for name, to query length */
|
|
|
|
|
name_len = H5Gget_objname_by_idx(root_group, (hsize_t)i, NULL, NAMELEN);
|
|
|
|
|
CHECK(name_len, FAIL, "H5Gget_objname_by_idx");
|
|
|
|
|
|
2004-07-17 04:48:40 +08:00
|
|
|
|
ret = (herr_t)H5Gget_objname_by_idx(root_group, (hsize_t)i, dataset_name, (size_t)(name_len+1));
|
2003-08-27 02:35:37 +08:00
|
|
|
|
CHECK(ret, FAIL, "H5Gget_objname_by_idx");
|
|
|
|
|
|
|
|
|
|
/* Double-check that the length is the same */
|
|
|
|
|
VERIFY(ret, name_len, "H5Gget_objname_by_idx");
|
2002-11-26 01:59:14 +08:00
|
|
|
|
|
|
|
|
|
/* Keep a copy of the dataset names around for later */
|
|
|
|
|
obj_names[i]=HDstrdup(dataset_name);
|
2003-08-27 02:35:37 +08:00
|
|
|
|
CHECK(obj_names[i], NULL, "strdup");
|
2002-11-26 01:59:14 +08:00
|
|
|
|
|
2003-07-08 03:02:46 +08:00
|
|
|
|
obj_type = H5Gget_objtype_by_idx(root_group, (hsize_t)i);
|
2003-08-27 02:35:37 +08:00
|
|
|
|
CHECK(obj_type, H5G_UNKNOWN, "H5Gget_objtype_by_idx");
|
2002-11-26 01:59:14 +08:00
|
|
|
|
|
|
|
|
|
if(!HDstrcmp(dataset_name, "grp"))
|
2003-08-27 02:35:37 +08:00
|
|
|
|
VERIFY(obj_type, H5G_GROUP, "H5Gget_objname_by_idx");
|
2002-11-26 01:59:14 +08:00
|
|
|
|
if(!HDstrcmp(dataset_name, "dtype"))
|
2003-08-27 02:35:37 +08:00
|
|
|
|
VERIFY(obj_type, H5G_TYPE, "H5Gget_objname_by_idx");
|
2002-11-26 01:59:14 +08:00
|
|
|
|
if(!HDstrncmp(dataset_name, "Dataset", 7))
|
2003-08-27 02:35:37 +08:00
|
|
|
|
VERIFY(obj_type, H5G_DATASET, "H5Gget_objname_by_idx");
|
2002-11-26 01:59:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
H5E_BEGIN_TRY {
|
2003-08-27 02:35:37 +08:00
|
|
|
|
ret = (herr_t)H5Gget_objname_by_idx(root_group, (hsize_t)(NDATASETS+3), dataset_name, NAMELEN);
|
2002-11-26 01:59:14 +08:00
|
|
|
|
} H5E_END_TRY;
|
2003-08-27 02:35:37 +08:00
|
|
|
|
VERIFY(ret, FAIL, "H5Gget_objname_by_idx");
|
2002-11-26 01:59:14 +08:00
|
|
|
|
|
|
|
|
|
/* Sort the dataset names */
|
|
|
|
|
qsort(obj_names,NDATASETS+2,sizeof(char *),iter_strcmp);
|
|
|
|
|
|
|
|
|
|
/* Compare object names */
|
2002-12-02 21:15:36 +08:00
|
|
|
|
for(i=0; i< (int)num_membs; i++) {
|
2002-11-26 01:59:14 +08:00
|
|
|
|
ret = HDstrcmp(dnames[i], obj_names[i]);
|
|
|
|
|
VERIFY(ret, 0, "HDstrcmp");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = H5Gclose(root_group);
|
|
|
|
|
CHECK(ret, FAIL, "H5Gclose");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ret=H5Fclose(file);
|
|
|
|
|
CHECK(ret, FAIL, "H5Fclose");
|
|
|
|
|
|
|
|
|
|
/* Free the dataset names */
|
[svn-r6252] Purpose:
Lots of performance improvements & a couple new internal API interfaces.
Description:
Performance Improvements:
- Cached file offset & length sizes in shared file struct, to avoid
constantly looking them up in the FCPL.
- Generic property improvements:
- Added "revision" number to generic property classes to speed
up comparisons.
- Changed method of storing properties from using a hash-table
to the TBBT routines in the library.
- Share the propery names between classes and the lists derived
from them.
- Removed redundant 'def_value' buffer from each property.
- Switching code to use a "copy on write" strategy for
properties in each list, where the properties in each list
are shared with the properties in the class, until a
property's value is changed in a list.
- Fixed error in layout code which was allocating too many buffers.
- Redefined public macros of the form (H5open()/H5check, <variable>)
internally to only be (<variable>), avoiding innumerable useless
calls to H5open() and H5check_version().
- Reuse already zeroed buffers in H5F_contig_fill instead of
constantly re-zeroing them.
- Don't write fill values if writing entire dataset.
- Use gettimeofday() system call instead of time() system when
checking the modification time of a dataset.
- Added reference counted string API and use it for tracking the
names of objects opening in a file (for the ID->name code).
- Removed redundant H5P_get() calls in B-tree routines.
- Redefine H5T datatype macros internally to the library, to avoid
calling H5check redundantly.
- Keep dataspace information for dataset locally instead of reading
from disk each time. Added new module to track open objects
in a file, to allow this (which will be useful eventually for
some FPH5 metadata caching issues).
- Remove H5AC_find macro which was inlining metadata cache lookups,
and call function instead.
- Remove redundant memset() calls from H5G_namei() routine.
- Remove redundant checking of object type when locating objects
in metadata cache and rely on the address only.
- Create default dataset object to use when default dataset creation
property list is used to create datasets, bypassing querying
for all the property list values.
- Use default I/O vector size when performing raw data with the
default dataset transfer property list, instead of querying for
I/O vector size.
- Remove H5P_DEFAULT internally to the library, replacing it with
more specific default property list based on the type of
property list needed.
- Remove redundant memset() calls in object header message (H5O*)
routines.
- Remove redunant memset() calls in data I/O routines.
- Split free-list allocation routines into malloc() and calloc()-
like routines, instead of one combined routine.
- Remove lots of indirection in H5O*() routines.
- Simplify metadata cache entry comparison routine (used when
flushing entire cache out).
- Only enable metadata cache statistics when H5AC_DEBUG is turned
on, instead of always tracking them.
- Simplify address comparison macro (H5F_addr_eq).
- Remove redundant metadata cache entry protections during dataset
creation by protecting the object header once and making all
the modifications necessary for the dataset creation before
unprotecting it.
- Reduce # of "number of element in extent" computations performed
by computing and storing the value during dataspace creation.
- Simplify checking for group location's file information, when file
has not been involving in file-mounting operations.
- Use binary encoding for modification time, instead of ASCII.
- Hoist H5HL_peek calls (to get information in a local heap)
out of loops in many group routine.
- Use static variable for iterators of selections, instead of
dynamically allocation them each time.
- Lookup & insert new entries in one step, avoiding traversing
group's B-tree twice.
- Fixed memory leak in H5Gget_objname_idx() routine (tangential to
performance improvements, but fixed along the way).
- Use free-list for reference counted strings.
- Don't bother copying object names into cached group entries,
since they are re-created when an object is opened.
The benchmark I used to measure these results created several thousand
small (2K) datasets in a file and wrote out the data for them. This is
Elena's "regular.c" benchmark.
These changes resulted in approximately ~4.3x speedup of the
development branch when compared to the previous code in the
development branch and ~1.4x speedup compared to the release
branch.
Additionally, these changes reduce the total memory used (code and
data) by the development branch by ~800KB, bringing the development
branch back into the same ballpark as the release branch.
I'll send out a more detailed description of the benchmark results
as a followup note.
New internal API routines:
Added "reference counted strings" API for tracking strings that get
used by multiple owners without duplicating the strings.
Added "ternary search tree" API for text->object mappings.
Platforms tested:
Tested h5committest {arabica (fortran), eirene (fortran, C++)
modi4 (parallel, fortran)}
Other platforms/configurations tested?
FreeBSD 4.7 (sleipnir) serial & parallel
Solaris 2.6 (baldric) serial
2003-01-10 01:20:03 +08:00
|
|
|
|
for(i=0; i< NDATASETS+2; i++) {
|
2002-11-26 01:59:14 +08:00
|
|
|
|
free(dnames[i]);
|
[svn-r6252] Purpose:
Lots of performance improvements & a couple new internal API interfaces.
Description:
Performance Improvements:
- Cached file offset & length sizes in shared file struct, to avoid
constantly looking them up in the FCPL.
- Generic property improvements:
- Added "revision" number to generic property classes to speed
up comparisons.
- Changed method of storing properties from using a hash-table
to the TBBT routines in the library.
- Share the propery names between classes and the lists derived
from them.
- Removed redundant 'def_value' buffer from each property.
- Switching code to use a "copy on write" strategy for
properties in each list, where the properties in each list
are shared with the properties in the class, until a
property's value is changed in a list.
- Fixed error in layout code which was allocating too many buffers.
- Redefined public macros of the form (H5open()/H5check, <variable>)
internally to only be (<variable>), avoiding innumerable useless
calls to H5open() and H5check_version().
- Reuse already zeroed buffers in H5F_contig_fill instead of
constantly re-zeroing them.
- Don't write fill values if writing entire dataset.
- Use gettimeofday() system call instead of time() system when
checking the modification time of a dataset.
- Added reference counted string API and use it for tracking the
names of objects opening in a file (for the ID->name code).
- Removed redundant H5P_get() calls in B-tree routines.
- Redefine H5T datatype macros internally to the library, to avoid
calling H5check redundantly.
- Keep dataspace information for dataset locally instead of reading
from disk each time. Added new module to track open objects
in a file, to allow this (which will be useful eventually for
some FPH5 metadata caching issues).
- Remove H5AC_find macro which was inlining metadata cache lookups,
and call function instead.
- Remove redundant memset() calls from H5G_namei() routine.
- Remove redundant checking of object type when locating objects
in metadata cache and rely on the address only.
- Create default dataset object to use when default dataset creation
property list is used to create datasets, bypassing querying
for all the property list values.
- Use default I/O vector size when performing raw data with the
default dataset transfer property list, instead of querying for
I/O vector size.
- Remove H5P_DEFAULT internally to the library, replacing it with
more specific default property list based on the type of
property list needed.
- Remove redundant memset() calls in object header message (H5O*)
routines.
- Remove redunant memset() calls in data I/O routines.
- Split free-list allocation routines into malloc() and calloc()-
like routines, instead of one combined routine.
- Remove lots of indirection in H5O*() routines.
- Simplify metadata cache entry comparison routine (used when
flushing entire cache out).
- Only enable metadata cache statistics when H5AC_DEBUG is turned
on, instead of always tracking them.
- Simplify address comparison macro (H5F_addr_eq).
- Remove redundant metadata cache entry protections during dataset
creation by protecting the object header once and making all
the modifications necessary for the dataset creation before
unprotecting it.
- Reduce # of "number of element in extent" computations performed
by computing and storing the value during dataspace creation.
- Simplify checking for group location's file information, when file
has not been involving in file-mounting operations.
- Use binary encoding for modification time, instead of ASCII.
- Hoist H5HL_peek calls (to get information in a local heap)
out of loops in many group routine.
- Use static variable for iterators of selections, instead of
dynamically allocation them each time.
- Lookup & insert new entries in one step, avoiding traversing
group's B-tree twice.
- Fixed memory leak in H5Gget_objname_idx() routine (tangential to
performance improvements, but fixed along the way).
- Use free-list for reference counted strings.
- Don't bother copying object names into cached group entries,
since they are re-created when an object is opened.
The benchmark I used to measure these results created several thousand
small (2K) datasets in a file and wrote out the data for them. This is
Elena's "regular.c" benchmark.
These changes resulted in approximately ~4.3x speedup of the
development branch when compared to the previous code in the
development branch and ~1.4x speedup compared to the release
branch.
Additionally, these changes reduce the total memory used (code and
data) by the development branch by ~800KB, bringing the development
branch back into the same ballpark as the release branch.
I'll send out a more detailed description of the benchmark results
as a followup note.
New internal API routines:
Added "reference counted strings" API for tracking strings that get
used by multiple owners without duplicating the strings.
Added "ternary search tree" API for text->object mappings.
Platforms tested:
Tested h5committest {arabica (fortran), eirene (fortran, C++)
modi4 (parallel, fortran)}
Other platforms/configurations tested?
FreeBSD 4.7 (sleipnir) serial & parallel
Solaris 2.6 (baldric) serial
2003-01-10 01:20:03 +08:00
|
|
|
|
free(obj_names[i]);
|
|
|
|
|
}
|
2002-11-26 01:59:14 +08:00
|
|
|
|
|
|
|
|
|
} /* test_grp_memb_funcs() */
|
|
|
|
|
|
2004-06-23 05:08:56 +08:00
|
|
|
|
/****************************************************************
|
|
|
|
|
**
|
|
|
|
|
** test_links(): Test soft and hard link iteration
|
|
|
|
|
**
|
|
|
|
|
****************************************************************/
|
|
|
|
|
static void test_links(void)
|
|
|
|
|
{
|
|
|
|
|
hid_t file; /* File ID */
|
|
|
|
|
char obj_name[NAMELEN]; /* Names of the object in group */
|
|
|
|
|
ssize_t name_len; /* Length of object's name */
|
|
|
|
|
herr_t ret; /* Generic return value */
|
|
|
|
|
hid_t gid, gid1;
|
2004-07-17 04:48:40 +08:00
|
|
|
|
hsize_t i;
|
2004-06-23 05:08:56 +08:00
|
|
|
|
H5G_obj_t obj_type; /* Type of object */
|
|
|
|
|
hsize_t nobjs; /* Number of objects */
|
|
|
|
|
|
|
|
|
|
/* Output message about test being performed */
|
|
|
|
|
MESSAGE(5, ("Testing Soft and Hard Link Iteration Functionality\n"));
|
|
|
|
|
|
|
|
|
|
/* Create the test file with the datasets */
|
|
|
|
|
file = H5Fcreate(DATAFILE, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
|
|
|
|
|
CHECK(file, FAIL, "H5Fcreate");
|
|
|
|
|
|
|
|
|
|
/* create groups */
|
|
|
|
|
gid = H5Gcreate (file, "/g1", 0);
|
|
|
|
|
CHECK(gid, FAIL, "H5Gcreate");
|
|
|
|
|
|
|
|
|
|
gid1 = H5Gcreate (file, "/g1/g1.1", 0);
|
|
|
|
|
CHECK(gid1, FAIL, "H5Gcreate");
|
|
|
|
|
|
|
|
|
|
/* create soft and hard links to the group "/g1". */
|
|
|
|
|
ret = H5Glink (gid, H5G_LINK_SOFT, "something", "softlink");
|
|
|
|
|
CHECK(ret, FAIL, "H5Glink");
|
|
|
|
|
|
|
|
|
|
ret = H5Glink (gid, H5G_LINK_HARD, "/g1", "hardlink");
|
|
|
|
|
CHECK(ret, FAIL, "H5Glink");
|
|
|
|
|
|
|
|
|
|
ret = H5Gget_num_objs(gid, &nobjs);
|
|
|
|
|
CHECK(ret, FAIL, "H5Gget_num_objs");
|
|
|
|
|
VERIFY(nobjs,3,"H5Gget_num_objs");
|
|
|
|
|
|
|
|
|
|
/* Test these two functions, H5Gget_num_objs and H5Gget_objname_by_idx */
|
|
|
|
|
for(i=0; i<nobjs; i++) {
|
|
|
|
|
/* Get object name */
|
2004-07-17 04:48:40 +08:00
|
|
|
|
name_len = H5Gget_objname_by_idx(gid, i, obj_name, NAMELEN);
|
2004-06-23 05:08:56 +08:00
|
|
|
|
CHECK(name_len, FAIL, "H5Gget_objname_by_idx");
|
|
|
|
|
|
2004-07-17 04:48:40 +08:00
|
|
|
|
obj_type = H5Gget_objtype_by_idx(gid, i);
|
2004-06-23 05:08:56 +08:00
|
|
|
|
CHECK(obj_type, H5G_UNKNOWN, "H5Gget_objtype_by_idx");
|
|
|
|
|
|
|
|
|
|
if(!HDstrcmp(obj_name, "g1.1"))
|
|
|
|
|
VERIFY(obj_type, H5G_GROUP, "H5Gget_objname_by_idx");
|
|
|
|
|
else if(!HDstrcmp(obj_name, "hardlink"))
|
|
|
|
|
VERIFY(obj_type, H5G_GROUP, "H5Gget_objname_by_idx");
|
|
|
|
|
else if(!HDstrcmp(obj_name, "softlink"))
|
|
|
|
|
VERIFY(obj_type, H5G_LINK, "H5Gget_objname_by_idx");
|
|
|
|
|
else
|
|
|
|
|
CHECK(0, 0, "unknown object name");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret=H5Gclose(gid);
|
|
|
|
|
CHECK(ret, FAIL, "H5Gclose");
|
|
|
|
|
|
|
|
|
|
ret=H5Gclose(gid1);
|
|
|
|
|
CHECK(ret, FAIL, "H5Gclose");
|
|
|
|
|
|
|
|
|
|
ret=H5Fclose(file);
|
|
|
|
|
CHECK(ret, FAIL, "H5Fclose");
|
|
|
|
|
} /* test_links() */
|
2004-07-17 04:48:40 +08:00
|
|
|
|
|
2000-04-06 04:51:44 +08:00
|
|
|
|
/****************************************************************
|
|
|
|
|
**
|
|
|
|
|
** test_iterate(): Main iteration testing routine.
|
|
|
|
|
**
|
|
|
|
|
****************************************************************/
|
|
|
|
|
void
|
|
|
|
|
test_iterate(void)
|
|
|
|
|
{
|
|
|
|
|
/* Output message about test being performed */
|
|
|
|
|
MESSAGE(5, ("Testing Iteration Operations\n"));
|
|
|
|
|
|
|
|
|
|
/* These next tests use the same file */
|
|
|
|
|
test_iter_group(); /* Test group iteration */
|
2000-04-12 23:44:48 +08:00
|
|
|
|
test_iter_group_large(); /* Test group iteration for large # of objects */
|
2000-04-06 04:51:44 +08:00
|
|
|
|
test_iter_attr(); /* Test attribute iteration */
|
2002-11-26 01:59:14 +08:00
|
|
|
|
test_grp_memb_funcs(); /* Test group member information functions */
|
2004-06-23 05:08:56 +08:00
|
|
|
|
test_links(); /* Test soft and hard link iteration */
|
2000-04-06 04:51:44 +08:00
|
|
|
|
} /* test_iterate() */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
|
* Function: cleanup_iterate
|
|
|
|
|
*
|
|
|
|
|
* Purpose: Cleanup temporary test files
|
|
|
|
|
*
|
|
|
|
|
* Return: none
|
|
|
|
|
*
|
|
|
|
|
* Programmer: Quincey Koziol
|
|
|
|
|
* April 5, 2000
|
|
|
|
|
*
|
|
|
|
|
* Modifications:
|
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
cleanup_iterate(void)
|
|
|
|
|
{
|
2001-04-01 11:25:53 +08:00
|
|
|
|
remove(DATAFILE);
|
2000-04-06 04:51:44 +08:00
|
|
|
|
}
|
|
|
|
|
|