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

com.itangcent.common.utils.MultiValuesMap.kt Maven / Gradle / Ivy

package com.itangcent.common.utils


/**
 * A collection that maps keys to values, similar to [Map], but in which each key may be
 * associated with multiple values. You can visualize the contents of a multimap either as a
 * map from keys to nonempty collections of values:
 *
 * 
    *
  • a → 1, 2 *
  • b → 3 *
* * ... or as a single "flattened" collection of key-value pairs: * *
    *
  • a → 1 *
  • a → 2 *
  • b → 3 *
* @author tangcent */ class MultiValuesMap : Map?> { /** * The head (eldest) of the doubly linked list. */ private var head: Node? = null /** * The tail (youngest) of the doubly linked list. */ private var tail: Node? = null @Transient private val keyToNode: HashMap> = LinkedHashMap() @Transient private var count = 0 internal open class Node(override val key: K, override val value: V) : Map.Entry { var previous: Node? = null// the previous node (with any key) var next: Node? = null// the next node (with any key) var nextSibling: Node? = null // the next node with the same key override fun toString(): String { return "Node(key=$key, value=$value)" } override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as Node<*, *> if (key != other.key) return false if (value != other.value) return false return true } override fun hashCode(): Int { var result = key?.hashCode() ?: 0 result = 31 * result + (value?.hashCode() ?: 0) return result } } override val entries: Set?>> get() = EntryCollectionImpl(keyToNode.entries, keyToNode.size) override val keys: Set get() = keyToNode.keys override val size: Int get() = keyToNode.size val valueSize: Int get() = count @Suppress("UNCHECKED_CAST") override val values: Collection?> get() { val node: MutableCollection> = keyToNode.values return ValueCollectionImpl(node as MutableCollection>, count) } override fun containsValue(value: Collection?): Boolean { return values.contains(value) } override fun isEmpty(): Boolean { return count == 0 } fun putAll(key: K, values: Collection) { for (value in values) { put(key, value) } } fun putAll(key: K, vararg values: V) { for (value in values) { put(key, value) } } fun put(key: K, value: V) { var node = keyToNode[key] if (node == null) { node = Node(key, value) keyToNode[key] = node addNode(node) } else { do { if (node!!.value == value) { return } if (node.nextSibling == null) { break } node = node.nextSibling } while (true) val newNode = Node(key, value) addNode(newNode) node!!.nextSibling = newNode } } private fun addNode(node: Node) { if (tail == null) { head = node tail = node } else { tail!!.next = node node.previous = tail tail = node } ++count } fun replace(key: K, value: V) { var node = keyToNode[key] if (node != null) { removeAll(node) } node = Node(key, value) keyToNode[key] = node addNode(node) return } override operator fun get(key: K): Collection? { return keyToNode[key]?.let { ValueSiblingCollectionImpl(it) } } fun flattenValues(): Collection { return ValueFlattenCollectionImpl(head, count) } fun flattenForEach(action: (K, V) -> Unit) { var h: Node? = head ?: return while (h != null) { action(h.key, h.value) h = h.next } } fun flattenForEach(keyFilter: (K) -> Boolean, action: (K, V) -> Unit) { flattenForEach { key, value -> if (keyFilter(key)) { action(key, value) } } } fun remove(key: K, value: V) { var node = keyToNode[key] ?: return if (node.value == value) { val next = node.nextSibling if (next == null) { keyToNode.remove(key) } else { keyToNode[key] = next } removeNode(node) return } do { val next = node.next ?: return if (next.value == value) { node.nextSibling = next.nextSibling removeNode(next) return } node = next } while (true) } fun clear() { keyToNode.clear() head = null tail = null count = 0 } fun removeAll(key: K) { val node = keyToNode[key] if (node != null) { removeAll(node) keyToNode.remove(key) } } private fun removeAll(node: Node) { var n: Node? = node while (n != null) { removeNode(n) n = n.nextSibling } } private fun removeNode(node: Node) { --count val previous = node.previous val next = node.next if (node === head) { head = next } if (node === tail) { tail = previous } previous?.next = next next?.previous = previous } override fun containsKey(key: K): Boolean { return keyToNode.containsKey(key) } fun getFirst(key: K): V? { return keyToNode[key]?.value } /** * it will throw an IllegalArgumentException if the value of the key is not unique */ fun getOne(key: K): V? { val node = keyToNode[key] ?: return null return when (node.nextSibling) { null -> node.value else -> throw IllegalArgumentException("$key has more than one value") } } private class EntryCollectionImpl( private var node: MutableSet>>, private var count: Int ) : AbstractSet>>() { override val size: Int get() = count override fun iterator(): Iterator>> { return EntryIteratorImpl(node.iterator()) } } private class EntryIteratorImpl(private var node: MutableIterator>>) : Iterator>> { override fun hasNext(): Boolean { return node.hasNext() } override fun next(): Map.Entry> { return node.next().let { EntryImpl(it.key, ValueSiblingCollectionImpl(it.value)) } } } private class EntryImpl( override val key: K, override val value: Collection ) : Map.Entry> { override fun toString(): String { return "EntryImpl(key=$key, value=$value)" } override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as EntryImpl<*, *> if (key != other.key) return false if (value != other.value) return false return true } override fun hashCode(): Int { var result = key?.hashCode() ?: 0 result = 31 * result + value.hashCode() return result } } private class ValueCollectionImpl( private var node: MutableCollection>, private var count: Int ) : AbstractCollection>() { override val size: Int get() = count override fun iterator(): Iterator> { return ValueIteratorImpl(node.iterator()) } override fun equals(other: Any?): Boolean { if (other === this) return true if (other !is Collection<*>) return false if (count != other.size) return false val e1 = iterator() val e2 = other.iterator() while (e1.hasNext() && e2.hasNext()) { val o1 = e1.next() val o2 = e2.next() if (o1 != o2) return false } return !(e1.hasNext() || e2.hasNext()) } override fun hashCode(): Int { var result = node.hashCode() result = 31 * result + count return result } } private class ValueIteratorImpl(private var node: MutableIterator>) : Iterator> { override fun hasNext(): Boolean { return node.hasNext() } override fun next(): Collection { return ValueSiblingCollectionImpl(node.next()) } } private class ValueFlattenCollectionImpl( private var node: Node<*, E>?, private var count: Int ) : AbstractList() { override val size: Int get() = count override fun iterator(): Iterator { return ValueFlattenIteratorImpl(node) } override fun equals(other: Any?): Boolean { if (other === this) return true if (other !is Collection<*>) return false if (count != other.size) return false val e1 = iterator() val e2 = other.iterator() while (e1.hasNext() && e2.hasNext()) { val o1 = e1.next() val o2 = e2.next() if (o1 != o2) return false } return !(e1.hasNext() || e2.hasNext()) } override fun hashCode(): Int { var result = node.hashCode() result = 31 * result + count return result } override fun get(index: Int): E { var x = node for (a in 1..index) { x = x!!.next } return x!!.value } } private class ValueFlattenIteratorImpl(private var node: Node<*, E>?) : Iterator { override fun hasNext(): Boolean { return node != null } override fun next(): E { val v = node!!.value node = node!!.next return v } } private class ValueSiblingCollectionImpl( private var node: Node<*, E>? ) : AbstractCollection() { override val size: Int get() = count() private fun count(): Int { var i = 0 iterator().forEach { ++i } return i } override fun iterator(): Iterator { return ValueSiblingIteratorImpl(node) } override fun equals(other: Any?): Boolean { if (other === this) return true if (other !is Collection<*>) return false val e1 = iterator() val e2 = other.iterator() while (e1.hasNext() && e2.hasNext()) { val o1 = e1.next() val o2 = e2.next() if (o1 != o2) return false } return !(e1.hasNext() || e2.hasNext()) } override fun hashCode(): Int { return node.hashCode() } } private class ValueSiblingIteratorImpl(private var node: Node<*, E>?) : Iterator { override fun hasNext(): Boolean { return node != null } override fun next(): E { val v = node!!.value node = node!!.nextSibling return v } } override fun toString(): String { if (isEmpty()) return "{}" val sb = StringBuilder() sb.append('{') var h: Node? = head while (h != null) { sb.append(if (h.key === this) "(this Map)" else h.key) sb.append('=') sb.append(if (h.value === this) "(this Map)" else h.value) h = h.next if (h != null) { sb.append(',').append(' ') } else { break } } return sb.append('}').toString() } override fun equals(other: Any?): Boolean { if (other === this) return true if (other !is MultiValuesMap<*, *>) return false if (other.size != size) return false var h1 = this.head var h2 = other.head while (h1 != null && h2 != null) { if (h1 != h2) { return false } h1 = h1.next h2 = h2.next } return h1 == h2 } override fun hashCode(): Int { var h = 0 val i = entries.iterator() while (i.hasNext()) h += i.next().hashCode() return h } } fun multiValuesMapOf(vararg pairs: Pair): MultiValuesMap = MultiValuesMap().also { map -> pairs.forEach { (first, second) -> map.put(first, second) } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy