From d69d19103fac01b781e4b7f8f138f0d2440b54c1 Mon Sep 17 00:00:00 2001 From: Rouslan Korneychuk Date: Thu, 18 Jan 2024 16:10:54 -0500 Subject: [PATCH] Improve cross-reference resolution performance in the C++ domain (#11892) Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com> --- CHANGES.rst | 3 +++ sphinx/domains/c.py | 16 +++++++++++++--- sphinx/domains/cpp.py | 15 ++++++++++++++- sphinx/util/cfamily.py | 12 +++++++++++- 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 9381798d7..f28248a3c 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -24,6 +24,9 @@ Features added * #11803: autodoc: Use an overriden ``__repr__()`` function in an enum, if defined. Patch by Shengyu Zhang. +* #11892: Improved performance when resolving cross references in cpp domain. + Patch by Rouslan Korneychuk. + Bugs fixed ---------- diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py index e3570e6fc..4492224b6 100644 --- a/sphinx/domains/c.py +++ b/sphinx/domains/c.py @@ -149,8 +149,12 @@ class ASTIdentifier(ASTBaseBase): assert len(identifier) != 0 self.identifier = identifier - def __eq__(self, other: Any) -> bool: - return type(other) is ASTIdentifier and self.identifier == other.identifier + # ASTBaseBase already implements this method, + # but specialising it here improves performance + def __eq__(self, other: object) -> bool: + if type(other) is not ASTIdentifier: + return NotImplemented + return self.identifier == other.identifier def is_anon(self) -> bool: return self.identifier[0] == '@' @@ -1448,6 +1452,10 @@ class ASTDeclaration(ASTBaseBase): # set by CObject._add_enumerator_to_parent self.enumeratorScopedSymbol: Symbol | None = None + # the cache assumes that by the time get_newest_id is called, no + # further changes will be made to this object + self._newest_id_cache: str | None = None + def clone(self) -> ASTDeclaration: return ASTDeclaration(self.objectType, self.directiveType, self.declaration.clone(), self.semicolon) @@ -1474,7 +1482,9 @@ class ASTDeclaration(ASTBaseBase): return id_ def get_newest_id(self) -> str: - return self.get_id(_max_id, True) + if self._newest_id_cache is None: + self._newest_id_cache = self.get_id(_max_id, True) + return self._newest_id_cache def _stringify(self, transform: StringifyTransform) -> str: res = transform(self.declaration) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index fcadf1f94..9c00d8748 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -615,6 +615,13 @@ class ASTIdentifier(ASTBase): assert len(identifier) != 0 self.identifier = identifier + # ASTBaseBase already implements this method, + # but specialising it here improves performance + def __eq__(self, other: object) -> bool: + if type(other) is not ASTIdentifier: + return NotImplemented + return self.identifier == other.identifier + def _stringify(self, transform: StringifyTransform) -> str: return transform(self.identifier) @@ -4018,6 +4025,10 @@ class ASTDeclaration(ASTBase): # set by CPPObject._add_enumerator_to_parent self.enumeratorScopedSymbol: Symbol | None = None + # the cache assumes that by the time get_newest_id is called, no + # further changes will be made to this object + self._newest_id_cache: str | None = None + def clone(self) -> ASTDeclaration: templatePrefixClone = self.templatePrefix.clone() if self.templatePrefix else None trailingRequiresClasueClone = self.trailingRequiresClause.clone() \ @@ -4083,7 +4094,9 @@ class ASTDeclaration(ASTBase): return ''.join(res) def get_newest_id(self) -> str: - return self.get_id(_max_id, True) + if self._newest_id_cache is None: + self._newest_id_cache = self.get_id(_max_id, True) + return self._newest_id_cache def _stringify(self, transform: StringifyTransform) -> str: res = [] diff --git a/sphinx/util/cfamily.py b/sphinx/util/cfamily.py index 644784ff2..8feb82bcc 100644 --- a/sphinx/util/cfamily.py +++ b/sphinx/util/cfamily.py @@ -88,7 +88,7 @@ class NoOldIdError(Exception): class ASTBaseBase: - def __eq__(self, other: Any) -> bool: + def __eq__(self, other: object) -> bool: if type(self) is not type(other): return False try: @@ -145,6 +145,11 @@ class ASTGnuAttribute(ASTBaseBase): self.name = name self.args = args + def __eq__(self, other: object) -> bool: + if type(other) is not ASTGnuAttribute: + return NotImplemented + return self.name == other.name and self.args == other.args + def _stringify(self, transform: StringifyTransform) -> str: res = [self.name] if self.args: @@ -204,6 +209,11 @@ class ASTAttributeList(ASTBaseBase): def __init__(self, attrs: list[ASTAttribute]) -> None: self.attrs = attrs + def __eq__(self, other: object) -> bool: + if type(other) is not ASTAttributeList: + return NotImplemented + return self.attrs == other.attrs + def __len__(self) -> int: return len(self.attrs)