1 // TortoiseSVN - a Windows shell extension for easy version control
\r
3 // Copyright (C) 2003-2008 - TortoiseSVN
\r
5 // This program is free software; you can redistribute it and/or
\r
6 // modify it under the terms of the GNU General Public License
\r
7 // as published by the Free Software Foundation; either version 2
\r
8 // of the License, or (at your option) any later version.
\r
10 // This program is distributed in the hope that it will be useful,
\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 // GNU General Public License for more details.
\r
15 // You should have received a copy of the GNU General Public License
\r
16 // along with this program; if not, write to the Free Software Foundation,
\r
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\r
21 #include "VisibleGraphNode.h"
\r
22 #include "VisibleGraph.h"
\r
24 // CVisibleGraphNode::CFoldedTag methods
\r
26 bool CVisibleGraphNode::CFoldedTag::IsAlias() const
\r
28 const CFullGraphNode* prev
\r
29 = tagNode->GetPrevious() == NULL
\r
30 ? tagNode->GetCopySource()
\r
31 : tagNode->GetPrevious();
\r
33 // skip all non-modifying nodes and make prev point to
\r
34 // either the copy node or the last modification
\r
36 while ( (prev != NULL)
\r
37 && (!prev->GetClassification().IsAnyOf
\r
38 (CNodeClassification::IS_OPERATION_MASK)))
\r
40 prev = prev->GetPrevious();
\r
43 // it's an alias if the previous node is a tag and has
\r
44 // not been modified since
\r
46 return (prev != NULL)
\r
47 && prev->GetClassification().Is (CNodeClassification::IS_TAG)
\r
48 && prev->GetClassification().IsAnyOf ( CNodeClassification::IS_ADDED
\r
49 + CNodeClassification::IS_RENAMED);
\r
52 // CVisibleGraphNode::CFactory methods
\r
54 CVisibleGraphNode::CFactory::CFactory()
\r
55 : nodePool (sizeof (CVisibleGraphNode), 1024)
\r
56 , tagPool (sizeof (CFoldedTag), 1024)
\r
57 , copyTargetFactory()
\r
62 // factory interface
\r
64 CVisibleGraphNode* CVisibleGraphNode::CFactory::Create
\r
65 ( const CFullGraphNode* base
\r
66 , CVisibleGraphNode* prev
\r
67 , bool preserveNode)
\r
69 CVisibleGraphNode * result = static_cast<CVisibleGraphNode *>(nodePool.malloc());
\r
70 new (result) CVisibleGraphNode (base, prev, copyTargetFactory, preserveNode);
\r
76 void CVisibleGraphNode::CFactory::Destroy (CVisibleGraphNode* node)
\r
78 node->DestroySubNodes (*this, copyTargetFactory);
\r
79 node->DestroyTags (*this);
\r
81 node->~CVisibleGraphNode();
\r
82 nodePool.free (node);
\r
87 CVisibleGraphNode::CFoldedTag* CVisibleGraphNode::CFactory::Create
\r
88 ( const CFullGraphNode* tagNode
\r
92 CFoldedTag * result = static_cast<CFoldedTag *>(tagPool.malloc());
\r
93 new (result) CFoldedTag (tagNode, depth, next);
\r
97 void CVisibleGraphNode::CFactory::Destroy (CFoldedTag* tag)
\r
100 tagPool.free (tag);
\r
103 // CVisibleGraphNode construction / destruction
\r
105 CVisibleGraphNode::CVisibleGraphNode
\r
106 ( const CFullGraphNode* base
\r
107 , CVisibleGraphNode* prev
\r
108 , CCopyTarget::factory& copyTargetFactory
\r
109 , bool preserveNode)
\r
111 , firstCopyTarget (NULL), firstTag (NULL)
\r
112 , prev (NULL), next (NULL), copySource (NULL)
\r
113 , classification ( preserveNode
\r
114 ? base->GetClassification().GetFlags()
\r
115 : ( base->GetClassification().GetFlags()
\r
116 | CNodeClassification::MUST_BE_PRESERVED))
\r
117 , index ((index_t)NO_INDEX)
\r
120 if (classification.Is (CNodeClassification::IS_COPY_TARGET))
\r
123 copyTargetFactory.insert (this, prev->firstCopyTarget);
\r
127 assert (prev->next == NULL);
\r
134 CVisibleGraphNode::~CVisibleGraphNode()
\r
136 assert (next == NULL);
\r
137 assert (firstCopyTarget == NULL);
\r
138 assert (firstTag == NULL);
\r
141 // destruction utilities
\r
143 void CVisibleGraphNode::DestroySubNodes
\r
144 ( CFactory& factory
\r
145 , CCopyTarget::factory& copyTargetFactory)
\r
147 while (next != NULL)
\r
149 CVisibleGraphNode* toDestroy = next;
\r
150 next = toDestroy->next;
\r
151 toDestroy->next = NULL;
\r
153 factory.Destroy (toDestroy);
\r
156 while (firstCopyTarget)
\r
158 CVisibleGraphNode* target = copyTargetFactory.remove (firstCopyTarget);
\r
159 if (target != NULL)
\r
160 factory.Destroy (target);
\r
164 void CVisibleGraphNode::DestroyTags (CFactory& factory)
\r
166 while (firstTag != NULL)
\r
168 CFoldedTag* toDestroy = firstTag;
\r
169 firstTag = toDestroy->next;
\r
170 factory.Destroy (toDestroy);
\r
174 // set index members within the whole sub-tree
\r
176 index_t CVisibleGraphNode::InitIndex (index_t startIndex)
\r
178 for (CVisibleGraphNode* node = this; node != NULL; node = node->next)
\r
180 node->index = startIndex;
\r
183 for ( CCopyTarget* target = node->firstCopyTarget
\r
185 ; target = target->next())
\r
187 startIndex = target->value()->InitIndex (startIndex);
\r
194 // remove node and move links to pre-decessor
\r
196 void CVisibleGraphNode::DropNode (CVisibleGraph* graph)
\r
198 // previous node to receive all our links
\r
200 CVisibleGraphNode* target = copySource == NULL
\r
204 // special case: remove one of the roots
\r
206 if (target == NULL)
\r
208 // handle this branch
\r
213 graph->ReplaceRoot (this, next);
\r
217 graph->RemoveRoot (this);
\r
220 // add sub-branches as new roots
\r
222 for (; firstCopyTarget != NULL; firstCopyTarget = firstCopyTarget->next())
\r
224 firstCopyTarget->value()->copySource = NULL;
\r
225 graph->AddRoot (firstCopyTarget->value());
\r
228 // no tag-folding supported here
\r
230 assert (firstTag == NULL);
\r
234 // move all branches
\r
236 if (firstCopyTarget != NULL)
\r
238 // find insertion point
\r
240 CCopyTarget** targetFirstCopyTarget = &target->firstCopyTarget;
\r
241 while (*targetFirstCopyTarget != NULL)
\r
242 targetFirstCopyTarget = &(*targetFirstCopyTarget)->next();
\r
244 // concatenate list
\r
246 *targetFirstCopyTarget = firstCopyTarget;
\r
248 // adjust copy sources and reset firstCopyTarget
\r
250 for (; firstCopyTarget != NULL; firstCopyTarget = firstCopyTarget->next())
\r
251 firstCopyTarget->value()->copySource = target;
\r
256 if (firstTag != NULL)
\r
258 // find insertion point
\r
260 CFoldedTag** targetFirstTag = &target->firstTag;
\r
261 while (*targetFirstTag != NULL)
\r
262 targetFirstTag = &(*targetFirstTag)->next;
\r
264 // concatenate list and reset firstTag
\r
266 *targetFirstTag = firstTag;
\r
270 // de-link this node
\r
280 // find the copy struct that links to *this
\r
282 CCopyTarget** copy = &target->firstCopyTarget;
\r
284 ; (*copy != NULL) && ((*copy)->value() != this)
\r
285 ; copy = &(*copy)->next())
\r
289 assert (*copy != NULL);
\r
291 // make it point to next or remove it
\r
295 (*copy)->value() = next;
\r
297 next->copySource = target;
\r
301 // remove from original list and attach it to *this for destruction
\r
303 firstCopyTarget = *copy;
\r
304 *copy = (*copy)->next();
\r
306 firstCopyTarget->next() = NULL;
\r
307 firstCopyTarget->value() = NULL;
\r
315 graph->GetFactory().Destroy (this);
\r
318 // remove node and add it as folded tag to the parent
\r
320 void CVisibleGraphNode::FoldTag (CVisibleGraph* graph)
\r
322 assert ((copySource || classification.Is (CNodeClassification::IS_RENAMED))
\r
323 && "This operation is only valid for copy nodes!");
\r
325 // fold the whole branch into this node.
\r
326 // Handle renames as sub-tags
\r
328 CVisibleGraphNode* node = this;
\r
332 while (node != this)
\r
334 CVisibleGraphNode* previous = node->prev;
\r
335 if (node->classification.Is (CNodeClassification::IS_RENAMED))
\r
336 node->FoldTag (graph);
\r
338 node->DropNode (graph);
\r
343 // fold all sub-branches as tags into this node
\r
345 while (firstCopyTarget != NULL)
\r
346 firstCopyTarget->value()->FoldTag (graph);
\r
348 // move tags to parent
\r
350 CVisibleGraphNode* source = copySource == NULL ? prev : copySource;
\r
351 if (firstTag != NULL)
\r
353 CFoldedTag* lastTag = NULL;
\r
354 for (CFoldedTag* tag = firstTag; tag != NULL; tag = tag->next)
\r
360 lastTag->next = source->firstTag;
\r
361 source->firstTag = firstTag;
\r
365 // create a tag for this node
\r
367 CFoldedTag* newTag
\r
368 = graph->GetFactory().Create (base, 0, source->firstTag);
\r
369 source->firstTag = newTag;
\r
371 // remove this node
\r