Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/classy-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,9 @@ jobs:
cd Tests/classy_hdf5_interface
export LD_LIBRARY_PATH="../../hdf5-1.12.0-install/lib:$LD_LIBRARY_PATH"
./search.exe

- name: Run ClassyHDF Test - Attributes
run: |
cd Tests/classy_hdf5_interface
export LD_LIBRARY_PATH="../../hdf5-1.12.0-install/lib:$LD_LIBRARY_PATH"
./attributes.exe
4 changes: 3 additions & 1 deletion Source/ClassyHDF.H
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@
#include "ClassyHDF_Location.H"
#include "ClassyHDF_Group.H"
#include "ClassyHDF_File.H"
#include "ClassyHDF_Errors.H"

#endif

#endif
13 changes: 13 additions & 0 deletions Source/ClassyHDF_Errors.H
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef CLASSY_HDF_ERRORS_H_
#define CLASSY_HDF_ERRORS_H_

namespace ClassyHDF {

namespace Errors {
enum {file_exists=1};
}

}

#endif

11 changes: 8 additions & 3 deletions Source/ClassyHDF_File.H
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
#include "hdf5.h"

#include "ClassyHDF_Group.H"
#include "ClassyHDF_Errors.H"

namespace ClassyHDF {

namespace FileMode {
enum {rw=0, trunc};
enum {rw=0, trunc, exists_is_error};
}

class File : public Location<Group> {
Expand All @@ -22,14 +23,18 @@ class File : public Location<Group> {
set_name(file_name);

// try to open the file in read/write mode, otherwise create it
if (access_type == FileMode::rw) {
if (access_type == FileMode::rw || access_type == FileMode::exists_is_error) {
set_existed(true);
H5E_BEGIN_TRY
set_id(H5Fopen(name().c_str(), H5F_ACC_RDWR, H5P_DEFAULT));
H5E_END_TRY

if (access_type == FileMode::exists_is_error && id() >= 0) {
throw Errors::file_exists;
}
}

if (access_type == FileMode::trunc ||
if (access_type == FileMode::trunc || access_type == FileMode::exists_is_error ||
(access_type == FileMode::rw && id() < 0)) {
set_existed(false);
set_id(H5Fcreate(name().c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT));
Expand Down
122 changes: 122 additions & 0 deletions Source/ClassyHDF_Location.H
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,125 @@
#include <string>
#include <vector>
#include "hdf5.h"
#include "hdf5_hl.h"

#include "ClassyHDF_Identity.H"
#include "ClassyHDF_Data.H"
#include "ClassyHDF_Dataset.H"

namespace ClassyHDF {

namespace {
template<typename T, class Tloc>
struct Attribute {
static void set(const Tloc& loc, const std::string& attr_name, const T& attr_value) { assert(false); }
static T get(const Tloc& loc, const std::string& attr_name) { assert(false); return static_cast<T>(0); }
};

template<class Tloc>
struct Attribute<std::string, Tloc> {
static void set(const Tloc& loc, const std::string& attr_name, const std::string& attr_value)
{
auto gattr = loc.get_group("Attributes");

herr_t status = H5LTset_attribute_string(loc.id(), "Attributes",
attr_name.c_str(),
attr_value.c_str());
assert(status >= 0);
}

static std::string get(const Tloc& loc, const std::string& attr_name)
{
char* buffer;
int size_buffer;
herr_t status = H5LTget_attribute_ndims(loc.id(), "Attributes",
attr_name.c_str(), &size_buffer);
assert(status >= 0);

buffer = new char[size_buffer];
status = H5LTget_attribute_string(loc.id(), "Attributes",
attr_name.c_str(), buffer);
std::string sattr = buffer;
delete buffer;
assert(status >= 0);

return sattr;
}
};

template<class Tloc>
struct Attribute<int, Tloc> {
static void set(const Tloc& loc, const std::string& attr_name, const int& attr_value)
{
auto gattr = loc.get_group("Attributes");

herr_t status = H5LTset_attribute_int(loc.id(), "Attributes",
attr_name.c_str(),
&attr_value, 1);
assert(status >= 0);
}

static int get(const Tloc& loc, const std::string& attr_name)
{
int attr_value = 0;

herr_t status = H5LTget_attribute_int(loc.id(), "Attributes",
attr_name.c_str(), &attr_value);
assert(status >= 0);

return attr_value;
}
};

template<class Tloc>
struct Attribute<float, Tloc> {
static void set(const Tloc& loc, const std::string& attr_name, const float& attr_value)
{
auto gattr = loc.get_group("Attributes");

herr_t status = H5LTset_attribute_float(loc.id(), "Attributes",
attr_name.c_str(),
&attr_value, 1);
assert(status >= 0);
}

static float get(const Tloc& loc, const std::string& attr_name)
{
float attr_value = 0;

herr_t status = H5LTget_attribute_float(loc.id(), "Attributes",
attr_name.c_str(), &attr_value);
assert(status >= 0);

return attr_value;
}
};

template<class Tloc>
struct Attribute<double, Tloc> {
static void set(const Tloc& loc, const std::string& attr_name, const double& attr_value)
{
auto gattr = loc.get_group("Attributes");

herr_t status = H5LTset_attribute_double(loc.id(), "Attributes",
attr_name.c_str(),
&attr_value, 1);
assert(status >= 0);
}

static double get(const Tloc& loc, const std::string& attr_name)
{
double attr_value = 0;

herr_t status = H5LTget_attribute_double(loc.id(), "Attributes",
attr_name.c_str(), &attr_value);
assert(status >= 0);

return attr_value;
}
};
}

// We're going to use the Curiously Recurring Template Pattern to
// allow any derived class from Location to create Group objects,
// even though Group derives from Location.
Expand Down Expand Up @@ -178,6 +290,16 @@ class Location : public NamedIdentity {
dataset.append(data);
return dataset;
}

template<typename T>
void attr(const std::string& attr_name, const T& attr_value) {
Attribute<T, decltype(*this)>::set(*this, attr_name, attr_value);
}

template<typename T>
T attr(const std::string& attr_name) {
return Attribute<T, decltype(*this)>::get(*this, attr_name);
}
};

}
Expand Down
5 changes: 4 additions & 1 deletion Source/Make.package
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ CEXE_headers += ClassyHDF_Dataset.H
CEXE_headers += ClassyHDF_Location.H
CEXE_headers += ClassyHDF_Group.H
CEXE_headers += ClassyHDF_File.H
CEXE_headers += ClassyHDF.H
CEXE_headers += ClassyHDF_Errors.H
CEXE_headers += ClassyHDF.H

LIBRARIES += -lhdf5_hl
2 changes: 2 additions & 0 deletions Tests/classy_hdf5_interface/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ EXTRA_LIBS ?= -lsz -lz -lm

all:
g++ -o append.exe append.cpp -I../../Source -I$(HDF5_HOME)/include -L$(HDF5_HOME)/lib -lhdf5 $(EXTRA_LIBS)
g++ -o attributes.exe attributes.cpp -I../../Source -I$(HDF5_HOME)/include -L$(HDF5_HOME)/lib -lhdf5 -lhdf5_hl $(EXTRA_LIBS)
g++ -o get_last_N.exe get_last_N.cpp -I../../Source -I$(HDF5_HOME)/include -L$(HDF5_HOME)/lib -lhdf5 $(EXTRA_LIBS)
g++ -o resize.exe resize.cpp -I../../Source -I$(HDF5_HOME)/include -L$(HDF5_HOME)/lib -lhdf5 $(EXTRA_LIBS)
g++ -o search.exe search.cpp -I../../Source -I$(HDF5_HOME)/include -L$(HDF5_HOME)/lib -lhdf5 $(EXTRA_LIBS)

test: all
./append.exe
./attributes.exe
./get_last_N.exe
./resize.exe
./search.exe
Expand Down
57 changes: 57 additions & 0 deletions Tests/classy_hdf5_interface/attributes.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include <iostream>
#include <string>
#include <assert.h>
#include "ClassyHDF.H"
#include "hdf5_hl.h"

using namespace ClassyHDF;

void write_test_file(const std::string& filename) {
File file(filename, FileMode::trunc);
Group group1 = file.get_group("Data");
Group group2 = group1.get_group("GroupA");

// put some attributes into the "GroupA" group
group2.attr<std::string>("TestAttribute", "Hello World!");
group2.attr<int>("TestAttInt", 5);
group2.attr<float>("TestAttFloat", -1.0);
group2.attr<double>("TestAttDouble", -2.0);
}

bool do_test(const std::string& filename) {
File file(filename);
Group group1 = file.get_group("Data");
Group group2 = group1.get_group("GroupA");

bool success = true;

// get some attributes from the "GroupA" group
std::string stest = group2.attr<std::string>("TestAttribute");
success = success && (stest == "Hello World!");

int itest = group2.attr<int>("TestAttInt");
success = success && (itest == 5);

float ftest = group2.attr<float>("TestAttFloat");
success = success && (ftest == -1.0);

double dtest = group2.attr<double>("TestAttDouble");
success = success && (dtest == -2.0);

return success;
}

int main() {
const std::string filename = "file_attributes.h5";

write_test_file(filename);

if (do_test(filename)) {
std::cout << "success" << std::endl;
return 0;
} else {
std::cout << "failure" << std::endl;
return -1;
}
}