Files
FESADev/src/fesa/io/hdf5/hdf5_primitives.cpp
T

288 lines
12 KiB
C++

#include "io/hdf5/hdf5_primitives.h"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <filesystem>
#include <limits>
#include <string>
#include <vector>
namespace fesa::hdf5_internal {
Status OutputFailure(const std::string& code, const std::string& message) {
return Status::Failure(FailureCategory::kOutput,
{{Severity::kError, code, {}, "", "", message}});
}
bool IsValidUtf8(const std::string& value) {
const auto* bytes = reinterpret_cast<const unsigned char*>(value.data());
std::size_t index = 0U;
while (index < value.size()) {
const unsigned char first = bytes[index];
if (first <= 0x7fU) {
++index;
continue;
}
std::size_t continuation_count = 0U;
std::uint32_t code_point = 0U;
if (first >= 0xc2U && first <= 0xdfU) {
continuation_count = 1U;
code_point = first & 0x1fU;
} else if (first >= 0xe0U && first <= 0xefU) {
continuation_count = 2U;
code_point = first & 0x0fU;
} else if (first >= 0xf0U && first <= 0xf4U) {
continuation_count = 3U;
code_point = first & 0x07U;
} else {
return false;
}
if (index + continuation_count >= value.size()) {
return false;
}
for (std::size_t offset = 1U; offset <= continuation_count; ++offset) {
const unsigned char next = bytes[index + offset];
if ((next & 0xc0U) != 0x80U) {
return false;
}
code_point = (code_point << 6U) | (next & 0x3fU);
}
if ((continuation_count == 2U && code_point < 0x800U) ||
(continuation_count == 3U && code_point < 0x10000U) ||
(code_point >= 0xd800U && code_point <= 0xdfffU) ||
code_point > 0x10ffffU) {
return false;
}
index += continuation_count + 1U;
}
return true;
}
bool SameIdentity(const SourceEntityId& left, const SourceEntityId& right) {
return left.instance_name == right.instance_name &&
left.source_label == right.source_label &&
left.source_label_text == right.source_label_text;
}
bool IsShellDomain(const Domain& domain) noexcept {
return !domain.ShellElements().Empty();
}
const char* ShellSourceTypeName(const ShellSourceElementType type) {
return type == ShellSourceElementType::kS4 ? "S4" : "S4R";
}
bool SizeProductFits(const std::size_t left, const std::size_t right,
std::size_t& product) {
if (right != 0U && left > (std::numeric_limits<std::size_t>::max)() / right) {
return false;
}
product = left * right;
return true;
}
std::string NormalizedPathString(const std::filesystem::path& path) {
if (path.empty()) {
return {};
}
return std::filesystem::absolute(path).lexically_normal().generic_u8string();
}
std::string SourceInputIdentity(const Domain& domain) {
return "path=" + NormalizedPathString(domain.SourcePath()) +
";content_identity=" + domain.SourceContentIdentity();
}
Hdf5Handle MakeUtf8StringType() {
Hdf5Handle type{
RequireHdf5Id(H5Tcopy(H5T_C_S1), "Unable to copy an HDF5 string type."),
H5Tclose};
RequireHdf5(H5Tset_size(type.Get(), H5T_VARIABLE),
"Unable to configure a variable-length HDF5 string.");
RequireHdf5(H5Tset_cset(type.Get(), H5T_CSET_UTF8),
"Unable to configure UTF-8 HDF5 strings.");
RequireHdf5(H5Tset_strpad(type.Get(), H5T_STR_NULLTERM),
"Unable to configure HDF5 string padding.");
return type;
}
void WriteStringAttribute(const hid_t object, const char* name,
const std::string& value) {
auto type = MakeUtf8StringType();
Hdf5Handle space{RequireHdf5Id(H5Screate(H5S_SCALAR),
"Unable to create an attribute space."),
H5Sclose};
Hdf5Handle attribute{
RequireHdf5Id(H5Acreate2(object, name, type.Get(), space.Get(),
H5P_DEFAULT, H5P_DEFAULT),
"Unable to create an HDF5 string attribute."),
H5Aclose};
const char* raw = value.c_str();
RequireHdf5(H5Awrite(attribute.Get(), type.Get(), &raw),
"Unable to write an HDF5 string attribute.");
}
void WriteUint64Attribute(const hid_t object, const char* name,
const std::uint64_t value) {
Hdf5Handle space{RequireHdf5Id(H5Screate(H5S_SCALAR),
"Unable to create an attribute space."),
H5Sclose};
Hdf5Handle attribute{
RequireHdf5Id(H5Acreate2(object, name, H5T_STD_U64LE, space.Get(),
H5P_DEFAULT, H5P_DEFAULT),
"Unable to create an HDF5 integer attribute."),
H5Aclose};
RequireHdf5(H5Awrite(attribute.Get(), H5T_NATIVE_UINT64, &value),
"Unable to write an HDF5 integer attribute.");
}
void WriteUint8Attribute(const hid_t object, const char* name,
const std::uint8_t value) {
Hdf5Handle space{RequireHdf5Id(H5Screate(H5S_SCALAR),
"Unable to create an attribute space."),
H5Sclose};
Hdf5Handle attribute{
RequireHdf5Id(H5Acreate2(object, name, H5T_STD_U8LE, space.Get(),
H5P_DEFAULT, H5P_DEFAULT),
"Unable to create an HDF5 uint8 attribute."),
H5Aclose};
RequireHdf5(H5Awrite(attribute.Get(), H5T_NATIVE_UINT8, &value),
"Unable to write an HDF5 uint8 attribute.");
}
void WriteDoubleAttribute(const hid_t object, const char* name,
const double value) {
Hdf5Handle space{RequireHdf5Id(H5Screate(H5S_SCALAR),
"Unable to create an attribute space."),
H5Sclose};
Hdf5Handle attribute{
RequireHdf5Id(H5Acreate2(object, name, H5T_IEEE_F64LE, space.Get(),
H5P_DEFAULT, H5P_DEFAULT),
"Unable to create an HDF5 float64 attribute."),
H5Aclose};
RequireHdf5(H5Awrite(attribute.Get(), H5T_NATIVE_DOUBLE, &value),
"Unable to write an HDF5 float64 attribute.");
}
Hdf5Handle CreateGroup(const hid_t file, const char* path) {
Hdf5Handle link_properties{RequireHdf5Id(H5Pcreate(H5P_LINK_CREATE),
"Unable to create link properties."),
H5Pclose};
RequireHdf5(H5Pset_create_intermediate_group(link_properties.Get(), 1U),
"Unable to enable intermediate HDF5 groups.");
return Hdf5Handle{RequireHdf5Id(H5Gcreate2(file, path, link_properties.Get(),
H5P_DEFAULT, H5P_DEFAULT),
"Unable to create an HDF5 group."),
H5Gclose};
}
Hdf5Handle CreateDatasetSpace(const std::vector<hsize_t>& dimensions) {
return Hdf5Handle{
RequireHdf5Id(H5Screate_simple(static_cast<int>(dimensions.size()),
dimensions.data(), nullptr),
"Unable to create an HDF5 dataset space."),
H5Sclose};
}
void WriteResultAttributes(const hid_t dataset,
const std::string& component_names,
const std::string& component_units,
const std::string& coordinate_system,
const std::string& location) {
WriteStringAttribute(dataset, "component_names", component_names);
WriteStringAttribute(dataset, "component_unit_dimensions", component_units);
WriteStringAttribute(dataset, "coordinate_system", coordinate_system);
WriteStringAttribute(dataset, "location", location);
WriteStringAttribute(dataset, "step_name", kStepName);
WriteUint64Attribute(dataset, "frame_index", 0U);
}
Hdf5Handle WriteDoubleValues(const hid_t file, const std::string& path,
const std::vector<hsize_t>& dimensions,
const double* values,
const std::size_t value_count) {
auto space = CreateDatasetSpace(dimensions);
Hdf5Handle dataset{
RequireHdf5Id(H5Dcreate2(file, path.c_str(), H5T_IEEE_F64LE, space.Get(),
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT),
"Unable to create a floating-point HDF5 dataset."),
H5Dclose};
if (value_count != 0U) {
RequireHdf5(H5Dwrite(dataset.Get(), H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL,
H5P_DEFAULT, values),
"Unable to write a floating-point HDF5 dataset.");
}
return dataset;
}
void WriteDoubleDataset(const hid_t file, const std::string& path,
const std::vector<hsize_t>& dimensions,
const double* values, const std::size_t value_count,
const std::string& component_names,
const std::string& component_units,
const std::string& coordinate_system,
const std::string& location) {
auto dataset = WriteDoubleValues(file, path, dimensions, values, value_count);
WriteResultAttributes(dataset.Get(), component_names, component_units,
coordinate_system, location);
}
void WriteModelDoubleDataset(const hid_t file, const std::string& path,
const std::vector<hsize_t>& dimensions,
const double* values,
const std::size_t value_count,
const std::string& component_names,
const std::string& component_units,
const std::string& coordinate_system,
const std::string& location) {
auto dataset = WriteDoubleValues(file, path, dimensions, values, value_count);
WriteStringAttribute(dataset.Get(), "component_names", component_names);
WriteStringAttribute(dataset.Get(), "component_unit_dimensions",
component_units);
WriteStringAttribute(dataset.Get(), "coordinate_system", coordinate_system);
WriteStringAttribute(dataset.Get(), "location", location);
}
void WriteUint8Dataset(const hid_t file, const std::string& path,
const std::vector<hsize_t>& dimensions,
const std::uint8_t* values,
const std::size_t value_count) {
auto space = CreateDatasetSpace(dimensions);
Hdf5Handle dataset{
RequireHdf5Id(H5Dcreate2(file, path.c_str(), H5T_STD_U8LE, space.Get(),
H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT),
"Unable to create a uint8 HDF5 dataset."),
H5Dclose};
if (value_count != 0U) {
RequireHdf5(H5Dwrite(dataset.Get(), H5T_NATIVE_UINT8, H5S_ALL, H5S_ALL,
H5P_DEFAULT, values),
"Unable to write a uint8 HDF5 dataset.");
}
WriteStringAttribute(dataset.Get(), "component_names",
"UX,UY,UZ,URX,URY,URZ");
WriteStringAttribute(dataset.Get(), "value_meaning", "0=free,1=constrained");
}
Hdf5Handle WriteCompoundDataset(const hid_t file, const char* path,
const std::size_t row_count,
const hid_t file_type, const hid_t memory_type,
const void* rows) {
const std::vector<hsize_t> dimensions = {static_cast<hsize_t>(row_count)};
auto space = CreateDatasetSpace(dimensions);
Hdf5Handle dataset{
RequireHdf5Id(H5Dcreate2(file, path, file_type, space.Get(), H5P_DEFAULT,
H5P_DEFAULT, H5P_DEFAULT),
"Unable to create a compound HDF5 dataset."),
H5Dclose};
if (row_count != 0U) {
RequireHdf5(H5Dwrite(dataset.Get(), memory_type, H5S_ALL, H5S_ALL,
H5P_DEFAULT, rows),
"Unable to write a compound HDF5 dataset.");
}
return dataset;
}
} // namespace fesa::hdf5_internal