summaryrefslogtreecommitdiffhomepage
path: root/options
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2018-07-08 23:29:49 +0200
committerStanislaw Halik <sthalik@misaki.pl>2018-07-08 23:29:49 +0200
commitfa1801471c2708ed8266ec7b99bd4cec886ccc1b (patch)
treeaa56218c2c7e4939aaf11a2046b0f12760326545 /options
parent90940a774eab876c38d5cef981b4be5bae67a462 (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.hpp82
-rw-r--r--options/bundle.cpp38
-rw-r--r--options/bundle.hpp7
-rw-r--r--options/connector.cpp14
-rw-r--r--options/defs.hpp30
-rw-r--r--options/globals.cpp160
-rw-r--r--options/globals.hpp71
-rw-r--r--options/group.cpp157
-rw-r--r--options/group.hpp113
-rw-r--r--options/metatype.cpp30
-rw-r--r--options/metatype.hpp19
-rw-r--r--options/options.hpp3
-rw-r--r--options/value-traits.hpp16
-rw-r--r--options/value.hpp96
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>);