Skip to content

Commit afa6752

Browse files
memoize the common fragments calculation
1 parent dc2ec9e commit afa6752

File tree

1 file changed

+52
-7
lines changed

1 file changed

+52
-7
lines changed

Sources/SwiftDocC/Model/Rendering/RenderSectionTranslator/DeclarationsSectionTranslator.swift

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,57 @@
1111
import Foundation
1212
import SymbolKit
1313

14+
typealias OverloadDeclaration = (
15+
declaration: [SymbolGraph.Symbol.DeclarationFragments.Fragment],
16+
reference: ResolvedTopicReference
17+
)
18+
1419
/// Translates a symbol's declaration into a render node's Declarations section.
1520
struct DeclarationsSectionTranslator: RenderSectionTranslator {
21+
/// A mapping from a symbol reference to the "common fragments" in its overload group.
22+
static let commonFragmentsMap: Synchronized<[ResolvedTopicReference: [SymbolGraph.Symbol.DeclarationFragments.Fragment]]> = .init([:])
23+
24+
/// Set the common fragments for the given symbol references.
25+
func setCommonFragments(
26+
references: [ResolvedTopicReference],
27+
fragments: [SymbolGraph.Symbol.DeclarationFragments.Fragment])
28+
{
29+
Self.commonFragmentsMap.sync({ map in
30+
for reference in references {
31+
map[reference] = fragments
32+
}
33+
})
34+
}
35+
36+
/// Fetch the common fragments for the given reference, if present.
37+
func commonFragments(
38+
for reference: ResolvedTopicReference
39+
) -> [SymbolGraph.Symbol.DeclarationFragments.Fragment]? {
40+
Self.commonFragmentsMap.sync({ $0[reference] })
41+
}
42+
43+
/// Fetch the common fragments for the given references, or compute it if necessary.
44+
func commonFragments(
45+
for mainDeclaration: OverloadDeclaration,
46+
overloadDeclarations: [OverloadDeclaration]
47+
) -> [SymbolGraph.Symbol.DeclarationFragments.Fragment] {
48+
if let fragments = commonFragments(for: mainDeclaration.reference) {
49+
return fragments
50+
}
51+
52+
let preProcessedDeclarations = [mainDeclaration.declaration] + overloadDeclarations.map(\.declaration)
53+
54+
// Collect the "common fragments" so we can highlight the ones that are different
55+
// in each declaration
56+
let commonFragments = longestCommonSubsequence(preProcessedDeclarations)
57+
58+
setCommonFragments(
59+
references: [mainDeclaration.reference] + overloadDeclarations.map(\.reference),
60+
fragments: commonFragments)
61+
62+
return commonFragments
63+
}
64+
1665
func translateSection(
1766
for symbol: Symbol,
1867
renderNode: inout RenderNode,
@@ -79,11 +128,6 @@ struct DeclarationsSectionTranslator: RenderSectionTranslator {
79128
return postProcessTokens(translatedDeclaration)
80129
}
81130

82-
typealias OverloadDeclaration = (
83-
declaration: [SymbolGraph.Symbol.DeclarationFragments.Fragment],
84-
reference: ResolvedTopicReference
85-
)
86-
87131
func renderOtherDeclarationsTokens(
88132
from overloadDeclarations: [OverloadDeclaration],
89133
displayIndex: Int,
@@ -162,11 +206,12 @@ struct DeclarationsSectionTranslator: RenderSectionTranslator {
162206
let processedOverloadDeclarations = overloadDeclarations.map({
163207
OverloadDeclaration($0.declaration.flatMap(preProcessFragment(_:)), $0.reference)
164208
})
165-
let preProcessedDeclarations = [mainDeclaration] + processedOverloadDeclarations.map(\.declaration)
166209

167210
// Collect the "common fragments" so we can highlight the ones that are different
168211
// in each declaration
169-
let commonFragments = longestCommonSubsequence(preProcessedDeclarations)
212+
let commonFragments = commonFragments(
213+
for: (mainDeclaration, renderNode.identifier),
214+
overloadDeclarations: processedOverloadDeclarations)
170215

171216
renderedTokens = translateDeclaration(
172217
mainDeclaration,

0 commit comments

Comments
 (0)