diff options
Diffstat (limited to 'options/value.hpp')
| -rw-r--r-- | options/value.hpp | 316 |
1 files changed, 151 insertions, 165 deletions
diff --git a/options/value.hpp b/options/value.hpp index 020cbeea..9a7487b8 100644 --- a/options/value.hpp +++ b/options/value.hpp @@ -10,226 +10,212 @@ #include "export.hpp" -#include "compat/util.hpp" - -#include "connector.hpp" #include "bundle.hpp" #include "slider.hpp" -#include <type_traits> -#include <typeinfo> -#include <typeindex> -#include <QString> -#include <QPointF> -#include <QList> - -#define OPENTRACK_DEFINE_SLOT(t) void setValue(t datum) { store(datum); } -#define OPENTRACK_DEFINE_SIGNAL(t) void valueChanged(t) const -namespace options { +#include "base-value.hpp" +#include "value-traits.hpp" -namespace detail { -template<typename t> struct value_type_traits { using type = t;}; -template<> struct value_type_traits<QString> { using type = const QString&; }; -template<> struct value_type_traits<slider_value> { using type = const slider_value&; }; -template<typename u> struct value_type_traits<QList<u>> -{ - using type = const QList<u>&; -}; -template<typename t> using value_type_t = typename value_type_traits<t>::type; -} +#include <type_traits> +#include <utility> -class OTR_OPTIONS_EXPORT base_value : public QObject -{ - Q_OBJECT - friend class ::options::detail::connector; - - using comparator = bool(*)(const QVariant& val1, const QVariant& val2); -public: - QString name() const { return self_name; } - base_value(bundle b, const QString& name, comparator cmp, std::type_index type_idx); - ~base_value() override; -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>&); -protected: - bundle b; - QString self_name; - comparator cmp; - std::type_index type_index; - - void store(const QVariant& datum) - { - b->store_kv(self_name, datum); - } +#include <QMetaType> +namespace options::detail { template<typename t> - void store(const t& datum) + class dereference_wrapper final { - b->store_kv(self_name, QVariant::fromValue(datum)); - } + t x; + public: + constexpr t const* operator->() const { return &x; } + constexpr t* operator->() { return &x; } + constexpr explicit dereference_wrapper(t&& x) : x(x) {} + }; +} // ns options::detail -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>&) - - virtual void reload() = 0; - virtual void bundle_value_changed() const = 0; - virtual void set_to_default() = 0; -}; +namespace options { -namespace detail { template<typename t> -struct value_get_traits +class value final : public value_ { - static inline t get(const t& val, const t&) - { - return val; - } -}; + static_assert(std::is_same_v<t, std::remove_cvref_t<t>>); + mutable QMutex mtx; + const t def; + mutable t cached_value; + using traits = detail::value_traits<t>; -template<> -struct value_get_traits<slider_value> -{ - using t = slider_value; - static inline t get(const t& val, const t& def) + never_inline + auto get() const noexcept { - return t(val.cur(), def.min(), def.max()); - } -}; + if (!b->contains(self_name)) + return traits::pass_value(def); -template<typename t, typename Enable = void> -struct value_element_type -{ - using type = typename std::remove_reference<typename std::remove_cv<t>::type>::type; -}; + QVariant variant = b->get_variant(self_name); -// Qt uses int a lot in slots so use it for all enums -template<typename t> -struct value_element_type<t, typename std::enable_if<std::is_enum<t>::value>::type> -{ - using type = int; -}; + if (variant.isNull() || !variant.isValid()) + return traits::pass_value(def); -template<> struct value_element_type<float, void> { using type = double; }; + return traits::pass_value(traits::value_with_default(traits::value_from_qvariant(variant), def)); + } -template<typename t> using value_element_type_t = typename value_element_type<t>::type; + never_inline + void store_variant(QVariant&& value) noexcept override + { + if (traits::is_equal(get(), traits::value_from_qvariant(value))) + return; -} + if (is_null()) + return; -template<typename t> -class value final : public base_value -{ - static bool is_equal(const QVariant& val1, const QVariant& val2) + if (value.isValid() && !value.isNull()) + b->store_kv(self_name, value); + else + b->store_kv(self_name, traits::qvariant_from_value(def)); + } + + never_inline + void store_variant(const QVariant& value) noexcept override { - return val1.value<element_type>() == val2.value<element_type>(); + QVariant copy{value}; + store_variant(std::move(copy)); } -public: - using element_type = detail::value_element_type_t<t>; + bool is_null() const + { + return self_name.isEmpty() || b->name().isEmpty(); + } - OTR_NEVER_INLINE - t operator=(const t& datum) +public: + QVariant get_variant() const noexcept override { - const element_type tmp = static_cast<element_type>(datum); - if (tmp != get()) - store(tmp); - return datum; + if (QVariant ret{b->get_variant(self_name)}; ret.isValid() && !ret.isNull()) + return ret; + + return traits::qvariant_from_value(def); } - static constexpr const Qt::ConnectionType DIRECT_CONNTYPE = Qt::DirectConnection; - static constexpr const Qt::ConnectionType SAFE_CONNTYPE = Qt::QueuedConnection; + never_inline + void notify_() const override + { + auto x = get(); + { + QMutexLocker l(&mtx); + cached_value = x; + } + maybe_trace("notify +"); + emit valueChanged(traits::storage_from_value(x)); + maybe_trace("notify -"); + } - OTR_NEVER_INLINE - value(bundle b, const QString& name, t def) : - base_value(b, name, &is_equal, std::type_index(typeid(element_type))), def(def) + never_inline + void notify() const override { - QObject::connect(b.get(), SIGNAL(reloading()), - this, SLOT(reload()), - DIRECT_CONNTYPE); - if (!b->contains(name) || b->get<QVariant>(name).type() == QVariant::Invalid) - *this = def; + if (is_null()) + return; + + auto x = get(); + { + QMutexLocker l(&mtx); + if (traits::is_equal(x, cached_value)) + { + //maybe_trace("notify ~"); + return; + } + else + { + cached_value = x; + l.unlock(); + maybe_trace("notify +"); + emit valueChanged(traits::storage_from_value(x)); + maybe_trace("notify -"); + } + } } - OTR_NEVER_INLINE - value(bundle b, const char* name, t def) : value(b, QString(name), def) + auto& operator=(t&& datum) noexcept { + if (is_null()) + return *this; + + store_variant(traits::qvariant_from_value(traits::pass_value(datum))); + maybe_trace("set-value"); + return *this; } - t default_value() const + auto& operator=(const t& datum) noexcept { - return def; + if (is_null()) + return *this; + + t copy{datum}; + *this = std::move(copy); + return *this; } - OTR_NEVER_INLINE - void set_to_default() override + auto& operator=(const value<t>& datum) noexcept { - *this = def; + *this = *datum; + return *this; } - OTR_NEVER_INLINE - operator t() const { return get(); } + static constexpr Qt::ConnectionType DIRECT_CONNTYPE = Qt::DirectConnection; + static constexpr Qt::ConnectionType SAFE_CONNTYPE = Qt::QueuedConnection; - OTR_NEVER_INLINE - void reload() override + value(bundle b, const QString& name, t def) noexcept : value_(b, name), def(std::move(def)), cached_value{get()} { - *this = static_cast<t>(*this); } - void bundle_value_changed() const override + //value(const value<t>& other) noexcept : value{other.b, other.self_name, other.def} {} + value(const value<t>&) = delete; + + t default_value() const { - emit valueChanged(static_cast<detail::value_type_t<t>>(get())); + return def; } - OTR_NEVER_INLINE - t operator()() const + void set_to_default() noexcept override { - return static_cast<t>(get()); + *this = def; } + operator t() const { return get(); } + template<typename u> - OTR_NEVER_INLINE - u to() const + explicit force_inline operator u() const { return to<u>(); } + + auto operator->() const noexcept { - return static_cast<u>(get()); + return detail::dereference_wrapper<t>{get()}; } -private: - OTR_NEVER_INLINE - t get() const + force_inline auto operator()() const noexcept { return get(); } + force_inline auto operator*() const noexcept { return get(); } + + template<typename u> + u to() const noexcept { - t val = b->contains(self_name) - ? static_cast<t>(b->get<element_type>(self_name)) - : def; - return detail::value_get_traits<t>::get(val, def); + return static_cast<u>(get()); } - - const t def; }; +#if !defined OTR_OPTIONS_INST_VALUE +# define OTR_OPTIONS_INST_VALUE OTR_TEMPLATE_IMPORT +#endif + +OTR_OPTIONS_INST_VALUE(value<double>) +OTR_OPTIONS_INST_VALUE(value<float>) +OTR_OPTIONS_INST_VALUE(value<int>) +OTR_OPTIONS_INST_VALUE(value<bool>) +OTR_OPTIONS_INST_VALUE(value<QString>) +OTR_OPTIONS_INST_VALUE(value<slider_value>) +OTR_OPTIONS_INST_VALUE(value<QPointF>) +OTR_OPTIONS_INST_VALUE(value<QVariant>) +OTR_OPTIONS_INST_VALUE(value<QList<double>>) +OTR_OPTIONS_INST_VALUE(value<QList<float>>) +OTR_OPTIONS_INST_VALUE(value<QList<int>>) +OTR_OPTIONS_INST_VALUE(value<QList<bool>>) +OTR_OPTIONS_INST_VALUE(value<QList<QString>>) +OTR_OPTIONS_INST_VALUE(value<QList<slider_value>>) +OTR_OPTIONS_INST_VALUE(value<QList<QPointF>>) +OTR_OPTIONS_INST_VALUE(value<QList<QVariant>>) + } // ns options |
