text: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
   * Copyright by The HDF Group.                                               *
   * 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 COPYING file, which can be found at the root of the source code       *
   * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases.  *
   * If you do not have access to either file, you may request a copy from     *
   * help@hdfgroup.org.                                                        *
   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  /*****************************************************************************
    This test generates attributes, groups, and datasets of many types. It
    creates a large number of attributes, groups, and datasets by specifying
    -a, -g, -d options respectively. Using "-h" option to see details.
  
    Programmer:  Peter Cao, Jan. 2013
   ****************************************************************************/
  
  #include "hdf5.h"
  #include <stdio.h>
  #include <stdlib.h>
  
  #define FNAME     "test_perf.h5"
  #define NGROUPS   20
  #define NDSETS    20
  #define NATTRS    20
  #define DIM0      40
  #define NROWS     100
  #define NTYPES    9
  #define MAXVLEN   10
  #define FIXED_LEN 8
  
  typedef enum { SOLID = 0, LIQUID, GAS, PLASMA } phase_t;
  
  typedef struct {
      int                i;
      unsigned long long l;
      float              f;
      double             d;
      char               s[FIXED_LEN];
      phase_t            e;
      float              f_array[FIXED_LEN];
      hvl_t              i_vlen;
      char *             s_vlen;
  } test_comp_t;
  
  typedef struct {
      int   zipcode;
      char *city;
  } zipcode_t;
  
  int    add_attrs(hid_t oid, int idx);
  int    add_attr(hid_t oid, const char *name, hid_t tid, hid_t sid, void *buf);
  herr_t create_perf_test_file(const char *fname, int ngrps, int ndsets, int nattrs, hsize_t nrows,
                               hsize_t dim0, hsize_t chunk, int vlen, int compressed, int latest);
  
  int
  main(int argc, char *argv[])
  {
      char fname[32];
      int  i, ngrps = NGROUPS, ndsets = NDSETS, nattrs = NATTRS, dim0 = DIM0, chunk = DIM0 / 10 + 1,
             nrows = NROWS, vlen = MAXVLEN, l = 0, z = 0;
  
      memset(fname, 0, 32);
      for (i = 1; i < argc; i++) {
          if (strcmp(argv[i], "-f") == 0)
              strcpy(fname, argv[i + 1]);
          else if (strcmp(argv[i], "-g") == 0)
              ngrps = atoi(argv[i + 1]);
          else if (strcmp(argv[i], "-d") == 0)
              ndsets = atoi(argv[i + 1]);
          else if (strcmp(argv[i], "-a") == 0)
              nattrs = atoi(argv[i + 1]);
          else if (strcmp(argv[i], "-r") == 0)
              nrows = atoi(argv[i + 1]);
          else if (strcmp(argv[i], "-s") == 0)
              dim0 = atoi(argv[i + 1]);
          else if (strcmp(argv[i], "-c") == 0)
              chunk = atoi(argv[i + 1]);
          else if (strcmp(argv[i], "-v") == 0)
              vlen = atoi(argv[i + 1]);
          else if (strcmp(argv[i], "-l") == 0)
              l = 1;
          else if (strcmp(argv[i], "-z") == 0)
              z = 1;
          else if (strcmp(argv[i], "-h") == 0) {
              HDprintf("\nOPTONS:\n");
              HDprintf("\t-f F:\tname of the test file (default: %s).\n", FNAME);
              HDprintf("\t-g N:\tnumber of top level groups (default: %d).\n", NGROUPS);
              HDprintf("\t-d N:\tnumber of datasets (default: %d).\n", NDSETS);
              HDprintf("\t-a N:\tnumber of attributes (default: %d).\n", NATTRS);
              HDprintf("\t-r N:\tnumber of rows in the large compound dataset (default: %d).\n", NROWS);
              HDprintf("\t-s N:\tsize of dim0 in datasets (default: %d).\n", DIM0);
              HDprintf("\t-c N:\tchunk size of dim0 (default: %d).\n", (DIM0 / 10 + 1));
              HDprintf("\t-v N:\tmax vlen size (default: %d).\n", MAXVLEN);
              HDprintf("\t-l:\tuse latest format (default: no).\n");
              HDprintf("\t-z:\tuse gzip compression (default: no).\n");
              HDprintf("\t-h:\tthis help information.\n");
              HDprintf("Example:\n");
              HDprintf("\t./a.out -f test.h5 -g 10000 -d 5000 -a 500 -r 10000 -s 200 -c 20 -v 40 -l -z\n\n");
              exit(0);
          }
      }
  
      if (strlen(fname) <= 0)
          HDsprintf(fname, FNAME);
  
      create_perf_test_file(fname, ngrps, ndsets, nattrs, (hsize_t)nrows, (hsize_t)dim0, (hsize_t)chunk, vlen,
                            z, l);
  
      return 0;
  }
  
  /*****************************************************************************
    This function generates attributes, groups, and datasets of many types.
  
    Parameters:
              fname:    file_name.
              ngrps:    number of top level groups.
              ndsets:    number of datasets.
              attrs:    number of attributes.
              nrow:    number of rows in a dataset.
              chunk:    chunk size (single number).
              vlen:    max vlen size.
              comp:    use latest format.
              latest:    use gzip comnpression.
  
    Return:  Non-negative on success/Negative on failure
  
    Programmer:  Peter Cao, Jan. 2013
   ****************************************************************************/
  herr_t
  create_perf_test_file(const char *fname, int ngrps, int ndsets, int nattrs, hsize_t nrows, hsize_t dim0,
                        hsize_t chunk, int vlen, int compressed, int latest)
  {
      int   i, j, k;
      hid_t fid, sid_null, sid_scalar, sid_1d, sid_2d, did, aid, sid_2, sid_large,
          fapl = H5P_DEFAULT, dcpl = H5P_DEFAULT, gid1, gid2, cmp_tid, tid_str, tid_enum, tid_array_f,
          tid_vlen_i, tid_vlen_s;
      char    name[32], tmp_name1[32], tmp_name2[32], tmp_name3[32];
      hsize_t dims[1] = {dim0}, dims2d[2] = {dim0, (dim0 / 4 + 1)}, dims_array[1] = {FIXED_LEN}, dim1[1] = {2};
      char *  enum_names[4] = {"SOLID", "LIQUID", "GAS", "PLASMA"};
      test_comp_t *buf_comp = NULL, *buf_comp_large = NULL;
      int *        buf_int           = NULL;
      float(*buf_float_a)[FIXED_LEN] = NULL;
      double **buf_double2d          = NULL;
      hvl_t *  buf_vlen_i            = NULL;
      char(*buf_str)[FIXED_LEN];
      char **         buf_vlen_s = NULL;
      hobj_ref_t      buf_ref[2];
      hdset_reg_ref_t buf_reg_ref[2];
      size_t          offset, len;
      herr_t          status;
      char *          names[NTYPES] = {"int",
                             "ulong",
                             "float",
                             "double",
                             "fixed string",
                             "enum",
                             "fixed float array",
                             "vlen int array",
                             "vlen strings"};
      hid_t   types[NTYPES] = {H5T_NATIVE_INT, H5T_NATIVE_UINT64, H5T_NATIVE_FLOAT, H5T_NATIVE_DOUBLE, tid_str,
                             tid_enum,       tid_array_f,       tid_vlen_i,       tid_vlen_s};
      hsize_t coords[4][2] = {{0, 1}, {3, 5}, {1, 0}, {2, 4}}, start = 0, stride = 1, count = 1;
  
      if (nrows < NROWS)
          nrows = NROWS;
      if (ngrps < NGROUPS)
          ngrps = NGROUPS;
      if (ndsets < NDSETS)
          ndsets = NDSETS;
      if (nattrs < NATTRS)
          nattrs = NATTRS;
      if (dim0 < DIM0)
          dim0 = DIM0;
      if (chunk > dim0)
          chunk = dim0 / 4;
      if (chunk < 1)
          chunk = 1;
      if (vlen < 1)
          vlen = MAXVLEN;
  
      /* create fixed string datatype */
      types[4] = tid_str = H5Tcopy(H5T_C_S1);
      H5Tset_size(tid_str, FIXED_LEN);
  
      /* create enum datatype */
      types[5] = tid_enum = H5Tenum_create(H5T_NATIVE_INT);
      for (i = (int)SOLID; i <= (int)PLASMA; i++) {
          phase_t val = (phase_t)i;
          status      = H5Tenum_insert(tid_enum, enum_names[i], &val);
      }
  
      /* create float array datatype */
      types[6] = tid_array_f = H5Tarray_create(H5T_NATIVE_FLOAT, 1, dims_array);
  
      /* create variable length integer datatypes */
      types[7] = tid_vlen_i = H5Tvlen_create(H5T_NATIVE_INT);
  
      /* create variable length string datatype */
      types[8] = tid_vlen_s = H5Tcopy(H5T_C_S1);
      H5Tset_size(tid_vlen_s, H5T_VARIABLE);
  
      /* create compound datatypes */
      cmp_tid = H5Tcreate(H5T_COMPOUND, sizeof(test_comp_t));
      offset  = 0;
      for (i = 0; i < NTYPES - 2; i++) {
          H5Tinsert(cmp_tid, names[i], offset, types[i]);
          offset += H5Tget_size(types[i]);
      }
  
      H5Tinsert(cmp_tid, names[7], offset, types[7]);
      offset += sizeof(hvl_t);
      H5Tinsert(cmp_tid, names[8], offset, types[8]);
  
      /* create dataspace */
      sid_1d     = H5Screate_simple(1, dims, NULL);
      sid_2d     = H5Screate_simple(2, dims2d, NULL);
      sid_2      = H5Screate_simple(1, dim1, NULL);
      sid_large  = H5Screate_simple(1, &nrows, NULL);
      sid_null   = H5Screate(H5S_NULL);
      sid_scalar = H5Screate(H5S_SCALAR);
  
      /* create fid access property */
      fapl = H5Pcreate(H5P_FILE_ACCESS);
      H5Pset_libver_bounds(fapl, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST);
  
      /* create dataset creation property */
      dcpl = H5Pcreate(H5P_DATASET_CREATE);
  
      /* set dataset chunk */
      if (chunk > 0) {
          H5Pset_chunk(dcpl, 1, &chunk);
      }
  
      /* set dataset compression */
      if (compressed) {
          if (chunk <= 0) {
              chunk = dim0 / 10 + 1;
              ;
              H5Pset_chunk(dcpl, 1, &chunk);
          }
          H5Pset_shuffle(dcpl);
          H5Pset_deflate(dcpl, 6);
      }
  
      /* allocate buffers */
      buf_comp       = (test_comp_t *)calloc(dim0, sizeof(test_comp_t));
      buf_comp_large = (test_comp_t *)calloc(nrows, sizeof(test_comp_t));
      buf_int        = (int *)calloc(dim0, sizeof(int));
      buf_float_a    = malloc(dim0 * sizeof(*buf_float_a));
      buf_vlen_i     = (hvl_t *)calloc(dim0, sizeof(hvl_t));
      buf_vlen_s     = (char **)calloc(dim0, sizeof(char *));
      buf_str        = malloc(dim0 * sizeof(*buf_str));
  
      /* allocate array of doulbe pointers */
      buf_double2d = (double **)calloc(dims2d[0], sizeof(double *));
      /* allocate a contigous chunk of memory for the data */
      buf_double2d[0] = (double *)calloc(dims2d[0] * dims2d[1], sizeof(double));
      /* assign memory city to pointer array */
      for (i = 1; i < dims2d[0]; i++)
          buf_double2d[i] = buf_double2d[0] + i * dims2d[1];
  
      /* fill buffer values */
      len = 1;
      for (i = 0; i < dims[0]; i++) {
          buf_comp[i].i = buf_int[i] = i - 2147483648;
          buf_comp[i].l              = 0xffffffffffffffff - i;
          buf_comp[i].f              = 1.0 / (i + 1.0);
          buf_comp[i].d              = 987654321.0 * i + 1.0 / (i + 1.0);
          buf_comp[i].e              = (phase_t)(i % (int)(PLASMA + 1));
  
          for (j = 0; j < FIXED_LEN; j++) {
              buf_comp[i].f_array[j] = buf_float_a[i][j] = i * 100 + j;
              buf_str[i][j]                              = 'a' + (i % 26);
          }
          buf_str[i][FIXED_LEN - 1] = 0;
          strcpy(buf_comp[i].s, buf_str[i]);
  
          len = (1 - cos(i / 8.0)) / 2 * vlen + 1;
          if (!i)
              len = vlen;
          buf_vlen_i[i].len = len;
          buf_vlen_i[i].p   = (int *)calloc(len, sizeof(int));
          for (j = 0; j < len; j++)
              ((int *)(buf_vlen_i[i].p))[j] = i * 100 + j;
          buf_comp[i].i_vlen = buf_vlen_i[i];
  
          buf_vlen_s[i] = (char *)calloc(len, sizeof(char));
          for (j = 0; j < len - 1; j++)
              buf_vlen_s[i][j] = j % 26 + 'A';
          buf_comp[i].s_vlen = buf_vlen_s[i];
  
          for (j = 0; j < dims2d[1]; j++)
              buf_double2d[i][j] = i + j / 10000.0;
      }
  
      for (i = 0; i < nrows; i++) {
          buf_comp_large[i].i = i - 2147483648;
          buf_comp_large[i].l = 0xffffffffffffffff - i;
          buf_comp_large[i].f = 1.0 / (i + 1.0);
          buf_comp_large[i].d = 987654321.0 * i + 1.0 / (i + 1.0);
          buf_comp_large[i].e = (phase_t)(i % (int)(PLASMA + 1));
          for (j = 0; j < FIXED_LEN - 1; j++) {
              buf_comp_large[i].f_array[j] = i * 100 + j;
              buf_comp_large[i].s[j]       = 'a' + (i % 26);
          }
          len                          = i % vlen + 1;
          buf_comp_large[i].i_vlen.len = len;
          buf_comp_large[i].i_vlen.p   = (int *)calloc(len, sizeof(int));
          for (j = 0; j < len; j++)
              ((int *)(buf_comp_large[i].i_vlen.p))[j] = i * 100 + j;
          buf_comp_large[i].s_vlen = (char *)calloc(i + 2, sizeof(char));
          for (j = 0; j < i + 1; j++)
              (buf_comp_large[i].s_vlen)[j] = j % 26 + 'A';
      }
  
      /* create file */
      if (latest)
          fid = H5Fcreate(fname, H5F_ACC_TRUNC, H5P_DEFAULT, fapl);
      else
          fid = H5Fcreate(fname, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
      add_attrs(fid, 0);
  
      HDsprintf(name, "a cmp ds of %d rows", nrows);
      did = H5Dcreate(fid, name, cmp_tid, sid_large, H5P_DEFAULT, dcpl, H5P_DEFAULT);
      H5Dwrite(did, cmp_tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_comp_large);
      add_attrs(did, 0);
      H5Dclose(did);
  
      // /* add attributes*/
      gid1 = H5Gcreate(fid, "attributes", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
      if (nattrs < 1)
          nattrs = 1;
      i = 0;
      while (i < nattrs)
          i += add_attrs(gid1, i);
      H5Gclose(gid1);
  
      /* add many sub groups to a group*/
      gid1 = H5Gcreate(fid, "groups", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
      add_attrs(gid1, 0);
      for (i = 0; i < ngrps; i++) {
          /* create sub groups */
          HDsprintf(name, "g%02d", i);
          gid2 = H5Gcreate(gid1, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
          if (i < 10)
              add_attrs(gid2, 0);
          H5Gclose(gid2);
      }
      H5Gclose(gid1);
  
      /* add many datasets to a group */
      gid1 = H5Gcreate(fid, "datasets", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
      add_attrs(gid1, 0);
      for (j = 0; j < ndsets; j += 12) {
          /* 1 add a null dataset */
          HDsprintf(name, "%05d null dataset", j);
          did = H5Dcreate(gid1, name, H5T_STD_I32LE, sid_null, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
          if (!j)
              add_attrs(did, j);
          H5Dclose(did);
  
          /* 2 add scalar int point */
          HDsprintf(name, "%05d scalar int point", j);
          did = H5Dcreate(gid1, name, H5T_NATIVE_INT, sid_scalar, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
          H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &j);
          if (!j)
              add_attrs(did, j);
          H5Dclose(did);
  
          /* 3 scalar vlen string */
          HDsprintf(name, "%05d scalar vlen string", j);
          did = H5Dcreate(gid1, name, tid_vlen_s, sid_scalar, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
          H5Dwrite(did, tid_vlen_s, H5S_ALL, H5S_ALL, H5P_DEFAULT, &buf_vlen_s[0]);
          if (!j)
              add_attrs(did, j);
          H5Dclose(did);
  
          /* 4 add fixed-length float array */
          HDsprintf(name, "%05d fixed-length float array", j);
          did = H5Dcreate(gid1, name, tid_array_f, sid_1d, H5P_DEFAULT, dcpl, H5P_DEFAULT);
          H5Dwrite(did, tid_array_f, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_float_a);
          if (!j)
              add_attrs(did, j);
          H5Dclose(did);
  
          /* 5 add fixed-length strings */
          HDsprintf(name, "%05d fixed-length strings", j);
          did = H5Dcreate(gid1, name, tid_str, sid_1d, H5P_DEFAULT, dcpl, H5P_DEFAULT);
          H5Dwrite(did, tid_str, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_str);
          if (!j)
              add_attrs(did, j);
          H5Dclose(did);
  
          /* 6 add compound data */
          HDsprintf(name, "%05d compund data", j);
          did = H5Dcreate(gid1, name, cmp_tid, sid_1d, H5P_DEFAULT, dcpl, H5P_DEFAULT);
          H5Dwrite(did, cmp_tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_comp);
          if (!j)
              add_attrs(did, j);
          H5Dclose(did);
  
          /* 7 add 2D double */
          HDsprintf(name, "%05d 2D double", j);
          strcpy(tmp_name1, name);
          did = H5Dcreate(gid1, name, H5T_NATIVE_DOUBLE, sid_2d, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
          H5Dwrite(did, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_double2d[0]);
          if (!j)
              add_attrs(did, j);
          H5Dclose(did);
  
          /* 8 add 1D int array */
          HDsprintf(name, "%05d 1D int array", j);
          did = H5Dcreate(gid1, name, H5T_NATIVE_INT, sid_1d, H5P_DEFAULT, dcpl, H5P_DEFAULT);
          H5Dwrite(did, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_int);
          if (!j)
              add_attrs(did, j);
          H5Dclose(did);
  
          /* 9 add vlen int array */
          HDsprintf(name, "%05d vlen int array", j);
          strcpy(tmp_name2, name);
          did = H5Dcreate(gid1, name, tid_vlen_i, sid_1d, H5P_DEFAULT, dcpl, H5P_DEFAULT);
          H5Dwrite(did, tid_vlen_i, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_vlen_i);
          if (!j)
              add_attrs(did, j);
          H5Dclose(did);
  
          /* 10 add vlen strings */
          HDsprintf(name, "%05d vlen strings", j);
          strcpy(tmp_name3, name);
          did = H5Dcreate(gid1, name, tid_vlen_s, sid_1d, H5P_DEFAULT, dcpl, H5P_DEFAULT);
          H5Dwrite(did, tid_vlen_s, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_vlen_s);
          if (!j)
              add_attrs(did, j);
          H5Dclose(did);
  
          /* 11 add object refs */
          H5Rcreate(&buf_ref[0], gid1, ".", H5R_OBJECT, (hid_t)-1);
          H5Rcreate(&buf_ref[1], gid1, tmp_name3, H5R_OBJECT, (hid_t)-1);
          HDsprintf(name, "%05d obj refs", j);
          did = H5Dcreate(gid1, name, H5T_STD_REF_OBJ, sid_2, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
          H5Dwrite(did, H5T_STD_REF_OBJ, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_ref);
          if (!j)
              add_attrs(did, j);
          H5Dclose(did);
  
          /* 12 add region refs */
          H5Sselect_elements(sid_2d, H5S_SELECT_SET, 4, coords[0]);
          H5Rcreate(&buf_reg_ref[0], gid1, tmp_name1, H5R_DATASET_REGION, sid_2d);
          H5Sselect_none(sid_2d);
          count = dims[0] / 2 + 1;
          H5Sselect_hyperslab(sid_1d, H5S_SELECT_SET, &start, &stride, &count, NULL);
          H5Rcreate(&buf_reg_ref[1], gid1, tmp_name2, H5R_DATASET_REGION, sid_1d);
          H5Sselect_none(sid_1d);
          HDsprintf(name, "%05d region refs", j);
          did = H5Dcreate(gid1, name, H5T_STD_REF_DSETREG, sid_2, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
          H5Dwrite(did, H5T_STD_REF_DSETREG, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf_reg_ref);
          if (!j)
              add_attrs(did, j);
          H5Dclose(did);
      }
      H5Gclose(gid1);
  
      H5Tclose(tid_array_f);
      H5Tclose(tid_vlen_i);
      H5Tclose(tid_vlen_s);
      H5Tclose(tid_enum);
      H5Tclose(tid_str);
      H5Tclose(cmp_tid);
      H5Pclose(dcpl);
      H5Pclose(fapl);
      H5Sclose(sid_1d);
      H5Sclose(sid_2d);
      H5Sclose(sid_2);
      H5Sclose(sid_large);
      H5Sclose(sid_null);
      H5Sclose(sid_scalar);
      H5Fclose(fid);
  
      for (i = 0; i < dims[0]; i++) {
          if (buf_vlen_i[i].p)
              free(buf_vlen_i[i].p);
          if (buf_vlen_s[i])
              free(buf_vlen_s[i]);
      }
  
      for (i = 0; i < nrows; i++) {
          if (buf_comp_large[i].i_vlen.p)
              free(buf_comp_large[i].i_vlen.p);
          if (buf_comp_large[i].s_vlen)
              free(buf_comp_large[i].s_vlen);
      }
  
      free(buf_comp);
      free(buf_comp_large);
      free(buf_int);
      free(buf_float_a);
      free(buf_double2d[0]);
      free(buf_double2d);
      free(buf_str);
      free(buf_vlen_i);
      free(buf_vlen_s);
  
      return 0;
  }
  
  /* add a single attribute */
  int
  add_attr(hid_t oid, const char *name, hid_t tid, hid_t sid, void *buf)
  {
      hid_t aid;
  
      aid = H5Acreate(oid, name, tid, sid, H5P_DEFAULT, H5P_DEFAULT);
      if (aid < 0)
          return 0;
  
      H5Awrite(aid, tid, buf);
  
      H5Aclose(aid);
  
      return 1;
  }
  
  /*
      adds different types of attributes to an object.
  
      returns the number of attributes added to the objects.
   */
  int
  add_attrs(hid_t oid, int idx)
  {
      char         name[32];
      int          i0, i1, i2, j, nattrs = 0;
      hid_t        aid, tid, tid1, sid;
      hvl_t        i_vlen[4];
      hobj_ref_t   ref;
      zipcode_t    cmp_data[4];
      unsigned int i          = 0xffffffff;
      long long    l          = -2147483647;
      float        f          = 123456789.987654321;
      double       d          = 987654321.123456789;
      char *       s[7]       = {"Parting", "is such", "sweeter", "sorrow."};
      float        f_array[4] = {1.0, 2.22, 3.333, 4.444};
      char *       s_vlen[4]  = {"Parting", "is such", "sweet", "sorrow."};
      hsize_t      dims1[1] = {1}, dims2[1] = {4}, dims3[2] = {3, 5};
      int          int3d[4][3][5];
      size_t       offset = 0;
  
      for (i0 = 0; i0 < 4; i0++) {
          i_vlen[i0].len = (i0 + 1);
          i_vlen[i0].p   = (int *)calloc(i_vlen[i0].len, sizeof(int));
          for (j = 0; j < i_vlen[i0].len; j++)
              ((int *)i_vlen[i0].p)[j] = i0 * 100 + j;
          for (i1 = 0; i1 < 3; i1++) {
              for (i2 = 0; i2 < 5; i2++)
                  int3d[i0][i1][i2] = i0 * i1 - i1 * i2 + i0 * i2;
          }
      }
  
      cmp_data[0].zipcode = 01001;
      cmp_data[0].city    = "Agawam, Massachusetts";
      cmp_data[1].zipcode = 99950;
      cmp_data[1].city    = "Ketchikan, Alaska";
      cmp_data[2].zipcode = 00501;
      cmp_data[2].city    = "Holtsville, New York";
      cmp_data[3].zipcode = 61820;
      cmp_data[3].city    = "Champaign, Illinois";
  
      /* 1 scalar point */
      sid = H5Screate(H5S_SCALAR);
      HDsprintf(name, "%05d scalar int", idx);
      nattrs += add_attr(oid, name, H5T_NATIVE_UINT, sid, &i);
      HDsprintf(name, "%05d scalar ulong", idx);
      nattrs += add_attr(oid, name, H5T_NATIVE_INT64, sid, &l);
      HDsprintf(name, "%05d scalar str", idx);
      tid = H5Tcopy(H5T_C_S1);
      H5Tset_size(tid, H5T_VARIABLE);
      nattrs += add_attr(oid, name, tid, sid, &s[2]);
      H5Tclose(tid);
      H5Sclose(sid);
  
      /* 4 single point */
      sid = H5Screate_simple(1, dims1, NULL);
      H5Rcreate(&ref, oid, ".", H5R_OBJECT, (hid_t)-1);
      HDsprintf(name, "%05d single float", idx);
      nattrs += add_attr(oid, name, H5T_NATIVE_FLOAT, sid, &f);
      HDsprintf(name, "%05d single double", idx);
      nattrs += add_attr(oid, name, H5T_NATIVE_DOUBLE, sid, &d);
      HDsprintf(name, "%05d single obj_ref", idx);
      nattrs += add_attr(oid, name, H5T_STD_REF_OBJ, sid, &ref);
      H5Sclose(sid);
  
      /* 7 fixed length 1D array */
      sid = H5Screate_simple(1, dims1, NULL);
      tid = H5Tarray_create(H5T_NATIVE_FLOAT, 1, dims2);
      HDsprintf(name, "%05d array float", idx);
      nattrs += add_attr(oid, name, tid, sid, &f_array[0]);
      H5Tclose(tid);
      tid = H5Tcopy(H5T_C_S1);
      H5Tset_size(tid, strlen(s[0]) + 1);
      tid1 = H5Tarray_create(tid, 1, dims2);
      HDsprintf(name, "%05d array str", idx);
      nattrs += add_attr(oid, name, tid1, sid, s);
      H5Tclose(tid1);
      H5Tclose(tid);
      H5Sclose(sid);
  
      /* 9 fixed length 2D int arrays */
      sid = H5Screate_simple(1, dims2, NULL);
      tid = H5Tarray_create(H5T_NATIVE_INT, 2, dims3);
      HDsprintf(name, "%05d array int 2D", idx);
      nattrs += add_attr(oid, name, tid, sid, int3d[0][0]);
      H5Tclose(tid);
      H5Sclose(sid);
  
      /* 10 variable length arrays */
      sid = H5Screate_simple(1, dims2, NULL);
      tid = H5Tcopy(H5T_C_S1);
      H5Tset_size(tid, H5T_VARIABLE);
      HDsprintf(name, "%05d vlen strings", idx);
      nattrs += add_attr(oid, name, tid, sid, s_vlen);
      H5Tclose(tid);
      tid = H5Tvlen_create(H5T_NATIVE_INT);
      ;
      HDsprintf(name, "%05d vlen int array", idx);
      nattrs += add_attr(oid, name, tid, sid, i_vlen);
      H5Tclose(tid);
      H5Sclose(sid);
  
      /* 12 compound data */
      sid  = H5Screate_simple(1, dims2, NULL);
      tid  = H5Tcreate(H5T_COMPOUND, sizeof(zipcode_t));
      tid1 = H5Tcopy(H5T_C_S1);
      H5Tset_size(tid1, H5T_VARIABLE);
      H5Tinsert(tid, "zip code", 0, H5T_NATIVE_INT);
      offset += sizeof(H5T_NATIVE_INT);
      H5Tinsert(tid, "City", offset, tid1);
      offset += sizeof(char *);
      HDsprintf(name, "%05d compound data", idx);
      nattrs += add_attr(oid, name, tid, sid, cmp_data);
      H5Tclose(tid1);
      H5Tclose(tid);
      H5Sclose(sid);
  
      for (i0 = 0; i0 < 4; i0++)
          free(i_vlen[i0].p);
  
      return nattrs;
  }
  