From aca13723a9373a1080ca7f108e7be0905b9ae793 Mon Sep 17 00:00:00 2001 From: Dimitri van Heesch Date: Thu, 27 Feb 2020 22:38:22 +0100 Subject: Restructure the way RefLists are handled --- src/classdef.cpp | 2 +- src/commentscan.l | 52 +++++------- src/definition.cpp | 26 +++--- src/definition.h | 6 +- src/definitionimpl.h | 8 +- src/docparser.cpp | 20 ++--- src/doxygen.cpp | 19 ++--- src/doxygen.h | 1 - src/entry.cpp | 9 --- src/entry.h | 6 +- src/filedef.cpp | 2 +- src/groupdef.cpp | 2 +- src/linkedmap.h | 84 +++++++++++++++++++ src/memberdef.cpp | 2 +- src/membergroup.cpp | 4 +- src/membergroup.h | 10 +-- src/namespacedef.cpp | 2 +- src/pagedef.cpp | 4 +- src/reflist.cpp | 225 ++++++++++++--------------------------------------- src/reflist.h | 134 ++++++++++++++++++++---------- src/section.h | 74 +++-------------- src/tagreader.cpp | 2 +- src/types.h | 6 -- src/util.cpp | 46 ++++------- src/util.h | 11 ++- 25 files changed, 334 insertions(+), 423 deletions(-) create mode 100644 src/linkedmap.h diff --git a/src/classdef.cpp b/src/classdef.cpp index 61ae528..2124817 100644 --- a/src/classdef.cpp +++ b/src/classdef.cpp @@ -4424,7 +4424,7 @@ void ClassDefImpl::addListReferences() if (!isLinkableInProject()) return; //printf("ClassDef(%s)::addListReferences()\n",name().data()); { - const std::vector &xrefItems = xrefListItems(); + const std::vector &xrefItems = xrefListItems(); addRefItem(xrefItems, qualifiedName(), lang==SrcLangExt_Fortran ? theTranslator->trType(TRUE,TRUE) diff --git a/src/commentscan.l b/src/commentscan.l index 9c38e18..053436c 100644 --- a/src/commentscan.l +++ b/src/commentscan.l @@ -54,6 +54,7 @@ #include "reflist.h" #include "section.h" #include "util.h" +#include "reflist.h" // forward declarations static bool handleBrief(yyscan_t yyscanner,const QCString &, const QCStringList &); @@ -2781,49 +2782,37 @@ static void addXRefItem(yyscan_t yyscanner, if (listName==0) return; //printf("addXRefItem(%s,%s,%s,%d)\n",listName,itemTitle,listTitle,append); - const ListItemInfo *lii=0; - RefList *refList = Doxygen::xrefLists->find(listName); - if (refList==0) // new list - { - refList = new RefList(listName,listTitle,itemTitle); - Doxygen::xrefLists->insert(listName,refList); - //printf("new list!\n"); - } - for (const ListItemInfo &item : yyextra->current->sli) + RefList *refList = RefListManager::instance().add(listName,listTitle,itemTitle); + RefItem *item = 0; + for (RefItem *i : yyextra->current->sli) { - if (qstrcmp(item.type,listName)==0) + if (i && qstrcmp(i->list()->listName(),listName)==0) { //printf("found %s lii->type=%s\n",listName,lii->type); - lii = &item; + item = i; break; } } - if (lii && append) // already found item of same type just before this one + if (item && append) // already found item of same type just before this one { //printf("listName=%s item id = %d existing\n",listName,lii->itemId); - RefItem *item = refList->getRefItem(lii->itemId); - ASSERT(item!=0); - item->text += "

"; - item->text += yyextra->outputXRef; + item->setText(item->text() + "

" + yyextra->outputXRef); //printf("%s: text +=%s\n",listName,item->text.data()); } else // new item { - int itemId = refList->addRefItem(); //printf("listName=%s item id = %d new yyextra->current=%p\n",listName,itemId,yyextra->current); // if we have already an item from the same list type (e.g. a second @todo) // in the same Entry (i.e. lii!=0) then we reuse its link anchor. - char anchorLabel[1024]; - //sprintf(anchorLabel,"_%s%06d",listName,lii ? lii->itemId : itemId); - sprintf(anchorLabel,"_%s%06d",listName,itemId); - RefItem *item = refList->getRefItem(itemId); - ASSERT(item!=0); - item->text = yyextra->outputXRef; - item->listAnchor = anchorLabel; - yyextra->current->addSpecialListItem(listName,itemId); + item = refList->add(); + QCString anchorLabel; + anchorLabel.sprintf("_%s%06d",listName,item->id()); + item->setText(yyextra->outputXRef); + item->setAnchor(anchorLabel); + yyextra->current->sli.push_back(item); QCString cmdString; - cmdString.sprintf(" \\xrefitem %s %d.",listName,itemId); + cmdString.sprintf(" \\xrefitem %s %d.",listName,item->id()); if (yyextra->inBody) { yyextra->current->inbodyDocs += cmdString; @@ -2832,22 +2821,23 @@ static void addXRefItem(yyscan_t yyscanner, { yyextra->current->doc += cmdString; } + SectionManager &sm = SectionManager::instance(); const SectionInfo *si = sm.find(anchorLabel); if (si) { if (si->lineNr() != -1) { - warn(listName,yyextra->lineNr,"multiple use of section label '%s', (first occurrence: %s, line %d)",anchorLabel,si->fileName().data(),si->lineNr()); + warn(listName,yyextra->lineNr,"multiple use of section label '%s', (first occurrence: %s, line %d)",anchorLabel.data(),si->fileName().data(),si->lineNr()); } else { - warn(listName,yyextra->lineNr,"multiple use of section label '%s', (first occurrence: %s)",anchorLabel,si->fileName().data()); + warn(listName,yyextra->lineNr,"multiple use of section label '%s', (first occurrence: %s)",anchorLabel.data(),si->fileName().data()); } } else { - si = sm.add(listName,yyextra->lineNr,anchorLabel, + si = sm.add(anchorLabel,listName,yyextra->lineNr, yyextra->sectionTitle,SectionType::Anchor, yyextra->sectionLevel); yyextra->current->anchors.push_back(si); @@ -2902,7 +2892,7 @@ static void addSection(yyscan_t yyscanner) // create a new section element yyextra->sectionTitle+=yytext; yyextra->sectionTitle=yyextra->sectionTitle.stripWhiteSpace(); - si = sm.add(yyextra->fileName,yyextra->lineNr,yyextra->sectionLabel, + si = sm.add(yyextra->sectionLabel,yyextra->fileName,yyextra->lineNr, yyextra->sectionTitle,sectionLevelToType(yyextra->sectionLevel), yyextra->sectionLevel); @@ -3082,7 +3072,7 @@ static void addAnchor(yyscan_t yyscanner,const char *anchor) } else { - si = sm.add(yyextra->fileName,yyextra->lineNr,anchor,0,SectionType::Anchor,0); + si = sm.add(anchor,yyextra->fileName,yyextra->lineNr,nullptr,SectionType::Anchor,0); yyextra->current->anchors.push_back(si); } } diff --git a/src/definition.cpp b/src/definition.cpp index 00f2bc5..043e210 100644 --- a/src/definition.cpp +++ b/src/definition.cpp @@ -44,6 +44,7 @@ #include "dirdef.h" #include "pagedef.h" #include "bufstr.h" +#include "reflist.h" //----------------------------------------------------------------------------------------- @@ -59,7 +60,7 @@ class DefinitionImpl::IMPL MemberSDict *sourceRefByDict = 0; MemberSDict *sourceRefsDict = 0; - std::vector xrefListItems; + std::vector xrefListItems; GroupList *partOfGroups = 0; DocInfo *details = 0; // not exported @@ -1577,7 +1578,7 @@ void DefinitionImpl::makePartOfGroup(GroupDef *gd) m_impl->partOfGroups->append(gd); } -void DefinitionImpl::setRefItems(const std::vector &sli) +void DefinitionImpl::setRefItems(const std::vector &sli) { m_impl->xrefListItems.insert(m_impl->xrefListItems.end(), sli.cbegin(), sli.cend()); } @@ -1593,31 +1594,34 @@ void DefinitionImpl::mergeRefItems(Definition *d) // sort results on itemId std::sort(m_impl->xrefListItems.begin(),m_impl->xrefListItems.end(), - [](const ListItemInfo &left,const ListItemInfo &right) - { return left.itemIdid() id() || + (left->id()==right->id() && + qstrcmp(left->list()->listName(),right->list()->listName())<0); }); // filter out duplicates auto last = std::unique(m_impl->xrefListItems.begin(),m_impl->xrefListItems.end(), - [](const ListItemInfo &left,const ListItemInfo &right) - { return left.itemId==right.itemId && left.type==right.type; }); + [](const RefItem *left,const RefItem *right) + { return left->id()==right->id() && + left->list()->listName()==right->list()->listName(); + }); m_impl->xrefListItems.erase(last, m_impl->xrefListItems.end()); } int DefinitionImpl::_getXRefListId(const char *listName) const { - for (const ListItemInfo &lii : m_impl->xrefListItems) + for (const RefItem *item : m_impl->xrefListItems) { - if (lii.type==listName) + if (item->list()->listName()==listName) { - return lii.itemId; + return item->id(); } } return -1; } -const std::vector &DefinitionImpl::xrefListItems() const +const std::vector &DefinitionImpl::xrefListItems() const { return m_impl->xrefListItems; } diff --git a/src/definition.h b/src/definition.h index 016cbe8..f28b47f 100644 --- a/src/definition.h +++ b/src/definition.h @@ -37,10 +37,10 @@ class MemberSDict; class MemberDef; class GroupDef; class GroupList; -struct ListItemInfo; class SectionInfo; class Definition; class FTextStream; +class RefItem; /** Data associated with a detailed description. */ struct DocInfo @@ -263,7 +263,7 @@ class Definition : public DefinitionIntf virtual GroupList *partOfGroups() const = 0; virtual bool isLinkableViaGroup() const = 0; - virtual const std::vector &xrefListItems() const = 0; + virtual const std::vector &xrefListItems() const = 0; virtual Definition *findInnerCompound(const char *name) const = 0; virtual Definition *getOuterScope() const = 0; @@ -319,7 +319,7 @@ class Definition : public DefinitionIntf virtual void setBodySegment(int bls,int ble) = 0; virtual void setBodyDef(FileDef *fd) = 0; - virtual void setRefItems(const std::vector &sli) = 0; + virtual void setRefItems(const std::vector &sli) = 0; virtual void setOuterScope(Definition *d) = 0; virtual void setHidden(bool b) = 0; diff --git a/src/definitionimpl.h b/src/definitionimpl.h index 1b2ce5b..d66ac93 100644 --- a/src/definitionimpl.h +++ b/src/definitionimpl.h @@ -67,7 +67,7 @@ class DefinitionImpl : virtual public Definition virtual SrcLangExt getLanguage() const; virtual GroupList *partOfGroups() const; virtual bool isLinkableViaGroup() const; - virtual const std::vector &xrefListItems() const; + virtual const std::vector &xrefListItems() const; virtual Definition *findInnerCompound(const char *name) const; virtual Definition *getOuterScope() const; virtual MemberSDict *getReferencesMembers() const; @@ -89,7 +89,7 @@ class DefinitionImpl : virtual public Definition virtual void setBodyDef(FileDef *fd); virtual void addSourceReferencedBy(const MemberDef *d); virtual void addSourceReferences(const MemberDef *d); - virtual void setRefItems(const std::vector &sli); + virtual void setRefItems(const std::vector &sli); virtual void mergeRefItems(Definition *d); virtual void addInnerCompound(const Definition *d); virtual void setOuterScope(Definition *d); @@ -213,7 +213,7 @@ class DefinitionAliasImpl : virtual public Definition { return m_def->partOfGroups(); } virtual bool isLinkableViaGroup() const { return m_def->isLinkableViaGroup(); } - virtual const std::vector &xrefListItems() const + virtual const std::vector &xrefListItems() const { return m_def->xrefListItems(); } virtual Definition *findInnerCompound(const char *name) const { return m_def->findInnerCompound(name); } @@ -249,7 +249,7 @@ class DefinitionAliasImpl : virtual public Definition virtual void setBodyDef(FileDef *fd) {} virtual void addSourceReferencedBy(const MemberDef *d) {} virtual void addSourceReferences(const MemberDef *d) {} - virtual void setRefItems(const std::vector &sli) {} + virtual void setRefItems(const std::vector &sli) {} virtual void mergeRefItems(Definition *d) {} virtual void addInnerCompound(const Definition *d) {} virtual void setOuterScope(Definition *d) {} diff --git a/src/docparser.cpp b/src/docparser.cpp index 4f11698..e26c2ac 100644 --- a/src/docparser.cpp +++ b/src/docparser.cpp @@ -2170,18 +2170,18 @@ DocXRefItem::DocXRefItem(DocNode *parent,int id,const char *key) : bool DocXRefItem::parse() { - RefList *refList = Doxygen::xrefLists->find(m_key); - if (refList && + RefList *refList = RefListManager::instance().find(m_key); + if (refList && ( // either not a built-in list or the list is enabled - (m_key!="todo" || Config_getBool(GENERATE_TODOLIST)) && - (m_key!="test" || Config_getBool(GENERATE_TESTLIST)) && - (m_key!="bug" || Config_getBool(GENERATE_BUGLIST)) && + (m_key!="todo" || Config_getBool(GENERATE_TODOLIST)) && + (m_key!="test" || Config_getBool(GENERATE_TESTLIST)) && + (m_key!="bug" || Config_getBool(GENERATE_BUGLIST)) && (m_key!="deprecated" || Config_getBool(GENERATE_DEPRECATEDLIST)) - ) + ) ) { - RefItem *item = refList->getRefItem(m_id); + RefItem *item = refList->find(m_id); ASSERT(item!=0); if (item) { @@ -2193,16 +2193,16 @@ bool DocXRefItem::parse() else { m_file = refList->fileName(); - m_anchor = item->listAnchor; + m_anchor = item->anchor(); } m_title = refList->sectionTitle(); //printf("DocXRefItem: file=%s anchor=%s title=%s\n", // m_file.data(),m_anchor.data(),m_title.data()); - if (!item->text.isEmpty()) + if (!item->text().isEmpty()) { docParserPushContext(); - internalValidatingParseDoc(this,m_children,item->text); + internalValidatingParseDoc(this,m_children,item->text()); docParserPopContext(); } } diff --git a/src/doxygen.cpp b/src/doxygen.cpp index 4021332..6a0f228 100644 --- a/src/doxygen.cpp +++ b/src/doxygen.cpp @@ -143,7 +143,6 @@ QIntDict Doxygen::memGrpInfoDict(1009); // dictionary of the me PageDef *Doxygen::mainPage = 0; bool Doxygen::insideMainPage = FALSE; // are we generating docs for the main page? NamespaceDef *Doxygen::globalScope = 0; -QDict *Doxygen::xrefLists = new QDict; // dictionary of cross-referenced item lists bool Doxygen::parseSourcesNeeded = FALSE; QTime Doxygen::runningTime; SearchIndexIntf *Doxygen::searchIndex=0; @@ -4955,7 +4954,7 @@ static void addListReferences() name = pd->getGroupDef()->getOutputFileBase(); } { - const std::vector &xrefItems = pd->xrefListItems(); + const std::vector &xrefItems = pd->xrefListItems(); addRefItem(xrefItems, name, theTranslator->trPage(TRUE,TRUE), @@ -4972,7 +4971,7 @@ static void addListReferences() //{ // name = dd->getGroupDef()->getOutputFileBase(); //} - const std::vector &xrefItems = dd->xrefListItems(); + const std::vector &xrefItems = dd->xrefListItems(); addRefItem(xrefItems, name, theTranslator->trDir(TRUE,TRUE), @@ -4984,9 +4983,7 @@ static void addListReferences() static void generateXRefPages() { - QDictIterator di(*Doxygen::xrefLists); - RefList *rl; - for (di.toFirst();(rl=di.current());++di) + for (RefListManager::Ptr &rl : RefListManager::instance()) { rl->generatePage(); } @@ -8525,8 +8522,9 @@ static void findMainPage(Entry *root) { // a page name is a label as well! but should no be double either SectionManager::instance().add( - indexName, root->startLine, Doxygen::mainPage->name(), + indexName, + root->startLine, Doxygen::mainPage->title(), SectionType::Page, 0); // level 0 @@ -8626,9 +8624,7 @@ static void resolveUserReferences() // name (not from the todo/test/bug/deprecated list, but from the file in // which they are defined). We correct this here by looking at the // generated section labels! - QDictIterator rli(*Doxygen::xrefLists); - RefList *rl; - for (rli.toFirst();(rl=rli.current());++rli) + for (const RefListManager::Ptr &rl : RefListManager::instance()) { QCString label="_"+rl->listName(); // "_todo", "_test", ... if (si->label().left(label.length())==label) @@ -9903,7 +9899,6 @@ void cleanUpDoxygen() delete Doxygen::pageSDict; delete Doxygen::exampleSDict; delete Doxygen::globalScope; - delete Doxygen::xrefLists; delete Doxygen::parserManager; delete Doxygen::preprocessor; delete theTranslator; @@ -10392,8 +10387,6 @@ void adjustConfiguration() Doxygen::htmlFileExtension = Config_getString(HTML_FILE_EXTENSION); - Doxygen::xrefLists->setAutoDelete(TRUE); - Doxygen::parseSourcesNeeded = Config_getBool(CALL_GRAPH) || Config_getBool(CALLER_GRAPH) || Config_getBool(REFERENCES_RELATION) || diff --git a/src/doxygen.h b/src/doxygen.h index 92ae460..635ac1d 100644 --- a/src/doxygen.h +++ b/src/doxygen.h @@ -119,7 +119,6 @@ class Doxygen static QIntDict memGrpInfoDict; static QDict expandAsDefinedDict; static NamespaceDef *globalScope; - static QDict *xrefLists; // array of xref lists: todo, test, bug, deprecated ... static QCString htmlFileExtension; static bool parseSourcesNeeded; static QTime runningTime; diff --git a/src/entry.cpp b/src/entry.cpp index a0e616a..706488b 100644 --- a/src/entry.cpp +++ b/src/entry.cpp @@ -255,13 +255,4 @@ void Entry::setFileDef(FileDef *fd) } } -void Entry::addSpecialListItem(const char *listName,int itemId) -{ - ListItemInfo ili; - ili.type = listName; - ili.itemId = itemId; - sli.push_back(ili); -} - - //------------------------------------------------------------------ diff --git a/src/entry.h b/src/entry.h index 5ae1d60..abd0a89 100644 --- a/src/entry.h +++ b/src/entry.h @@ -29,7 +29,7 @@ class SectionInfo; class QFile; class FileDef; -struct ListItemInfo; +class RefItem; /** This class stores information about an inheritance relation */ @@ -194,8 +194,6 @@ class Entry Entry(const Entry &); ~Entry(); - void addSpecialListItem(const char *listName,int index); - /*! Returns the parent for this Entry or 0 if this entry has no parent. */ Entry *parent() const { return m_parent; } @@ -289,7 +287,7 @@ class Entry QCString fileName; //!< file this entry was extracted from int startLine; //!< start line of entry in the source int startColumn; //!< start column of entry in the source - std::vector sli; //!< special lists (test/todo/bug/deprecated/..) this entry is in + std::vector sli; //!< special lists (test/todo/bug/deprecated/..) this entry is in SrcLangExt lang; //!< programming language in which this entry was found bool hidden; //!< does this represent an entity that is hidden from the output bool artificial; //!< Artificially introduced item diff --git a/src/filedef.cpp b/src/filedef.cpp index fb0e290..a60f4d8 100644 --- a/src/filedef.cpp +++ b/src/filedef.cpp @@ -1682,7 +1682,7 @@ bool FileDefImpl::generateSourceFile() const void FileDefImpl::addListReferences() { { - const std::vector &xrefItems = xrefListItems(); + const std::vector &xrefItems = xrefListItems(); addRefItem(xrefItems, getOutputFileBase(), theTranslator->trFile(TRUE,TRUE), diff --git a/src/groupdef.cpp b/src/groupdef.cpp index 7b954e5..960252d 100644 --- a/src/groupdef.cpp +++ b/src/groupdef.cpp @@ -1659,7 +1659,7 @@ QCString GroupDefImpl::getOutputFileBase() const void GroupDefImpl::addListReferences() { { - const std::vector &xrefItems = xrefListItems(); + const std::vector &xrefItems = xrefListItems(); addRefItem(xrefItems, getOutputFileBase(), theTranslator->trGroup(TRUE,TRUE), diff --git a/src/linkedmap.h b/src/linkedmap.h new file mode 100644 index 0000000..76d906d --- /dev/null +++ b/src/linkedmap.h @@ -0,0 +1,84 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2020 by Dimitri van Heesch. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software + * for any purpose. It is provided "as is" without express or implied warranty. + * See the GNU General Public License for more details. + * + * Documents produced by Doxygen are derivative works derived from the + * input used in their production; they are not affected by this license. + * + */ + +#ifndef LINKEDMAP_H +#define LINKEDMAP_H + +#include +#include +#include +#include + +//! @brief Container class representing a vector of objects with unique keys. +//! @details Elements can be quickly looked up given the key. +//! When adding objects the order of addition is kept, and used while iterating. +template +class LinkedMap +{ + public: + using Ptr = std::unique_ptr; + using Vec = std::vector; + using Map = std::unordered_map; + using iterator = typename Vec::iterator; + + //! find an element given the key. + //! Returns a pointer to the element if found or nullptr if it is not found. + const T *find(const char *key) const + { + auto it = m_lookup.find(key); + return it!=m_lookup.end() ? it->second : nullptr; + } + + //! non-const wrapper for find() const + T* find(const char *key) + { + return const_cast(static_cast(*this).find(key)); + } + + //! Adds a new element to the ordered set if it was not added already. + //! Return a non-owning pointer to the newly added item, or to the existing item if it was + //! already inserted before. + template + T *add(const char *key, Args&&... args) + { + T *result = find(key); + if (result==nullptr) + { + Ptr ptr = std::make_unique(key,std::forward(args)...); + result = ptr.get(); + m_lookup.insert({std::string(key),result}); + m_entries.push_back(std::move(ptr)); + } + return result; + } + + iterator begin() { return m_entries.begin(); } + iterator end() { return m_entries.end(); } + bool empty() const { return m_entries.empty(); } + int size() const { return m_entries.size(); } + + void clear() + { + m_entries.clear(); + m_lookup.clear(); + } + + private: + Map m_lookup; + Vec m_entries; +}; + + +#endif diff --git a/src/memberdef.cpp b/src/memberdef.cpp index dd746d6..1d2a54e 100644 --- a/src/memberdef.cpp +++ b/src/memberdef.cpp @@ -4479,7 +4479,7 @@ void MemberDefImpl::addListReference(Definition *) memArgs = argsString(); } } - const std::vector &xrefItems = xrefListItems(); + const std::vector &xrefItems = xrefListItems(); addRefItem(xrefItems, qualifiedName()+argsString(), // argsString is needed for overloaded functions (see bug 609624) memLabel, diff --git a/src/membergroup.cpp b/src/membergroup.cpp index 05c38c3..ee46ced 100644 --- a/src/membergroup.cpp +++ b/src/membergroup.cpp @@ -356,7 +356,7 @@ void MemberGroup::findSectionsInDocumentation(const Definition *d) memberList->findSectionsInDocumentation(d); } -void MemberGroup::setRefItems(const std::vector &sli) +void MemberGroup::setRefItems(const std::vector &sli) { m_xrefListItems.insert(m_xrefListItems.end(), sli.cbegin(), sli.cend()); } @@ -368,7 +368,7 @@ void MemberGroup::writeTagFile(FTextStream &tagFile) //-------------------------------------------------------------------------- -void MemberGroupInfo::setRefItems(const std::vector &sli) +void MemberGroupInfo::setRefItems(const std::vector &sli) { m_sli.insert(m_sli.end(), sli.cbegin(), sli.cend()); } diff --git a/src/membergroup.h b/src/membergroup.h index aa30063..dee998b 100644 --- a/src/membergroup.h +++ b/src/membergroup.h @@ -35,7 +35,7 @@ class GroupDef; class OutputList; class Definition; class FTextStream; -struct ListItemInfo; +class RefItem; /** A class representing a group of members. */ class MemberGroup @@ -81,7 +81,7 @@ class MemberGroup int countInheritableMembers(const ClassDef *inheritedFrom) const; void setInGroup(bool b); void addListReferences(Definition *d); - void setRefItems(const std::vector &sli); + void setRefItems(const std::vector &sli); MemberList *members() const { return memberList; } QCString anchor() const; @@ -101,7 +101,7 @@ class MemberGroup const Definition *m_parent = 0; QCString m_docFile; int m_docLine = 0; - std::vector m_xrefListItems; + std::vector m_xrefListItems; }; /** A list of MemberGroup objects. */ @@ -133,13 +133,13 @@ class MemberGroupSDict : public SIntDict /** Data collected for a member group */ struct MemberGroupInfo { - void setRefItems(const std::vector &sli); + void setRefItems(const std::vector &sli); QCString header; QCString doc; QCString docFile; int docLine = -1; QCString compoundName; - std::vector m_sli; + std::vector m_sli; }; #endif diff --git a/src/namespacedef.cpp b/src/namespacedef.cpp index 220f300..ee2d878 100644 --- a/src/namespacedef.cpp +++ b/src/namespacedef.cpp @@ -1269,7 +1269,7 @@ void NamespaceDefImpl::addListReferences() { //bool fortranOpt = Config_getBool(OPTIMIZE_FOR_FORTRAN); { - const std::vector &xrefItems = xrefListItems(); + const std::vector &xrefItems = xrefListItems(); addRefItem(xrefItems, qualifiedName(), getLanguage()==SrcLangExt_Fortran ? diff --git a/src/pagedef.cpp b/src/pagedef.cpp index 0a6e014..3f96a4b 100644 --- a/src/pagedef.cpp +++ b/src/pagedef.cpp @@ -148,9 +148,7 @@ bool PageDefImpl::hasParentPage() const void PageDefImpl::writeTagFile(FTextStream &tagFile) { bool found = name()=="citelist"; - QDictIterator rli(*Doxygen::xrefLists); - RefList *rl; - for (rli.toFirst();(rl=rli.current()) && !found;++rli) + for (RefListManager::Ptr &rl : RefListManager::instance()) { if (rl->listName()==name()) { diff --git a/src/reflist.cpp b/src/reflist.cpp index 016ef49..45313f9 100644 --- a/src/reflist.cpp +++ b/src/reflist.cpp @@ -1,9 +1,6 @@ /****************************************************************************** * - * - * - * - * Copyright (C) 1997-2015 by Dimitri van Heesch. + * Copyright (C) 1997-2020 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its * documentation under the terms of the GNU General Public License is hereby @@ -16,196 +13,76 @@ * */ +#include + #include #include "reflist.h" -#include "util.h" #include "ftextstream.h" #include "definition.h" - -/*! Create a list of items that are cross referenced with documentation blocks - * @param listName String representing the name of the list. - * @param pageTitle String representing the title of the list page. - * @param secTitle String representing the title of the section. - */ -RefList::RefList(const char *listName, - const char *pageTitle, - const char *secTitle - ) -{ - m_itemList = 0; - m_dict = 0; - m_dictIterator = 0; - m_id = 0; - m_listName = listName; - m_fileName = convertNameToFile(listName,FALSE,TRUE); - m_pageTitle = pageTitle; - m_secTitle = secTitle; -} - -/*! Destroy the todo list. Currently not called! */ -RefList::~RefList() -{ - delete m_dictIterator; - delete m_dict; - delete m_itemList; -} - -/*! Adds a new item to the list. - * \returns A unique id for this item. - */ -int RefList::addRefItem() -{ - if (m_dict==0) - { - m_dict = new QIntDict(1009); - m_dict->setAutoDelete(TRUE); - m_dictIterator = new QIntDictIterator(*m_dict); - } - RefItem *item = new RefItem; - m_id++; - m_dict->insert(m_id,item); - return m_id; -} - -/*! Returns an item given it's id that is obtained with addRefItem() - * \param itemId item's identifier. - * \returns A pointer to the todo item's structure. - */ -RefItem *RefList::getRefItem(int itemId) -{ - return m_dict ? m_dict->find(itemId) : 0; -} - -/*! Returns the first item in the dictionary or 0 if - * non is available. - * Items are not sorted. - */ -RefItem *RefList::getFirstRefItem() -{ - return m_dictIterator ? m_dictIterator->toFirst() : 0; -} - -/*! Returns the next item in the dictionary or 0 if - * we are at the end of the list. - * Items are not sorted. - */ -RefItem *RefList::getNextRefItem() -{ - return m_dictIterator ? m_dictIterator->operator++() : 0; -} - -/*! Returns the name of the list as set in the constructor. */ -QCString RefList::listName() const -{ - return m_listName; -} - -QCString RefList::fileName() const -{ - return m_fileName; -} - -QCString RefList::pageTitle() const -{ - return m_pageTitle; -} - -QCString RefList::sectionTitle() const -{ - return m_secTitle; -} - -void RefList::insertIntoList(const char *key,RefItem *item) -{ - if (m_itemList==0) - { - m_itemList = new SortedRefItems(1009); - } - RefItem *ri = m_itemList->find(key); - if (ri==0) - { - m_itemList->append(key,item); - } - else // item already added to the list (i.e. multiple item for the same - // entity) - { - if (ri!=item) - { - // We also have to check if the item is not already in the "extra" list - QListIterator li(ri->extraItems); - RefItem *extraItem; - bool doubleItem = false; - for (li.toFirst();(extraItem=li.current());++li) - { - if (item == extraItem) doubleItem = true; - } - if (!doubleItem) ri->extraItems.append(item); - } - } -} - +#include "sortdict.h" void RefList::generatePage() { - if (m_itemList==0) return; - m_itemList->sort(); - SDict::Iterator it(*m_itemList); - RefItem *item; + std::sort(m_entries.begin(),m_entries.end(), + [](std::unique_ptr &left,std::unique_ptr &right) + { return qstricmp(left->title(),left->title()); }); + //RefItem *item; QCString doc; doc += "

"; - for (it.toFirst();(item=it.current());++it) + QCString lastGroup; + bool first=true; + for (const std::unique_ptr &item : m_entries) { - doc += "
"; - doc += "\n"; - if (item->scope) + bool startNewGroup = item->group()!=lastGroup; + if (startNewGroup) { - if (item->scope->name() != "") + if (!first) { - doc += "\\_setscope "; - doc += item->scope->name(); - doc += " "; + doc += ""; + first=false; } + doc += "
"; + doc += "\n"; + if (item->scope()) + { + if (item->scope()->name() != "") + { + doc += "\\_setscope "; + doc += item->scope()->name(); + doc += " "; + } + } + doc += item->prefix(); + doc += " \\_internalref "; + doc += item->name(); + // escape \'s in title, see issue #5901 + QCString escapedTitle = substitute(item->title(),"\\","\\\\"); + doc += " \""+escapedTitle+"\" "; + // write declaration in case a function with arguments + if (!item->args().isEmpty()) + { + // escape @'s in argument list, needed for Java annotations (see issue #6208) + // escape \'s in argument list (see issue #6533) + doc += substitute(substitute(item->args(),"@","@@"),"\\","\\\\"); + } + doc += "
"; } - doc += item->prefix; - doc += " \\_internalref "; - doc += item->name; - // escape \'s in title, see issue #5901 - QCString escapedTitle = substitute(item->title,"\\","\\\\"); - if (item->scope && - (item->scope->definitionType()==Definition::TypeClass || - item->scope->definitionType()==Definition::TypeNamespace || - item->scope->definitionType()==Definition::TypeMember || - item->scope->definitionType()==Definition::TypePackage) - ) - { - // prevent Obj-C names in e.g. todo list are seen as emoji - escapedTitle = substitute(escapedTitle,":","∷"); - } - doc += " \""+escapedTitle+"\" "; - // write declaration in case a function with arguments - if (!item->args.isEmpty()) + else { - // escape @'s in argument list, needed for Java annotations (see issue #6208) - // escape \'s in argument list (see issue #6533) - doc += substitute(substitute(item->args,"@","@@"),"\\","\\\\"); + doc += "

"; } - doc += "

\\anchor "; - doc += item->listAnchor; + doc += " \\anchor "; + doc += item->anchor(); doc += " "; - doc += item->text; - QListIterator li(item->extraItems); - RefItem *extraItem; - for (li.toFirst();(extraItem=li.current());++li) - { - doc += "

\\anchor "; - doc += extraItem->listAnchor; - doc += " "; - doc += extraItem->text; - } + doc += item->text(); + lastGroup = item->group(); + } + if (!first) + { doc += "

"; } doc += "
\n"; //printf("generatePage('%s')\n",doc.data()); - addRelatedPage(m_listName,m_pageTitle,doc,m_fileName,1,std::vector(),0,0,TRUE); + addRelatedPage(m_listName,m_pageTitle,doc,m_fileName,1,std::vector(),0,0,TRUE); } diff --git a/src/reflist.h b/src/reflist.h index d064c58..4030c8b 100644 --- a/src/reflist.h +++ b/src/reflist.h @@ -1,9 +1,6 @@ /****************************************************************************** * - * - * - * - * Copyright (C) 1997-2015 by Dimitri van Heesch. + * Copyright (C) 1997-2020 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its * documentation under the terms of the GNU General Public License is hereby @@ -21,37 +18,49 @@ #include #include -#include "sortdict.h" +#include "util.h" +#include "linkedmap.h" class Definition; +class RefList; /** This struct represents an item in the list of references. */ -struct RefItem +class RefItem { - RefItem() : scope(0) {} - QCString text; //!< text of the item. - QCString listAnchor; //!< anchor in the list + public: + RefItem(int id,RefList *list) : m_id(id), m_list(list) {} - QCString prefix; //!< type prefix for the name - Definition *scope; //!< scope to use for references. - QCString name; //!< name of the entity containing the reference - QCString title; //!< display name of the entity - QCString args; //!< optional arguments for the entity (if function) - //bool written; - QList extraItems; //!< more items belonging to the same entity -}; + void setText (const char *text) { m_text = text; } + void setAnchor(const char *anchor) { m_anchor = anchor; } + void setPrefix(const char *prefix) { m_prefix = prefix; } + void setName (const char *name) { m_name = name; } + void setTitle (const char *title) { m_title = title; } + void setArgs (const char *args) { m_args = args; } + void setGroup (const char *group) { m_group = group; } + void setScope (const Definition *scope) { m_scope = scope; } + + QCString text() const { return m_text; } + QCString anchor() const { return m_anchor; } + QCString prefix() const { return m_prefix; } + QCString name() const { return m_name; } + QCString title() const { return m_title; } + QCString args() const { return m_args; } + QCString group() const { return m_group; } + int id() const { return m_id; } + RefList *list() const { return m_list; } + const Definition *scope() const { return m_scope; } -/** List of items sorted by title */ -class SortedRefItems : public SDict -{ - public: - SortedRefItems(int size=17) : SDict(size) {} - virtual ~SortedRefItems() {} private: - int compareValues(const RefItem *r1,const RefItem *r2) const - { - return qstricmp(r1->title,r2->title); - } + int m_id = 0; //!< unique identifier for this item within its list + RefList *m_list; //!< list owning this item + QCString m_text; //!< text of the item. + QCString m_anchor; //!< anchor in the list + QCString m_prefix; //!< type prefix for the name + QCString m_name; //!< name of the entity containing the reference + QCString m_title; //!< display name of the entity + QCString m_args; //!< optional arguments for the entity (if function) + QCString m_group; //!< group id used to combine item under a single header + const Definition *m_scope = 0; //!< scope to use for references. }; /** List of cross-referenced items @@ -67,31 +76,68 @@ class SortedRefItems : public SDict class RefList { public: - int addRefItem(); - RefItem *getRefItem(int todoItemId); - RefItem *getFirstRefItem(); - RefItem *getNextRefItem(); - QCString listName() const; - QCString fileName() const; - QCString pageTitle() const; - QCString sectionTitle() const; + /*! Create a list of items that are cross referenced with documentation blocks + * @param listName String representing the name of the list. + * @param pageTitle String representing the title of the list page. + * @param secTitle String representing the title of the section. + */ + RefList(const char *listName, const char *pageTitle, const char *secTitle) : + m_listName(listName), m_fileName(convertNameToFile(listName,FALSE,TRUE)), + m_pageTitle(pageTitle), m_secTitle(secTitle) {} + + /*! Adds a new item to the list. + * @returns A unique id for this item. + */ + RefItem *add() + { + m_id++; + std::unique_ptr item = std::make_unique(m_id,this); + RefItem *result = item.get(); + m_entries.push_back(std::move(item)); + m_lookup.insert({m_id,result}); + return result; + } + + /*! Returns an item given it's id that is obtained with addRefItem() + * @param itemId item's identifier. + * @returns A pointer to the todo item's structure. + */ + RefItem *find(int itemId) + { + auto it = m_lookup.find(itemId); + return it!=m_lookup.end() ? it->second : nullptr; + } + + QCString listName() const { return m_listName; } + QCString fileName() const { return m_fileName; } + QCString pageTitle() const { return m_pageTitle; } + QCString sectionTitle() const { return m_secTitle; } - RefList(const char *listName, - const char *pageTitle,const char *secTitle - ); - ~RefList(); - void insertIntoList(const char *key,RefItem *item); void generatePage(); private: - int m_id; + int m_id = 0; QCString m_listName; QCString m_fileName; QCString m_pageTitle; QCString m_secTitle; - SortedRefItems *m_itemList; - QIntDict *m_dict; - QIntDictIterator *m_dictIterator; + std::vector< std::unique_ptr< RefItem > > m_entries; + std::unordered_map< int, RefItem* > m_lookup; +}; + +class RefListManager : public LinkedMap +{ + public: + static RefListManager &instance() + { + static RefListManager rlm; + return rlm; + } + + private: + RefListManager() {} + RefListManager(const RefListManager &other) = delete; + RefListManager &operator=(const RefListManager &other) = delete; }; #endif diff --git a/src/section.h b/src/section.h index daee254..9bdfb3b 100644 --- a/src/section.h +++ b/src/section.h @@ -16,13 +16,12 @@ #ifndef SECTION_H #define SECTION_H -#include -#include -#include -#include +#include #include +#include "linkedmap.h" + class Definition; //! enum representing the various types of sections and entities that can be referred to. @@ -50,8 +49,8 @@ inline constexpr bool isSection(SectionType type) class SectionInfo { public: - SectionInfo(const char *fileName, int lineNr, const char *label, - const char *title, SectionType type, int level, const char *ref): + SectionInfo(const char *label, const char *fileName, int lineNr, + const char *title, SectionType type, int level,const char *ref) : m_label(label), m_title(title), m_type(type), m_ref(ref), m_lineNr(lineNr), m_fileName(fileName), m_level(level) { @@ -120,70 +119,26 @@ class SectionRefs private: SectionInfoVec m_entries; - std::map< std::string, const SectionInfo* > m_lookup; + std::unordered_map< std::string, const SectionInfo* > m_lookup; }; //! singleton class that owns the list of all sections -class SectionManager +class SectionManager : public LinkedMap { - using SectionInfoPtr = std::unique_ptr; - using SectionInfoVec = std::vector; - public: - using iterator = SectionInfoVec::iterator; - - //! Return a pointer to the section info given a section label or nullptr if - //! no section with the given label can be found. - SectionInfo *find(const char *label) - { - auto it = m_lookup.find(label); - return it!=m_lookup.end() ? it->second : nullptr; - } - - //! Returns a constant pointers to the section info given a section label or nullptr - //! if no section with the given label can be found. - const SectionInfo *find(const char *label) const - { - auto it = m_lookup.find(label); - return it!=m_lookup.end() ? it->second : nullptr; - } - - //! Add a new section given the section data. - //! Returns a non-owning pointer to the newly added section. - SectionInfo *add(const char *fileName, - int lineNr, - const char *label, - const char *title, - SectionType type, - int level, - const char *ref=0) - { - SectionInfoPtr si = std::make_unique( - fileName,lineNr,label,title,type,level,ref); - SectionInfo *result = si.get(); - m_lookup.insert({std::string(label),result}); - m_entries.push_back(std::move(si)); - return result; - } - //! Add a new section given the data of an existing section. //! Returns a non-owning pointer to the newly added section. SectionInfo *add(const SectionInfo &si) { - add(si.fileName(),si.lineNr(),si.label(),si.title(),si.type(),si.level(),si.ref()); - return find(si.label()); + return LinkedMap::add(si.label(),si.fileName(),si.lineNr(),si.title(),si.type(),si.level(),si.ref()); } - iterator begin() { return m_entries.begin(); } - iterator end() { return m_entries.end(); } - bool empty() const { return m_entries.empty(); } - int size() const { return m_entries.size(); } - - //! clears the sections - void clear() + //! Add a new section + //! Return a non-owning pointer to the newly added section + SectionInfo *add(const char *label, const char *fileName, int lineNr, + const char *title, SectionType type, int level,const char *ref=0) { - m_entries.clear(); - m_lookup.clear(); + return LinkedMap::add(label,fileName,lineNr,title,type,level,ref); } //! returns a reference to the singleton @@ -197,9 +152,6 @@ class SectionManager SectionManager() {} SectionManager(const SectionManager &other) = delete; SectionManager &operator=(const SectionManager &other) = delete; - - SectionInfoVec m_entries; - std::map< std::string, SectionInfo* > m_lookup; }; diff --git a/src/tagreader.cpp b/src/tagreader.cpp index 60b2e53..3640f0e 100644 --- a/src/tagreader.cpp +++ b/src/tagreader.cpp @@ -1167,7 +1167,7 @@ void TagFileParser::addDocAnchors(const std::shared_ptr &e,const TagAncho //printf("New sectionInfo file=%s anchor=%s\n", // ta->fileName.data(),ta->label.data()); SectionInfo *si=SectionManager::instance().add( - ta->fileName,-1,ta->label,ta->title, + ta->label,ta->fileName,-1,ta->title, SectionType::Anchor,0,m_tagName); e->anchors.push_back(si); } diff --git a/src/types.h b/src/types.h index 189a93d..d503c58 100644 --- a/src/types.h +++ b/src/types.h @@ -97,12 +97,6 @@ struct Grouping }; -struct ListItemInfo -{ - QCString type; - int itemId; -}; - enum MemberListType { MemberListType_privateLists = 0x0800, diff --git a/src/util.cpp b/src/util.cpp index 25ca13e..84f21a3 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -6595,7 +6595,7 @@ found: PageDef *addRelatedPage(const char *name,const QCString &ptitle, const QCString &doc, const char *fileName,int startLine, - const std::vector &sli, + const std::vector &sli, GroupDef *gd, const TagInfo *tagInfo, bool xref, @@ -6667,8 +6667,8 @@ PageDef *addRelatedPage(const char *name,const QCString &ptitle, } else { - SectionManager::instance().add( - file,-1,pd->name(),pd->title(),SectionType::Page,0,pd->getReference()); + SectionManager::instance().add(pd->name(), + file,-1,pd->title(),SectionType::Page,0,pd->getReference()); //printf("si->label='%s' si->definition=%s si->fileName='%s'\n", // si->label.data(),si->definition?si->definition->name().data():"", // si->fileName.data()); @@ -6682,39 +6682,21 @@ PageDef *addRelatedPage(const char *name,const QCString &ptitle, //---------------------------------------------------------------------------- -void addRefItem(const std::vector &sli, +void addRefItem(const std::vector &sli, const char *key, - const char *prefix, const char *name,const char *title,const char *args,Definition *scope) + const char *prefix, const char *name,const char *title,const char *args,const Definition *scope) { - //printf("addRefItem(sli=%p,key=%s,prefix=%s,name=%s,title=%s,args=%s)\n",sli,key,prefix,name,title,args); + //printf("addRefItem(sli=%d,key=%s,prefix=%s,name=%s,title=%s,args=%s)\n",(int)sli.size(),key,prefix,name,title,args); if (key && key[0]!='@') // check for @ to skip anonymous stuff (see bug427012) { - for (const ListItemInfo &lii : sli) - { - RefList *refList = Doxygen::xrefLists->find(lii.type); - if (refList - && - ( - // either not a built-in list or the list is enabled - (lii.type!="todo" || Config_getBool(GENERATE_TODOLIST)) && - (lii.type!="test" || Config_getBool(GENERATE_TESTLIST)) && - (lii.type!="bug" || Config_getBool(GENERATE_BUGLIST)) && - (lii.type!="deprecated" || Config_getBool(GENERATE_DEPRECATEDLIST)) - ) - ) - { - RefItem *item = refList->getRefItem(lii.itemId); - ASSERT(item!=0); - - item->prefix = prefix; - item->scope = scope; - item->name = name; - item->title = title; - item->args = args; - - refList->insertIntoList(key,item); - - } + for (RefItem *item : sli) + { + item->setPrefix(prefix); + item->setScope(scope); + item->setName(name); + item->setTitle(title); + item->setArgs(args); + item->setGroup(key); } } } diff --git a/src/util.h b/src/util.h index b9628e9..2bde421 100644 --- a/src/util.h +++ b/src/util.h @@ -49,7 +49,6 @@ class ClassList; class MemberGroupSDict; struct TagInfo; class MemberNameInfoSDict; -struct ListItemInfo; class PageDef; class SectionInfo; class QDir; @@ -327,15 +326,19 @@ int getScopeFragment(const QCString &s,int p,int *l); int filterCRLF(char *buf,int len); -void addRefItem(const std::vector &sli,const char *prefix, +void addRefItem(const std::vector &sli, const char *key, - const char *name,const char *title,const char *args,Definition *scope); + const char *prefix, + const char *name, + const char *title, + const char *args, + const Definition *scope); PageDef *addRelatedPage(const char *name, const QCString &ptitle, const QCString &doc, const char *fileName,int startLine, - const std::vector &sli = std::vector(), + const std::vector &sli = std::vector(), GroupDef *gd=0, const TagInfo *tagInfo=0, bool xref=FALSE, -- cgit v0.12