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