Config: Add support for enums

This makes it possible to use enums as the config type.
Default values are now clearer and there's no need for casts
when calling Config::Get/Set anymore.

In order to add support for enums, the common code was updated to
handle enums by using the underlying type when loading/saving settings.

A copy constructor is also provided for conversions from
`ConfigInfo<Enum>` to `ConfigInfo<underlying_type<Enum>>`
so that enum settings can still easily work with code that doesn't care
about the actual enum values (like Graphics{Choice,Radio} in DolphinQt2
which only treat the setting as an integer).
This commit is contained in:
Léo Lam
2018-05-11 22:38:44 +02:00
parent 7dca7c237e
commit 6763a3fce1
10 changed files with 87 additions and 54 deletions

View File

@ -5,11 +5,19 @@
#pragma once
#include <string>
#include <type_traits>
#include "Common/Config/Enums.h"
namespace Config
{
namespace detail
{
// std::underlying_type may only be used with enum types, so make sure T is an enum type first.
template <typename T>
using UnderlyingType = typename std::enable_if_t<std::is_enum<T>{}, std::underlying_type<T>>::type;
} // namespace detail
struct ConfigLocation
{
System system;
@ -24,6 +32,21 @@ struct ConfigLocation
template <typename T>
struct ConfigInfo
{
ConfigInfo(const ConfigLocation& location_, const T& default_value_)
: location{location_}, default_value{default_value_}
{
}
// Make it easy to convert ConfigInfo<Enum> into ConfigInfo<UnderlyingType<Enum>>
// so that enum settings can still easily work with code that doesn't care about the enum values.
template <typename Enum,
std::enable_if_t<std::is_same<T, detail::UnderlyingType<Enum>>::value>* = nullptr>
ConfigInfo(const ConfigInfo<Enum>& other)
: location{other.location}, default_value{static_cast<detail::UnderlyingType<Enum>>(
other.default_value)}
{
}
ConfigLocation location;
T default_value;
};

View File

@ -8,6 +8,7 @@
#include <memory>
#include <optional>
#include <string>
#include <type_traits>
#include <vector>
#include "Common/Config/ConfigInfo.h"
@ -25,8 +26,13 @@ std::string ValueToString(double value);
std::string ValueToString(int value);
std::string ValueToString(bool value);
std::string ValueToString(const std::string& value);
template <typename T, std::enable_if_t<std::is_enum<T>::value>* = nullptr>
std::string ValueToString(T value)
{
return ValueToString(static_cast<std::underlying_type_t<T>>(value));
}
template <typename T>
template <typename T, std::enable_if_t<!std::is_enum<T>::value>* = nullptr>
std::optional<T> TryParse(const std::string& str_value)
{
T value;
@ -35,6 +41,15 @@ std::optional<T> TryParse(const std::string& str_value)
return value;
}
template <typename T, std::enable_if_t<std::is_enum<T>::value>* = nullptr>
std::optional<T> TryParse(const std::string& str_value)
{
const auto result = TryParse<std::underlying_type_t<T>>(str_value);
if (result)
return static_cast<T>(*result);
return {};
}
template <>
inline std::optional<std::string> TryParse(const std::string& str_value)
{