
e.ultra.mutator.0.77.0.source-code.ListMutator.kt Maven / Gradle / Ivy
package de.peekandpoke.ultra.mutator
import de.peekandpoke.ultra.common.containsAny
import de.peekandpoke.ultra.common.pop
import de.peekandpoke.ultra.common.push
import de.peekandpoke.ultra.common.shift
import de.peekandpoke.ultra.common.unshift
/**
* Creates a [ListMutator] for this List
*/
fun List.mutator(
/** onModify callback */
onModify: OnModify>,
/** The backwardMapper maps any mutator [M] back to its value [T] */
backwardMapper: (M) -> T,
/** The forwardMapper maps any [T] to is mutator [M] */
forwardMapper: (T, OnModify) -> M
): ListMutator {
return ListMutator(this, onModify, forwardMapper, backwardMapper)
}
/**
* Mutator implementation for lists
*/
@Suppress("Detekt.TooManyFunctions")
class ListMutator(
/** the input value, the original list */
original: List,
/** onModify callback */
onModify: OnModify>,
/** The forwardMapper maps any [T] to is mutator [M] */
private val forwardMapper: (T, OnModify) -> M,
/** The backwardMapper maps any mutator [M] back to its value [T] */
private val backwardMapper: (M) -> T
) : MutatorBase, MutableList>(original, onModify), MutableList {
/**
* Replaces the whole list
*/
operator fun plusAssign(value: List) = plusAssign(value.map(backwardMapper))
/**
* Creates a mutable copy of the given [input]
*/
override fun copy(input: List) = input.toMutableList()
/**
* Returns an iterator over all elements mapped to [M]
*/
override fun iterator(): MutableIterator = It(getResult(), forwardMapper)
override fun listIterator(): MutableListIterator {
TODO("not implemented")
}
override fun listIterator(index: Int): MutableListIterator {
TODO("not implemented")
}
override fun subList(fromIndex: Int, toIndex: Int): MutableList {
TODO("not implemented")
}
// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MutableList implementation
// //
/**
* Returns the size of the list
*/
override val size get() = getResult().size
/**
* Returns true when the list is empty
*/
override fun isEmpty() = getResult().isEmpty()
/**
* Returns true if the list contains the given [element]
*/
override fun contains(element: M) = contains(backwardMapper(element))
/**
* Returns true if the list contains all of the given [elements]
*/
override fun containsAll(elements: Collection) = containsAll(elements.map(backwardMapper))
/**
* Returns the index of the first occurrence of the specified element in the list, or -1 if the specified
* element is not contained in the list.
*/
override fun indexOf(element: M) = indexOf(backwardMapper(element))
/**
* Returns the index of the last occurrence of the specified element in the list, or -1 if the specified
* element is not contained in the list.
*/
override fun lastIndexOf(element: M) = lastIndexOf(backwardMapper(element))
/**
* Clears the whole list
*/
override fun clear() {
if (size > 0) {
getMutableResult().clear()
}
}
/**
* Get the element at the given index
*/
override operator fun get(index: Int) =
forwardMapper(getResult()[index]) { setAt(index, it) }
/**
* Replaces the element at the specified position in this list with the specified element.
*
* NOTICE: modifying the return element will have no effect
*
* @return The element previously at the specified position
*/
override operator fun set(index: Int, element: M) =
forwardMapper(setAt(index, backwardMapper(element))) {}
/**
* Adds the specified element to the end of this list.
*
* @return `true` because the list is always modified as the result of this operation.
*/
override fun add(element: M) = add(backwardMapper(element))
/**
* Inserts an element into the list at the specified [index].
*/
override fun add(index: Int, element: M) = add(index, backwardMapper(element))
/**
* Adds all of the elements of the specified collection to the end of this list.
*
* The elements are appended in the order they appear in the [elements] collection.
*
* @return `true` if the list was changed as the result of the operation.
*/
override fun addAll(elements: Collection) = addAll(elements.map(backwardMapper))
/**
* Helper function to work around clashes of [T] and [M]
*/
fun addAllM(elements: Collection) = addAll(elements)
/**
* Inserts all of the elements of the specified collection [elements] into this list at the specified [index].
*
* @return `true` if the list was changed as the result of the operation.
*/
override fun addAll(index: Int, elements: Collection) = addAll(index, elements.map(backwardMapper))
/**
* Helper function to work around clashes of [T] and [M]
*/
fun addAllM(index: Int, elements: Collection) = addAll(index, elements)
/**
* Removes the given element
*
* @return true when the element has been removed from the list
*/
override fun remove(element: M) = remove(backwardMapper(element))
/**
* Removes an element at the specified [index] from the list.
*
* NOTICE: modifying the returned element will have no effect
*
* @return the element that has been removed.
*/
override fun removeAt(index: Int) = forwardMapper(getMutableResult().removeAt(index)) {}
/**
* Removes all of the given [elements]
*/
override fun removeAll(elements: Collection) = removeAll(elements.map(backwardMapper))
/**
* Retains all of the given [elements]
*/
override fun retainAll(elements: Collection) = retainAll(elements.map(backwardMapper))
// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// additional functionality
// //
/**
* Returns true if the list contains the given [element]
*/
@JvmName("contains_T")
fun contains(element: T) = getResult().contains(element)
/**
* Returns true if the list contains all of the given [elements]
*/
@JvmName("containsAll_T")
fun containsAll(elements: Collection) = getResult().containsAll(elements)
/**
* Returns the index of the first occurrence of the specified element in the list, or -1 if the specified
* element is not contained in the list.
*/
@JvmName("indexOf_T")
fun indexOf(element: T) = getResult().indexOf(element)
/**
* Returns the index of the last occurrence of the specified element in the list, or -1 if the specified
* element is not contained in the list.
*/
@JvmName("lastIndexOf_T")
fun lastIndexOf(element: T) = getResult().lastIndexOf(element)
/**
* Adds the specified element to the end of this list.
*
* @return `true` because the list is always modified as the result of this operation.
*/
@JvmName("add_T")
fun add(element: T) = getMutableResult().add(element)
/**
* Inserts an element into the list at the specified [index].
*/
@JvmName("add_T")
fun add(index: Int, element: T) = getMutableResult().add(index, element)
/**
* Adds all of the elements of the specified collection to the end of this list.
*
* The elements are appended in the order they appear in the [elements] collection.
*
* @return `true` if the list was changed as the result of the operation.
*/
@JvmName("addAll_T")
fun addAll(elements: Collection) = when {
elements.isEmpty() -> false
else -> getMutableResult().addAll(elements)
}
/**
* Inserts all of the elements of the specified collection [elements] into this list at the specified [index].
*
* @return `true` if the list was changed as the result of the operation.
*/
@JvmName("addAll_T")
fun addAll(index: Int, elements: Collection) = when {
elements.isEmpty() -> false
else -> getMutableResult().addAll(index, elements)
}
/**
* Add an element at the end of the list
*/
fun push(vararg element: T) = apply { getMutableResult().push(element) }
/**
* Removes the last element from the list and returns it
*/
fun pop() = if (size > 0) getMutableResult().pop() else null
/**
* Add an element at the beginning of the list
*/
fun unshift(vararg element: T) = apply { getMutableResult().unshift(element) }
/**
* Removes the first element from the list and returns it
*/
fun shift() = if (size > 0) getMutableResult().shift() else null
/**
* Removes a specific [element] from the list
*
* @return 'true' when the list has been modified
*/
fun remove(vararg element: T) = removeAll(element.toList())
/**
* Removes the specified [elements] from the list
*
* @return 'true' when the list has been modified
*/
@JvmName("removeAll_T")
fun removeAll(elements: Collection): Boolean = when {
getResult().containsAny(elements) -> getMutableResult().removeAll(elements)
else -> false
}
/**
* Removes all elements from the the list that match the filter
*/
fun removeWhere(predicate: T.() -> Boolean) = retainWhere { !predicate(this) }
/**
* Retains the given [element]s in the list
*
* @return 'true' when the list has been modified
*/
fun retain(vararg element: T) = retainAll(element.toList())
/**
* Retains the given [elements]s in the list
*
* @return 'true' when the list has been modified
*/
@JvmName("retainAll_T")
fun retainAll(elements: Collection): Boolean = when {
getResult().size != elements.size ||
!getResult().containsAll(elements) -> getMutableResult().retainAll(elements)
else -> false
}
/**
* Retains all elements in the list that match the predicate
*/
fun retainWhere(predicate: T.() -> Boolean) = apply {
val filtered = getResult().filter(predicate)
if (filtered.size < size) {
plusAssign(filtered)
}
}
/**
* Set the element at the given index
*/
fun setAt(index: Int, element: T): T {
val current = getResult()[index]
// We only trigger the cloning, when the value has changed
if (current.isNotSameAs(element)) {
getMutableResult()[index] = element
}
return current
}
/**
* Iterator impl
*/
internal inner class It(
private val list: List,
private val mapper: (T, OnModify) -> M
) : MutableIterator {
private var pos = 0
private var current: T? = null
override fun hasNext() = pos < list.size
override fun next(): M {
val idx = pos++
return list[idx].run {
// remember the current element, so we can use it for remove()
current = this
// return the current element mapped to a mutator with onModify callback
mapper(this) { setAt(idx, it) }
}
}
override fun remove() {
current?.apply { remove(this) }
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy