Remove confusing for-loop in favor of a helper function

This logic is hopefully easier to follow. Added more inline comments
to explain how the algorithm works.
This commit is contained in:
Andrew Clark
2016-12-15 18:15:03 -08:00
parent dfe3d089cc
commit f070aaa1b8
@@ -162,6 +162,26 @@ function insertUpdateIntoQueue(queue, update, insertAfter, insertBefore) {
}
}
// Returns the update after which the incoming update should be inserted into
// the queue, or null if it should be inserted at beginning.
function findInsertionPosition(queue, update) : Update | null {
const priorityLevel = update.priorityLevel;
let insertAfter = null;
let insertBefore = null;
if (queue.last && comparePriority(queue.last.priorityLevel, priorityLevel) <= 0) {
// Fast path for the common case where the update should be inserted at
// the end of the queue.
insertAfter = queue.last;
} else {
insertBefore = queue.first;
while (insertBefore && comparePriority(insertBefore.priorityLevel, priorityLevel) <= 0) {
insertAfter = insertBefore;
insertBefore = insertBefore.next;
}
}
return insertAfter;
}
// The work-in-progress queue is a subset of the current queue (if it exists).
// We need to insert the incoming update into both lists. However, it's possible
// that the correct position in one list will be different from the position in
@@ -189,7 +209,6 @@ function insertUpdateIntoQueue(queue, update, insertAfter, insertBefore) {
//
// However, if incoming update is inserted into the same position of both lists,
// we shouldn't make a copy.
function insertUpdate(fiber : Fiber, update : Update, methodName : ?string) : void {
const queue1 = ensureUpdateQueue(fiber);
const queue2 = fiber.alternate ? ensureUpdateQueue(fiber.alternate) : null;
@@ -218,54 +237,40 @@ function insertUpdate(fiber : Fiber, update : Update, methodName : ?string) : vo
}
}
const priorityLevel = update.priorityLevel;
// Find the insertion position in the first queue.
const insertAfter1 = findInsertionPosition(queue1, update);
const insertBefore1 = insertAfter1 ? insertAfter1.next : queue1.first;
let queue = queue1;
let insertAfter1;
let insertBefore1;
let insertAfter2;
let insertBefore2;
for (let i = 0; queue && i < 2; i++) {
let insertAfter = null;
let insertBefore = null;
if (queue.last && comparePriority(queue.last.priorityLevel, priorityLevel) <= 0) {
// Fast path for the common case where the update should be inserted at
// the end of the queue.
insertAfter = queue.last;
} else {
insertBefore = queue.first;
while (insertBefore && comparePriority(insertBefore.priorityLevel, priorityLevel) <= 0) {
insertAfter = insertBefore;
insertBefore = insertBefore.next;
}
}
if (i === 0) {
insertAfter1 = insertAfter;
insertBefore1 = insertBefore;
queue = queue2;
} else {
insertAfter2 = insertAfter;
insertBefore2 = insertBefore;
queue = null;
}
if (!queue2) {
// If there's no alternate queue, there's nothing else to do but insert.
insertUpdateIntoQueue(queue1, update, insertAfter1, insertBefore1);
return;
}
const update1 = update;
insertUpdateIntoQueue(queue1, update1, insertAfter1, insertBefore1);
// If there is an alternate queue, find the insertion position.
const insertAfter2 = findInsertionPosition(queue2, update);
const insertBefore2 = insertAfter2 ? insertAfter2.next : queue2.first;
if (queue2) {
let update2;
if (insertBefore1 === insertBefore2) {
// The update is inserted into the same position of both lists. There's no
// need to clone the update.
update2 = update1;
} else {
// The update is inserted into two separate positions. Make a clone of the
// update and insert it twice. One or the other will be dropped the next
// time we commit.
update2 = cloneUpdate(update1);
}
// Now we can insert into the first queue. This must come after finding both
// insertion positions because it mutates the list.
insertUpdateIntoQueue(queue1, update, insertAfter1, insertBefore1);
if (insertBefore1 !== insertBefore2) {
// The insertion positions are different, so we need to clone the update and
// insert the clone into the alternate queue.
const update2 = cloneUpdate(update);
insertUpdateIntoQueue(queue2, update2, insertAfter2, insertBefore2);
} else {
// The insertion positions are the same, so when we inserted into the first
// queue, it also inserted into the alternate. All we need to do is update
// the alternate queue's `first` and `last` pointers, in case they
// have changed.
if (!insertAfter2) {
queue2.first = update;
}
if (!insertBefore2) {
queue2.last = null;
}
}
}