2017-10-30 16:22:37 +00:00
|
|
|
// Copyright 2017 Dolphin Emulator Project
|
2021-07-05 03:22:19 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2017-10-30 16:22:37 +00:00
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
2020-12-05 18:24:41 +01:00
|
|
|
#include <mutex>
|
2017-10-30 16:22:37 +00:00
|
|
|
#include <string>
|
2020-12-05 18:24:41 +01:00
|
|
|
#include <utility>
|
2017-10-30 16:22:37 +00:00
|
|
|
|
2020-12-05 18:24:41 +01:00
|
|
|
#include "Common/CommonTypes.h"
|
2017-10-30 16:22:37 +00:00
|
|
|
#include "Common/Config/Enums.h"
|
2025-10-31 20:48:20 -05:00
|
|
|
#include "Common/Mutex.h"
|
2025-05-05 19:30:53 -05:00
|
|
|
#include "Common/TypeUtils.h"
|
2017-10-30 16:22:37 +00:00
|
|
|
|
|
|
|
|
namespace Config
|
|
|
|
|
{
|
2020-05-02 14:39:40 +02:00
|
|
|
struct Location
|
2017-10-30 16:22:37 +00:00
|
|
|
{
|
2021-09-03 21:43:19 -07:00
|
|
|
System system{};
|
2017-10-30 16:22:37 +00:00
|
|
|
std::string section;
|
|
|
|
|
std::string key;
|
|
|
|
|
|
2020-05-02 14:39:40 +02:00
|
|
|
bool operator==(const Location& other) const;
|
|
|
|
|
bool operator<(const Location& other) const;
|
2017-10-30 16:22:37 +00:00
|
|
|
};
|
|
|
|
|
|
2020-12-05 18:24:41 +01:00
|
|
|
template <typename T>
|
|
|
|
|
struct CachedValue
|
|
|
|
|
{
|
|
|
|
|
T value;
|
|
|
|
|
u64 config_version;
|
|
|
|
|
};
|
|
|
|
|
|
2017-10-30 16:22:37 +00:00
|
|
|
template <typename T>
|
2020-09-20 13:58:17 +02:00
|
|
|
class Info
|
2017-10-30 16:22:37 +00:00
|
|
|
{
|
2020-09-20 13:58:17 +02:00
|
|
|
public:
|
2025-10-31 16:26:06 -05:00
|
|
|
constexpr Info(Location location, T default_value)
|
|
|
|
|
: m_location{std::move(location)}, m_default_value{default_value},
|
|
|
|
|
m_cached_value{std::move(default_value), 0}
|
2018-05-11 22:38:44 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-31 16:26:06 -05:00
|
|
|
Info(const Info<T>& other)
|
|
|
|
|
: m_location{other.m_location}, m_default_value{other.m_default_value},
|
|
|
|
|
m_cached_value(other.GetCachedValue())
|
|
|
|
|
{
|
|
|
|
|
}
|
2020-12-05 18:24:41 +01:00
|
|
|
|
2020-05-02 14:39:40 +02:00
|
|
|
// Make it easy to convert Info<Enum> into Info<UnderlyingType<Enum>>
|
2018-05-11 22:38:44 +02:00
|
|
|
// so that enum settings can still easily work with code that doesn't care about the enum values.
|
2025-05-05 19:30:53 -05:00
|
|
|
template <Common::TypedEnum<T> Enum>
|
2020-12-05 18:24:41 +01:00
|
|
|
Info(const Info<Enum>& other)
|
2025-10-31 16:26:06 -05:00
|
|
|
: m_location{other.GetLocation()}, m_default_value{static_cast<T>(other.GetDefaultValue())},
|
|
|
|
|
m_cached_value(other.template GetCachedValueCasted<T>())
|
2018-05-11 22:38:44 +02:00
|
|
|
{
|
2020-12-05 18:24:41 +01:00
|
|
|
}
|
|
|
|
|
|
2025-10-31 16:26:06 -05:00
|
|
|
~Info() = default;
|
2020-12-05 18:24:41 +01:00
|
|
|
|
2025-10-31 16:26:06 -05:00
|
|
|
// Assignments after construction would require more locking to be thread safe.
|
|
|
|
|
// It seems unnecessary to have this functionality anyways.
|
|
|
|
|
Info& operator=(const Info&) = delete;
|
|
|
|
|
Info& operator=(Info&&) = delete;
|
|
|
|
|
// Moves are also unnecessary and would be thread unsafe without additional locking.
|
|
|
|
|
Info(Info&&) = delete;
|
2018-05-11 22:38:44 +02:00
|
|
|
|
2020-09-20 13:58:17 +02:00
|
|
|
constexpr const Location& GetLocation() const { return m_location; }
|
|
|
|
|
constexpr const T& GetDefaultValue() const { return m_default_value; }
|
|
|
|
|
|
2020-12-05 18:24:41 +01:00
|
|
|
CachedValue<T> GetCachedValue() const
|
|
|
|
|
{
|
2025-10-31 20:48:20 -05:00
|
|
|
std::lock_guard lk{m_cached_value_mutex};
|
2020-12-05 18:24:41 +01:00
|
|
|
return m_cached_value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename U>
|
|
|
|
|
CachedValue<U> GetCachedValueCasted() const
|
|
|
|
|
{
|
2025-10-31 20:48:20 -05:00
|
|
|
std::lock_guard lk{m_cached_value_mutex};
|
2025-10-31 16:26:06 -05:00
|
|
|
return {static_cast<U>(m_cached_value.value), m_cached_value.config_version};
|
2020-12-05 18:24:41 +01:00
|
|
|
}
|
|
|
|
|
|
2025-10-31 16:26:06 -05:00
|
|
|
// Only updates if the provided config_version is newer.
|
|
|
|
|
void TryToSetCachedValue(CachedValue<T> new_value) const
|
2020-12-05 18:24:41 +01:00
|
|
|
{
|
2025-10-31 16:26:06 -05:00
|
|
|
std::lock_guard lk{m_cached_value_mutex};
|
|
|
|
|
if (new_value.config_version > m_cached_value.config_version)
|
|
|
|
|
m_cached_value = std::move(new_value);
|
2020-12-05 18:24:41 +01:00
|
|
|
}
|
|
|
|
|
|
2020-09-20 13:58:17 +02:00
|
|
|
private:
|
|
|
|
|
Location m_location;
|
|
|
|
|
T m_default_value;
|
2020-12-05 18:24:41 +01:00
|
|
|
|
|
|
|
|
mutable CachedValue<T> m_cached_value;
|
2025-10-31 20:48:20 -05:00
|
|
|
|
|
|
|
|
// In testing, this mutex is effectively never contested.
|
|
|
|
|
// The lock durations are brief and each `Info` object is mostly relevant to one thread.
|
|
|
|
|
// Common::SpinMutex is ~3x faster than std::shared_mutex when uncontested.
|
|
|
|
|
mutable Common::SpinMutex m_cached_value_mutex;
|
2017-10-30 16:22:37 +00:00
|
|
|
};
|
2019-05-05 23:48:12 +00:00
|
|
|
} // namespace Config
|