-/*
- Description: history graph computation
-
- Author: Marco Costalba (C) 2005-2007
-
- Copyright: See COPYING file that comes with this distribution
-
-*/
-#include "stdafx.h"
-#include "lanes.h"
-
-#define IS_NODE(x) (x == NODE || x == NODE_R || x == NODE_L)
-
-
-void Lanes::init(const QString& expectedSha) {
-
- clear();
- activeLane = 0;
- setBoundary(false);
- add(BRANCH, expectedSha, activeLane);
-}
-
-void Lanes::clear() {
-
- typeVec.clear();
- nextShaVec.clear();
-}
-
-void Lanes::setBoundary(bool b) {
-// changes the state so must be called as first one
-
- NODE = b ? BOUNDARY_C : MERGE_FORK;
- NODE_R = b ? BOUNDARY_R : MERGE_FORK_R;
- NODE_L = b ? BOUNDARY_L : MERGE_FORK_L;
- boundary = b;
-
- if (boundary)
- typeVec[activeLane] = BOUNDARY;
-}
-
-bool Lanes::isFork(const QString& sha, bool& isDiscontinuity) {
-
- int pos = findNextSha(sha, 0);
- isDiscontinuity = (activeLane != pos);
- if (pos == -1) // new branch case
- return false;
-
- return (findNextSha(sha, pos + 1) != -1);
-/*
- int cnt = 0;
- while (pos != -1) {
- cnt++;
- pos = findNextSha(sha, pos + 1);
-// if (isDiscontinuity)
-// isDiscontinuity = (activeLane != pos);
- }
- return (cnt > 1);
-*/
-}
-
-void Lanes::setFork(const QString& sha) {
-
- int rangeStart, rangeEnd, idx;
- rangeStart = rangeEnd = idx = findNextSha(sha, 0);
-
- while (idx != -1) {
- rangeEnd = idx;
- typeVec[idx] = TAIL;
- idx = findNextSha(sha, idx + 1);
- }
- typeVec[activeLane] = NODE;
-
- int& startT = typeVec[rangeStart];
- int& endT = typeVec[rangeEnd];
-
- if (startT == NODE)
- startT = NODE_L;
-
- if (endT == NODE)
- endT = NODE_R;
-
- if (startT == TAIL)
- startT = TAIL_L;
-
- if (endT == TAIL)
- endT = TAIL_R;
-
- for (int i = rangeStart + 1; i < rangeEnd; i++) {
-
- int& t = typeVec[i];
-
- if (t == NOT_ACTIVE)
- t = CROSS;
-
- else if (t == EMPTY)
- t = CROSS_EMPTY;
- }
-}
-
-void Lanes::setMerge(const QStringList& parents) {
-// setFork() must be called before setMerge()
-
- if (boundary)
- return; // handle as a simple active line
-
- int& t = typeVec[activeLane];
- bool wasFork = (t == NODE);
- bool wasFork_L = (t == NODE_L);
- bool wasFork_R = (t == NODE_R);
- bool joinWasACross = false;
-
- t = NODE;
-
- int rangeStart = activeLane, rangeEnd = activeLane;
-
- QStringList::const_iterator it=parents.begin();
-
- for (++it; it != parents.end(); ++it) { // skip first parent
-
- int idx = findNextSha(*it, 0);
- if (idx != -1) {
-
- if (typeVec[idx] == CROSS)
- joinWasACross = true;
-
- typeVec[idx] = JOIN;
-
- if (idx > rangeEnd)
- rangeEnd = idx;
-
- if (idx < rangeStart)
- rangeStart = idx;
- } else
- rangeEnd = add(HEAD, *it, rangeEnd + 1);
- }
- int& startT = typeVec[rangeStart];
- int& endT = typeVec[rangeEnd];
-
- if (startT == NODE && !wasFork && !wasFork_R)
- startT = NODE_L;
-
- if (endT == NODE && !wasFork && !wasFork_L)
- endT = NODE_R;
-
- if (startT == JOIN && !joinWasACross)
- startT = JOIN_L;
-
- if (endT == JOIN && !joinWasACross)
- endT = JOIN_R;
-
- if (startT == HEAD)
- startT = HEAD_L;
-
- if (endT == HEAD)
- endT = HEAD_R;
-
- for (int i = rangeStart + 1; i < rangeEnd; i++) {
-
- int& t = typeVec[i];
-
- if (t == NOT_ACTIVE)
- t = CROSS;
-
- else if (t == EMPTY)
- t = CROSS_EMPTY;
-
- else if (t == TAIL_R || t == TAIL_L)
- t = TAIL;
- }
-}
-
-void Lanes::setInitial() {
-
- int& t = typeVec[activeLane];
- if (!IS_NODE(t) && t != APPLIED)
- t = (boundary ? BOUNDARY : INITIAL);
-}
-
-void Lanes::setApplied() {
-
- // applied patches are not merges, nor forks
- typeVec[activeLane] = APPLIED; // TODO test with boundaries
-}
-
-void Lanes::changeActiveLane(const QString& sha) {
-
- int& t = typeVec[activeLane];
- if (t == INITIAL || isBoundary(t))
- t = EMPTY;
- else
- t = NOT_ACTIVE;
-
- int idx = findNextSha(sha, 0); // find first sha
- if (idx != -1)
- typeVec[idx] = ACTIVE; // called before setBoundary()
- else
- idx = add(BRANCH, sha, activeLane); // new branch
-
- activeLane = idx;
-}
-
-void Lanes::afterMerge() {
-
- if (boundary)
- return; // will be reset by changeActiveLane()
-
- for (unsigned int i = 0; i < typeVec.size(); i++) {
-
- int& t = typeVec[i];
-
- if (isHead(t) || isJoin(t) || t == CROSS)
- t = NOT_ACTIVE;
-
- else if (t == CROSS_EMPTY)
- t = EMPTY;
-
- else if (IS_NODE(t))
- t = ACTIVE;
- }
-}
-
-void Lanes::afterFork() {
-
- for (unsigned int i = 0; i < typeVec.size(); i++) {
-
- int& t = typeVec[i];
-
- if (t == CROSS)
- t = NOT_ACTIVE;
-
- else if (isTail(t) || t == CROSS_EMPTY)
- t = EMPTY;
-
- if (!boundary && IS_NODE(t))
- t = ACTIVE; // boundary will be reset by changeActiveLane()
- }
- while (typeVec.back() == EMPTY) {
- typeVec.pop_back();
- nextShaVec.pop_back();
- }
-}
-
-bool Lanes::isBranch() {
-
- return (typeVec[activeLane] == BRANCH);
-}
-
-void Lanes::afterBranch() {
-
- typeVec[activeLane] = ACTIVE; // TODO test with boundaries
-}
-
-void Lanes::afterApplied() {
-
- typeVec[activeLane] = ACTIVE; // TODO test with boundaries
-}
-
-void Lanes::nextParent(const QString& sha) {
-
- nextShaVec[activeLane] = (boundary ? QString(_T("")) : sha);
-}
-
-int Lanes::findNextSha(const QString& next, int pos) {
-
- for (unsigned int i = pos; i < nextShaVec.size(); i++)
- if (nextShaVec[i] == next)
- return i;
- return -1;
-}
-
-int Lanes::findType(int type, int pos) {
-
- for (unsigned int i = pos; i < typeVec.size(); i++)
- if (typeVec[i] == type)
- return i;
- return -1;
-}
-
-int Lanes::add(int type, const QString& next, int pos) {
-
- // first check empty lanes starting from pos
- if (pos < (int)typeVec.size()) {
- pos = findType(EMPTY, pos);
- if (pos != -1) {
- typeVec[pos] = type;
- nextShaVec[pos] = next;
- return pos;
- }
- }
- // if all lanes are occupied add a new lane
- typeVec.push_back(type);
- nextShaVec.push_back(next);
- return typeVec.size() - 1;
-}
+/*\r
+ Description: history graph computation\r
+\r
+ Author: Marco Costalba (C) 2005-2007\r
+\r
+ Copyright: See COPYING file that comes with this distribution\r
+\r
+*/\r
+#include "stdafx.h"\r
+#include "lanes.h"\r
+\r
+#define IS_NODE(x) (x == NODE || x == NODE_R || x == NODE_L)\r
+\r
+\r
+void Lanes::init(const QString& expectedSha) {\r
+\r
+ clear();\r
+ activeLane = 0;\r
+ setBoundary(false);\r
+ add(BRANCH, expectedSha, activeLane);\r
+}\r
+\r
+void Lanes::clear() {\r
+\r
+ typeVec.clear();\r
+ nextShaVec.clear();\r
+}\r
+\r
+void Lanes::setBoundary(bool b) {\r
+// changes the state so must be called as first one\r
+\r
+ NODE = b ? BOUNDARY_C : MERGE_FORK;\r
+ NODE_R = b ? BOUNDARY_R : MERGE_FORK_R;\r
+ NODE_L = b ? BOUNDARY_L : MERGE_FORK_L;\r
+ boundary = b;\r
+\r
+ if (boundary)\r
+ typeVec[activeLane] = BOUNDARY;\r
+}\r
+\r
+bool Lanes::isFork(const QString& sha, bool& isDiscontinuity) {\r
+\r
+ int pos = findNextSha(sha, 0);\r
+ isDiscontinuity = (activeLane != pos);\r
+ if (pos == -1) // new branch case\r
+ return false;\r
+\r
+ return (findNextSha(sha, pos + 1) != -1);\r
+/*\r
+ int cnt = 0;\r
+ while (pos != -1) {\r
+ cnt++;\r
+ pos = findNextSha(sha, pos + 1);\r
+// if (isDiscontinuity)\r
+// isDiscontinuity = (activeLane != pos);\r
+ }\r
+ return (cnt > 1);\r
+*/\r
+}\r
+\r
+void Lanes::setFork(const QString& sha) {\r
+\r
+ int rangeStart, rangeEnd, idx;\r
+ rangeStart = rangeEnd = idx = findNextSha(sha, 0);\r
+\r
+ while (idx != -1) {\r
+ rangeEnd = idx;\r
+ typeVec[idx] = TAIL;\r
+ idx = findNextSha(sha, idx + 1);\r
+ }\r
+ typeVec[activeLane] = NODE;\r
+\r
+ int& startT = typeVec[rangeStart];\r
+ int& endT = typeVec[rangeEnd];\r
+\r
+ if (startT == NODE)\r
+ startT = NODE_L;\r
+\r
+ if (endT == NODE)\r
+ endT = NODE_R;\r
+\r
+ if (startT == TAIL)\r
+ startT = TAIL_L;\r
+\r
+ if (endT == TAIL)\r
+ endT = TAIL_R;\r
+\r
+ for (int i = rangeStart + 1; i < rangeEnd; i++) {\r
+\r
+ int& t = typeVec[i];\r
+\r
+ if (t == NOT_ACTIVE)\r
+ t = CROSS;\r
+\r
+ else if (t == EMPTY)\r
+ t = CROSS_EMPTY;\r
+ }\r
+}\r
+\r
+void Lanes::setMerge(const QStringList& parents) {\r
+// setFork() must be called before setMerge()\r
+\r
+ if (boundary)\r
+ return; // handle as a simple active line\r
+\r
+ int& t = typeVec[activeLane];\r
+ bool wasFork = (t == NODE);\r
+ bool wasFork_L = (t == NODE_L);\r
+ bool wasFork_R = (t == NODE_R);\r
+ bool startJoinWasACross = false, endJoinWasACross = false;\r
+\r
+ t = NODE;\r
+\r
+ int rangeStart = activeLane, rangeEnd = activeLane;\r
+ QStringList::const_iterator it(parents.begin());\r
+ for (++it; it != parents.end(); ++it) { // skip first parent\r
+\r
+ int idx = findNextSha(*it, 0);\r
+ if (idx != -1) {\r
+\r
+ if (idx > rangeEnd) {\r
+\r
+ rangeEnd = idx;\r
+ endJoinWasACross = typeVec[idx] == CROSS;\r
+ }\r
+\r
+ if (idx < rangeStart) {\r
+\r
+ rangeStart = idx;\r
+ startJoinWasACross = typeVec[idx] == CROSS;\r
+ }\r
+\r
+ typeVec[idx] = JOIN;\r
+ } else\r
+ rangeEnd = add(HEAD, *it, rangeEnd + 1);\r
+ }\r
+ int& startT = typeVec[rangeStart];\r
+ int& endT = typeVec[rangeEnd];\r
+\r
+ if (startT == NODE && !wasFork && !wasFork_R)\r
+ startT = NODE_L;\r
+\r
+ if (endT == NODE && !wasFork && !wasFork_L)\r
+ endT = NODE_R;\r
+\r
+ if (startT == JOIN && !startJoinWasACross)\r
+ startT = JOIN_L;\r
+\r
+ if (endT == JOIN && !endJoinWasACross)\r
+ endT = JOIN_R;\r
+\r
+ if (startT == HEAD)\r
+ startT = HEAD_L;\r
+\r
+ if (endT == HEAD)\r
+ endT = HEAD_R;\r
+\r
+ for (int i = rangeStart + 1; i < rangeEnd; i++) {\r
+\r
+ int& t = typeVec[i];\r
+\r
+ if (t == NOT_ACTIVE)\r
+ t = CROSS;\r
+\r
+ else if (t == EMPTY)\r
+ t = CROSS_EMPTY;\r
+\r
+ else if (t == TAIL_R || t == TAIL_L)\r
+ t = TAIL;\r
+ }\r
+}\r
+\r
+void Lanes::setInitial() {\r
+\r
+ int& t = typeVec[activeLane];\r
+ if (!IS_NODE(t) && t != APPLIED)\r
+ t = (boundary ? BOUNDARY : INITIAL);\r
+}\r
+\r
+void Lanes::setApplied() {\r
+\r
+ // applied patches are not merges, nor forks\r
+ typeVec[activeLane] = APPLIED; // TODO test with boundaries\r
+}\r
+\r
+void Lanes::changeActiveLane(const QString& sha) {\r
+\r
+ int& t = typeVec[activeLane];\r
+ if (t == INITIAL || isBoundary(t))\r
+ t = EMPTY;\r
+ else\r
+ t = NOT_ACTIVE;\r
+\r
+ int idx = findNextSha(sha, 0); // find first sha\r
+ if (idx != -1)\r
+ typeVec[idx] = ACTIVE; // called before setBoundary()\r
+ else\r
+ idx = add(BRANCH, sha, activeLane); // new branch\r
+\r
+ activeLane = idx;\r
+}\r
+\r
+void Lanes::afterMerge() {\r
+\r
+ if (boundary)\r
+ return; // will be reset by changeActiveLane()\r
+\r
+ for (unsigned int i = 0; i < typeVec.size(); i++) {\r
+\r
+ int& t = typeVec[i];\r
+\r
+ if (isHead(t) || isJoin(t) || t == CROSS)\r
+ t = NOT_ACTIVE;\r
+\r
+ else if (t == CROSS_EMPTY)\r
+ t = EMPTY;\r
+\r
+ else if (IS_NODE(t))\r
+ t = ACTIVE;\r
+ }\r
+}\r
+\r
+void Lanes::afterFork() {\r
+\r
+ for (unsigned int i = 0; i < typeVec.size(); i++) {\r
+\r
+ int& t = typeVec[i];\r
+\r
+ if (t == CROSS)\r
+ t = NOT_ACTIVE;\r
+\r
+ else if (isTail(t) || t == CROSS_EMPTY)\r
+ t = EMPTY;\r
+\r
+ if (!boundary && IS_NODE(t))\r
+ t = ACTIVE; // boundary will be reset by changeActiveLane()\r
+ }\r
+ while (typeVec.back() == EMPTY) {\r
+ typeVec.pop_back();\r
+ nextShaVec.pop_back();\r
+ }\r
+}\r
+\r
+bool Lanes::isBranch() {\r
+\r
+ return (typeVec[activeLane] == BRANCH);\r
+}\r
+\r
+void Lanes::afterBranch() {\r
+\r
+ typeVec[activeLane] = ACTIVE; // TODO test with boundaries\r
+}\r
+\r
+void Lanes::afterApplied() {\r
+\r
+ typeVec[activeLane] = ACTIVE; // TODO test with boundaries\r
+}\r
+\r
+void Lanes::nextParent(const QString& sha) {\r
+\r
+ nextShaVec[activeLane] = (boundary ? QString(_T("")) : sha);\r
+}\r
+\r
+int Lanes::findNextSha(const QString& next, int pos) {\r
+\r
+ for (unsigned int i = pos; i < nextShaVec.size(); i++)\r
+ if (nextShaVec[i] == next)\r
+ return i;\r
+ return -1;\r
+}\r
+\r
+int Lanes::findType(int type, int pos) {\r
+\r
+ for (unsigned int i = pos; i < typeVec.size(); i++)\r
+ if (typeVec[i] == type)\r
+ return i;\r
+ return -1;\r
+}\r
+\r
+int Lanes::add(int type, const QString& next, int pos) {\r
+\r
+ // first check empty lanes starting from pos\r
+ if (pos < (int)typeVec.size()) {\r
+ pos = findType(EMPTY, pos);\r
+ if (pos != -1) {\r
+ typeVec[pos] = type;\r
+ nextShaVec[pos] = next;\r
+ return pos;\r
+ }\r
+ }\r
+ // if all lanes are occupied add a new lane\r
+ typeVec.push_back(type);\r
+ nextShaVec.push_back(next);\r
+ return typeVec.size() - 1;\r
+}\r