From c05b5c2b79f9ab301fee587ee781b9c8e18b8a2f Mon Sep 17 00:00:00 2001 From: Alexey Rusakov <Kitsune-Ral@users.sf.net> Date: Fri, 16 Jul 2021 20:03:06 +0200 Subject: MembershipType -> Membership, also used for JoinState Instead of being defined independently, JoinState now uses values from the Membership enumeration (former MemberEventContent::MembershipType) that was moved to quotient_common.h for that purpose. Both enumerations gained a Q_FLAG_NS decoration and operator<< overrides that strip "Quotient::" prefix when dumping member/join state values to the log - obviating toCString(JoinState) along the way. Quotient::MembershipType alias is deprecated from now. --- CMakeLists.txt | 6 +--- lib/connection.cpp | 4 +-- lib/connection.h | 1 - lib/events/roommemberevent.cpp | 65 ++++++++++++++++++++-------------------- lib/events/roommemberevent.h | 26 ++++++++-------- lib/joinstate.h | 32 -------------------- lib/quotient_common.cpp | 45 ++++++++++++++++++++++++++++ lib/quotient_common.h | 67 +++++++++++++++++++++++++++++++++++++----- lib/room.cpp | 49 ++++++++++++++++-------------- lib/room.h | 9 +++++- lib/syncdata.h | 2 +- lib/user.cpp | 2 +- 12 files changed, 190 insertions(+), 118 deletions(-) delete mode 100644 lib/joinstate.h create mode 100644 lib/quotient_common.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index deb50aea..49105389 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -122,11 +122,7 @@ endif () # Set up source files list(APPEND lib_SRCS - # This .h is special in that it declares a Q_NAMESPACE but has no .cpp - # where staticMetaObject for that namespace would be defined; passing it - # to add_library (see below) puts it on the automoc radar, producing - # a compilation unit with the needed definition. - lib/quotient_common.h + lib/quotient_common.cpp lib/networkaccessmanager.cpp lib/connectiondata.cpp lib/connection.cpp diff --git a/lib/connection.cpp b/lib/connection.cpp index e076957a..7dd04aaa 100644 --- a/lib/connection.cpp +++ b/lib/connection.cpp @@ -640,7 +640,7 @@ void Connection::Private::consumeRoomData(SyncDataList&& roomDataList, } qWarning(MAIN) << "Room" << roomData.roomId << "has just been forgotten but /sync returned it in" - << toCString(roomData.joinState) + << roomData.joinState << "state - suspiciously fast turnaround"; } if (auto* r = q->provideRoom(roomData.roomId, roomData.joinState)) { @@ -1356,7 +1356,7 @@ void Connection::Private::removeRoom(const QString& roomId) for (auto f : { false, true }) if (auto r = roomMap.take({ roomId, f })) { qCDebug(MAIN) << "Room" << r->objectName() << "in state" - << toCString(r->joinState()) << "will be deleted"; + << r->joinState() << "will be deleted"; emit r->beforeDestruction(r); r->deleteLater(); } diff --git a/lib/connection.h b/lib/connection.h index 0d22d01f..a7a071f3 100644 --- a/lib/connection.h +++ b/lib/connection.h @@ -6,7 +6,6 @@ #pragma once #include "ssosession.h" -#include "joinstate.h" #include "qt_connection_util.h" #include "quotient_common.h" diff --git a/lib/events/roommemberevent.cpp b/lib/events/roommemberevent.cpp index 9634ca3a..8a6bddd8 100644 --- a/lib/events/roommemberevent.cpp +++ b/lib/events/roommemberevent.cpp @@ -7,27 +7,26 @@ #include "converters.h" #include "logging.h" -#include <array> - -static const std::array<QString, 5> membershipStrings = { - { QStringLiteral("invite"), QStringLiteral("join"), QStringLiteral("knock"), - QStringLiteral("leave"), QStringLiteral("ban") } -}; +#include <QtCore/QtAlgorithms> namespace Quotient { template <> -struct JsonConverter<MembershipType> { - static MembershipType load(const QJsonValue& jv) +struct JsonConverter<Membership> { + static Membership load(const QJsonValue& jv) { - const auto& membershipString = jv.toString(); - for (auto it = membershipStrings.begin(); it != membershipStrings.end(); - ++it) - if (membershipString == *it) - return MembershipType(it - membershipStrings.begin()); - - if (!membershipString.isEmpty()) - qCWarning(EVENTS) << "Unknown MembershipType: " << membershipString; - return MembershipType::Undefined; + const auto& ms = jv.toString(); + if (ms.isEmpty()) + { + qCWarning(EVENTS) << "Empty member state:" << ms; + return Membership::Invalid; + } + const auto it = + std::find(MembershipStrings.begin(), MembershipStrings.end(), ms); + if (it != MembershipStrings.end()) + return Membership(1U << (it - MembershipStrings.begin())); + + qCWarning(EVENTS) << "Unknown Membership value: " << ms; + return Membership::Invalid; } }; } // namespace Quotient @@ -35,7 +34,7 @@ struct JsonConverter<MembershipType> { using namespace Quotient; MemberEventContent::MemberEventContent(const QJsonObject& json) - : membership(fromJson<MembershipType>(json["membership"_ls])) + : membership(fromJson<Membership>(json["membership"_ls])) , isDirect(json["is_direct"_ls].toBool()) , displayName(fromJson<Omittable<QString>>(json["displayname"_ls])) , avatarUrl(fromJson<Omittable<QString>>(json["avatar_url"_ls])) @@ -48,10 +47,12 @@ MemberEventContent::MemberEventContent(const QJsonObject& json) void MemberEventContent::fillJson(QJsonObject* o) const { Q_ASSERT(o); - Q_ASSERT_X(membership != MembershipType::Undefined, __FUNCTION__, - "The key 'membership' must be explicit in MemberEventContent"); - if (membership != MembershipType::Undefined) - o->insert(QStringLiteral("membership"), membershipStrings[membership]); + if (membership != Membership::Invalid) + o->insert( + QStringLiteral("membership"), + MembershipStrings[qCountTrailingZeroBits( + std::underlying_type_t<Membership>(membership)) + + 1]); if (displayName) o->insert(QStringLiteral("displayname"), *displayName); if (avatarUrl && avatarUrl->isValid()) @@ -67,37 +68,37 @@ bool RoomMemberEvent::changesMembership() const bool RoomMemberEvent::isInvite() const { - return membership() == MembershipType::Invite && changesMembership(); + return membership() == Membership::Invite && changesMembership(); } bool RoomMemberEvent::isRejectedInvite() const { - return membership() == MembershipType::Leave && prevContent() - && prevContent()->membership == MembershipType::Invite; + return membership() == Membership::Leave && prevContent() + && prevContent()->membership == Membership::Invite; } bool RoomMemberEvent::isJoin() const { - return membership() == MembershipType::Join && changesMembership(); + return membership() == Membership::Join && changesMembership(); } bool RoomMemberEvent::isLeave() const { - return membership() == MembershipType::Leave && prevContent() + return membership() == Membership::Leave && prevContent() && prevContent()->membership != membership() - && prevContent()->membership != MembershipType::Ban - && prevContent()->membership != MembershipType::Invite; + && prevContent()->membership != Membership::Ban + && prevContent()->membership != Membership::Invite; } bool RoomMemberEvent::isBan() const { - return membership() == MembershipType::Ban && changesMembership(); + return membership() == Membership::Ban && changesMembership(); } bool RoomMemberEvent::isUnban() const { - return membership() == MembershipType::Leave && prevContent() - && prevContent()->membership == MembershipType::Ban; + return membership() == Membership::Leave && prevContent() + && prevContent()->membership == Membership::Ban; } bool RoomMemberEvent::isRename() const diff --git a/lib/events/roommemberevent.h b/lib/events/roommemberevent.h index f2fbe689..f3047159 100644 --- a/lib/events/roommemberevent.h +++ b/lib/events/roommemberevent.h @@ -7,23 +7,21 @@ #include "eventcontent.h" #include "stateevent.h" +#include "quotient_common.h" namespace Quotient { class MemberEventContent : public EventContent::Base { public: - enum MembershipType : unsigned char { - Invite = 0, - Join, - Knock, - Leave, - Ban, - Undefined - }; + using MembershipType + [[deprecated("Use Quotient::Membership instead")]] = Membership; - explicit MemberEventContent(MembershipType mt = Join) : membership(mt) {} + explicit MemberEventContent(Membership ms = Membership::Join) + : membership(ms) + {} explicit MemberEventContent(const QJsonObject& json); - MembershipType membership; + Membership membership; + /// (Only for invites) Whether the invite is to a direct chat bool isDirect = false; Omittable<QString> displayName; Omittable<QUrl> avatarUrl; @@ -33,15 +31,15 @@ protected: void fillJson(QJsonObject* o) const override; }; -using MembershipType = MemberEventContent::MembershipType; +using MembershipType [[deprecated("Use Membership instead")]] = Membership; class RoomMemberEvent : public StateEvent<MemberEventContent> { Q_GADGET public: DEFINE_EVENT_TYPEID("m.room.member", RoomMemberEvent) - using MembershipType = MemberEventContent::MembershipType; - Q_ENUM(MembershipType) + using MembershipType + [[deprecated("Use Quotient::Membership instead")]] = Membership; explicit RoomMemberEvent(const QJsonObject& obj) : StateEvent(typeId(), obj) {} @@ -65,7 +63,7 @@ public: : StateEvent(type, fullJson) {} - MembershipType membership() const { return content().membership; } + Membership membership() const { return content().membership; } QString userId() const { return stateKey(); } bool isDirect() const { return content().isDirect; } Omittable<QString> newDisplayName() const { return content().displayName; } diff --git a/lib/joinstate.h b/lib/joinstate.h deleted file mode 100644 index 805ce73a..00000000 --- a/lib/joinstate.h +++ /dev/null @@ -1,32 +0,0 @@ -// SPDX-FileCopyrightText: 2016 Kitsune Ral <Kitsune-Ral@users.sf.net> -// SPDX-License-Identifier: LGPL-2.1-or-later - -#pragma once - -#include <QtCore/QFlags> - -#include <array> - -namespace Quotient { -enum class JoinState : unsigned int { - Join = 0x1, - Invite = 0x2, - Leave = 0x4, -}; - -Q_DECLARE_FLAGS(JoinStates, JoinState) - -// We cannot use Q_ENUM outside of a Q_OBJECT and besides, we want -// to use strings that match respective JSON keys. -static const std::array<const char*, 3> JoinStateStrings { { "join", "invite", - "leave" } }; - -inline const char* toCString(JoinState js) -{ - size_t state = size_t(js), index = 0; - while (state >>= 1u) - ++index; - return JoinStateStrings[index]; -} -} // namespace Quotient -Q_DECLARE_OPERATORS_FOR_FLAGS(Quotient::JoinStates) diff --git a/lib/quotient_common.cpp b/lib/quotient_common.cpp new file mode 100644 index 00000000..805070d1 --- /dev/null +++ b/lib/quotient_common.cpp @@ -0,0 +1,45 @@ +#include "quotient_common.h" + +#include <QtCore/QDebug> + +using namespace Quotient; + +template <typename Enum> +inline QDebug suppressScopeAndDump(QDebug dbg, Enum e) +{ + // Suppress "Quotient::" prefix + QDebugStateSaver _dss(dbg); + dbg.setVerbosity(QDebug::MinimumVerbosity); + return qt_QMetaEnum_debugOperator(dbg, std::underlying_type_t<Enum>(e), + qt_getEnumMetaObject(e), + qt_getEnumName(e)); +} + +template <typename Enum> +inline QDebug suppressScopeAndDump(QDebug dbg, const QFlags<Enum>& f) +{ + // Suppress "Quotient::" prefix + QDebugStateSaver _dss(dbg); + dbg.setVerbosity(QDebug::MinimumVerbosity); + return qt_QMetaEnum_flagDebugOperator_helper(dbg, f); +} + +QDebug operator<<(QDebug dbg, Membership m) +{ + return suppressScopeAndDump(dbg, m); +} + +QDebug operator<<(QDebug dbg, MembershipMask mm) +{ + return suppressScopeAndDump(dbg, mm) << ")"; +} + +QDebug operator<<(QDebug dbg, JoinState js) +{ + return suppressScopeAndDump(dbg, js); +} + +QDebug operator<<(QDebug dbg, JoinStates jss) +{ + return suppressScopeAndDump(dbg, jss) << ")"; +} diff --git a/lib/quotient_common.h b/lib/quotient_common.h index 22fdbe94..789128cf 100644 --- a/lib/quotient_common.h +++ b/lib/quotient_common.h @@ -8,15 +8,62 @@ namespace Quotient { Q_NAMESPACE -/** Enumeration with flags defining the network job running policy - * So far only background/foreground flags are available. - * - * \sa Connection::callApi, Connection::run - */ +// TODO: code like this should be generated from the CS API definition + +//! \brief Membership states +//! +//! These are used for member events. The names here are case-insensitively +//! equal to state names used on the wire. +//! \sa MemberEventContent, RoomMemberEvent +enum class Membership : unsigned int { + // Specific power-of-2 values (1,2,4,...) are important here as syncdata.cpp + // depends on that, as well as Join being the first in line + Invalid = 0x0, + Join = 0x1, + Leave = 0x2, + Invite = 0x4, + Knock = 0x8, + Ban = 0x10, + Undefined = Invalid +}; +Q_DECLARE_FLAGS(MembershipMask, Membership) +Q_FLAG_NS(MembershipMask) + +constexpr inline std::array MembershipStrings = { + // The order MUST be the same as the order in the original enum + "join", "leave", "invite", "knock", "ban" +}; + +//! \brief Local user join-state names +//! +//! This represents a subset of Membership values that may arrive as the local +//! user's state grouping for the sync response. +//! \sa SyncData +enum class JoinState : std::underlying_type_t<Membership> { + Invalid = std::underlying_type_t<Membership>(Membership::Invalid), + Join = std::underlying_type_t<Membership>(Membership::Join), + Leave = std::underlying_type_t<Membership>(Membership::Leave), + Invite = std::underlying_type_t<Membership>(Membership::Invite), + Knock = std::underlying_type_t<Membership>(Membership::Knock), +}; +Q_DECLARE_FLAGS(JoinStates, JoinState) +Q_FLAG_NS(JoinStates) + +constexpr inline std::array JoinStateStrings { + MembershipStrings[0], MembershipStrings[1], MembershipStrings[2], + MembershipStrings[3] /* same as MembershipStrings, sans "ban" */ +}; + +//! \brief Network job running policy flags +//! +//! So far only background/foreground flags are available. +//! \sa Connection::callApi, Connection::run enum RunningPolicy { ForegroundRequest = 0x0, BackgroundRequest = 0x1 }; Q_ENUM_NS(RunningPolicy) +//! \brief The result of URI resolution using UriResolver +//! \sa UriResolver enum UriResolveResult : short { StillResolving = -1, UriResolved = 0, @@ -28,5 +75,11 @@ enum UriResolveResult : short { Q_ENUM_NS(UriResolveResult) } // namespace Quotient -/// \deprecated Use namespace Quotient instead -namespace QMatrixClient = Quotient; +Q_DECLARE_OPERATORS_FOR_FLAGS(Quotient::MembershipMask) +Q_DECLARE_OPERATORS_FOR_FLAGS(Quotient::JoinStates) + +class QDebug; +QDebug operator<<(QDebug dbg, Quotient::Membership m); +QDebug operator<<(QDebug dbg, Quotient::MembershipMask m); +QDebug operator<<(QDebug dbg, Quotient::JoinState js); +QDebug operator<<(QDebug dbg, Quotient::JoinStates js); diff --git a/lib/room.cpp b/lib/room.cpp index 6b729b8f..54c67c2f 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -460,7 +460,7 @@ Room::Room(Connection* connection, QString id, JoinState initialJoinState) emit baseStateLoaded(); return this == r; // loadedRoomState fires only once per room }); - qCDebug(STATE) << "New" << toCString(initialJoinState) << "Room:" << id; + qCDebug(STATE) << "New" << initialJoinState << "Room:" << id; } Room::~Room() { delete d; } @@ -603,6 +603,11 @@ JoinState Room::memberJoinState(User* user) const : JoinState::Leave; } +Membership Room::memberState(User* user) const +{ + return d->getCurrentState<RoomMemberEvent>(user->id())->membership(); +} + JoinState Room::joinState() const { return d->joinState; } void Room::setJoinState(JoinState state) @@ -611,8 +616,8 @@ void Room::setJoinState(JoinState state) if (state == oldState) return; d->joinState = state; - qCDebug(STATE) << "Room" << id() << "changed state: " << int(oldState) - << "->" << int(state); + qCDebug(STATE) << "Room" << id() << "changed state: " << oldState + << "->" << state; emit changed(Change::JoinStateChange); emit joinStateChanged(oldState, state); } @@ -2513,16 +2518,16 @@ Room::Changes Room::processStateEvent(const RoomEvent& e) return false; // Stay low and hope for the best... } const auto prevMembership = oldRme ? oldRme->membership() - : MembershipType::Leave; + : Membership::Leave; switch (prevMembership) { - case MembershipType::Invite: + case Membership::Invite: if (rme.membership() != prevMembership) { d->usersInvited.removeOne(u); Q_ASSERT(!d->usersInvited.contains(u)); } break; - case MembershipType::Join: - if (rme.membership() == MembershipType::Join) { + case Membership::Join: + if (rme.membership() == Membership::Join) { // rename/avatar change or no-op if (rme.newDisplayName()) { emit memberAboutToRename(u, *rme.newDisplayName()); @@ -2536,7 +2541,7 @@ Room::Changes Room::processStateEvent(const RoomEvent& e) return false; } } else { - if (rme.membership() == MembershipType::Invite) + if (rme.membership() == Membership::Invite) qCWarning(MAIN) << "Membership change from Join to Invite:" << rme; // whatever the new membership, it's no more Join @@ -2544,16 +2549,16 @@ Room::Changes Room::processStateEvent(const RoomEvent& e) emit userRemoved(u); } break; - case MembershipType::Ban: - case MembershipType::Knock: - case MembershipType::Leave: - if (rme.membership() == MembershipType::Invite - || rme.membership() == MembershipType::Join) { + case Membership::Ban: + case Membership::Knock: + case Membership::Leave: + if (rme.membership() == Membership::Invite + || rme.membership() == Membership::Join) { d->membersLeft.removeOne(u); Q_ASSERT(!d->membersLeft.contains(u)); } break; - case MembershipType::Undefined: + case Membership::Undefined: ; // A warning will be dropped in the post-processing block below } return true; @@ -2636,10 +2641,10 @@ Room::Changes Room::processStateEvent(const RoomEvent& e) static_cast<const RoomMemberEvent*>(oldStateEvent); const auto prevMembership = oldMemberEvent ? oldMemberEvent->membership() - : MembershipType::Leave; + : Membership::Leave; switch (evt.membership()) { - case MembershipType::Join: - if (prevMembership != MembershipType::Join) { + case Membership::Join: + if (prevMembership != Membership::Join) { d->insertMemberIntoMap(u); emit userAdded(u); } else { @@ -2651,19 +2656,19 @@ Room::Changes Room::processStateEvent(const RoomEvent& e) emit memberAvatarChanged(u); } break; - case MembershipType::Invite: + case Membership::Invite: if (!d->usersInvited.contains(u)) d->usersInvited.push_back(u); if (u == localUser() && evt.isDirect()) connection()->addToDirectChats(this, user(evt.senderId())); break; - case MembershipType::Knock: - case MembershipType::Ban: - case MembershipType::Leave: + case Membership::Knock: + case Membership::Ban: + case Membership::Leave: if (!d->membersLeft.contains(u)) d->membersLeft.append(u); break; - case MembershipType::Undefined: + case Membership::Undefined: qCWarning(MEMBERS) << "Ignored undefined membership type"; } return MembersChange; diff --git a/lib/room.h b/lib/room.h index d71bff9c..cdbfe58f 100644 --- a/lib/room.h +++ b/lib/room.h @@ -11,7 +11,7 @@ #include "connection.h" #include "eventitem.h" -#include "joinstate.h" +#include "quotient_common.h" #include "csapi/message_pagination.h" @@ -245,6 +245,8 @@ public: /** * \brief Check the join state of a given user in this room * + * \deprecated Use memberState and check against a mask + * * \note Banned and invited users are not tracked separately for now (Leave * will be returned for them). * @@ -252,6 +254,11 @@ public: */ Q_INVOKABLE Quotient::JoinState memberJoinState(Quotient::User* user) const; + //! \brief Check the join state of a given user in this room + //! + //! \return the given user's state with respect to the room + Q_INVOKABLE Quotient::Membership memberState(User* user) const; + //! \brief Get a display name (without disambiguation) for the given member //! //! \sa safeMemberName, htmlSafeMemberName diff --git a/lib/syncdata.h b/lib/syncdata.h index e69bac17..0153bfd6 100644 --- a/lib/syncdata.h +++ b/lib/syncdata.h @@ -3,7 +3,7 @@ #pragma once -#include "joinstate.h" +#include "quotient_common.h" #include "events/stateevent.h" diff --git a/lib/user.cpp b/lib/user.cpp index 6cc9e161..c97e33a4 100644 --- a/lib/user.cpp +++ b/lib/user.cpp @@ -123,7 +123,7 @@ void User::rename(const QString& newName, const Room* r) } // #481: take the current state and update it with the new name auto evtC = r->getCurrentState<RoomMemberEvent>(id())->content(); - Q_ASSERT_X(evtC.membership == MembershipType::Join, __FUNCTION__, + Q_ASSERT_X(evtC.membership == Membership::Join, __FUNCTION__, "Attempt to rename a user that's not a room member"); evtC.displayName = sanitized(newName); r->setState<RoomMemberEvent>(id(), move(evtC)); -- cgit v1.2.3 From e05402045261a404ad5d8add63b82672d3d9aebb Mon Sep 17 00:00:00 2001 From: Alexey Rusakov <Kitsune-Ral@users.sf.net> Date: Sat, 17 Jul 2021 13:47:19 +0200 Subject: Fix building with Qt 5.12 --- lib/quotient_common.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/quotient_common.cpp b/lib/quotient_common.cpp index 805070d1..5d7a3027 100644 --- a/lib/quotient_common.cpp +++ b/lib/quotient_common.cpp @@ -9,7 +9,7 @@ inline QDebug suppressScopeAndDump(QDebug dbg, Enum e) { // Suppress "Quotient::" prefix QDebugStateSaver _dss(dbg); - dbg.setVerbosity(QDebug::MinimumVerbosity); + dbg.setVerbosity(0 /* QDebug::MinimumVerbosity since Qt 5.13 */); return qt_QMetaEnum_debugOperator(dbg, std::underlying_type_t<Enum>(e), qt_getEnumMetaObject(e), qt_getEnumName(e)); @@ -20,7 +20,7 @@ inline QDebug suppressScopeAndDump(QDebug dbg, const QFlags<Enum>& f) { // Suppress "Quotient::" prefix QDebugStateSaver _dss(dbg); - dbg.setVerbosity(QDebug::MinimumVerbosity); + dbg.setVerbosity(0 /* QDebug::MinimumVerbosity since Qt 5.13 */); return qt_QMetaEnum_flagDebugOperator_helper(dbg, f); } -- cgit v1.2.3 From 3c28d13c1a61999e7c3141f3ca08b5b734bd160c Mon Sep 17 00:00:00 2001 From: Alexey Rusakov <Kitsune-Ral@users.sf.net> Date: Sun, 18 Jul 2021 19:00:07 +0200 Subject: Introduce to_array() to fix building on macOS A previous incarnation, make_array, existed in basejob.cpp before. The new direction taken by C++20 is to either deduce the array (but the used Apple standard library doesn't have deduction guides yet) or to use to_array() that converts a C array to std::array. This latter option is taken here, with to_array() defined in quotient_common.h until we move over to C++20. --- lib/jobs/basejob.cpp | 13 +++---------- lib/quotient_common.h | 27 ++++++++++++++++++++++----- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/lib/jobs/basejob.cpp b/lib/jobs/basejob.cpp index 9a7b9b5e..400a9243 100644 --- a/lib/jobs/basejob.cpp +++ b/lib/jobs/basejob.cpp @@ -5,6 +5,7 @@ #include "basejob.h" #include "connectiondata.h" +#include "quotient_common.h" #include <QtCore/QRegularExpression> #include <QtCore/QTimer> @@ -15,8 +16,6 @@ #include <QtNetwork/QNetworkReply> #include <QtNetwork/QNetworkRequest> -#include <array> - using namespace Quotient; using std::chrono::seconds, std::chrono::milliseconds; using namespace std::chrono_literals; @@ -63,12 +62,6 @@ QDebug BaseJob::Status::dumpToLog(QDebug dbg) const return dbg << ": " << message; } -template <typename... Ts> -constexpr auto make_array(Ts&&... items) -{ - return std::array<std::common_type_t<Ts...>, sizeof...(Ts)>({items...}); -} - class BaseJob::Private { public: struct JobTimeoutConfig { @@ -163,8 +156,8 @@ public: { // FIXME: use std::array {} when Apple stdlib gets deduction guides for it static const auto verbs = - make_array(QStringLiteral("GET"), QStringLiteral("PUT"), - QStringLiteral("POST"), QStringLiteral("DELETE")); + to_array({ QStringLiteral("GET"), QStringLiteral("PUT"), + QStringLiteral("POST"), QStringLiteral("DELETE") }); const auto verbWord = verbs.at(size_t(verb)); return verbWord % ' ' % (reply ? reply->url().toString(QUrl::RemoveQuery) diff --git a/lib/quotient_common.h b/lib/quotient_common.h index 789128cf..037d5ded 100644 --- a/lib/quotient_common.h +++ b/lib/quotient_common.h @@ -8,6 +8,24 @@ namespace Quotient { Q_NAMESPACE +namespace impl { + template <class T, std::size_t N, std::size_t... I> + constexpr std::array<std::remove_cv_t<T>, N> + to_array_impl(T (&&a)[N], std::index_sequence<I...>) + { + return { {std::move(a[I])...} }; + } +} +// std::array {} needs explicit template parameters on macOS because +// Apple stdlib doesn't have deduction guides for std::array; to alleviate that, +// to_array() is borrowed from C++20 (thanks to cppreference for the possible +// implementation: https://en.cppreference.com/w/cpp/container/array/to_array) +template <typename T, size_t N> +constexpr auto to_array(T (&& items)[N]) +{ + return impl::to_array_impl(std::move(items), std::make_index_sequence<N>{}); +} + // TODO: code like this should be generated from the CS API definition //! \brief Membership states @@ -29,10 +47,9 @@ enum class Membership : unsigned int { Q_DECLARE_FLAGS(MembershipMask, Membership) Q_FLAG_NS(MembershipMask) -constexpr inline std::array MembershipStrings = { +constexpr inline auto MembershipStrings = to_array( // The order MUST be the same as the order in the original enum - "join", "leave", "invite", "knock", "ban" -}; + { "join", "leave", "invite", "knock", "ban" }); //! \brief Local user join-state names //! @@ -49,10 +66,10 @@ enum class JoinState : std::underlying_type_t<Membership> { Q_DECLARE_FLAGS(JoinStates, JoinState) Q_FLAG_NS(JoinStates) -constexpr inline std::array JoinStateStrings { +constexpr inline auto JoinStateStrings = to_array({ MembershipStrings[0], MembershipStrings[1], MembershipStrings[2], MembershipStrings[3] /* same as MembershipStrings, sans "ban" */ -}; +}); //! \brief Network job running policy flags //! -- cgit v1.2.3 From 2187f26ebdc9edf7b3cbfa1d208c03c4384f4135 Mon Sep 17 00:00:00 2001 From: Alexey Rusakov <Kitsune-Ral@users.sf.net> Date: Sun, 18 Jul 2021 20:56:33 +0200 Subject: Add a missing #include Without this, it compiles on Linux but on macOS and Windows. --- lib/quotient_common.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/quotient_common.h b/lib/quotient_common.h index 037d5ded..d225ad63 100644 --- a/lib/quotient_common.h +++ b/lib/quotient_common.h @@ -5,6 +5,8 @@ #include <qobjectdefs.h> +#include <array> + namespace Quotient { Q_NAMESPACE -- cgit v1.2.3