From: vro Date: Thu, 31 Dec 2020 12:34:42 +0000 (+0300) Subject: 0031920: Application Framework - speed up methods of getting label by entry and vice... X-Git-Url: http://git.dev.opencascade.org/gitweb/?a=commitdiff_plain;h=f897c93e14baf9241cca4d79ccd46f85d8efbf65;p=occt-copy.git 0031920: Application Framework - speed up methods of getting label by entry and vice versa // A method TDF_Data::AddLabel() is set Standard_EXPORT. (cherry picked from commit 8f2e87bddeffea13156ca6b0d7a1ae7619403844) --- diff --git a/src/DDF/DDF_DataCommands.cxx b/src/DDF/DDF_DataCommands.cxx index f0e4391e02..29658bc07f 100644 --- a/src/DDF/DDF_DataCommands.cxx +++ b/src/DDF/DDF_DataCommands.cxx @@ -371,11 +371,30 @@ static Standard_Integer DDF_CheckLabel (Draw_Interpretor& di,Standard_Integer n return 1; } - +//======================================================================= +//function : DDF_SetAccessByEntry +//purpose : SetAccessByEntry DOC 1|0 +//======================================================================= +static Standard_Integer DDF_SetAccessByEntry (Draw_Interpretor& di, Standard_Integer nb, const char** a) +{ + Standard_Integer aRet = 0; + if (nb != 3) { + di << "SetAccessByEntry DOC 1|0\n"; + aRet = 1; + } else { + Handle(TDF_Data) aDF; + if (DDF::GetDF(a[1], aDF)) { + Standard_Boolean aSet = (Draw::Atoi (a[2]) == 1); + aDF->SetAccessByEntries (aSet); + } else { + aRet = 1; + } + } + return aRet; +} // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - //======================================================================= //function : DataCommands //purpose : @@ -415,10 +434,13 @@ void DDF::DataCommands (Draw_Interpretor& theCommands) "CopyLabel (DOC, from, to)", __FILE__, CopyLabel_SCopy, g); - theCommands.Add("CheckAttrs","CheckAttrs DocName Lab1 Lab2 ", + theCommands.Add ("CheckAttrs","CheckAttrs DocName Lab1 Lab2 ", __FILE__, DDF_CheckAttrs, g); - theCommands.Add("CheckLabel","CheckLabel DocName Label ", + theCommands.Add ("CheckLabel","CheckLabel DocName Label ", __FILE__, DDF_CheckLabel, g); + theCommands.Add ("SetAccessByEntry", "SetAccessByEntry DOC 1|0", + __FILE__, DDF_SetAccessByEntry, g); + } diff --git a/src/TDF/TDF_Data.cxx b/src/TDF/TDF_Data.cxx index 7cd8877047..96027493fb 100644 --- a/src/TDF/TDF_Data.cxx +++ b/src/TDF/TDF_Data.cxx @@ -94,7 +94,8 @@ myTransaction (0), myNbTouchedAtt (0), myNotUndoMode (Standard_True), myTime (0), -myAllowModification (Standard_True) +myAllowModification (Standard_True), +myAccessByEntries (Standard_False) { const Handle(NCollection_IncAllocator) anIncAllocator= new NCollection_IncAllocator (16000); @@ -118,6 +119,7 @@ void TDF_Data::Destroy() Handle(TDF_Attribute) aFirst = myRoot->FirstAttribute(); myRoot->RemoveAttribute(anEmpty, aFirst); } + myAccessByEntriesTable.Clear(); myRoot->Destroy (myLabelNodeAllocator); myRoot = NULL; } @@ -439,7 +441,66 @@ Handle(TDF_Delta) TDF_Data::Undo(const Handle(TDF_Delta)& aDelta, return newDelta; } +//======================================================================= +//function : SetAccessByEntries +//purpose : +//======================================================================= + +void TDF_Data::SetAccessByEntries(const Standard_Boolean aSet) +{ + myAccessByEntries = aSet; + + myAccessByEntriesTable.Clear(); + if (myAccessByEntries) { + // Add root label. + TCollection_AsciiString anEntry; + TDF_Tool::Entry(myRoot, anEntry); + myAccessByEntriesTable.Bind(anEntry, myRoot); + + // Add all other labels. + TDF_ChildIterator itr(myRoot, Standard_True); + for (; itr.More(); itr.Next()) { + const TDF_Label aLabel = itr.Value(); + TDF_Tool::Entry(aLabel, anEntry); + myAccessByEntriesTable.Bind(anEntry, aLabel); + } + } +} + +//======================================================================= +//function : IsAccessByEntries +//purpose : +//======================================================================= + +Standard_Boolean TDF_Data::IsAccessByEntries() const +{ + return myAccessByEntries; +} + +//======================================================================= +//function : GetLabel +//purpose : +//======================================================================= + +Standard_Boolean TDF_Data::GetLabel(const TCollection_AsciiString& anEntry, TDF_Label& aLabel) +{ + Standard_Boolean aResult = myAccessByEntriesTable.IsBound(anEntry); + if (aResult) + aLabel = myAccessByEntriesTable(anEntry); + return aResult; +} +//======================================================================= +//function : AddLabel +//purpose : +//======================================================================= + +void TDF_Data::AddLabel(const TDF_Label& aLabel) +{ + TCollection_AsciiString anEntry; + TDF_Tool::Entry(aLabel, anEntry); + myAccessByEntriesTable.Bind(anEntry, aLabel); +} //======================================================================= //function : Dump diff --git a/src/TDF/TDF_Data.hxx b/src/TDF/TDF_Data.hxx index 73a2341d3b..17846c6fca 100644 --- a/src/TDF/TDF_Data.hxx +++ b/src/TDF/TDF_Data.hxx @@ -27,13 +27,13 @@ #include #include #include +#include class Standard_NoMoreObject; class TDF_Transaction; class TDF_LabelNode; class TDF_Delta; class TDF_Label; - class TDF_Data; DEFINE_STANDARD_HANDLE(TDF_Data, Standard_Transient) @@ -100,6 +100,27 @@ Standard_OStream& operator<< (Standard_OStream& anOS) const //! returns modification mode. Standard_Boolean IsModificationAllowed() const; + //! Initializes a mechanism for fast access to the labels by their entries. + //! The fast access is useful for large documents and often access to the labels + //! via entries. Internally, a table of entry - label icreated, + //! which allows to obtain a label by its entry in a very fast way. + //! If the mechanism is turned off, the internal table is cleaned. + //! New labels are added to the table, if the mechanism is on + //! (no need to re-initialize the mechanism). + Standard_EXPORT void SetAccessByEntries (const Standard_Boolean aSet); + + //! Returns a status of mechanism for fast access to the labels via entries. + Standard_EXPORT Standard_Boolean IsAccessByEntries() const; + + //! Returns a label by an entry. + //! Returns Standard_False, if such a label doesn't exist + //! or mechanism for fast access to the label by entry is not initialized. + Standard_EXPORT Standard_Boolean GetLabel (const TCollection_AsciiString& anEntry, TDF_Label& aLabel); + + //! An internal method. It is used internally on creation of new labels. + //! It adds a new label into internal table for fast access to the labels by entry. + Standard_EXPORT void AddLabel (const TDF_Label& aLabel); + //! Returns TDF_HAllocator, which is an //! incremental allocator used by //! TDF_LabelNode. @@ -198,8 +219,8 @@ private: TColStd_ListOfInteger myTimes; TDF_HAllocator myLabelNodeAllocator; Standard_Boolean myAllowModification; - - + Standard_Boolean myAccessByEntries; + NCollection_DataMap myAccessByEntriesTable; }; diff --git a/src/TDF/TDF_Label.cxx b/src/TDF/TDF_Label.cxx index 9fac8c344f..b1b0cea3f8 100644 --- a/src/TDF/TDF_Label.cxx +++ b/src/TDF/TDF_Label.cxx @@ -345,6 +345,9 @@ TDF_LabelNode* TDF_Label::FindOrAddChild myLabelNode->myFirstChild = childLabelNode; else // ... somewhere. lastLnp->myBrother = childLabelNode; + // Update table for fast access to the labels. + if (myLabelNode->Data()->IsAccessByEntries()) + myLabelNode->Data()->AddLabel (childLabelNode); } if (lastLnp) //agv 14.07.2010 diff --git a/src/TDF/TDF_Tool.cxx b/src/TDF/TDF_Tool.cxx index f587c69603..efa6ae9328 100644 --- a/src/TDF/TDF_Tool.cxx +++ b/src/TDF/TDF_Tool.cxx @@ -372,30 +372,43 @@ void TDF_Tool::RelocateLabel //purpose : Returns the entry as an ascii string. //======================================================================= -void TDF_Tool::Entry -(const TDF_Label& aLabel, - TCollection_AsciiString& anEntry) +void TDF_Tool::Entry (const TDF_Label& aLabel, TCollection_AsciiString& anEntry) { - anEntry.Clear(); if (!aLabel.IsNull()) { - TColStd_ListOfInteger Tags; - TDF_Tool::TagList(aLabel, Tags); - anEntry += TCollection_AsciiString(Tags.First()); - Tags.RemoveFirst(); - if (Tags.IsEmpty()) { - anEntry += TDF_TagSeparator; // It must be the root label case. + int aStrLen = 1; // initial "0" of a root label + TDF_Label aLab = aLabel; + for (; !aLab.IsRoot(); aLab = aLab.Father()) + { + for (int aTag = aLab.Tag(); aTag > 9; aTag /= 10) + ++aStrLen; + aStrLen += 2; // one digit and separator } - else { - while (!Tags.IsEmpty()) { - anEntry += TDF_TagSeparator; - anEntry += TCollection_AsciiString(Tags.First()); - Tags.RemoveFirst(); - } + + if (aStrLen == 1) + { + // an exceptional case for the root label, it ends with separator + static const TCollection_AsciiString THE_ROOT_ENTRY = TCollection_AsciiString ('0') + TDF_TagSeparator; + anEntry = THE_ROOT_ENTRY; + } + else + { + anEntry = TCollection_AsciiString (aStrLen, TDF_TagSeparator); + Standard_Character* aPtr = const_cast(anEntry.ToCString() + aStrLen - 1); + for (aLab = aLabel; !aLab.IsRoot(); aLab = aLab.Father()) + { + int aTag = aLab.Tag(); + for (; aTag > 9; --aPtr, aTag /= 10) + *aPtr = Standard_Character (aTag % 10) + '0'; + *aPtr = Standard_Character (aTag) + '0'; + aPtr -= 2; + } + *aPtr = '0'; } } + else + anEntry.Clear(); } - //======================================================================= //function : TagList //purpose : Returns the entry of a label as a list of integers. @@ -452,12 +465,18 @@ void TDF_Tool::TagList //purpose : Returns the label expressed by . //======================================================================= -void TDF_Tool::Label -(const Handle(TDF_Data)& aDF, - const TCollection_AsciiString& anEntry, - TDF_Label& aLabel, - const Standard_Boolean create) -{ TDF_Tool::Label(aDF,anEntry.ToCString(),aLabel,create); } +void TDF_Tool::Label (const Handle(TDF_Data)& aDF, + const TCollection_AsciiString& anEntry, + TDF_Label& aLabel, + const Standard_Boolean create) +{ + Standard_Boolean isFound = Standard_False; + if (aDF->IsAccessByEntries()) + isFound = aDF->GetLabel (anEntry, aLabel); + + if (!isFound) + TDF_Tool::Label (aDF, anEntry.ToCString(), aLabel, create); +} //======================================================================= @@ -466,15 +485,20 @@ void TDF_Tool::Label // and creates it if is true. //======================================================================= -void TDF_Tool::Label -(const Handle(TDF_Data)& aDF, - const Standard_CString anEntry, - TDF_Label& aLabel, - const Standard_Boolean create) +void TDF_Tool::Label (const Handle(TDF_Data)& aDF, + const Standard_CString anEntry, + TDF_Label& aLabel, + const Standard_Boolean create) { - TColStd_ListOfInteger tagList; - TDF_Tool::TagList(anEntry,tagList); - TDF_Tool::Label(aDF,tagList,aLabel,create); + Standard_Boolean isFound = Standard_False; + if (aDF->IsAccessByEntries()) + isFound = aDF->GetLabel (anEntry, aLabel); + + if (!isFound) { + TColStd_ListOfInteger tagList; + TDF_Tool::TagList (anEntry, tagList); + TDF_Tool::Label (aDF, tagList, aLabel, create); + } } diff --git a/tests/bugs/caf/bug31920 b/tests/bugs/caf/bug31920 new file mode 100644 index 0000000000..9d5a19cfff --- /dev/null +++ b/tests/bugs/caf/bug31920 @@ -0,0 +1,22 @@ +puts "===========" +puts "0031920: Application Framework - speed up methods of getting label by entry and vice versa" +puts "===========" + +NewDocument D +set entry 0:2 +set value 5 +SetInteger D $entry 5 +set checkvalue1 [GetInteger D $entry] +if { $value != $checkvalue1 } { + puts "Set a value of TDataStd_Integer attribute: Error" + return +} + +SetAccessByEntry D 1 +set checkvalue2 [GetInteger D $entry] +if { $value != $checkvalue2 } { + puts "Fast access to label by entry: Error" + return +} + +puts "Fast access to label by entry: OK"