diff options
author | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2018-12-08 17:44:42 +0900 |
---|---|---|
committer | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2018-12-08 17:44:42 +0900 |
commit | 3489b77bba1b9429925dfe9539c2a9e8137fc622 (patch) | |
tree | 59a7cb3bc7b25eee12a37c43db4c069b7c240464 | |
parent | 39204f0099e5556eb46bed00f3b31413af860a45 (diff) | |
parent | 5ea115d6eb0b60dfd0c2be5fbe5e69615b133238 (diff) | |
download | libquotient-3489b77bba1b9429925dfe9539c2a9e8137fc622.tar.gz libquotient-3489b77bba1b9429925dfe9539c2a9e8137fc622.zip |
Merge branch 'kitsune-tweaks-fixes'
-rw-r--r-- | lib/connection.cpp | 2 | ||||
-rw-r--r-- | lib/csapi/definitions/room_event_filter.cpp | 6 | ||||
-rw-r--r-- | lib/csapi/definitions/room_event_filter.h | 4 | ||||
-rw-r--r-- | lib/csapi/kicking.h | 2 | ||||
-rw-r--r-- | lib/csapi/read_markers.h | 2 | ||||
-rw-r--r-- | lib/csapi/rooms.cpp | 40 | ||||
-rw-r--r-- | lib/csapi/rooms.h | 26 | ||||
-rw-r--r-- | lib/events/roommemberevent.h | 7 | ||||
-rw-r--r-- | lib/events/stateevent.h | 2 | ||||
-rw-r--r-- | lib/util.cpp | 64 | ||||
-rw-r--r-- | lib/util.h | 106 |
11 files changed, 153 insertions, 108 deletions
diff --git a/lib/connection.cpp b/lib/connection.cpp index 9372acd5..26c33767 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -825,7 +825,7 @@ QHash<QString, QVector<Room*>> Connection::tagsToRooms() const for (auto it = result.begin(); it != result.end(); ++it) std::sort(it->begin(), it->end(), [t=it.key()] (Room* r1, Room* r2) { - return r1->tags().value(t).order < r2->tags().value(t).order; + return r1->tags().value(t) < r2->tags().value(t); }); return result; } diff --git a/lib/csapi/definitions/room_event_filter.cpp b/lib/csapi/definitions/room_event_filter.cpp index f6f1e5cb..8cd2ded7 100644 --- a/lib/csapi/definitions/room_event_filter.cpp +++ b/lib/csapi/definitions/room_event_filter.cpp @@ -12,6 +12,8 @@ QJsonObject QMatrixClient::toJson(const RoomEventFilter& pod) addParam<IfNotEmpty>(jo, QStringLiteral("not_rooms"), pod.notRooms); addParam<IfNotEmpty>(jo, QStringLiteral("rooms"), pod.rooms); addParam<IfNotEmpty>(jo, QStringLiteral("contains_url"), pod.containsUrl); + addParam<IfNotEmpty>(jo, QStringLiteral("lazy_load_members"), pod.lazyLoadMembers); + addParam<IfNotEmpty>(jo, QStringLiteral("include_redundant_members"), pod.includeRedundantMembers); return jo; } @@ -24,6 +26,10 @@ RoomEventFilter FromJsonObject<RoomEventFilter>::operator()(const QJsonObject& j fromJson<QStringList>(jo.value("rooms"_ls)); result.containsUrl = fromJson<bool>(jo.value("contains_url"_ls)); + result.lazyLoadMembers = + fromJson<bool>(jo.value("lazy_load_members"_ls)); + result.includeRedundantMembers = + fromJson<bool>(jo.value("include_redundant_members"_ls)); return result; } diff --git a/lib/csapi/definitions/room_event_filter.h b/lib/csapi/definitions/room_event_filter.h index 697fe661..87f01189 100644 --- a/lib/csapi/definitions/room_event_filter.h +++ b/lib/csapi/definitions/room_event_filter.h @@ -21,6 +21,10 @@ namespace QMatrixClient QStringList rooms; /// If ``true``, includes only events with a ``url`` key in their content. If ``false``, excludes those events. Defaults to ``false``. bool containsUrl; + /// If ``true``, the only ``m.room.member`` events returned in the ``state`` section of the ``/sync`` response are those which are definitely necessary for a client to display the ``sender`` of the timeline events in that response. If ``false``, ``m.room.member`` events are not filtered. By default, servers should suppress duplicate redundant lazy-loaded ``m.room.member`` events from being sent to a given client across multiple calls to ``/sync``, given that most clients cache membership events (see include_redundant_members to change this behaviour). + bool lazyLoadMembers; + /// If ``true``, the ``state`` section of the ``/sync`` response will always contain the ``m.room.member`` events required to display the ``sender`` of the timeline events in that response, assuming ``lazy_load_members`` is enabled. This means that redundant duplicate member events may be returned across multiple calls to ``/sync``. This is useful for naive clients who never track membership data. If ``false``, duplicate ``m.room.member`` events may be suppressed by the server across multiple calls to ``/sync``. If ``lazy_load_members`` is ``false`` this field is ignored. + bool includeRedundantMembers; }; QJsonObject toJson(const RoomEventFilter& pod); diff --git a/lib/csapi/kicking.h b/lib/csapi/kicking.h index 5968187e..714079cf 100644 --- a/lib/csapi/kicking.h +++ b/lib/csapi/kicking.h @@ -29,7 +29,7 @@ namespace QMatrixClient * \param userId * The fully qualified user ID of the user being kicked. * \param reason - * The reason the user has been kicked. This will be supplied as the + * The reason the user has been kicked. This will be supplied as the * ``reason`` on the target's updated `m.room.member`_ event. */ explicit KickJob(const QString& roomId, const QString& userId, const QString& reason = {}); diff --git a/lib/csapi/read_markers.h b/lib/csapi/read_markers.h index f19f46b0..d982b477 100644 --- a/lib/csapi/read_markers.h +++ b/lib/csapi/read_markers.h @@ -26,7 +26,7 @@ namespace QMatrixClient * event MUST belong to the room. * \param mRead * The event ID to set the read receipt location at. This is - * equivalent to calling ``/receipt/m.read/$elsewhere:domain.com`` + * equivalent to calling ``/receipt/m.read/$elsewhere:example.org`` * and is provided here to save that extra call. */ explicit SetReadMarkerJob(const QString& roomId, const QString& mFullyRead, const QString& mRead = {}); diff --git a/lib/csapi/rooms.cpp b/lib/csapi/rooms.cpp index 3befeee5..cebb295a 100644 --- a/lib/csapi/rooms.cpp +++ b/lib/csapi/rooms.cpp @@ -46,12 +46,6 @@ BaseJob::Status GetOneRoomEventJob::parseJson(const QJsonDocument& data) return Success; } -class GetRoomStateWithKeyJob::Private -{ - public: - StateEventPtr data; -}; - QUrl GetRoomStateWithKeyJob::makeRequestUrl(QUrl baseUrl, const QString& roomId, const QString& eventType, const QString& stateKey) { return BaseJob::makeRequestUrl(std::move(baseUrl), @@ -63,29 +57,9 @@ static const auto GetRoomStateWithKeyJobName = QStringLiteral("GetRoomStateWithK GetRoomStateWithKeyJob::GetRoomStateWithKeyJob(const QString& roomId, const QString& eventType, const QString& stateKey) : BaseJob(HttpVerb::Get, GetRoomStateWithKeyJobName, basePath % "/rooms/" % roomId % "/state/" % eventType % "/" % stateKey) - , d(new Private) -{ -} - -GetRoomStateWithKeyJob::~GetRoomStateWithKeyJob() = default; - -StateEventPtr&& GetRoomStateWithKeyJob::data() { - return std::move(d->data); -} - -BaseJob::Status GetRoomStateWithKeyJob::parseJson(const QJsonDocument& data) -{ - d->data = fromJson<StateEventPtr>(data); - return Success; } -class GetRoomStateByTypeJob::Private -{ - public: - StateEventPtr data; -}; - QUrl GetRoomStateByTypeJob::makeRequestUrl(QUrl baseUrl, const QString& roomId, const QString& eventType) { return BaseJob::makeRequestUrl(std::move(baseUrl), @@ -97,21 +71,7 @@ static const auto GetRoomStateByTypeJobName = QStringLiteral("GetRoomStateByType GetRoomStateByTypeJob::GetRoomStateByTypeJob(const QString& roomId, const QString& eventType) : BaseJob(HttpVerb::Get, GetRoomStateByTypeJobName, basePath % "/rooms/" % roomId % "/state/" % eventType) - , d(new Private) -{ -} - -GetRoomStateByTypeJob::~GetRoomStateByTypeJob() = default; - -StateEventPtr&& GetRoomStateByTypeJob::data() { - return std::move(d->data); -} - -BaseJob::Status GetRoomStateByTypeJob::parseJson(const QJsonDocument& data) -{ - d->data = fromJson<StateEventPtr>(data); - return Success; } class GetRoomStateJob::Private diff --git a/lib/csapi/rooms.h b/lib/csapi/rooms.h index 2366918b..80895b4e 100644 --- a/lib/csapi/rooms.h +++ b/lib/csapi/rooms.h @@ -80,19 +80,6 @@ namespace QMatrixClient */ static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId, const QString& eventType, const QString& stateKey); - ~GetRoomStateWithKeyJob() override; - - // Result properties - - /// The content of the state event. - StateEventPtr&& data(); - - protected: - Status parseJson(const QJsonDocument& data) override; - - private: - class Private; - QScopedPointer<Private> d; }; /// Get the state identified by the type, with the empty state key. @@ -122,19 +109,6 @@ namespace QMatrixClient */ static QUrl makeRequestUrl(QUrl baseUrl, const QString& roomId, const QString& eventType); - ~GetRoomStateByTypeJob() override; - - // Result properties - - /// The content of the state event. - StateEventPtr&& data(); - - protected: - Status parseJson(const QJsonDocument& data) override; - - private: - class Private; - QScopedPointer<Private> d; }; /// Get all state events in the current state of a room. diff --git a/lib/events/roommemberevent.h b/lib/events/roommemberevent.h index db25d026..149d74f8 100644 --- a/lib/events/roommemberevent.h +++ b/lib/events/roommemberevent.h @@ -29,13 +29,10 @@ namespace QMatrixClient enum MembershipType : size_t { Invite = 0, Join, Knock, Leave, Ban, Undefined }; - explicit MemberEventContent(MembershipType mt = MembershipType::Join) + explicit MemberEventContent(MembershipType mt = Join) : membership(mt) { } explicit MemberEventContent(const QJsonObject& json); - explicit MemberEventContent(const QJsonValue& jv) - : MemberEventContent(jv.toObject()) - { } MembershipType membership; bool isDirect = false; @@ -60,7 +57,7 @@ namespace QMatrixClient : StateEvent(typeId(), obj) { } RoomMemberEvent(MemberEventContent&& c) - : StateEvent(typeId(), matrixTypeId(), c.toJson()) + : StateEvent(typeId(), matrixTypeId(), c) { } // This is a special constructor enabling RoomMemberEvent to be diff --git a/lib/events/stateevent.h b/lib/events/stateevent.h index d4a7e8b3..d82de7e1 100644 --- a/lib/events/stateevent.h +++ b/lib/events/stateevent.h @@ -95,7 +95,7 @@ namespace QMatrixClient { QString prevSenderId() const { return _prev ? _prev->senderId : QString(); } - protected: + private: ContentT _content; std::unique_ptr<Prev<ContentT>> _prev; }; diff --git a/lib/util.cpp b/lib/util.cpp index af06013c..4c176fc7 100644 --- a/lib/util.cpp +++ b/lib/util.cpp @@ -75,3 +75,67 @@ QString QMatrixClient::cacheLocation(const QString& dirName) dir.mkpath(cachePath); return cachePath; } + +// Tests for function_traits<> + +#ifdef Q_CC_CLANG +#pragma clang diagnostic push +#pragma ide diagnostic ignored "OCSimplifyInspection" +#endif +using namespace QMatrixClient; + +int f(); +static_assert(std::is_same<fn_return_t<decltype(f)>, int>::value, + "Test fn_return_t<>"); + +void f1(int); +static_assert(function_traits<decltype(f1)>::arg_number == 1, + "Test fn_arg_number"); + +void f2(int, QString); +static_assert(std::is_same<fn_arg_t<decltype(f2), 1>, QString>::value, + "Test fn_arg_t<>"); + +struct S { int mf(); }; +static_assert(is_callable_v<decltype(&S::mf)>, "Test member function"); +static_assert(returns<int, decltype(&S::mf)>(), "Test returns<> with member function"); + +struct Fo { void operator()(int); }; +static_assert(function_traits<Fo>::arg_number == 1, "Test function object 1"); +static_assert(is_callable_v<Fo>, "Test is_callable<>"); +static_assert(std::is_same<fn_arg_t<Fo>, int>(), + "Test fn_arg_t defaulting to first argument"); + +static auto l = [] { return 1; }; +static_assert(is_callable_v<decltype(l)>, "Test is_callable_v<> with lambda"); +static_assert(std::is_same<fn_return_t<decltype(l)>, int>::value, + "Test fn_return_t<> with lambda"); + +template <typename T> +struct fn_object +{ + static int smf(double) { return 0; } +}; +template <> +struct fn_object<QString> +{ + void operator()(QString); +}; +static_assert(is_callable_v<fn_object<QString>>, "Test function object"); +static_assert(returns<void, fn_object<QString>>(), + "Test returns<> with function object"); +static_assert(!is_callable_v<fn_object<int>>, "Test non-function object"); +// FIXME: These two don't work +//static_assert(is_callable_v<decltype(&fn_object<int>::smf)>, +// "Test static member function"); +//static_assert(returns<int, decltype(&fn_object<int>::smf)>(), +// "Test returns<> with static member function"); + +template <typename T> +QString ft(T&&); +static_assert(std::is_same<fn_arg_t<decltype(ft<QString>)>, QString&&>(), + "Test function templates"); + +#ifdef Q_CC_CLANG +#pragma clang diagnostic pop +#endif @@ -31,6 +31,8 @@ #define FALLTHROUGH [[fallthrough]] #elif __has_cpp_attribute(clang::fallthrough) #define FALLTHROUGH [[clang::fallthrough]] +#elif __has_cpp_attribute(gnu::fallthrough) +#define FALLTHROUGH [[gnu::fallthrough]] #else #define FALLTHROUGH // -fallthrough #endif @@ -86,17 +88,19 @@ namespace QMatrixClient 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(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) + 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=(std::decay_t<T>&& val) + Omittable<T>& operator=(value_type&& val) { _value = std::move(val); _omitted = false; @@ -104,56 +108,92 @@ namespace QMatrixClient } 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); } + const value_type& value() const + { + Q_ASSERT(!_omitted); + return _value; + } + value_type& editValue() + { + _omitted = false; + return _value; + } + value_type&& 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(); } + operator value_type&() & { return editValue(); } + 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; }; + namespace _impl { + template <typename AlwaysVoid, typename> struct fn_traits; + } + /** 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 + * 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() + struct function_traits : public _impl::fn_traits<void, T> {}; // Specialisation for a function - template <typename ReturnT, typename ArgT> - struct function_traits<ReturnT(ArgT)> + template <typename ReturnT, typename... ArgTs> + struct function_traits<ReturnT(ArgTs...)> { + static constexpr auto is_callable = true; using return_type = ReturnT; - using arg_type = ArgT; + using arg_types = std::tuple<ArgTs..., void>; + static constexpr auto arg_number = std::tuple_size<arg_types>::value - 1; }; - // Specialisation for a member function - template <typename ReturnT, typename ClassT, typename ArgT> - struct function_traits<ReturnT(ClassT::*)(ArgT)> - : function_traits<ReturnT(ArgT)> - { }; + namespace _impl { + template <typename AlwaysVoid, typename T> + struct fn_traits + { + static constexpr auto is_callable = false; + }; - // Specialisation for a const member function - template <typename ReturnT, typename ClassT, typename ArgT> - struct function_traits<ReturnT(ClassT::*)(ArgT) const> - : function_traits<ReturnT(ArgT)> - { }; + 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> - using fn_arg_t = typename function_traits<FnT>::arg_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; inline auto operator"" _ls(const char* s, std::size_t size) { |