Merge branch 'developer' into dev/matterhorn_server_funcs
Build on RHEL9 docker image / build (push) Successful in 4m1s
Build on RHEL8 docker image / build (push) Successful in 5m38s
Run Simulator Tests on local RHEL9 / build (push) Successful in 18m56s
Run Simulator Tests on local RHEL8 / build (push) Successful in 22m23s

This commit is contained in:
2026-07-14 10:55:00 +02:00
48 changed files with 1269 additions and 142431 deletions
+1
View File
@@ -6,6 +6,7 @@ target_sources(tests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/test-SharedMemory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/acquire/Acquire.cpp
${CMAKE_CURRENT_SOURCE_DIR}/acquire/CTBState.cpp
${CMAKE_CURRENT_SOURCE_DIR}/acquire/ExpectedState.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Caller/test-Caller.cpp
@@ -589,46 +589,6 @@ TEST_CASE("quad", "[.detectorintegration]") {
}
}
TEST_CASE("datastream", "[.detectorintegration]") {
Detector det;
Caller caller(&det);
auto det_type = det.getDetectorType().squash();
if (det_type == defs::EIGER) {
auto prev_val_left = det.getDataStream(defs::LEFT);
auto prev_val_right = det.getDataStream(defs::RIGHT);
// no "left" or "right"
REQUIRE_THROWS(caller.call("datastream", {"1"}, -1, PUT));
{
std::ostringstream oss;
caller.call("datastream", {"left", "0"}, -1, PUT, oss);
REQUIRE(oss.str() == "datastream [left, 0]\n");
}
{
std::ostringstream oss;
caller.call("datastream", {"right", "0"}, -1, PUT, oss);
REQUIRE(oss.str() == "datastream [right, 0]\n");
}
{
std::ostringstream oss;
caller.call("datastream", {"left", "1"}, -1, PUT, oss);
REQUIRE(oss.str() == "datastream [left, 1]\n");
}
{
std::ostringstream oss;
caller.call("datastream", {"right", "1"}, -1, PUT, oss);
REQUIRE(oss.str() == "datastream [right, 1]\n");
}
for (int i = 0; i != det.size(); ++i) {
det.setDataStream(defs::LEFT, prev_val_left[i], {i});
det.setDataStream(defs::RIGHT, prev_val_right[i], {i});
}
} else {
REQUIRE_THROWS(caller.call("datastream", {}, -1, GET));
REQUIRE_THROWS(caller.call("datastream", {"1"}, -1, PUT));
REQUIRE_THROWS(caller.call("datastream", {"left", "1"}, -1, PUT));
}
}
TEST_CASE("top", "[.detectorintegration]") {
Detector det;
Caller caller(&det);
@@ -99,31 +99,4 @@ void test_onchip_dac_caller(defs::dacIndex index, const std::string &dacname,
}
}
std::pair<uint64_t, int>
calculate_ctb_image_size(const acq::CTBState &test_info, bool isXilinxCtb) {
LOG(logDEBUG1) << test_info;
sls::CtbImageInputs inputs{};
inputs.mode = test_info.readout_mode;
inputs.nAnalogSamples = test_info.num_adc_samples;
inputs.adcMask = test_info.adc_enable_10g;
if (!isXilinxCtb && !test_info.ten_giga) {
inputs.adcMask = test_info.adc_enable_1g;
}
inputs.nTransceiverSamples = test_info.num_trans_samples;
inputs.transceiverMask = test_info.transceiver_mask;
inputs.nDigitalSamples = test_info.num_dbit_samples;
inputs.dbitOffset = test_info.dbit_offset;
inputs.dbitReorder = test_info.dbit_reorder;
inputs.dbitList = test_info.dbit_list;
auto out = computeCtbImageSize(inputs);
uint64_t image_size =
out.nAnalogBytes + out.nDigitalBytes + out.nTransceiverBytes;
LOG(logDEBUG1) << "Expected image size: " << image_size;
int npixelx = out.nPixelsX;
LOG(logDEBUG1) << "Expected number of pixels in x: " << npixelx;
return std::make_pair(image_size, npixelx);
}
} // namespace sls
@@ -2,7 +2,7 @@
// Copyright (C) 2021 Contributors to the SLS Detector Package
#pragma once
#include "acquire/CTBState.h"
#include "checks/MasterFileChecks.h"
#include "sls/sls_detector_defs.h"
#include <chrono>
@@ -13,6 +13,8 @@
namespace sls {
namespace acq = sls::test::acquire;
namespace mf = sls::test::master_file;
namespace checks = sls::test::checks;
void test_valid_port_caller(const std::string &command,
const std::vector<std::string> &arguments,
@@ -23,7 +25,42 @@ void test_dac_caller(slsDetectorDefs::dacIndex index,
void test_onchip_dac_caller(slsDetectorDefs::dacIndex index,
const std::string &dacname, int dacvalue);
std::pair<uint64_t, int>
calculate_ctb_image_size(const acq::CTBState &test_info, bool isXilinxCtb);
/**
* Helper function to run an acquisition and check the master file (both binary
* and hdf5) for expected values. The function takes in a lambda that is called
* with the master filechecker object to perform checks on the master file. The
* acquisition is run with default acquisition and file states, but these can be
* modified within the lambda if needed. This version has the master file
* checker object created within the function instead of using a helper
* function, to allow for more flexibility in handling exceptions (especially
* HDF5 exceptions) and logging.
*/
template <typename F>
void test_run_with_master_file_checker(Detector &det, F f) {
auto acq_state = acq::default_acquisition_state();
auto file_state = acq::default_file_state();
std::array<defs::fileFormat, 2> formats = {defs::BINARY, defs::HDF5};
for (const auto &format : formats) {
file_state.file_format = format;
acq::run(det, acq_state, file_state);
std::string fname = acq::get_master_file_name(file_state);
if (format == defs::HDF5) {
#ifdef HDF5C
try {
mf::Checker<mf::H5Context> checker(fname);
f(det, acq_state, file_state, checker);
} catch (H5::Exception &e) {
LOG(logERROR) << "HDF5 error: " << e.getDetailMsg();
throw;
}
#endif
} else {
mf::Checker<mf::JsonContext> checker(fname);
f(det, acq_state, file_state, checker);
}
}
}
} // namespace sls
@@ -1,29 +1,15 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#include "acquire/ExpectedState.h"
#include "checks/MasterFileChecks.h"
#include "sls/Detector.h"
#include "sls/ToString.h"
#include "sls/logger.h"
#include "test-Caller-global.h"
#include "catch.hpp"
#include <filesystem>
#include <fstream>
#include <rapidjson/document.h>
#include <rapidjson/error/en.h>
#include <sstream>
#include <string>
#ifdef HDF5C
#include "H5Cpp.h"
#endif
namespace sls {
namespace mf = sls::test::master_file;
namespace acq = sls::test::acquire;
namespace checks = sls::test::checks;
TEST_CASE("check_master_file_attributes",
"[.detectorintegration][.disable_check_data_file]") {
@@ -32,10 +18,6 @@ TEST_CASE("check_master_file_attributes",
auto detType = det.getDetectorType().squash(defs::GENERIC);
INFO("Testing master file attributes with " << ToString(detType));
// currently num frame = 1 (default)
auto acq_state = acq::default_acquisition_state();
auto file_state = acq::default_file_state();
// if ctb, set to default and restore after test
std::optional<acq::CTBState> ctb_state = std::nullopt;
if (detType == defs::CHIPTESTBOARD ||
@@ -44,36 +26,75 @@ TEST_CASE("check_master_file_attributes",
}
acq::CTBStateGuard ctb_guard(det, ctb_state);
// binary => /tmp/sls_test_master_0.json
file_state.file_format = defs::BINARY;
acq::run(det, acq_state, file_state);
test_run_with_master_file_checker(
det, [&](auto &det, auto &acq_state, auto &file_state, auto &checker) {
// get expected state of parameters and check against master file
auto expected_state = acq::build_expected_state(
det, acq_state, file_state, ctb_state);
checks::check_metadata(checker, expected_state);
});
}
std::string fname = acq::get_master_file_name(file_state);
mf::Checker<mf::JsonContext> checker(fname);
TEST_CASE("udp_datastream with master file",
"[.detectorintegration][.disable_check_data_file]") {
Detector det;
auto det_type = det.getDetectorType().squash();
if (det_type == defs::EIGER) {
auto prev_val_left = det.getUDPDataStream(defs::LEFT);
auto prev_val_right = det.getUDPDataStream(defs::RIGHT);
// get expected state of parameters and check against master file
acq::ExpectedState expected_state =
acq::build_expected_state(det, acq_state, file_state, ctb_state);
checks::check_metadata(checker, expected_state);
det.setUDPDataStream(defs::LEFT, false);
// check master file
{
// expected
std::vector<defs::portPosition> expected_ports =
det.getPortPositionList();
std::vector<int> expected_disabled_ports =
det.getRxDisabledUDPPortIndices();
REQUIRE(expected_disabled_ports.size() > 0);
#ifdef HDF5C
try {
// hdf5 => /tmp/sls_test_master_0.h5
file_state.file_format = defs::HDF5;
acq::run(det, acq_state, file_state);
test_run_with_master_file_checker(
det, [&](auto &det, auto &acq_state, auto &file_state,
auto &checker) {
checks::check_udp_ports_type(checker, expected_ports);
checks::check_udp_ports_disabled(checker,
expected_disabled_ports);
});
}
std::string fname = acq::get_master_file_name(file_state);
mf::Checker<mf::H5Context> checker(fname);
for (int i = 0; i != det.size(); ++i) {
det.setUDPDataStream(defs::LEFT, prev_val_left[i], {i});
det.setUDPDataStream(defs::RIGHT, prev_val_right[i], {i});
}
} else if ((det_type == defs::JUNGFRAU || det_type == defs::MOENCH) &&
(det.getNumberofUDPInterfaces().squash(0) == 2)) {
auto prev_val_top = det.getUDPDataStream(defs::TOP);
auto prev_val_bottom = det.getUDPDataStream(defs::BOTTOM);
// get expected state of parameters and check against master file
acq::ExpectedState expected_state =
acq::build_expected_state(det, acq_state, file_state, ctb_state);
checks::check_metadata(checker, expected_state);
} catch (H5::Exception &e) {
LOG(logERROR) << "HDF5 error: " << e.getDetailMsg();
throw;
det.setUDPDataStream(defs::TOP, false);
// check master file
{
// expected
std::vector<defs::portPosition> expected_ports =
det.getPortPositionList();
std::vector<int> expected_disabled_ports =
det.getRxDisabledUDPPortIndices();
REQUIRE(expected_disabled_ports.size() > 0);
test_run_with_master_file_checker(
det, [&](auto &det, auto &acq_state, auto &file_state,
auto &checker) {
checks::check_udp_ports_type(checker, expected_ports);
checks::check_udp_ports_disabled(checker,
expected_disabled_ports);
});
}
for (int i = 0; i != det.size(); ++i) {
det.setUDPDataStream(defs::TOP, prev_val_top[i], {i});
det.setUDPDataStream(defs::BOTTOM, prev_val_bottom[i], {i});
}
}
#endif
}
} // namespace sls
@@ -127,7 +127,8 @@ TEST_CASE("rx_framescaught", "[.detectorintegration]") {
}
}
TEST_CASE("rx_missingpackets", "[.detectorintegration]") {
TEST_CASE("rx_missingpackets",
"[.detectorintegration][.disable_check_data_file]") {
Detector det;
Caller caller(&det);
auto prev_val = det.getFileWrite();
@@ -3068,6 +3068,95 @@ TEST_CASE("txdelay", "[.detectorintegration]") {
}
}
TEST_CASE("udp_datastream", "[.detectorintegration]") {
Detector det;
Caller caller(&det);
auto det_type = det.getDetectorType().squash();
if (det_type == defs::EIGER) {
auto prev_val_left = det.getUDPDataStream(defs::LEFT);
auto prev_val_right = det.getUDPDataStream(defs::RIGHT);
// invalid args
REQUIRE_THROWS(caller.call("udp_datastream", {"top", "1"}, -1, PUT));
REQUIRE_THROWS(caller.call("udp_datastream", {"bottom", "1"}, -1, PUT));
// no "left" or "right" argument
REQUIRE_THROWS(caller.call("udp_datastream", {"1"}, -1, PUT));
{
std::ostringstream oss;
caller.call("udp_datastream", {"left", "0"}, -1, PUT, oss);
REQUIRE(oss.str() == "udp_datastream [left, 0]\n");
}
{
std::ostringstream oss;
caller.call("udp_datastream", {"right", "0"}, -1, PUT, oss);
REQUIRE(oss.str() == "udp_datastream [right, 0]\n");
}
{
std::ostringstream oss;
caller.call("udp_datastream", {"left", "1"}, -1, PUT, oss);
REQUIRE(oss.str() == "udp_datastream [left, 1]\n");
}
{
std::ostringstream oss;
caller.call("udp_datastream", {"right", "1"}, -1, PUT, oss);
REQUIRE(oss.str() == "udp_datastream [right, 1]\n");
}
for (int i = 0; i != det.size(); ++i) {
det.setUDPDataStream(defs::LEFT, prev_val_left[i], {i});
det.setUDPDataStream(defs::RIGHT, prev_val_right[i], {i});
}
} else if (det_type == defs::JUNGFRAU || det_type == defs::MOENCH) {
// throw with 1 interface
if (det.getNumberofUDPInterfaces().squash() == 1) {
REQUIRE_THROWS(
caller.call("udp_datastream", {"top", "0"}, -1, PUT));
}
// 2 interfaces
else {
auto prev_val_top = det.getUDPDataStream(defs::TOP);
auto prev_val_bottom = det.getUDPDataStream(defs::BOTTOM);
// invalid args
REQUIRE_THROWS(
caller.call("udp_datastream", {"left", "1"}, -1, PUT));
REQUIRE_THROWS(
caller.call("udp_datastream", {"right", "1"}, -1, PUT));
// no "top" or "bottom" argument
REQUIRE_THROWS(caller.call("udp_datastream", {"1"}, -1, PUT));
{
std::ostringstream oss;
caller.call("udp_datastream", {"top", "0"}, -1, PUT, oss);
REQUIRE(oss.str() == "udp_datastream [top, 0]\n");
}
{
std::ostringstream oss;
caller.call("udp_datastream", {"bottom", "0"}, -1, PUT, oss);
REQUIRE(oss.str() == "udp_datastream [bottom, 0]\n");
}
{
std::ostringstream oss;
caller.call("udp_datastream", {"top", "1"}, -1, PUT, oss);
REQUIRE(oss.str() == "udp_datastream [top, 1]\n");
}
{
std::ostringstream oss;
caller.call("udp_datastream", {"bottom", "1"}, -1, PUT, oss);
REQUIRE(oss.str() == "udp_datastream [bottom, 1]\n");
}
for (int i = 0; i != det.size(); ++i) {
det.setUDPDataStream(defs::TOP, prev_val_top[i], {i});
det.setUDPDataStream(defs::BOTTOM, prev_val_bottom[i], {i});
}
}
} else {
REQUIRE_THROWS(caller.call("udp_datastream", {}, -1, GET));
REQUIRE_THROWS(caller.call("udp_datastream", {"1"}, -1, PUT));
REQUIRE_THROWS(caller.call("udp_datastream", {"left", "1"}, -1, PUT));
REQUIRE_THROWS(caller.call("udp_datastream", {"top", "1"}, -1, PUT));
}
}
/* ZMQ Streaming Parameters (Receiver<->Client) */
TEST_CASE("zmqport", "[.detectorintegration]") {
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: LGPL-3.0-or-other
// Copyright (C) 2021 Contributors to the SLS Detector Package
#include "CTBState.h"
#include "GeneralData.h"
namespace sls::test::acquire {
std::pair<uint64_t, int> calculate_ctb_image_size(const CTBState &test_info,
bool isXilinxCtb) {
LOG(logDEBUG1) << test_info;
CtbImageInputs inputs{};
inputs.mode = test_info.readout_mode;
inputs.nAnalogSamples = test_info.num_adc_samples;
inputs.adcMask = test_info.adc_enable_10g;
if (!isXilinxCtb && !test_info.ten_giga) {
inputs.adcMask = test_info.adc_enable_1g;
}
inputs.nTransceiverSamples = test_info.num_trans_samples;
inputs.transceiverMask = test_info.transceiver_mask;
inputs.nDigitalSamples = test_info.num_dbit_samples;
inputs.dbitOffset = test_info.dbit_offset;
inputs.dbitReorder = test_info.dbit_reorder;
inputs.dbitList = test_info.dbit_list;
auto out = computeCtbImageSize(inputs);
uint64_t image_size =
out.nAnalogBytes + out.nDigitalBytes + out.nTransceiverBytes;
LOG(logDEBUG1) << "Expected image size: " << image_size;
int npixelx = out.nPixelsX;
LOG(logDEBUG1) << "Expected number of pixels in x: " << npixelx;
return std::make_pair(image_size, npixelx);
}
} // namespace sls::test::acquire
@@ -135,4 +135,14 @@ class CTBStateGuard {
CTBState saved_;
};
/**
* @brief
* @param test_info current CTB state
* @param isXilinxCtb if the detector type is Xilinx CTB
* @return std::pair<uint64_t, int> pair of image size in bytes and number of
* channels in dimension X (Currently only analog channels)
*/
std::pair<uint64_t, int> calculate_ctb_image_size(const CTBState &test_info,
bool isXilinxCtb);
} // namespace sls::test::acquire
@@ -2,7 +2,6 @@
// Copyright (C) 2021 Contributors to the SLS Detector Package
#include "ExpectedState.h"
#include "Caller/test-Caller-global.h"
#include "receiver_defs.h"
// unnamed namespace for internal linkage
@@ -47,7 +46,7 @@ defs::xy get_port_shape(const Detector &det,
"CTB state must be provided to calculate expected port shape");
}
portSize.x =
sls::calculate_ctb_image_size(
acq::calculate_ctb_image_size(
ctb_state.value(), det_type == defs::XILINX_CHIPTESTBOARD)
.second;
portSize.y = 1;
@@ -136,6 +135,14 @@ int get_num_udp_interfaces(const Detector &det) {
"Inconsistent number of UDP interfaces");
}
std::vector<defs::portPosition> get_udp_port_types(const Detector &det) {
return det.getPortPositionList();
}
std::vector<int> get_udp_ports_disabled(const Detector &det) {
return det.getRxDisabledUDPPortIndices();
}
int get_read_n_rows(const Detector &det) {
return det.getReadNRows().tsquash("Inconsistent number of read rows");
}
@@ -184,6 +191,10 @@ acq::JungfrauExpectedState build_jungfrau_specific_state(const Detector &det) {
e.exptime = get_exptime(det);
e.period = get_period(det);
e.num_udp_interfaces = get_num_udp_interfaces(det);
if (e.num_udp_interfaces == 2) {
e.udp_port_types = get_udp_port_types(det);
e.udp_ports_disabled = get_udp_ports_disabled(det);
}
e.read_n_rows = get_read_n_rows(det);
e.readout_speed = get_readout_speed(det);
return e;
@@ -195,6 +206,10 @@ acq::MoenchExpectedState build_moench_specific_state(const Detector &det) {
e.exptime = get_exptime(det);
e.period = get_period(det);
e.num_udp_interfaces = get_num_udp_interfaces(det);
if (e.num_udp_interfaces == 2) {
e.udp_port_types = get_udp_port_types(det);
e.udp_ports_disabled = get_udp_ports_disabled(det);
}
e.read_n_rows = get_read_n_rows(det);
e.readout_speed = get_readout_speed(det);
return e;
@@ -213,6 +228,8 @@ acq::EigerExpectedState build_eiger_specific_state(const Detector &det) {
e.sub_exptime = sub_exptime;
e.sub_period = sub_period;
e.quad = det.getQuad().tsquash("Inconsistent quad setting");
e.udp_port_types = get_udp_port_types(det);
e.udp_ports_disabled = get_udp_ports_disabled(det);
e.read_n_rows = get_read_n_rows(det);
{
for (auto item : det.getRateCorrection())
@@ -342,7 +359,7 @@ int get_expected_image_size(const Detector &det,
}
LOG(logINFORED) << ctb_state.value();
image_size =
sls::calculate_ctb_image_size(
acq::calculate_ctb_image_size(
ctb_state.value(), (det_type == defs::XILINX_CHIPTESTBOARD))
.first;
break;
@@ -31,6 +31,8 @@ struct JungfrauExpectedState {
ns exptime{};
ns period{};
int num_udp_interfaces{};
std::vector<defs::portPosition> udp_port_types;
std::vector<int> udp_ports_disabled;
int read_n_rows{};
defs::speedLevel readout_speed{};
};
@@ -40,6 +42,8 @@ struct MoenchExpectedState {
ns exptime{};
ns period{};
int num_udp_interfaces{};
std::vector<defs::portPosition> udp_port_types;
std::vector<int> udp_ports_disabled;
int read_n_rows{};
defs::speedLevel readout_speed{};
};
@@ -54,6 +58,8 @@ struct EigerExpectedState {
ns sub_exptime{};
ns sub_period{};
bool quad{};
std::vector<defs::portPosition> udp_port_types;
std::vector<int> udp_ports_disabled;
int read_n_rows{};
std::vector<int64_t> rate_corrections{};
defs::speedLevel readout_speed{};
@@ -128,6 +128,22 @@ void check_num_udp_interfaces(CheckerT &checker, const int &value) {
value);
}
template <typename CheckerT>
void check_udp_ports_type(CheckerT &checker,
const std::vector<defs::portPosition> &value) {
REQUIRE(value.size() == 2);
std::vector<std::string> ports = {ToString(value[0]), ToString(value[1])};
checker.template check<std::vector<std::string>>(
MasterAttributes::N_UDP_PORTS_TYPE.data(), ports);
}
template <typename CheckerT>
void check_udp_ports_disabled(CheckerT &checker,
const std::vector<int> &value) {
checker.template check<std::vector<int>>(
MasterAttributes::N_UDP_PORTS_DISABLED.data(), value);
}
template <typename CheckerT>
void check_read_n_rows(CheckerT &checker, const int &value) {
checker.template check<int>(MasterAttributes::N_NUMBER_OF_ROWS.data(),
@@ -318,6 +334,10 @@ void check_jungfrau_metadata(CheckerT &checker,
check_exptime(checker, st.exptime);
check_period(checker, st.period);
check_num_udp_interfaces(checker, st.num_udp_interfaces);
if (st.num_udp_interfaces == 2) {
check_udp_ports_type(checker, st.udp_port_types);
check_udp_ports_disabled(checker, st.udp_ports_disabled);
}
check_read_n_rows(checker, st.read_n_rows);
check_readout_speed(checker, st.readout_speed);
}
@@ -331,6 +351,10 @@ void check_moench_metadata(CheckerT &checker,
check_exptime(checker, st.exptime);
check_period(checker, st.period);
check_num_udp_interfaces(checker, st.num_udp_interfaces);
if (st.num_udp_interfaces == 2) {
check_udp_ports_type(checker, st.udp_port_types);
check_udp_ports_disabled(checker, st.udp_ports_disabled);
}
check_read_n_rows(checker, st.read_n_rows);
check_readout_speed(checker, st.readout_speed);
}
@@ -349,6 +373,8 @@ void check_eiger_metadata(CheckerT &checker,
check_sub_exptime(checker, st.sub_exptime);
check_sub_period(checker, st.sub_period);
check_quad(checker, st.quad);
check_udp_ports_type(checker, st.udp_port_types);
check_udp_ports_disabled(checker, st.udp_ports_disabled);
check_read_n_rows(checker, st.read_n_rows);
check_rate_corrections(checker, st.rate_corrections);
check_readout_speed(checker, st.readout_speed);
@@ -238,6 +238,23 @@ template <> struct Reader<H5Context, std::array<ns, 3UL>> {
}
};
template <> struct Reader<H5Context, std::vector<int>> {
static std::vector<int> read(const H5Context &ctx, const std::string &name,
AccessType access) {
if (access == AccessType::Attribute) {
throw RuntimeError("'std::vector<int>' attribute access not "
"supported for HDF5");
}
require_dataset(ctx, name);
auto ds = ctx.file.openDataSet(HDF5_GROUP + name);
auto len = get_1d_size(ds);
std::vector<int> out{};
out.resize(len);
ds.read(out.data(), H5::PredType::NATIVE_INT);
return out;
}
};
template <> struct Reader<H5Context, std::vector<int64_t>> {
static std::vector<int64_t>
read(const H5Context &ctx, const std::string &name, AccessType access) {
@@ -255,6 +272,29 @@ template <> struct Reader<H5Context, std::vector<int64_t>> {
}
};
template <> struct Reader<H5Context, std::vector<std::string>> {
static std::vector<std::string>
read(const H5Context &ctx, const std::string &name, AccessType access) {
if (access == AccessType::Attribute) {
throw RuntimeError(
"'std::vector<std::string>' attribute access not "
"supported for HDF5");
}
require_dataset(ctx, name);
auto ds = ctx.file.openDataSet(HDF5_GROUP + name);
H5::StrType strType(H5::PredType::C_S1, H5T_VARIABLE);
std::vector<const char *> raw;
raw.resize(get_1d_size(ds));
ds.read(raw.data(), strType);
std::vector<std::string> out;
out.reserve(raw.size());
for (auto c : raw) {
out.emplace_back(c);
}
return out;
}
};
template <> struct Reader<H5Context, std::map<std::string, std::string>> {
static std::map<std::string, std::string>
read(const H5Context &ctx, const std::string &name, AccessType access) {
@@ -120,6 +120,17 @@ template <> struct Reader<JsonContext, std::array<ns, 3UL>> {
}
};
template <> struct Reader<JsonContext, std::vector<int>> {
static std::vector<int> read(const JsonContext &ctx,
const std::string &name, AccessType access) {
std::vector<int> out{};
for (const auto &item : ctx.doc[name.c_str()].GetArray()) {
out.push_back(item.GetInt());
}
return out;
}
};
template <> struct Reader<JsonContext, std::vector<int64_t>> {
static std::vector<int64_t>
read(const JsonContext &ctx, const std::string &name, AccessType access) {
@@ -131,6 +142,17 @@ template <> struct Reader<JsonContext, std::vector<int64_t>> {
}
};
template <> struct Reader<JsonContext, std::vector<std::string>> {
static std::vector<std::string>
read(const JsonContext &ctx, const std::string &name, AccessType access) {
std::vector<std::string> out{};
for (const auto &item : ctx.doc[name.c_str()].GetArray()) {
out.push_back(item.GetString());
}
return out;
}
};
template <> struct Reader<JsonContext, std::map<std::string, std::string>> {
static std::map<std::string, std::string>
read(const JsonContext &ctx, const std::string &name, AccessType access) {