diff options
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>); | 
