| Index: chrome/browser/ui/app_list/search/app_search_provider.cc
|
| diff --git a/chrome/browser/ui/app_list/search/app_search_provider.cc b/chrome/browser/ui/app_list/search/app_search_provider.cc
|
| index 9f0642c82ee9ac4ed111e002f1b09c46b47c2d7b..6e8066094315a62df81d79a3496a8c5772cab74b 100644
|
| --- a/chrome/browser/ui/app_list/search/app_search_provider.cc
|
| +++ b/chrome/browser/ui/app_list/search/app_search_provider.cc
|
| @@ -44,7 +44,11 @@ using extensions::ExtensionRegistry;
|
| namespace {
|
|
|
| // The size of each step unlaunched apps should increase their relevance by.
|
| -const double kUnlaunchedAppRelevanceStepSize = 0.0001;
|
| +constexpr double kUnlaunchedAppRelevanceStepSize = 0.0001;
|
| +
|
| +// The minimum capacity we reserve in the Apps container which will be filled
|
| +// with extensions and ARC apps, to avoid successive reallocation.
|
| +constexpr size_t kMinimumReservedAppsContainerCapacity = 60U;
|
| }
|
|
|
| namespace app_list {
|
| @@ -58,21 +62,31 @@ class AppSearchProvider::App {
|
| const base::Time& install_time)
|
| : data_source_(data_source),
|
| id_(id),
|
| - indexed_name_(base::UTF8ToUTF16(name)),
|
| + name_(base::UTF8ToUTF16(name)),
|
| last_launch_time_(last_launch_time),
|
| install_time_(install_time) {}
|
| ~App() {}
|
|
|
| + TokenizedString* GetTokenizedIndexedName() {
|
| + // Tokenizing a string is expensive. Don't pay the price for it at
|
| + // construction of every App, but rather, only when needed (i.e. when the
|
| + // query is not empty and cache the result.
|
| + if (!tokenized_indexed_name_)
|
| + tokenized_indexed_name_ = base::MakeUnique<TokenizedString>(name_);
|
| + return tokenized_indexed_name_.get();
|
| + }
|
| +
|
| AppSearchProvider::DataSource* data_source() { return data_source_; }
|
| const std::string& id() const { return id_; }
|
| - const TokenizedString& indexed_name() const { return indexed_name_; }
|
| + const base::string16& name() const { return name_; }
|
| const base::Time& last_launch_time() const { return last_launch_time_; }
|
| const base::Time& install_time() const { return install_time_; }
|
|
|
| private:
|
| AppSearchProvider::DataSource* data_source_;
|
| + std::unique_ptr<TokenizedString> tokenized_indexed_name_;
|
| const std::string id_;
|
| - const TokenizedString indexed_name_;
|
| + const base::string16 name_;
|
| const base::Time last_launch_time_;
|
| const base::Time install_time_;
|
|
|
| @@ -131,8 +145,8 @@ class ExtensionDataSource : public AppSearchProvider::DataSource,
|
| AppListControllerDelegate* list_controller,
|
| AppListItemList* top_level_item_list,
|
| bool is_recommended) override {
|
| - return std::unique_ptr<AppResult>(new ExtensionAppResult(
|
| - profile(), app_id, list_controller, is_recommended));
|
| + return base::MakeUnique<ExtensionAppResult>(
|
| + profile(), app_id, list_controller, is_recommended);
|
| }
|
|
|
| // extensions::ExtensionRegistryObserver overrides:
|
| @@ -165,11 +179,10 @@ class ExtensionDataSource : public AppSearchProvider::DataSource,
|
| continue;
|
| }
|
|
|
| - std::unique_ptr<AppSearchProvider::App> app(new AppSearchProvider::App(
|
| + apps->emplace_back(base::MakeUnique<AppSearchProvider::App>(
|
| this, extension->id(), extension->short_name(),
|
| prefs->GetLastLaunchTime(extension->id()),
|
| prefs->GetInstallTime(extension->id())));
|
| - apps->push_back(std::move(app));
|
| }
|
| }
|
|
|
| @@ -210,10 +223,9 @@ class ArcDataSource : public AppSearchProvider::DataSource,
|
| if (!app_info->launchable || !app_info->showInLauncher)
|
| continue;
|
|
|
| - std::unique_ptr<AppSearchProvider::App> app(new AppSearchProvider::App(
|
| + apps->emplace_back(base::MakeUnique<AppSearchProvider::App>(
|
| this, app_id, app_info->name, app_info->last_launch_time,
|
| app_info->install_time));
|
| - apps->push_back(std::move(app));
|
| }
|
| }
|
|
|
| @@ -222,8 +234,8 @@ class ArcDataSource : public AppSearchProvider::DataSource,
|
| AppListControllerDelegate* list_controller,
|
| AppListItemList* top_level_item_list,
|
| bool is_recommended) override {
|
| - return std::unique_ptr<AppResult>(
|
| - new ArcAppResult(profile(), app_id, list_controller, is_recommended));
|
| + return base::MakeUnique<ArcAppResult>(profile(), app_id, list_controller,
|
| + is_recommended);
|
| }
|
|
|
| // ArcAppListPrefs::Observer overrides:
|
| @@ -256,16 +268,12 @@ AppSearchProvider::AppSearchProvider(Profile* profile,
|
| top_level_item_list_(top_level_item_list),
|
| clock_(std::move(clock)),
|
| update_results_factory_(this) {
|
| - data_sources_.push_back(
|
| - std::unique_ptr<DataSource>(new ExtensionDataSource(profile, this)));
|
| + data_sources_.emplace_back(
|
| + base::MakeUnique<ExtensionDataSource>(profile, this));
|
| #if defined(OS_CHROMEOS)
|
| - if (arc::IsArcAllowedForProfile(profile)) {
|
| - data_sources_.push_back(
|
| - std::unique_ptr<DataSource>(new ArcDataSource(profile, this)));
|
| - }
|
| + if (arc::IsArcAllowedForProfile(profile))
|
| + data_sources_.emplace_back(base::MakeUnique<ArcDataSource>(profile, this));
|
| #endif
|
| -
|
| - RefreshApps();
|
| }
|
|
|
| AppSearchProvider::~AppSearchProvider() {}
|
| @@ -273,12 +281,10 @@ AppSearchProvider::~AppSearchProvider() {}
|
| void AppSearchProvider::Start(bool /*is_voice_query*/,
|
| const base::string16& query) {
|
| query_ = query;
|
| - ClearResults();
|
| -
|
| - bool show_recommendations = query.empty();
|
| + const bool show_recommendations = query.empty();
|
| // Refresh list of apps to ensure we have the latest launch time information.
|
| // This will also cause the results to update.
|
| - if (show_recommendations)
|
| + if (show_recommendations || apps_.empty())
|
| RefreshApps();
|
|
|
| UpdateResults();
|
| @@ -289,27 +295,29 @@ void AppSearchProvider::Stop() {
|
|
|
| void AppSearchProvider::RefreshApps() {
|
| apps_.clear();
|
| - for (auto& data_source : data_sources_) {
|
| + apps_.reserve(kMinimumReservedAppsContainerCapacity);
|
| + for (auto& data_source : data_sources_)
|
| data_source->AddApps(&apps_);
|
| - }
|
| }
|
|
|
| void AppSearchProvider::UpdateResults() {
|
| - const TokenizedString query_terms(query_);
|
| - bool show_recommendations = query_.empty();
|
| - ClearResults();
|
| + const bool show_recommendations = query_.empty();
|
|
|
| + // No need to clear the current results as we will swap them with
|
| + // |new_results| at the end.
|
| + SearchProvider::Results new_results;
|
| + const size_t apps_size = apps_.size();
|
| + new_results.reserve(apps_size);
|
| if (show_recommendations) {
|
| // Build a map of app ids to their position in the app list.
|
| std::map<std::string, size_t> id_to_app_list_index;
|
| - for (size_t i = 0; i < top_level_item_list_->item_count(); ++i) {
|
| + for (size_t i = 0; i < top_level_item_list_->item_count(); ++i)
|
| id_to_app_list_index[top_level_item_list_->item_at(i)->id()] = i;
|
| - }
|
|
|
| for (auto& app : apps_) {
|
| std::unique_ptr<AppResult> result = app->data_source()->CreateResult(
|
| app->id(), list_controller_, top_level_item_list_, true);
|
| - result->set_title(app->indexed_name().text());
|
| + result->set_title(app->name());
|
|
|
| // Use the app list order to tiebreak apps that have never been launched.
|
| // The apps that have been installed or launched recently should be
|
| @@ -318,34 +326,37 @@ void AppSearchProvider::UpdateResults() {
|
| ? app->install_time()
|
| : app->last_launch_time();
|
| if (time.is_null()) {
|
| - auto it = id_to_app_list_index.find(app->id());
|
| + const auto& it = id_to_app_list_index.find(app->id());
|
| // If it's in a folder, it won't be in |id_to_app_list_index|. Rank
|
| // those as if they are at the end of the list.
|
| - size_t app_list_index =
|
| - it == id_to_app_list_index.end() ? apps_.size() : (*it).second;
|
| - if (app_list_index > apps_.size())
|
| - app_list_index = apps_.size();
|
| + const size_t app_list_index = (it == id_to_app_list_index.end())
|
| + ? apps_size
|
| + : std::min(apps_size, it->second);
|
|
|
| result->set_relevance(kUnlaunchedAppRelevanceStepSize *
|
| - (apps_.size() - app_list_index));
|
| + (apps_size - app_list_index));
|
| } else {
|
| result->UpdateFromLastLaunchedOrInstalledTime(clock_->Now(), time);
|
| }
|
| - Add(std::move(result));
|
| + new_results.emplace_back(std::move(result));
|
| }
|
| } else {
|
| + const TokenizedString query_terms(query_);
|
| for (auto& app : apps_) {
|
| std::unique_ptr<AppResult> result = app->data_source()->CreateResult(
|
| app->id(), list_controller_, top_level_item_list_, false);
|
| TokenizedStringMatch match;
|
| - if (!match.Calculate(query_terms, app->indexed_name()))
|
| + TokenizedString* indexed_name = app->GetTokenizedIndexedName();
|
| + if (!match.Calculate(query_terms, *indexed_name))
|
| continue;
|
|
|
| - result->UpdateFromMatch(app->indexed_name(), match);
|
| - Add(std::move(result));
|
| + result->UpdateFromMatch(*indexed_name, match);
|
| + new_results.emplace_back(std::move(result));
|
| }
|
| }
|
|
|
| + SwapResults(&new_results);
|
| +
|
| update_results_factory_.InvalidateWeakPtrs();
|
| }
|
|
|
|
|