aboutsummaryrefslogtreecommitdiff
path: root/lib/util.h
diff options
context:
space:
mode:
authorn-peugnet <n.peugnet@free.fr>2022-10-06 19:27:24 +0200
committern-peugnet <n.peugnet@free.fr>2022-10-06 19:27:24 +0200
commitd911b207f49e936b3e992200796110f0749ed150 (patch)
tree96d20ebb4d074a4c1755e21cb316a52d584daee3 /lib/util.h
parent8ad8a74152c5701b6ca1f9a00487ba9257a439b4 (diff)
parent56c2f2e2b809b9077393eb617828f33d144f5634 (diff)
downloadlibquotient-d911b207f49e936b3e992200796110f0749ed150.tar.gz
libquotient-d911b207f49e936b3e992200796110f0749ed150.zip
New upstream version 0.7.0
Diffstat (limited to 'lib/util.h')
-rw-r--r--lib/util.h433
1 files changed, 220 insertions, 213 deletions
diff --git a/lib/util.h b/lib/util.h
index 13eec143..ab219488 100644
--- a/lib/util.h
+++ b/lib/util.h
@@ -1,244 +1,251 @@
-/******************************************************************************
- * Copyright (C) 2016 Kitsune Ral <kitsune-ral@users.sf.net>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+// SPDX-FileCopyrightText: 2016 Kitsune Ral <kitsune-ral@users.sf.net>
+// SPDX-FileCopyrightText: 2019 Alexey Andreyev <aa13q@ya.ru>
+// SPDX-License-Identifier: LGPL-2.1-or-later
#pragma once
-#include <QtCore/QPointer>
-#if (QT_VERSION < QT_VERSION_CHECK(5, 5, 0))
-#include <QtCore/QMetaEnum>
-#include <QtCore/QDebug>
-#endif
+#include "quotient_export.h"
+
+#include <QtCore/QLatin1String>
+#include <QtCore/QHashFunctions>
-#include <functional>
#include <memory>
+#include <unordered_map>
-#if __cplusplus >= 201703L
-#define FALLTHROUGH [[fallthrough]]
-#elif __has_cpp_attribute(clang::fallthrough)
-#define FALLTHROUGH [[clang::fallthrough]]
-#else
-#define FALLTHROUGH // -fallthrough
+#ifndef Q_DISABLE_MOVE
+// Q_DISABLE_MOVE was introduced in Q_VERSION_CHECK(5,13,0)
+# define Q_DISABLE_MOVE(_ClassName) \
+ _ClassName(_ClassName&&) Q_DECL_EQ_DELETE; \
+ _ClassName& operator=(_ClassName&&) Q_DECL_EQ_DELETE;
#endif
-// Along the lines of Q_DISABLE_COPY
-#define DISABLE_MOVE(_ClassName) \
- _ClassName(_ClassName&&) Q_DECL_EQ_DELETE; \
- _ClassName& operator=(_ClassName&&) Q_DECL_EQ_DELETE;
+#ifndef Q_DISABLE_COPY_MOVE
+#define Q_DISABLE_COPY_MOVE(Class) \
+ Q_DISABLE_COPY(Class) \
+ Q_DISABLE_MOVE(Class)
+#endif
-#if QT_VERSION < QT_VERSION_CHECK(5, 7, 0)
-// Copy-pasted from Qt 5.10
-template <typename T>
-Q_DECL_CONSTEXPR typename std::add_const<T>::type &qAsConst(T &t) Q_DECL_NOTHROW { return t; }
-// prevent rvalue arguments:
-template <typename T>
-static void qAsConst(const T &&) Q_DECL_EQ_DELETE;
+#define DISABLE_MOVE(_ClassName) \
+static_assert(false, "Use Q_DISABLE_MOVE instead; Quotient enables it across all used versions of Qt");
+
+#ifndef QT_IGNORE_DEPRECATIONS
+// QT_IGNORE_DEPRECATIONS was introduced in Q_VERSION_CHECK(5,15,0)
+# define QT_IGNORE_DEPRECATIONS(statement) \
+ QT_WARNING_PUSH \
+ QT_WARNING_DISABLE_DEPRECATED \
+ statement \
+ QT_WARNING_POP
#endif
-namespace QMatrixClient
-{
- // The below enables pretty-printing of enums in logs
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
-#define REGISTER_ENUM(EnumName) Q_ENUM(EnumName)
+#if __cpp_conditional_explicit >= 201806L
+#define QUO_IMPLICIT explicit(false)
#else
- // Thanks to Olivier for spelling it and for making Q_ENUM to replace it:
- // https://woboq.com/blog/q_enum.html
-#define REGISTER_ENUM(EnumName) \
- Q_ENUMS(EnumName) \
- friend QDebug operator<<(QDebug dbg, EnumName val) \
- { \
- static int enumIdx = staticMetaObject.indexOfEnumerator(#EnumName); \
- return dbg << Event::staticMetaObject.enumerator(enumIdx).valueToKey(int(val)); \
- }
+#define QUO_IMPLICIT
#endif
- /** static_cast<> for unique_ptr's */
- template <typename T1, typename PtrT2>
- inline auto unique_ptr_cast(PtrT2&& p)
+#define DECL_DEPRECATED_ENUMERATOR(Deprecated, Recommended) \
+ Deprecated Q_DECL_ENUMERATOR_DEPRECATED_X("Use " #Recommended) = Recommended
+
+/// \brief Copy an object with slicing
+///
+/// Unintended slicing is bad, which why there's a C++ Core Guideline that
+/// basically says "don't slice, or if you do, make it explicit". Sonar and
+/// clang-tidy have warnings matching this guideline; unfortunately, those
+/// warnings trigger even when you have a dedicated method (as the guideline
+/// recommends) that makes a slicing copy.
+///
+/// This macro is meant for cases when slicing is intended: the static cast
+/// silences the static analysis warning, and the macro appearance itself makes
+/// it very clear that slicing is wanted here. It is made as a macro
+/// (not as a function template) to support the case of private inheritance
+/// in which a function template would not be able to cast to the private base
+/// (see Uri::toUrl() for an example of just that situation).
+#define SLICE(Object, ToType) ToType{static_cast<const ToType&>(Object)}
+
+namespace Quotient {
+/// An equivalent of std::hash for QTypes to enable std::unordered_map<QType, ...>
+template <typename T>
+struct HashQ {
+ size_t operator()(const T& s) const Q_DECL_NOEXCEPT
{
- return std::unique_ptr<T1>(static_cast<T1*>(p.release()));
+ return qHash(s, uint(qGlobalQHashSeed()));
}
+};
+/// A wrapper around std::unordered_map compatible with types that have qHash
+template <typename KeyT, typename ValT>
+using UnorderedMap = std::unordered_map<KeyT, ValT, HashQ<KeyT>>;
- struct NoneTag {};
- constexpr NoneTag none {};
+constexpr auto operator"" _ls(const char* s, std::size_t size)
+{
+ return QLatin1String(s, int(size));
+}
- /** A crude substitute for `optional` while we're not C++17
- *
- * Only works with default-constructible types.
- */
- template <typename T>
- class Omittable
+/** An abstraction over a pair of iterators
+ * This is a very basic range type over a container with iterators that
+ * are at least ForwardIterators. Inspired by Ranges TS.
+ */
+template <typename ArrayT>
+class Range {
+ // Looking forward to C++20 ranges
+ using iterator = typename ArrayT::iterator;
+ using const_iterator = typename ArrayT::const_iterator;
+ using size_type = typename ArrayT::size_type;
+
+public:
+ constexpr Range(ArrayT& arr) : from(std::begin(arr)), to(std::end(arr)) {}
+ constexpr Range(iterator from, iterator to) : from(from), to(to) {}
+
+ constexpr size_type size() const
{
- static_assert(!std::is_reference<T>::value,
- "You cannot make an Omittable<> with a reference type");
- public:
- explicit Omittable() : Omittable(none) { }
- Omittable(NoneTag) : _value(std::decay_t<T>()), _omitted(true) { }
- Omittable(const std::decay_t<T>& val) : _value(val) { }
- Omittable(std::decay_t<T>&& val) : _value(std::move(val)) { }
- Omittable<T>& operator=(const std::decay_t<T>& val)
- {
- _value = val;
- _omitted = false;
- return *this;
- }
- Omittable<T>& operator=(std::decay_t<T>&& val)
- {
- _value = std::move(val);
- _omitted = false;
- return *this;
- }
-
- bool omitted() const { return _omitted; }
- const std::decay_t<T>& value() const { Q_ASSERT(!_omitted); return _value; }
- std::decay_t<T>& value() { Q_ASSERT(!_omitted); return _value; }
- std::decay_t<T>&& release() { _omitted = true; return std::move(_value); }
-
- operator bool() const { return !omitted(); }
- const std::decay<T>* operator->() const { return &value(); }
- std::decay_t<T>* operator->() { return &value(); }
- const std::decay_t<T>& operator*() const { return value(); }
- std::decay_t<T>& operator*() { return value(); }
-
- private:
- T _value;
- bool _omitted = false;
- };
+ Q_ASSERT(std::distance(from, to) >= 0);
+ return size_type(std::distance(from, to));
+ }
+ constexpr bool empty() const { return from == to; }
+ constexpr const_iterator begin() const { return from; }
+ constexpr const_iterator end() const { return to; }
+ constexpr iterator begin() { return from; }
+ constexpr iterator end() { return to; }
- /** Determine traits of an arbitrary function/lambda/functor
- * This only works with arity of 1 (1-argument) for now but is extendable
- * to other cases. Also, doesn't work with generic lambdas and function
- * objects that have operator() overloaded
- * \sa https://stackoverflow.com/questions/7943525/is-it-possible-to-figure-out-the-parameter-type-and-return-type-of-a-lambda#7943765
- */
- template <typename T>
- struct function_traits : public function_traits<decltype(&T::operator())>
- { }; // A generic function object that has (non-overloaded) operator()
-
- // Specialisation for a function
- template <typename ReturnT, typename ArgT>
- struct function_traits<ReturnT(ArgT)>
- {
- using return_type = ReturnT;
- using arg_type = ArgT;
- };
+private:
+ iterator from;
+ iterator to;
+};
- // Specialisation for a member function
- template <typename ReturnT, typename ClassT, typename ArgT>
- struct function_traits<ReturnT(ClassT::*)(ArgT)>
- : function_traits<ReturnT(ArgT)>
- { };
+template <typename T>
+class asKeyValueRange
+{
+public:
+ asKeyValueRange(T& data)
+ : m_data { data }
+ {}
- // Specialisation for a const member function
- template <typename ReturnT, typename ClassT, typename ArgT>
- struct function_traits<ReturnT(ClassT::*)(ArgT) const>
- : function_traits<ReturnT(ArgT)>
- { };
+ auto begin() { return m_data.keyValueBegin(); }
+ auto end() { return m_data.keyValueEnd(); }
- template <typename FnT>
- using fn_return_t = typename function_traits<FnT>::return_type;
+private:
+ T &m_data;
+};
+template <typename T>
+asKeyValueRange(T&) -> asKeyValueRange<T>;
- template <typename FnT>
- using fn_arg_t = typename function_traits<FnT>::arg_type;
+/** A replica of std::find_first_of that returns a pair of iterators
+ *
+ * Convenient for cases when you need to know which particular "first of"
+ * [sFirst, sLast) has been found in [first, last).
+ */
+template <typename InputIt, typename ForwardIt, typename Pred>
+inline std::pair<InputIt, ForwardIt> findFirstOf(InputIt first, InputIt last,
+ ForwardIt sFirst,
+ ForwardIt sLast, Pred pred)
+{
+ for (; first != last; ++first)
+ for (auto it = sFirst; it != sLast; ++it)
+ if (pred(*first, *it))
+ return std::make_pair(first, it);
+
+ return std::make_pair(last, sLast);
+}
+
+//! \brief An owning implementation pointer
+//!
+//! This is basically std::unique_ptr<> to hold your pimpl's but without having
+//! to define default constructors/operator=() out of line.
+//! Thanks to https://oliora.github.io/2015/12/29/pimpl-and-rule-of-zero.html
+//! for inspiration
+template <typename ImplType, typename TypeToDelete = ImplType>
+using ImplPtr = std::unique_ptr<ImplType, void (*)(TypeToDelete*)>;
+
+// Why this works (see also the link above): because this defers the moment
+// of requiring sizeof of ImplType to the place where makeImpl is invoked
+// (which is located, necessarily, in the .cpp file after ImplType definition).
+// The stock unique_ptr deleter (std::default_delete) normally needs sizeof
+// at the same spot - as long as you defer definition of the owning type
+// constructors and operator='s to the .cpp file as well. Which means you
+// have to explicitly declare and define them (even if with = default),
+// formally breaking the rule of zero; informally, just adding boilerplate code.
+// The custom deleter itself is instantiated at makeImpl invocation - there's
+// no way earlier to even know how ImplType will be deleted and whether that
+// will need sizeof(ImplType) earlier. In theory it's a tad slower because
+// the deleter is called by the pointer; however, the difference will not
+// be noticeable (if exist at all) for any class with non-trivial contents.
+
+//! \brief make_unique for ImplPtr
+//!
+//! Since std::make_unique is not compatible with ImplPtr, this should be used
+//! in constructors of frontend classes to create implementation instances.
+template <typename ImplType, typename TypeToDelete = ImplType, typename... ArgTs>
+inline ImplPtr<ImplType, TypeToDelete> makeImpl(ArgTs&&... args)
+{
+ return ImplPtr<ImplType, TypeToDelete> {
+ new ImplType{std::forward<ArgTs>(args)...},
+ [](TypeToDelete* impl) { delete impl; }
+ };
+}
- inline auto operator"" _ls(const char* s, std::size_t size)
- {
- return QLatin1String(s, int(size));
- }
+template <typename ImplType, typename TypeToDelete = ImplType>
+inline ImplPtr<ImplType, TypeToDelete> acquireImpl(ImplType* from)
+{
+ return ImplPtr<ImplType, TypeToDelete> { from, [](TypeToDelete* impl) {
+ delete impl;
+ } };
+}
- /** An abstraction over a pair of iterators
- * This is a very basic range type over a container with iterators that
- * are at least ForwardIterators. Inspired by Ranges TS.
- */
- template <typename ArrayT>
- class Range
- {
- // Looking forward for Ranges TS to produce something (in C++23?..)
- using iterator = typename ArrayT::iterator;
- using const_iterator = typename ArrayT::const_iterator;
- using size_type = typename ArrayT::size_type;
- public:
- Range(ArrayT& arr) : from(std::begin(arr)), to(std::end(arr)) { }
- Range(iterator from, iterator to) : from(from), to(to) { }
-
- size_type size() const
- {
- Q_ASSERT(std::distance(from, to) >= 0);
- return size_type(std::distance(from, to));
- }
- bool empty() const { return from == to; }
- const_iterator begin() const { return from; }
- const_iterator end() const { return to; }
- iterator begin() { return from; }
- iterator end() { return to; }
-
- private:
- iterator from;
- iterator to;
- };
+template <typename ImplType, typename TypeToDelete = ImplType>
+constexpr ImplPtr<ImplType, TypeToDelete> ZeroImpl()
+{
+ return { nullptr, [](TypeToDelete*) { /* nullptr doesn't need deletion */ } };
+}
+
+//! \brief Multiplex several functors in one
+//!
+//! This is a well-known trick to wrap several lambdas into a single functor
+//! class that can be passed to std::visit.
+//! \sa https://en.cppreference.com/w/cpp/utility/variant/visit
+template <typename... FunctorTs>
+struct Overloads : FunctorTs... {
+ using FunctorTs::operator()...;
+};
+
+template <typename... FunctorTs>
+Overloads(FunctorTs&&...) -> Overloads<FunctorTs...>;
+
+/** Convert what looks like a URL or a Matrix ID to an HTML hyperlink */
+QUOTIENT_API void linkifyUrls(QString& htmlEscapedText);
+
+/** Sanitize the text before showing in HTML
+ *
+ * This does toHtmlEscaped() and removes Unicode BiDi marks.
+ */
+QUOTIENT_API QString sanitized(const QString& plainText);
- /** A replica of std::find_first_of that returns a pair of iterators
- *
- * Convenient for cases when you need to know which particular "first of"
- * [sFirst, sLast) has been found in [first, last).
- */
- template<typename InputIt, typename ForwardIt, typename Pred>
- inline std::pair<InputIt, ForwardIt> findFirstOf(
- InputIt first, InputIt last, ForwardIt sFirst, ForwardIt sLast,
- Pred pred)
- {
- for (; first != last; ++first)
- for (auto it = sFirst; it != sLast; ++it)
- if (pred(*first, *it))
- return std::make_pair(first, it);
+/** Pretty-print plain text into HTML
+ *
+ * This includes HTML escaping of <,>,",& and calling linkifyUrls()
+ */
+QUOTIENT_API QString prettyPrint(const QString& plainText);
- return std::make_pair(last, sLast);
- }
+/** Return a path to cache directory after making sure that it exists
+ *
+ * The returned path has a trailing slash, clients don't need to append it.
+ * \param dirName path to cache directory relative to the standard cache path
+ */
+QUOTIENT_API QString cacheLocation(const QString& dirName);
- /** A guard pointer that disconnects an interested object upon destruction
- * It's almost QPointer<> except that you have to initialise it with one
- * more additional parameter - a pointer to a QObject that will be
- * disconnected from signals of the underlying pointer upon the guard's
- * destruction.
- */
- template <typename T>
- class ConnectionsGuard : public QPointer<T>
- {
- public:
- ConnectionsGuard(T* publisher, QObject* subscriber)
- : QPointer<T>(publisher), subscriber(subscriber)
- { }
- ~ConnectionsGuard()
- {
- if (*this)
- (*this)->disconnect(subscriber);
- }
- ConnectionsGuard(ConnectionsGuard&&) = default;
- ConnectionsGuard& operator=(ConnectionsGuard&&) = default;
- Q_DISABLE_COPY(ConnectionsGuard)
- using QPointer<T>::operator=;
-
- private:
- QObject* subscriber;
- };
+/** Hue color component of based of the hash of the string.
+ *
+ * The implementation is based on XEP-0392:
+ * https://xmpp.org/extensions/xep-0392.html
+ * Naming and range are the same as QColor's hueF method:
+ * https://doc.qt.io/qt-5/qcolor.html#integer-vs-floating-point-precision
+ */
+QUOTIENT_API qreal stringToHueF(const QString& s);
- /** Pretty-prints plain text into HTML
- * This includes HTML escaping of <,>,",& and URLs linkification.
- */
- QString prettyPrint(const QString& plainText);
-} // namespace QMatrixClient
+/** Extract the serverpart from MXID */
+QUOTIENT_API QString serverPart(const QString& mxId);
+QUOTIENT_API QString versionString();
+QUOTIENT_API int majorVersion();
+QUOTIENT_API int minorVersion();
+QUOTIENT_API int patchVersion();
+QUOTIENT_API bool encryptionSupported();
+} // namespace Quotient