@@ -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
0 commit comments