diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2018-07-08 23:29:49 +0200 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2018-07-08 23:29:49 +0200 |
commit | fa1801471c2708ed8266ec7b99bd4cec886ccc1b (patch) | |
tree | aa56218c2c7e4939aaf11a2046b0f12760326545 /options | |
parent | 90940a774eab876c38d5cef981b4be5bae67a462 (diff) |
options: fix 2 issues
1. Calling valueChanged didn't invoke machinery in
value<t>, only base_value aka value_.
There's a fast path in value<t>::type() despite the
pessimization.
2. Split global scope stuff into options::globals from
the options::globals stuff
3. Adjust usages
Diffstat (limited to 'options')
-rw-r--r-- | options/base-value.hpp | 82 | ||||
-rw-r--r-- | options/bundle.cpp | 38 | ||||
-rw-r--r-- | options/bundle.hpp | 7 | ||||
-rw-r--r-- | options/connector.cpp | 14 | ||||
-rw-r--r-- | options/defs.hpp | 30 | ||||
-rw-r--r-- | options/globals.cpp | 160 | ||||
-rw-r--r-- | options/globals.hpp | 71 | ||||
-rw-r--r-- | options/group.cpp | 157 | ||||
-rw-r--r-- | options/group.hpp | 113 | ||||
-rw-r--r-- | options/metatype.cpp | 30 | ||||
-rw-r--r-- | options/metatype.hpp | 19 | ||||
-rw-r--r-- | options/options.hpp | 3 | ||||
-rw-r--r-- | options/value-traits.hpp | 16 | ||||
-rw-r--r-- | options/value.hpp | 96 |
14 files changed, 451 insertions, 385 deletions
diff --git a/options/base-value.hpp b/options/base-value.hpp index 5b924ab3..750f93f1 100644 --- a/options/base-value.hpp +++ b/options/base-value.hpp @@ -7,6 +7,7 @@ #include "export.hpp" #include "compat/macros.hpp" +#include "value-traits.hpp" #include <QObject> #include <QString> @@ -15,9 +16,10 @@ #include <QVariant> #include <typeindex> +#include <utility> -#define OPENTRACK_DEFINE_SLOT(t) void setValue(t datum) { store(datum); } -#define OPENTRACK_DEFINE_SIGNAL(t) void valueChanged(t) const +#define OTR_OPTIONS_SLOT(t) void setValue(t datum) { store_(datum); } +#define OTR_OPTIONS_SIGNAL(t) void valueChanged(t) const namespace options { @@ -32,15 +34,13 @@ class OTR_OPTIONS_EXPORT value_ : public QObject using signal_sig = void(value_::*)(cv_qualified<t>) const; public: - bundle get_bundle() { return b; } QString name() const { return self_name; } - value_(bundle b, const QString& name, comparator cmp, std::type_index type_idx); + value_(bundle const& b, const QString& name, comparator cmp, std::type_index type_idx); ~value_() override; - // MSVC has ODR problems in 15.4 // no C++17 "constexpr inline" for data declarations in MSVC template<typename t> - constexpr static auto value_changed() + static constexpr auto value_changed() { return static_cast<signal_sig<t>>(&value_::valueChanged); } @@ -48,22 +48,22 @@ public: void notify() const; signals: - OPENTRACK_DEFINE_SIGNAL(double); - OPENTRACK_DEFINE_SIGNAL(float); - OPENTRACK_DEFINE_SIGNAL(int); - OPENTRACK_DEFINE_SIGNAL(bool); - OPENTRACK_DEFINE_SIGNAL(const QString&); - OPENTRACK_DEFINE_SIGNAL(const slider_value&); - OPENTRACK_DEFINE_SIGNAL(const QPointF&); - OPENTRACK_DEFINE_SIGNAL(const QVariant&); - - OPENTRACK_DEFINE_SIGNAL(const QList<double>&); - OPENTRACK_DEFINE_SIGNAL(const QList<float>&); - OPENTRACK_DEFINE_SIGNAL(const QList<int>&); - OPENTRACK_DEFINE_SIGNAL(const QList<bool>&); - OPENTRACK_DEFINE_SIGNAL(const QList<QString>&); - OPENTRACK_DEFINE_SIGNAL(const QList<slider_value>&); - OPENTRACK_DEFINE_SIGNAL(const QList<QPointF>&); + OTR_OPTIONS_SIGNAL(double); + OTR_OPTIONS_SIGNAL(float); + OTR_OPTIONS_SIGNAL(int); + OTR_OPTIONS_SIGNAL(bool); + OTR_OPTIONS_SIGNAL(const QString&); + OTR_OPTIONS_SIGNAL(const slider_value&); + OTR_OPTIONS_SIGNAL(const QPointF&); + OTR_OPTIONS_SIGNAL(const QVariant&); + + OTR_OPTIONS_SIGNAL(const QList<double>&); + OTR_OPTIONS_SIGNAL(const QList<float>&); + OTR_OPTIONS_SIGNAL(const QList<int>&); + OTR_OPTIONS_SIGNAL(const QList<bool>&); + OTR_OPTIONS_SIGNAL(const QList<QString>&); + OTR_OPTIONS_SIGNAL(const QList<slider_value>&); + OTR_OPTIONS_SIGNAL(const QList<QPointF>&); protected: bundle b; @@ -71,30 +71,32 @@ protected: comparator cmp; std::type_index type_index; - void store(const QVariant& datum); + virtual void store_variant(const QVariant& x) = 0; template<typename t> - void store(const t& datum) + void store_(const t& datum) { - b->store_kv(self_name, QVariant::fromValue(datum)); + using traits = detail::value_traits<t>; + using stored_type = typename traits::stored_type; + store_variant(QVariant::fromValue<stored_type>(datum)); } public slots: - OPENTRACK_DEFINE_SLOT(double) - OPENTRACK_DEFINE_SLOT(int) - OPENTRACK_DEFINE_SLOT(bool) - OPENTRACK_DEFINE_SLOT(const QString&) - OPENTRACK_DEFINE_SLOT(const slider_value&) - OPENTRACK_DEFINE_SLOT(const QPointF&) - OPENTRACK_DEFINE_SLOT(const QVariant&) - - OPENTRACK_DEFINE_SLOT(const QList<double>&) - OPENTRACK_DEFINE_SLOT(const QList<float>&) - OPENTRACK_DEFINE_SLOT(const QList<int>&) - OPENTRACK_DEFINE_SLOT(const QList<bool>&) - OPENTRACK_DEFINE_SLOT(const QList<QString>&) - OPENTRACK_DEFINE_SLOT(const QList<slider_value>&) - OPENTRACK_DEFINE_SLOT(const QList<QPointF>&) + OTR_OPTIONS_SLOT(double) + OTR_OPTIONS_SLOT(int) + OTR_OPTIONS_SLOT(bool) + OTR_OPTIONS_SLOT(const QString&) + OTR_OPTIONS_SLOT(const slider_value&) + OTR_OPTIONS_SLOT(const QPointF&) + OTR_OPTIONS_SLOT(const QVariant&) + + OTR_OPTIONS_SLOT(const QList<double>&) + OTR_OPTIONS_SLOT(const QList<float>&) + OTR_OPTIONS_SLOT(const QList<int>&) + OTR_OPTIONS_SLOT(const QList<bool>&) + OTR_OPTIONS_SLOT(const QList<QString>&) + OTR_OPTIONS_SLOT(const QList<slider_value>&) + OTR_OPTIONS_SLOT(const QList<QPointF>&) virtual void reload() = 0; virtual void bundle_value_changed() const = 0; diff --git a/options/bundle.cpp b/options/bundle.cpp index b722338b..c426dd2e 100644 --- a/options/bundle.cpp +++ b/options/bundle.cpp @@ -8,11 +8,13 @@ #include "bundle.hpp" #include "value.hpp" +#include "globals.hpp" #include <QThread> #include <QApplication> -using options::value_; +using namespace options; +using namespace options::globals; namespace options::detail { @@ -24,9 +26,7 @@ bundle::bundle(const QString& group_name) { } -bundle::~bundle() -{ -} +bundle::~bundle() = default; void bundle::reload() { @@ -53,19 +53,23 @@ void bundle::set_all_to_default() forall([](const QString&, value_* val) { set_base_value_to_default(val); }); if (is_modified()) - group::mark_ini_modified(); + mark_ini_modified(); } -void bundle::store_kv(const QString& name, const QVariant& datum) +void bundle::store_kv(const QString& name, const QVariant& new_value) { QMutexLocker l(&mtx); - transient.put(name, datum); - - if (group_name.size()) - connector::notify_values(name); - - emit changed(); + if (!group_name.isEmpty()) + { + const QVariant old_value = transient.get_variant(name); + if (!connector::is_equal(name, old_value, new_value)) + { + transient.put(name, new_value); + connector::notify_values(name); + emit changed(); + } + } } bool bundle::contains(const QString &name) const @@ -152,14 +156,8 @@ void bundler::refresh_all_bundles() bundler_singleton().after_profile_changed_(); } -bundler::bundler() : implsgl_mtx(QMutex::Recursive) -{ -} - -bundler::~bundler() -{ - //qDebug() << "exit: bundle singleton"; -} +bundler::bundler() = default; +bundler::~bundler() = default; std::shared_ptr<bundler::v> bundler::make_bundle_(const bundler::k& key) { diff --git a/options/bundle.hpp b/options/bundle.hpp index a12a335c..98291fc5 100644 --- a/options/bundle.hpp +++ b/options/bundle.hpp @@ -48,7 +48,7 @@ class OTR_OPTIONS_EXPORT bundle final : public QObject, public connector class OTR_OPTIONS_EXPORT mutex final : public QMutex { public: - mutex(QMutex::RecursionMode mode) : QMutex(mode) {} + explicit mutex(QMutex::RecursionMode mode) : QMutex(mode) {} operator QMutex*() const { return const_cast<QMutex*>(static_cast<const QMutex*>(this)); } }; @@ -70,7 +70,7 @@ public: bundle& operator=(const bundle&) = delete; QMutex* get_mtx() const override; - cc_noinline bundle(const QString& group_name); + cc_noinline explicit bundle(const QString& group_name); cc_noinline ~bundle() override; QString name() const { return group_name; } cc_noinline void store_kv(const QString& name, const QVariant& datum); @@ -83,6 +83,7 @@ public: QMutexLocker l(mtx); return transient.get<t>(name); } + public slots: void save(); void reload(); @@ -97,7 +98,7 @@ struct OTR_OPTIONS_EXPORT bundler final using shared = std::shared_ptr<v>; private: - QMutex implsgl_mtx; + QMutex implsgl_mtx { QMutex::Recursive }; std::map<k, weak> implsgl_data; void after_profile_changed_(); diff --git a/options/connector.cpp b/options/connector.cpp index 0efac8f1..73aefed8 100644 --- a/options/connector.cpp +++ b/options/connector.cpp @@ -18,7 +18,7 @@ static bool generic_is_equal(const QVariant& val1, const QVariant& val2) return val1 == val2; } -connector::~connector() {} +connector::~connector() = default; bool connector::is_equal(const QString& name, const QVariant& val1, const QVariant& val2) const { @@ -109,23 +109,17 @@ void connector::notify_values(const QString& name) const { auto it = connected_values.find(name); if (it != connected_values.cend()) - { for (value_type val : std::get<0>((*it).second)) - { val->bundle_value_changed(); - } - } } void connector::notify_all_values() const { - for (auto& pair : connected_values) - for (value_type val : std::get<0>(pair.second)) + for (auto& [k, v] : connected_values) + for (value_type val : std::get<0>(v)) val->bundle_value_changed(); } -connector::connector() -{ -} +connector::connector() = default; } // ns options::detail diff --git a/options/defs.hpp b/options/defs.hpp index 2467a7a0..a71a56e2 100644 --- a/options/defs.hpp +++ b/options/defs.hpp @@ -7,35 +7,5 @@ #define OPENTRACK_CONFIG_FILENAME_KEY "settings-filename" #define OPENTRACK_DEFAULT_CONFIG "default.ini" -#define OTR_OPTIONS_EXPAND2(x) x -#define OTR_OPTIONS_EXPAND1(x) OTR_OPTIONS_EXPAND2(x) -#define OPENTRACK_DEFINE_METATYPE2(t, ctr) \ - OPENTRACK_DEFINE_METATYPE3(t, ctr) - -#define OPENTRACK_DEFINE_METATYPE3(t, ctr) \ - OPENTRACK_DEFINE_METATYPE4(t, init_metatype_ ## ctr) - -#define OPENTRACK_DEFINE_METATYPE4(t, sym) \ - static class sym { \ - static const int dribble; \ - } sym ## _singleton; \ - const int sym :: dribble = ::options::detail::custom_type_initializer::declare_for_type<t>(#t); - -#define OPENTRACK_DEFINE_METATYPE(t) OPENTRACK_DEFINE_METATYPE2(t, __COUNTER__) - -namespace options::detail { - -struct custom_type_initializer final -{ - template<typename t> static int declare_for_type(const char* str) - { - qRegisterMetaType<t>(str); - qRegisterMetaTypeStreamOperators<t>(); - - return -1; - } -}; - -} // ns options::detail diff --git a/options/globals.cpp b/options/globals.cpp new file mode 100644 index 00000000..85a6bdf2 --- /dev/null +++ b/options/globals.cpp @@ -0,0 +1,160 @@ +#include "globals.hpp" +#include "compat/base-path.hpp" +#include "defs.hpp" + +#include <QFile> +#include <QDir> +#include <QStandardPaths> +#include <QDebug> + +namespace options::globals::detail { + +bool is_portable_installation() +{ +#if defined _WIN32 + // must keep consistent between invocations + static const bool ret = QFile::exists(OPENTRACK_BASE_PATH + "/portable.txt"); + return ret; +#endif + return false; +} + +saver_::~saver_() +{ + if (--ctx.refcount == 0 && ctx.modifiedp) + { + ctx.modifiedp = false; + auto& settings = *ctx.qsettings; + settings.sync(); + if (settings.status() != QSettings::NoError) + qDebug() << "error with .ini file" << settings.fileName() << settings.status(); + } + ctx.mtx.unlock(); +} + +saver_::saver_(ini_ctx& ini) : ctx { ini } +{ + ctx.refcount++; +} + +ini_ctx& cur_settings() +{ + static ini_ctx ini; + const QString pathname = ini_pathname(); + static QString ini_pathname; + + ini.mtx.lock(); + + if (pathname.isEmpty()) + { + ini.qsettings.emplace(); + ini.pathname = pathname; + } + + if (pathname != ini_pathname) + { + ini.qsettings.emplace(pathname, QSettings::IniFormat); + ini.pathname = pathname; + } + + return ini; +} + +ini_ctx& global_settings() +{ + static ini_ctx ini; + + ini.mtx.lock(); + + if (!is_portable_installation()) + // Windows registry or xdg on Linux + ini.qsettings.emplace(OPENTRACK_ORG); + else + { + static const QString pathname = OPENTRACK_BASE_PATH + QStringLiteral("/globals.ini"); + // file in executable's directory + ini.qsettings.emplace(pathname, QSettings::IniFormat); + ini.pathname = pathname; + } + + return ini; +} + +} // ns options::globals::detail + +namespace options::globals +{ + +QString ini_filename() +{ + return with_global_settings_object([&](QSettings& settings) { + const QString ret = settings.value(OPENTRACK_CONFIG_FILENAME_KEY, OPENTRACK_DEFAULT_CONFIG).toString(); + if (ret.size() == 0) + return QStringLiteral(OPENTRACK_DEFAULT_CONFIG); + return ret; + }); +} + +QString ini_pathname() +{ + const auto dir = ini_directory(); + if (dir.isEmpty()) + return {}; + return dir + "/" + ini_filename(); +} + +QString ini_combine(const QString& filename) +{ + return ini_directory() + QStringLiteral("/") + filename; +} + +QStringList ini_list() +{ + const auto dirname = ini_directory(); + if (dirname == "") + return QStringList(); + QDir settings_dir(dirname); + QStringList list = settings_dir.entryList( QStringList { "*.ini" } , QDir::Files, QDir::Name ); + std::sort(list.begin(), list.end()); + return list; +} + +void mark_ini_modified() +{ + using namespace detail; + auto& ini = cur_settings(); + ini.modifiedp = true; + ini.mtx.unlock(); +} + +QString ini_directory() +{ + QString dir; + + if (detail::is_portable_installation()) + { + dir = OPENTRACK_BASE_PATH; + + static const QString subdir = "ini"; + + if (!QDir(dir).mkpath(subdir)) + return QString(); + + return dir + '/' + subdir; + } + else + { + dir = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).value(0, QString()); + if (dir.isEmpty()) + return QString(); + if (!QDir(dir).mkpath(OPENTRACK_ORG)) + return QString(); + + dir += '/'; + dir += OPENTRACK_ORG; + } + + return dir; +} + +} // ns options::globals diff --git a/options/globals.hpp b/options/globals.hpp new file mode 100644 index 00000000..4d74cbf0 --- /dev/null +++ b/options/globals.hpp @@ -0,0 +1,71 @@ +#pragma once + +#include "export.hpp" +#include "compat/macros.hpp" + +#include <optional> + +#include <QString> +#include <QSettings> +#include <QMutex> + +namespace options::globals::detail { + +struct ini_ctx; +struct saver_; + +OTR_OPTIONS_EXPORT ini_ctx& cur_settings(); +OTR_OPTIONS_EXPORT ini_ctx& global_settings(); +OTR_OPTIONS_EXPORT bool is_portable_installation(); + +struct ini_ctx +{ + std::optional<QSettings> qsettings { std::in_place }; + int refcount = 0; + bool modifiedp = false; + QMutex mtx { QMutex::Recursive }; + QString pathname; +}; + +struct OTR_OPTIONS_EXPORT saver_ final +{ + ini_ctx& ctx; + + cc_noinline ~saver_(); + explicit cc_noinline saver_(ini_ctx& ini); +}; + +template<typename F> +cc_noinline +auto with_settings_object_(ini_ctx& ini, F&& fun) +{ + saver_ saver { ini }; + + return fun(*ini.qsettings); +} + +} // ns options::globals::detail + +namespace options::globals +{ + OTR_OPTIONS_EXPORT void mark_ini_modified(); + OTR_OPTIONS_EXPORT QString ini_directory(); + OTR_OPTIONS_EXPORT QString ini_filename(); + OTR_OPTIONS_EXPORT QString ini_pathname(); + OTR_OPTIONS_EXPORT QString ini_combine(const QString& filename); + OTR_OPTIONS_EXPORT QStringList ini_list(); + + template<typename F> + auto with_settings_object(F&& fun) + { + using namespace detail; + return with_settings_object_(cur_settings(), fun); + } + + template<typename F> + auto with_global_settings_object(F&& fun) + { + using namespace detail; + return with_settings_object_(global_settings(), fun); + } +} // ns options::globals diff --git a/options/group.cpp b/options/group.cpp index 788dd5de..5f6c3232 100644 --- a/options/group.cpp +++ b/options/group.cpp @@ -8,18 +8,19 @@ #include "group.hpp" #include "defs.hpp" +#include "globals.hpp" -#include "compat/timer.hpp" -#include "compat/library-path.hpp" - -#include <cmath> +#include <utility> +#include <algorithm> #include <QFile> -#include <QStandardPaths> + #include <QDir> #include <QDebug> -namespace options { +namespace options::detail { + +using namespace options::globals; group::group(const QString& name) : name(name) { @@ -66,146 +67,14 @@ bool group::contains(const QString &s) const return it != kvs.cend() && it->second != QVariant::Invalid; } -bool group::is_portable_installation() -{ -#if defined _WIN32 - return QFile::exists(OPENTRACK_BASE_PATH + "/portable.txt"); -#endif - return false; -} - -QString group::ini_directory() +QVariant group::get_variant(const QString& name) const { + auto it = kvs.find(name); + if (it != kvs.cend()) + return it->second; - QString dir; - - if (is_portable_installation()) - { - dir = OPENTRACK_BASE_PATH; - - static const QString subdir = "ini"; - - if (!QDir(dir).mkpath(subdir)) - return QString(); - - return dir + '/' + subdir; - } - else - { - dir = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).value(0, QString()); - if (dir.isEmpty()) - return QString(); - if (!QDir(dir).mkpath(OPENTRACK_ORG)) - return QString(); - - dir += '/'; - dir += OPENTRACK_ORG; - } - - return dir; + return {}; } -QString group::ini_filename() -{ - return with_global_settings_object([&](QSettings& settings) { - const QString ret = settings.value(OPENTRACK_CONFIG_FILENAME_KEY, OPENTRACK_DEFAULT_CONFIG).toString(); - if (ret.size() == 0) - return QStringLiteral(OPENTRACK_DEFAULT_CONFIG); - return ret; - }); -} - -QString group::ini_pathname() -{ - const auto dir = ini_directory(); - if (dir == "") - return ""; - return dir + "/" + ini_filename(); -} - -QString group::ini_combine(const QString& filename) -{ - return ini_directory() + QStringLiteral("/") + filename; -} - -QStringList group::ini_list() -{ - const auto dirname = ini_directory(); - if (dirname == "") - return QStringList(); - QDir settings_dir(dirname); - QStringList list = settings_dir.entryList( QStringList { "*.ini" } , QDir::Files, QDir::Name ); - std::sort(list.begin(), list.end()); - return list; -} - -void group::mark_ini_modified() -{ - QMutexLocker l(&cur_ini_mtx); - ini_modifiedp = true; -} - -QString group::cur_ini_pathname; - -std::shared_ptr<QSettings> group::cur_ini; -QMutex group::cur_ini_mtx(QMutex::Recursive); -int group::ini_refcount = 0; -bool group::ini_modifiedp = false; - -std::shared_ptr<QSettings> group::cur_global_ini; -QMutex group::global_ini_mtx(QMutex::Recursive); -int group::global_ini_refcount = 0; -bool group::global_ini_modifiedp = false; - -std::shared_ptr<QSettings> group::cur_settings_object() -{ - const QString pathname = ini_pathname(); - - if (pathname.isEmpty()) - return std::make_shared<QSettings>(); - - if (pathname != cur_ini_pathname) - { - cur_ini = std::make_shared<QSettings>(pathname, QSettings::IniFormat); - cur_ini_pathname = pathname; - } - - return cur_ini; -} - -std::shared_ptr<QSettings> group::cur_global_settings_object() -{ - if (cur_global_ini) - return cur_global_ini; - - if (!is_portable_installation()) - cur_global_ini = std::make_shared<QSettings>(OPENTRACK_ORG); - else - { - static const QString pathname = OPENTRACK_BASE_PATH + QStringLiteral("/globals.ini"); - cur_global_ini = std::make_shared<QSettings>(pathname, QSettings::IniFormat); - } - - return cur_global_ini; -} - -cc_noinline -group::saver_::~saver_() -{ - if (--refcount == 0 && modifiedp) - { - modifiedp = false; - s.sync(); - if (s.status() != QSettings::NoError) - qDebug() << "error with .ini file" << s.fileName() << s.status(); - } -} - -cc_noinline -group::saver_::saver_(QSettings& s, int& refcount, bool& modifiedp) : - s(s), refcount(refcount), modifiedp(modifiedp) -{ - refcount++; -} +} // ns options::detail -} // ns options diff --git a/options/group.hpp b/options/group.hpp index f191fdd5..ef9f1121 100644 --- a/options/group.hpp +++ b/options/group.hpp @@ -1,96 +1,49 @@ #pragma once +#include "options/defs.hpp" + +#include "compat/base-path.hpp" +#include "compat/library-path.hpp" +#include "compat/qhash.hpp" #include "compat/macros.hpp" #include "export.hpp" -// included here to propagate into callers of options::group -#include "metatype.hpp" +#include <optional> +#include <unordered_map> -#include <map> -#include <memory> +#include <QHash> #include <QString> -#include <QList> +#include <QMutex> +#include <QFile> +#include <QDir> +#include <QStandardPaths> #include <QVariant> #include <QSettings> -#include <QMutex> +#include <QDebug> // XXX TODO remove qsettings usage -sh 20180624 -namespace options { - -// snapshot of qsettings group at given time -class OTR_OPTIONS_EXPORT group final -{ - QString name; - - static QString cur_ini_pathname; - - static std::shared_ptr<QSettings> cur_ini; - static int ini_refcount; - static bool ini_modifiedp; - static QMutex cur_ini_mtx; - - static std::shared_ptr<QSettings> cur_global_ini; - static int global_ini_refcount; - static bool global_ini_modifiedp; - static QMutex global_ini_mtx; - - struct OTR_OPTIONS_EXPORT saver_ final +namespace options::detail { + // snapshot of qsettings group at given time + class OTR_OPTIONS_EXPORT group final { - QSettings& s; - int& refcount; - bool& modifiedp; - - cc_noinline ~saver_(); - cc_noinline saver_(QSettings& s, int& refcount, bool& modifiedp); + QString name; + + public: + std::unordered_map<QString, QVariant> kvs; + explicit group(const QString& name); + void save() const; + void put(const QString& s, const QVariant& d); + bool contains(const QString& s) const; + + template<typename t> + cc_noinline t get(const QString& k) const + { + return get_variant(k).value<t>(); + } + + cc_noinline QVariant get_variant(const QString& name) const; }; - static std::shared_ptr<QSettings> cur_settings_object(); - static std::shared_ptr<QSettings> cur_global_settings_object(); - -public: - std::map<QString, QVariant> kvs; - group(const QString& name); - void save() const; - void put(const QString& s, const QVariant& d); - bool contains(const QString& s) const; - static QString ini_directory(); - static QString ini_filename(); - static QString ini_pathname(); - static QString ini_combine(const QString& filename); - static QStringList ini_list(); - static bool is_portable_installation(); - - static void mark_ini_modified(); - - template<typename t> - cc_noinline - t get(const QString& k) const - { - auto value = kvs.find(k); - if (value != kvs.cend()) - return value->second.value<t>(); - return t(); - } - - template<typename F> - cc_noinline - static auto with_settings_object(F&& fun) - { - QMutexLocker l(&cur_ini_mtx); - saver_ saver { *cur_settings_object(), ini_refcount, ini_modifiedp }; - - return fun(saver.s); - } - - template<typename F> - static auto with_global_settings_object(F&& fun) - { - QMutexLocker l(&global_ini_mtx); - saver_ saver { *cur_global_settings_object(), global_ini_refcount, global_ini_modifiedp }; - global_ini_modifiedp = true; +} // ns options::detail - return fun(saver.s); - } -}; -} diff --git a/options/metatype.cpp b/options/metatype.cpp index 0fa33933..e54970c0 100644 --- a/options/metatype.cpp +++ b/options/metatype.cpp @@ -1,3 +1,31 @@ -#include "defs.hpp" +#include <QMetaType> + +namespace options::detail { + +template<typename t> +int declare_metatype_for_type(const char* str) +{ + qRegisterMetaType<t>(str); + qRegisterMetaTypeStreamOperators<t>(); + + return -1; +} + +} // ns options::detail + +#define OPENTRACK_DEFINE_METATYPE2(t, ctr) \ + OPENTRACK_DEFINE_METATYPE3(t, ctr) + +#define OPENTRACK_DEFINE_METATYPE3(t, ctr) \ + OPENTRACK_DEFINE_METATYPE4(t, init_metatype_ ## ctr) + +#define OPENTRACK_DEFINE_METATYPE4(t, sym) \ + static class sym { \ + static const int dribble; \ + } sym ## _singleton; \ + const int sym :: dribble = ::options::detail::declare_metatype_for_type<t>(#t) + +#define OPENTRACK_DEFINE_METATYPE(t) OPENTRACK_DEFINE_METATYPE2(t, __COUNTER__) + #define OPENTRACK_METATYPE_(x) OPENTRACK_DEFINE_METATYPE(x) #include "metatype.hpp" diff --git a/options/metatype.hpp b/options/metatype.hpp index 023c1a36..9d3cbda1 100644 --- a/options/metatype.hpp +++ b/options/metatype.hpp @@ -7,6 +7,7 @@ #include "slider.hpp" #include "defs.hpp" +#include <QMetaType> #ifndef OPENTRACK_METATYPE_ # define OPENTRACK_METATYPE(x) Q_DECLARE_METATYPE(x) @@ -14,12 +15,12 @@ # define OPENTRACK_METATYPE(x) Q_DECLARE_METATYPE(x) OPENTRACK_METATYPE_(x) #endif -OPENTRACK_METATYPE(QList<double>) -OPENTRACK_METATYPE(QList<float>) -OPENTRACK_METATYPE(QList<int>) -OPENTRACK_METATYPE(QList<bool>) -OPENTRACK_METATYPE(QList<QString>) -OPENTRACK_METATYPE(QList<QPointF>) -OPENTRACK_METATYPE(::options::slider_value) - - +#if !defined __clang_analyzer__ && !defined Q_CREATOR_RUN +OPENTRACK_METATYPE(QList<double>); +OPENTRACK_METATYPE(QList<float>); +OPENTRACK_METATYPE(QList<int>); +OPENTRACK_METATYPE(QList<bool>); +OPENTRACK_METATYPE(QList<QString>); +OPENTRACK_METATYPE(QList<QPointF>); +OPENTRACK_METATYPE(::options::slider_value); +#endif diff --git a/options/options.hpp b/options/options.hpp index bc892120..a99d5c59 100644 --- a/options/options.hpp +++ b/options/options.hpp @@ -8,9 +8,8 @@ #include "defs.hpp" #include "bundle.hpp" -#include "group.hpp" #include "slider.hpp" #include "value.hpp" #include "tie.hpp" -#include "metatype.hpp" #include "scoped.hpp" +#include "globals.hpp" diff --git a/options/value-traits.hpp b/options/value-traits.hpp index b507874c..1c98f3e9 100644 --- a/options/value-traits.hpp +++ b/options/value-traits.hpp @@ -18,9 +18,19 @@ struct default_value_traits using stored_type = std::decay_t<t>; using value_type = std::decay_t<u>; - static inline value_type from_value(const value_type& val, const value_type&) { return val; } - static inline value_type from_storage(const stored_type& x) { return static_cast<value_type>(x); } - static inline stored_type to_storage(const value_type& val) { return static_cast<stored_type>(val); } + static value_type from_value(const value_type& val, const value_type&) { return val; } + static value_type from_storage(const stored_type& x) { return static_cast<value_type>(x); } + static stored_type to_storage(const value_type& val) { return static_cast<stored_type>(val); } + + static value_type value_from_variant(const QVariant& x) + { + return from_storage(storage_from_variant(x)); + } + + static stored_type storage_from_variant(const QVariant& x) + { + return x.value<stored_type>(); + } }; template<typename t, typename u = t, typename Enable = void> diff --git a/options/value.hpp b/options/value.hpp index e73456ca..af3cfd57 100644 --- a/options/value.hpp +++ b/options/value.hpp @@ -16,24 +16,19 @@ #include "value-traits.hpp" #include "compat/macros.hpp" -#include <cstdio> #include <type_traits> #include <typeinfo> -#include <typeindex> -#include <utility> -#include <QVariant> -#include <QString> -#include <QPointF> -#include <QList> -#include <QMutex> +#include <QMetaType> namespace options { template<typename t> class value final : public value_ { - using traits = detail::value_traits<t, t, void>; + const t def; + + using traits = detail::value_traits<t>; using stored_type = typename traits::stored_type; static bool is_equal(const QVariant& val1, const QVariant& val2) @@ -52,22 +47,40 @@ class value final : public value_ if (!b->contains(self_name) || variant.type() == QVariant::Invalid) return def; - const stored_type x(variant.value<stored_type>()); + const stored_type x { variant.value<stored_type>() }; return traits::from_value(traits::from_storage(x), def); } + friend class detail::connector; + void bundle_value_changed() const override + { + if (!self_name.isEmpty()) + emit valueChanged(traits::to_storage(get())); + } + + void store_variant(const QVariant& value) override + { + if (self_name.isEmpty()) + return; + + if (value.type() == qMetaTypeId<stored_type>()) + b->store_kv(self_name, value); + else + operator=(traits::value_from_variant(value)); + } + public: cc_noinline - t operator=(const t& datum) + value<t>& operator=(const t& datum) { if (self_name.isEmpty()) - return def; + return *this; if (datum != get()) - store(traits::to_storage(datum)); + b->store_kv(self_name, QVariant::fromValue<stored_type>(traits::to_storage(datum))); - return datum; + return *this; } static constexpr inline Qt::ConnectionType DIRECT_CONNTYPE = Qt::DirectConnection; @@ -79,8 +92,8 @@ public: def(def) { if (!self_name.isEmpty()) - QObject::connect(b.get(), SIGNAL(reloading()), - this, SLOT(reload()), + QObject::connect(b.get(), &detail::bundle::reloading, + this, &value_::reload, DIRECT_CONNTYPE); } @@ -96,52 +109,49 @@ public: *this = def; } - operator t() const { return get(); } + operator t() const { return get(); } // NOLINT - t operator->() const - { - return get(); - } + template<typename u, typename = decltype(static_cast<u>(std::declval<t>()))> + explicit cc_forceinline operator u() const { return to<u>(); } - cc_noinline - void reload() override + auto operator->() const { - if (!self_name.isEmpty()) - *this = static_cast<t>(*this); + struct dereference_wrapper final + { + cc_forceinline t const* operator->() const { return &x; } + cc_forceinline t* operator->() { return &x; } + t x; + explicit cc_forceinline dereference_wrapper(t&& x) : x(x) {} + }; + + return dereference_wrapper { get() }; } cc_noinline - void bundle_value_changed() const override + void reload() override { +#if 0 if (!self_name.isEmpty()) - emit valueChanged(traits::to_storage(get())); - } - - t operator()() const - { - return get(); + store(traits::to_storage(get())); +#endif } - t operator*() const - { - return get(); - } + cc_forceinline t operator()() const { return get(); } + cc_forceinline t operator*() const { return get(); } template<typename u> u to() const { return static_cast<u>(get()); } - -private: - const t def; }; -#if !defined OTR_INST_VALUE -# define OTR_INST_VALUE OTR_TEMPLATE_IMPORT -#endif - +// some linker problems #if !defined __APPLE__ +# if !defined OTR_INST_VALUE +# define OTR_INST_VALUE OTR_TEMPLATE_IMPORT +# endif + OTR_INST_VALUE(value<double>); OTR_INST_VALUE(value<float>); OTR_INST_VALUE(value<int>); |