0

I am working with the HDF5 library and am trying to write a template function to support I/O with different data types. The goal just to reduce and simplify the copy and pasting i need to do to create all the different functions.

In the HDF5 library this is the format for the write call (documentation here):

H5Dwrite(hid_t dataset_id, hid_t mem_type_id, hid_t mem_space_id, hid_t file_space_id, hid_t xfer_plist_id, const void * buf )

Many of these parameters are generated in my function or passed as function parameters. The only problem is the mem_type_id, which is defined as a series of #define clauses in the header file for the library.

Is there some trick I can use to change this based on the template type? I would prefer to avoid a giant conditional statement with the std::typeid(T) everywhere. The code is already massive, when compiled, so avoiding the bytes needed to store an unnecessary conditional seems advisable. There are over 40 types that I should implement to keep this generic for future projects. If there is anyway to limit my template from allowing types I have not defined, that might allow me to reduce the work to the minimum.

Possible solutions that I have though of include:

  1. Creating a specialized template function that returns the HDF5 type id, where i have a specialization for each type.
  2. Giant if statement
crazywill32
  • 390
  • 1
  • 4
  • 12
  • 1
    `#define` is a preprocessor directive; It is evaluated before the compiler even tokenizes the program; So I see no chance to somehow choose a different set of `#define`-statements based on types evaluated in a later compiling step. But I'm not sure if this is actually your question. – Stephan Lechner Jun 17 '17 at 21:16

1 Answers1

1

So while I was originally down-voted because it is a pre-processor statement that i am trying to select. Here is a solution I worked out.

I have two header files the first is this

#pragma once
#include "hdf5.h"
template <typename T> hid_t  HdfType();

template<> hid_t  HdfType<short>() { return H5T_NATIVE_SHORT; }
template<> hid_t  HdfType<unsigned short>()  { return H5T_NATIVE_USHORT; }
template<> hid_t  HdfType<int> () { return H5T_NATIVE_INT;}
template<> hid_t  HdfType<unsigned int> () { return H5T_NATIVE_UINT; }
template<> hid_t  HdfType<long> () { return H5T_NATIVE_LONG; }
template<> hid_t  HdfType<unsigned long> () { return H5T_NATIVE_ULONG; }
template<> hid_t  HdfType<long long> () { return H5T_NATIVE_LLONG; }
template<> hid_t  HdfType<unsigned long long> () { return H5T_NATIVE_ULLONG; }

template<> hid_t  HdfType<char> () { return H5T_NATIVE_CHAR; }
template<> hid_t  HdfType<unsigned char> () { return H5T_NATIVE_UCHAR; }
template<> hid_t  HdfType<signed char> () { return H5T_NATIVE_SCHAR; }

template<> hid_t  HdfType<float> () { return H5T_NATIVE_FLOAT; }
template<> hid_t  HdfType<double> () { return H5T_NATIVE_DOUBLE; }
template<> hid_t  HdfType<long double> () { return H5T_NATIVE_LDOUBLE; }

This file returns the Predefined handle numbers from the #define. The second file contains the following

#pragma once
#include "hdf5.h"
#include "HdfTypeTemplate.h"
#include <vector>

template <typename T, int dims=1, int numColumns =1>
void CollectiveHdfBlockImport(hid_t datasetId, long long startRowIndex, long long numRowsToImport, std::vector<T>& data)
{
    data.resize(numRowsToImport * numColumns + 10);
    hid_t dtplId = CreateCollectiveDataTransferPropertiesList();

    hid_t dataspaceId = H5Dget_space(datasetId);
    hsize_t start[2] = { 0 }, count[2] = { 0 }, strideAndBlocks[2] = { 1,1 };
    count[0] = numRowsToImport;
    count[1] = numColumns;
    start[0] = startRowIndex;
    start[1] = 0;
    hid_t memspaceId = H5Screate_simple(dims, count, NULL);
    H5Sselect_hyperslab(dataspaceId, H5S_SELECT_SET, start, strideAndBlocks, count, strideAndBlocks);
    H5Dread(datasetId, HdfType<T>(), memspaceId, dataspaceId, dtplId, data.data());

    H5Sclose(dataspaceId);
    H5Sclose(memspaceId);
    H5Pclose(dtplId);
}

You see that the HDFType() is placed in the correct location. This performs the import for a specific block of data. It utilizes a template so I can easily use it to create functions in my code without needing to rewrite this using. By not defining the general template and using template specialization, I can limit the cases to what I know in general people will use in the library. If a new case is needed I can construct one.

If someone has a better solution please post them.

crazywill32
  • 390
  • 1
  • 4
  • 12