2 Description: history graph computation
\r
4 Author: Marco Costalba (C) 2005-2007
\r
6 Copyright: See COPYING file that comes with this distribution
\r
12 #define IS_NODE(x) (x == NODE || x == NODE_R || x == NODE_L)
\r
15 void Lanes::init(const QString& expectedSha) {
\r
20 add(BRANCH, expectedSha, activeLane);
\r
23 void Lanes::clear() {
\r
29 void Lanes::setBoundary(bool b) {
\r
30 // changes the state so must be called as first one
\r
32 NODE = b ? BOUNDARY_C : MERGE_FORK;
\r
33 NODE_R = b ? BOUNDARY_R : MERGE_FORK_R;
\r
34 NODE_L = b ? BOUNDARY_L : MERGE_FORK_L;
\r
38 typeVec[activeLane] = BOUNDARY;
\r
41 bool Lanes::isFork(const QString& sha, bool& isDiscontinuity) {
\r
43 int pos = findNextSha(sha, 0);
\r
44 isDiscontinuity = (activeLane != pos);
\r
45 if (pos == -1) // new branch case
\r
48 return (findNextSha(sha, pos + 1) != -1);
\r
53 pos = findNextSha(sha, pos + 1);
\r
54 // if (isDiscontinuity)
\r
55 // isDiscontinuity = (activeLane != pos);
\r
61 void Lanes::setFork(const QString& sha) {
\r
63 int rangeStart, rangeEnd, idx;
\r
64 rangeStart = rangeEnd = idx = findNextSha(sha, 0);
\r
68 typeVec[idx] = TAIL;
\r
69 idx = findNextSha(sha, idx + 1);
\r
71 typeVec[activeLane] = NODE;
\r
73 int& startT = typeVec[rangeStart];
\r
74 int& endT = typeVec[rangeEnd];
\r
88 for (int i = rangeStart + 1; i < rangeEnd; i++) {
\r
90 int& t = typeVec[i];
\r
92 if (t == NOT_ACTIVE)
\r
95 else if (t == EMPTY)
\r
100 void Lanes::setMerge(const QStringList& parents) {
\r
101 // setFork() must be called before setMerge()
\r
104 return; // handle as a simple active line
\r
106 int& t = typeVec[activeLane];
\r
107 bool wasFork = (t == NODE);
\r
108 bool wasFork_L = (t == NODE_L);
\r
109 bool wasFork_R = (t == NODE_R);
\r
110 bool startJoinWasACross = false, endJoinWasACross = false;
\r
114 int rangeStart = activeLane, rangeEnd = activeLane;
\r
115 QStringList::const_iterator it(parents.begin());
\r
116 for (++it; it != parents.end(); ++it) { // skip first parent
\r
118 int idx = findNextSha(*it, 0);
\r
121 if (idx > rangeEnd) {
\r
124 endJoinWasACross = typeVec[idx] == CROSS;
\r
127 if (idx < rangeStart) {
\r
130 startJoinWasACross = typeVec[idx] == CROSS;
\r
133 typeVec[idx] = JOIN;
\r
135 rangeEnd = add(HEAD, *it, rangeEnd + 1);
\r
137 int& startT = typeVec[rangeStart];
\r
138 int& endT = typeVec[rangeEnd];
\r
140 if (startT == NODE && !wasFork && !wasFork_R)
\r
143 if (endT == NODE && !wasFork && !wasFork_L)
\r
146 if (startT == JOIN && !startJoinWasACross)
\r
149 if (endT == JOIN && !endJoinWasACross)
\r
152 if (startT == HEAD)
\r
158 for (int i = rangeStart + 1; i < rangeEnd; i++) {
\r
160 int& t = typeVec[i];
\r
162 if (t == NOT_ACTIVE)
\r
165 else if (t == EMPTY)
\r
168 else if (t == TAIL_R || t == TAIL_L)
\r
173 void Lanes::setInitial() {
\r
175 int& t = typeVec[activeLane];
\r
176 if (!IS_NODE(t) && t != APPLIED)
\r
177 t = (boundary ? BOUNDARY : INITIAL);
\r
180 void Lanes::setApplied() {
\r
182 // applied patches are not merges, nor forks
\r
183 typeVec[activeLane] = APPLIED; // TODO test with boundaries
\r
186 void Lanes::changeActiveLane(const QString& sha) {
\r
188 int& t = typeVec[activeLane];
\r
189 if (t == INITIAL || isBoundary(t))
\r
194 int idx = findNextSha(sha, 0); // find first sha
\r
196 typeVec[idx] = ACTIVE; // called before setBoundary()
\r
198 idx = add(BRANCH, sha, activeLane); // new branch
\r
203 void Lanes::afterMerge() {
\r
206 return; // will be reset by changeActiveLane()
\r
208 for (unsigned int i = 0; i < typeVec.size(); i++) {
\r
210 int& t = typeVec[i];
\r
212 if (isHead(t) || isJoin(t) || t == CROSS)
\r
215 else if (t == CROSS_EMPTY)
\r
218 else if (IS_NODE(t))
\r
223 void Lanes::afterFork() {
\r
225 for (unsigned int i = 0; i < typeVec.size(); i++) {
\r
227 int& t = typeVec[i];
\r
232 else if (isTail(t) || t == CROSS_EMPTY)
\r
235 if (!boundary && IS_NODE(t))
\r
236 t = ACTIVE; // boundary will be reset by changeActiveLane()
\r
238 while (typeVec.back() == EMPTY) {
\r
239 typeVec.pop_back();
\r
240 nextShaVec.pop_back();
\r
244 bool Lanes::isBranch() {
\r
246 return (typeVec[activeLane] == BRANCH);
\r
249 void Lanes::afterBranch() {
\r
251 typeVec[activeLane] = ACTIVE; // TODO test with boundaries
\r
254 void Lanes::afterApplied() {
\r
256 typeVec[activeLane] = ACTIVE; // TODO test with boundaries
\r
259 void Lanes::nextParent(const QString& sha) {
\r
261 nextShaVec[activeLane] = (boundary ? QString(_T("")) : sha);
\r
264 int Lanes::findNextSha(const QString& next, int pos) {
\r
266 for (unsigned int i = pos; i < nextShaVec.size(); i++)
\r
267 if (nextShaVec[i] == next)
\r
272 int Lanes::findType(int type, int pos) {
\r
274 for (unsigned int i = pos; i < typeVec.size(); i++)
\r
275 if (typeVec[i] == type)
\r
280 int Lanes::add(int type, const QString& next, int pos) {
\r
282 // first check empty lanes starting from pos
\r
283 if (pos < (int)typeVec.size()) {
\r
284 pos = findType(EMPTY, pos);
\r
286 typeVec[pos] = type;
\r
287 nextShaVec[pos] = next;
\r
291 // if all lanes are occupied add a new lane
\r
292 typeVec.push_back(type);
\r
293 nextShaVec.push_back(next);
\r
294 return typeVec.size() - 1;
\r