Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(360)

Side by Side Diff: chrome/browser/ui/app_list/search/mixer.cc

Issue 369693004: Make app list search result mixer more resilient to reordering. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rework algorithm, rebase onto https://codereview.chromium.org/372843003/ Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/app_list/search/mixer.h" 5 #include "chrome/browser/ui/app_list/search/mixer.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <set> 8 #include <set>
9 #include <string> 9 #include <string>
10 #include <vector> 10 #include <vector>
11 11
12 #include "chrome/browser/ui/app_list/search/chrome_search_result.h" 12 #include "chrome/browser/ui/app_list/search/chrome_search_result.h"
13 #include "ui/app_list/search_provider.h" 13 #include "ui/app_list/search_provider.h"
14 14
15 namespace app_list { 15 namespace app_list {
16 16
17 namespace { 17 namespace {
18 18
19 // Maximum number of results to show. 19 // Maximum number of results to show.
20 const size_t kMaxResults = 6; 20 const size_t kMaxResults = 6;
21 const size_t kMaxMainGroupResults = 4; 21 const size_t kMaxMainGroupResults = 4;
22 const size_t kMaxWebstoreResults = 2; 22 const size_t kMaxWebstoreResults = 2;
23 const size_t kMaxPeopleResults = 2; 23 const size_t kMaxPeopleResults = 2;
24 24
25 // A value to indicate no max number of results limit. 25 // A value to indicate no max number of results limit.
26 const size_t kNoMaxResultsLimit = 0; 26 const size_t kNoMaxResultsLimit = 0;
27 27
28 void UpdateResult(const ChromeSearchResult& source,
29 ChromeSearchResult* target) {
30 target->set_title(source.title());
31 target->set_title_tags(source.title_tags());
32 target->set_details(source.details());
33 target->set_details_tags(source.details_tags());
34 }
35
28 } // namespace 36 } // namespace
29 37
30 Mixer::SortData::SortData() : result(NULL), score(0.0) { 38 Mixer::SortData::SortData() : result(NULL), score(0.0) {
31 } 39 }
32 40
33 Mixer::SortData::SortData(ChromeSearchResult* result, double score) 41 Mixer::SortData::SortData(ChromeSearchResult* result, double score)
34 : result(result), score(score) { 42 : result(result), score(score) {
35 } 43 }
36 44
37 bool Mixer::SortData::operator<(const SortData& other) const { 45 bool Mixer::SortData::operator<(const SortData& other) const {
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
164 groups_[OMNIBOX_GROUP]->results().begin() + remaining_slots); 172 groups_[OMNIBOX_GROUP]->results().begin() + remaining_slots);
165 173
166 std::sort(results.begin(), results.end()); 174 std::sort(results.begin(), results.end());
167 RemoveDuplicates(&results); 175 RemoveDuplicates(&results);
168 if (results.size() > kMaxResults) 176 if (results.size() > kMaxResults)
169 results.resize(kMaxResults); 177 results.resize(kMaxResults);
170 178
171 Publish(results, ui_results_); 179 Publish(results, ui_results_);
172 } 180 }
173 181
174 void Mixer::Publish(const SortedResults& results, 182 // The following algorithm is used:
Matt Giuca 2014/07/09 01:30:54 nit: Move this comment inside the function braces
calamity 2014/07/09 03:03:48 Done.
183 // 1. Transform the |ui_results| list into an unordered map from result ID
184 // to item.
185 // 2. Use the order of items in |new_results| to build an ordered list. If the
186 // result IDs exist in the map, update and use the item in the map and delete
187 // it from the map afterwards. Otherwise, clone new items from |new_results|.
188 // 3. Delete the objects remaining in the map as they are unused.
189 void Mixer::Publish(const SortedResults& new_results,
175 AppListModel::SearchResults* ui_results) { 190 AppListModel::SearchResults* ui_results) {
176 for (size_t i = 0; i < results.size(); ++i) { 191 typedef std::map<std::string, ChromeSearchResult*> IdToResultMap;
177 ChromeSearchResult* result = results[i].result;
178 192
193 // A map of the items in |ui_results| that takes ownership of the items.
194 IdToResultMap ui_results_map;
195 for (size_t i = 0; i < ui_results->item_count(); ++i) {
179 ChromeSearchResult* ui_result = 196 ChromeSearchResult* ui_result =
180 i < ui_results->item_count() 197 static_cast<ChromeSearchResult*>(ui_results->GetItemAt(i));
181 ? static_cast<ChromeSearchResult*>(ui_results->GetItemAt(i)) 198 ui_results_map[ui_result->id()] = ui_result;
182 : NULL; 199 }
183 if (ui_result && ui_result->id() == result->id()) { 200 // We have to erase all results at once so that observers are notified with
184 ui_result->set_title(result->title()); 201 // meaningful indexes.
185 ui_result->set_title_tags(result->title_tags()); 202 ui_results->RemoveAll();
186 ui_result->set_details(result->details()); 203
187 ui_result->set_details_tags(result->details_tags()); 204 // Add items back to |ui_results| in the order of |new_results|.
188 ui_results->NotifyItemsChanged(i, 1); 205 for (size_t i = 0; i < new_results.size(); ++i) {
206 ChromeSearchResult* new_result = new_results[i].result;
207 IdToResultMap::const_iterator ui_result_it =
208 ui_results_map.find(new_result->id());
209 if (ui_result_it != ui_results_map.end()) {
210 // Update and use the old result if it exists.
211 ChromeSearchResult* ui_result = ui_result_it->second;
212 UpdateResult(*new_result, ui_result);
213
214 // |ui_results| takes back ownership from |ui_results_map| here.
215 ui_results->Add(ui_result);
216
217 // Remove the item from the map so that it ends up only with unused
218 // results.
219 ui_results_map.erase(ui_result_it);
189 } else { 220 } else {
190 if (ui_result) 221 // Copy the result from |new_results| otherwise.
191 ui_results->DeleteAt(i); 222 ui_results->Add(new_result->Duplicate().release());
192 ui_results->AddAt(i, result->Duplicate().release());
193 } 223 }
194 } 224 }
195 225
196 while (ui_results->item_count() > results.size()) 226 // Delete the results remaining in the map as they are not in the new results.
197 ui_results->DeleteAt(ui_results->item_count() - 1); 227 for (IdToResultMap::const_iterator ui_result_it = ui_results_map.begin();
228 ui_result_it != ui_results_map.end();
229 ++ui_result_it) {
230 delete ui_result_it->second;
231 }
198 } 232 }
199 233
200 void Mixer::RemoveDuplicates(SortedResults* results) { 234 void Mixer::RemoveDuplicates(SortedResults* results) {
201 SortedResults final; 235 SortedResults final;
202 final.reserve(results->size()); 236 final.reserve(results->size());
203 237
204 std::set<std::string> id_set; 238 std::set<std::string> id_set;
205 for (SortedResults::iterator it = results->begin(); it != results->end(); 239 for (SortedResults::iterator it = results->begin(); it != results->end();
206 ++it) { 240 ++it) {
207 const std::string& id = it->result->id(); 241 const std::string& id = it->result->id();
208 if (id_set.find(id) != id_set.end()) 242 if (id_set.find(id) != id_set.end())
209 continue; 243 continue;
210 244
211 id_set.insert(id); 245 id_set.insert(id);
212 final.push_back(*it); 246 final.push_back(*it);
213 } 247 }
214 248
215 results->swap(final); 249 results->swap(final);
216 } 250 }
217 251
218 void Mixer::FetchResults(const KnownResults& known_results) { 252 void Mixer::FetchResults(const KnownResults& known_results) {
219 for (Groups::iterator group_it = groups_.begin(); 253 for (Groups::iterator group_it = groups_.begin();
220 group_it != groups_.end(); 254 group_it != groups_.end();
221 ++group_it) { 255 ++group_it) {
222 (*group_it)->FetchResults(known_results); 256 (*group_it)->FetchResults(known_results);
223 } 257 }
224 } 258 }
225 259
226 } // namespace app_list 260 } // namespace app_list
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698