1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
|
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/omnibox/browser/autocomplete_grouper_groups.h"
#include <algorithm>
#include "base/check.h"
#include "base/containers/contains.h"
#include "base/containers/flat_map.h"
#include "components/omnibox/browser/autocomplete_match.h"
#include "third_party/omnibox_proto/groups.pb.h"
namespace {
constexpr bool is_android = !!BUILDFLAG(IS_ANDROID);
} // namespace
Group::Group(size_t limit,
std::map<omnibox::GroupId, size_t> group_id_limits,
bool is_zps,
bool is_default)
: limit_(limit), is_zps_(is_zps), is_default_(is_default) {
for (const auto& [group_id, group_id_limit] : group_id_limits) {
group_id_limits_and_counts_[group_id] = {.limit = group_id_limit,
.count = 0};
}
}
Group::Group(const Group& group) = default;
Group& Group::operator=(const Group& group) = default;
Group::~Group() = default;
bool Group::CanAdd(const AutocompleteMatch& match) const {
DCHECK(match.suggestion_group_id.has_value());
const auto group_id = match.suggestion_group_id.value();
// Check if `group_id` is permitted in this `Group`.
if (!base::Contains(group_id_limits_and_counts_, group_id)) {
return false;
}
const auto& limit_and_count = group_id_limits_and_counts_.at(group_id);
// Check this `Group`'s total limit and the limit for the `group_id`. For a
// default group, also check if the match is `allowed_to_be_default_match`.
return count_ < limit_ && limit_and_count.count < limit_and_count.limit &&
(!is_default_ || match.allowed_to_be_default_match);
}
void Group::Add(const AutocompleteMatch& match) {
DCHECK(CanAdd(match));
matches_.push_back(&const_cast<AutocompleteMatch&>(match));
count_++;
DCHECK_EQ(count_, matches_.size());
group_id_limits_and_counts_[match.suggestion_group_id.value()].count++;
}
void Group::GroupMatches() {
if (is_zps_) {
GroupMatchesByGroupId();
} else if (is_android) {
GroupMatchesBySearchVsUrl();
}
}
void Group::GroupMatchesBySearchVsUrl() {
std::ranges::stable_sort(matches_.begin(), matches_.end(), {},
[](const auto& m) { return m->GetSortingOrder(); });
}
void Group::GroupMatchesByGroupId() {
// Assign a position to each GroupId based on its first occurrence in the list
// of matches and perform a stable sort to group matches by their GroupId
// while preserving the relative order of matches within the same GroupId.
base::flat_map<omnibox::GroupId, size_t> group_id_position;
size_t position = 0;
for (const auto& match : matches_) {
auto group_id = match->suggestion_group_id.value();
if (!base::Contains(group_id_position, group_id)) {
group_id_position[group_id] = position++;
}
}
std::stable_sort(
matches_.begin(), matches_.end(), [&](const auto& lhs, const auto& rhs) {
return group_id_position[lhs->suggestion_group_id.value()] <
group_id_position[rhs->suggestion_group_id.value()];
});
}
|