Fix last fix...
[qgit4.git] / src / lanes.cpp
blob335822ed8bef3058c828e4cfb35dde12d09721d5
1 /*
2 Description: history graph computation
4 Author: Marco Costalba (C) 2005-2007
6 Copyright: See COPYING file that comes with this distribution
8 */
9 #include <QStringList>
10 #include "common.h"
11 #include "lanes.h"
13 #define IS_NODE(x) (x == NODE || x == NODE_R || x == NODE_L)
15 using namespace QGit;
17 void Lanes::init(const QString& expectedSha) {
19 clear();
20 activeLane = 0;
21 setBoundary(false);
22 add(BRANCH, expectedSha, activeLane);
25 void Lanes::clear() {
27 typeVec.clear();
28 nextShaVec.clear();
31 void Lanes::setBoundary(bool b) {
32 // changes the state so must be called as first one
34 NODE = b ? BOUNDARY_C : MERGE_FORK;
35 NODE_R = b ? BOUNDARY_R : MERGE_FORK_R;
36 NODE_L = b ? BOUNDARY_L : MERGE_FORK_L;
37 boundary = b;
39 if (boundary)
40 typeVec[activeLane] = BOUNDARY;
43 bool Lanes::isFork(const QString& sha, bool& isDiscontinuity) {
45 int pos = findNextSha(sha, 0);
46 isDiscontinuity = (activeLane != pos);
47 if (pos == -1) // new branch case
48 return false;
50 return (findNextSha(sha, pos + 1) != -1);
52 int cnt = 0;
53 while (pos != -1) {
54 cnt++;
55 pos = findNextSha(sha, pos + 1);
56 // if (isDiscontinuity)
57 // isDiscontinuity = (activeLane != pos);
59 return (cnt > 1);
63 void Lanes::setFork(const QString& sha) {
65 int rangeStart, rangeEnd, idx;
66 rangeStart = rangeEnd = idx = findNextSha(sha, 0);
68 while (idx != -1) {
69 rangeEnd = idx;
70 typeVec[idx] = TAIL;
71 idx = findNextSha(sha, idx + 1);
73 typeVec[activeLane] = NODE;
75 int& startT = typeVec[rangeStart];
76 int& endT = typeVec[rangeEnd];
78 if (startT == NODE)
79 startT = NODE_L;
81 if (endT == NODE)
82 endT = NODE_R;
84 if (startT == TAIL)
85 startT = TAIL_L;
87 if (endT == TAIL)
88 endT = TAIL_R;
90 for (int i = rangeStart + 1; i < rangeEnd; i++) {
92 int& t = typeVec[i];
94 if (t == NOT_ACTIVE)
95 t = CROSS;
97 else if (t == EMPTY)
98 t = CROSS_EMPTY;
102 void Lanes::setMerge(const QStringList& parents) {
103 // setFork() must be called before setMerge()
105 if (boundary)
106 return; // handle as a simple active line
108 int& t = typeVec[activeLane];
109 bool wasFork = (t == NODE);
110 bool wasFork_L = (t == NODE_L);
111 bool wasFork_R = (t == NODE_R);
112 bool startJoinWasACross = false, endJoinWasACross = false;
114 t = NODE;
116 int rangeStart = activeLane, rangeEnd = activeLane;
117 QStringList::const_iterator it(parents.constBegin());
118 for (++it; it != parents.constEnd(); ++it) { // skip first parent
120 int idx = findNextSha(*it, 0);
121 if (idx != -1) {
123 if (idx > rangeEnd) {
125 rangeEnd = idx;
126 endJoinWasACross = typeVec[idx] == CROSS;
129 if (idx < rangeStart) {
131 rangeStart = idx;
132 startJoinWasACross = typeVec[idx] == CROSS;
135 typeVec[idx] = JOIN;
136 } else
137 rangeEnd = add(HEAD, *it, rangeEnd + 1);
139 int& startT = typeVec[rangeStart];
140 int& endT = typeVec[rangeEnd];
142 if (startT == NODE && !wasFork && !wasFork_R)
143 startT = NODE_L;
145 if (endT == NODE && !wasFork && !wasFork_L)
146 endT = NODE_R;
148 if (startT == JOIN && !startJoinWasACross)
149 startT = JOIN_L;
151 if (endT == JOIN && !endJoinWasACross)
152 endT = JOIN_R;
154 if (startT == HEAD)
155 startT = HEAD_L;
157 if (endT == HEAD)
158 endT = HEAD_R;
160 for (int i = rangeStart + 1; i < rangeEnd; i++) {
162 int& t = typeVec[i];
164 if (t == NOT_ACTIVE)
165 t = CROSS;
167 else if (t == EMPTY)
168 t = CROSS_EMPTY;
170 else if (t == TAIL_R || t == TAIL_L)
171 t = TAIL;
175 void Lanes::setInitial() {
177 int& t = typeVec[activeLane];
178 if (!IS_NODE(t) && t != APPLIED)
179 t = (boundary ? BOUNDARY : INITIAL);
182 void Lanes::setApplied() {
184 // applied patches are not merges, nor forks
185 typeVec[activeLane] = APPLIED; // TODO test with boundaries
188 void Lanes::changeActiveLane(const QString& sha) {
190 int& t = typeVec[activeLane];
191 if (t == INITIAL || isBoundary(t))
192 t = EMPTY;
193 else
194 t = NOT_ACTIVE;
196 int idx = findNextSha(sha, 0); // find first sha
197 if (idx != -1)
198 typeVec[idx] = ACTIVE; // called before setBoundary()
199 else
200 idx = add(BRANCH, sha, activeLane); // new branch
202 activeLane = idx;
205 void Lanes::afterMerge() {
207 if (boundary)
208 return; // will be reset by changeActiveLane()
210 for (int i = 0; i < typeVec.count(); i++) {
212 int& t = typeVec[i];
214 if (isHead(t) || isJoin(t) || t == CROSS)
215 t = NOT_ACTIVE;
217 else if (t == CROSS_EMPTY)
218 t = EMPTY;
220 else if (IS_NODE(t))
221 t = ACTIVE;
225 void Lanes::afterFork() {
227 for (int i = 0; i < typeVec.count(); i++) {
229 int& t = typeVec[i];
231 if (t == CROSS)
232 t = NOT_ACTIVE;
234 else if (isTail(t) || t == CROSS_EMPTY)
235 t = EMPTY;
237 if (!boundary && IS_NODE(t))
238 t = ACTIVE; // boundary will be reset by changeActiveLane()
240 while (typeVec.last() == EMPTY) {
241 typeVec.pop_back();
242 nextShaVec.pop_back();
246 bool Lanes::isBranch() {
248 return (typeVec[activeLane] == BRANCH);
251 void Lanes::afterBranch() {
253 typeVec[activeLane] = ACTIVE; // TODO test with boundaries
256 void Lanes::afterApplied() {
258 typeVec[activeLane] = ACTIVE; // TODO test with boundaries
261 void Lanes::nextParent(const QString& sha) {
263 nextShaVec[activeLane] = (boundary ? "" : sha);
266 int Lanes::findNextSha(const QString& next, int pos) {
268 for (int i = pos; i < nextShaVec.count(); i++)
269 if (nextShaVec[i] == next)
270 return i;
271 return -1;
274 int Lanes::findType(int type, int pos) {
276 for (int i = pos; i < typeVec.count(); i++)
277 if (typeVec[i] == type)
278 return i;
279 return -1;
282 int Lanes::add(int type, const QString& next, int pos) {
284 // first check empty lanes starting from pos
285 if (pos < (int)typeVec.count()) {
286 pos = findType(EMPTY, pos);
287 if (pos != -1) {
288 typeVec[pos] = type;
289 nextShaVec[pos] = next;
290 return pos;
293 // if all lanes are occupied add a new lane
294 typeVec.append(type);
295 nextShaVec.append(next);
296 return typeVec.count() - 1;