Update RevisionGraph to 15570
[TortoiseGit.git] / src / TortoiseProc / RevisionGraph / VisibleGraphNode.cpp
blob40f5d771cc258e0a8244ffdbd10a452d581f1ba8
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.
20 #include "StdAfx.h"
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
43 return (prev != NULL)
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)
54 , copyTargetFactory()
55 , nodeCount (0)
59 // just checkin ...
61 CVisibleGraphNode::CFactory::~CFactory()
63 assert (nodeCount == 0);
66 // factory interface
68 CVisibleGraphNode* CVisibleGraphNode::CFactory::Create
69 ( const CFullGraphNode* base
70 , CVisibleGraphNode* prev
71 , bool preserveNode)
73 CVisibleGraphNode * result = static_cast<CVisibleGraphNode *>(nodePool.malloc());
74 new (result) CVisibleGraphNode (base, prev, copyTargetFactory, preserveNode);
76 ++nodeCount;
77 return result;
80 void CVisibleGraphNode::CFactory::Destroy (CVisibleGraphNode* node)
82 node->DestroySubNodes (*this, copyTargetFactory);
83 node->DestroyTags (*this);
85 node->~CVisibleGraphNode();
86 nodePool.free (node);
88 --nodeCount;
91 void CVisibleGraphNode::CFactory::Destroy (CCopyTarget*& copyTarget)
93 CVisibleGraphNode* node = copyTargetFactory.remove (copyTarget);
94 if (node != NULL)
95 Destroy (node);
98 CVisibleGraphNode::CFoldedTag* CVisibleGraphNode::CFactory::Create
99 ( const CFullGraphNode* tagNode
100 , size_t depth
101 , CFoldedTag* next)
103 CFoldedTag * result = static_cast<CFoldedTag *>(tagPool.malloc());
104 new (result) CFoldedTag (tagNode, depth, next);
105 return result;
108 void CVisibleGraphNode::CFactory::Destroy (CFoldedTag* tag)
110 tag->~CFoldedTag();
111 tagPool.free (tag);
114 // CVisibleGraphNode construction / destruction
116 CVisibleGraphNode::CVisibleGraphNode
117 ( const CFullGraphNode* base
118 , CVisibleGraphNode* prev
119 , CCopyTarget::factory& copyTargetFactory
120 , bool preserveNode)
121 : base (base)
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)
130 if (prev != NULL)
131 if (classification.Is (CNodeClassification::IS_COPY_TARGET))
133 copySource = prev;
134 copyTargetFactory.insert (this, prev->firstCopyTarget);
136 else
138 assert (prev->next == NULL);
140 prev->next = this;
141 this->prev = prev;
145 CVisibleGraphNode::~CVisibleGraphNode()
147 assert (next == NULL);
148 assert (firstCopyTarget == NULL);
149 assert (firstTag == NULL);
152 // destruction utilities
154 void CVisibleGraphNode::DestroySubNodes
155 ( CFactory& factory
156 , CCopyTarget::factory& copyTargetFactory)
158 while (next != NULL)
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);
170 if (target != NULL)
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;
192 ++startIndex;
194 for ( CCopyTarget* target = node->firstCopyTarget
195 ; target != NULL
196 ; target = target->next())
198 startIndex = target->value()->InitIndex (startIndex);
202 return 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
212 ? prev
213 : copySource;
215 // special case: remove one of the roots
217 if (source == NULL)
219 // handle this branch
221 if (next)
223 next->prev = NULL;
224 graph->ReplaceRoot (this, next);
226 else
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);
243 else
245 // move all branches
247 if (firstCopyTarget != NULL)
249 // find insertion point
251 CCopyTarget** targetFirstCopyTarget = &source->firstCopyTarget;
252 while (*targetFirstCopyTarget != NULL)
253 targetFirstCopyTarget = &(*targetFirstCopyTarget)->next();
255 // concatenate list
257 *targetFirstCopyTarget = firstCopyTarget;
259 // adjust copy sources and reset firstCopyTarget
261 for (; firstCopyTarget != NULL; firstCopyTarget = firstCopyTarget->next())
262 firstCopyTarget->value()->copySource = source;
265 // move all tags
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;
278 firstTag = NULL;
281 // de-link this node
283 if (prev != NULL)
285 prev->next = next;
286 if (next)
287 next->prev = prev;
289 else
291 // find the copy struct that links to *this
293 CCopyTarget** copy = &source->firstCopyTarget;
294 for (
295 ; (*copy != NULL) && ((*copy)->value() != this)
296 ; copy = &(*copy)->next())
300 assert (*copy != NULL);
302 // make it point to next or remove it
304 if (next)
306 (*copy)->value() = next;
307 next->prev = NULL;
308 next->copySource = source;
310 else
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;
323 // destruct this
325 next = NULL;
326 graph->GetFactory().Destroy (this);
329 // remove node and sub-tree
331 void CVisibleGraphNode::DropSubTree (CVisibleGraph* graph)
333 // de-link this node
335 if (prev != NULL)
337 prev->next = NULL;
339 else if (copySource != NULL)
341 // find the copy struct that links to *this
343 CCopyTarget** copy = &copySource->firstCopyTarget;
344 for (
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;
359 *copy = next;
362 // destruct this
364 graph->GetFactory().Destroy (this);
367 // remove node and add it as folded tag to the parent
369 void CVisibleGraphNode::FoldTag (CVisibleGraph* graph)
371 assert (( copySource
372 || ( classification.Is (CNodeClassification::IS_RENAMED))
373 && prev)
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;
380 while (node->next)
381 node = node->next;
383 while (node != this)
385 CVisibleGraphNode* previous = node->prev;
386 if (node->classification.Is (CNodeClassification::IS_RENAMED))
387 node->FoldTag (graph);
388 else
389 node->DropNode (graph, true);
391 node = previous;
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)
407 tag->depth++;
408 lastTag = tag;
411 lastTag->next = source->firstTag;
412 source->firstTag = firstTag;
413 firstTag = NULL;
416 // create a tag for this node
418 CFoldedTag* newTag
419 = graph->GetFactory().Create (base, 0, source->firstTag);
420 source->firstTag = newTag;
422 // remove this node
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
434 ? prev
435 : copySource;
437 // at the beginning of some branch
439 if (copySource != NULL)
441 // find the copy struct that links to *this
443 for ( CCopyTarget** copy = &copySource->firstCopyTarget
444 ; *copy != NULL
445 ; copy = &(*copy)->next())
447 if ((*copy)->value() == this)
449 // remove it from the list
451 (*copy)->value() = NULL;
452 graph->GetFactory().Destroy (*copy);
454 // update this node
456 copySource = NULL;
457 break;
461 assert (copySource == NULL);
463 else
465 // within a branch line?
467 if (prev != NULL)
469 prev->next = NULL;
470 prev = NULL;
472 else
474 // already a root
476 return;
480 // remove the source tree, if requested
482 if (deleteSource)
484 CVisibleGraphNode* oldRoot = this;
485 while (source != NULL)
487 oldRoot = source;
488 source = oldRoot->copySource == NULL
489 ? oldRoot->prev
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);
502 else
504 // now, add this as a new root
506 graph->AddRoot (this);