Slightly optimized bindChildrenTo for the frequent case where all list cell elements have been replaced.

This commit is contained in:
Daan Vanden Bosch 2021-12-03 22:08:04 +01:00
parent e492b28aac
commit 4792dc1172
7 changed files with 86 additions and 23 deletions

View File

@ -65,9 +65,12 @@ abstract class AbstractDependentListCell<E> :
observer(
ListChangeEvent(
value,
listOf(
ListChange.Structural(index = 0, removed = emptyList(), inserted = value),
),
listOf(ListChange.Structural(
index = 0,
prevSize = 0,
removed = emptyList(),
inserted = value,
)),
)
)
}
@ -81,7 +84,15 @@ abstract class AbstractDependentListCell<E> :
computeElements()
emitDependencyChanged(
ListChangeEvent(elements, listOf(ListChange.Structural(0, oldElements, elements)))
ListChangeEvent(
elements,
listOf(ListChange.Structural(
index = 0,
prevSize = oldElements.size,
removed = oldElements,
inserted = elements,
)),
)
)
}

View File

@ -49,9 +49,12 @@ abstract class AbstractListCell<E> : AbstractCell<List<E>>(), ListCell<E> {
observer(
ListChangeEvent(
value,
listOf(
ListChange.Structural(index = 0, removed = emptyList(), inserted = value),
),
listOf(ListChange.Structural(
index = 0,
prevSize = 0,
removed = emptyList(),
inserted = value
)),
)
)
}

View File

@ -48,6 +48,7 @@ class FilteredListCell<E>(
override fun dependencyChanged(dependency: Dependency, event: ChangeEvent<*>?) {
if (event is ListChangeEvent<*>) {
val prevSize = elements.size
val filteredChanges = mutableListOf<ListChange<E>>()
for (change in event.changes) {
@ -95,6 +96,7 @@ class FilteredListCell<E>(
filteredChanges.add(
ListChange.Structural(
eventIndex,
prevSize,
removed,
inserted
)
@ -140,6 +142,7 @@ class FilteredListCell<E>(
filteredChanges.add(
ListChange.Structural(
insertIndex,
prevSize,
removed = emptyList(),
inserted = listOf(change.updated),
)
@ -167,6 +170,7 @@ class FilteredListCell<E>(
filteredChanges.add(
ListChange.Structural(
index,
prevSize,
removed = listOf(change.updated),
inserted = emptyList(),
)

View File

@ -32,7 +32,15 @@ class ImmutableListCell<E>(private val elements: List<E>) : AbstractDependency()
override fun observeList(callNow: Boolean, observer: ListObserver<E>): Disposable {
if (callNow) {
observer(ListChangeEvent(value, listOf(ListChange.Structural(0, emptyList(), value))))
observer(ListChangeEvent(
value,
listOf(ListChange.Structural(
index = 0,
prevSize = 0,
removed = emptyList(),
inserted = value,
)),
))
}
return nopDisposable()

View File

@ -13,6 +13,7 @@ sealed class ListChange<out E> {
*/
class Structural<out E>(
val index: Int,
val prevSize: Int,
/**
* The elements that were removed from the list at [index].
*
@ -27,7 +28,9 @@ sealed class ListChange<out E> {
* be mutated when the originating [ListCell] is mutated.
*/
val inserted: List<E>,
) : ListChange<E>()
) : ListChange<E>() {
val allRemoved: Boolean get() = removed.size == prevSize
}
/**
* Represents a change to an element in a list cell. Will only be emitted if the list is

View File

@ -50,7 +50,12 @@ class SimpleListCell<E>(
elementDependents[index] = ElementDependent(index, element)
}
changes.add(ListChange.Structural(index, listOf(removed), listOf(element)))
changes.add(ListChange.Structural(
index,
prevSize = elements.size,
removed = listOf(removed),
inserted = listOf(element),
))
ChangeManager.changed(this)
return removed
@ -63,17 +68,23 @@ class SimpleListCell<E>(
copyAndResetWrapper()
elements.add(element)
finalizeStructuralChange(index, emptyList(), listOf(element))
finalizeStructuralChange(
index,
prevSize = index,
removed = emptyList(),
inserted = listOf(element),
)
}
override fun add(index: Int, element: E) {
checkIndex(index, elements.size)
val prevSize = elements.size
checkIndex(index, prevSize)
emitMightChange()
copyAndResetWrapper()
elements.add(index, element)
finalizeStructuralChange(index, emptyList(), listOf(element))
finalizeStructuralChange(index, prevSize, removed = emptyList(), inserted = listOf(element))
}
override fun remove(element: E): Boolean {
@ -91,34 +102,41 @@ class SimpleListCell<E>(
checkIndex(index, elements.lastIndex)
emitMightChange()
val prevSize = elements.size
copyAndResetWrapper()
val removed = elements.removeAt(index)
finalizeStructuralChange(index, listOf(removed), emptyList())
finalizeStructuralChange(index, prevSize, removed = listOf(removed), inserted = emptyList())
return removed
}
override fun replaceAll(elements: Iterable<E>) {
emitMightChange()
val prevSize = this.elements.size
val removed = elementsWrapper
copyAndResetWrapper()
this.elements.replaceAll(elements)
finalizeStructuralChange(0, removed, elementsWrapper)
finalizeStructuralChange(index = 0, prevSize, removed, inserted = elementsWrapper)
}
override fun replaceAll(elements: Sequence<E>) {
emitMightChange()
val prevSize = this.elements.size
val removed = elementsWrapper
copyAndResetWrapper()
this.elements.replaceAll(elements)
finalizeStructuralChange(0, removed, elementsWrapper)
finalizeStructuralChange(index = 0, prevSize, removed, inserted = elementsWrapper)
}
override fun splice(fromIndex: Int, removeCount: Int, newElement: E) {
val prevSize = elements.size
val removed = ArrayList<E>(removeCount)
for (i in fromIndex until (fromIndex + removeCount)) {
@ -131,17 +149,19 @@ class SimpleListCell<E>(
repeat(removeCount) { elements.removeAt(fromIndex) }
elements.add(fromIndex, newElement)
finalizeStructuralChange(fromIndex, removed, listOf(newElement))
finalizeStructuralChange(fromIndex, prevSize, removed, inserted = listOf(newElement))
}
override fun clear() {
emitMightChange()
val prevSize = elements.size
val removed = elementsWrapper
copyAndResetWrapper()
elements.clear()
finalizeStructuralChange(0, removed, emptyList())
finalizeStructuralChange(index = 0, prevSize, removed, inserted = emptyList())
}
override fun sortWith(comparator: Comparator<E>) {
@ -157,7 +177,12 @@ class SimpleListCell<E>(
throwable = e
}
finalizeStructuralChange(0, removed, elementsWrapper)
finalizeStructuralChange(
index = 0,
prevSize = elements.size,
removed,
inserted = elementsWrapper,
)
if (throwable != null) {
throw throwable
@ -200,7 +225,12 @@ class SimpleListCell<E>(
}
}
private fun finalizeStructuralChange(index: Int, removed: List<E>, inserted: List<E>) {
private fun finalizeStructuralChange(
index: Int,
prevSize: Int,
removed: List<E>,
inserted: List<E>,
) {
if (dependents.isNotEmpty() && extractDependencies != null) {
repeat(removed.size) {
elementDependents.removeAt(index).dispose()
@ -218,7 +248,7 @@ class SimpleListCell<E>(
}
}
changes.add(ListChange.Structural(index, removed, inserted))
changes.add(ListChange.Structural(index, prevSize, removed, inserted))
ChangeManager.changed(this)
}

View File

@ -273,8 +273,12 @@ private fun <T> bindChildrenTo(
list.observeList(callNow = true) { event: ListChangeEvent<T> ->
for (change in event.changes) {
if (change is ListChange.Structural) {
repeat(change.removed.size) {
parent.removeChild(parent.childNodes[change.index].unsafeCast<Node>())
if (change.allRemoved) {
parent.innerHTML = ""
} else {
repeat(change.removed.size) {
parent.removeChild(parent.childNodes[change.index].unsafeCast<Node>())
}
}
childrenRemoved(change.index, change.removed.size)