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"
13#include "ALib.System.H"
14
15using namespace alib;
16using namespace std;
17
18namespace dxl {
19
20bool IndexLoader::Do() { index.Load(); return true; }
21
22// create the file name from the path
23Index::Index(const system::PathString& tagFilePath, const String& baseURL, bool isMainTagFile )
24: TreeType{ma, '@'}
25, ma {ALIB_DBG("DL Index", ) 1024, 200}
26, entityMap {ma}
27, fileMap {ma}
28, anchorMap {ma}
29, FilePath {tagFilePath}
30, BaseURL {baseURL}
31, IsMainTagFile{isMainTagFile} {
32
33 #if ALIB_DEBUG_CRITICAL_SECTIONS
34 nodeTable.dcs.DCSLock= &SLock;
35 entityMap.dcs.DCSLock= &SLock;
36 fileMap .dcs.DCSLock= &SLock;
37 anchorMap.dcs.DCSLock= &SLock;
38 #endif
39
41
42 // create the file name from the path
43 FileName= tagFilePath;
44 integer slashPos= std::max(FileName.LastIndexOf('/'), FileName.LastIndexOf('\\'));
45 if (slashPos > 0)
46 FileName= FileName.Substring(slashPos+1);
47
48 // split file-name by dots
50 String backwardsParser= FileName;
51 for (;;) {
52 integer dotPos= backwardsParser.LastIndexOf('.');
53 if (dotPos < 0) {
55 break;
56 }
57 fileNameDotComponents[fileNameDotComponentsSize++]= backwardsParser.Substring(dotPos + 1);
58 backwardsParser= backwardsParser.Substring(0, dotPos);
59 }
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 and namespaces
130 fileMap.EmplaceUnique( tag.HTMLFile, entityIterator.Node().Export() );
131 }
132
133 // add Members to the anchor-map
134 else if (auto* member= Cast<TGTMember>(&tag); member ) {
135 auto result= anchorMap.InsertIfNotExistent(
136 AnchorKey{ tag.HTMLFile, member->Anchor },
137 entityIterator.Node().Export() );
138 if ( !result.second ) {
139 Lox_Info( "In HTML file {!Q}, the anchor {!Q} already exists. (Skipped)\n"
140 " Previous anchor: {}:{} Kind: {:10} FileName: {}\n"
141 " New anchor: {}:{} Kind: {:10} FileName: {}"
142 ,tag.HTMLFile, member->Anchor
143 , FilePath, ImportNode(result.first.Mapped()).LineNo()
144 , ImportNode(result.first.Mapped()).Kind()
145 , ImportNode(result.first.Mapped()).HTMLFile()
146 , FilePath, tag.LineNo, tag.Kind(), tag.HTMLFile
147 )
148 }
149 }
150 // add DocAnchors in the anchor-map used with local links for members
151 else if (auto* docAnchor= Cast<TGTDocAnchor>(&tag); docAnchor ) {
152 auto result= anchorMap.InsertIfNotExistent(
153 AnchorKey{ tag.HTMLFile, docAnchor->Name },
154 entityIterator.Node().Export() );
155 if ( !result.second ) {
156 Lox_Warning( "In HTML file {!Q}, the DocAnchor {!Q} already exists. (Skipped)\n"
157 " Previous anchor: {}:{} Kind: {:10} FileName: {}\n"
158 " New anchor: {}:{} Kind: {:10} FileName: {}"
159 ,tag.HTMLFile, docAnchor->Name
160 , FilePath, ImportNode(result.first.Mapped()).LineNo()
161 , ImportNode(result.first.Mapped()).Kind()
162 , ImportNode(result.first.Mapped()).HTMLFile()
163 , FilePath, tag.LineNo, tag.Kind(), tag.HTMLFile
164 )
165 }
166 }
167
168 // cut template specialization args from record names
169 if (auto* scu= Cast<TGTRecord>(&tag); scu) {
170 if ( scu->SpecializationArgs ) {
171 integer bracePos= name.IndexOf('<');
172 if (bracePos>0) {
173 name= name.Substring(0, bracePos);
174 name.TrimEnd();
175 }
176 }
177 ALIB_ASSERT_ERROR(name.IndexOf('<') < 0, "DXL/XLINK",
178 "Parse error (only specialization args should appear in the name and those "
179 "have been removed already.")
180 }
181
182 // cut parameters from function names
183 else if ( auto* mf= Cast<TGTFunction>(&tag); mf ) {
184 if ( mf->Args
185 || mf->Qualifiers.IsNotEmpty() ) {
186 integer bracePos= name.LastIndexOf('(');
187 if ( bracePos > 0)
188 name= name.Substring(0, bracePos);
189 }
190 }
191
192 entityMap.Insert( {name, entityIterator.Node().Export()} );
193 entityIterator.Next();
194 }
195
196 ALIB_ASSERT_ERROR(entityMap.Size() == Size(), "DXL/XLINK",
197 "Expected size of entityMap {} != {} real size.", Size() , entityMap.Size())
198
199 ALIB_ASSERT_ERROR(expectedFileMapSize == fileMap.Size(), "DXL/XLINK",
200 "Expected size of fileMap {} != {} real size.", expectedFileMapSize , fileMap.Size())
201
202 ALIB_ASSERT_ERROR(expectedAnchorMapSize >= anchorMap.Size(), "DXL/XLINK",
203 "Expected size of anchorMap {} < {} real size.", expectedAnchorMapSize, anchorMap.Size())
204
205 LoadTime= startTime.Age();
206
207} // ReSharper restore CppDFAUnreachableCode
208
209Index::ConstCursorHandle Index::GetHTMLFileEntity(const File& htmlFile) {
211 auto it= fileMap.Find(htmlFile.Name());
212 if ( it == fileMap.end()) {
213 Lox_Warning( "HTML-File {!Q} not found in index: ", htmlFile.Name() )
214 return CursorHandle(0);
215 }
216 return it->second;
217}
218
220 if ( HasOneOf(kind, Target::Dir | Target::File | Target::FILEPATH_COMPONENT) )
222 else
223 buffer.SearchAndReplace( "::", String8(Separator()), startPos);
224}
225
227 if ( buffer.CharAt(startPos) == Separator() )
228 buffer.Delete(startPos, 1);
229 if ( HasOneOf(kind, Target::Dir | Target::File | Target::FILEPATH_COMPONENT) )
231 else
232 buffer.SearchAndReplace(String8(Separator()), "::");
233
234}
235bool Index::ScopeHintMatch(Index::Node entry, XLink& searchLink) {
236 if ( searchLink.HintsSize() == 0 )
237 return true;
238
239 // build path stack from string tree
240 int stackSize= 0;
241 String pathNameStack[32];
242 auto parent= entry.Parent();
243 while (!parent.IsRoot()) {
244 pathNameStack[stackSize++]= parent.Name();
245 parent= parent.Parent();
246 }
247 for (int i= 0; i < fileNameDotComponentsSize; ++i)
248 pathNameStack[stackSize++]= fileNameDotComponents[i];
249
250 // add tag-file name
251 {
252 system::PathString tagFileName= entry.Index().FileName;
253
254 for (;;) {
255 integer dotPos= tagFileName.LastIndexOf('.');
256 if (dotPos < 0) {
257 pathNameStack[stackSize++]= tagFileName;
258 break;
259 }
260 pathNameStack[stackSize++]= tagFileName.Substring(dotPos + 1);
261 tagFileName= tagFileName.Substring(0, dotPos);
262 }
263 }
264
265
266 // search hints in the path-stack
267 int stackPointer= stackSize-1;
268 integer pos= 0;
269 int hintNo = 0;
270 for (;;) {
271 pos= pathNameStack[stackPointer].IndexOf<CHK, lang::Case::Ignore>(
272 searchLink.Hint(hintNo), pos );
273 if ( pos >= 0 ) {
274 if ( ++hintNo == searchLink.HintsSize())
275 return true;
276 pos= pos + searchLink.Hint(hintNo).Length();
277 continue;
278 }
279
280 if ( --stackPointer < 0)
281 return false;
282 pos= 0;
283 }
284}
285
286void Index::searchFile( XLink& xLink ) {
287 if (xLink.KindSpec != Target::File || !xLink.NoIndirectionWarning )
289 for ( auto range= entityMap.EqualRange(xLink.Name()) ;
290 range.first!=range.second ;
291 ++range.first) {
292 Node node= ImportNode(range.first->second);
293 // String256 dbgPath;
294 // node.AssemblePath(dbgPath);
295 if ( !node.IsA(Target::File |Target::Dir) )
296 continue;
297
298 xLink.DidYouMeanSameName.emplace_back(node);
299
300 //------------- check scope -------------
301 // check parent scope components (those attached with "::" to the target name. Have to match exactly)
302 if ( xLink.ScopeSize() ) {
303 Node parent= node.Parent();
304 bool foundParentScope= true;
305 for (int i= xLink.ScopeSize() - 1; i>= 0 ; --i) {
306 String componentName= xLink.Scope(i);
307 if ( !parent.IsValid() || !parent.Name().Equals(componentName) ) {
308 foundParentScope= false;
309 break;
310 }
311 parent= parent.Parent();
312 }
313
314 if (!foundParentScope)
315 continue;
316 }
317
318 // check path hints
319 // (those prepended separated by a space to the target path. Substring match is enough)
320 if (!ScopeHintMatch(node, xLink))
321 continue;
322
323 // check kind
324 // (The first check is probably not needed, as only if the typespec is given, we search
325 // for files and folders. But let's keep it in.)
326 if ( xLink.KindSpec != Target::UNSPECIFIED
327 && xLink.KindSpec != node.Kind() )
328 continue;
329
330 // add result
331 xLink.Targets.push_back({ node
332 ,BaseURL
333 , node.HTMLFile()
335 ,false,false,false,false,false,false,false
336 });
337 }
338 } // unlock index
339
340 // dedup group entries (this is also done with other search methods)
341 if (xLink.Targets.size() > 1)
343}
344
346 bool isIndirectByInheritance, bool isIndirectByTypeDef ) {
347 const Target* target= node.Target();
348
349 //------- searching a function, but the entry is not a function or a definition? ----
350 if ( xLink.Args ) {
351 if ( !target->IsA(Target::Function | Target::Macro) )
352 return;
353 xLink.DidYouMeanFunctionOverload.emplace_back(node);
354 }
355
356 //------ searching an array variable, but the entry is not a variable? ------
357 if ( xLink.Subscript!=nullptr) {
358 auto* var= Cast<TGTVariable>(target);
359 if (!var)
360 return;
361 if (var->Subscript.IndexOf(xLink.Subscript) < 0) {
362 xLink.DidYouMeanVariable.push_back(node);
363 return;
364 }
365 }
366
367 //------ searching template type? ----------------------
368 if ( xLink.TemplateArgs) {
369 // result is not a template?
370 auto* rec= Cast<TGTRecord>(target);
371 if ( !rec) {
372 xLink.DidYouMeanNotATemplate.push_back(node);
373 return;
374 }
375 if (!rec->TemplateArgs) {
376 xLink.DidYouMeanNotATemplate.push_back(node);
377 return;
378 }
379
380 // args don't match?
381 int match= xLink.TemplateArgs->Match(*rec->TemplateArgs);
382 if ( match == 0) {
383 xLink.DidYouMeanTemplateType= node;
384 return;
385 }
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
409 // ------------------------- "Typedef in inner path" erasion rule --------------------------
410 // 1. Skip this result if it is "just" a typedef and a deeper object exists
411 bool skipThis= false;
412 if ( target->IsA(Target::Typedef) )
413 for (auto& it : xLink.Targets ) {
414 if ( it.Node.IsA(Target::RECORD | Target::Enumeration) ) {
415
416 Node parent = it.Node.Parent();
417 while (parent.IsValid()) {
418 if (parent == node.Parent()) {
419 skipThis= true;
420 break;
421 }
422 parent= parent.Parent();
423 } }
424 if (skipThis) break;
425 }
426
427 if ( skipThis ) return;
428
429 // 2. Erase an existing result if it is "just" a typedef while this is a deeper object
430 if ( target->IsA(Target::RECORD | Target::Enumeration) )
431 std::erase_if(xLink.Targets, [&](const auto& it) {
432 if ( !it.Node.IsA(Target::Typedef) )
433 return false;
434 Node parent = node.Parent();
435 while (parent.IsValid()) {
436 if ( parent == it.Node.Parent())
437 return true;
438 parent= parent.Parent();
439 }
440 return false; // Keep this result
441 });
442
443
444 // ------------------------- "Prefer outer entities" erasion rule --------------------------
445 // 1. Remove existing results that are children of this one
446 std::erase_if(xLink.Targets, [&,node](const auto& it) {
447 Node parent = it.Node.Parent();
448 while (parent.IsValid()) {
449 if (parent == node)
450 return true; // Delete this result
451 parent = parent.Parent();
452 }
453 return false; // Keep this result
454 });
455
456 // 2. Skip this result if it is a child of one of the others.
457 for (auto& it : xLink.Targets) {
458 Node parent = node.Parent();
459 while (parent.IsValid()) {
460 if (parent == it.Node) {
461 skipThis= true;
462 break;
463 }
464 parent= parent.Parent();
465 }
466 if (skipThis) break;
467 }
468 if (skipThis) return;
469
470
471 //--------------- check function arguments ---------------
472 int funcArgMatch= 1;
473 if ( target->IsA(Target::Function | Target::Macro) ) {
474 // with functions, we can use the MATCH method directly
475 if ( target->IsA(Target::Function) )
476 funcArgMatch= Target::FunctionArguments::MATCH( xLink.Args,
477 Cast<TGTFunction,NC>(target)->Args );
478
479 // with definitions, we have to check if the target is a prepro macro or a
480 // prepro constant
481 else {
482 auto* targetArgs= Cast<TGTMacro,NC>(target)->Args;
483 if ( xLink.Args && !targetArgs)
484 funcArgMatch= 0;
485 else
486 funcArgMatch= Target::FunctionArguments::MATCH(xLink.Args, targetArgs);
487 }
488
489 if ( funcArgMatch == 0)
490 return;
491
492 // check if one had a better result before.
493 bool hasBetterMatch= false;
494 std::erase_if(xLink.Targets, [&](const auto& it) {
495 if ( it.FunctionArgumentMatch < funcArgMatch)
496 return true;
497 if ( it.FunctionArgumentMatch > funcArgMatch)
498 hasBetterMatch= true;
499 return false;
500 });
501
502 if ( hasBetterMatch)
503 return;
504 }
505
506 // check qualifiers
507 bool qualifiersHintMatch= false;
508 if (xLink.Qualifiers.IsNotNull()) {
509 if ( !target->IsA(Target::Function)
510 || Cast<TGTFunction,NC>(target)->Qualifiers.IndexOf(xLink.Qualifiers) < 0)
511 return;
512 qualifiersHintMatch= true;
513
514 // remove functions that did not match in respect to Qualifiers
515 std::erase_if(xLink.Targets, [&,node](const auto& it) {
516 return it.Node.IsA(Target::Function)
517 && Cast<TGTFunction,NC>(it.Node)->Qualifiers.IsEmpty();
518 });
519 }
520 else {
521 if ( auto* func= Cast<TGTFunction>(target); func ) {
522 if ( func->Qualifiers.IsNotEmpty()) {
523 bool hasBetterMatch= false;
524 for ( auto& it : xLink.Targets) {
525 if ( auto* f= Cast<TGTFunction>(it.Node); f ) {
526 hasBetterMatch= f->Qualifiers.IsEmpty();
527 break;
528 }
529 }
530 if ( hasBetterMatch)
531 return;
532 }
533 else // todo: the case where no qualifiers are given is now resolved later in dxl
534 // disambiguation. So this can be deleted I guess (have a try)
535 // In general: we have to check again what goes where best.
536 std::erase_if(xLink.Targets, [&,node](const auto& it) {
537 return it.Node.IsA(Target::Function)
538 && Cast<TGTFunction,NC>(it.Node)->Qualifiers.IsNotEmpty();
539 });
540
541 }
542 }
543
544 // rule: Template class beats deduction guide if no function args are given
545 {
546 std::erase_if(xLink.Targets, [&](const auto& it) {
547
548 // within the same scope?
549 if ( it.Node.Parent() == node.Parent() ) {
550 if (target->IsA(Target::RECORD)) {
551 if ( it.Node.IsA(Target::Function)
552 && xLink.Args==nullptr)
553 return true;
554 }
555 }
556
557 return false;
558 });
559 }
560
561
562 // add result
563 xLink.Targets.push_back({ node
564 ,BaseURL
565 ,target->HTMLFile
566 , target->IsA(Target::MEMBER) ? Cast<TGTMember ,NC>(target)->Anchor
567 : target->IsA(Target::DocAnchor) ? Cast<TGTDocAnchor,NC>(target)->Name
569 ,funcArgMatch
570 ,qualifiersHintMatch
571 ,isIndirectByInheritance
572 ,isIndirectByTypeDef
573 ,false ,false, false
574 });
575
576}
577
578// -------------------------------------------------------------------------------------------------
579// -------- Search ----------------------------------------------------------------
580// -------------------------------------------------------------------------------------------------
581void Index::Search( XLink& xLink ) {
582 // special treatment for files
583 if ( HasOneOf(xLink.KindSpec, Target::Dir | Target::File) ) {
584 searchFile(xLink);
585 return;
586 }
587
588 //------------------------------ loop over all entities of the target name -------------------
589 // first we collect the results. Otherwise, we have a problem with recursive locking,
590 // because when resolving the possible entities, recursive searches in all indices might
591 // occur. (Currently this is donte for example with GetLinkToParent())
593 StdVectorMA<CursorHandle> results(la);
594 results.reserve(1024/sizeof(CursorHandle) - 4);
596 for ( auto range= entityMap.EqualRange( xLink.Name()) ; range.first!=range.second ; ++range.first)
597 results.push_back(range.first->second);
598 }
599
600 for ( auto handle : results ) {
601
602 // get cursor and check if it is a real target
603 Node node= ImportNode(handle);
606 continue;
607
608 // store in general "did you mean..." list
609 xLink.DidYouMeanSameName.emplace_back(node);
610
611 // check if kind is specified and if so, if it fits
612 if ( xLink.KindSpec != Target::UNSPECIFIED
613 && !HasOneOf(xLink.KindSpec, node.Kind() ) )
614 continue;
615
616 //------------- check scope -------------
617 bool scopeMatches= true;
618 {
619 Node parent= node.Parent();
620
621 // check parent scope components
622 if ( xLink.ScopeSize() ) {
623 int fileNameComponentIdx= -1;
624 for (int i= xLink.ScopeSize() - 1; i>= 0 ; --i) {
625 String componentName= xLink.Scope(i);
626 integer templatePos= componentName.IndexOf('<');
627 if ( templatePos > 0 )
628 componentName= componentName.Substring(0, templatePos);
629
630 if ( !parent.IsRoot() ) {
631 if ( !componentName.Equals( parent.Name() ) ) {
632 scopeMatches= false;
633 break;
634 }
635 parent= parent.Parent();
636 } else {
637 if ( ++fileNameComponentIdx >= fileNameDotComponentsSize
638 || !componentName.Equals( fileNameDotComponents[fileNameComponentIdx] ) ){
639 scopeMatches= false;
640 break;
641 }
642 }
643 }
644 }
645 if ( scopeMatches && xLink.IsLocal)
646 scopeMatches &= (parent.Export().value == xLink.LocalLinkEntity.value);
647
648 // check path hints
649 // (those prepended separated by a space to the target path. Substring match is enough)
650 scopeMatches= scopeMatches && ScopeHintMatch(node, xLink);
651 }
652
653 // if the scope matched, we give it a chance
654 if ( scopeMatches )
655 evaluateEntity(xLink, node, false, false); // if it fits, the node is added to the XLink's Targets.
656 } // loop over all entities
657
658 // if we now have exactly one match, we stop here.
659 if (xLink.Targets.size() == 1)
660 return;
661
662 // ---- wrong scope? Search for inherited members and Type definition target's members ---------
663 if ( xLink.ScopeSize() || xLink.IsLocal ) {
664 // get the parent XLink. This call also creates the vector link.BaseTypes
665 xLink.GetLinkToParent();
666
667 //---------------------------- loop over all entities of the target name -------------------
668 for ( auto cursorHandle : results ) {
669 Node node = ImportNode(cursorHandle);
670
671 //----------- check inheritance: is the current node a member of a parent? ----------
672 if ( xLink.BaseTypes )
673 for (Node& inheritanceParent : *xLink.BaseTypes) {
674 if (inheritanceParent == node.Parent())
675 evaluateEntity(xLink, node, true, false);
676 }
677
678 //------------- if not inherited, check if it is trough a type-definition --------
679 if ( xLink.TypeDefinitionTargets)
680 for (auto& typeDefTarget : *xLink.TypeDefinitionTargets) {
681 if (typeDefTarget == node.Parent() )
682 evaluateEntity(xLink, node, false, true);
683 }
684 } // loop over entities
685 } // XLink has outer scope
686
687
688 // finally dedup group entries (this is also done with other search methods)
689 if (xLink.Targets.size() > 1)
691}
692
694
695 bool hasNonGroupResults= false;
696 for (auto& it : targets)
697 if ( it.Node.Parent().IsRoot()
698 || !it.Node.Parent().IsA(Target::Group) ) {
699 hasNonGroupResults= true;
700 break;
701 }
702 if ( hasNonGroupResults)
703 std::erase_if(targets, [](const auto& it) {
704 return !it.Node.Parent().IsRoot()
705 && it.Node.Parent().IsA(Target::Group);
706 });
707}
708
709} //namespace [dxl]
710
#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
alib::system::PathString FilePath
The path to the doxygenTagFile.
Definition index.hpp:227
ConstCursorHandle GetHTMLFileEntity(const alib::File &htmlFile)
Definition index.cpp:209
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:693
void Search(XLink &xLink)
Definition index.cpp:581
alib::Ticks::Duration LoadTime
A timestamp set when loaded.
Definition index.hpp:458
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
int fileNameDotComponentsSize
The number of components in fileNameDotComponents.
Definition index.hpp:251
alib::system::PathString FileName
The base name component of FilePath.
Definition index.hpp:230
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:219
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:226
void searchFile(XLink &xLink)
Definition index.cpp:286
void evaluateEntity(XLink &xLink, Node node, bool isIndirectByInheritance, bool isIndirectByTypeDef)
Definition index.cpp:345
void loadTagFile()
Loads the tag-file. This is called by Load.
Definition tagfile.cpp:372
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:235
alib::SharedLock SLock
Definition index.hpp:238
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(const alib::system::PathString &tagFilePath, const alib::String &baseURL, bool isMainTagFile)
Definition index.cpp:23
~Index()
Destructor.
Definition index.cpp:62
alib::String fileNameDotComponents[10]
Definition index.hpp:248
static Target * GetRootNodeTarget()
Definition target.hpp:247
bool IsA(Kinds aKind) const
Definition target.hpp:240
Kinds Kind() const
Definition target.hpp:235
alib::String HTMLFile
The HTML file that this target links to (or into).
Definition target.hpp:219
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:46
@ Variable
Denotes a namespace- or member-variable.
Definition target.hpp:45
@ UNSPECIFIED
Used with the field #"XLink::KindSpec;2".
Definition target.hpp:56
@ Union
Denotes a union.
Definition target.hpp:39
@ Class
Denotes a class.
Definition target.hpp:38
@ UNKNOWN_COMPOUND
Definition target.hpp:53
@ Typedef
Denotes a type definition.
Definition target.hpp:44
@ File
Denotes a source file.
Definition target.hpp:31
@ EnumElement
Denotes an enumeration element.
Definition target.hpp:48
@ Concept
Denotes a C++20 concept.
Definition target.hpp:40
@ Macro
Denotes a preprocessor definition.
Definition target.hpp:43
@ 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:47
@ FILEPATH_COMPONENT
A node of a file path (not a doxygen kind).
Definition target.hpp:52
@ 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:67
int LineNo
The line number in the Doxygen tag-file where this entity is defined.
Definition target.hpp:216
strings::TString< PathCharType > PathString
constexpr PathCharType DIRECTORY_SEPARATOR
monomem::TLocalAllocator< 1 > LocalAllocator1K
files::File File
LocalString< 8 > String8
constexpr const String EMPTY_STRING
lang::integer integer
strings::TString< character > String
strings::TSubstring< character > Substring
time::Ticks Ticks
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:20
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:241