[Zucchini] Use TargetsAffinity for target association.

This CL brings changes in ImageIndex to use target affinities
and to avoid mutation of ImageIndex. Mainly:

- ImageIndex becomes immutable after initialization.
- LabelTargets()/LabelAssociatedTargets()/UnlabelTargets() are
  removed.
- EncodedView uses labels directly to compute Projection(), using
  lookups in a label table.
  - Introduce EncodedView::PoolInfo to hold data.

Note that LabelManager is still being used to minimize changes, even
though most of its functionality are stripped down. It will be
remove as a follow-up CL (627188) that simplifies reference delta.

Bug: 760614
Change-Id: Ia8aaa7e5f287480c987d65a5dc24b01e7d1622dd
Reviewed-on: https://chromium-review.googlesource.com/630558
Commit-Queue: Etienne Pierre-Doray <[email protected]>
Reviewed-by: Samuel Huang <[email protected]>
Cr-Commit-Position: refs/heads/master@{#527986}
diff --git a/chrome/installer/zucchini/equivalence_map.cc b/chrome/installer/zucchini/equivalence_map.cc
index fb9ad26..da585ea4 100644
--- a/chrome/installer/zucchini/equivalence_map.cc
+++ b/chrome/installer/zucchini/equivalence_map.cc
@@ -14,10 +14,12 @@
 
 /******** Utility Functions ********/
 
-double GetTokenSimilarity(const ImageIndex& old_image_index,
-                          const ImageIndex& new_image_index,
-                          offset_t src,
-                          offset_t dst) {
+double GetTokenSimilarity(
+    const ImageIndex& old_image_index,
+    const ImageIndex& new_image_index,
+    const std::vector<TargetsAffinity>& targets_affinities,
+    offset_t src,
+    offset_t dst) {
   DCHECK(old_image_index.IsToken(src));
   DCHECK(new_image_index.IsToken(dst));
 
@@ -37,23 +39,24 @@
   const ReferenceSet& new_ref_set = new_image_index.refs(new_type);
   IndirectReference old_reference = old_ref_set.at(src);
   IndirectReference new_reference = new_ref_set.at(dst);
+  PoolTag pool_tag = old_ref_set.pool_tag();
 
-  offset_t old_target =
-      old_ref_set.target_pool().OffsetForKey(old_reference.target_key);
-  offset_t new_target =
-      new_ref_set.target_pool().OffsetForKey(new_reference.target_key);
+  double affinity = targets_affinities[pool_tag.value()].AffinityBetween(
+      old_reference.target_key, new_reference.target_key);
 
   // Both targets are not associated, which implies a weak match.
-  if (!IsMarked(old_target) && !IsMarked(new_target))
+  if (affinity == 0.0)
     return 0.5 * old_ref_set.width();
 
   // At least one target is associated, so values are compared.
-  return old_target == new_target ? old_ref_set.width() : -2.0;
+  return affinity > 0.0 ? old_ref_set.width() : -2.0;
 }
 
-double GetEquivalenceSimilarity(const ImageIndex& old_image_index,
-                                const ImageIndex& new_image_index,
-                                const Equivalence& equivalence) {
+double GetEquivalenceSimilarity(
+    const ImageIndex& old_image_index,
+    const ImageIndex& new_image_index,
+    const std::vector<TargetsAffinity>& targets_affinities,
+    const Equivalence& equivalence) {
   double similarity = 0.0;
   for (offset_t k = 0; k < equivalence.length; ++k) {
     // Non-tokens are joined with the nearest previous token: skip until we
@@ -61,9 +64,9 @@
     if (!new_image_index.IsToken(equivalence.dst_offset + k))
       continue;
 
-    similarity += GetTokenSimilarity(old_image_index, new_image_index,
-                                     equivalence.src_offset + k,
-                                     equivalence.dst_offset + k);
+    similarity += GetTokenSimilarity(
+        old_image_index, new_image_index, targets_affinities,
+        equivalence.src_offset + k, equivalence.dst_offset + k);
     if (similarity == kMismatchFatal)
       return kMismatchFatal;
   }
@@ -73,6 +76,7 @@
 EquivalenceCandidate ExtendEquivalenceForward(
     const ImageIndex& old_image_index,
     const ImageIndex& new_image_index,
+    const std::vector<TargetsAffinity>& targets_affinities,
     const EquivalenceCandidate& candidate,
     double min_similarity) {
   Equivalence equivalence = candidate.eq;
@@ -98,9 +102,9 @@
       continue;
     }
 
-    double similarity = GetTokenSimilarity(old_image_index, new_image_index,
-                                           equivalence.src_offset + k,
-                                           equivalence.dst_offset + k);
+    double similarity = GetTokenSimilarity(
+        old_image_index, new_image_index, targets_affinities,
+        equivalence.src_offset + k, equivalence.dst_offset + k);
     current_similarity += similarity;
     current_penalty = std::max(0.0, current_penalty) - similarity;
 
@@ -118,6 +122,7 @@
 EquivalenceCandidate ExtendEquivalenceBackward(
     const ImageIndex& old_image_index,
     const ImageIndex& new_image_index,
+    const std::vector<TargetsAffinity>& targets_affinities,
     const EquivalenceCandidate& candidate,
     double min_similarity) {
   Equivalence equivalence = candidate.eq;
@@ -141,9 +146,10 @@
     DCHECK_EQ(old_image_index.LookupType(equivalence.src_offset - k),
               new_image_index.LookupType(equivalence.dst_offset -
                                          k));  // Sanity check.
-    double similarity = GetTokenSimilarity(old_image_index, new_image_index,
-                                           equivalence.src_offset - k,
-                                           equivalence.dst_offset - k);
+    double similarity = GetTokenSimilarity(
+        old_image_index, new_image_index, targets_affinities,
+        equivalence.src_offset - k, equivalence.dst_offset - k);
+
     current_similarity += similarity;
     current_penalty = std::max(0.0, current_penalty) - similarity;
 
@@ -161,17 +167,23 @@
   return {equivalence, best_similarity};
 }
 
-EquivalenceCandidate VisitEquivalenceSeed(const ImageIndex& old_image_index,
-                                          const ImageIndex& new_image_index,
-                                          offset_t src,
-                                          offset_t dst,
-                                          double min_similarity) {
+EquivalenceCandidate VisitEquivalenceSeed(
+    const ImageIndex& old_image_index,
+    const ImageIndex& new_image_index,
+    const std::vector<TargetsAffinity>& targets_affinities,
+    offset_t src,
+    offset_t dst,
+    double min_similarity) {
   EquivalenceCandidate candidate{{src, dst, 0}, 0.0};  // Empty.
-  candidate = ExtendEquivalenceForward(old_image_index, new_image_index,
-                                       candidate, min_similarity);
+  if (!old_image_index.IsToken(src))
+    return candidate;
+  candidate =
+      ExtendEquivalenceForward(old_image_index, new_image_index,
+                               targets_affinities, candidate, min_similarity);
   if (candidate.similarity < min_similarity)
     return candidate;  // Not worth exploring any more.
-  return ExtendEquivalenceBackward(old_image_index, new_image_index, candidate,
+  return ExtendEquivalenceBackward(old_image_index, new_image_index,
+                                   targets_affinities, candidate,
                                    min_similarity);
 }
 
@@ -189,15 +201,18 @@
 
 EquivalenceMap::~EquivalenceMap() = default;
 
-void EquivalenceMap::Build(const std::vector<offset_t>& old_sa,
-                           const EncodedView& old_view,
-                           const EncodedView& new_view,
-                           double min_similarity) {
+void EquivalenceMap::Build(
+    const std::vector<offset_t>& old_sa,
+    const EncodedView& old_view,
+    const EncodedView& new_view,
+    const std::vector<TargetsAffinity>& targets_affinities,
+    double min_similarity) {
   DCHECK_EQ(old_sa.size(), old_view.size());
 
-  CreateCandidates(old_sa, old_view, new_view, min_similarity);
+  CreateCandidates(old_sa, old_view, new_view, targets_affinities,
+                   min_similarity);
   SortByDestination();
-  Prune(old_view, new_view, min_similarity);
+  Prune(old_view, new_view, targets_affinities, min_similarity);
 
   offset_t coverage = 0;
   offset_t current_offset = 0;
@@ -222,10 +237,12 @@
   return equivalences;
 }
 
-void EquivalenceMap::CreateCandidates(const std::vector<offset_t>& old_sa,
-                                      const EncodedView& old_view,
-                                      const EncodedView& new_view,
-                                      double min_similarity) {
+void EquivalenceMap::CreateCandidates(
+    const std::vector<offset_t>& old_sa,
+    const EncodedView& old_view,
+    const EncodedView& new_view,
+    const std::vector<TargetsAffinity>& targets_affinities,
+    double min_similarity) {
   candidates_.clear();
 
   // This is an heuristic to find 'good' equivalences on encoded views.
@@ -247,7 +264,7 @@
     EquivalenceCandidate best_candidate = {{0, 0, 0}, 0.0};
     for (auto it = match; it != old_sa.end(); ++it) {
       EquivalenceCandidate candidate = VisitEquivalenceSeed(
-          old_view.image_index(), new_view.image_index(),
+          old_view.image_index(), new_view.image_index(), targets_affinities,
           static_cast<offset_t>(*it), dst_offset, min_similarity);
       if (candidate.similarity > best_similarity) {
         best_candidate = candidate;
@@ -259,7 +276,7 @@
     }
     for (auto it = match; it != old_sa.begin(); --it) {
       EquivalenceCandidate candidate = VisitEquivalenceSeed(
-          old_view.image_index(), new_view.image_index(),
+          old_view.image_index(), new_view.image_index(), targets_affinities,
           static_cast<offset_t>(it[-1]), dst_offset, min_similarity);
       if (candidate.similarity > best_similarity) {
         best_candidate = candidate;
@@ -284,9 +301,11 @@
             });
 }
 
-void EquivalenceMap::Prune(const EncodedView& old_view,
-                           const EncodedView& new_view,
-                           double min_similarity) {
+void EquivalenceMap::Prune(
+    const EncodedView& old_view,
+    const EncodedView& new_view,
+    const std::vector<TargetsAffinity>& target_affinities,
+    double min_similarity) {
   for (auto current = candidates_.begin(); current != candidates_.end();
        ++current) {
     if (current->similarity < min_similarity)
@@ -304,7 +323,8 @@
       if (current->similarity < next->similarity) {
         current->eq.length -= delta;
         current->similarity = GetEquivalenceSimilarity(
-            old_view.image_index(), new_view.image_index(), current->eq);
+            old_view.image_index(), new_view.image_index(), target_affinities,
+            current->eq);
         break;
       }
     }
@@ -318,8 +338,9 @@
       next->eq.length = next->eq.length > delta ? next->eq.length - delta : 0;
       next->eq.src_offset += delta;
       next->eq.dst_offset += delta;
-      next->similarity = GetEquivalenceSimilarity(
-          old_view.image_index(), new_view.image_index(), next->eq);
+      next->similarity = GetEquivalenceSimilarity(old_view.image_index(),
+                                                  new_view.image_index(),
+                                                  target_affinities, next->eq);
       DCHECK_EQ(next->eq.dst_offset, current->eq.dst_end());
     }
   }