diff --git a/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp b/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp index 5984494ca1..64f08a979d 100644 --- a/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp +++ b/Telegram/SourceFiles/media/view/media_view_group_thumbs.cpp @@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/media/history_view_media.h" #include "ui/image/image.h" #include "main/main_session.h" +#include "core/crash_reports.h" #include "app.h" #include "styles/style_media_view.h" @@ -37,6 +38,42 @@ int Round(float64 value) { using Context = GroupThumbs::Context; using Key = GroupThumbs::Key; +[[nodiscard]] QString DebugSerializeMsgId(FullMsgId itemId) { + return QString("msg%1_%2").arg(itemId.channel).arg(itemId.msg); +} + +[[nodiscard]] QString DebugSerializePeer(PeerId peerId) { + return peerIsUser(peerId) + ? QString("user%1").arg(peerToUser(peerId)) + : peerIsChat(peerId) + ? QString("chat%1").arg(peerToChat(peerId)) + : QString("channel%1").arg(peerToChannel(peerId)); +} + +[[nodiscard]] QString DebugSerializeKey(const Key &key) { + return v::match(key, [&](PhotoId photoId) { + return QString("photo%1").arg(photoId); + }, [](FullMsgId itemId) { + return DebugSerializeMsgId(itemId); + }, [&](GroupThumbs::CollageKey key) { + return QString("collage%1").arg(key.index); + }); +} + +[[nodiscard]] QString DebugSerializeContext(const Context &context) { + return v::match(context, [](PeerId peerId) { + return DebugSerializePeer(peerId); + }, [](MessageGroupId groupId) { + return QString("group_%1_%2" + ).arg(DebugSerializePeer(groupId.peer) + ).arg(groupId.value); + }, [](FullMsgId item) { + return DebugSerializeMsgId(item); + }, [](v::null_t) -> QString { + return "null"; + }); +} + Data::FileOrigin ComputeFileOrigin(const Key &key, const Context &context) { return v::match(key, [&](PhotoId photoId) { return v::match(context, [&](PeerId peerId) { @@ -474,6 +511,37 @@ void GroupThumbs::RefreshFromSlice( } } +template +void ValidateSlice( + const Slice &slice, + const Context &context, + int from, + int index, + int till) { + auto keys = base::flat_set(); + for (auto i = from; i != till; ++i) { + const auto key = ComputeKey(slice, i); + if (keys.contains(key)) { + // All items should be unique! + auto strings = QStringList(); + strings.reserve(till - from); + for (auto i = from; i != till; ++i) { + strings.push_back(DebugSerializeKey(ComputeKey(slice, i))); + } + CrashReports::SetAnnotation( + "keys", + QString("%1:%2-(%3)-%4:" + ).arg(DebugSerializeContext(context) + ).arg(from + ).arg(index + ).arg(till) + strings.join(",")); + Unexpected("Bad slice in GroupThumbs."); + } else { + keys.emplace(key); + } + } +} + template void GroupThumbs::fillItems( const Slice &slice, @@ -487,6 +555,10 @@ void GroupThumbs::fillItems( const auto current = (index - from); const auto old = base::take(_items); + if (Logs::DebugEnabled()) { + ValidateSlice(slice, _context, from, index, till); + } + markCacheStale(); _items.reserve(till - from); for (auto i = from; i != till; ++i) { @@ -514,12 +586,16 @@ void GroupThumbs::animateAliveItems(int current) { } void GroupThumbs::fillDyingItems(const std::vector> &old) { + Expects(_cache.size() >= _items.size()); + _dying.reserve(_cache.size() - _items.size()); animatePreviouslyAlive(old); markRestAsDying(); } void GroupThumbs::markRestAsDying() { + Expects(_cache.size() >= _items.size()); + _dying.reserve(_cache.size() - _items.size()); for (const auto &cacheItem : _cache) { const auto &thumb = cacheItem.second;