/** * Finds a matching item that is before the given coordinates in the matrix * (before : left and above). * * @param x The x position in the matrix (position in the old list) * @param y The y position in the matrix (position in the new list) * @param snakeIndex The current snake index * @param removal True if we are looking for a removal, false otherwise * * @return True if such item is found. */ private bool FindMatchingItem(int x, int y, int snakeIndex, bool removal) { int myItemPos; int curX; int curY; if (removal) { myItemPos = y - 1; curX = x; curY = y - 1; } else { myItemPos = x - 1; curX = x - 1; curY = y; } for (int i = snakeIndex; i >= 0; i--) { Snake snake = mSnakes[i]; int endX = snake.x + snake.size; int endY = snake.y + snake.size; if (removal) { // check removals for a match for (int pos = curX - 1; pos >= endX; pos--) { if (mCallback.AreItemsTheSame(pos, myItemPos)) { // found! bool theSame = mCallback.AreContentsTheSame(pos, myItemPos); int changeFlag = theSame ? FLAG_MOVED_NOT_CHANGED : FLAG_MOVED_CHANGED; mNewItemStatuses[myItemPos] = (pos << FLAG_OFFSET) | FLAG_IGNORE; mOldItemStatuses[pos] = (myItemPos << FLAG_OFFSET) | changeFlag; return(true); } } } else { // check for additions for a match for (int pos = curY - 1; pos >= endY; pos--) { if (mCallback.AreItemsTheSame(myItemPos, pos)) { // found bool theSame = mCallback.AreContentsTheSame(myItemPos, pos); int changeFlag = theSame ? FLAG_MOVED_NOT_CHANGED : FLAG_MOVED_CHANGED; mOldItemStatuses[x - 1] = (pos << FLAG_OFFSET) | FLAG_IGNORE; mNewItemStatuses[pos] = ((x - 1) << FLAG_OFFSET) | changeFlag; return(true); } } } curX = snake.x; curY = snake.y; } return(false); }
private static Snake DiffPartial(Callback cb, int startOld, int endOld, int startNew, int endNew, int[] forward, int[] backward, int kOffset) { int oldSize = endOld - startOld; int newSize = endNew - startNew; if (endOld - startOld < 1 || endNew - startNew < 1) { return(null); } int delta = oldSize - newSize; int dLimit = (oldSize + newSize + 1) / 2; Array.Fill(forward, 0, kOffset - dLimit - 1, kOffset + dLimit + 1 - (kOffset - dLimit - 1)); Array.Fill(backward, oldSize, kOffset - dLimit - 1 + delta, kOffset + dLimit + 1 + delta - (kOffset - dLimit - 1 + delta)); bool checkInFwd = delta % 2 != 0; for (int d = 0; d <= dLimit; d++) { for (int k = -d; k <= d; k += 2) { // find forward path // we can reach k from k - 1 or k + 1. Check which one is further in the graph int x; bool removal; if (k == -d || (k != d && forward[kOffset + k - 1] < forward[kOffset + k + 1])) { x = forward[kOffset + k + 1]; removal = false; } else { x = forward[kOffset + k - 1] + 1; removal = true; } // set y based on x int y = x - k; // move diagonal as long as items match while (x < oldSize && y < newSize && cb.AreItemsTheSame(startOld + x, startNew + y)) { x++; y++; } forward[kOffset + k] = x; if (checkInFwd && k >= delta - d + 1 && k <= delta + d - 1) { if (forward[kOffset + k] >= backward[kOffset + k]) { Snake outSnake = new Snake(); outSnake.x = backward[kOffset + k]; outSnake.y = outSnake.x - k; outSnake.size = forward[kOffset + k] - backward[kOffset + k]; outSnake.removal = removal; outSnake.reverse = false; return(outSnake); } } } for (int k = -d; k <= d; k += 2) { // find reverse path at k + delta, in reverse int backwardK = k + delta; int x; bool removal; if (backwardK == d + delta || (backwardK != -d + delta && backward[kOffset + backwardK - 1] < backward[kOffset + backwardK + 1])) { x = backward[kOffset + backwardK - 1]; removal = false; } else { x = backward[kOffset + backwardK + 1] - 1; removal = true; } // set y based on x int y = x - backwardK; // move diagonal as long as items match while (x > 0 && y > 0 && cb.AreItemsTheSame(startOld + x - 1, startNew + y - 1)) { x--; y--; } backward[kOffset + backwardK] = x; if (!checkInFwd && k + delta >= -d && k + delta <= d) { if (forward[kOffset + backwardK] >= backward[kOffset + backwardK]) { Snake outSnake = new Snake(); outSnake.x = backward[kOffset + backwardK]; outSnake.y = outSnake.x - backwardK; outSnake.size = forward[kOffset + backwardK] - backward[kOffset + backwardK]; outSnake.removal = removal; outSnake.reverse = true; return(outSnake); } } } } throw new Exception("DiffUtil hit an unexpected case while trying to calculate" + " the optimal path. Please make sure your data is not changing during the" + " diff calculation."); }