diff options
author | n-peugnet <n.peugnet@free.fr> | 2022-10-06 19:27:24 +0200 |
---|---|---|
committer | n-peugnet <n.peugnet@free.fr> | 2022-10-06 19:27:24 +0200 |
commit | d911b207f49e936b3e992200796110f0749ed150 (patch) | |
tree | 96d20ebb4d074a4c1755e21cb316a52d584daee3 /lib/util.h | |
parent | 8ad8a74152c5701b6ca1f9a00487ba9257a439b4 (diff) | |
parent | 56c2f2e2b809b9077393eb617828f33d144f5634 (diff) | |
download | libquotient-d911b207f49e936b3e992200796110f0749ed150.tar.gz libquotient-d911b207f49e936b3e992200796110f0749ed150.zip |
New upstream version 0.7.0
Diffstat (limited to 'lib/util.h')
-rw-r--r-- | lib/util.h | 433 |
1 files changed, 220 insertions, 213 deletions
@@ -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 |