22#include < cassert>
33#include < cstdlib>
44#include < algorithm>
5+ #include < cmath>
56
67using namespace std ;
78
@@ -88,19 +89,25 @@ pair<Commit*, int> findNext(Commit *c, Commit *start, int delta) {
8889 return make_pair (start, 0 );
8990 }
9091
91- auto left = findNext (c, start->left_parent_ , delta / 2 );
92- auto right = findNext (c, start->right_parent_ , delta / 2 );
93- if (left.first == nullptr ) {
94- return findNext (c, right.first , left.second );
95- } else if (right.first == nullptr ) {
96- return findNext (c, left.first , right.second );
92+ if (start->right_parent_ == nullptr ) {
93+ return findNext (c, start->left_parent_ , delta - 1 );
9794 } else {
98- if (left.first ->depth_ > right.first ->depth_ ) {
99- return left;
95+ auto left = findNext (c, start->left_parent_ , delta / 2 );
96+ auto right = findNext (c, start->right_parent_ , delta / 2 );
97+ if (left.first == nullptr ) {
98+ // pick up the remainders
99+ return findNext (c, right.first , left.second );
100+ } else if (right.first == nullptr ) {
101+ return findNext (c, left.first , right.second );
100102 } else {
101- return right;
103+ if (left.first ->depth_ > right.first ->depth_ ) {
104+ return left;
105+ } else {
106+ return right;
107+ }
102108 }
103109 }
110+
104111}
105112
106113// Bisect returns a commit c such that the following holds:
@@ -111,12 +118,24 @@ pair<Commit*, int> findNext(Commit *c, Commit *start, int delta) {
111118// About half are ancestors of c and half aren't.
112119Commit *Bisect (set< Commit *> allCommits, set<Commit *> goodCommits, Commit *badCommit) {
113120 Commit *c = firstKnownGood (goodCommits, badCommit);
114- int delta = (badCommit->depth_ - c->depth_ ) / 2 ;
121+ assert (c->depth_ != badCommit->depth_ );
122+ int delta = (badCommit->depth_ - c->depth_ );
123+ if (delta == 1 ) {
124+ if (badCommit->left_parent_ == c) {
125+ if (badCommit->right_parent_ != nullptr ) {
126+ return badCommit->right_parent_ ;
127+ } else {
128+ return badCommit;
129+ }
130+ } else {
131+ return badCommit->left_parent_ ;
132+ }
133+ }
115134 if (delta == 0 ) {
116135 return badCommit;
117136 }
118137
119- auto mid = findNext (c, badCommit, delta);
138+ auto mid = findNext (c, badCommit, delta / 2 );
120139 assert (mid.first != nullptr );
121140 return mid.first ;
122141}
@@ -155,12 +174,15 @@ typedef Commit *(*Bisector)( set< Commit *> allCommits, set<Commit *> goodCommi
155174// finds the first bad commit
156175Commit *findBad (set< Commit *> &allCommits, set<Commit *> &goodCommits, Commit *badCommit,
157176 Bisector bisector) {
158- while (true ) {
177+ int depth = badCommit->depth_ ;
178+
179+ for (int i = 0 ; ; i++) {
159180 Commit *mid = bisector (allCommits, goodCommits, badCommit);
160181 if (mid->good_ ) {
161182 goodCommits.insert (mid);
162183 } else {
163184 if (mid == badCommit) {
185+ assert (i <= ((log (depth) / log (2 )) + 1 ));
164186 return mid;
165187 } else {
166188 badCommit = mid;
@@ -213,5 +235,43 @@ main(int argc, char *argv[]) {
213235 left = left->newCommit ();
214236 }
215237 final = left->merge (right);
216- assert (findBad (root, final , Bisect) == right);
238+ auto res = findBad (root, final , Bisect);
239+ assert (res == right);
240+
241+ root = new Commit (nullptr , nullptr );
242+ left = root->newCommit ()->bad ();
243+ right = root;
244+ for (int i = 0 ; i < 10 ; i++) {
245+ right = right->newCommit ();
246+ }
247+ final = left->merge (right);
248+ res = findBad (root, final , Bisect);
249+ assert (res == left);
250+
251+ root = new Commit (nullptr , nullptr );
252+ left = root->newCommit ()->bad ();
253+ right = root;
254+ for (int i = 0 ; i < 1000 ; i++) {
255+ right = right->newCommit ();
256+ }
257+ final = left->merge (right);
258+ res = findBad (root, final , Bisect);
259+ assert (res == left);
260+
261+ root = new Commit (nullptr , nullptr );
262+ left = root;
263+ for (int i = 0 ; i < 10 ; i++) {
264+ left = left->newCommit ();
265+ }
266+ assert (left->depth_ == 10 );
267+ right = left->newCommit ()->newCommit ()->bad ();
268+ assert (right->depth_ == 12 );
269+ right = right->newCommit ()->merge (right->newCommit ());
270+ assert (right->depth_ == 14 );
271+ left = left->newCommit ()->newCommit ()->newCommit ();
272+ assert (left->depth_ == 13 );
273+ final = left->merge (right);
274+ assert (final ->depth_ == 15 );
275+ res = findBad (root, final , Bisect);
276+ assert (res->depth_ == 12 );
217277}
0 commit comments