Chromium Code Reviews| Index: components/sessions/core/persistent_tab_restore_service.cc |
| diff --git a/components/sessions/core/persistent_tab_restore_service.cc b/components/sessions/core/persistent_tab_restore_service.cc |
| index 984c3af264dbecaa1ec7c86cba9328eaf2596948..7273d1555e5fbf260648f1145621a5dc34b956f0 100644 |
| --- a/components/sessions/core/persistent_tab_restore_service.cc |
| +++ b/components/sessions/core/persistent_tab_restore_service.cc |
| @@ -15,8 +15,8 @@ |
| #include "base/files/file_path.h" |
| #include "base/logging.h" |
| #include "base/macros.h" |
| +#include "base/memory/ptr_util.h" |
| #include "base/memory/ref_counted.h" |
| -#include "base/memory/scoped_vector.h" |
| #include "base/stl_util.h" |
| #include "base/task/cancelable_task_tracker.h" |
| #include "base/time/time.h" |
| @@ -35,8 +35,6 @@ typedef bool PinnedStatePayload; |
| typedef int32_t RestoredEntryPayload; |
| -typedef std::map<SessionID::id_type, TabRestoreService::Entry*> IDToEntry; |
| - |
| // Payload used for the start of a tab close. This is the old struct that is |
| // used for backwards compat when it comes to reading the session files. |
| struct SelectedNavigationInTabPayload { |
| @@ -148,8 +146,9 @@ class PersistentTabRestoreService::Delegate |
| bool IsLoaded() const; |
| // Creates and add entries to |entries| for each of the windows in |windows|. |
| - static void CreateEntriesFromWindows(std::vector<SessionWindow*>* windows, |
| - std::vector<Entry*>* entries); |
| + static void CreateEntriesFromWindows( |
| + std::vector<SessionWindow*>* windows, |
| + std::vector<std::unique_ptr<Entry>>* entries); |
| void Shutdown(); |
| @@ -189,12 +188,14 @@ class PersistentTabRestoreService::Delegate |
| void OnGotLastSessionCommands(ScopedVector<SessionCommand> commands); |
| // Populates |loaded_entries| with Entries from |commands|. |
| - void CreateEntriesFromCommands(const std::vector<SessionCommand*>& commands, |
| - std::vector<Entry*>* loaded_entries); |
| + void CreateEntriesFromCommands( |
| + const std::vector<SessionCommand*>& commands, |
| + std::vector<std::unique_ptr<Entry>>* loaded_entries); |
| // Validates all entries in |entries|, deleting any with no navigations. This |
| // also deletes any entries beyond the max number of entries we can hold. |
| - static void ValidateAndDeleteEmptyEntries(std::vector<Entry*>* entries); |
| + static void ValidateAndDeleteEmptyEntries( |
| + std::vector<std::unique_ptr<Entry>>* entries); |
| // Callback from BaseSessionService when we've received the windows from the |
| // previous session. This creates and add entries to |staging_entries_| and |
| @@ -213,13 +214,6 @@ class PersistentTabRestoreService::Delegate |
| // observers are notified. |
| void LoadStateChanged(); |
| - // If |id_to_entry| contains an entry for |id| the corresponding entry is |
| - // deleted and removed from both |id_to_entry| and |entries|. This is used |
| - // when creating entries from the backend file. |
| - void RemoveEntryByID(SessionID::id_type id, |
| - IDToEntry* id_to_entry, |
| - std::vector<TabRestoreService::Entry*>* entries); |
| - |
| private: |
| // The associated client. |
| TabRestoreServiceClient* client_; |
| @@ -240,7 +234,7 @@ class PersistentTabRestoreService::Delegate |
| // Results from previously closed tabs/sessions is first added here. When the |
| // results from both us and the session restore service have finished loading |
| // LoadStateChanged is invoked, which adds these entries to entries_. |
| - ScopedVector<Entry> staging_entries_; |
| + std::vector<std::unique_ptr<Entry>> staging_entries_; |
| // Used when loading previous tabs/session and open tabs/session. |
| base::CancelableTaskTracker cancelable_task_tracker_; |
| @@ -287,14 +281,18 @@ void PersistentTabRestoreService::Delegate::OnWillSaveCommands() { |
| DCHECK(static_cast<size_t>(to_write_count) <= entries.size()); |
| std::advance(i, entries.size() - static_cast<int>(to_write_count)); |
| for (; i != entries.rend(); ++i) { |
| - Entry* entry = *i; |
| - if (entry->type == TAB) { |
| - Tab* tab = static_cast<Tab*>(entry); |
| - int selected_index = GetSelectedNavigationIndexToPersist(*tab); |
| - if (selected_index != -1) |
| - ScheduleCommandsForTab(*tab, selected_index); |
| - } else { |
| - ScheduleCommandsForWindow(*static_cast<Window*>(entry)); |
| + Entry* entry = i->get(); |
| + switch (entry->type) { |
| + case TAB: { |
| + Tab* tab = static_cast<Tab*>(entry); |
| + int selected_index = GetSelectedNavigationIndexToPersist(*tab); |
| + if (selected_index != -1) |
| + ScheduleCommandsForTab(*tab, selected_index); |
| + break; |
| + } |
| + case WINDOW: |
| + ScheduleCommandsForWindow(*static_cast<Window*>(entry)); |
| + break; |
| } |
| entries_written_++; |
| } |
| @@ -380,11 +378,11 @@ bool PersistentTabRestoreService::Delegate::IsLoaded() const { |
| // static |
| void PersistentTabRestoreService::Delegate::CreateEntriesFromWindows( |
| std::vector<SessionWindow*>* windows, |
| - std::vector<Entry*>* entries) { |
| + std::vector<std::unique_ptr<Entry>>* entries) { |
| for (size_t i = 0; i < windows->size(); ++i) { |
| std::unique_ptr<Window> window(new Window()); |
| if (ConvertSessionWindowToWindow((*windows)[i], window.get())) |
| - entries->push_back(window.release()); |
| + entries->push_back(std::move(window)); |
| } |
| } |
| @@ -399,7 +397,7 @@ void PersistentTabRestoreService::Delegate::ScheduleCommandsForWindow( |
| int valid_tab_count = 0; |
| int real_selected_tab = selected_tab; |
| for (size_t i = 0; i < window.tabs.size(); ++i) { |
| - if (GetSelectedNavigationIndexToPersist(window.tabs[i]) != -1) { |
| + if (GetSelectedNavigationIndexToPersist(*window.tabs[i]) != -1) { |
| valid_tab_count++; |
| } else if (static_cast<int>(i) < selected_tab) { |
| real_selected_tab--; |
| @@ -418,9 +416,9 @@ void PersistentTabRestoreService::Delegate::ScheduleCommandsForWindow( |
| } |
| for (size_t i = 0; i < window.tabs.size(); ++i) { |
| - int selected_index = GetSelectedNavigationIndexToPersist(window.tabs[i]); |
| + int selected_index = GetSelectedNavigationIndexToPersist(*window.tabs[i]); |
| if (selected_index != -1) |
| - ScheduleCommandsForTab(window.tabs[i], selected_index); |
| + ScheduleCommandsForTab(*window.tabs[i], selected_index); |
| } |
| } |
| @@ -555,28 +553,56 @@ int PersistentTabRestoreService::Delegate::GetSelectedNavigationIndexToPersist( |
| void PersistentTabRestoreService::Delegate::OnGotLastSessionCommands( |
| ScopedVector<SessionCommand> commands) { |
| - std::vector<Entry*> entries; |
| + std::vector<std::unique_ptr<Entry>> entries; |
| CreateEntriesFromCommands(commands.get(), &entries); |
| // Closed tabs always go to the end. |
| - staging_entries_.insert(staging_entries_.end(), entries.begin(), |
| - entries.end()); |
| + staging_entries_.insert(staging_entries_.end(), |
| + make_move_iterator(entries.begin()), |
| + make_move_iterator(entries.end())); |
| load_state_ |= LOADED_LAST_TABS; |
| LoadStateChanged(); |
| } |
| +namespace { |
| + |
| +class RemoveByIDIndex { |
|
sky
2016/08/04 16:34:39
This code is far too subtle. Please document it al
Sidney San Martín
2016/08/04 17:04:50
Can you think of a simpler way to model this? I ma
sky
2016/08/04 19:09:52
How about changing Entries to a std::vector? TabRe
Sidney San Martín
2016/08/04 20:17:19
I like this idea in general, but it doesn't solve
sky
2016/08/04 22:57:12
I prefer the old code, while not as efficient it's
Sidney San Martín
2016/08/09 04:10:52
OK, agreed. I still want to find a simple and effi
|
| + std::unordered_map<SessionID::id_type, std::function<void()>> index_; |
|
sky
2016/08/04 16:34:39
public section is first, then private.
|
| + |
| + public: |
| + template <typename T> |
| + void index_back(T* collection) { |
| + auto entry = &collection->back(); |
| + index_[(*entry)->id] = [=]() { |
|
sky
2016/08/04 16:34:39
Oy, this is hard to parse. Please be explicit abou
|
| + auto it = std::find(collection->begin(), collection->end(), *entry); |
| + if (it != collection->end()) { |
|
sky
2016/08/04 16:34:39
no {}
|
| + collection->erase(it); |
| + } |
| + }; |
| + } |
| + |
| + void remove(SessionID::id_type id) { |
| + auto it = index_.find(id); |
| + if (it != index_.end()) { |
|
sky
2016/08/04 16:34:39
no {}
|
| + it->second(); |
|
sky
2016/08/04 16:34:39
This is subtle and woth a comment.
|
| + } |
| + } |
| +}; |
| + |
| +} // namespace |
| + |
| void PersistentTabRestoreService::Delegate::CreateEntriesFromCommands( |
| const std::vector<SessionCommand*>& commands, |
| - std::vector<Entry*>* loaded_entries) { |
| + std::vector<std::unique_ptr<Entry>>* loaded_entries) { |
| if (tab_restore_service_helper_->entries().size() == kMaxEntries) |
| return; |
| - // Iterate through the commands populating entries and id_to_entry. |
| - ScopedVector<Entry> entries; |
| - IDToEntry id_to_entry; |
| + // Iterate through the commands populating entries and remove_by_id. |
| + std::vector<std::unique_ptr<Entry>> entries; |
| + RemoveByIDIndex remove_by_id; |
| // If non-null we're processing the navigations of this tab. |
| - Tab* current_tab = NULL; |
| + Tab* current_tab = nullptr; |
| // If non-null we're processing the tabs of this window. |
| - Window* current_window = NULL; |
| + Window* current_window = nullptr; |
| // If > 0, we've gotten a window command but not all the tabs yet. |
| int pending_window_tabs = 0; |
| for (std::vector<SessionCommand*>::const_iterator i = commands.begin(); |
| @@ -590,13 +616,13 @@ void PersistentTabRestoreService::Delegate::CreateEntriesFromCommands( |
| return; |
| } |
| - current_tab = NULL; |
| - current_window = NULL; |
| + current_tab = nullptr; |
| + current_window = nullptr; |
| RestoredEntryPayload payload; |
| if (!command.GetPayload(&payload, sizeof(payload))) |
| return; |
| - RemoveEntryByID(payload, &id_to_entry, &(entries.get())); |
| + remove_by_id.remove(payload); |
| break; |
| } |
| @@ -630,14 +656,14 @@ void PersistentTabRestoreService::Delegate::CreateEntriesFromCommands( |
| return; |
| } |
| - RemoveEntryByID(payload.window_id, &id_to_entry, &(entries.get())); |
| + remove_by_id.remove(payload.window_id); |
| - current_window = new Window(); |
| + entries.push_back(base::MakeUnique<Window>()); |
| + current_window = static_cast<Window*>(entries.back().get()); |
| current_window->selected_tab_index = payload.selected_tab_index; |
| current_window->timestamp = |
| base::Time::FromInternalValue(payload.timestamp); |
| - entries.push_back(current_window); |
| - id_to_entry[payload.window_id] = current_window; |
| + remove_by_id.index_back(&entries); |
| break; |
| } |
| @@ -660,17 +686,17 @@ void PersistentTabRestoreService::Delegate::CreateEntriesFromCommands( |
| NOTREACHED(); |
| return; |
| } |
| - current_window->tabs.resize(current_window->tabs.size() + 1); |
| - current_tab = &(current_window->tabs.back()); |
| + current_window->tabs.push_back(base::MakeUnique<Tab>()); |
| + current_tab = current_window->tabs.back().get(); |
| if (--pending_window_tabs == 0) |
| - current_window = NULL; |
| + current_window = nullptr; |
| } else { |
| - RemoveEntryByID(payload.id, &id_to_entry, &(entries.get())); |
| - current_tab = new Tab(); |
| - id_to_entry[payload.id] = current_tab; |
| + remove_by_id.remove(payload.id); |
| + entries.push_back(base::MakeUnique<Tab>()); |
| + remove_by_id.index_back(&entries); |
| + current_tab = static_cast<Tab*>(entries.back().get()); |
| current_tab->timestamp = |
| base::Time::FromInternalValue(payload.timestamp); |
| - entries.push_back(current_tab); |
| } |
| current_tab->current_navigation_index = payload.index; |
| break; |
| @@ -757,40 +783,34 @@ void PersistentTabRestoreService::Delegate::CreateEntriesFromCommands( |
| } |
| // If there was corruption some of the entries won't be valid. |
| - ValidateAndDeleteEmptyEntries(&(entries.get())); |
| + ValidateAndDeleteEmptyEntries(&entries); |
| - loaded_entries->swap(entries.get()); |
| + loaded_entries->swap(entries); |
| } |
| // static |
| void PersistentTabRestoreService::Delegate::ValidateAndDeleteEmptyEntries( |
| - std::vector<Entry*>* entries) { |
| - std::vector<Entry*> valid_entries; |
| - std::vector<Entry*> invalid_entries; |
| + std::vector<std::unique_ptr<Entry>>* entries) { |
| + std::vector<std::unique_ptr<Entry>> valid_entries; |
| // Iterate from the back so that we keep the most recently closed entries. |
| - for (std::vector<Entry*>::reverse_iterator i = entries->rbegin(); |
| - i != entries->rend(); ++i) { |
| - if (TabRestoreServiceHelper::ValidateEntry(*i)) |
| - valid_entries.push_back(*i); |
| - else |
| - invalid_entries.push_back(*i); |
| + for (auto i = entries->rbegin(); i != entries->rend(); ++i) { |
| + if (TabRestoreServiceHelper::ValidateEntry(**i)) |
| + valid_entries.push_back(std::move(*i)); |
| } |
| // NOTE: at this point the entries are ordered with newest at the front. |
| entries->swap(valid_entries); |
| - |
| - // Delete the remaining entries. |
| - STLDeleteElements(&invalid_entries); |
| } |
| void PersistentTabRestoreService::Delegate::OnGotPreviousSession( |
| ScopedVector<SessionWindow> windows, |
| SessionID::id_type ignored_active_window) { |
| - std::vector<Entry*> entries; |
| + std::vector<std::unique_ptr<Entry>> entries; |
| CreateEntriesFromWindows(&windows.get(), &entries); |
| // Previous session tabs go first. |
| - staging_entries_.insert(staging_entries_.begin(), entries.begin(), |
| - entries.end()); |
| + staging_entries_.insert(staging_entries_.begin(), |
| + make_move_iterator(entries.begin()), |
| + make_move_iterator(entries.end())); |
| load_state_ |= LOADED_LAST_SESSION; |
| LoadStateChanged(); |
| } |
| @@ -800,8 +820,8 @@ bool PersistentTabRestoreService::Delegate::ConvertSessionWindowToWindow( |
| Window* window) { |
| for (size_t i = 0; i < session_window->tabs.size(); ++i) { |
| if (!session_window->tabs[i]->navigations.empty()) { |
| - window->tabs.resize(window->tabs.size() + 1); |
| - Tab& tab = window->tabs.back(); |
| + window->tabs.push_back(base::MakeUnique<Tab>()); |
| + Tab& tab = *window->tabs.back(); |
| tab.pinned = session_window->tabs[i]->pinned; |
| tab.navigations.swap(session_window->tabs[i]->navigations); |
| tab.current_navigation_index = |
| @@ -850,19 +870,14 @@ void PersistentTabRestoreService::Delegate::LoadStateChanged() { |
| } |
| // And add them. |
| - for (size_t i = 0; i < staging_entries_.size(); ++i) { |
| - staging_entries_[i]->from_last_session = true; |
| - tab_restore_service_helper_->AddEntry(staging_entries_[i], false, false); |
| + for (auto& staging_entry : staging_entries_) { |
| + staging_entry->from_last_session = true; |
| + tab_restore_service_helper_->AddEntry(std::move(staging_entry), false, |
| + false); |
| } |
| - // AddEntry takes ownership of the entry, need to clear out entries so that |
| - // it doesn't delete them. |
| - staging_entries_.weak_clear(); |
| - |
| - // Make it so we rewrite all the tabs. We need to do this otherwise we won't |
| - // correctly write out the entries when Save is invoked (Save starts from |
| - // the front, not the end and we just added the entries to the end). |
| - entries_to_write_ = staging_entries_.size(); |
| + staging_entries_.clear(); |
| + entries_to_write_ = 0; |
| tab_restore_service_helper_->PruneEntries(); |
| tab_restore_service_helper_->NotifyTabsChanged(); |
| @@ -870,40 +885,6 @@ void PersistentTabRestoreService::Delegate::LoadStateChanged() { |
| tab_restore_service_helper_->NotifyLoaded(); |
| } |
| -void PersistentTabRestoreService::Delegate::RemoveEntryByID( |
| - SessionID::id_type id, |
| - IDToEntry* id_to_entry, |
| - std::vector<TabRestoreService::Entry*>* entries) { |
| - // Look for the entry in the map. If it is present, erase it from both |
| - // collections and return. |
| - IDToEntry::iterator i = id_to_entry->find(id); |
| - if (i != id_to_entry->end()) { |
| - entries->erase(std::find(entries->begin(), entries->end(), i->second)); |
| - delete i->second; |
| - id_to_entry->erase(i); |
| - return; |
| - } |
| - |
| - // Otherwise, loop over all items in the map and see if any of the Windows |
| - // have Tabs with the |id|. |
| - for (IDToEntry::iterator i = id_to_entry->begin(); i != id_to_entry->end(); |
| - ++i) { |
| - if (i->second->type == TabRestoreService::WINDOW) { |
| - TabRestoreService::Window* window = |
| - static_cast<TabRestoreService::Window*>(i->second); |
| - std::vector<TabRestoreService::Tab>::iterator j = window->tabs.begin(); |
| - for ( ; j != window->tabs.end(); ++j) { |
| - // If the ID matches one of this window's tabs, remove it from the |
| - // list. |
| - if ((*j).id == id) { |
| - window->tabs.erase(j); |
| - return; |
| - } |
| - } |
| - } |
| - } |
| -} |
| - |
| // PersistentTabRestoreService ------------------------------------------------- |
| PersistentTabRestoreService::PersistentTabRestoreService( |
| @@ -953,8 +934,8 @@ std::vector<LiveTab*> PersistentTabRestoreService::RestoreMostRecentEntry( |
| return helper_.RestoreMostRecentEntry(context); |
| } |
| -TabRestoreService::Tab* PersistentTabRestoreService::RemoveTabEntryById( |
| - SessionID::id_type id) { |
| +std::unique_ptr<TabRestoreService::Tab> |
| +PersistentTabRestoreService::RemoveTabEntryById(SessionID::id_type id) { |
| return helper_.RemoveTabEntryById(id); |
| } |