1 // TortoiseSVN - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2008 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "VisibleGraphNode.h"
22 #include "VisibleGraph.h"
24 // CVisibleGraphNode::CFoldedTag methods
26 bool CVisibleGraphNode::CFoldedTag::IsAlias() const
28 const CFullGraphNode
* prev
= tagNode
->GetSource();
30 // skip all non-modifying nodes and make prev point to
31 // either the copy node or the last modification
33 while ( (prev
!= NULL
)
34 && (!prev
->GetClassification().IsAnyOf
35 (CNodeClassification::IS_OPERATION_MASK
)))
37 prev
= prev
->GetPrevious();
40 // it's an alias if the previous node is a tag and has
41 // not been modified since
44 && prev
->GetClassification().Is (CNodeClassification::IS_TAG
)
45 && prev
->GetClassification().IsAnyOf ( CNodeClassification::IS_ADDED
46 + CNodeClassification::IS_RENAMED
);
49 // CVisibleGraphNode::CFactory methods
51 CVisibleGraphNode::CFactory::CFactory()
52 : nodePool (sizeof (CVisibleGraphNode
), 1024)
53 , tagPool (sizeof (CFoldedTag
), 1024)
61 CVisibleGraphNode::CFactory::~CFactory()
63 assert (nodeCount
== 0);
68 CVisibleGraphNode
* CVisibleGraphNode::CFactory::Create
69 ( const CFullGraphNode
* base
70 , CVisibleGraphNode
* prev
73 CVisibleGraphNode
* result
= static_cast<CVisibleGraphNode
*>(nodePool
.malloc());
74 new (result
) CVisibleGraphNode (base
, prev
, copyTargetFactory
, preserveNode
);
80 void CVisibleGraphNode::CFactory::Destroy (CVisibleGraphNode
* node
)
82 node
->DestroySubNodes (*this, copyTargetFactory
);
83 node
->DestroyTags (*this);
85 node
->~CVisibleGraphNode();
91 void CVisibleGraphNode::CFactory::Destroy (CCopyTarget
*& copyTarget
)
93 CVisibleGraphNode
* node
= copyTargetFactory
.remove (copyTarget
);
98 CVisibleGraphNode::CFoldedTag
* CVisibleGraphNode::CFactory::Create
99 ( const CFullGraphNode
* tagNode
103 CFoldedTag
* result
= static_cast<CFoldedTag
*>(tagPool
.malloc());
104 new (result
) CFoldedTag (tagNode
, depth
, next
);
108 void CVisibleGraphNode::CFactory::Destroy (CFoldedTag
* tag
)
114 // CVisibleGraphNode construction / destruction
116 CVisibleGraphNode::CVisibleGraphNode
117 ( const CFullGraphNode
* base
118 , CVisibleGraphNode
* prev
119 , CCopyTarget::factory
& copyTargetFactory
122 , firstCopyTarget (NULL
), firstTag (NULL
)
123 , prev (NULL
), next (NULL
), copySource (NULL
)
124 , classification ( preserveNode
125 ? ( base
->GetClassification().GetFlags()
126 | CNodeClassification::MUST_BE_PRESERVED
)
127 : base
->GetClassification().GetFlags())
128 , index ((index_t
)NO_INDEX
)
131 if (classification
.Is (CNodeClassification::IS_COPY_TARGET
))
134 copyTargetFactory
.insert (this, prev
->firstCopyTarget
);
138 assert (prev
->next
== NULL
);
145 CVisibleGraphNode::~CVisibleGraphNode()
147 assert (next
== NULL
);
148 assert (firstCopyTarget
== NULL
);
149 assert (firstTag
== NULL
);
152 // destruction utilities
154 void CVisibleGraphNode::DestroySubNodes
156 , CCopyTarget::factory
& copyTargetFactory
)
160 CVisibleGraphNode
* toDestroy
= next
;
161 next
= toDestroy
->next
;
162 toDestroy
->next
= NULL
;
164 factory
.Destroy (toDestroy
);
167 while (firstCopyTarget
)
169 CVisibleGraphNode
* target
= copyTargetFactory
.remove (firstCopyTarget
);
171 factory
.Destroy (target
);
175 void CVisibleGraphNode::DestroyTags (CFactory
& factory
)
177 while (firstTag
!= NULL
)
179 CFoldedTag
* toDestroy
= firstTag
;
180 firstTag
= toDestroy
->next
;
181 factory
.Destroy (toDestroy
);
185 // set index members within the whole sub-tree
187 index_t
CVisibleGraphNode::InitIndex (index_t startIndex
)
189 for (CVisibleGraphNode
* node
= this; node
!= NULL
; node
= node
->next
)
191 node
->index
= startIndex
;
194 for ( CCopyTarget
* target
= node
->firstCopyTarget
196 ; target
= target
->next())
198 startIndex
= target
->value()->InitIndex (startIndex
);
205 // remove node and move links to pre-decessor
207 void CVisibleGraphNode::DropNode (CVisibleGraph
* graph
, bool preserveTags
)
209 // previous node to receive all our links
211 CVisibleGraphNode
* source
= copySource
== NULL
215 // special case: remove one of the roots
219 // handle this branch
224 graph
->ReplaceRoot (this, next
);
228 graph
->RemoveRoot (this);
231 // add sub-branches as new roots
233 for (; firstCopyTarget
!= NULL
; firstCopyTarget
= firstCopyTarget
->next())
235 firstCopyTarget
->value()->copySource
= NULL
;
236 graph
->AddRoot (firstCopyTarget
->value());
239 // no tag-folding supported here
241 assert (firstTag
== NULL
);
247 if (firstCopyTarget
!= NULL
)
249 // find insertion point
251 CCopyTarget
** targetFirstCopyTarget
= &source
->firstCopyTarget
;
252 while (*targetFirstCopyTarget
!= NULL
)
253 targetFirstCopyTarget
= &(*targetFirstCopyTarget
)->next();
257 *targetFirstCopyTarget
= firstCopyTarget
;
259 // adjust copy sources and reset firstCopyTarget
261 for (; firstCopyTarget
!= NULL
; firstCopyTarget
= firstCopyTarget
->next())
262 firstCopyTarget
->value()->copySource
= source
;
267 if (preserveTags
&& (firstTag
!= NULL
))
269 // find insertion point
271 CFoldedTag
** targetFirstTag
= &source
->firstTag
;
272 while (*targetFirstTag
!= NULL
)
273 targetFirstTag
= &(*targetFirstTag
)->next
;
275 // concatenate list and reset firstTag
277 *targetFirstTag
= firstTag
;
291 // find the copy struct that links to *this
293 CCopyTarget
** copy
= &source
->firstCopyTarget
;
295 ; (*copy
!= NULL
) && ((*copy
)->value() != this)
296 ; copy
= &(*copy
)->next())
300 assert (*copy
!= NULL
);
302 // make it point to next or remove it
306 (*copy
)->value() = next
;
308 next
->copySource
= source
;
312 // remove from original list and attach it to *this for destruction
314 firstCopyTarget
= *copy
;
315 *copy
= (*copy
)->next();
317 firstCopyTarget
->next() = NULL
;
318 firstCopyTarget
->value() = NULL
;
326 graph
->GetFactory().Destroy (this);
329 // remove node and sub-tree
331 void CVisibleGraphNode::DropSubTree (CVisibleGraph
* graph
)
339 else if (copySource
!= NULL
)
341 // find the copy struct that links to *this
343 CCopyTarget
** copy
= ©Source
->firstCopyTarget
;
345 ; (*copy
!= NULL
) && ((*copy
)->value() != this)
346 ; copy
= &(*copy
)->next())
350 assert (*copy
!= NULL
);
352 // remove from original list and attach it to *this for destruction
354 CCopyTarget
* next
= (*copy
)->next();
355 (*copy
)->next() = firstCopyTarget
;
356 (*copy
)->value() = NULL
;
358 firstCopyTarget
= *copy
;
364 graph
->GetFactory().Destroy (this);
367 // remove node and add it as folded tag to the parent
369 void CVisibleGraphNode::FoldTag (CVisibleGraph
* graph
)
372 || ( classification
.Is (CNodeClassification::IS_RENAMED
))
374 && "This operation is only valid for copy nodes!");
376 // fold the whole branch into this node.
377 // Handle renames as sub-tags
379 CVisibleGraphNode
* node
= this;
385 CVisibleGraphNode
* previous
= node
->prev
;
386 if (node
->classification
.Is (CNodeClassification::IS_RENAMED
))
387 node
->FoldTag (graph
);
389 node
->DropNode (graph
, true);
394 // fold all sub-branches as tags into this node
396 while (firstCopyTarget
!= NULL
)
397 firstCopyTarget
->value()->FoldTag (graph
);
399 // move tags to parent
401 CVisibleGraphNode
* source
= copySource
== NULL
? prev
: copySource
;
402 if (firstTag
!= NULL
)
404 CFoldedTag
* lastTag
= NULL
;
405 for (CFoldedTag
* tag
= firstTag
; tag
!= NULL
; tag
= tag
->next
)
411 lastTag
->next
= source
->firstTag
;
412 source
->firstTag
= firstTag
;
416 // create a tag for this node
419 = graph
->GetFactory().Create (base
, 0, source
->firstTag
);
420 source
->firstTag
= newTag
;
424 DropNode (graph
, true);
427 /// remove links to this node and make it a new root
429 void CVisibleGraphNode::MakeRoot (CVisibleGraph
* graph
, bool deleteSource
)
431 // previous node to receive all our links
433 CVisibleGraphNode
* source
= copySource
== NULL
437 // at the beginning of some branch
439 if (copySource
!= NULL
)
441 // find the copy struct that links to *this
443 for ( CCopyTarget
** copy
= ©Source
->firstCopyTarget
445 ; copy
= &(*copy
)->next())
447 if ((*copy
)->value() == this)
449 // remove it from the list
451 (*copy
)->value() = NULL
;
452 graph
->GetFactory().Destroy (*copy
);
461 assert (copySource
== NULL
);
465 // within a branch line?
480 // remove the source tree, if requested
484 CVisibleGraphNode
* oldRoot
= this;
485 while (source
!= NULL
)
488 source
= oldRoot
->copySource
== NULL
490 : oldRoot
->copySource
;
493 // now, add this as a new root
495 assert (oldRoot
!= this);
496 graph
->ReplaceRoot (oldRoot
, this);
498 // remove old parent tree
500 graph
->GetFactory().Destroy (oldRoot
);
504 // now, add this as a new root
506 graph
->AddRoot (this);