Skip to content

Commit

Permalink
Generalise types with a utility function.
Browse files Browse the repository at this point in the history
Convert between native C++ datatypes and H5::PredTypes.
Needs some unit testing!

Co-authored-by: willGraham01 <[email protected]>
  • Loading branch information
samcunliffe and willGraham01 committed May 19, 2023
1 parent 3f75c1f commit c266ef9
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 22 deletions.
29 changes: 29 additions & 0 deletions tdms/include/hdf5_io/hdf5_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,42 @@
#pragma once

#include <memory>
#include <stdexcept>
#include <string>
#include <vector>

#include <H5Cpp.h>

#include "hdf5_io/hdf5_dimension.h"

/**
* @brief Convert from C++ datatype T to a H5::PredType for HDF5 write out.
*
* TODO: Doesn't support complex doubles. Might need a compount datatype.
* Investigate how to read complex doubles first.
*
* @tparam T the native C++ type.
* @return H5::PredType The HDF5 type to save.
*/
template<typename T>
H5::PredType to_hdf5_datatype() {

if (std::is_same<T, double>()) {
return H5::PredType::NATIVE_DOUBLE;
} else if (std::is_same<T, int>()) {
return H5::PredType::NATIVE_INT;
} else if (std::is_same<T, char>()) {
return H5::PredType::NATIVE_CHAR;
} else if (std::is_same<T, uint16_t>()) {
return H5::PredType::NATIVE_UINT16;
} else if (std::is_same<T, int16_t>()) {
return H5::PredType::NATIVE_INT16;
} else {
throw std::runtime_error("I don't know how to convert this datatype to "
"something HDF5 wants");
}
};

/**
* @brief The base class for HDF5 I/O.
* @details Common functionality and wraps handling the std::unique_ptr to hold
Expand Down
14 changes: 5 additions & 9 deletions tdms/include/hdf5_io/hdf5_writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ class HDF5Writer : public HDF5Base {
const std::string &dataset,
std::vector<T> data) const {
spdlog::debug("Writing {} to file: {}", group, filename_);
// Infer the datatype to write to and throw error immediately if we cannot
// convert to it
H5::PredType write_data_as_type = to_hdf5_datatype<T>();

// Create group if it does not exist
H5::Group group_to_write_to;
Expand All @@ -86,20 +89,13 @@ class HDF5Writer : public HDF5Base {
hsize_t dims[1] = {data.size()};
H5::DataSpace dimension_info(1, dims);
H5::DataSet dataset_to_write_to = group_to_write_to.createDataSet(
dataset,
// to_hdf5_dtype(data),
H5::PredType::NATIVE_DOUBLE, dimension_info);
dataset, write_data_as_type, dimension_info);

dataset_to_write_to.write(data.data(),
// to_hdf5_dtype(data),
H5::PredType::NATIVE_DOUBLE);
dataset_to_write_to.write(data.data(), write_data_as_type);

dataset_to_write_to.close();
dimension_info.close();
group_to_write_to.close();
return;
}
};

// https://support.hdfgroup.org/HDF5/doc/RM/RM_H5T.html#Datatype-Equal <-
// possible compare C++ types to HDF5 types?
49 changes: 36 additions & 13 deletions tdms/tests/unit/hdf5_io_tests/test_hdf5_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,35 +27,58 @@ TEST_CASE("HDF5Writer: Write doubles to a group.") {
// setup
string tmp_dir = create_tmp_dir();
string file_name = tmp_dir + "/some_test_data.hdf5";
spdlog::info("Temporary file: {}", file_name);

string group_out = "test_group";
string dataset_out = "array_of_10_doubles";
string group_name = "group_name";
string double_dataset = "array_of_10_doubles";
string int_dataset = "array_of_5_ints";

{
HDF5Writer writer(file_name);

vector<double> write_me_out = {.0, .1, .2, .3, .4, .5, .6, .7, .8, .9};
{
vector<double> write_me_out = {.0, .1, .2, .3, .4, .5, .6, .7, .8, .9};

writer.write_dataset_to_group(group_out, dataset_out, write_me_out);
writer.write_dataset_to_group(group_name, double_dataset, write_me_out);
}
{
vector<int> write_me_out = {0, 1, 2, 3, 4, 5};

writer.write_dataset_to_group(group_name, int_dataset, write_me_out);
}

REQUIRE(writer.contains(group_out));
REQUIRE(writer.contains(group_name));
}

// Read data back to confirm entries are as expected
{
HDF5Reader reader(file_name);

REQUIRE(reader.contains(group_out));
REQUIRE(reader.contains(group_name));

vector<double> read_back_in;
reader.read_dataset_in_group(group_out, dataset_out, read_back_in);
{
vector<double> read_back_in;
reader.read_dataset_in_group(group_name, double_dataset, read_back_in);

bool all_entries_correct = true;
for (int i = 0; i < 10; i++) {
all_entries_correct = all_entries_correct &&
(read_back_in[i] == Approx((double) i / 10.));
bool all_entries_correct = true;
for (int i = 0; i < 10; i++) {
all_entries_correct = all_entries_correct &&
(read_back_in[i] == Approx((double) i / 10.));
}
REQUIRE(all_entries_correct);
}
REQUIRE(all_entries_correct);
// TODO: fix this!
// {
// vector<int> read_back_in;
// reader.read_dataset_in_group(group_name, double_dataset, read_back_in);

// bool all_entries_correct = true;
// for (int i = 0; i < 5; i++) {
// all_entries_correct = all_entries_correct &&
// (read_back_in[i] == i);
// }
// REQUIRE(all_entries_correct);
// }
}

// Teardown
Expand Down

0 comments on commit c266ef9

Please sign in to comment.