Make member list sorted a bit more efficient
I don't have any hard numbers on what difference this makes, but it's definitely a positive improvement. I noticed and fixed a few issues that were made more glaring by recent changes in libQuotient: 1. Room::memberJoined is called during the historical loading or whatever, when we only need that *after* stuff is settled. 2. We really don't need to sort the room's members immediately - it's only relevant when UserListModel is used (and I think this was previous behavior?) So now its done lazily. 3. We do not want to call Room::effectivePowerLevel willy-nilly. It may become a more expensive lookup, and it's also varying levels of wasteful depending on which sorting algorithm the STL uses. It doesn't cost much for us to keep a temporary cache for the lambda function to use.
This commit is contained in:
@@ -172,6 +172,10 @@ void UserListModel::refreshAllMembers()
|
|||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
if (m_currentRoom != nullptr) {
|
if (m_currentRoom != nullptr) {
|
||||||
|
// Only sort members when this model needs to be refreshed.
|
||||||
|
if (m_currentRoom->sortedMemberIds().isEmpty()) {
|
||||||
|
m_currentRoom->sortAllMembers();
|
||||||
|
}
|
||||||
m_members = m_currentRoom->sortedMemberIds();
|
m_members = m_currentRoom->sortedMemberIds();
|
||||||
} else {
|
} else {
|
||||||
m_members.clear();
|
m_members.clear();
|
||||||
|
|||||||
@@ -175,9 +175,16 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS
|
|||||||
connect(neochatconnection, &NeoChatConnection::globalUrlPreviewEnabledChanged, this, &NeoChatRoom::urlPreviewEnabledChanged);
|
connect(neochatconnection, &NeoChatConnection::globalUrlPreviewEnabledChanged, this, &NeoChatRoom::urlPreviewEnabledChanged);
|
||||||
connect(this, &Room::fullyReadMarkerMoved, this, &NeoChatRoom::invalidateLastUnreadHighlightId);
|
connect(this, &Room::fullyReadMarkerMoved, this, &NeoChatRoom::invalidateLastUnreadHighlightId);
|
||||||
|
|
||||||
// Wait until the initial member list is available before sorting
|
// This may look weird, but this is actually for performance.
|
||||||
connect(this, &Room::memberListChanged, this, &NeoChatRoom::refreshAllMembers, Qt::SingleShotConnection);
|
// We only want to listen to new member joining *when* the initial member list was loaded.
|
||||||
connect(this, &Room::memberJoined, this, &NeoChatRoom::insertMemberSorted);
|
connect(
|
||||||
|
this,
|
||||||
|
&Room::memberListChanged,
|
||||||
|
this,
|
||||||
|
[this] {
|
||||||
|
connect(this, &Room::memberJoined, this, &NeoChatRoom::insertMemberSorted);
|
||||||
|
},
|
||||||
|
Qt::SingleShotConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NeoChatRoom::visible() const
|
bool NeoChatRoom::visible() const
|
||||||
@@ -1917,14 +1924,21 @@ void NeoChatRoom::invalidateLastUnreadHighlightId(const QString &fromEventId, co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NeoChatRoom::refreshAllMembers()
|
void NeoChatRoom::sortAllMembers()
|
||||||
{
|
{
|
||||||
m_sortedMemberIds = memberIds();
|
m_sortedMemberIds = memberIds();
|
||||||
|
|
||||||
|
// Build up a temporary cache, because we may be checking the same member over and over while sorting.
|
||||||
|
QHash<QString, int> effectivePowerLevels;
|
||||||
|
effectivePowerLevels.reserve(m_sortedMemberIds.size());
|
||||||
|
for (const auto &member : m_sortedMemberIds) {
|
||||||
|
effectivePowerLevels[member] = memberEffectivePowerLevel(member);
|
||||||
|
}
|
||||||
|
|
||||||
MemberSorter sorter;
|
MemberSorter sorter;
|
||||||
std::ranges::sort(m_sortedMemberIds, [this, &sorter](const auto &left, const auto &right) {
|
std::ranges::sort(m_sortedMemberIds, [&sorter, &effectivePowerLevels](const auto &left, const auto &right) {
|
||||||
const auto leftPl = memberEffectivePowerLevel(left);
|
const auto leftPl = effectivePowerLevels[left];
|
||||||
const auto rightPl = memberEffectivePowerLevel(right);
|
const auto rightPl = effectivePowerLevels[right];
|
||||||
if (leftPl > rightPl) {
|
if (leftPl > rightPl) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -683,6 +683,8 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return List of members in this room, sorted by power level and then by name.
|
* @return List of members in this room, sorted by power level and then by name.
|
||||||
|
*
|
||||||
|
* This list is only populated after sortAllMembers() is called.
|
||||||
*/
|
*/
|
||||||
QList<QString> sortedMemberIds() const;
|
QList<QString> sortedMemberIds() const;
|
||||||
|
|
||||||
@@ -721,6 +723,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
Q_INVOKABLE void clearSelectedMessages();
|
Q_INVOKABLE void clearSelectedMessages();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sort all members based on their display name, and power level.
|
||||||
|
*
|
||||||
|
* @note This is a very expensive operation, and should only be done when truly needed.
|
||||||
|
*/
|
||||||
|
void sortAllMembers();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_visible = false;
|
bool m_visible = false;
|
||||||
|
|
||||||
@@ -767,8 +776,6 @@ private Q_SLOTS:
|
|||||||
|
|
||||||
void invalidateLastUnreadHighlightId(const QString &fromEventId, const QString &toEventId);
|
void invalidateLastUnreadHighlightId(const QString &fromEventId, const QString &toEventId);
|
||||||
|
|
||||||
void refreshAllMembers();
|
|
||||||
|
|
||||||
void insertMemberSorted(Quotient::RoomMember member);
|
void insertMemberSorted(Quotient::RoomMember member);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
|
|||||||
Reference in New Issue
Block a user