1*a03ca8b9SKrzysztof Kosiński // Copyright 2016 The Chromium Authors. All rights reserved.
2*a03ca8b9SKrzysztof Kosiński // Use of this source code is governed by a BSD-style license that can be
3*a03ca8b9SKrzysztof Kosiński // found in the LICENSE file.
4*a03ca8b9SKrzysztof Kosiński
5*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/targets_affinity.h"
6*a03ca8b9SKrzysztof Kosiński
7*a03ca8b9SKrzysztof Kosiński #include <algorithm>
8*a03ca8b9SKrzysztof Kosiński
9*a03ca8b9SKrzysztof Kosiński #include "base/check_op.h"
10*a03ca8b9SKrzysztof Kosiński #include "components/zucchini/equivalence_map.h"
11*a03ca8b9SKrzysztof Kosiński
12*a03ca8b9SKrzysztof Kosiński namespace zucchini {
13*a03ca8b9SKrzysztof Kosiński
14*a03ca8b9SKrzysztof Kosiński namespace {
15*a03ca8b9SKrzysztof Kosiński
16*a03ca8b9SKrzysztof Kosiński constexpr uint32_t kNoLabel = 0;
17*a03ca8b9SKrzysztof Kosiński }
18*a03ca8b9SKrzysztof Kosiński
19*a03ca8b9SKrzysztof Kosiński TargetsAffinity::TargetsAffinity() = default;
20*a03ca8b9SKrzysztof Kosiński TargetsAffinity::~TargetsAffinity() = default;
21*a03ca8b9SKrzysztof Kosiński
InferFromSimilarities(const EquivalenceMap & equivalences,const std::deque<offset_t> & old_targets,const std::deque<offset_t> & new_targets)22*a03ca8b9SKrzysztof Kosiński void TargetsAffinity::InferFromSimilarities(
23*a03ca8b9SKrzysztof Kosiński const EquivalenceMap& equivalences,
24*a03ca8b9SKrzysztof Kosiński const std::deque<offset_t>& old_targets,
25*a03ca8b9SKrzysztof Kosiński const std::deque<offset_t>& new_targets) {
26*a03ca8b9SKrzysztof Kosiński forward_association_.assign(old_targets.size(), {});
27*a03ca8b9SKrzysztof Kosiński backward_association_.assign(new_targets.size(), {});
28*a03ca8b9SKrzysztof Kosiński
29*a03ca8b9SKrzysztof Kosiński if (old_targets.empty() || new_targets.empty())
30*a03ca8b9SKrzysztof Kosiński return;
31*a03ca8b9SKrzysztof Kosiński
32*a03ca8b9SKrzysztof Kosiński key_t new_key = 0;
33*a03ca8b9SKrzysztof Kosiński for (auto candidate : equivalences) { // Sorted by |dst_offset|.
34*a03ca8b9SKrzysztof Kosiński DCHECK_GT(candidate.similarity, 0.0);
35*a03ca8b9SKrzysztof Kosiński while (new_key < new_targets.size() &&
36*a03ca8b9SKrzysztof Kosiński new_targets[new_key] < candidate.eq.dst_offset) {
37*a03ca8b9SKrzysztof Kosiński ++new_key;
38*a03ca8b9SKrzysztof Kosiński }
39*a03ca8b9SKrzysztof Kosiński
40*a03ca8b9SKrzysztof Kosiński // Visit each new target covered by |candidate.eq| and find / update its
41*a03ca8b9SKrzysztof Kosiński // associated old target.
42*a03ca8b9SKrzysztof Kosiński for (; new_key < new_targets.size() &&
43*a03ca8b9SKrzysztof Kosiński new_targets[new_key] < candidate.eq.dst_end();
44*a03ca8b9SKrzysztof Kosiński ++new_key) {
45*a03ca8b9SKrzysztof Kosiński if (backward_association_[new_key].affinity >= candidate.similarity)
46*a03ca8b9SKrzysztof Kosiński continue;
47*a03ca8b9SKrzysztof Kosiński
48*a03ca8b9SKrzysztof Kosiński DCHECK_GE(new_targets[new_key], candidate.eq.dst_offset);
49*a03ca8b9SKrzysztof Kosiński offset_t old_target = new_targets[new_key] - candidate.eq.dst_offset +
50*a03ca8b9SKrzysztof Kosiński candidate.eq.src_offset;
51*a03ca8b9SKrzysztof Kosiński auto old_it =
52*a03ca8b9SKrzysztof Kosiński std::lower_bound(old_targets.begin(), old_targets.end(), old_target);
53*a03ca8b9SKrzysztof Kosiński // If new target can be mapped via |candidate.eq| to an old target, then
54*a03ca8b9SKrzysztof Kosiński // attempt to associate them. Multiple new targets can compete for the
55*a03ca8b9SKrzysztof Kosiński // same old target. The heuristic here makes selections to maximize
56*a03ca8b9SKrzysztof Kosiński // |candidate.similarity|, and if a tie occurs, minimize new target offset
57*a03ca8b9SKrzysztof Kosiński // (by first-come, first-served).
58*a03ca8b9SKrzysztof Kosiński if (old_it != old_targets.end() && *old_it == old_target) {
59*a03ca8b9SKrzysztof Kosiński key_t old_key = static_cast<key_t>(old_it - old_targets.begin());
60*a03ca8b9SKrzysztof Kosiński if (candidate.similarity > forward_association_[old_key].affinity) {
61*a03ca8b9SKrzysztof Kosiński // Reset other associations.
62*a03ca8b9SKrzysztof Kosiński if (forward_association_[old_key].affinity > 0.0)
63*a03ca8b9SKrzysztof Kosiński backward_association_[forward_association_[old_key].other] = {};
64*a03ca8b9SKrzysztof Kosiński if (backward_association_[new_key].affinity > 0.0)
65*a03ca8b9SKrzysztof Kosiński forward_association_[backward_association_[new_key].other] = {};
66*a03ca8b9SKrzysztof Kosiński // Assign new association.
67*a03ca8b9SKrzysztof Kosiński forward_association_[old_key] = {new_key, candidate.similarity};
68*a03ca8b9SKrzysztof Kosiński backward_association_[new_key] = {old_key, candidate.similarity};
69*a03ca8b9SKrzysztof Kosiński }
70*a03ca8b9SKrzysztof Kosiński }
71*a03ca8b9SKrzysztof Kosiński }
72*a03ca8b9SKrzysztof Kosiński }
73*a03ca8b9SKrzysztof Kosiński }
74*a03ca8b9SKrzysztof Kosiński
AssignLabels(double min_affinity,std::vector<uint32_t> * old_labels,std::vector<uint32_t> * new_labels)75*a03ca8b9SKrzysztof Kosiński uint32_t TargetsAffinity::AssignLabels(double min_affinity,
76*a03ca8b9SKrzysztof Kosiński std::vector<uint32_t>* old_labels,
77*a03ca8b9SKrzysztof Kosiński std::vector<uint32_t>* new_labels) {
78*a03ca8b9SKrzysztof Kosiński old_labels->assign(forward_association_.size(), kNoLabel);
79*a03ca8b9SKrzysztof Kosiński new_labels->assign(backward_association_.size(), kNoLabel);
80*a03ca8b9SKrzysztof Kosiński
81*a03ca8b9SKrzysztof Kosiński uint32_t label = kNoLabel + 1;
82*a03ca8b9SKrzysztof Kosiński for (key_t old_key = 0; old_key < forward_association_.size(); ++old_key) {
83*a03ca8b9SKrzysztof Kosiński Association association = forward_association_[old_key];
84*a03ca8b9SKrzysztof Kosiński if (association.affinity >= min_affinity) {
85*a03ca8b9SKrzysztof Kosiński (*old_labels)[old_key] = label;
86*a03ca8b9SKrzysztof Kosiński DCHECK_EQ(0U, (*new_labels)[association.other]);
87*a03ca8b9SKrzysztof Kosiński (*new_labels)[association.other] = label;
88*a03ca8b9SKrzysztof Kosiński ++label;
89*a03ca8b9SKrzysztof Kosiński }
90*a03ca8b9SKrzysztof Kosiński }
91*a03ca8b9SKrzysztof Kosiński return label;
92*a03ca8b9SKrzysztof Kosiński }
93*a03ca8b9SKrzysztof Kosiński
AffinityBetween(key_t old_key,key_t new_key) const94*a03ca8b9SKrzysztof Kosiński double TargetsAffinity::AffinityBetween(key_t old_key, key_t new_key) const {
95*a03ca8b9SKrzysztof Kosiński DCHECK_LT(old_key, forward_association_.size());
96*a03ca8b9SKrzysztof Kosiński DCHECK_LT(new_key, backward_association_.size());
97*a03ca8b9SKrzysztof Kosiński if (forward_association_[old_key].affinity > 0.0 &&
98*a03ca8b9SKrzysztof Kosiński forward_association_[old_key].other == new_key) {
99*a03ca8b9SKrzysztof Kosiński DCHECK_EQ(backward_association_[new_key].other, old_key);
100*a03ca8b9SKrzysztof Kosiński DCHECK_EQ(forward_association_[old_key].affinity,
101*a03ca8b9SKrzysztof Kosiński backward_association_[new_key].affinity);
102*a03ca8b9SKrzysztof Kosiński return forward_association_[old_key].affinity;
103*a03ca8b9SKrzysztof Kosiński }
104*a03ca8b9SKrzysztof Kosiński return -std::max(forward_association_[old_key].affinity,
105*a03ca8b9SKrzysztof Kosiński backward_association_[new_key].affinity);
106*a03ca8b9SKrzysztof Kosiński }
107*a03ca8b9SKrzysztof Kosiński
108*a03ca8b9SKrzysztof Kosiński } // namespace zucchini
109