diff options
Diffstat (limited to 'options/value.hpp')
| -rw-r--r-- | options/value.hpp | 237 |
1 files changed, 144 insertions, 93 deletions
diff --git a/options/value.hpp b/options/value.hpp index c8fb02ca..9a7487b8 100644 --- a/options/value.hpp +++ b/options/value.hpp @@ -14,157 +14,208 @@ #include "slider.hpp" #include "base-value.hpp" #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::detail { + template<typename t> + class dereference_wrapper final + { + 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 namespace options { template<typename t> -class value final : public base_value +class value final : public value_ { - using traits = detail::value_traits<t, t, void>; - using element_type = typename traits::element_type; + 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>; - static bool is_equal(const QVariant& val1, const QVariant& val2) + never_inline + auto get() const noexcept { - return val1.value<element_type>() == val2.value<element_type>(); + if (!b->contains(self_name)) + return traits::pass_value(def); + + QVariant variant = b->get_variant(self_name); + + if (variant.isNull() || !variant.isValid()) + return traits::pass_value(def); + + return traits::pass_value(traits::value_with_default(traits::value_from_qvariant(variant), def)); } never_inline - t get() const + void store_variant(QVariant&& value) noexcept override { - if (self_name.isEmpty()) - return def; + if (traits::is_equal(get(), traits::value_from_qvariant(value))) + return; - QVariant variant = b->get<QVariant>(self_name); + if (is_null()) + return; - if (!b->contains(self_name) || variant.type() == QVariant::Invalid) - return def; + if (value.isValid() && !value.isNull()) + b->store_kv(self_name, value); + else + b->store_kv(self_name, traits::qvariant_from_value(def)); + } - const element_type x(variant.value<element_type>()); + never_inline + void store_variant(const QVariant& value) noexcept override + { + QVariant copy{value}; + store_variant(std::move(copy)); + } - return traits::from_value(traits::from_storage(x), def); + bool is_null() const + { + return self_name.isEmpty() || b->name().isEmpty(); } public: - never_inline - t operator=(const t& datum) + QVariant get_variant() const noexcept override { - if (self_name.isEmpty()) - return def; - - if (datum != get()) - store(traits::to_storage(datum)); + if (QVariant ret{b->get_variant(self_name)}; ret.isValid() && !ret.isNull()) + return ret; - return datum; + return traits::qvariant_from_value(def); } - static constexpr inline Qt::ConnectionType DIRECT_CONNTYPE = Qt::DirectConnection; - static constexpr inline 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 -"); + } never_inline - value(bundle b, const QString& name, t def) : - base_value(b, name, &is_equal, std::type_index(typeid(element_type))), - def(def) - { - if (!self_name.isEmpty()) - QObject::connect(b.get(), SIGNAL(reloading()), - this, SLOT(reload()), - DIRECT_CONNTYPE); + void notify() const override + { + 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 -"); + } + } } - template<unsigned k> - inline value(bundle b, const char (&name)[k], t def) : value(b, QLatin1String(name, k-1), def) + auto& operator=(t&& datum) noexcept { - static_assert(k > 0, ""); + if (is_null()) + return *this; + + store_variant(traits::qvariant_from_value(traits::pass_value(datum))); + maybe_trace("set-value"); + return *this; } - never_inline - 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; } - never_inline - void set_to_default() override + auto& operator=(const value<t>& datum) noexcept { - *this = def; + *this = *datum; + return *this; } - never_inline - operator t() const { return get(); } + static constexpr Qt::ConnectionType DIRECT_CONNTYPE = Qt::DirectConnection; + static constexpr Qt::ConnectionType SAFE_CONNTYPE = Qt::QueuedConnection; - never_inline - t operator->() const + value(bundle b, const QString& name, t def) noexcept : value_(b, name), def(std::move(def)), cached_value{get()} { - return get(); } - never_inline - void reload() override + //value(const value<t>& other) noexcept : value{other.b, other.self_name, other.def} {} + value(const value<t>&) = delete; + + t default_value() const { - if (!self_name.isEmpty()) - *this = static_cast<t>(*this); + return def; } - never_inline - void bundle_value_changed() const override + void set_to_default() noexcept override { - if (!self_name.isEmpty()) - emit valueChanged(traits::to_storage(get())); + *this = def; } - never_inline - t operator()() const + operator t() const { return get(); } + + template<typename u> + explicit force_inline operator u() const { return to<u>(); } + + auto operator->() const noexcept { - return get(); + return detail::dereference_wrapper<t>{get()}; } + force_inline auto operator()() const noexcept { return get(); } + force_inline auto operator*() const noexcept { return get(); } + template<typename u> - never_inline - u to() const + u to() const noexcept { return static_cast<u>(get()); } - -private: - const t def; }; -#if defined _MSC_VER - -# if !defined OTR_OPT_VALUE -# define OTR_OPT_VALUE OTR_TEMPLATE_IMPORT -# endif - - OTR_OPT_VALUE value<double>; - OTR_OPT_VALUE value<float>; - OTR_OPT_VALUE value<int>; - OTR_OPT_VALUE value<bool>; - OTR_OPT_VALUE value<QString>; - OTR_OPT_VALUE value<slider_value>; - OTR_OPT_VALUE value<QPointF>; - OTR_OPT_VALUE value<QVariant>; - - OTR_OPT_VALUE value<QList<double>>; - OTR_OPT_VALUE value<QList<float>>; - OTR_OPT_VALUE value<QList<int>>; - OTR_OPT_VALUE value<QList<bool>>; - OTR_OPT_VALUE value<QList<QString>>; - OTR_OPT_VALUE value<QList<slider_value>>; - OTR_OPT_VALUE value<QList<QPointF>>; - +#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 |
