summaryrefslogtreecommitdiffhomepage
path: root/options/value.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'options/value.hpp')
-rw-r--r--options/value.hpp237
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