# HG changeset patch
# User Arseniy Alekseyev <aalekseyev@janestreet.com>
# Date 2023-01-12 13:14:00
# Node ID c7a04bfabd4da227d8edbffe101396360909a66d
# Parent  7b474609f1997652728bcc3f13697d92a5923f4a

merge: add mergeresult.mapaction to improve speed

As a part of [hg update] we convert all [ACTION_CREATED] merge
results into [ACTION_GET] actions, and that's slightly inefficient
because every insertion pays the full cost of maintaining the
[mergeresult] data structure up to date.

This commit adds a function [mapaction], which is faster.
(saves around 0.3s on a large update involving ~400k files)

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -246,9 +246,7 @@ def _checkunknownfiles(repo, wctx, mctx,
         else:
             repo.ui.warn(_(b"%s: replacing untracked files in directory\n") % f)
 
-    for f, args, msg in list(
-        mresult.getactions([mergestatemod.ACTION_CREATED])
-    ):
+    def transformargs(f, args):
         backup = (
             f in fileconflicts
             or pathconflicts
@@ -258,7 +256,11 @@ def _checkunknownfiles(repo, wctx, mctx,
             )
         )
         (flags,) = args
-        mresult.addfile(f, mergestatemod.ACTION_GET, (flags, backup), msg)
+        return (flags, backup)
+
+    mresult.mapaction(
+        mergestatemod.ACTION_CREATED, mergestatemod.ACTION_GET, transformargs
+    )
 
 
 def _forgetremoved(wctx, mctx, branchmerge, mresult):
@@ -590,6 +592,18 @@ class mergeresult:
         self._filemapping[filename] = (action, data, message)
         self._actionmapping[action][filename] = (data, message)
 
+    def mapaction(self, actionfrom, actionto, transform):
+        """changes all occurrences of action `actionfrom` into `actionto`,
+        transforming its args with the function `transform`.
+        """
+        orig = self._actionmapping[actionfrom]
+        del self._actionmapping[actionfrom]
+        dest = self._actionmapping[actionto]
+        for f, (data, msg) in orig.items():
+            data = transform(f, data)
+            self._filemapping[f] = (actionto, data, msg)
+            dest[f] = (data, msg)
+
     def getfile(self, filename, default_return=None):
         """returns (action, args, msg) about this file