#pragma once #include "errors.hpp" #include #include #include #include #include namespace utils { template struct ConstexprString { constexpr ConstexprString(const char (&data)[N]) : s() { for (size_t i = 0; i < N; ++i) { s[i] = data[i]; } } constexpr operator std::string_view() const { return {s.data(), s.size()}; } std::array s; }; [[noreturn]] inline void throwConversionError(std::string_view propertyName) { throw errors::InvalidArgument(propertyName, "Cannot convert."); } template struct EnumTraits; template inline T toEnum(std::underlying_type_t x) { if (x < static_cast>(first) || x > static_cast>(last)) { throwConversionError(EnumTraits::propertyName); } return static_cast(x); } template constexpr inline std::underlying_type_t toUnderlying(T value) { return static_cast>(value); } template constexpr inline T minEnumValue(std::array, N> data) { auto min = data[0].second; for (auto [key, value] : data) { if (toUnderlying(min) > toUnderlying(value)) { min = value; } } return min; } template constexpr inline T maxEnumValue(std::array, N> data) { auto max = data[0].second; for (auto [key, value] : data) { if (toUnderlying(max) < toUnderlying(value)) { max = value; } } return max; } template inline T toEnum(const std::array, N>& data, const std::string& value) { auto it = std::find_if( std::begin(data), std::end(data), [&value](const auto& item) { return item.first == value; }); if (it == std::end(data)) { throwConversionError(EnumTraits::propertyName); } return it->second; } template inline std::string_view enumToString(const std::array, N>& data, T value) { auto it = std::find_if( std::begin(data), std::end(data), [value](const auto& item) { return item.second == value; }); if (it == std::end(data)) { throwConversionError(EnumTraits::propertyName); } return it->first; } } // namespace utils