Skip to content

Commit 8d8cd84

Browse files
authored
Merge pull request #38953 from mantidproject/38949-ornl-next
`NeXusIOHelper` using non-type templates and `enum` for Narrowing -- `ornl-next`
2 parents 1fd0b8b + 4249e77 commit 8d8cd84

File tree

3 files changed

+73
-96
lines changed

3 files changed

+73
-96
lines changed

Framework/DataHandling/src/LoadBankFromDiskTask.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ std::unique_ptr<std::vector<uint32_t>> LoadBankFromDiskTask::loadEventId(::NeXus
184184
auto event_id = std::make_unique<std::vector<uint32_t>>(dim0);
185185

186186
if (!m_loadError) {
187-
Mantid::NeXus::NeXusIOHelper::readNexusSlab<uint32_t, Mantid::NeXus::NeXusIOHelper::PreventNarrowing>(
187+
Mantid::NeXus::NeXusIOHelper::readNexusSlab<uint32_t, Mantid::NeXus::NeXusIOHelper::Narrowing::Prevent>(
188188
*event_id, file, m_detIdFieldName, m_loadStart, m_loadSize);
189189
file.closeData();
190190

@@ -248,7 +248,7 @@ std::unique_ptr<std::vector<float>> LoadBankFromDiskTask::loadTof(::NeXus::File
248248
// explicitly allow downcasting using the additional AllowDowncasting
249249
// template argument.
250250
// the memory is allocated earlier in the function
251-
Mantid::NeXus::NeXusIOHelper::readNexusSlab<float, Mantid::NeXus::NeXusIOHelper::AllowNarrowing>(
251+
Mantid::NeXus::NeXusIOHelper::readNexusSlab<float, Mantid::NeXus::NeXusIOHelper::Narrowing::Allow>(
252252
*event_time_of_flight, file, m_timeOfFlightFieldName, m_loadStart, m_loadSize);
253253
std::string tof_unit;
254254
file.getAttr("units", tof_unit);

Framework/Nexus/inc/MantidNexus/NexusIOHelper.h

Lines changed: 67 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -20,34 +20,33 @@ namespace Mantid {
2020
namespace NeXus {
2121
namespace NeXusIOHelper {
2222

23-
struct AllowNarrowing {};
24-
struct PreventNarrowing {};
23+
enum class Narrowing : bool { Allow = true, Prevent = false };
2524

2625
namespace {
2726

2827
/// Macro to run a function depending on the type of data in the Nexus file
29-
#define RUN_NEXUSIOHELPER_FUNCTION(Narrow, type, func_name, ...) \
28+
#define RUN_NEXUSIOHELPER_FUNCTION(narrow, type, func_name, ...) \
3029
switch (type) { \
3130
case NXnumtype::FLOAT32: \
32-
return func_name<T, float, Narrow>(__VA_ARGS__); \
31+
return func_name<T, float, narrow>(__VA_ARGS__); \
3332
case NXnumtype::FLOAT64: \
34-
return func_name<T, double, Narrow>(__VA_ARGS__); \
33+
return func_name<T, double, narrow>(__VA_ARGS__); \
3534
case NXnumtype::INT8: \
36-
return func_name<T, int8_t, Narrow>(__VA_ARGS__); \
35+
return func_name<T, int8_t, narrow>(__VA_ARGS__); \
3736
case NXnumtype::UINT8: \
38-
return func_name<T, uint8_t, Narrow>(__VA_ARGS__); \
37+
return func_name<T, uint8_t, narrow>(__VA_ARGS__); \
3938
case NXnumtype::INT16: \
40-
return func_name<T, int16_t, Narrow>(__VA_ARGS__); \
39+
return func_name<T, int16_t, narrow>(__VA_ARGS__); \
4140
case NXnumtype::UINT16: \
42-
return func_name<T, uint16_t, Narrow>(__VA_ARGS__); \
41+
return func_name<T, uint16_t, narrow>(__VA_ARGS__); \
4342
case NXnumtype::INT32: \
44-
return func_name<T, int32_t, Narrow>(__VA_ARGS__); \
43+
return func_name<T, int32_t, narrow>(__VA_ARGS__); \
4544
case NXnumtype::UINT32: \
46-
return func_name<T, uint32_t, Narrow>(__VA_ARGS__); \
45+
return func_name<T, uint32_t, narrow>(__VA_ARGS__); \
4746
case NXnumtype::INT64: \
48-
return func_name<T, int64_t, Narrow>(__VA_ARGS__); \
47+
return func_name<T, int64_t, narrow>(__VA_ARGS__); \
4948
case NXnumtype::UINT64: \
50-
return func_name<T, uint64_t, Narrow>(__VA_ARGS__); \
49+
return func_name<T, uint64_t, narrow>(__VA_ARGS__); \
5150
default: \
5251
throw std::runtime_error("NeXusIOHelper: Unknown type in Nexus file"); \
5352
}
@@ -67,135 +66,113 @@ std::pair<::NeXus::Info, bool> checkIfOpenAndGetInfo(::NeXus::File &file, const
6766
return info_and_close;
6867
}
6968

70-
/// Use the getData function to read the buffer into vector and close file if
71-
/// needed
72-
template <typename T> void callGetData(::NeXus::File &file, std::vector<T> &buf, const bool close_file) {
73-
file.getData(buf);
74-
if (close_file)
75-
file.closeData();
76-
}
77-
78-
/// Use the getData function to read the buffer and close file if needed
79-
template <typename T> void callGetData(::NeXus::File &file, T &buf, const bool close_file) {
80-
file.getData(&buf);
81-
if (close_file)
82-
file.closeData();
83-
}
84-
85-
/// Use the getSlab function to read the buffer and close file if needed
86-
template <typename T>
87-
void callGetSlab(::NeXus::File &file, std::vector<T> &buf, const std::vector<int64_t> &start,
88-
const std::vector<int64_t> &size, const bool close_file) {
89-
file.getSlab(buf.data(), start, size);
90-
if (close_file)
91-
file.closeData();
92-
}
93-
9469
/** Templated function to read any type of vector and (potentially) convert it
9570
* to another type. If the two types are the same, the conversion is skipped.
9671
*/
97-
template <typename T, typename U, typename Narrow>
98-
void doReadNexusAnyVector(std::vector<T> &out, ::NeXus::File &file, const size_t size, const bool close_file) {
99-
if constexpr (sizeof(T) < sizeof(U) && !std::is_same_v<Narrow, AllowNarrowing>) {
100-
if (close_file)
72+
template <typename T, typename U, Narrowing narrow>
73+
void doReadNexusAnyVector(std::vector<T> &out, ::NeXus::File &file, const size_t size, const bool close_data) {
74+
if constexpr (sizeof(T) < sizeof(U) && narrow == Narrowing::Prevent) {
75+
if (close_data)
10176
file.closeData();
10277
throw std::runtime_error("Narrowing is forbidden in NeXusIOHelper::readNexusAnyVector");
10378
} else if constexpr (std::is_same_v<T, U>) {
104-
if (size > 0)
105-
callGetData(file, out, close_file);
106-
else {
107-
if (close_file) {
108-
file.closeData();
109-
}
79+
if (size > 0) {
80+
file.getData(out);
11081
}
11182
} else {
11283
if (size > 0) {
11384
std::vector<U> buf(size);
114-
callGetData(file, buf, close_file);
85+
file.getData(buf);
11586
std::transform(buf.cbegin(), buf.cend(), out.begin(), [](U a) -> T { return static_cast<T>(a); });
116-
} else {
117-
if (close_file) {
118-
file.closeData();
119-
}
12087
}
12188
}
89+
if (close_data) {
90+
file.closeData();
91+
}
12292
}
12393

12494
/// Read any type of vector and return it as a new vector.
125-
template <typename T, typename U, typename Narrow>
126-
std::vector<T> readNexusAnyVector(::NeXus::File &file, const size_t size, const bool close_file) {
95+
template <typename T, typename U, Narrowing narrow>
96+
std::vector<T> readNexusAnyVector(::NeXus::File &file, const size_t size, const bool close_data) {
12797
std::vector<T> vec(size);
128-
doReadNexusAnyVector<T, U, Narrow>(vec, file, size, close_file);
98+
doReadNexusAnyVector<T, U, narrow>(vec, file, size, close_data);
12999
return vec;
130100
}
131101

132102
/// Read any type of vector and store it into the provided buffer vector.
133-
template <typename T, typename U, typename Narrow>
134-
void readNexusAnyVector(std::vector<T> &out, ::NeXus::File &file, const size_t size, const bool close_file) {
103+
template <typename T, typename U, Narrowing narrow>
104+
void readNexusAnyVector(std::vector<T> &out, ::NeXus::File &file, const size_t size, const bool close_data) {
135105
if (out.size() < size)
136106
throw std::runtime_error("The output buffer is too small in NeXusIOHelper::readNexusAnyVector");
137-
doReadNexusAnyVector<T, U, Narrow>(out, file, size, close_file);
107+
doReadNexusAnyVector<T, U, narrow>(out, file, size, close_data);
138108
}
139109

140110
/** Templated function to read any type of slab and (potentially) convert it to
141111
* another type. If the two types are the same, the conversion is skipped.
142112
*/
143-
template <typename T, typename U, typename Narrow>
113+
template <typename T, typename U, Narrowing narrow>
144114
void doReadNexusAnySlab(std::vector<T> &out, ::NeXus::File &file, const std::vector<int64_t> &start,
145-
const std::vector<int64_t> &size, const int64_t volume, const bool close_file) {
146-
if constexpr (sizeof(T) < sizeof(U) && !std::is_same_v<Narrow, AllowNarrowing>) {
147-
if (close_file)
115+
const std::vector<int64_t> &size, const int64_t volume, const bool close_data) {
116+
if constexpr (sizeof(T) < sizeof(U) && narrow == Narrowing::Prevent) {
117+
if (close_data)
148118
file.closeData();
149119
throw std::runtime_error("Narrowing is forbidden in NeXusIOHelper::readNexusAnySlab");
150120
} else if constexpr (std::is_same_v<T, U>) {
151-
if (volume > 0)
152-
callGetSlab(file, out, start, size, close_file);
121+
if (volume > 0) {
122+
file.getSlab(out.data(), start, size);
123+
}
153124
} else {
154125
if (volume > 0) {
155126
std::vector<U> buf(volume);
156-
callGetSlab(file, buf, start, size, close_file);
127+
file.getSlab(buf.data(), start, size);
157128
std::transform(buf.cbegin(), buf.cend(), out.begin(), [](U a) -> T { return static_cast<T>(a); });
158129
}
159130
}
131+
if (volume > 0 && close_data) {
132+
file.closeData();
133+
}
160134
}
161135

162136
/// Read any type of slab and return it as a new vector.
163-
template <typename T, typename U, typename Narrow>
137+
template <typename T, typename U, Narrowing narrow>
164138
std::vector<T> readNexusAnySlab(::NeXus::File &file, const std::vector<int64_t> &start,
165-
const std::vector<int64_t> &size, const bool close_file) {
139+
const std::vector<int64_t> &size, const bool close_data) {
166140
const auto volume = vectorVolume(size);
167141
std::vector<T> vec(volume);
168-
doReadNexusAnySlab<T, U, Narrow>(vec, file, start, size, volume, close_file);
142+
doReadNexusAnySlab<T, U, narrow>(vec, file, start, size, volume, close_data);
169143
return vec;
170144
}
171145

172146
/// Read any type of slab and store it into the provided buffer vector.
173-
template <typename T, typename U, typename Narrow>
147+
template <typename T, typename U, Narrowing narrow>
174148
void readNexusAnySlab(std::vector<T> &out, ::NeXus::File &file, const std::vector<int64_t> &start,
175-
const std::vector<int64_t> &size, const bool close_file) {
149+
const std::vector<int64_t> &size, const bool close_data) {
176150
const auto volume = vectorVolume(size);
177151
if (out.size() < static_cast<size_t>(volume))
178152
throw std::runtime_error("The output buffer is too small in NeXusIOHelper::readNexusAnySlab");
179-
doReadNexusAnySlab<T, U, Narrow>(out, file, start, size, volume, close_file);
153+
doReadNexusAnySlab<T, U, narrow>(out, file, start, size, volume, close_data);
180154
}
181155

182156
/** Templated function to read any type of variable and (potentially) convert it
183157
* to another type. If the two types are the same, the conversion is skipped.
184158
*/
185-
template <typename T, typename U, typename Narrow> T readNexusAnyVariable(::NeXus::File &file, const bool close_file) {
186-
if constexpr (sizeof(T) < sizeof(U) && !std::is_same_v<Narrow, AllowNarrowing>) {
187-
if (close_file)
159+
template <typename T, typename U, Narrowing narrow> T readNexusAnyVariable(::NeXus::File &file, const bool close_data) {
160+
T buf;
161+
if constexpr (sizeof(T) < sizeof(U) && narrow == Narrowing::Prevent) {
162+
if (close_data)
188163
file.closeData();
189164
throw std::runtime_error("Narrowing is forbidden in NeXusIOHelper::readAnyVariable");
190165
} else if constexpr (std::is_same_v<T, U>) {
191-
T buf;
192-
callGetData(file, buf, close_file);
193-
return buf;
166+
file.getData(&buf);
194167
} else {
195-
U buf;
196-
callGetData(file, buf, close_file);
197-
return static_cast<T>(buf);
168+
U bufu;
169+
file.getData(&bufu);
170+
buf = std::move(static_cast<T>(bufu));
171+
}
172+
if (close_data) {
173+
file.closeData();
198174
}
175+
return buf;
199176
}
200177

201178
} // end of anonymous namespace
@@ -204,51 +181,51 @@ template <typename T, typename U, typename Narrow> T readNexusAnyVariable(::NeXu
204181
* and calls readNexusAnyVector via the RUN_NEXUSIOHELPER_FUNCTION macro.
205182
* Version that allows Narrowing.
206183
*/
207-
template <typename T, typename Narrow = PreventNarrowing>
184+
template <typename T, Narrowing narrow = Narrowing::Prevent>
208185
std::vector<T> readNexusVector(::NeXus::File &file, const std::string &entry = "") {
209186
const auto info_and_close = checkIfOpenAndGetInfo(file, std::move(std::move(entry)));
210-
RUN_NEXUSIOHELPER_FUNCTION(Narrow, (info_and_close.first).type, readNexusAnyVector, file,
187+
RUN_NEXUSIOHELPER_FUNCTION(narrow, (info_and_close.first).type, readNexusAnyVector, file,
211188
vectorVolume((info_and_close.first).dims), info_and_close.second);
212189
}
213190

214191
/** Opens the data group if needed, finds the data type, computes the data size,
215192
* and calls readNexusAnyVector via the RUN_NEXUSIOHELPER_FUNCTION macro.
216193
* The provided output buffer is filled.
217194
*/
218-
template <typename T, typename Narrow = PreventNarrowing>
195+
template <typename T, Narrowing narrow = Narrowing::Prevent>
219196
void readNexusVector(std::vector<T> &out, ::NeXus::File &file, const std::string &entry = "") {
220197
const auto info_and_close = checkIfOpenAndGetInfo(file, std::move(std::move(entry)));
221-
RUN_NEXUSIOHELPER_FUNCTION(Narrow, (info_and_close.first).type, readNexusAnyVector, out, file,
198+
RUN_NEXUSIOHELPER_FUNCTION(narrow, (info_and_close.first).type, readNexusAnyVector, out, file,
222199
vectorVolume((info_and_close.first).dims), info_and_close.second);
223200
}
224201

225202
/** Opens the data group if needed, finds the data type, and calls
226203
* readNexusAnySlab via the RUN_NEXUSIOHELPER_FUNCTION macro.
227204
*/
228-
template <typename T, typename Narrow = PreventNarrowing>
205+
template <typename T, Narrowing narrow = Narrowing::Prevent>
229206
std::vector<T> readNexusSlab(::NeXus::File &file, const std::string &entry, const std::vector<int64_t> &start,
230207
const std::vector<int64_t> &size) {
231208
const auto info_and_close = checkIfOpenAndGetInfo(file, std::move(std::move(entry)));
232-
RUN_NEXUSIOHELPER_FUNCTION(Narrow, (info_and_close.first).type, readNexusAnySlab, file, start, size,
209+
RUN_NEXUSIOHELPER_FUNCTION(narrow, (info_and_close.first).type, readNexusAnySlab, file, start, size,
233210
info_and_close.second);
234211
}
235212

236213
/** Opens the data group if needed, finds the data type, and calls
237214
* readNexusAnySlab via the RUN_NEXUSIOHELPER_FUNCTION macro.
238215
* The provided output buffer is filled.
239216
*/
240-
template <typename T, typename Narrow = PreventNarrowing>
217+
template <typename T, Narrowing narrow = Narrowing::Prevent>
241218
void readNexusSlab(std::vector<T> &out, ::NeXus::File &file, const std::string &entry,
242219
const std::vector<int64_t> &start, const std::vector<int64_t> &size) {
243220
const auto info_and_close = checkIfOpenAndGetInfo(file, std::move(std::move(entry)));
244-
RUN_NEXUSIOHELPER_FUNCTION(Narrow, (info_and_close.first).type, readNexusAnySlab, out, file, start, size,
221+
RUN_NEXUSIOHELPER_FUNCTION(narrow, (info_and_close.first).type, readNexusAnySlab, out, file, start, size,
245222
info_and_close.second);
246223
}
247224

248-
template <typename T, typename Narrow = PreventNarrowing>
225+
template <typename T, Narrowing narrow = Narrowing::Prevent>
249226
T readNexusValue(::NeXus::File &file, const std::string &entry = "") {
250227
const auto info_and_close = checkIfOpenAndGetInfo(file, std::move(std::move(entry)));
251-
RUN_NEXUSIOHELPER_FUNCTION(Narrow, (info_and_close.first).type, readNexusAnyVariable, file, info_and_close.second);
228+
RUN_NEXUSIOHELPER_FUNCTION(narrow, (info_and_close.first).type, readNexusAnyVariable, file, info_and_close.second);
252229
}
253230

254231
} // namespace NeXusIOHelper

Framework/Nexus/test/NexusIOHelperTest.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,16 +91,16 @@ class NexusIOHelperTest : public CxxTest::TestSuite {
9191
::NeXus::File file(filename);
9292
file.openGroup("entry", "NXentry");
9393
file.openGroup("raw_event_data", "NXevent_data");
94-
auto event_index = Nioh::readNexusVector<uint32_t, Nioh::AllowNarrowing>(file, "event_index");
94+
auto event_index = Nioh::readNexusVector<uint32_t, Nioh::Narrowing::Allow>(file, "event_index");
9595
TS_ASSERT_EQUALS(event_index.size(), 1439);
9696
TS_ASSERT_EQUALS(event_index[100], 100);
97-
auto event_id = Nioh::readNexusVector<uint32_t, Nioh::AllowNarrowing>(file, "event_id");
97+
auto event_id = Nioh::readNexusVector<uint32_t, Nioh::Narrowing::Allow>(file, "event_id");
9898
TS_ASSERT_EQUALS(event_id.size(), 1439);
9999
TS_ASSERT_EQUALS(event_id[100], 3843);
100-
auto event_time_offset = Nioh::readNexusVector<uint16_t, Nioh::AllowNarrowing>(file, "event_time_offset");
100+
auto event_time_offset = Nioh::readNexusVector<uint16_t, Nioh::Narrowing::Allow>(file, "event_time_offset");
101101
TS_ASSERT_EQUALS(event_time_offset.size(), 1439);
102102
TS_ASSERT_EQUALS(event_time_offset[100], 0.);
103-
auto event_time_zero = Nioh::readNexusVector<float, Nioh::AllowNarrowing>(file, "event_time_zero");
103+
auto event_time_zero = Nioh::readNexusVector<float, Nioh::Narrowing::Allow>(file, "event_time_zero");
104104
TS_ASSERT_EQUALS(event_time_zero.size(), 1439);
105105
TS_ASSERT_DIFFERS(event_time_zero[100], 1543584891250635008.0);
106106
file.closeGroup();

0 commit comments

Comments
 (0)