mirror of https://github.com/OpenMW/openmw.git
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.depth-refraction
parent
ba1f91661f
commit
3bad40153c
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
@ -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
|
@ -0,0 +1,12 @@
|
||||
#include "values.hpp"
|
||||
|
||||
namespace Settings
|
||||
{
|
||||
Values* Values::sValues = nullptr;
|
||||
|
||||
void Values::init()
|
||||
{
|
||||
static Values values;
|
||||
Values::sValues = &values;
|
||||
}
|
||||
}
|
@ -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…
Reference in New Issue