
e.ultra.mutator.0.77.0.source-code.SetMutator.kt Maven / Gradle / Ivy
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()
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy