head-revs: teach the pure indexes about the `headrevs` method
Having this computation done at the index level unify the API and remove revlog
side complexity. It might also be a front runner of handing more responsability
to the index.
--- a/mercurial/pure/parsers.py Thu Sep 26 00:50:21 2024 +0200
+++ b/mercurial/pure/parsers.py Wed Sep 25 17:18:40 2024 +0200
@@ -696,6 +696,22 @@
p = p[revlog_constants.INDEX_HEADER.size :]
return p
+ def headrevs(self, excluded_revs=None):
+ count = len(self)
+ if not count:
+ return [nullrev]
+ # we won't iter over filtered rev so nobody is a head at start
+ ishead = [0] * (count + 1)
+ revs = range(count)
+ if excluded_revs is not None:
+ revs = (r for r in revs if r not in excluded_revs)
+
+ for r in revs:
+ ishead[r] = 1 # I may be an head
+ e = self[r]
+ ishead[e[5]] = ishead[e[6]] = 0 # my parent are not
+ return [r for r, val in enumerate(ishead) if val]
+
class IndexObject(BaseIndexObject):
def __init__(self, data):
--- a/mercurial/repoview.py Thu Sep 26 00:50:21 2024 +0200
+++ b/mercurial/repoview.py Wed Sep 25 17:18:40 2024 +0200
@@ -312,12 +312,7 @@
def headrevs(self, revs=None):
if revs is None:
- try:
- return self.index.headrevs(self.filteredrevs)
- # AttributeError covers non-c-extension environments and
- # old c extensions without filter handling.
- except AttributeError:
- return self._headrevs()
+ return self.index.headrevs(self.filteredrevs)
revs = self._checknofilteredinrevs(revs)
return super(filteredchangelogmixin, self).headrevs(revs)
--- a/mercurial/revlog.py Thu Sep 26 00:50:21 2024 +0200
+++ b/mercurial/revlog.py Wed Sep 25 17:18:40 2024 +0200
@@ -2382,10 +2382,7 @@
def headrevs(self, revs=None):
if revs is None:
- try:
- return self.index.headrevs()
- except AttributeError:
- return self._headrevs()
+ return self.index.headrevs()
if rustdagop is not None and self.index.rust_ext_compat:
return rustdagop.headrevs(self.index, revs)
return dagop.headrevs(revs, self._uncheckedparentrevs)
@@ -2399,19 +2396,6 @@
def computephases(self, roots):
return self.index.computephasesmapsets(roots)
- def _headrevs(self):
- count = len(self)
- if not count:
- return [nullrev]
- # we won't iter over filtered rev so nobody is a head at start
- ishead = [0] * (count + 1)
- index = self.index
- for r in self:
- ishead[r] = 1 # I may be an head
- e = index[r]
- ishead[e[5]] = ishead[e[6]] = 0 # my parent are not
- return [r for r, val in enumerate(ishead) if val]
-
def _head_node_ids(self):
try:
return self.index.head_node_ids()
--- a/mercurial/revlogutils/revlogv0.py Thu Sep 26 00:50:21 2024 +0200
+++ b/mercurial/revlogutils/revlogv0.py Wed Sep 25 17:18:40 2024 +0200
@@ -111,6 +111,22 @@
)
return INDEX_ENTRY_V0.pack(*e2)
+ def headrevs(self, excluded_revs=None):
+ count = len(self)
+ if not count:
+ return [node.nullrev]
+ # we won't iter over filtered rev so nobody is a head at start
+ ishead = [0] * (count + 1)
+ revs = range(count)
+ if excluded_revs is not None:
+ revs = (r for r in revs if r not in excluded_revs)
+
+ for r in revs:
+ ishead[r] = 1 # I may be an head
+ e = self[r]
+ ishead[e[5]] = ishead[e[6]] = 0 # my parent are not
+ return [r for r, val in enumerate(ishead) if val]
+
def parse_index_v0(data, inline):
s = INDEX_ENTRY_V0.size