A table for fast access to the labels by entry is implemented in OCAF document. A method TDF_Data::SetAccessByEntries(true) fills-in a table for fast access to the labels. New labels, created later will be added to the table automatically. The method TDF_Tool::Label() will search the entry in the table and then, if not found, will call the old code. Disabling of usage of the table (by calling of TDF_Data::SetAccessByEntries(false)) cleans the internal table of entries - labels. By default, the table is not used.
This improvement is useful for large documents with a lot of labels, and if the application uses entries to get labels. The application should call TDF_Data::SetAccessByEntries(true) for a document and then, the method TDF_Tool::Label() called inside OCAF and XCAF will use the fast access to the labels and speed-up the application.
Also, the method TDF_Tool::Entry() is improved (by MPV).
Modified files:
- TDF_Data.hxx and cxx: the new methods SetAccessByEntries(bool), IsAccessByEntries() and GetLabel(entry) are implemented. No need to use the method GetLabel() directly. It is called in TDF_Tool::Label().
- TDF_Label.cxx: adding of a newly created label to the table of entries - labels.
- TDF_Tool.cxx: the method Entry() is accelerated (by MPV) and Label() is improved to call TDF_Data::GetLabel().
- DDF_DataCommands.cxx: a new draw-command is added SetAccessByEntry, which sets or unsets usage of the table for fast access to the labels. Usage of the draw-command is illustrated in a new test "bugs caf bug31920".
Tests:
- bugs caf bug31920: a new simple test to check TDF_Tool::Label() when fast access to the labels is on.
Doc:
- dox\upgrade\upgrade.md is extended for new information
Existing applications depending on OpenGL ES (mobile projects first of all) should be adjusted to link against *TKOpenGles*.
Note that both *TKOpenGl* and *TKOpenGles* keep exporting classes with the same name, so applications should not attempt to link both libraries simultaneously.
+
+@subsection upgrade_occt760_fast_access_to_labels Fast access to OCAF label
+
+Access to an OCAF label via its entry is accelerated. In order to activate it, call *TDF_Data::SetAccessByEntries()*.
+The method *TDF_Tool::Label()*, which returns a label by an entry, becomes faster for about 10 .. 20 times.
+It has sense for applications, which use an entry as a unique key to access the data in OCAF tree.
+Also, the method *TDF_Tool::Entry()*, which returns an entry for a label, is accelerated as well.
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;
+}
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
"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);
}
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);
Handle(TDF_Attribute) aFirst = myRoot->FirstAttribute();
myRoot->RemoveAttribute(anEmpty, aFirst);
}
+ myAccessByEntriesTable.Clear();
myRoot->Destroy (myLabelNodeAllocator);
myRoot = NULL;
}
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 : RegisterLabel
+//purpose :
+//=======================================================================
+
+void TDF_Data::RegisterLabel(const TDF_Label& aLabel)
+{
+ TCollection_AsciiString anEntry;
+ TDF_Tool::Entry (aLabel, anEntry);
+ myAccessByEntriesTable.Bind (anEntry, aLabel);
+}
//=======================================================================
//function : Dump
#include <Standard_Transient.hxx>
#include <TDF_Label.hxx>
#include <Standard_OStream.hxx>
+#include <NCollection_DataMap.hxx>
class Standard_NoMoreObject;
class TDF_Transaction;
class TDF_LabelNode;
//! 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 is created,
+ //! 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_Boolean IsAccessByEntries() const { return myAccessByEntries; }
+
+ //! 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_Boolean GetLabel (const TCollection_AsciiString& anEntry, TDF_Label& aLabel) { return myAccessByEntriesTable.Find(anEntry, 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 RegisterLabel (const TDF_Label& aLabel);
+
//! Returns TDF_HAllocator, which is an
//! incremental allocator used by
//! TDF_LabelNode.
TColStd_ListOfInteger myTimes;
TDF_HAllocator myLabelNodeAllocator;
Standard_Boolean myAllowModification;
-
-
+ Standard_Boolean myAccessByEntries;
+ NCollection_DataMap<TCollection_AsciiString, TDF_Label> myAccessByEntriesTable;
};
myLabelNode->myFirstChild = childLabelNode;
else // ... somewhere.
lastLnp->myBrother = childLabelNode;
+ // Update table for fast access to the labels.
+ if (myLabelNode->Data()->IsAccessByEntries())
+ myLabelNode->Data()->RegisterLabel (childLabelNode);
}
if (lastLnp) //agv 14.07.2010
//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<Standard_Character*>(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.
//purpose : Returns the label expressed by <anEntry>.
//=======================================================================
-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);
+}
//=======================================================================
// and creates it if <create> 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);
+ }
}
--- /dev/null
+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"