e.ultra.mutator.0.76.0.source-code.SetMutator.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mutator Show documentation
Show all versions of mutator Show documentation
"Make immutable objects mutable"
The newest version!
package de.peekandpoke.ultra.mutator
import de.peekandpoke.ultra.common.containsAny
/**
* Creates a [SetMutator] for this Set
*/
fun Set.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
): SetMutator {
return SetMutator(this, onModify, forwardMapper, backwardMapper)
}
/**
* Mutator implementation for sets
*/
@Suppress("Detekt.TooManyFunctions")
class SetMutator(
/** the input value, the original set */
original: Set,
/** 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, MutableSet>(original, onModify), MutableSet {
/**
* Replaces the whole list
*/
operator fun plusAssign(value: List) = plusAssign(value.map(backwardMapper).toSet())
/**
* Creates a mutable copy of the given [input]
*/
override fun copy(input: Set): MutableSet = MutableSetWrapper(input.toMutableSet())
/**
* Returns an iterator over all elements mapped to [M]
*/
override fun iterator(): MutableIterator = It(getResult(), forwardMapper)
// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MutableSet 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 set contains the given [element]
*/
override fun contains(element: M) = contains(backwardMapper(element))
/**
* Returns true if the set contains all of the given [elements]
*/
override fun containsAll(elements: Collection) = containsAll(elements.map(backwardMapper))
/**
* Clears the whole list
*/
override fun clear() {
if (size > 0) {
getMutableResult().clear()
}
}
/**
* Adds the specified element to the set.
*
* @return `true` if the element has been added, `false` if the element is already contained in the set.
*/
override fun add(element: M) = add(backwardMapper(element))
/**
* Adds all [elements] to the set
*
* @return 'true if any of the elements has been added, 'false' if all elements are already contained in the set.
*/
override fun addAll(elements: Collection) = addAll(elements.map(backwardMapper))
/**
* Removes an [element] from the set
*
* @return 'true' of the element was removed from the set
*/
override fun remove(element: M) = remove(backwardMapper(element))
/**
* Removes the specified [elements] from the list
*
* @return 'true' when the list has been modified
*/
override fun removeAll(elements: Collection) = removeAll(elements.map(backwardMapper))
/**
* Retains all of the given [elements]
*
* @return 'true' when the list has been modified
*/
override fun retainAll(elements: Collection) = retainAll(elements.map(backwardMapper))
// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// additional implementation
// //
/**
* Returns true if the set contains the given [element]
*/
@JvmName("contains_T")
fun contains(element: T) = getResult().contains(element)
/**
* Returns true if the set contains all of the given [elements]
*/
@JvmName("containsAll_T")
fun containsAll(elements: Collection) = getResult().containsAll(elements)
/**
* Adds [element]s to the set
*
* @return 'true if any of the elements has been added, 'false' if all elements are already contained in the set.
*/
fun add(vararg element: T) = addAll(element.toList())
/**
* Adds [elements] to the set
*
* @return 'true if any of the elements has been added, 'false' if all elements are already contained in the set.
*/
@JvmName("addAll_T")
fun addAll(elements: Collection): Boolean = when {
getResult().containsAll(elements) -> false
else -> getMutableResult().addAll(elements)
}
/**
* Removes elements from the set
*/
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
}
/**
* 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.toSet())
}
}
/**
* Removes all elements from the the list that match the predicate
*/
fun removeWhere(predicate: T.() -> Boolean) = retainWhere { !predicate(this) }
/**
* Iterator impl
*/
internal inner class It(set: Set, private val mapper: (T, OnModify) -> M) : MutableIterator {
private val inner = set.iterator()
private var current: T? = null
override fun hasNext() = inner.hasNext()
override fun next(): M {
return inner.next().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) {
remove(this)
add(it)
}
}
}
override fun remove() {
current?.apply { remove(this) }
}
}
}
@Suppress("Detekt.TooManyFunctions")
internal class MutableSetWrapper(inner: MutableSet) : MutableSet {
private var _inner = inner
private var primed = false
override fun toString() = _inner.toString()
override fun equals(other: Any?) = repair { _inner == other }
override fun hashCode() = repair { _inner.hashCode() }
override val size: Int get() = _inner.size
// Safe operations ////////////////////////////////////////////////////////////////////
override fun iterator() = _inner.iterator()
override fun contains(element: X) = _inner.contains(element)
override fun containsAll(elements: Collection) = _inner.containsAll(elements)
override fun isEmpty() = _inner.isEmpty()
// Ops that prime reparations /////////////////////////////////////////////////////////
override fun add(element: X) = prime { _inner.add(element) }
override fun addAll(elements: Collection) = prime { _inner.addAll(elements) }
override fun clear() = prime { _inner.clear() }
override fun remove(element: X) = prime { _inner.remove(element) }
override fun removeAll(elements: Collection) = prime { _inner.removeAll(elements) }
override fun retainAll(elements: Collection) = prime { _inner.retainAll(elements) }
// helpers ////////////////////////////////////////////////////////////////////////////
private fun prime(cb: () -> R): R {
primed = true
return cb()
}
private fun repair(cb: () -> R): R {
if (primed) {
primed = false
// Here we restore the inner hash tables of the set
_inner = LinkedHashSet(_inner)
}
return cb()
}
}