Doxygen XLinks
by
V: 2511R0
Website: doxygen
Loading...
Searching...
No Matches
index.cpp
1//==================================================================================================
2// This implementation-file is part of DoxygenXLinks - A doxygen post-processor that allows to
3// define smarter <b>Doxygen</b>-links.
4//
5// \emoji :copyright: 2025-2026 A-Worx GmbH, Germany.
6// Published under \ref mainpage_license "Boost Software License".
7//==================================================================================================
8
9#include "jobs.hpp"
10#include "index.hpp"
11#include "dxl.hpp"
12#include "xlink.hpp"
14#include "ALib.System.H"
15
16using namespace alib;
17using namespace std;
18
19namespace dxl {
20
21bool IndexLoader::Do() { index.Load(); return true; }
22
23// create the file name from the path
24Index::Index(const PathString& tagFilePath, const String& baseURL, bool isMainTagFile )
25: TreeType{ma, '@'}
26, ma {ALIB_DBG("DL Index", ) 1024, 200}
27, entityMap {ma}
28, fileMap {ma}
29, anchorMap {ma}
30, FilePath {tagFilePath}
31, BaseURL {baseURL}
32, IsMainTagFile{isMainTagFile} {
33
34 #if ALIB_DEBUG_CRITICAL_SECTIONS
35 nodeTable.dcs.DCSLock= &SLock;
36 entityMap.dcs.DCSLock= &SLock;
37 fileMap .dcs.DCSLock= &SLock;
38 anchorMap.dcs.DCSLock= &SLock;
39 #endif
40
42
43 // create the file name from the path
44 FileName= tagFilePath;
45 integer slashPos= std::max(FileName.LastIndexOf('/'), FileName.LastIndexOf('\\'));
46 if (slashPos > 0)
47 FileName= FileName.Substring(slashPos+1);
48
49 // split file-name by dots
51 String backwardsParser= FileName;
52 for (;;) {
53 integer dotPos= backwardsParser.LastIndexOf('.');
54 if (dotPos < 0) {
56 break;
57 }
58 fileNameDotComponents[fileNameDotComponentsSize++]= backwardsParser.Substring(dotPos + 1);
59 backwardsParser= backwardsParser.Substring(0, dotPos);
60} }
61
63 #if ALIB_DEBUG_CRITICAL_SECTIONS
64 nodeTable.dcs.DCSLock= nullptr;
65 entityMap.dcs.DCSLock= nullptr;
66 fileMap .dcs.DCSLock= nullptr;
67 anchorMap.dcs.DCSLock= nullptr;
68 #endif
70 entityMap.Reset();
71 fileMap .Reset();
72 anchorMap.Reset();
73 Reset();
74}
75
76void Index::Load() { // ReSharper disable CppDFAUnreachableCode
77
79 Ticks startTime;
80
81 // load the file
83
84 // count types
86 entityIterator.SetPathGeneration(lang::Switch::Off);
87 entityIterator.Initialize(Root(), lang::Inclusion::Exclude);
88 while (entityIterator.IsValid()) {
89 KindStats.Add(Node(entityIterator.Node()).Kind());
90 entityIterator.Next();
91 }
92
93 // reserve spaces
94 entityMap .Reserve(Size(), lang::ValueReference::Absolute);
95
96 int expectedFileMapSize = 0;
97 int expectedAnchorMapSize= 0;
98 expectedFileMapSize= KindStats.Get(Target::Namespace )
103 + KindStats.Get(Target::Page )
104 + KindStats.Get(Target::File )
105 + KindStats.Get(Target::Dir );
106
107 expectedAnchorMapSize= KindStats.Get(Target::Macro )
114
115 fileMap .Reserve(expectedFileMapSize , lang::ValueReference::Absolute );
116 anchorMap .Reserve(expectedAnchorMapSize , lang::ValueReference::Absolute );
117
118
119 // loop over all entities and fill hashtables entityMap, fileMap, and anchorMap
120 entityIterator.SetPathGeneration(lang::Switch::On);
121 entityIterator.Initialize(Root(), lang::Inclusion::Exclude);
122 while (entityIterator.IsValid()) {
123 Substring name= entityIterator.Node().Name();
124 Target& tag= *entityIterator.Node().Value();
125
126
127 // add an entry in the file-map for records, concepts, modules and namespaces
130 fileMap.EmplaceUnique( tag.HTMLFile, entityIterator.Node().Export() );
131 }
132
133 // Note: We do not read modules, as of today, Doxygen obviously puts the wrong
134 // filename into the tag file. It seems to be the filename of the
135 // module-interface file (i.e. *.ixx) that defines the module instead of the
136 // module page. Otherwise, it had to go to the filemap as well. But we must not
137 // do it due to the uniqueness of the key.
138 // See other notes tagged DOXYMODFILENAME.
139
140
141 // add Members to the anchor-map
142 else if (auto* member= Cast<TGTMember>(&tag); member ) {
143 auto result= anchorMap.InsertIfNotExistent(
144 AnchorKey{ tag.HTMLFile, member->Anchor },
145 entityIterator.Node().Export() );
146 if ( !result.second ) {
147 Lox_Info( "In HTML file {!Q}, the anchor {!Q} already exists. (Skipped)\n"
148 " Previous anchor: {}:{} Kind: {:10} FileName: {}\n"
149 " New anchor: {}:{} Kind: {:10} FileName: {}"
150 ,tag.HTMLFile, member->Anchor
151 , FilePath, ImportNode(result.first.Mapped()).LineNo()
152 , ImportNode(result.first.Mapped()).Kind()
153 , ImportNode(result.first.Mapped()).HTMLFile()
154 , FilePath, tag.LineNo, tag.Kind(), tag.HTMLFile
155 )
156 } }
157 // add DocAnchors in the anchor-map used with local links for members
158 else if (auto* docAnchor= Cast<TGTDocAnchor>(&tag); docAnchor ) {
159 auto result= anchorMap.InsertIfNotExistent(
160 AnchorKey{ tag.HTMLFile, docAnchor->Name },
161 entityIterator.Node().Export() );
162 if ( !result.second ) {
163 Lox_Warning( "In HTML file {!Q}, the DocAnchor {!Q} already exists. (Skipped)\n"
164 " Previous anchor: {}:{} Kind: {:10} FileName: {}\n"
165 " New anchor: {}:{} Kind: {:10} FileName: {}"
166 ,tag.HTMLFile, docAnchor->Name
167 , FilePath, ImportNode(result.first.Mapped()).LineNo()
168 , ImportNode(result.first.Mapped()).Kind()
169 , ImportNode(result.first.Mapped()).HTMLFile()
170 , FilePath, tag.LineNo, tag.Kind(), tag.HTMLFile
171 )
172 } }
173
174 // cut template specialization args from record names
175 if (auto* scu= Cast<TGTRecord>(&tag); scu) {
176 if ( scu->SpecializationArgs ) {
177 integer bracePos= name.IndexOf('<');
178 if (bracePos>0) {
179 name= name.Substring(0, bracePos);
180 name.TrimEnd();
181 } }
182 ALIB_ASSERT_ERROR(name.IndexOf('<') < 0, "DXL/XLINK",
183 "Parse error (only specialization args should appear in the name and those "
184 "have been removed already.")
185 }
186
187 // cut parameters from function names
188 else if ( auto* mf= Cast<TGTFunction>(&tag); mf ) {
189 if ( mf->Args
190 || mf->Qualifiers.IsNotEmpty() ) {
191 integer bracePos= name.LastIndexOf('(');
192 if ( bracePos > 0)
193 name= name.Substring(0, bracePos);
194 } }
195
196 entityMap.Insert( {name, entityIterator.Node().Export()} );
197 entityIterator.Next();
198 }
199
200 ALIB_ASSERT_ERROR(entityMap.Size() == Size(), "DXL/XLINK",
201 "Expected size of entityMap {} != {} real size.", Size() , entityMap.Size())
202
203 ALIB_ASSERT_ERROR(expectedFileMapSize == fileMap.Size(), "DXL/XLINK",
204 "Expected size of fileMap {} != {} real size.", expectedFileMapSize , fileMap.Size())
205
206 ALIB_ASSERT_ERROR(expectedAnchorMapSize >= anchorMap.Size(), "DXL/XLINK",
207 "Expected size of anchorMap {} < {} real size.", expectedAnchorMapSize, anchorMap.Size())
208
209 LoadTime= startTime.Age();
210
211} // ReSharper restore CppDFAUnreachableCode
212
213Index::ConstCursorHandle Index::GetHTMLFileEntity(const FTFile& htmlFile) {
215 auto it= fileMap.Find(htmlFile.Name());
216 if ( it == fileMap.end()) {
217 Lox_Warning( "HTML-File {!Q} not found in index: ", htmlFile.Name() )
218 return CursorHandle(0);
219 }
220 return it->second;
221}
222
224 if ( HasOneOf(kind, Target::Dir | Target::File | Target::FILEPATH_COMPONENT) )
226 else
227 buffer.SearchAndReplace( "::", String8(Separator()), startPos);
228}
229
231 if ( buffer.CharAt(startPos) == Separator() )
232 buffer.Delete(startPos, 1);
233 if ( HasOneOf(kind, Target::Dir | Target::File | Target::FILEPATH_COMPONENT) )
235 else
236 buffer.SearchAndReplace(String8(Separator()), "::");
237
238}
239bool Index::ScopeHintMatch(Index::Node entry, XLink& searchLink) {
240 if ( searchLink.HintsSize() == 0 )
241 return true;
242
243 // build path stack from string tree
244 int stackSize= 0;
245 String pathNameStack[32];
246 auto parent= entry.Parent();
247 while (!parent.IsRoot()) {
248 pathNameStack[stackSize++]= parent.Name();
249 parent= parent.Parent();
250 }
251 for (int i= 0; i < fileNameDotComponentsSize; ++i)
252 pathNameStack[stackSize++]= fileNameDotComponents[i];
253
254 // add tag-file name
255 {
256 PathString tagFileName= entry.Index().FileName;
257
258 for (;;) {
259 integer dotPos= tagFileName.LastIndexOf('.');
260 if (dotPos < 0) {
261 pathNameStack[stackSize++]= tagFileName;
262 break;
263 }
264 pathNameStack[stackSize++]= tagFileName.Substring(dotPos + 1);
265 tagFileName= tagFileName.Substring(0, dotPos);
266 } }
267
268
269 // search hints in the path-stack
270 int stackPointer= stackSize-1;
271 integer pos= 0;
272 int hintNo = 0;
273 for (;;) {
274 pos= pathNameStack[stackPointer].IndexOf<CHK, lang::Case::Ignore>(
275 searchLink.Hint(hintNo), pos );
276 if ( pos >= 0 ) {
277 if ( ++hintNo == searchLink.HintsSize())
278 return true;
279 pos= pos + searchLink.Hint(hintNo).Length();
280 continue;
281 }
282
283 if ( --stackPointer < 0)
284 return false;
285 pos= 0;
286} }
287
288void Index::searchFile( XLink& xLink ) {
289 if (xLink.KindSpec != Target::File || !xLink.NoIndirectionWarning )
291 for ( auto range= entityMap.EqualRange(xLink.Name()) ;
292 range.first!=range.second ;
293 ++range.first) {
294 Node node= ImportNode(range.first->second);
295 // String256 dbgPath;
296 // node.AssemblePath(dbgPath);
297 if ( !node.IsA(Target::File |Target::Dir) )
298 continue;
299
300 xLink.DidYouMeanSameName.emplace_back(node);
301
302 //-------------------------------------- check scope -------------------------------------
303 // check parent scope components (those attached with "::" to the target name. Have to match exactly)
304 if ( xLink.ScopeSize() ) {
305 Node parent= node.Parent();
306 bool foundParentScope= true;
307 for (int i= xLink.ScopeSize() - 1; i>= 0 ; --i) {
308 String componentName= xLink.Scope(i);
309 if ( !parent.IsValid() || !parent.Name().Equals(componentName) ) {
310 foundParentScope= false;
311 break;
312 }
313 parent= parent.Parent();
314 }
315
316 if (!foundParentScope)
317 continue;
318 }
319
320 // check path hints
321 // (those prepended separated by a space to the target path. Substring match is enough)
322 if (!ScopeHintMatch(node, xLink))
323 continue;
324
325 // check kind
326 // (The first check is probably not needed, as only if the typespec is given, we search
327 // for files and folders. But let's keep it in.)
328 if ( xLink.KindSpec != Target::UNSPECIFIED
329 && xLink.KindSpec != node.Kind() )
330 continue;
331
332 // add result
333 xLink.Targets.push_back({ node
334 ,BaseURL
335 , node.HTMLFile()
337 ,0,false,false,false,false,false,false
338 });
339 }
340 } // unlock index
341
342 // dedup group entries (this is also done with other search methods)
343 if (xLink.Targets.size() > 1)
345}
346
348 bool isIndirectByInheritance, bool isIndirectByTypeDef ) {
349 const Target* target= node.Target();
350
351 //------- searching a function, but the entry is not a function or a definition? ----
352 if ( xLink.Args ) {
353 if ( !target->IsA(Target::Function | Target::Macro) )
354 return;
355 xLink.DidYouMeanFunctionOverload.emplace_back(node);
356 }
357
358 //------ searching an array variable, but the entry is not a variable? ------
359 if ( xLink.Subscript!=nullptr) {
360 auto* var= Cast<TGTVariable>(target);
361 if (!var)
362 return;
363 if (var->Subscript.IndexOf(xLink.Subscript) < 0) {
364 xLink.DidYouMeanVariable.push_back(node);
365 return;
366 } }
367
368 //------------------------------------ searching template type? ----------------------------------
369 if ( xLink.TemplateArgs) {
370 // result is not a template?
371 auto* rec= Cast<TGTRecord>(target);
372 if ( !rec) {
373 xLink.DidYouMeanNotATemplate.push_back(node);
374 return;
375 }
376 if (!rec->TemplateArgs) {
377 xLink.DidYouMeanNotATemplate.push_back(node);
378 return;
379 }
380
381 // args don't match?
382 int match= xLink.TemplateArgs->Match(*rec->TemplateArgs);
383 if ( match == 0) {
384 xLink.DidYouMeanTemplateType= node;
385 return;
386 } }
387
388 //------------------------------- searching template specialization? -----------------------------
389 if ( xLink.SpecializationArgs) {
390 // result is not a specialization?
391 auto* rec= Cast<TGTRecord>(target);
392 if ( !rec) {
393 xLink.DidYouMeanSpecializations.push_back(node);
394 return;
395 }
396 if (!rec->SpecializationArgs) {
397 xLink.DidYouMeanSpecializations.push_back(node);
398 return;
399 }
400
401 // args don't match?
402 int match= xLink.SpecializationArgs->Match(*rec->SpecializationArgs);
403 if ( match == 0) {
404 xLink.DidYouMeanSpecializations.push_back(node);
405 return;
406 } }
407
408 //------------------------------ "Typedef in inner path" erasion rule ----------------------------
409 // 1. Skip this result if it is "just" a typedef and a deeper object exists
410 bool skipThis= false;
411 if ( target->IsA(Target::Typedef) )
412 for (auto& it : xLink.Targets ) {
413 if ( it.Node.IsA(Target::RECORD | Target::Enumeration) ) {
414
415 Node parent = it.Node.Parent();
416 while (parent.IsValid()) {
417 if (parent == node.Parent()) {
418 skipThis= true;
419 break;
420 }
421 parent= parent.Parent();
422 } }
423 if (skipThis) break;
424 }
425
426 if ( skipThis ) return;
427
428 // 2. Erase an existing result if it is "just" a typedef while this is a deeper object
429 if ( target->IsA(Target::RECORD | Target::Enumeration) )
430 std::erase_if(xLink.Targets, [&](const auto& it) {
431 if ( !it.Node.IsA(Target::Typedef) )
432 return false;
433 Node parent = node.Parent();
434 while (parent.IsValid()) {
435 if ( parent == it.Node.Parent())
436 return true;
437 parent= parent.Parent();
438 }
439 return false; // Keep this result
440 });
441
442
443 //------------------------------ "Prefer outer entities" erasion rule ----------------------------
444 // 1. Remove existing results that are children of this one
445 std::erase_if(xLink.Targets, [&,node](const auto& it) {
446 Node parent = it.Node.Parent();
447 while (parent.IsValid()) {
448 if (parent == node)
449 return true; // Delete this result
450 parent = parent.Parent();
451 }
452 return false; // Keep this result
453 });
454
455 // 2. Skip this result if it is a child of one of the others.
456 for (auto& it : xLink.Targets) {
457 Node parent = node.Parent();
458 while (parent.IsValid()) {
459 if (parent == it.Node) {
460 skipThis= true;
461 break;
462 }
463 parent= parent.Parent();
464 }
465 if (skipThis) break;
466 }
467 if (skipThis) return;
468
469
470 //------------------------------------ check function arguments ----------------------------------
471 int funcArgMatch= 1;
472 if ( target->IsA(Target::Function | Target::Macro) ) {
473 // with functions, we can use the MATCH method directly
474 if ( target->IsA(Target::Function) )
475 funcArgMatch= Target::FunctionArguments::MATCH( xLink.Args,
476 Cast<TGTFunction,NC>(target)->Args );
477
478 // with definitions, we have to check if the target is a prepro macro or a
479 // prepro constant
480 else {
481 auto* targetArgs= Cast<TGTMacro,NC>(target)->Args;
482 if ( xLink.Args && !targetArgs)
483 funcArgMatch= 0;
484 else
485 funcArgMatch= Target::FunctionArguments::MATCH(xLink.Args, targetArgs);
486 }
487
488 if ( funcArgMatch == 0)
489 return;
490
491 // check if one had a better result before.
492 bool hasBetterMatch= false;
493 std::erase_if(xLink.Targets, [&](const auto& it) {
494 if ( it.FunctionArgumentMatch < funcArgMatch)
495 return true;
496 if ( it.FunctionArgumentMatch > funcArgMatch)
497 hasBetterMatch= true;
498 return false;
499 });
500
501 if ( hasBetterMatch)
502 return;
503 }
504
505 // check qualifiers
506 bool qualifiersHintMatch= false;
507 if (xLink.Qualifiers.IsNotNull()) {
508 if ( !target->IsA(Target::Function)
509 || Cast<TGTFunction,NC>(target)->Qualifiers.IndexOf(xLink.Qualifiers) < 0)
510 return;
511 qualifiersHintMatch= true;
512
513 // remove functions that did not match in respect to Qualifiers
514 std::erase_if(xLink.Targets, [&,node](const auto& it) {
515 return it.Node.IsA(Target::Function)
516 && Cast<TGTFunction,NC>(it.Node)->Qualifiers.IsEmpty();
517 });
518 }
519 else {
520 if ( auto* func= Cast<TGTFunction>(target); func ) {
521 if ( func->Qualifiers.IsNotEmpty()) {
522 bool hasBetterMatch= false;
523 for ( auto& it : xLink.Targets) {
524 if ( auto* f= Cast<TGTFunction>(it.Node); f ) {
525 hasBetterMatch= f->Qualifiers.IsEmpty();
526 break;
527 } }
528 if ( hasBetterMatch)
529 return;
530 }
531 else // todo: the case where no qualifiers are given is now resolved later in dxl
532 // disambiguation. So this can be deleted I guess (have a try)
533 // In general: we have to check again what goes where best.
534 std::erase_if(xLink.Targets, [&,node](const auto& it) {
535 return it.Node.IsA(Target::Function)
536 && Cast<TGTFunction,NC>(it.Node)->Qualifiers.IsNotEmpty();
537 });
538
539 } }
540
541 // rule: Template class beats deduction guide if no function args are given
542 {
543 std::erase_if(xLink.Targets, [&](const auto& it) {
544
545 // within the same scope?
546 if ( it.Node.Parent() == node.Parent() ) {
547 if (target->IsA(Target::RECORD)) {
548 if ( it.Node.IsA(Target::Function)
549 && xLink.Args==nullptr)
550 return true;
551 } }
552
553 return false;
554 });
555 }
556
557
558 // add result
559 xLink.Targets.push_back({ node
560 ,BaseURL
561 ,target->HTMLFile
562 , target->IsA(Target::MEMBER) ? Cast<TGTMember ,NC>(target)->Anchor
563 : target->IsA(Target::DocAnchor) ? Cast<TGTDocAnchor,NC>(target)->Name
565 ,funcArgMatch
566 ,qualifiersHintMatch
567 ,isIndirectByInheritance
568 ,isIndirectByTypeDef
569 ,false ,false, false
570 });
571
572}
573
574//--------------------------------------------------------------------------------------------------
575//---------------------------------------------- Search --------------------------------------------
576//--------------------------------------------------------------------------------------------------
577void Index::Search( XLink& xLink ) {
578 // special treatment for files
579 if ( HasOneOf(xLink.KindSpec, Target::Dir | Target::File) ) {
580 searchFile(xLink);
581 return;
582 }
583
584 //--------------------------- loop over all entities of the target name --------------------------
585 // first we collect the results. Otherwise, we have a problem with recursive locking,
586 // because when resolving the possible entities, recursive searches in all indices might
587 // occur. (Currently this is done for example with GetLinkToParent())
589 StdVectorMA<CursorHandle> results(la);
590 results.reserve(1024/sizeof(CursorHandle) - 4);
592 for ( auto range= entityMap.EqualRange( xLink.Name()) ; range.first!=range.second ; ++range.first)
593 results.push_back(range.first->second);
594 }
595
596 for ( auto handle : results ) {
597
598 // get cursor and check if it is a real target
599 Node node= ImportNode(handle);
602 continue;
603
604 // store in general "did you mean..." list
605 xLink.DidYouMeanSameName.emplace_back(node);
606
607 // check if kind is specified and if so, whether it fits
608 if ( xLink.KindSpec != Target::UNSPECIFIED
609 && !HasOneOf(xLink.KindSpec, node.Kind() ) )
610 continue;
611
612 //---------------------------------------- check scope ---------------------------------------
613 bool scopeMatches= true;
614 {
615 Node parent= node.Parent();
616
617 // check parent scope components
618 if ( xLink.ScopeSize() ) {
619 int fileNameComponentIdx= -1;
620 for (int i= xLink.ScopeSize() - 1; i>= 0 ; --i) {
621 String componentName= xLink.Scope(i);
622 integer templatePos= componentName.IndexOf('<');
623 if ( templatePos > 0 )
624 componentName= componentName.Substring(0, templatePos);
625
626 if ( !parent.IsRoot() ) {
627 if ( !componentName.Equals( parent.Name() ) ) {
628 scopeMatches= false;
629 break;
630 }
631 parent= parent.Parent();
632 } else {
633 if ( ++fileNameComponentIdx >= fileNameDotComponentsSize
634 || !componentName.Equals( fileNameDotComponents[fileNameComponentIdx] ) ){
635 scopeMatches= false;
636 break;
637 } } } }
638 if ( scopeMatches && xLink.IsLocal)
639 scopeMatches &= (parent.Export().value == xLink.LocalLinkEntity.value);
640
641 // check path hints
642 // (those prepended separated by a space to the target path. Substring match is enough)
643 scopeMatches= scopeMatches && ScopeHintMatch(node, xLink);
644 }
645
646 // if the scope matched, we give it a chance
647 if ( scopeMatches )
648 evaluateEntity(xLink, node, false, false); // if it fits, the node is added to the XLink's Targets.
649 } // loop over all entities
650
651 // if we now have exactly one match, we stop here.
652 if (xLink.Targets.size() == 1)
653 return;
654
655 //--------- wrong scope? Search for inherited members and Type definition target's members -------
656 if ( xLink.ScopeSize() || xLink.IsLocal ) {
657 // get the parent XLink. This call also creates the vector link.BaseTypes
658 xLink.GetLinkToParent();
659
660 //------------------------- loop over all entities of the target name ------------------------
661 for ( auto cursorHandle : results ) {
662 Node node = ImportNode(cursorHandle);
663
664 //----------- check inheritance: is the current node a member of a parent type? ----------
665 if ( xLink.BaseTypes )
666 for (Node& inheritanceParent : *xLink.BaseTypes) {
667 if (inheritanceParent == node.Parent())
668 evaluateEntity(xLink, node, true, false);
669 }
670
671 //--------------------- if not inherited, check if it is through a type ------------------
672 if ( xLink.TypeDefinitionTargets)
673 for (auto& typeDefTarget : *xLink.TypeDefinitionTargets) {
674 if (typeDefTarget == node.Parent() )
675 evaluateEntity(xLink, node, false, true);
676 }
677 } // loop over entities
678 } // XLink has outer scope
679
680
681 // finally dedup group entries (this is also done with other search methods)
682 if (xLink.Targets.size() > 1)
684}
685
687
688 bool hasNonGroupResults= false;
689 for (auto& it : targets)
690 if ( it.Node.Parent().IsRoot()
691 || !it.Node.Parent().IsA(Target::Group) ) {
692 hasNonGroupResults= true;
693 break;
694 }
695 if ( hasNonGroupResults)
696 std::erase_if(targets, [](const auto& it) {
697 return !it.Node.Parent().IsRoot()
698 && it.Node.Parent().IsA(Target::Group);
699 });
700}
701
702} //namespace [dxl]
#define ALIB_LOCK_SHARED_WITH(lock)
#define ALIB_DBG(...)
#define ALIB_ASSERT_ERROR(cond, domain,...)
#define ALIB_LOCK_WITH(lock)
#define Lox_Info(...)
#define Lox_Warning(...)
void Initialize(CursorType startNode, lang::Inclusion includeStartNode)
void SetPathGeneration(lang::Switch pathGeneration)
TAString & Delete(integer regionStart, integer regionLength=MAX_LEN)
integer SearchAndReplace(const TString< TChar > &needle, const TString< TChar > &replacement, integer startIdx=0, integer maxReplacements=strings::MAX_LEN, lang::Case sensitivity=lang::Case::Sensitive, integer endIdx=strings::MAX_LEN)
constexpr integer Length() const
TChar CharAt(integer idx) const
integer IndexOf(const TString &needle, integer startIdx=0, integer endIdx=strings::MAX_LEN) const
integer LastIndexOf(TChar needle, integer startIndex=MAX_LEN) const
TString< TChar > Substring(integer regionStart, integer regionLength=MAX_LEN) const
bool Equals(const TString< TChar > &rhs) const
TSubstring & TrimEnd(const TCString< TChar > &whiteSpaces=CStringConstantsTraits< TChar >::DefaultWhitespaces())
Duration Age() const
Index(const alib::PathString &tagFilePath, const alib::String &baseURL, bool isMainTagFile)
Definition index.cpp:24
const bool IsMainTagFile
Definition index.hpp:242
alib::MonoAllocator ma
The allocator used for the parent #"StringTree" and for the hashtable in the field map.
Definition index.hpp:50
void dedupGroupEntries(alib::StdVectorMA< SearchResult > &targets)
Definition index.cpp:686
void Search(XLink &xLink)
Definition index.cpp:577
alib::Ticks::Duration LoadTime
A timestamp set when loaded.
Definition index.hpp:459
alib::containers::HashMap< alib::MonoAllocator, const alib::String &, CursorHandle, std::hash< alib::String >, std::equal_to< const alib::String >, alib::lang::Caching::Disabled, alib::Recycling::None > fileMap
Maps HTML-files found to their corresponding tree nodes.
Definition index.hpp:93
const alib::String & BaseURL
The URL of the HTML-output created with this tag-file.
Definition index.hpp:233
ConstCursorHandle GetHTMLFileEntity(const alib::FTFile &htmlFile)
Definition index.cpp:213
int fileNameDotComponentsSize
The number of components in fileNameDotComponents.
Definition index.hpp:251
alib::PathString FilePath
The path to the doxygenTagFile.
Definition index.hpp:227
void Load()
Loads the tag-file and creates the index.
Definition index.cpp:76
void ReplaceToTreeSeparator(alib::AString &buffer, Target::Kinds kind, alib::integer startPos=0)
Definition index.cpp:223
alib::containers::HashMap< alib::MonoAllocator, AnchorKey, CursorHandle, AnchorKey::Hash, std::equal_to< AnchorKey >, alib::lang::Caching::Enabled > anchorMap
Maps HTML-files found to their corresponding tree nodes.
Definition index.hpp:101
void ReplaceFromTreeSeparator(alib::AString &buffer, Target::Kinds kind, alib::integer startPos=0)
Definition index.cpp:230
void searchFile(XLink &xLink)
Definition index.cpp:288
void evaluateEntity(XLink &xLink, Node node, bool isIndirectByInheritance, bool isIndirectByTypeDef)
Definition index.cpp:347
void loadTagFile()
Loads the tag-file. This is called by Load.
Definition tagfile.cpp:371
Node ImportNode(CursorHandle handle)
Definition index.hpp:490
alib::containers::HashMap< alib::MonoAllocator, alib::String, CursorHandle > entityMap
Definition index.hpp:84
bool ScopeHintMatch(Node entry, XLink &searchLink)
Definition index.cpp:239
alib::SharedLock SLock
Definition index.hpp:238
alib::PathString FileName
The base name component of FilePath.
Definition index.hpp:230
Target::KindStats KindStats
Statistics on the number of entities found per kind in #"Target::Kinds;2".
Definition index.hpp:378
StringTree TreeType
The type of the string tree that holds the tag-file.
Definition index.hpp:47
~Index()
Destructor.
Definition index.cpp:62
alib::String fileNameDotComponents[10]
Definition index.hpp:248
static Target * GetRootNodeTarget()
Definition target.hpp:246
bool IsA(Kinds aKind) const
Definition target.hpp:241
Kinds Kind() const
Definition target.hpp:236
alib::String HTMLFile
The HTML file that this target links to (or into).
Definition target.hpp:220
Kinds
Enumerates the kinds of compounds found in a the Doxygen tagfile.
Definition target.hpp:28
@ Struct
Denotes a struct.
Definition target.hpp:37
@ Function
Denotes a namespace- or member-function.
Definition target.hpp:47
@ Variable
Denotes a namespace- or member-variable.
Definition target.hpp:46
@ UNSPECIFIED
Used with the field #"XLink::KindSpec;2".
Definition target.hpp:57
@ Union
Denotes a union.
Definition target.hpp:39
@ Class
Denotes a class.
Definition target.hpp:38
@ UNKNOWN_COMPOUND
Definition target.hpp:54
@ Typedef
Denotes a type definition.
Definition target.hpp:45
@ File
Denotes a source file.
Definition target.hpp:31
@ EnumElement
Denotes an enumeration element.
Definition target.hpp:49
@ Concept
Denotes a C++20 concept.
Definition target.hpp:40
@ Macro
Denotes a preprocessor definition.
Definition target.hpp:44
@ Dir
Denotes a source folder.
Definition target.hpp:30
@ Page
Denotes a page.
Definition target.hpp:32
@ Group
Denotes a group.
Definition target.hpp:33
@ Enumeration
Denotes an enumeration.
Definition target.hpp:48
@ FILEPATH_COMPONENT
A node of a file path (not a doxygen kind).
Definition target.hpp:53
@ Namespace
Denotes a namespace.
Definition target.hpp:36
@ DocAnchor
Denotes a preprocessor definition.
Definition target.hpp:34
@ RECORD
Mask to identify records types.
Definition target.hpp:68
int LineNo
The line number in the Doxygen tag-file where this entity is defined.
Definition target.hpp:217
monomem::TLocalAllocator< 1 > LocalAllocator1K
LocalString< 8 > String8
constexpr const String EMPTY_STRING
lang::integer integer
strings::TString< character > String
strings::TSubstring< character > Substring
strings::TString< PathCharType > PathString
filetree::FTFile FTFile
time::Ticks Ticks
constexpr PathCharType DIRECTORY_SEPARATOR
strings::TAString< character, lang::HeapAllocator > AString
std::vector< T, StdMA< T > > StdVectorMA
containers::StringTreeIterator< TTree > StringTreeIterator
todox
Definition doxyfile.cpp:20
const TGT * Cast(const Index::Node &node)
Definition index.hpp:544
HashTable< TAllocator, typename NodeKey::ValueDescriptor, typename NodeKey::Hash, typename NodeKey::EqualTo, lang::Caching::Enabled, TRecycling > nodeTable
Index & index
The index to load.
Definition jobs.hpp:28
bool Do() override
Definition index.cpp:21
A pod-like struct providing the key for the hash table found in the field #"Index::anchorMap;2".
Definition index.hpp:53
The cursor type of the #"StringTree".
Definition index.hpp:105
const alib::String & HTMLFile() const
Definition index.hpp:187
const Target * Target() const
Definition index.hpp:176
Index & Index() const
Definition index.hpp:173
bool IsA(Target::Kinds kind) const
Definition index.hpp:197
Target::Kinds Kind() const
Definition index.hpp:192
Node()=default
Defaulted default constructor. Creates an invalid node.
int Match(TemplateArguments &target)
Definition target.cpp:239