Skip to content

Commit 093dfab

Browse files
committed
perf: add O(1) lookup caching for ProjectNode document entries
- Cache root document entry for O(1) getRootDocumentEntry() - Use direct hash lookup for getDocumentEntry() instead of iteration - Properly rekey array in setDocumentEntries() via addDocumentEntry() - Invalidate cache on reset() The functional test is updated to mark the document as root before compilation (using withIsRoot(true)) so the compiler creates the DocumentEntryNode correctly, rather than pre-creating an entry that gets overwritten by the compiler.
1 parent 8acd95a commit 093dfab

File tree

2 files changed

+22
-14
lines changed

2 files changed

+22
-14
lines changed

packages/guides/src/Nodes/ProjectNode.php

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,10 @@ final class ProjectNode extends CompoundNode
4747
/** @var array<string, array<string, InternalTarget>> */
4848
private array $internalLinkTargets = [];
4949

50-
/** @var DocumentEntryNode[] */
50+
/** Cached root document entry for O(1) lookup */
51+
private DocumentEntryNode|null $rootDocumentEntry = null;
52+
53+
/** @var array<string, DocumentEntryNode> */
5154
private array $documentEntries = [];
5255
private DateTimeImmutable $lastRendered;
5356

@@ -182,6 +185,11 @@ public function getAllInternalTargets(): array
182185

183186
public function addDocumentEntry(DocumentEntryNode $documentEntry): void
184187
{
188+
// Cache root for O(1) lookup
189+
if ($documentEntry->isRoot()) {
190+
$this->rootDocumentEntry = $documentEntry;
191+
}
192+
185193
$this->documentEntries[$documentEntry->getFile()] = $documentEntry;
186194
}
187195

@@ -193,10 +201,8 @@ public function getAllDocumentEntries(): array
193201

194202
public function getRootDocumentEntry(): DocumentEntryNode
195203
{
196-
foreach ($this->documentEntries as $documentEntry) {
197-
if ($documentEntry->isRoot()) {
198-
return $documentEntry;
199-
}
204+
if ($this->rootDocumentEntry !== null) {
205+
return $this->rootDocumentEntry;
200206
}
201207

202208
throw new Exception('No root document entry was found');
@@ -205,10 +211,9 @@ public function getRootDocumentEntry(): DocumentEntryNode
205211
/** @throws DocumentEntryNotFound */
206212
public function getDocumentEntry(string $file): DocumentEntryNode
207213
{
208-
foreach ($this->documentEntries as $documentEntry) {
209-
if ($documentEntry->getFile() === $file) {
210-
return $documentEntry;
211-
}
214+
// O(1) lookup by file path
215+
if (isset($this->documentEntries[$file])) {
216+
return $this->documentEntries[$file];
212217
}
213218

214219
throw new DocumentEntryNotFound('No document Entry found for file ' . $file);
@@ -217,7 +222,12 @@ public function getDocumentEntry(string $file): DocumentEntryNode
217222
/** @param DocumentEntryNode[] $documentEntries */
218223
public function setDocumentEntries(array $documentEntries): void
219224
{
220-
$this->documentEntries = $documentEntries;
225+
$this->documentEntries = [];
226+
$this->rootDocumentEntry = null;
227+
228+
foreach ($documentEntries as $entry) {
229+
$this->addDocumentEntry($entry);
230+
}
221231
}
222232

223233
public function findDocumentEntry(string $filePath): DocumentEntryNode|null
@@ -228,6 +238,7 @@ public function findDocumentEntry(string $filePath): DocumentEntryNode|null
228238
public function reset(): void
229239
{
230240
$this->documentEntries = [];
241+
$this->rootDocumentEntry = null;
231242
}
232243

233244
public function getLastRendered(): DateTimeImmutable

tests/Functional/FunctionalTest.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
use phpDocumentor\Guides\Compiler\Compiler;
2626
use phpDocumentor\Guides\Compiler\CompilerContext;
2727
use phpDocumentor\Guides\NodeRenderers\NodeRenderer;
28-
use phpDocumentor\Guides\Nodes\DocumentTree\DocumentEntryNode;
2928
use phpDocumentor\Guides\Nodes\Node;
3029
use phpDocumentor\Guides\Nodes\ProjectNode;
3130
use phpDocumentor\Guides\Nodes\TitleNode;
@@ -110,13 +109,11 @@ public function testFunctional(
110109

111110
$parser = $this->getContainer()->get(Parser::class);
112111
assert($parser instanceof Parser);
113-
$document = $parser->parse($rst);
114-
$documentEntry = new DocumentEntryNode($document->getFilePath(), $document->getTitle() ?? TitleNode::fromString(''), true);
112+
$document = $parser->parse($rst)->withIsRoot(true);
115113

116114
$compiler = $this->getContainer()->get(Compiler::class);
117115
assert($compiler instanceof Compiler);
118116
$projectNode = new ProjectNode();
119-
$projectNode->setDocumentEntries([$documentEntry]);
120117
$compiler->run([$document], new CompilerContext($projectNode));
121118

122119
$inputFilesystem = FlySystemAdapter::createFromFileSystem(new Filesystem(new InMemoryFilesystemAdapter()));

0 commit comments

Comments
 (0)