From bf775cb4ca67ab2c36082b20817bfbcd44379f26 Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Sat, 9 Jun 2018 11:52:37 +0300
Subject: [PATCH] Fix history items cleanup.

---
 Telegram/SourceFiles/app.cpp             | 79 +++++++++++-------------
 Telegram/SourceFiles/history/history.cpp |  4 +-
 2 files changed, 38 insertions(+), 45 deletions(-)

diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp
index dd9c3b912..613fd5261 100644
--- a/Telegram/SourceFiles/app.cpp
+++ b/Telegram/SourceFiles/app.cpp
@@ -50,8 +50,7 @@ namespace {
 
 	UserData *self = nullptr;
 
-	using PeersData = QHash<PeerId, PeerData*>;
-	PeersData peersData;
+	std::unordered_map<PeerId, std::unique_ptr<PeerData>> peersData;
 
 	using LocationsData = QHash<LocationCoords, LocationData*>;
 	LocationsData locationsData;
@@ -747,7 +746,7 @@ namespace App {
 		} else if (chat->version <= d.vversion.v && chat->count > 0) {
 			chat->version = d.vversion.v;
 			auto canEdit = chat->canEdit();
-			UserData *user = App::userLoaded(d.vuser_id.v);
+			const auto user = App::userLoaded(d.vuser_id.v);
 			if (user) {
 				if (chat->participants.empty()) {
 					if (chat->count > 0) {
@@ -1074,40 +1073,43 @@ namespace App {
 	}
 
 	PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction) {
-		if (!id) return nullptr;
+		if (!id) {
+			return nullptr;
+		}
 
-		auto i = peersData.constFind(id);
+		auto i = peersData.find(id);
 		if (i == peersData.cend()) {
-			PeerData *newData = nullptr;
-			if (peerIsUser(id)) {
-				newData = new UserData(id);
-			} else if (peerIsChat(id)) {
-				newData = new ChatData(id);
-			} else if (peerIsChannel(id)) {
-				newData = new ChannelData(id);
-			}
-			Assert(newData != nullptr);
+			auto newData = [&]() -> std::unique_ptr<PeerData> {
+				if (peerIsUser(id)) {
+					return std::make_unique<UserData>(id);
+				} else if (peerIsChat(id)) {
+					return std::make_unique<ChatData>(id);
+				} else if (peerIsChannel(id)) {
+					return std::make_unique<ChannelData>(id);
+				}
+				Unexpected("Peer id type.");
+			}();
 
 			newData->input = MTPinputPeer(MTP_inputPeerEmpty());
-			i = peersData.insert(id, newData);
+			i = peersData.emplace(id, std::move(newData)).first;
 		}
 		switch (restriction) {
 		case PeerData::MinimalLoaded: {
-			if (i.value()->loadedStatus == PeerData::NotLoaded) {
+			if (i->second->loadedStatus == PeerData::NotLoaded) {
 				return nullptr;
 			}
 		} break;
 		case PeerData::FullLoaded: {
-			if (i.value()->loadedStatus != PeerData::FullLoaded) {
+			if (i->second->loadedStatus != PeerData::FullLoaded) {
 				return nullptr;
 			}
 		} break;
 		}
-		return i.value();
+		return i->second.get();
 	}
 
 	void enumerateUsers(Fn<void(not_null<UserData*>)> action) {
-		for_const (const auto peer, peersData) {
+		for (const auto &[peerId, peer] : peersData) {
 			if (const auto user = peer->asUser()) {
 				action(user);
 			}
@@ -1116,9 +1118,9 @@ namespace App {
 
 	void enumerateChatsChannels(
 			Fn<void(not_null<PeerData*>)> action) {
-		for_const (const auto peer, peersData) {
+		for (const auto &[peerId, peer] : peersData) {
 			if (!peer->isUser()) {
-				action(peer);
+				action(peer.get());
 			}
 		}
 	}
@@ -1128,10 +1130,10 @@ namespace App {
 	}
 
 	PeerData *peerByName(const QString &username) {
-		QString uname(username.trimmed());
-		for_const (PeerData *peer, peersData) {
+		const auto uname = username.trimmed();
+		for (const auto &[peerId, peer] : peersData) {
 			if (!peer->userName().compare(uname, Qt::CaseInsensitive)) {
-				return peer;
+				return peer.get();
 			}
 		}
 		return nullptr;
@@ -1246,24 +1248,16 @@ namespace App {
 	void historyClearMsgs() {
 		::dependentItems.clear();
 
-		QVector<HistoryItem*> toDelete;
-		for_const (auto item, msgsData) {
-			if (!item->mainView()) {
-				toDelete.push_back(item);
-			}
-		}
-		for_const (auto &chMsgsData, channelMsgsData) {
-			for_const (auto item, chMsgsData) {
-				if (!item->mainView()) {
-					toDelete.push_back(item);
-				}
-			}
-		}
-		msgsData.clear();
-		channelMsgsData.clear();
-		for_const (auto item, toDelete) {
+		const auto oldData = base::take(msgsData);
+		const auto oldChannelData = base::take(channelMsgsData);
+		for (const auto item : oldData) {
 			delete item;
 		}
+		for (const auto &data : oldChannelData) {
+			for (const auto item : data) {
+				delete item;
+			}
+		}
 
 		clearMousedItems();
 	}
@@ -1275,10 +1269,7 @@ namespace App {
 		cSetSavedPeersByTime(SavedPeersByTime());
 		cSetRecentInlineBots(RecentInlineBots());
 
-		for_const (auto peer, ::peersData) {
-			delete peer;
-		}
-		::peersData.clear();
+		peersData.clear();
 
 		if (AuthSession::Exists()) {
 			Auth().api().clearWebPageRequests();
diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp
index e84582876..e41800226 100644
--- a/Telegram/SourceFiles/history/history.cpp
+++ b/Telegram/SourceFiles/history/history.cpp
@@ -99,8 +99,10 @@ not_null<History*> Histories::findOrInsert(PeerId peerId) {
 }
 
 void Histories::clear() {
+	for (const auto &[peerId, history] : _map) {
+		history->unloadBlocks();
+	}
 	App::historyClearMsgs();
-
 	_map.clear();
 
 	_unreadFull = _unreadMuted = 0;