xref: /openbmc/telemetry/src/utils/conversion.hpp (revision b3e03d2d)
1 #pragma once
2 
3 #include "errors.hpp"
4 
5 #include <sdbusplus/exception.hpp>
6 
7 #include <algorithm>
8 #include <array>
9 #include <stdexcept>
10 #include <string>
11 
12 namespace utils
13 {
14 
15 template <size_t N>
16 struct ConstexprString
17 {
18     constexpr ConstexprString(const char (&data)[N]) : s()
19     {
20         for (size_t i = 0; i < N; ++i)
21         {
22             s[i] = data[i];
23         }
24     }
25 
26     constexpr operator std::string_view() const
27     {
28         return {s.data(), s.size()};
29     }
30 
31     std::array<char, N> s;
32 };
33 
34 [[noreturn]] inline void throwConversionError(std::string_view propertyName)
35 {
36     throw errors::InvalidArgument(propertyName, "Cannot convert.");
37 }
38 
39 template <class T>
40 struct EnumTraits;
41 
42 template <class T, T first, T last>
43 inline T toEnum(std::underlying_type_t<T> x)
44 {
45     if (x < static_cast<std::underlying_type_t<T>>(first) ||
46         x > static_cast<std::underlying_type_t<T>>(last))
47     {
48         throwConversionError(EnumTraits<T>::propertyName);
49     }
50     return static_cast<T>(x);
51 }
52 
53 template <class T>
54 constexpr inline std::underlying_type_t<T> toUnderlying(T value)
55 {
56     return static_cast<std::underlying_type_t<T>>(value);
57 }
58 
59 template <class T, size_t N>
60 constexpr inline T
61     minEnumValue(std::array<std::pair<std::string_view, T>, N> data)
62 {
63     auto min = data[0].second;
64     for (auto [key, value] : data)
65     {
66         if (toUnderlying(min) > toUnderlying(value))
67         {
68             min = value;
69         }
70     }
71     return min;
72 }
73 
74 template <class T, size_t N>
75 constexpr inline T
76     maxEnumValue(std::array<std::pair<std::string_view, T>, N> data)
77 {
78     auto max = data[0].second;
79     for (auto [key, value] : data)
80     {
81         if (toUnderlying(max) < toUnderlying(value))
82         {
83             max = value;
84         }
85     }
86     return max;
87 }
88 
89 template <class T, size_t N>
90 inline T toEnum(const std::array<std::pair<std::string_view, T>, N>& data,
91                 const std::string& value)
92 {
93     auto it = std::find_if(
94         std::begin(data), std::end(data),
95         [&value](const auto& item) { return item.first == value; });
96     if (it == std::end(data))
97     {
98         throwConversionError(EnumTraits<T>::propertyName);
99     }
100     return it->second;
101 }
102 
103 template <class T, size_t N>
104 inline std::string_view
105     enumToString(const std::array<std::pair<std::string_view, T>, N>& data,
106                  T value)
107 {
108     auto it = std::find_if(
109         std::begin(data), std::end(data),
110         [value](const auto& item) { return item.second == value; });
111     if (it == std::end(data))
112     {
113         throwConversionError(EnumTraits<T>::propertyName);
114     }
115     return it->first;
116 }
117 
118 } // namespace utils
119