mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-27 21:35:24 +00:00
Define typed settings storage with single time initialization
To make sure loaded settings have valid values doing the check once per loading. And to make access more efficient.
This commit is contained in:
parent
ba1f91661f
commit
3bad40153c
@ -42,7 +42,14 @@ add_component_dir (l10n
|
||||
)
|
||||
|
||||
add_component_dir (settings
|
||||
settings parser
|
||||
categories
|
||||
parser
|
||||
sanitizer
|
||||
sanitizerimpl
|
||||
settings
|
||||
settingvalue
|
||||
shadermanager
|
||||
values
|
||||
)
|
||||
|
||||
add_component_dir (bsa
|
||||
|
15
components/settings/sanitizer.hpp
Normal file
15
components/settings/sanitizer.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef OPENMW_COMPONENTS_SETTINGS_SANITIZER_H
|
||||
#define OPENMW_COMPONENTS_SETTINGS_SANITIZER_H
|
||||
|
||||
namespace Settings
|
||||
{
|
||||
template <class T>
|
||||
struct Sanitizer
|
||||
{
|
||||
virtual ~Sanitizer() = default;
|
||||
|
||||
virtual T apply(const T& value) const = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
205
components/settings/sanitizerimpl.cpp
Normal file
205
components/settings/sanitizerimpl.cpp
Normal file
@ -0,0 +1,205 @@
|
||||
#include "sanitizerimpl.hpp"
|
||||
|
||||
#include <osg/Vec3f>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace Settings
|
||||
{
|
||||
namespace
|
||||
{
|
||||
template <class T>
|
||||
struct Max final : Sanitizer<T>
|
||||
{
|
||||
T mMax;
|
||||
|
||||
explicit Max(const T& max)
|
||||
: mMax(max)
|
||||
{
|
||||
}
|
||||
|
||||
T apply(const T& value) const override { return std::max(value, mMax); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct MaxStrict final : Sanitizer<T>
|
||||
{
|
||||
static_assert(std::is_floating_point_v<T>);
|
||||
|
||||
T mMax;
|
||||
|
||||
explicit MaxStrict(const T& max)
|
||||
: mMax(std::nextafter(max, std::numeric_limits<T>::max()))
|
||||
{
|
||||
}
|
||||
|
||||
T apply(const T& value) const override { return std::max(value, mMax); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct MaxStrict<osg::Vec3f> final : Sanitizer<osg::Vec3f>
|
||||
{
|
||||
osg::Vec3f mMax;
|
||||
|
||||
explicit MaxStrict(const osg::Vec3f& max)
|
||||
: mMax(std::nextafter(max.x(), std::numeric_limits<float>::max()),
|
||||
std::nextafter(max.y(), std::numeric_limits<float>::max()),
|
||||
std::nextafter(max.z(), std::numeric_limits<float>::max()))
|
||||
{
|
||||
}
|
||||
|
||||
osg::Vec3f apply(const osg::Vec3f& value) const override
|
||||
{
|
||||
return osg::Vec3f(
|
||||
std::max(value.x(), mMax.x()), std::max(value.y(), mMax.y()), std::max(value.z(), mMax.z()));
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct Clamp final : Sanitizer<T>
|
||||
{
|
||||
T mMin;
|
||||
T mMax;
|
||||
|
||||
explicit Clamp(const T& min, const T& max)
|
||||
: mMin(min)
|
||||
, mMax(max)
|
||||
{
|
||||
}
|
||||
|
||||
T apply(const T& value) const override { return std::clamp(value, mMin, mMax); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
auto getPrev(const T& value) -> std::enable_if_t<std::is_floating_point_v<T>, T>
|
||||
{
|
||||
assert(value > -std::numeric_limits<T>::max());
|
||||
return std::nextafter(value, -std::numeric_limits<T>::max());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct ClampStrictMax final : Sanitizer<T>
|
||||
{
|
||||
T mMin;
|
||||
T mMax;
|
||||
|
||||
explicit ClampStrictMax(const T& min, const T& max)
|
||||
: mMin(min)
|
||||
, mMax(getPrev(max))
|
||||
{
|
||||
}
|
||||
|
||||
T apply(const T& value) const override { return std::clamp(value, mMin, mMax); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct Enum final : Sanitizer<T>
|
||||
{
|
||||
std::vector<T> mValues;
|
||||
|
||||
explicit Enum(std::initializer_list<T> value)
|
||||
: mValues(std::make_move_iterator(value.begin()), std::make_move_iterator(value.end()))
|
||||
{
|
||||
}
|
||||
|
||||
T apply(const T& value) const override
|
||||
{
|
||||
if (std::find(mValues.begin(), mValues.end(), value) == mValues.end())
|
||||
{
|
||||
std::ostringstream message;
|
||||
message << "Invalid enum value: " << value;
|
||||
throw std::runtime_error(message.str());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct EqualOrMax final : Sanitizer<T>
|
||||
{
|
||||
T mEqual;
|
||||
T mMax;
|
||||
|
||||
explicit EqualOrMax(const T& equal, const T& max)
|
||||
: mEqual(equal)
|
||||
, mMax(max)
|
||||
{
|
||||
}
|
||||
|
||||
T apply(const T& value) const override
|
||||
{
|
||||
if (value == mEqual)
|
||||
return value;
|
||||
return std::max(value, mMax);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
std::unique_ptr<Sanitizer<float>> makeMaxSanitizerFloat(float max)
|
||||
{
|
||||
return std::make_unique<Max<float>>(max);
|
||||
}
|
||||
|
||||
std::unique_ptr<Sanitizer<int>> makeMaxSanitizerInt(int max)
|
||||
{
|
||||
return std::make_unique<Max<int>>(max);
|
||||
}
|
||||
|
||||
std::unique_ptr<Sanitizer<std::size_t>> makeMaxSanitizerSize(std::size_t max)
|
||||
{
|
||||
return std::make_unique<Max<std::size_t>>(max);
|
||||
}
|
||||
|
||||
std::unique_ptr<Sanitizer<std::uint64_t>> makeMaxSanitizerUInt64(std::uint64_t max)
|
||||
{
|
||||
return std::make_unique<Max<std::uint64_t>>(max);
|
||||
}
|
||||
|
||||
std::unique_ptr<Sanitizer<float>> makeMaxStrictSanitizerFloat(float max)
|
||||
{
|
||||
return std::make_unique<MaxStrict<float>>(max);
|
||||
}
|
||||
|
||||
std::unique_ptr<Sanitizer<osg::Vec3f>> makeMaxStrictSanitizerVec3f(const osg::Vec3f& max)
|
||||
{
|
||||
return std::make_unique<MaxStrict<osg::Vec3f>>(max);
|
||||
}
|
||||
|
||||
std::unique_ptr<Sanitizer<float>> makeClampSanitizerFloat(float min, float max)
|
||||
{
|
||||
return std::make_unique<Clamp<float>>(min, max);
|
||||
}
|
||||
|
||||
std::unique_ptr<Sanitizer<int>> makeClampSanitizerInt(int min, int max)
|
||||
{
|
||||
return std::make_unique<Clamp<int>>(min, max);
|
||||
}
|
||||
|
||||
std::unique_ptr<Sanitizer<float>> makeClampStrictMaxSanitizerFloat(float min, float max)
|
||||
{
|
||||
return std::make_unique<ClampStrictMax<float>>(min, max);
|
||||
}
|
||||
|
||||
std::unique_ptr<Sanitizer<int>> makeEnumSanitizerInt(std::initializer_list<int> values)
|
||||
{
|
||||
return std::make_unique<Enum<int>>(values);
|
||||
}
|
||||
|
||||
std::unique_ptr<Sanitizer<std::string>> makeEnumSanitizerString(std::initializer_list<std::string> values)
|
||||
{
|
||||
return std::make_unique<Enum<std::string>>(values);
|
||||
}
|
||||
|
||||
std::unique_ptr<Sanitizer<float>> makeEqualOrMaxSanitizerFloat(float equal, float max)
|
||||
{
|
||||
return std::make_unique<EqualOrMax<float>>(equal, max);
|
||||
}
|
||||
}
|
40
components/settings/sanitizerimpl.hpp
Normal file
40
components/settings/sanitizerimpl.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef OPENMW_COMPONENTS_SETTINGS_SANITIZERIMPL_H
|
||||
#define OPENMW_COMPONENTS_SETTINGS_SANITIZERIMPL_H
|
||||
|
||||
#include "sanitizer.hpp"
|
||||
|
||||
#include <osg/Vec3f>
|
||||
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace Settings
|
||||
{
|
||||
std::unique_ptr<Sanitizer<float>> makeMaxSanitizerFloat(float max);
|
||||
|
||||
std::unique_ptr<Sanitizer<int>> makeMaxSanitizerInt(int max);
|
||||
|
||||
std::unique_ptr<Sanitizer<std::size_t>> makeMaxSanitizerSize(std::size_t max);
|
||||
|
||||
std::unique_ptr<Sanitizer<std::uint64_t>> makeMaxSanitizerUInt64(std::uint64_t max);
|
||||
|
||||
std::unique_ptr<Sanitizer<float>> makeMaxStrictSanitizerFloat(float max);
|
||||
|
||||
std::unique_ptr<Sanitizer<osg::Vec3f>> makeMaxStrictSanitizerVec3f(const osg::Vec3f& max);
|
||||
|
||||
std::unique_ptr<Sanitizer<float>> makeClampSanitizerFloat(float min, float max);
|
||||
|
||||
std::unique_ptr<Sanitizer<int>> makeClampSanitizerInt(int min, int max);
|
||||
|
||||
std::unique_ptr<Sanitizer<float>> makeClampStrictMaxSanitizerFloat(float min, float max);
|
||||
|
||||
std::unique_ptr<Sanitizer<int>> makeEnumSanitizerInt(std::initializer_list<int> values);
|
||||
|
||||
std::unique_ptr<Sanitizer<std::string>> makeEnumSanitizerString(std::initializer_list<std::string> values);
|
||||
|
||||
std::unique_ptr<Sanitizer<float>> makeEqualOrMaxSanitizerFloat(float equal, float max);
|
||||
}
|
||||
|
||||
#endif
|
@ -1,5 +1,6 @@
|
||||
#include "settings.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "values.hpp"
|
||||
|
||||
#include <charconv>
|
||||
#include <filesystem>
|
||||
@ -79,11 +80,19 @@ namespace Settings
|
||||
return doubleValue;
|
||||
}
|
||||
#endif
|
||||
template <class T>
|
||||
std::string serialize(const T& value)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << value;
|
||||
return stream.str();
|
||||
}
|
||||
}
|
||||
|
||||
CategorySettingValueMap Manager::mDefaultSettings = CategorySettingValueMap();
|
||||
CategorySettingValueMap Manager::mUserSettings = CategorySettingValueMap();
|
||||
CategorySettingVector Manager::mChangedSettings = CategorySettingVector();
|
||||
std::set<std::pair<std::string_view, std::string_view>> Manager::sInitialized;
|
||||
|
||||
void Manager::clear()
|
||||
{
|
||||
@ -136,6 +145,12 @@ namespace Settings
|
||||
if (std::filesystem::exists(settingspath))
|
||||
parser.loadSettingsFile(settingspath, mUserSettings, false, false);
|
||||
|
||||
Settings::Values::init();
|
||||
|
||||
for (const auto& [key, value] : mDefaultSettings)
|
||||
if (!sInitialized.contains(key))
|
||||
throw std::runtime_error("Default setting [" + key.first + "] " + key.second + " is not initialized");
|
||||
|
||||
return settingspath;
|
||||
}
|
||||
|
||||
@ -203,6 +218,21 @@ namespace Settings
|
||||
return parseNumberFromSetting<size_t>(getString(setting, category), setting, category);
|
||||
}
|
||||
|
||||
unsigned Manager::getUnsigned(std::string_view setting, std::string_view category)
|
||||
{
|
||||
return parseNumberFromSetting<unsigned>(getString(setting, category), setting, category);
|
||||
}
|
||||
|
||||
unsigned long Manager::getUnsignedLong(std::string_view setting, std::string_view category)
|
||||
{
|
||||
return parseNumberFromSetting<unsigned long>(getString(setting, category), setting, category);
|
||||
}
|
||||
|
||||
unsigned long long Manager::getUnsignedLongLong(std::string_view setting, std::string_view category)
|
||||
{
|
||||
return parseNumberFromSetting<unsigned long long>(getString(setting, category), setting, category);
|
||||
}
|
||||
|
||||
bool Manager::getBool(std::string_view setting, std::string_view category)
|
||||
{
|
||||
const std::string& string = getString(setting, category);
|
||||
@ -360,4 +390,59 @@ namespace Settings
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::set(std::string_view setting, std::string_view category, int value)
|
||||
{
|
||||
setInt(setting, category, value);
|
||||
}
|
||||
|
||||
void Manager::set(std::string_view setting, std::string_view category, unsigned value)
|
||||
{
|
||||
setString(setting, category, serialize(value));
|
||||
}
|
||||
|
||||
void Manager::set(std::string_view setting, std::string_view category, unsigned long value)
|
||||
{
|
||||
setString(setting, category, serialize(value));
|
||||
}
|
||||
|
||||
void Manager::set(std::string_view setting, std::string_view category, unsigned long long value)
|
||||
{
|
||||
setString(setting, category, serialize(value));
|
||||
}
|
||||
|
||||
void Manager::set(std::string_view setting, std::string_view category, float value)
|
||||
{
|
||||
setFloat(setting, category, value);
|
||||
}
|
||||
|
||||
void Manager::set(std::string_view setting, std::string_view category, double value)
|
||||
{
|
||||
setDouble(setting, category, value);
|
||||
}
|
||||
|
||||
void Manager::set(std::string_view setting, std::string_view category, const std::string& value)
|
||||
{
|
||||
setString(setting, category, value);
|
||||
}
|
||||
|
||||
void Manager::set(std::string_view setting, std::string_view category, bool value)
|
||||
{
|
||||
setBool(setting, category, value);
|
||||
}
|
||||
|
||||
void Manager::set(std::string_view setting, std::string_view category, const osg::Vec2f& value)
|
||||
{
|
||||
setVector2(setting, category, value);
|
||||
}
|
||||
|
||||
void Manager::set(std::string_view setting, std::string_view category, const osg::Vec3f& value)
|
||||
{
|
||||
setVector3(setting, category, value);
|
||||
}
|
||||
|
||||
void Manager::recordInit(std::string_view setting, std::string_view category)
|
||||
{
|
||||
sInitialized.emplace(category, setting);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "categories.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
@ -61,6 +62,9 @@ namespace Settings
|
||||
static int getInt(std::string_view setting, std::string_view category);
|
||||
static std::uint64_t getUInt64(std::string_view setting, std::string_view category);
|
||||
static std::size_t getSize(std::string_view setting, std::string_view category);
|
||||
static unsigned getUnsigned(std::string_view setting, std::string_view category);
|
||||
static unsigned long getUnsignedLong(std::string_view setting, std::string_view category);
|
||||
static unsigned long long getUnsignedLongLong(std::string_view setting, std::string_view category);
|
||||
static float getFloat(std::string_view setting, std::string_view category);
|
||||
static double getDouble(std::string_view setting, std::string_view category);
|
||||
static const std::string& getString(std::string_view setting, std::string_view category);
|
||||
@ -69,6 +73,13 @@ namespace Settings
|
||||
static osg::Vec2f getVector2(std::string_view setting, std::string_view category);
|
||||
static osg::Vec3f getVector3(std::string_view setting, std::string_view category);
|
||||
|
||||
template <class T>
|
||||
static T get(std::string_view setting, std::string_view category)
|
||||
{
|
||||
recordInit(setting, category);
|
||||
return getImpl<T>(setting, category);
|
||||
}
|
||||
|
||||
static void setInt(std::string_view setting, std::string_view category, int value);
|
||||
static void setUInt64(std::string_view setting, std::string_view category, std::uint64_t value);
|
||||
static void setFloat(std::string_view setting, std::string_view category, float value);
|
||||
@ -79,8 +90,86 @@ namespace Settings
|
||||
static void setBool(std::string_view setting, std::string_view category, bool value);
|
||||
static void setVector2(std::string_view setting, std::string_view category, osg::Vec2f value);
|
||||
static void setVector3(std::string_view setting, std::string_view category, osg::Vec3f value);
|
||||
|
||||
static void set(std::string_view setting, std::string_view category, int value);
|
||||
static void set(std::string_view setting, std::string_view category, unsigned value);
|
||||
static void set(std::string_view setting, std::string_view category, unsigned long value);
|
||||
static void set(std::string_view setting, std::string_view category, unsigned long long value);
|
||||
static void set(std::string_view setting, std::string_view category, float value);
|
||||
static void set(std::string_view setting, std::string_view category, double value);
|
||||
static void set(std::string_view setting, std::string_view category, const std::string& value);
|
||||
static void set(std::string_view setting, std::string_view category, bool value);
|
||||
static void set(std::string_view setting, std::string_view category, const osg::Vec2f& value);
|
||||
static void set(std::string_view setting, std::string_view category, const osg::Vec3f& value);
|
||||
|
||||
private:
|
||||
static std::set<std::pair<std::string_view, std::string_view>> sInitialized;
|
||||
|
||||
template <class T>
|
||||
static T getImpl(std::string_view setting, std::string_view category);
|
||||
|
||||
static void recordInit(std::string_view setting, std::string_view category);
|
||||
};
|
||||
|
||||
template <>
|
||||
inline int Manager::getImpl<int>(std::string_view setting, std::string_view category)
|
||||
{
|
||||
return getInt(setting, category);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned Manager::getImpl<unsigned>(std::string_view setting, std::string_view category)
|
||||
{
|
||||
return getUnsigned(setting, category);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned long Manager::getImpl<unsigned long>(std::string_view setting, std::string_view category)
|
||||
{
|
||||
return getUnsignedLong(setting, category);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned long long Manager::getImpl<unsigned long long>(std::string_view setting, std::string_view category)
|
||||
{
|
||||
return getUnsignedLongLong(setting, category);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline float Manager::getImpl<float>(std::string_view setting, std::string_view category)
|
||||
{
|
||||
return getFloat(setting, category);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline double Manager::getImpl<double>(std::string_view setting, std::string_view category)
|
||||
{
|
||||
return getDouble(setting, category);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string Manager::getImpl<std::string>(std::string_view setting, std::string_view category)
|
||||
{
|
||||
return getString(setting, category);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool Manager::getImpl<bool>(std::string_view setting, std::string_view category)
|
||||
{
|
||||
return getBool(setting, category);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline osg::Vec2f Manager::getImpl<osg::Vec2f>(std::string_view setting, std::string_view category)
|
||||
{
|
||||
return getVector2(setting, category);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline osg::Vec3f Manager::getImpl<osg::Vec3f>(std::string_view setting, std::string_view category)
|
||||
{
|
||||
return getVector3(setting, category);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // COMPONENTS_SETTINGS_H
|
||||
|
70
components/settings/settingvalue.hpp
Normal file
70
components/settings/settingvalue.hpp
Normal file
@ -0,0 +1,70 @@
|
||||
#ifndef OPENMW_COMPONENTS_SETTINGS_SETTINGVALUE_H
|
||||
#define OPENMW_COMPONENTS_SETTINGS_SETTINGVALUE_H
|
||||
|
||||
#include "sanitizer.hpp"
|
||||
#include "settings.hpp"
|
||||
|
||||
#include "components/debug/debuglog.hpp"
|
||||
|
||||
#include <osg/io_utils>
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string_view>
|
||||
|
||||
namespace Settings
|
||||
{
|
||||
template <class T>
|
||||
class SettingValue
|
||||
{
|
||||
public:
|
||||
explicit SettingValue(
|
||||
std::string_view category, std::string_view name, std::unique_ptr<const Sanitizer<T>>&& sanitizer = nullptr)
|
||||
: mCategory(category)
|
||||
, mName(name)
|
||||
, mSanitizer(std::move(sanitizer))
|
||||
, mValue(sanitize(Settings::Manager::get<T>(name, category)))
|
||||
{
|
||||
}
|
||||
|
||||
const T& get() const { return mValue; }
|
||||
|
||||
operator const T&() const { return mValue; }
|
||||
|
||||
void set(const T& value)
|
||||
{
|
||||
if (mValue == value)
|
||||
return;
|
||||
mValue = sanitize(value);
|
||||
Settings::Manager::set(mName, mCategory, mValue);
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string_view mCategory;
|
||||
const std::string_view mName;
|
||||
const std::unique_ptr<const Sanitizer<T>> mSanitizer;
|
||||
T mValue{};
|
||||
|
||||
T sanitize(const T& value) const
|
||||
{
|
||||
if (mSanitizer == nullptr)
|
||||
return value;
|
||||
try
|
||||
{
|
||||
T sanitizedValue = mSanitizer->apply(value);
|
||||
if (sanitizedValue != value)
|
||||
Log(Debug::Warning) << "Setting [" << mCategory << "] " << mName
|
||||
<< " value is out of allowed values set: " << value << ", sanitized to "
|
||||
<< sanitizedValue;
|
||||
return sanitizedValue;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
throw std::runtime_error("Invalid setting [" + std::string(mCategory) + "] " + std::string(mName)
|
||||
+ " value: " + std::string(e.what()));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
12
components/settings/values.cpp
Normal file
12
components/settings/values.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
#include "values.hpp"
|
||||
|
||||
namespace Settings
|
||||
{
|
||||
Values* Values::sValues = nullptr;
|
||||
|
||||
void Values::init()
|
||||
{
|
||||
static Values values;
|
||||
Values::sValues = &values;
|
||||
}
|
||||
}
|
33
components/settings/values.hpp
Normal file
33
components/settings/values.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef OPENMW_COMPONENTS_SETTINGS_VALUES_H
|
||||
#define OPENMW_COMPONENTS_SETTINGS_VALUES_H
|
||||
|
||||
#include "sanitizerimpl.hpp"
|
||||
#include "settingvalue.hpp"
|
||||
|
||||
namespace Settings
|
||||
{
|
||||
class Values
|
||||
{
|
||||
public:
|
||||
static void init();
|
||||
|
||||
private:
|
||||
static Values* sValues;
|
||||
|
||||
friend const Values& values();
|
||||
|
||||
friend Values& valuesMutable();
|
||||
};
|
||||
|
||||
inline const Values& values()
|
||||
{
|
||||
return *Values::sValues;
|
||||
}
|
||||
|
||||
inline Values& valuesMutable()
|
||||
{
|
||||
return *Values::sValues;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user