blob: 222b9904c49962bd8e00a17aff8ecd99ff1a6191 [file] [log] [blame]
Wludzik, Jozefd960e1f2021-01-08 09:25:59 +01001#pragma once
2
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +00003#include <algorithm>
4#include <array>
Wludzik, Jozefd960e1f2021-01-08 09:25:59 +01005#include <stdexcept>
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +00006#include <string>
Wludzik, Jozefd960e1f2021-01-08 09:25:59 +01007
8namespace utils
9{
10
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010011template <class T>
12struct EnumTraits
13{
14 [[noreturn]] static void throwConversionError()
15 {
16 throw std::out_of_range("Value is not in range of enum");
17 }
18};
19
Wludzik, Jozefd960e1f2021-01-08 09:25:59 +010020template <class T, T first, T last>
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000021inline T toEnum(std::underlying_type_t<T> x)
Wludzik, Jozefd960e1f2021-01-08 09:25:59 +010022{
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000023 if (x < static_cast<std::underlying_type_t<T>>(first) ||
24 x > static_cast<std::underlying_type_t<T>>(last))
Wludzik, Jozefd960e1f2021-01-08 09:25:59 +010025 {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010026 EnumTraits<T>::throwConversionError();
Wludzik, Jozefd960e1f2021-01-08 09:25:59 +010027 }
28 return static_cast<T>(x);
29}
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000030
31template <class T>
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010032constexpr inline std::underlying_type_t<T> toUnderlying(T value)
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000033{
34 return static_cast<std::underlying_type_t<T>>(value);
35}
36
37template <class T, size_t N>
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010038constexpr inline T
39 minEnumValue(std::array<std::pair<std::string_view, T>, N> data)
40{
41 auto min = data[0].second;
42 for (auto [key, value] : data)
43 {
44 if (toUnderlying(min) > toUnderlying(value))
45 {
46 min = value;
47 }
48 }
49 return min;
50}
51
52template <class T, size_t N>
53constexpr inline T
54 maxEnumValue(std::array<std::pair<std::string_view, T>, N> data)
55{
56 auto max = data[0].second;
57 for (auto [key, value] : data)
58 {
59 if (toUnderlying(max) < toUnderlying(value))
60 {
61 max = value;
62 }
63 }
64 return max;
65}
66
67template <class T, size_t N>
68inline T toEnum(const std::array<std::pair<std::string_view, T>, N>& data,
69 const std::string& value)
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000070{
71 auto it = std::find_if(
72 std::begin(data), std::end(data),
73 [&value](const auto& item) { return item.first == value; });
74 if (it == std::end(data))
75 {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010076 EnumTraits<T>::throwConversionError();
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000077 }
78 return it->second;
79}
80
81template <class T, size_t N>
82inline std::string_view
83 enumToString(const std::array<std::pair<std::string_view, T>, N>& data,
84 T value)
85{
86 auto it = std::find_if(
87 std::begin(data), std::end(data),
88 [value](const auto& item) { return item.second == value; });
89 if (it == std::end(data))
90 {
Krzysztof Grobelny51497a02021-11-09 14:56:22 +010091 EnumTraits<T>::throwConversionError();
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000092 }
93 return it->first;
94}
95
Wludzik, Jozefd960e1f2021-01-08 09:25:59 +010096} // namespace utils