aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKitsune Ral <Kitsune-Ral@users.sf.net>2018-12-08 17:44:42 +0900
committerKitsune Ral <Kitsune-Ral@users.sf.net>2018-12-08 17:44:42 +0900
commit3489b77bba1b9429925dfe9539c2a9e8137fc622 (patch)
tree59a7cb3bc7b25eee12a37c43db4c069b7c240464
parent39204f0099e5556eb46bed00f3b31413af860a45 (diff)
parent5ea115d6eb0b60dfd0c2be5fbe5e69615b133238 (diff)
downloadlibquotient-3489b77bba1b9429925dfe9539c2a9e8137fc622.tar.gz
libquotient-3489b77bba1b9429925dfe9539c2a9e8137fc622.zip
Merge branch 'kitsune-tweaks-fixes'
-rw-r--r--lib/connection.cpp2
-rw-r--r--lib/csapi/definitions/room_event_filter.cpp6
-rw-r--r--lib/csapi/definitions/room_event_filter.h4
-rw-r--r--lib/csapi/kicking.h2
-rw-r--r--lib/csapi/read_markers.h2
-rw-r--r--lib/csapi/rooms.cpp40
-rw-r--r--lib/csapi/rooms.h26
-rw-r--r--lib/events/roommemberevent.h7
-rw-r--r--lib/events/stateevent.h2
-rw-r--r--lib/util.cpp64
-rw-r--r--lib/util.h106
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
diff --git a/lib/util.h b/lib/util.h
index 88c756a1..722a7e3d 100644
--- a/lib/util.h
+++ b/lib/util.h
@@ -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)
{