Skip to content

Commit 185ceb3

Browse files
authored
Merge pull request #718 from sebproell/enum-tools
Put magic_enum reflection into EnumTools namespace
2 parents 5153454 + d7a8b77 commit 185ceb3

20 files changed

+82
-69
lines changed

doc/documentation/src/developer_guide/codingguidelines.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,9 @@ Enums
8282
- By default, use scoped ``enum class`` instead of unscoped ``enum``.
8383
- Use enums instead of strings for parameters that take one from a fixed set of values.
8484
- You do not have to write conversion functions between enum constants and strings.
85-
Use ``magic_enum::enum_name`` to get the name of an enum constant and ``magic_enum::enum_cast`` to convert a string to
86-
an enum constant.
85+
Use ``EnumTools::enum_name`` to get the name of an enum constant and ``EnumTools::enum_cast`` to convert a string to
86+
an enum constant. ``EnumTools::operator<<`` and ``EnumTools::operator>>`` allow for easy interaction
87+
with std streams.
8788

8889
See also `Enum.3 <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#enum3-prefer-class-enums-over-plain-enums>`_.
8990

src/core/io/src/4C_io_input_parameter_container.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ namespace Core::IO
5656
/**
5757
* \brief Add @data to the container at the given key @name.
5858
*
59-
* If an entry with given @p name already exists, it will be overwritten.
59+
* If an entry with given @p name already exists, it will be overwritten. The type must be
60+
* one of the SupportedType of the input framework.
6061
*/
6162
template <typename T>
6263
void add(const std::string& name, const T& data);
@@ -77,7 +78,7 @@ namespace Core::IO
7778
[[nodiscard]] auto groups() const;
7879

7980
/**
80-
* Check if a group with the name @p name exists.
81+
* Check if a group with the given @p name exists.
8182
*/
8283
[[nodiscard]] bool has_group(const std::string& name) const;
8384

src/core/io/src/4C_io_input_parameter_container.templates.hpp

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,34 @@ FOUR_C_NAMESPACE_OPEN
2222
// into this special templates file.
2323
namespace Core::IO::Internal::InputParameterContainerImplementation
2424
{
25-
// Default printer if not printable.
2625
template <typename T>
27-
struct PrintHelper
28-
{
29-
void operator()(std::ostream& os, const std::any& data) { os << "<not printable> "; }
26+
concept StreamInsertable = requires(std::ostream& os, const std::any& data) {
27+
{ os << std::any_cast<T>(data) };
3028
};
3129

30+
// Helper struct to print the data in the container.
3231
template <typename T>
33-
concept StreamInsertable = requires(std::ostream& os, const T& t) { os << t; };
34-
35-
// Specialization for stream insert.
36-
template <StreamInsertable T>
37-
struct PrintHelper<T>
32+
struct PrintHelper
3833
{
39-
void operator()(std::ostream& os, const std::any& data) { os << std::any_cast<T>(data) << " "; }
34+
void operator()(std::ostream& os, const std::any& data) const
35+
{
36+
if constexpr (StreamInsertable<std::remove_reference_t<T>> || std::is_enum_v<T>)
37+
{
38+
using EnumTools::operator<<;
39+
os << std::any_cast<T>(data) << " ";
40+
}
41+
else
42+
{
43+
os << "<not printable> ";
44+
}
45+
}
4046
};
4147

42-
template <StreamInsertable T>
48+
// Specialization for std::optional.
49+
template <SupportedType T>
4350
struct PrintHelper<std::optional<T>>
4451
{
45-
void operator()(std::ostream& os, const std::any& data)
52+
void operator()(std::ostream& os, const std::any& data) const
4653
{
4754
auto val = std::any_cast<std::optional<T>>(data);
4855
if (val.has_value())
@@ -53,10 +60,10 @@ namespace Core::IO::Internal::InputParameterContainerImplementation
5360
};
5461

5562
// Specialization for vectors.
56-
template <typename T>
63+
template <SupportedType T>
5764
struct PrintHelper<std::vector<T>>
5865
{
59-
void operator()(std::ostream& os, const std::any& data)
66+
void operator()(std::ostream& os, const std::any& data) const
6067
{
6168
FOUR_C_ASSERT(typeid(std::vector<T>) == data.type(), "Implementation error.");
6269
const auto& vec = std::any_cast<std::vector<T>>(data);
@@ -68,10 +75,10 @@ namespace Core::IO::Internal::InputParameterContainerImplementation
6875
};
6976

7077
// Specialization for maps.
71-
template <typename Key, typename Value>
78+
template <typename Key, SupportedType Value>
7279
struct PrintHelper<std::map<Key, Value>>
7380
{
74-
void operator()(std::ostream& os, const std::any& data)
81+
void operator()(std::ostream& os, const std::any& data) const
7582
{
7683
FOUR_C_ASSERT(typeid(std::map<Key, Value>) == data.type(), "Implementation error.");
7784
const auto& map = std::any_cast<std::map<Key, Value>>(data);

src/core/io/src/4C_io_input_spec_builders.hpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ namespace Core::IO
4545
template <SupportedType T>
4646
void operator()(std::ostream& out, const T& val) const
4747
{
48-
using magic_enum::iostream_operators::operator<<;
48+
using EnumTools::operator<<;
4949
out << val;
5050
}
5151

@@ -118,7 +118,7 @@ namespace Core::IO
118118
requires(std::is_enum_v<Enum>)
119119
struct PrettyTypeName<Enum>
120120
{
121-
std::string operator()() { return std::string{magic_enum::enum_type_name<Enum>()}; }
121+
std::string operator()() { return std::string{EnumTools::enum_type_name<Enum>()}; }
122122
};
123123

124124
template <typename T>
@@ -174,7 +174,7 @@ namespace Core::IO
174174
FOUR_C_ASSERT(node.is_map(), "Expected a map node.");
175175
node["type"] = "enum";
176176
node["choices"] |= ryml::SEQ;
177-
for (const auto& choice_string : magic_enum::enum_values<Enum>())
177+
for (const auto& choice_string : EnumTools::enum_values<Enum>())
178178
{
179179
auto entry = node["choices"].append_child();
180180
// Write every choice entry as a map to easily extend the information at a later point.
@@ -1445,7 +1445,7 @@ bool Core::IO::Internal::ParameterSpec<T>::match(ConstYamlNodeRef node,
14451445
if constexpr (std::is_enum_v<T>)
14461446
{
14471447
std::string choices_string;
1448-
for (const auto& e : magic_enum::enum_names<T>())
1448+
for (const auto& e : EnumTools::enum_names<T>())
14491449
{
14501450
choices_string += std::string(e) + "|";
14511451
}
@@ -1850,7 +1850,7 @@ void Core::IO::Internal::SelectionSpec<T>::print(std::ostream& stream, std::size
18501850
{
18511851
stream << "\n";
18521852
stream << "//" << std::string(indent + 2, ' ') << " if value of " << based_on.selector << " is "
1853-
<< magic_enum::enum_name<T>(selector_value);
1853+
<< EnumTools::enum_name<T>(selector_value);
18541854
spec.impl().print(stream, indent + 4);
18551855
}
18561856
stream << "\n";
@@ -1973,12 +1973,12 @@ Core::IO::InputSpec Core::IO::InputSpecBuilders::selection(
19731973
std::string name, Internal::BasedOn<T> based_on, SelectionData data)
19741974
{
19751975
// Ensure that every enum constant is mapped to a spec.
1976-
for (const auto& e : magic_enum::enum_values<T>())
1976+
for (const auto& e : EnumTools::enum_values<T>())
19771977
{
19781978
FOUR_C_ASSERT_ALWAYS(based_on.choices.contains(e),
19791979
"You need to give an InputSpec for every possible value of enum '{}'. Missing "
19801980
"choice for enum constant '{}'.",
1981-
magic_enum::enum_type_name<T>(), magic_enum::enum_name(e));
1981+
EnumTools::enum_type_name<T>(), EnumTools::enum_name(e));
19821982
}
19831983

19841984
std::size_t max_specs_for_choices = std::ranges::max_element(

src/core/io/src/4C_io_value_parser.hpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@
1212

1313
#include "4C_io_input_types.hpp"
1414
#include "4C_utils_demangle.hpp"
15+
#include "4C_utils_enum.hpp"
1516
#include "4C_utils_exceptions.hpp"
1617

17-
#include <magic_enum/magic_enum.hpp>
18-
1918
#include <array>
2019
#include <filesystem>
2120
#include <format>
@@ -199,15 +198,15 @@ namespace Core::IO
199198
{
200199
std::string string;
201200
read_internal(string);
202-
auto val = magic_enum::enum_cast<Enum>(string);
201+
auto val = EnumTools::enum_cast<Enum>(string);
203202
if (val)
204203
{
205204
value = *val;
206205
}
207206
else
208207
{
209208
FOUR_C_THROW("Could not parse value '{}' as an enum constant of type '{}'.", string,
210-
magic_enum::enum_type_name<Enum>());
209+
EnumTools::enum_type_name<Enum>());
211210
}
212211
}
213212

src/core/io/src/4C_io_yaml.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010

1111
#include "4C_config.hpp"
1212

13+
#include "4C_utils_enum.hpp"
1314
#include "4C_utils_exceptions.hpp"
1415

15-
#include <magic_enum/magic_enum.hpp>
1616
#include <ryml.hpp> // IWYU pragma: export
1717
#include <ryml_std.hpp> // IWYU pragma: export
1818

@@ -173,15 +173,15 @@ namespace Core::IO
173173
{
174174
FOUR_C_ASSERT_ALWAYS(node.node.has_val(), "Expected a value node.");
175175
auto substr = node.node.val();
176-
auto val = magic_enum::enum_cast<T>(std::string_view(substr.data(), substr.size()));
176+
auto val = EnumTools::enum_cast<T>(std::string_view(substr.data(), substr.size()));
177177
if (val)
178178
{
179179
value = *val;
180180
}
181181
else
182182
{
183183
FOUR_C_THROW("Could not parse value '{}' as an enum constant of type '{}'.",
184-
std::string_view(substr.data(), substr.size()), magic_enum::enum_type_name<T>());
184+
std::string_view(substr.data(), substr.size()), EnumTools::enum_type_name<T>());
185185
}
186186
}
187187

@@ -233,7 +233,7 @@ template <typename T>
233233
requires(std::is_enum_v<T>)
234234
void Core::IO::emit_value_as_yaml(YamlNodeRef node, const T& value)
235235
{
236-
std::string_view str = magic_enum::enum_name(value);
236+
std::string_view str = EnumTools::enum_name(value);
237237
node.node << ryml::csubstr(str.data(), str.size());
238238
}
239239

src/core/linalg/src/dense/4C_linalg_utils_densematrix_funct.hpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@ exponential and the logarithm, along with specific derivatives in namespace Core
2323
#include "4C_linalg_fixedsizematrix.hpp"
2424
#include "4C_linalg_utils_densematrix_eigen.hpp"
2525

26-
#include <magic_enum/magic_enum.hpp>
27-
28-
#include <cstddef>
2926
#include <optional>
3027

3128
FOUR_C_NAMESPACE_OPEN

src/core/linalg/src/dense/4C_linalg_utils_tensor_interpolation.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ Core::LinAlg::TensorInterpolation::SecondOrderTensorInterpolator<loc_dim>::get_i
573573
FOUR_C_THROW(
574574
"We do not have an implementation for RotationInterpolationType {} and EigenvalInterpType "
575575
"{}!",
576-
magic_enum::enum_name(rot_interp_type_), magic_enum::enum_name(eigenval_interp_type_));
576+
rot_interp_type_, eigenval_interp_type_);
577577
}
578578
return output;
579579
}

src/core/linalg/src/dense/4C_linalg_utils_tensor_interpolation.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
#include "4C_utils_enum.hpp"
1717
#include "4C_utils_exceptions.hpp"
1818

19-
#include <magic_enum/magic_enum.hpp>
20-
2119
FOUR_C_NAMESPACE_OPEN
2220

2321
namespace Core::LinAlg

src/core/utils/src/stl_extension/4C_utils_enum.hpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,24 @@
1616
// 2) Include magic_enum header.
1717
#include <magic_enum/magic_enum_format.hpp>
1818
#include <magic_enum/magic_enum_iostream.hpp>
19+
#include <magic_enum/magic_enum_switch.hpp>
1920

2021
FOUR_C_NAMESPACE_OPEN
2122

22-
// Import the stream insertion and extraction operators for enums.
23-
using magic_enum::iostream_operators::operator<<;
24-
using magic_enum::iostream_operators::operator>>;
23+
/**
24+
* This namespace contains helpers for static reflection of enums.
25+
*
26+
* @note The implementation is currently provided by the magic_enum library.
27+
*/
28+
namespace EnumTools
29+
{
30+
// Import the stream insertion and extraction operators for enums.
31+
using magic_enum::iostream_operators::operator<<;
32+
using magic_enum::iostream_operators::operator>>;
33+
34+
// Import everything from magic_enum into our namespace.
35+
using namespace magic_enum;
36+
} // namespace EnumTools
2537

2638
FOUR_C_NAMESPACE_CLOSE
2739

0 commit comments

Comments
 (0)