예제 #1
0
bool
MoveResolver::resolve()
{
    resetState();
    orderedMoves_.clear();

    InlineList<PendingMove> stack;

    // This is a depth-first-search without recursion, which tries to find
    // cycles in a list of moves.
    //
    // Algorithm.
    //
    // S = Traversal stack.
    // P = Pending move list.
    // O = Ordered list of moves.
    //
    // As long as there are pending moves in P:
    //      Let |root| be any pending move removed from P
    //      Add |root| to the traversal stack.
    //      As long as S is not empty:
    //          Let |L| be the most recent move added to S.
    //
    //          Find any pending move M whose source is L's destination, thus
    //          preventing L's move until M has completed.
    //
    //          If a move M was found,
    //              Remove M from the pending list.
    //              If M's destination is |root|,
    //                  Annotate M and |root| as cycles.
    //                  Add M to S.
    //                  do not Add M to O, since M may have other conflictors in P that have not yet been processed.
    //              Otherwise,
    //                  Add M to S.
    //         Otherwise,
    //              Remove L from S.
    //              Add L to O.
    //
    while (!pending_.empty()) {
        PendingMove* pm = pending_.popBack();

        // Add this pending move to the cycle detection stack.
        stack.pushBack(pm);

        while (!stack.empty()) {
            PendingMove* blocking = findBlockingMove(stack.peekBack());

            if (blocking) {
                PendingMoveIterator stackiter = stack.begin();
                PendingMove* cycled = findCycledMove(&stackiter, stack.end(), blocking);
                if (cycled) {
                    // Find the cycle's start.
                    // We annotate cycles at each move in the cycle, and
                    // assert that we do not find two cycles in one move chain
                    // traversal (which would indicate two moves to the same
                    // destination).
                    // Since there can be more than one cycle, find them all.
                    do {
                        cycled->setCycleEnd(curCycles_);
                        cycled = findCycledMove(&stackiter, stack.end(), blocking);
                    } while (cycled);

                    blocking->setCycleBegin(pm->type(), curCycles_);
                    curCycles_++;
                    pending_.remove(blocking);
                    stack.pushBack(blocking);
                } else {
                    // This is a new link in the move chain, so keep
                    // searching for a cycle.
                    pending_.remove(blocking);
                    stack.pushBack(blocking);
                }
            } else {
                // Otherwise, pop the last move on the search stack because it's
                // complete and not participating in a cycle. The resulting
                // move can safely be added to the ordered move list.
                PendingMove* done = stack.popBack();
                if (!addOrderedMove(*done))
                    return false;
                movePool_.free(done);
            }
        }
        // If the current queue is empty, it is certain that there are
        // all previous cycles cannot conflict with future cycles,
        // so re-set the counter of pending cycles, while keeping a high-water mark.
        if (numCycles_ < curCycles_)
            numCycles_ = curCycles_;
        curCycles_ = 0;
    }

    return true;
}
예제 #2
0
  bool testBasic()
  {
    IntThing thing1(1);
    IntThing thing2(2);
    IntThing thing3(3);
    IntThing thing4(4);
    IntThing thing5(5);

    // Do these test twice. InlineList does not take ownership of pointers,
    // so we should be guaranteed we can keep moving them in between lists.
    for (size_t i = 0; i <= 1; i++)
    {
      InlineList<IntThing> list;

      InlineList<IntThing>::iterator iter = list.begin();
      if (!check(iter == list.end(), "list should be empty"))
        return false;
      
      list.append(&thing1);
      list.append(&thing2);
      list.append(&thing3);
      list.append(&thing4);
      list.append(&thing5);

      iter = list.begin();
      for (int n = 1; n <= 5; n++) {
        if (!check(iter->value() == n, "value %d should be %d", iter->value(), n))
          return false;
        iter++;
      }
      if (!check(iter == list.end(), "iterator should have ended"))
        return false;

      list.remove(&thing1);
      iter = list.begin();
      if (!check(iter->value() == 2, "list should start at 2 after removal"))
        return false;

      list.remove(&thing5);
      iter = list.begin();
      iter++;
      iter++;
      if (!check(iter->value() == 4, "list should end at 4 after removal"))
        return false;
      iter++;
      if (!check(iter == list.end(), "iterator should have ended"))
        return false;

      list.remove(&thing3);
      iter = list.begin();
      if (!check(iter->value() == 2, "first value should be 2 after removal"))
        return false;
      iter++;
      if (!check(iter->value() == 4, "second value should be 4 after removal"))
        return false;
      iter++;
      if (!check(iter == list.end(), "iterator should have ended"))
        return false;

      iter = list.begin();
      while (iter != list.end())
        iter = list.erase(iter);

      if (!check(list.begin() == list.end(), "list should be empty"))
        return false;
    }

    return true;
  }