(a, b, get, before)
| 23835 | * @returns {Node[]} The same list of future children. |
| 23836 | */ |
| 23837 | const udomdiff = (a, b, get, before) => { |
| 23838 | const bLength = b.length; |
| 23839 | let aEnd = a.length; |
| 23840 | let bEnd = bLength; |
| 23841 | let aStart = 0; |
| 23842 | let bStart = 0; |
| 23843 | let map = null; |
| 23844 | while (aStart < aEnd || bStart < bEnd) { |
| 23845 | // append head, tail, or nodes in between: fast path |
| 23846 | if (aEnd === aStart) { |
| 23847 | // we could be in a situation where the rest of nodes that |
| 23848 | // need to be added are not at the end, and in such case |
| 23849 | // the node to `insertBefore`, if the index is more than 0 |
| 23850 | // must be retrieved, otherwise it's gonna be the first item. |
| 23851 | const node = |
| 23852 | bEnd < bLength |
| 23853 | ? bStart |
| 23854 | ? get(b[bStart - 1], -0).nextSibling |
| 23855 | : get(b[bEnd - bStart], 0) |
| 23856 | : before; |
| 23857 | while (bStart < bEnd) insertBefore(get(b[bStart++], 1), node); |
| 23858 | } |
| 23859 | // remove head or tail: fast path |
| 23860 | else if (bEnd === bStart) { |
| 23861 | while (aStart < aEnd) { |
| 23862 | // remove the node only if it's unknown or not live |
| 23863 | if (!map || !map.has(a[aStart])) removeChild(get(a[aStart], -1)); |
| 23864 | aStart++; |
| 23865 | } |
| 23866 | } |
| 23867 | // same node: fast path |
| 23868 | else if (a[aStart] === b[bStart]) { |
| 23869 | aStart++; |
| 23870 | bStart++; |
| 23871 | } |
| 23872 | // same tail: fast path |
| 23873 | else if (a[aEnd - 1] === b[bEnd - 1]) { |
| 23874 | aEnd--; |
| 23875 | bEnd--; |
| 23876 | } |
| 23877 | // The once here single last swap "fast path" has been removed in v1.1.0 |
| 23878 | // https://github.com/WebReflection/udomdiff/blob/single-final-swap/esm/index.js#L69-L85 |
| 23879 | // reverse swap: also fast path |
| 23880 | else if (a[aStart] === b[bEnd - 1] && b[bStart] === a[aEnd - 1]) { |
| 23881 | // this is a "shrink" operation that could happen in these cases: |
| 23882 | // [1, 2, 3, 4, 5] |
| 23883 | // [1, 4, 3, 2, 5] |
| 23884 | // or asymmetric too |
| 23885 | // [1, 2, 3, 4, 5] |
| 23886 | // [1, 2, 3, 5, 6, 4] |
| 23887 | const node = get(a[--aEnd], -1).nextSibling; |
| 23888 | moveBefore(get(b[bStart++], 1), get(a[aStart++], -1).nextSibling); |
| 23889 | moveBefore(get(b[--bEnd], 1), node); |
| 23890 | // mark the future index as identical (yeah, it's dirty, but cheap 👍) |
| 23891 | // The main reason to do this, is that when a[aEnd] will be reached, |
| 23892 | // the loop will likely be on the fast path, as identical to b[bEnd]. |
| 23893 | // In the best case scenario, the next loop will skip the tail, |
| 23894 | // but in the worst one, this node will be considered as already |
no test coverage detected
searching dependent graphs…