All Downloads are FREE. Search and download functionalities are using the official Maven repository.

e.ultra.mutator.0.76.0.source-code.SetMutator.kt Maven / Gradle / Ivy

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()
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy