aboutsummaryrefslogtreecommitdiff
path: root/lib/util.h
diff options
context:
space:
mode:
authorKitsune Ral <Kitsune-Ral@users.sf.net>2019-06-24 07:21:13 +0900
committerKitsune Ral <Kitsune-Ral@users.sf.net>2019-06-24 07:21:13 +0900
commit63ae79c3e2820efc2ba60d33e2caf2d7b9b3c408 (patch)
tree2552f5049a6ef7ba0034483b25ca4ab33d1fcb13 /lib/util.h
parente083d327e6f6581210f8d077d8bbe1151e81e82c (diff)
parent93f0c8fe89f448d1d58caa757573f17102369471 (diff)
downloadlibquotient-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.h500
1 files changed, 265 insertions, 235 deletions
diff --git a/lib/util.h b/lib/util.h
index fbcafc0d..d626834c 100644
--- a/lib/util.h
+++ b/lib/util.h
@@ -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