diff options
author | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2019-06-24 07:21:13 +0900 |
---|---|---|
committer | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2019-06-24 07:21:13 +0900 |
commit | 63ae79c3e2820efc2ba60d33e2caf2d7b9b3c408 (patch) | |
tree | 2552f5049a6ef7ba0034483b25ca4ab33d1fcb13 /lib/util.h | |
parent | e083d327e6f6581210f8d077d8bbe1151e81e82c (diff) | |
parent | 93f0c8fe89f448d1d58caa757573f17102369471 (diff) | |
download | libquotient-63ae79c3e2820efc2ba60d33e2caf2d7b9b3c408.tar.gz libquotient-63ae79c3e2820efc2ba60d33e2caf2d7b9b3c408.zip |
Merge branch 'master' into clang-format
# Conflicts:
# CMakeLists.txt
# lib/avatar.cpp
# lib/connection.cpp
# lib/connection.h
# lib/connectiondata.cpp
# lib/csapi/account-data.cpp
# lib/csapi/account-data.h
# lib/csapi/capabilities.cpp
# lib/csapi/capabilities.h
# lib/csapi/content-repo.cpp
# lib/csapi/create_room.cpp
# lib/csapi/filter.cpp
# lib/csapi/joining.cpp
# lib/csapi/keys.cpp
# lib/csapi/list_joined_rooms.cpp
# lib/csapi/notifications.cpp
# lib/csapi/openid.cpp
# lib/csapi/presence.cpp
# lib/csapi/pushrules.cpp
# lib/csapi/registration.cpp
# lib/csapi/room_upgrades.cpp
# lib/csapi/room_upgrades.h
# lib/csapi/search.cpp
# lib/csapi/users.cpp
# lib/csapi/versions.cpp
# lib/csapi/whoami.cpp
# lib/csapi/{{base}}.cpp.mustache
# lib/events/accountdataevents.h
# lib/events/eventcontent.h
# lib/events/roommemberevent.cpp
# lib/events/stateevent.cpp
# lib/jobs/basejob.cpp
# lib/jobs/basejob.h
# lib/networkaccessmanager.cpp
# lib/networksettings.cpp
# lib/room.cpp
# lib/room.h
# lib/settings.cpp
# lib/settings.h
# lib/syncdata.cpp
# lib/user.cpp
# lib/user.h
# lib/util.cpp
Diffstat (limited to 'lib/util.h')
-rw-r--r-- | lib/util.h | 500 |
1 files changed, 265 insertions, 235 deletions
@@ -21,26 +21,26 @@ #include <QtCore/QLatin1String> #if QT_VERSION < QT_VERSION_CHECK(5, 5, 0) -#include <QtCore/QDebug> -#include <QtCore/QMetaEnum> +# include <QtCore/QDebug> +# include <QtCore/QMetaEnum> #endif #include <functional> #include <memory> #if __has_cpp_attribute(fallthrough) -#define FALLTHROUGH [[fallthrough]] +# define FALLTHROUGH [[fallthrough]] #elif __has_cpp_attribute(clang::fallthrough) -#define FALLTHROUGH [[clang::fallthrough]] +# define FALLTHROUGH [[clang::fallthrough]] #elif __has_cpp_attribute(gnu::fallthrough) -#define FALLTHROUGH [[gnu::fallthrough]] +# define FALLTHROUGH [[gnu::fallthrough]] #else -#define FALLTHROUGH // -fallthrough +# define FALLTHROUGH // -fallthrough #endif // Along the lines of Q_DISABLE_COPY -#define DISABLE_MOVE(_ClassName) \ - _ClassName(_ClassName&&) Q_DECL_EQ_DELETE; \ +#define DISABLE_MOVE(_ClassName) \ + _ClassName(_ClassName&&) Q_DECL_EQ_DELETE; \ _ClassName& operator=(_ClassName&&) Q_DECL_EQ_DELETE; #if QT_VERSION < QT_VERSION_CHECK(5, 7, 0) @@ -51,264 +51,294 @@ 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; +template <typename T> +static void qAsConst(const T&&) Q_DECL_EQ_DELETE; #endif // MSVC 2015 and older GCC's don't handle initialisation from initializer lists // right in the absense of a constructor; MSVC 2015, notably, fails with // "error C2440: 'return': cannot convert from 'initializer list' to '<type>'" -#if (defined(_MSC_VER) && _MSC_VER < 1910) \ - || (defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 4) -#define BROKEN_INITIALIZER_LISTS +#if (defined(_MSC_VER) && _MSC_VER < 1910) \ + || (defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 4) +# define BROKEN_INITIALIZER_LISTS #endif -namespace QMatrixClient { - // The below enables pretty-printing of enums in logs +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) +# define REGISTER_ENUM(EnumName) Q_ENUM(EnumName) #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)); \ - } +// 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)); \ + } #endif - /** static_cast<> for unique_ptr's */ - template <typename T1, typename PtrT2> - inline auto unique_ptr_cast(PtrT2&& p) +/** static_cast<> for unique_ptr's */ +template <typename T1, typename PtrT2> +inline auto unique_ptr_cast(PtrT2&& p) +{ + return std::unique_ptr<T1>(static_cast<T1*>(p.release())); +} + +struct NoneTag +{}; +constexpr NoneTag none {}; + +/** A crude substitute for `optional` while we're not C++17 + * + * Only works with default-constructible types. + */ +template <typename T> +class Omittable +{ + static_assert(!std::is_reference<T>::value, + "You cannot make an Omittable<> with a reference type"); + +public: + using value_type = std::decay_t<T>; + + explicit Omittable() + : Omittable(none) + {} + Omittable(NoneTag) + : _value(value_type()) + , _omitted(true) + {} + Omittable(const value_type& val) + : _value(val) + {} + Omittable(value_type&& val) + : _value(std::move(val)) + {} + Omittable<T>& operator=(const value_type& val) { - return std::unique_ptr<T1>(static_cast<T1*>(p.release())); + _value = val; + _omitted = false; + return *this; + } + Omittable<T>& operator=(value_type&& val) + { + // For some reason GCC complains about -Wmaybe-uninitialized + // in the context of using Omittable<bool> with converters.h; + // though the logic looks very much benign (GCC bug???) + _value = std::move(val); + _omitted = false; + return *this; } - struct NoneTag { - }; - constexpr NoneTag none {}; + bool operator==(const value_type& rhs) const + { + return !omitted() && value() == rhs; + } + friend bool operator==(const value_type& lhs, + const Omittable<value_type>& rhs) + { + return rhs == lhs; + } + bool operator!=(const value_type& rhs) const { return !operator==(rhs); } + friend bool operator!=(const value_type& lhs, + const Omittable<value_type>& rhs) + { + return !(rhs == lhs); + } - /** A crude substitute for `optional` while we're not C++17 - * - * Only works with default-constructible types. - */ - template <typename T> class Omittable + bool omitted() const { return _omitted; } + const value_type& value() const { - static_assert(!std::is_reference<T>::value, - "You cannot make an Omittable<> with a reference type"); - - public: - using value_type = std::decay_t<T>; - - explicit Omittable() : Omittable(none) {} - Omittable(NoneTag) : _value(value_type()), _omitted(true) {} - Omittable(const value_type& val) : _value(val) {} - Omittable(value_type&& val) : _value(std::move(val)) {} - Omittable<T>& operator=(const value_type& val) - { - _value = val; - _omitted = false; - return *this; - } - Omittable<T>& operator=(value_type&& val) - { - // For some reason GCC complains about -Wmaybe-uninitialized - // in the context of using Omittable<bool> with converters.h; - // though the logic looks very much benign (GCC bug???) - _value = std::move(val); - _omitted = false; - return *this; - } + Q_ASSERT(!_omitted); + return _value; + } + value_type& editValue() + { + _omitted = false; + return _value; + } + /// Merge the value from another Omittable + /// \return true if \p other is not omitted and the value of + /// the current Omittable was different (or omitted); + /// in other words, if the current Omittable has changed; + /// false otherwise + template <typename T1> + auto merge(const Omittable<T1>& other) + -> std::enable_if_t<std::is_convertible<T1, T>::value, bool> + { + if (other.omitted() || (!_omitted && _value == other.value())) + return false; + _omitted = false; + _value = other.value(); + return true; + } + value_type&& release() + { + _omitted = true; + return std::move(_value); + } - bool operator==(const value_type& rhs) const - { - return !omitted() && value() == rhs; - } - friend bool operator==(const value_type& lhs, - const Omittable<value_type>& rhs) - { - return rhs == lhs; - } - bool operator!=(const value_type& rhs) const - { - return !operator==(rhs); - } - friend bool operator!=(const value_type& lhs, - const Omittable<value_type>& rhs) - { - return !(rhs == lhs); - } + const value_type* operator->() const& { return &value(); } + value_type* operator->() & { return &editValue(); } + const value_type& operator*() const& { return value(); } + value_type& operator*() & { return editValue(); } - bool omitted() const { return _omitted; } - const value_type& value() const - { - Q_ASSERT(!_omitted); - return _value; - } - value_type& editValue() - { - _omitted = false; - return _value; - } - /// Merge the value from another Omittable - /// \return true if \p other is not omitted and the value of - /// the current Omittable was different (or omitted); - /// in other words, if the current Omittable has changed; - /// false otherwise - template <typename T1> - auto merge(const Omittable<T1>& other) - -> std::enable_if_t<std::is_convertible<T1, T>::value, bool> - { - if (other.omitted() || (!_omitted && _value == other.value())) - return false; - _omitted = false; - _value = other.value(); - return true; - } - value_type&& release() - { - _omitted = true; - return std::move(_value); - } - - const value_type* operator->() const& { return &value(); } - value_type* operator->() & { return &editValue(); } - const value_type& operator*() const& { return value(); } - value_type& operator*() & { return editValue(); } +private: + T _value; + bool _omitted = false; +}; - private: - T _value; - bool _omitted = false; - }; +namespace _impl +{ + template <typename AlwaysVoid, typename> + struct fn_traits; +} - namespace _impl { - template <typename AlwaysVoid, typename> struct fn_traits; - } +/** Determine traits of an arbitrary function/lambda/functor + * 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 _impl::fn_traits<void, T> +{}; - /** Determine traits of an arbitrary function/lambda/functor - * 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 _impl::fn_traits<void, T> { +// Specialisation for a function +template <typename ReturnT, typename... ArgTs> +struct function_traits<ReturnT(ArgTs...)> +{ + static constexpr auto is_callable = true; + using return_type = ReturnT; + using arg_types = std::tuple<ArgTs...>; + using function_type = std::function<ReturnT(ArgTs...)>; + static constexpr auto arg_number = std::tuple_size<arg_types>::value; +}; + +namespace _impl +{ + template <typename AlwaysVoid, typename T> + struct fn_traits + { + static constexpr auto is_callable = false; }; - // Specialisation for a function - template <typename ReturnT, typename... ArgTs> - struct function_traits<ReturnT(ArgTs...)> { - static constexpr auto is_callable = true; - using return_type = ReturnT; - using arg_types = std::tuple<ArgTs...>; - using function_type = std::function<ReturnT(ArgTs...)>; - static constexpr auto arg_number = std::tuple_size<arg_types>::value; - }; + template <typename T> + struct fn_traits<decltype(void(&T::operator())), T> + : public fn_traits<void, decltype(&T::operator())> + {}; // A generic function object that has (non-overloaded) operator() + + // Specialisation for a member function + template <typename ReturnT, typename ClassT, typename... ArgTs> + struct fn_traits<void, ReturnT (ClassT::*)(ArgTs...)> + : function_traits<ReturnT(ArgTs...)> + {}; + + // Specialisation for a const member function + template <typename ReturnT, typename ClassT, typename... ArgTs> + struct fn_traits<void, ReturnT (ClassT::*)(ArgTs...) const> + : function_traits<ReturnT(ArgTs...)> + {}; +} // namespace _impl + +template <typename FnT> +using fn_return_t = typename function_traits<FnT>::return_type; + +template <typename FnT, int ArgN = 0> +using fn_arg_t = + std::tuple_element_t<ArgN, typename function_traits<FnT>::arg_types>; + +template <typename R, typename FnT> +constexpr bool returns() +{ + return std::is_same<fn_return_t<FnT>, R>::value; +} - namespace _impl { - template <typename AlwaysVoid, typename T> struct fn_traits { - static constexpr auto is_callable = false; - }; - - template <typename T> - struct fn_traits<decltype(void(&T::operator())), T> - : public fn_traits<void, decltype(&T::operator())> { - }; // A generic function object that has (non-overloaded) operator() - - // Specialisation for a member function - template <typename ReturnT, typename ClassT, typename... ArgTs> - struct fn_traits<void, ReturnT (ClassT::*)(ArgTs...)> - : function_traits<ReturnT(ArgTs...)> { - }; - - // Specialisation for a const member function - template <typename ReturnT, typename ClassT, typename... ArgTs> - struct fn_traits<void, ReturnT (ClassT::*)(ArgTs...) const> - : function_traits<ReturnT(ArgTs...)> { - }; - } // namespace _impl - - template <typename FnT> - using fn_return_t = typename function_traits<FnT>::return_type; - - template <typename FnT, int ArgN = 0> - using fn_arg_t = - std::tuple_element_t<ArgN, - typename function_traits<FnT>::arg_types>; - - template <typename R, typename FnT> constexpr bool returns() - { - return std::is_same<fn_return_t<FnT>, R>::value; - } +// Poor-man's is_invokable +template <typename T> +constexpr auto is_callable_v = function_traits<T>::is_callable; - // Poor-man's is_invokable - template <typename T> - constexpr auto is_callable_v = function_traits<T>::is_callable; +inline auto operator"" _ls(const char* s, std::size_t size) +{ + return QLatin1String(s, int(size)); +} - inline auto operator"" _ls(const char* s, std::size_t size) +/** 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 { - return QLatin1String(s, int(size)); + 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; +}; + +/** 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); - /** 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; - }; + return std::make_pair(last, sLast); +} - /** 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); +/** Convert what looks like a URL or a Matrix ID to an HTML hyperlink */ +void linkifyUrls(QString& htmlEscapedText); - return std::make_pair(last, sLast); - } +/** Sanitize the text before showing in HTML + * This does toHtmlEscaped() and removes Unicode BiDi marks. + */ +QString sanitized(const QString& plainText); - /** Pretty-prints plain text into HTML - * This includes HTML escaping of <,>,",& and URLs linkification. - */ - QString prettyPrint(const QString& plainText); +/** Pretty-print plain text into HTML + * This includes HTML escaping of <,>,",& and calling linkifyUrls() + */ +QString prettyPrint(const QString& plainText); - /** 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 dir path to cache directory relative to the standard cache path - */ - QString cacheLocation(const QString& dirName); +/** 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 dir path to cache directory relative to the standard cache path + */ +QString cacheLocation(const QString& dirName); } // namespace QMatrixClient |