0026936: Drawbacks of inlining in new type system in OCCT 7.0 -- automatic
[occt.git] / src / TDF / TDF_Data.cxx
1 // Created by: DAUTRY Philippe
2 // Copyright (c) 1997-1999 Matra Datavision
3 // Copyright (c) 1999-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16
17 #include <NCollection_IncAllocator.hxx>
18 #include <Standard_NoMoreObject.hxx>
19 #include <Standard_NullObject.hxx>
20 #include <Standard_Type.hxx>
21 #include <TCollection_AsciiString.hxx>
22 #include <TDF_Attribute.hxx>
23 #include <TDF_AttributeDelta.hxx>
24 #include <TDF_AttributeIndexedMap.hxx>
25 #include <TDF_AttributeIterator.hxx>
26 #include <TDF_ChildIterator.hxx>
27 #include <TDF_Data.hxx>
28 #include <TDF_Delta.hxx>
29 #include <TDF_DeltaOnAddition.hxx>
30 #include <TDF_DeltaOnForget.hxx>
31 #include <TDF_DeltaOnModification.hxx>
32 #include <TDF_DeltaOnRemoval.hxx>
33 #include <TDF_DeltaOnResume.hxx>
34 #include <TDF_Label.hxx>
35 #include <TDF_LabelNode.hxx>
36 #include <TDF_LabelNodePtr.hxx>
37 #include <TDF_Tool.hxx>
38 #include <TDF_Transaction.hxx>
39
40 IMPLEMENT_STANDARD_RTTIEXT(TDF_Data,MMgt_TShared)
41
42 #undef DEB_DELTA_CREATION
43 #undef TDF_DATA_COMMIT_OPTIMIZED
44
45 #ifdef OCCT_DEBUG_DELTA
46 #define TDF_Data_DebugModified(ACTION) \
47   cout<<"After "<<ACTION<<" #"<<myTransaction+1<<", DF "<<this<<" had "<<myNbTouchedAtt<<" attribute(s) touched. Time = "<<myTime<<endl; \
48 if (!myTransaction) { \
49   TCollection_AsciiString entry; \
50   for (TDF_ChildIterator itr(Root(),Standard_True); itr.More(); itr.Next()) { \
51     const TDF_LabelNode* lnp = itr.Value().myLabelNode; \
52     if (lnp->AttributesModified() || lnp->MayBeModified()) { \
53       TDF_Tool::Entry(itr.Value(),entry); \
54       cout<<ACTION<<" on "<<entry<<" : flag(s) "; \
55       if (lnp->AttributesModified()) cout<<"AttributesModified "; \
56       if (lnp->MayBeModified()) cout<<"MayBeModified already set in transaction 0! Please contact TDF developer."; \
57       cout<<endl; \
58       cout<<itr.Value()<<endl; \
59       entry.Clear(); \
60     }}}
61 #else
62 #define TDF_Data_DebugModified(ACTION)
63 #endif
64
65 #ifdef OCCT_DEBUG_DELTA_CREATION
66 #define TDF_DataDebugDeltaCreation(DELTATYPE) \
67 { \
68 TCollection_AsciiString entry; \
69 TDF_Tool::Entry(currentAtt->Label(),entry); \
70 cout<<"Creation of a DeltaOn"<<DELTATYPE<<" \tat "<<entry<<" \ton "<<currentAtt->DynamicType()<<endl; \
71 }
72 #else
73 #define TDF_DataDebugDeltaCreation(DELTATYPE)
74 #endif
75
76 #define TDF_Data_DeltaCreation(DELTACOMMENT,DELTACREATION) \
77 if (withDelta) { \
78   TDF_DataDebugDeltaCreation(DELTACOMMENT); \
79   aDelta->AddAttributeDelta(DELTACREATION); \
80 }
81
82 //=======================================================================
83 //function : TDF_Data
84 //purpose  : empty constructor
85 //=======================================================================
86
87 TDF_Data::TDF_Data() :
88 myTransaction           (0),
89 myNbTouchedAtt          (0),
90 myNotUndoMode           (Standard_True),
91 myTime                  (0),
92 myAllowModification     (Standard_True)
93 {
94   const Handle(NCollection_IncAllocator) anIncAllocator=
95     new NCollection_IncAllocator (16000);
96   myLabelNodeAllocator = anIncAllocator;
97   myRoot = new (anIncAllocator) TDF_LabelNode (this);
98 }
99
100 //=======================================================================
101 //function : Destroy
102 //purpose  : Used to implement the destructor ~.
103 //=======================================================================
104
105 void TDF_Data::Destroy()
106 {
107   AbortUntilTransaction(1);
108   myRoot->Destroy (myLabelNodeAllocator);
109   myRoot = NULL;
110 }
111
112
113 //=======================================================================
114 //function : OpenTransaction
115 //purpose  : 
116 //=======================================================================
117
118 Standard_Integer TDF_Data::OpenTransaction() 
119 {
120   myTimes.Prepend(myTime);
121   return ++myTransaction;
122 }
123
124
125 //=======================================================================
126 //function : CommitTransaction
127 //purpose  : Commits the current transaction.
128 //=======================================================================
129
130 Handle(TDF_Delta) TDF_Data::CommitTransaction
131 (const Standard_Boolean withDelta) 
132 {
133   Handle(TDF_Delta) delta;
134   if (myTransaction>0) {
135     if (withDelta) delta = new TDF_Delta();
136 #ifdef OCCT_DEBUG_DELTA
137     cout<<"TDF_Data::Begin Commit #"<<myTransaction<<endl;    
138 #endif
139 #ifdef TDF_DATA_COMMIT_OPTIMIZED
140     myNbTouchedAtt = 0;
141     if (Root().myLabelNode->MayBeModified())
142 #endif
143       myNbTouchedAtt =
144         TDF_Data::CommitTransaction(Root(),delta,withDelta);
145
146     if (myNbTouchedAtt && !(withDelta && delta->IsEmpty())) ++myTime;
147     --myTransaction;
148     if (withDelta) {
149       if (!delta->IsEmpty()) {
150         delta->Validity(myTimes.First(),myTime);
151 #ifdef OCCT_DEBUG_DELTA
152         if (myTransaction == 0) {
153           cout<<"TDF_Data::Commit generated this delta in t=0:"<<endl;
154           delta->Dump(cout);
155         }
156 #endif
157       }
158 #ifdef OCCT_DEBUG_DELTA
159       else {
160         if (myTransaction == 0)
161           cout<<"TDF_Data::Commit generated NO delta."<<endl;
162       }
163 #endif
164     }
165     myTimes.RemoveFirst();
166   }
167   TDF_Data_DebugModified("COMMIT");
168   return delta;
169 }
170
171
172 //=======================================================================
173 //function : CommitUntilTransaction
174 //purpose  : Commits the transactions until AND including
175 //           the given transaction index.
176 //=======================================================================
177
178 Handle(TDF_Delta) TDF_Data::CommitUntilTransaction
179 (const Standard_Integer untilTransaction,
180  const Standard_Boolean withDelta)
181 {
182   Handle(TDF_Delta) delta;
183   if ((untilTransaction>0) && (myTransaction >= untilTransaction)) {
184     while (myTransaction > untilTransaction) {
185       delta = TDF_Data::CommitTransaction(Standard_False);
186     }
187     delta = TDF_Data::CommitTransaction(withDelta);
188   }
189   return delta;
190 }
191
192
193 //=======================================================================
194 //function : CommitTransaction
195 //purpose  : Recursive method used to implement the commit action.
196 //=======================================================================
197
198 Standard_Integer TDF_Data::CommitTransaction
199 (const TDF_Label& aLabel,
200  const Handle(TDF_Delta)& aDelta,
201  const Standard_Boolean withDelta)
202 {
203   aLabel.myLabelNode->MayBeModified(Standard_False);
204   Standard_Integer nbTouchedAtt = 0;
205 #ifdef TDF_DATA_COMMIT_OPTIMIZED
206   Standard_Boolean attMod = aLabel.myLabelNode->AttributesModified();
207 #else
208   Standard_Boolean attMod = Standard_True;
209 #endif
210
211   if (attMod) {
212     Handle(TDF_Attribute)    lastAtt;
213     Handle(TDF_Attribute)  backupAtt;
214     Standard_Boolean currentIsRemoved = Standard_False;
215     attMod = Standard_False;
216
217     TDF_AttributeIterator itr1(aLabel, Standard_False);
218     while (itr1.More()) {
219       TDF_Attribute * aPtrCurrentAtt = itr1.Value();
220       itr1.Next();
221       //      currentAtt = itr1.Value();
222
223       // A callback:
224       aPtrCurrentAtt->BeforeCommitTransaction();
225
226       backupAtt  = aPtrCurrentAtt->myBackup;
227
228       if (aPtrCurrentAtt->myTransaction == myTransaction) {
229         ++nbTouchedAtt;
230         --(aPtrCurrentAtt->myTransaction);
231
232         // ------------------------------------------------------- Forgotten
233         if (aPtrCurrentAtt->IsForgotten()) {
234           if (aPtrCurrentAtt->mySavedTransaction >=
235               aPtrCurrentAtt->myTransaction)
236           {
237             const Handle(TDF_Attribute) currentAtt = aPtrCurrentAtt;
238             // Collision with a not forgotten version.
239             if (backupAtt.IsNull()) {
240               TDF_Data_DeltaCreation
241                 ("Removal(1)",
242                  currentAtt->DeltaOnRemoval());
243               if (myNotUndoMode) currentAtt->BeforeRemoval();
244               aLabel.myLabelNode->RemoveAttribute(lastAtt,currentAtt);
245               currentIsRemoved = Standard_True;
246               attMod = Standard_True;
247             }
248             else {
249               // Modified then Forgotten...
250               // Forgotten flag spreading?
251               currentAtt->Resume();
252               currentAtt->Restore(backupAtt);
253               currentAtt->myTransaction = backupAtt->myTransaction;
254               currentAtt->RemoveBackup();
255               backupAtt = currentAtt->myBackup;
256               if (myTransaction == 1) {
257                 TDF_Data_DeltaCreation
258                   ("Removal(2)",
259                    currentAtt->DeltaOnRemoval());
260                 if (myNotUndoMode) currentAtt->BeforeRemoval();
261                 aLabel.myLabelNode->RemoveAttribute(lastAtt,currentAtt);
262                 currentIsRemoved = Standard_True;
263               }
264               else {
265                 // BeforeForget has already been called once.
266                 // if (myNotUndoMode) currentAtt->BeforeForget();
267                 currentAtt->Forget(myTransaction-1);
268                 TDF_Data_DeltaCreation
269                   ("Forget(1)",
270                    currentAtt->DeltaOnForget());
271                 attMod = Standard_True;
272               }
273             }
274           }
275           else {
276             // Forgotten in lower transaction than the current one.
277             TDF_Data_DeltaCreation
278               ("Forget(2)",
279                aPtrCurrentAtt->DeltaOnForget());
280           }
281         }
282         // ---------------------------------------------------------- Resumed.
283         else if (aPtrCurrentAtt->mySavedTransaction < 0) {
284           TDF_Data_DeltaCreation
285             ("Resume",
286              aPtrCurrentAtt->DeltaOnResume());
287           aPtrCurrentAtt->mySavedTransaction = 0;
288           attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
289         }
290
291         // ------------------------------------------------------------ Added.
292         else if (backupAtt.IsNull()) {
293           TDF_Data_DeltaCreation
294             ("Addition",
295              aPtrCurrentAtt->DeltaOnAddition());
296           attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
297         }
298         // --------------------------------------------------------- Modified.
299         else {
300           const TDF_Attribute* anAttrPtr = aPtrCurrentAtt; // to avoid ambiguity
301           TDF_Data_DeltaCreation
302             ("Modification",
303              anAttrPtr->DeltaOnModification(backupAtt));
304           if (aPtrCurrentAtt->myTransaction == backupAtt->myTransaction)
305             aPtrCurrentAtt->RemoveBackup();
306           attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
307         }
308
309       }
310       else attMod = attMod || (aPtrCurrentAtt->myTransaction > 0);
311
312       if (currentIsRemoved) currentIsRemoved = Standard_False;
313       else lastAtt = aPtrCurrentAtt;
314     }
315     aLabel.myLabelNode->AttributesModified(attMod);
316   }
317
318   // Iteration on the children to do the same!
319   //------------------------------------------
320   for (TDF_ChildIterator itr2(aLabel); itr2.More(); itr2.Next()) {
321 #ifdef TDF_DATA_COMMIT_OPTIMIZED
322     if (itr2.Value().myLabelNode->MayBeModified())
323 #endif
324       nbTouchedAtt +=
325         TDF_Data::CommitTransaction(itr2.Value(),aDelta,withDelta);
326   }
327
328   return nbTouchedAtt;
329 }
330
331
332 //=======================================================================
333 //function : AbortTransaction
334 //purpose  : Aborts the current transaction.
335 //=======================================================================
336
337 void TDF_Data::AbortTransaction() 
338 {
339   if (myTransaction>0)
340     Undo(TDF_Data::CommitTransaction(Standard_True),Standard_False);
341   TDF_Data_DebugModified("New ABORT");
342 }
343
344
345 //=======================================================================
346 //function : AbortUntilTransaction
347 //purpose  : Aborts the transactions until AND including the given index.
348 //=======================================================================
349
350 void TDF_Data::AbortUntilTransaction(const Standard_Integer untilTransaction)
351 {
352   if (untilTransaction>0)
353     Undo(TDF_Data::CommitUntilTransaction(untilTransaction,Standard_True),Standard_False);
354 }
355
356
357 //=======================================================================
358 //function : IsApplicable
359 //purpose  : 
360 //=======================================================================
361
362 Standard_Boolean TDF_Data::IsApplicable
363 (const Handle(TDF_Delta)& aDelta) const
364 {
365   return !aDelta.IsNull() && aDelta->IsApplicable(myTime);
366 }
367
368
369 //=======================================================================
370 //function : Undo
371 //purpose  : Applies a delta to undo  actions.
372 //=======================================================================
373
374 Handle(TDF_Delta) TDF_Data::Undo
375 (const Handle(TDF_Delta)& aDelta,
376  const Standard_Boolean withDelta)
377 {
378   Handle(TDF_Delta) newDelta;
379   if (!aDelta.IsNull ()) {
380     if (aDelta->IsApplicable(myTime)) {
381       if (withDelta) OpenTransaction();
382 #ifdef OCCT_DEBUG_DELTA
383       cout<<"TDF_Data::Undo applies this delta:"<<endl;
384       aDelta->Dump(cout);
385 #endif
386       aDelta->BeforeOrAfterApply(Standard_True);
387       myNotUndoMode = Standard_False;
388       aDelta->Apply ();
389       myNotUndoMode = Standard_True;
390       if (withDelta) {
391         newDelta = CommitTransaction(Standard_True);
392         newDelta->Validity(aDelta->EndTime(),aDelta->BeginTime());
393 #ifdef OCCT_DEBUG_DELTA
394         cout<<"TDF_Data::Undo, after validity correction, Delta is now available from time \t#"<<newDelta->BeginTime()<<" to time \t#"<<newDelta->EndTime()<<endl;
395 #endif
396       }
397       myTime = aDelta->BeginTime();
398       aDelta->BeforeOrAfterApply(Standard_False);
399     }
400   }
401   return newDelta;
402 }
403
404
405
406 //=======================================================================
407 //function : Dump
408 //purpose  : 
409 //=======================================================================
410
411 Standard_OStream& TDF_Data::Dump(Standard_OStream& anOS) const
412 {
413   anOS<<"Dump of a TDF_Data."<<endl;
414   anOS<<"Current transaction: "<<myTransaction;
415   anOS<<"; Current tick: "<<myTime<<";"<<endl;
416   return anOS;
417 }