Skip to content

Commit 3255bc3

Browse files
committed
Reduce implementation sizes for RequireScalar / RequireVector
1 parent bf9cac6 commit 3255bc3

6 files changed

Lines changed: 167 additions & 89 deletions

File tree

include/openPMD/auxiliary/TypeTraits.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ inline constexpr bool IsChar_v = detail::IsChar<C>::value;
160160
template <typename T>
161161
using ScalarType_t = typename detail::ScalarType<T>::type;
162162

163+
template <typename T>
164+
using VectorType_t = std::vector<ScalarType_t<T>>;
165+
163166
/** Emulate in the C++ concept ContiguousContainer
164167
*
165168
* Users can implement this trait for a type to signal it can be used as

include/openPMD/backend/Attributable.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ class Attributable
278278
template <typename T>
279279
bool setAttribute(std::string const &key, T value);
280280
bool setAttribute(std::string const &key, char const value[]);
281+
bool setAttribute(std::string const &key, Attribute value);
281282
/** @}
282283
*/
283284

include/openPMD/backend/Attribute.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ class Attribute
117117

118118
template <typename U>
119119
std::variant<U, std::runtime_error> getOrError() const;
120+
121+
[[nodiscard]] std::variant<Attribute, std::runtime_error>
122+
requireVector() const;
123+
[[nodiscard]] std::variant<Attribute, std::runtime_error>
124+
requireScalar() const;
120125
};
121126

122127
namespace detail

src/backend/Attributable.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,36 @@ Attributable::Attributable()
7272
Attributable::Attributable(NoInit) noexcept
7373
{}
7474

75+
bool Attributable::setAttribute(std::string const &key, Attribute attribute)
76+
{
77+
auto &attri = get();
78+
if (IOHandler() &&
79+
IOHandler()->m_seriesStatus == internal::SeriesStatus::Default &&
80+
Access::READ_ONLY == IOHandler()->m_frontendAccess)
81+
{
82+
auxiliary::OutOfRangeMsg const out_of_range_msg(
83+
"Attribute", "can not be set (read-only).");
84+
error::throwNoSuchAttribute(out_of_range_msg(key));
85+
}
86+
87+
setDirty(true);
88+
auto it = attri.m_attributes.lower_bound(key);
89+
if (it != attri.m_attributes.end() &&
90+
!attri.m_attributes.key_comp()(key, it->first))
91+
{
92+
// key already exists in map, just replace the value
93+
it->second = std::move(attribute);
94+
return true;
95+
}
96+
else
97+
{
98+
// emplace a new map element for an unknown key
99+
attri.m_attributes.emplace_hint(
100+
it, std::make_pair(key, std::move(attribute)));
101+
return false;
102+
}
103+
}
104+
75105
Attribute Attributable::getAttribute(std::string const &key) const
76106
{
77107
auto &attri = get();

src/backend/Attribute.cpp

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,107 @@ std::optional<U> Attribute::getOptional() const
148148
std::move(res));
149149
}
150150

151+
template <typename is_type>
152+
std::variant<Attribute, std::runtime_error>
153+
requireVector_impl(Attribute const &attr, attribute_types const &variant)
154+
{
155+
using res_t = std::variant<Attribute, std::runtime_error>;
156+
if constexpr (auxiliary::IsVector_v<is_type>)
157+
{
158+
return attr;
159+
}
160+
else if constexpr (auxiliary::IsArray_v<is_type>)
161+
{
162+
using target_type = auxiliary::VectorType_t<is_type>;
163+
auto maybe_res = detail::doConvert<is_type, target_type>(
164+
&std::get<is_type>(variant));
165+
return std::visit(
166+
auxiliary::overloaded{
167+
[](target_type val) -> res_t {
168+
return Attribute(std::move(val));
169+
},
170+
[](std::runtime_error err) -> res_t { return err; }},
171+
maybe_res);
172+
}
173+
else if constexpr (std::is_same_v<is_type, bool>)
174+
{
175+
return std::runtime_error("Cannot cast bool to a vector is_type.");
176+
}
177+
else
178+
{
179+
return Attribute(std::vector<is_type>{std::get<is_type>(variant)});
180+
}
181+
}
182+
183+
std::variant<Attribute, std::runtime_error> Attribute::requireVector() const
184+
{
185+
auto variant = Variant::getVariant<attribute_types>();
186+
size_t index = variant.index();
187+
188+
#define OPENPMD_ENUMERATE_TYPES(type) \
189+
case datatypeIndex<type>(): { \
190+
return requireVector_impl<type>(*this, variant); \
191+
break; \
192+
}
193+
194+
switch (index)
195+
{
196+
OPENPMD_FOREACH_DATATYPE(OPENPMD_ENUMERATE_TYPES)
197+
default:
198+
return {std::runtime_error("Unreachable!")};
199+
}
200+
#undef OPENPMD_ENUMERATE_TYPES
201+
202+
return {std::runtime_error("Unreachable!")};
203+
}
204+
205+
template <typename is_type>
206+
std::variant<Attribute, std::runtime_error>
207+
requireScalar_impl(Attribute const &attr, attribute_types const &variant)
208+
{
209+
using res_t = std::variant<Attribute, std::runtime_error>;
210+
if constexpr (
211+
auxiliary::IsVector_v<is_type> || auxiliary::IsArray_v<is_type>)
212+
{
213+
using target_type = auxiliary::ScalarType_t<is_type>;
214+
auto maybe_res = detail::doConvert<is_type, target_type>(
215+
&std::get<is_type>(variant));
216+
return std::visit(
217+
auxiliary::overloaded{
218+
[](target_type val) -> res_t {
219+
return Attribute(std::move(val));
220+
},
221+
[](std::runtime_error err) -> res_t { return err; }},
222+
maybe_res);
223+
}
224+
else
225+
{
226+
return attr;
227+
}
228+
}
229+
230+
std::variant<Attribute, std::runtime_error> Attribute::requireScalar() const
231+
{
232+
auto variant = Variant::getVariant<attribute_types>();
233+
size_t index = variant.index();
234+
235+
#define OPENPMD_ENUMERATE_TYPES(type) \
236+
case datatypeIndex<type>(): { \
237+
return requireScalar_impl<type>(*this, variant); \
238+
break; \
239+
}
240+
241+
switch (index)
242+
{
243+
OPENPMD_FOREACH_DATATYPE(OPENPMD_ENUMERATE_TYPES)
244+
default:
245+
return {std::runtime_error("Unreachable!")};
246+
}
247+
#undef OPENPMD_ENUMERATE_TYPES
248+
249+
return {std::runtime_error("Unreachable!")};
250+
}
251+
151252
#define OPENPMD_INSTANTIATE(type) \
152253
template type Attribute::get() const; \
153254
template std::optional<type> Attribute::getOptional() const;

src/backend/ScientificDefaults.cpp

Lines changed: 27 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#include <iostream>
2929
#include <optional>
30+
#include <stdexcept>
3031
#include <type_traits>
3132
#include <utility>
3233

@@ -328,113 +329,50 @@ void ScientificDefaults<Child>::addDefaultsRecursively(OpenpmdStandard standard)
328329
}
329330
}
330331

331-
template <typename T>
332-
struct to_scalar
333-
{
334-
using type = T;
335-
};
336-
template <typename T>
337-
struct to_scalar<std::vector<T>>
338-
{
339-
using type = T;
340-
};
341-
template <typename T, size_t N>
342-
struct to_scalar<std::array<T, N>>
343-
{
344-
using type = T;
345-
};
346-
347332
// 2, 0.0976562
348333
auto RequireScalar::operator()(
349334
Attributable &record, char const *attrName, Attribute const &attr)
350335
-> std::optional<error::ReadError>
351336
{
337+
auto res = attr.requireScalar();
338+
using res_t = std::optional<error::ReadError>;
352339
return std::visit(
353-
[&](auto const &attr_val) -> std::optional<error::ReadError> {
354-
using actual_type =
355-
std::remove_cv_t<std::remove_reference_t<decltype(attr_val)>>;
356-
using target_type = typename to_scalar<actual_type>::type;
357-
auto converted_or_error = attr.getOrError<target_type>();
358-
return std::visit(
359-
auxiliary::overloaded{
360-
[&](target_type casted_val)
361-
-> std::optional<error::ReadError> {
362-
record.setAttribute<target_type>(
363-
attrName, std::move(casted_val));
364-
return std::nullopt;
365-
},
366-
[](std::runtime_error const &err)
367-
-> std::optional<error::ReadError> {
368-
return error::ReadError(
369-
error::AffectedObject::Attribute,
370-
error::Reason::UnexpectedContent,
371-
std::nullopt,
372-
std::string("Expected a scalar type: ") +
373-
err.what());
374-
}},
375-
converted_or_error);
376-
},
377-
attr.getVariant<attribute_types>());
340+
auxiliary::overloaded{
341+
[](std::runtime_error const &err) -> res_t {
342+
return error::ReadError(
343+
error::AffectedObject::Attribute,
344+
error::Reason::UnexpectedContent,
345+
std::nullopt,
346+
std::string("Expected a scalar type: ") + err.what());
347+
},
348+
[&](Attribute converted_attr) -> res_t {
349+
record.setAttribute(attrName, std::move(converted_attr));
350+
return std::nullopt;
351+
}},
352+
std::move(res));
378353
}
379354

380-
template <typename T>
381-
struct to_vector
382-
{
383-
using type = std::vector<T>;
384-
};
385-
template <typename T>
386-
struct to_vector<std::vector<T>>
387-
{
388-
using type = std::vector<T>;
389-
};
390-
template <typename T, size_t N>
391-
struct to_vector<std::array<T, N>>
392-
{
393-
using type = std::vector<T>;
394-
};
395-
396355
// 1, 0.113281
397356
auto RequireVector::operator()(
398357
Attributable &record, char const *attrName, Attribute const &attr)
399358
-> std::optional<error::ReadError>
400359
{
360+
auto res = attr.requireVector();
361+
using res_t = std::optional<error::ReadError>;
401362
return std::visit(
402-
[&](auto const &attr_val) -> std::optional<error::ReadError> {
403-
using actual_type =
404-
std::remove_cv_t<std::remove_reference_t<decltype(attr_val)>>;
405-
if constexpr (std::is_same_v<bool, actual_type>)
406-
{
363+
auxiliary::overloaded{
364+
[](std::runtime_error const &err) -> res_t {
407365
return error::ReadError(
408366
error::AffectedObject::Attribute,
409367
error::Reason::UnexpectedContent,
410368
std::nullopt,
411-
"Expected a vector type, found a boolean.");
412-
}
413-
else
414-
{
415-
using target_type = typename to_vector<actual_type>::type;
416-
auto converted_or_error = attr.getOrError<target_type>();
417-
return std::visit(
418-
auxiliary::overloaded{
419-
[&](target_type casted_val)
420-
-> std::optional<error::ReadError> {
421-
record.setAttribute<target_type>(
422-
attrName, std::move(casted_val));
423-
return std::nullopt;
424-
},
425-
[](std::runtime_error const &err)
426-
-> std::optional<error::ReadError> {
427-
return error::ReadError(
428-
error::AffectedObject::Attribute,
429-
error::Reason::UnexpectedContent,
430-
std::nullopt,
431-
std::string("Expected a scalar type: ") +
432-
err.what());
433-
}},
434-
converted_or_error);
435-
}
436-
},
437-
attr.getVariant<attribute_types>());
369+
std::string("Expected a vector type: ") + err.what());
370+
},
371+
[&](Attribute converted_attr) -> res_t {
372+
record.setAttribute(attrName, std::move(converted_attr));
373+
return std::nullopt;
374+
}},
375+
std::move(res));
438376
}
439377

440378
// 3, 0.0117188

0 commit comments

Comments
 (0)