Code polish
parent
2f60a33ef0
commit
599fc0554a
|
@ -231,7 +231,7 @@ class ArrayMap<K: Any, V> : MutableMap<K, V?>{
|
|||
* Returns the value (which may be null) for the specified key, or the default value if the key is not in the map. Note this
|
||||
* does a .equals() comparison of each key in reverse order until the specified key is found.
|
||||
*/
|
||||
operator fun get(key: K?, defaultValue: V?): V? {
|
||||
operator fun get(key: K?, defaultValue: V): V? {
|
||||
val keys = keyTable
|
||||
var i = size_ - 1
|
||||
if (key == null) {
|
||||
|
@ -246,6 +246,7 @@ class ArrayMap<K: Any, V> : MutableMap<K, V?>{
|
|||
i--
|
||||
}
|
||||
}
|
||||
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
|
@ -626,7 +627,7 @@ class ArrayMap<K: Any, V> : MutableMap<K, V?>{
|
|||
val key = keys[i] as K
|
||||
val value = values[i]
|
||||
if (value == null) {
|
||||
if (other.get(key, dummy as V?) != null) {
|
||||
if (other.get(key, dummy as V) != null) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -656,7 +657,7 @@ class ArrayMap<K: Any, V> : MutableMap<K, V?>{
|
|||
var i = 0
|
||||
val n = size_
|
||||
while (i < n) {
|
||||
if (values[i] !== other.get(keys[i], dummy as V?)) return false
|
||||
if (values[i] !== other.get(keys[i], dummy as V)) return false
|
||||
i++
|
||||
}
|
||||
return true
|
||||
|
@ -787,11 +788,17 @@ class ArrayMap<K: Any, V> : MutableMap<K, V?>{
|
|||
return keys2!!
|
||||
}
|
||||
|
||||
class Entries<K: Any, V>(private val map: ArrayMap<K, V?>) : MutableSet<Entry<K, V?>>,Iterable<Entry<K, V?>>, MutableIterator<Entry<K, V?>> {
|
||||
class Entries<K: Any, V>(private val map: ArrayMap<K, V?>) : MutableSet<Entry<K, V?>>, MutableIterator<Entry<K, V?>> {
|
||||
|
||||
var entry: Entry<K, V?> = Entry(map)
|
||||
var index = 0
|
||||
var valid = true
|
||||
private lateinit var entry: Entry<K, V?>
|
||||
internal var index = 0
|
||||
internal var valid = true
|
||||
|
||||
init {
|
||||
if (hasNext()) {
|
||||
entry = Entry(map)
|
||||
}
|
||||
}
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
if (!valid) throw RuntimeException("#iterator() cannot be used nested.")
|
||||
|
@ -882,7 +889,7 @@ class ArrayMap<K: Any, V> : MutableMap<K, V?>{
|
|||
if (index >= map.size_) throw NoSuchElementException(index.toString())
|
||||
if (!valid) throw RuntimeException("#iterator() cannot be used nested.")
|
||||
|
||||
entry.key = map.keyTable[index] as K
|
||||
entry.key = map.keyTable[index]!!
|
||||
entry.value = map.valueTable[index++]
|
||||
return entry
|
||||
}
|
||||
|
@ -897,9 +904,10 @@ class ArrayMap<K: Any, V> : MutableMap<K, V?>{
|
|||
}
|
||||
}
|
||||
|
||||
class Entry<K: Any, V>(val map: ArrayMap<K, V?>) : MutableMap.MutableEntry<K, V?> {
|
||||
override lateinit var key: K
|
||||
override var value: V? = null
|
||||
class Entry<K: Any, V>(val map: ArrayMap<K, V>) : MutableMap.MutableEntry<K, V?> {
|
||||
// we know there will be at least one
|
||||
override var key: K = map.keyTable[0]!!
|
||||
override var value: V? = map.valueTable[0]
|
||||
|
||||
override fun setValue(newValue: V?): V? {
|
||||
val oldValue = value
|
||||
|
@ -913,7 +921,7 @@ class ArrayMap<K: Any, V> : MutableMap<K, V?>{
|
|||
}
|
||||
}
|
||||
|
||||
class Values<V>(map: ArrayMap<Any, V?>) : MutableCollection<V>, Iterable<V>, MutableIterator<V> {
|
||||
class Values<V>(map: ArrayMap<Any, V?>) : MutableCollection<V>, MutableIterator<V> {
|
||||
private val map: ArrayMap<Any, V?>
|
||||
var index = 0
|
||||
var valid = true
|
||||
|
@ -1028,7 +1036,7 @@ class ArrayMap<K: Any, V> : MutableMap<K, V?>{
|
|||
}
|
||||
}
|
||||
|
||||
class Keys<K: Any>(map: ArrayMap<K, Any>) : MutableSet<K>, Iterable<K>, MutableIterator<K> {
|
||||
class Keys<K: Any>(map: ArrayMap<K, Any>) : MutableSet<K>, MutableIterator<K> {
|
||||
private val map: ArrayMap<K, Any>
|
||||
var index = 0
|
||||
var valid = true
|
||||
|
|
|
@ -238,8 +238,8 @@ open class IntMap<V> : MutableMap<Int, V> {
|
|||
return if (i >= 0) valueTable[i] else null
|
||||
}
|
||||
|
||||
operator fun get(key: Int, defaultValue: V?): V? {
|
||||
if (key == 0) return if (hasZeroValue) zeroValue else defaultValue
|
||||
operator fun get(key: Int, defaultValue: V): V? {
|
||||
if (key == 0) return if (hasZeroValue) zeroValue!! else defaultValue
|
||||
val i = locateKey(key)
|
||||
return if (i >= 0) valueTable[i] else defaultValue
|
||||
}
|
||||
|
@ -489,7 +489,7 @@ open class IntMap<V> : MutableMap<Int, V> {
|
|||
if (key != 0) {
|
||||
val value: V? = valueTable[i]
|
||||
if (value == null) {
|
||||
if (other.get(key, ObjectMap.dummy as V?) != null) return false
|
||||
if (other.get(key, ObjectMap.dummy as V) != null) return false
|
||||
}
|
||||
else {
|
||||
if (value != other[key]) return false
|
||||
|
@ -518,7 +518,7 @@ open class IntMap<V> : MutableMap<Int, V> {
|
|||
val n = keyTable.size
|
||||
while (i < n) {
|
||||
val key = keyTable[i]
|
||||
if (key != 0 && valueTable[i] !== other.get(key, ObjectMap.dummy as V?)) return false
|
||||
if (key != 0 && valueTable[i] !== other.get(key, ObjectMap.dummy as V)) return false
|
||||
i++
|
||||
}
|
||||
return true
|
||||
|
|
|
@ -263,16 +263,13 @@ class LockFreeBiMap<K: Any, V: Any> : MutableMap<K, V>, Cloneable, Serializable
|
|||
*
|
||||
* @param key key whose mapping is to be removed from the map
|
||||
*
|
||||
* @return the previous value associated with <tt>key</tt>, or
|
||||
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
|
||||
* (A <tt>null</tt> return can also indicate that the map
|
||||
* previously associated <tt>null</tt> with <tt>key</tt>.)
|
||||
* @return the previous value associated with [key]
|
||||
*/
|
||||
@Synchronized
|
||||
override fun remove(key: K): V? {
|
||||
override fun remove(key: K): V {
|
||||
val value = forwardHashMap.remove(key)
|
||||
reverseHashMap.remove(value)
|
||||
return value
|
||||
return value!!
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,10 +34,10 @@ import java.util.concurrent.atomic.*
|
|||
*
|
||||
* This data structure is for many-read/few-write scenarios
|
||||
*/
|
||||
class LockFreeHashMap<K: Any, V> : MutableMap<K, V?>, Cloneable, Serializable {
|
||||
class LockFreeHashMap<K: Any, V> : MutableMap<K, V>, Cloneable, Serializable {
|
||||
|
||||
@Volatile
|
||||
private var hashMap: MutableMap<K, V?>
|
||||
private var hashMap: HashMap<K, V>
|
||||
|
||||
|
||||
// synchronized is used here to ensure the "single writer principle", and make sure that ONLY one thread at a time can enter this
|
||||
|
@ -96,11 +96,11 @@ class LockFreeHashMap<K: Any, V> : MutableMap<K, V?>, Cloneable, Serializable {
|
|||
hashMap = HashMap(initialCapacity, loadFactor)
|
||||
}
|
||||
|
||||
val map: MutableMap<K, V>
|
||||
get() {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return mapREF[this] as MutableMap<K, V>
|
||||
}
|
||||
private val map: MutableMap<K, V>
|
||||
get() {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return mapREF[this] as MutableMap<K, V>
|
||||
}
|
||||
|
||||
|
||||
override val size: Int
|
||||
|
@ -114,16 +114,14 @@ class LockFreeHashMap<K: Any, V> : MutableMap<K, V?>, Cloneable, Serializable {
|
|||
return map.keys
|
||||
}
|
||||
|
||||
override val values: MutableCollection<V?>
|
||||
override val values: MutableCollection<V>
|
||||
get() {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return map.values as MutableCollection<V?>
|
||||
return map.values
|
||||
}
|
||||
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V?>>
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
|
||||
get() {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return map.entries as MutableSet<MutableMap.MutableEntry<K, V?>>
|
||||
return map.entries
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
|
@ -136,7 +134,7 @@ class LockFreeHashMap<K: Any, V> : MutableMap<K, V?>, Cloneable, Serializable {
|
|||
return mapREF[this].containsKey(key)
|
||||
}
|
||||
|
||||
override fun containsValue(value: V?): Boolean {
|
||||
override fun containsValue(value: V): Boolean {
|
||||
// use the SWP to get a lock-free get of the value
|
||||
return mapREF[this].containsValue(value)
|
||||
}
|
||||
|
@ -147,7 +145,7 @@ class LockFreeHashMap<K: Any, V> : MutableMap<K, V?>, Cloneable, Serializable {
|
|||
}
|
||||
|
||||
@Synchronized
|
||||
override fun put(key: K, value: V?): V? {
|
||||
override fun put(key: K, value: V): V? {
|
||||
return hashMap.put(key, value)
|
||||
}
|
||||
|
||||
|
@ -168,7 +166,7 @@ class LockFreeHashMap<K: Any, V> : MutableMap<K, V?>, Cloneable, Serializable {
|
|||
}
|
||||
|
||||
@Synchronized
|
||||
override fun putAll(from: Map<out K, V?>) {
|
||||
override fun putAll(from: Map<out K, V>) {
|
||||
hashMap.putAll(from)
|
||||
}
|
||||
|
||||
|
|
|
@ -282,10 +282,7 @@ class LockFreeIntBiMap<V: Any> : MutableMap<Int, V>, Cloneable, Serializable {
|
|||
*
|
||||
* @param key key whose mapping is to be removed from the map
|
||||
*
|
||||
* @return the previous value associated with <tt>key</tt>, or
|
||||
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
|
||||
* (A <tt>null</tt> return can also indicate that the map
|
||||
* previously associated <tt>null</tt> with <tt>key</tt>.)
|
||||
* @return the previous value associated with [key]
|
||||
*/
|
||||
@Synchronized
|
||||
override fun remove(key: Int): V? {
|
||||
|
|
|
@ -47,7 +47,7 @@ import java.util.concurrent.atomic.*
|
|||
* Iteration can be very slow for a map with a large capacity. [.clear] and [.shrink] can be used to reduce
|
||||
* the capacity. [OrderedMap] provides much faster iteration.
|
||||
*/
|
||||
class LockFreeIntMap<V> : IntMap<V>, Cloneable, Serializable {
|
||||
class LockFreeIntMap<V> : MutableMap<Int, V>, Cloneable, Serializable {
|
||||
|
||||
@Volatile
|
||||
private var hashMap: IntMap<V>
|
||||
|
@ -107,7 +107,11 @@ class LockFreeIntMap<V> : IntMap<V>, Cloneable, Serializable {
|
|||
return value.containsKey(key)
|
||||
}
|
||||
|
||||
override fun containsValue(value: Any?, identity: Boolean): Boolean {
|
||||
override fun containsValue(value: V): Boolean {
|
||||
return containsValue(value, false)
|
||||
}
|
||||
|
||||
fun containsValue(value: Any?, identity: Boolean): Boolean {
|
||||
// use the SWP to get a lock-free get of the value
|
||||
return mapREF[this].containsValue(value, identity)
|
||||
}
|
||||
|
@ -130,7 +134,7 @@ class LockFreeIntMap<V> : IntMap<V>, Cloneable, Serializable {
|
|||
}
|
||||
|
||||
@Synchronized
|
||||
override fun putAll(from: IntMap<out V>) {
|
||||
override fun putAll(from: Map<out Int, V>) {
|
||||
hashMap.putAll(from)
|
||||
}
|
||||
|
||||
|
@ -145,9 +149,10 @@ class LockFreeIntMap<V> : IntMap<V>, Cloneable, Serializable {
|
|||
* Returns an iterator for the keys in the map. Remove is supported. Note that the same iterator instance is returned each
|
||||
* time this method is called. Use the [ObjectMap.Entries] constructor for nested or multithreaded iteration.
|
||||
*/
|
||||
override fun keys(): Keys {
|
||||
return mapREF[this].keys()
|
||||
}
|
||||
override val keys: IntMap.Keys
|
||||
get() {
|
||||
return mapREF[this].keys()
|
||||
}
|
||||
|
||||
/**
|
||||
* DO NOT MODIFY THE MAP VIA THIS (unless you synchronize around it!) It will result in unknown object visibility!
|
||||
|
@ -156,9 +161,10 @@ class LockFreeIntMap<V> : IntMap<V>, Cloneable, Serializable {
|
|||
* time this method is called. Use the [ObjectMap.Entries] constructor for nested or multithreaded iteration.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun values(): Values<V> {
|
||||
return mapREF[this].values() as Values<V>
|
||||
}
|
||||
override val values: IntMap.Values<V>
|
||||
get() {
|
||||
return mapREF[this].values() as IntMap.Values<V>
|
||||
}
|
||||
|
||||
/**
|
||||
* DO NOT MODIFY THE MAP VIA THIS (unless you synchronize around it!) It will result in unknown object visibility!
|
||||
|
@ -167,15 +173,16 @@ class LockFreeIntMap<V> : IntMap<V>, Cloneable, Serializable {
|
|||
* time this method is called. Use the [ObjectMap.Entries] constructor for nested or multithreaded iteration.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun entries(): Entries<V?> {
|
||||
return mapREF[this].entries() as Entries<V?>
|
||||
}
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<Int, V>>
|
||||
get() {
|
||||
return mapREF[this].entries() as MutableSet<MutableMap.MutableEntry<Int, V>>
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return mapREF[this] == other
|
||||
}
|
||||
|
||||
override fun equalsIdentity(other: Any?): Boolean {
|
||||
fun equalsIdentity(other: Any?): Boolean {
|
||||
return mapREF[this].equalsIdentity(other)
|
||||
}
|
||||
|
||||
|
@ -192,7 +199,7 @@ class LockFreeIntMap<V> : IntMap<V>, Cloneable, Serializable {
|
|||
* is done by allocating new arrays, though for large arrays this can be faster than clearing the existing array.
|
||||
*/
|
||||
@Synchronized
|
||||
override fun clear(maximumCapacity: Int) {
|
||||
fun clear(maximumCapacity: Int) {
|
||||
mapREF[this].clear(maximumCapacity)
|
||||
}
|
||||
|
||||
|
@ -202,7 +209,7 @@ class LockFreeIntMap<V> : IntMap<V>, Cloneable, Serializable {
|
|||
* If the map contains more items than the specified capacity, the next highest power of two capacity is used instead.
|
||||
*/
|
||||
@Synchronized
|
||||
override fun shrink(maximumCapacity: Int) {
|
||||
fun shrink(maximumCapacity: Int) {
|
||||
mapREF[this].shrink(maximumCapacity)
|
||||
}
|
||||
|
||||
|
|
|
@ -36,10 +36,10 @@ import java.util.concurrent.atomic.*
|
|||
*/
|
||||
class LockFreeObjectBiMap<K: Any, V: Any> : MutableMap<K, V>, Cloneable, Serializable {
|
||||
@Volatile
|
||||
private var forwardHashMap: MutableMap<K, V>
|
||||
private var forwardHashMap: ObjectMap<K, V>
|
||||
|
||||
@Volatile
|
||||
private var reverseHashMap: MutableMap<V, K>
|
||||
private var reverseHashMap: ObjectMap<V, K>
|
||||
|
||||
private val inverse: LockFreeObjectBiMap<V, K>
|
||||
|
||||
|
@ -52,7 +52,7 @@ class LockFreeObjectBiMap<K: Any, V: Any> : MutableMap<K, V>, Cloneable, Seriali
|
|||
inverse = LockFreeObjectBiMap(reverseHashMap, forwardHashMap, this)
|
||||
}
|
||||
|
||||
private constructor(forwardHashMap: MutableMap<K, V>, reverseHashMap: MutableMap<V, K>, inverse: LockFreeObjectBiMap<V, K>) {
|
||||
private constructor(forwardHashMap: ObjectMap<K, V>, reverseHashMap: ObjectMap<V, K>, inverse: LockFreeObjectBiMap<V, K>) {
|
||||
this.forwardHashMap = forwardHashMap
|
||||
this.reverseHashMap = reverseHashMap
|
||||
this.inverse = inverse
|
||||
|
@ -428,10 +428,10 @@ class LockFreeObjectBiMap<K: Any, V: Any> : MutableMap<K, V>, Cloneable, Seriali
|
|||
|
||||
// Recommended for best performance while adhering to the "single writer principle". Must be static-final
|
||||
private val forwardREF = AtomicReferenceFieldUpdater.newUpdater(
|
||||
LockFreeObjectBiMap::class.java, MutableMap::class.java, "forwardHashMap"
|
||||
LockFreeObjectBiMap::class.java, ObjectMap::class.java, "forwardHashMap"
|
||||
)
|
||||
private val reverseREF = AtomicReferenceFieldUpdater.newUpdater(
|
||||
LockFreeObjectBiMap::class.java, MutableMap::class.java, "reverseHashMap"
|
||||
LockFreeObjectBiMap::class.java, ObjectMap::class.java, "reverseHashMap"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -286,21 +286,19 @@ class LockFreeObjectIntBiMap<K: Any> : MutableMap<K, Int>, Cloneable, Serializab
|
|||
*
|
||||
* @param key key whose mapping is to be removed from the map
|
||||
*
|
||||
* @return the previous value associated with <tt>key</tt>, or
|
||||
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
|
||||
* (A <tt>null</tt> return can also indicate that the map
|
||||
* previously associated <tt>null</tt> with <tt>key</tt>.)
|
||||
* @return the previous value associated with [key] or [defaultReturnValue] if it doesn't exist
|
||||
*
|
||||
*/
|
||||
@Synchronized
|
||||
override fun remove(key: K): Int? {
|
||||
override fun remove(key: K): Int {
|
||||
val value = forwardHashMap.remove(key)
|
||||
reverseHashMap.remove(value)
|
||||
return value
|
||||
return value ?: defaultReturnValue
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to which the specified key is mapped,
|
||||
* or `null` if this map contains no mapping for the key.
|
||||
* or [defaultReturnValue] if this map contains no mapping for the key.
|
||||
*
|
||||
*
|
||||
* More formally, if this map contains a mapping from a key
|
||||
|
@ -309,9 +307,9 @@ class LockFreeObjectIntBiMap<K: Any> : MutableMap<K, Int>, Cloneable, Serializab
|
|||
* it returns `null`. (There can be at most one such mapping.)
|
||||
*
|
||||
*
|
||||
* A return value of `null` does not *necessarily*
|
||||
* A return value of [defaultReturnValue] does not *necessarily*
|
||||
* indicate that the map contains no mapping for the key; it's also
|
||||
* possible that the map explicitly maps the key to `null`.
|
||||
* possible that the map explicitly maps the key to [defaultReturnValue].
|
||||
* The [containsKey][HashMap.containsKey] operation may be used to
|
||||
* distinguish these two cases.
|
||||
*
|
||||
|
@ -319,8 +317,7 @@ class LockFreeObjectIntBiMap<K: Any> : MutableMap<K, Int>, Cloneable, Serializab
|
|||
*/
|
||||
override operator fun get(key: K): Int {
|
||||
// use the SWP to get a lock-free get of the value
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return (forwardREF[this] as ObjectIntMap<K>)[key] as Int
|
||||
return forwardREF[this][key] ?: defaultReturnValue
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Copyright 2023 dorkbox, llc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package dorkbox.collections
|
||||
|
||||
import java.io.Serializable
|
||||
import java.util.concurrent.atomic.*
|
||||
|
||||
/**
|
||||
* This class uses the "single-writer-principle" for lock-free publication.
|
||||
*
|
||||
*
|
||||
* Since there are only 2 methods to guarantee that modifications can only be called one-at-a-time (either it is only called by
|
||||
* one thread, or only one thread can access it at a time) -- we chose the 2nd option -- and use 'synchronized' to make sure that only
|
||||
* one thread can access this modification methods at a time. Getting or checking the presence of values can then happen in a lock-free
|
||||
* manner.
|
||||
*
|
||||
*
|
||||
* According to my benchmarks, this is approximately 25% faster than ConcurrentHashMap for (all types of) reads, and a lot slower for
|
||||
* contended writes.
|
||||
*
|
||||
*
|
||||
* This data structure is for many-read/few-write scenarios
|
||||
*
|
||||
*
|
||||
* An unordered map. This implementation is a cuckoo hash map using 3 hashes, random walking, and a small stash for problematic
|
||||
* keys. Null keys are not allowed. Null values are allowed. No allocation is done except when growing the table size. <br></br>
|
||||
*
|
||||
*
|
||||
* This map performs very fast get, containsKey, and remove (typically O(1), worst case O(log(n))). Put may be a bit slower,
|
||||
* depending on hash collisions. Load factors greater than 0.91 greatly increase the chances the map will have to rehash to the
|
||||
* next higher POT size.
|
||||
*
|
||||
*
|
||||
* Iteration can be very slow for a map with a large capacity. [.clear] and [.shrink] can be used to reduce
|
||||
* the capacity. [OrderedMap] provides much faster iteration.
|
||||
*/
|
||||
class LockFreeObjectIntMap<K: Any> : MutableMap<K, Int>, Cloneable, Serializable {
|
||||
|
||||
@Volatile
|
||||
private var hashMap: ObjectIntMap<K>
|
||||
|
||||
// synchronized is used here to ensure the "single writer principle", and make sure that ONLY one thread at a time can enter this
|
||||
// section. Because of this, we can have unlimited reader threads all going at the same time, without contention (which is our
|
||||
// use-case 99% of the time)
|
||||
/**
|
||||
* Constructs an empty <tt>HashMap</tt> with the default initial capacity
|
||||
* (16) and the default load factor (0.75).
|
||||
*/
|
||||
constructor() {
|
||||
hashMap = ObjectIntMap()
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty <tt>HashMap</tt> with the specified initial
|
||||
* capacity and the default load factor (0.75).
|
||||
*
|
||||
* @param initialCapacity the initial capacity.
|
||||
*
|
||||
* @throws IllegalArgumentException if the initial capacity is negative.
|
||||
*/
|
||||
constructor(initialCapacity: Int) {
|
||||
hashMap = ObjectIntMap(initialCapacity)
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty <tt>HashMap</tt> with the specified initial
|
||||
* capacity and load factor.
|
||||
*
|
||||
* @param initialCapacity the initial capacity
|
||||
* @param loadFactor the load factor
|
||||
*
|
||||
* @throws IllegalArgumentException if the initial capacity is negative
|
||||
* or the load factor is nonpositive
|
||||
*/
|
||||
constructor(initialCapacity: Int, loadFactor: Float) {
|
||||
hashMap = ObjectIntMap(initialCapacity, loadFactor)
|
||||
}
|
||||
|
||||
override val size: Int
|
||||
get() {
|
||||
// use the SWP to get a lock-free get of the value
|
||||
return mapREF[this].size
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
// use the SWP to get a lock-free get of the value
|
||||
return mapREF[this].size == 0
|
||||
}
|
||||
|
||||
override fun containsKey(key: K): Boolean {
|
||||
// use the SWP to get a lock-free get of the value
|
||||
return mapREF[this].containsKey(key)
|
||||
}
|
||||
|
||||
override fun containsValue(value: Int): Boolean {
|
||||
// use the SWP to get a lock-free get of the value
|
||||
return mapREF[this].containsValue(value)
|
||||
}
|
||||
|
||||
override operator fun get(key: K): Int? {
|
||||
// use the SWP to get a lock-free get of the value
|
||||
return mapREF[this].get(key)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value for the specified key, or the default value if the key is not in the map.
|
||||
*/
|
||||
operator fun get(key: K, defaultValue: Int): Int {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val objectIntMap = mapREF[this] as ObjectIntMap<K>
|
||||
return objectIntMap.get(key, defaultValue)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun put(key: K, value: Int): Int? {
|
||||
return hashMap.put(key, value)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun remove(key: K): Int? {
|
||||
return hashMap.remove(key)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun putAll(from: Map<out K, Int>) {
|
||||
hashMap.putAll(from)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun clear() {
|
||||
hashMap.clear()
|
||||
}
|
||||
|
||||
/**
|
||||
* DO NOT MODIFY THE MAP VIA THIS (unless you synchronize around it!) It will result in unknown object visibility!
|
||||
*
|
||||
* Returns an iterator for the keys in the map. Remove is supported. Note that the same iterator instance is returned each
|
||||
* time this method is called. Use the [ObjectMap.Entries] constructor for nested or multithreaded iteration.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override val keys: ObjectIntMap.Keys<K>
|
||||
get() {
|
||||
return mapREF[this].keys() as ObjectIntMap.Keys<K>
|
||||
}
|
||||
|
||||
/**
|
||||
* DO NOT MODIFY THE MAP VIA THIS (unless you synchronize around it!) It will result in unknown object visibility!
|
||||
*
|
||||
* Returns an iterator for the values in the map. Remove is supported. Note that the same iterator instance is returned each
|
||||
* time this method is called. Use the [ObjectMap.Entries] constructor for nested or multithreaded iteration.
|
||||
*/
|
||||
override val values: ObjectIntMap.Values
|
||||
get() {
|
||||
return mapREF[this].values()
|
||||
}
|
||||
|
||||
/**
|
||||
* DO NOT MODIFY THE MAP VIA THIS (unless you synchronize around it!) It will result in unknown object visibility!
|
||||
*
|
||||
* Returns an iterator for the entries in the map. Remove is supported. Note that the same iterator instance is returned each
|
||||
* time this method is called. Use the [ObjectMap.Entries] constructor for nested or multithreaded iteration.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, Int>>
|
||||
get() {
|
||||
return mapREF[this].entries() as MutableSet<MutableMap.MutableEntry<K, Int>>
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return mapREF[this] == other
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return mapREF[this].hashCode()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return mapREF[this].toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the map and reduces the size of the backing arrays to be the specified capacity, if they are larger. The reduction
|
||||
* is done by allocating new arrays, though for large arrays this can be faster than clearing the existing array.
|
||||
*/
|
||||
@Synchronized
|
||||
fun clear(maximumCapacity: Int) {
|
||||
mapREF[this].clear(maximumCapacity)
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces the size of the backing arrays to be the specified capacity or less. If the capacity is already less, nothing is
|
||||
* done.
|
||||
* If the map contains more items than the specified capacity, the next highest power of two capacity is used instead.
|
||||
*/
|
||||
@Synchronized
|
||||
fun shrink(maximumCapacity: Int) {
|
||||
mapREF[this].shrink(maximumCapacity)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val version = Collections.version
|
||||
|
||||
// Recommended for best performance while adhering to the "single writer principle". Must be static-final
|
||||
private val mapREF = AtomicReferenceFieldUpdater.newUpdater(
|
||||
LockFreeObjectIntMap::class.java, ObjectIntMap::class.java, "hashMap"
|
||||
)
|
||||
}
|
||||
}
|
|
@ -47,10 +47,10 @@ import java.util.concurrent.atomic.*
|
|||
* Iteration can be very slow for a map with a large capacity. [.clear] and [.shrink] can be used to reduce
|
||||
* the capacity. [OrderedMap] provides much faster iteration.
|
||||
*/
|
||||
class LockFreeObjectMap<K: Any, V> : ObjectMap<K, V?>, Cloneable, Serializable {
|
||||
class LockFreeObjectMap<K: Any, V> : MutableMap<K, V>, Cloneable, Serializable {
|
||||
|
||||
@Volatile
|
||||
private var hashMap: ObjectMap<K, V?>
|
||||
private var hashMap: ObjectMap<K, V>
|
||||
|
||||
// synchronized is used here to ensure the "single writer principle", and make sure that ONLY one thread at a time can enter this
|
||||
// section. Because of this, we can have unlimited reader threads all going at the same time, without contention (which is our
|
||||
|
@ -107,7 +107,12 @@ class LockFreeObjectMap<K: Any, V> : ObjectMap<K, V?>, Cloneable, Serializable {
|
|||
return value.containsKey(key)
|
||||
}
|
||||
|
||||
override fun containsValue(value: Any?, identity: Boolean): Boolean {
|
||||
override fun containsValue(value: V): Boolean {
|
||||
// use the SWP to get a lock-free get of the value
|
||||
return mapREF[this].containsValue(value, false)
|
||||
}
|
||||
|
||||
fun containsValue(value: Any?, identity: Boolean): Boolean {
|
||||
// use the SWP to get a lock-free get of the value
|
||||
return mapREF[this].containsValue(value, identity)
|
||||
}
|
||||
|
@ -120,7 +125,7 @@ class LockFreeObjectMap<K: Any, V> : ObjectMap<K, V?>, Cloneable, Serializable {
|
|||
}
|
||||
|
||||
@Synchronized
|
||||
override fun put(key: K, value: V?): V? {
|
||||
override fun put(key: K, value: V): V? {
|
||||
return hashMap.put(key, value)
|
||||
}
|
||||
|
||||
|
@ -130,7 +135,7 @@ class LockFreeObjectMap<K: Any, V> : ObjectMap<K, V?>, Cloneable, Serializable {
|
|||
}
|
||||
|
||||
@Synchronized
|
||||
override fun putAll(from: ObjectMap<out K, out V?>) {
|
||||
override fun putAll(from: Map<out K, V>) {
|
||||
hashMap.putAll(from)
|
||||
}
|
||||
|
||||
|
@ -139,6 +144,8 @@ class LockFreeObjectMap<K: Any, V> : ObjectMap<K, V?>, Cloneable, Serializable {
|
|||
hashMap.clear()
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* DO NOT MODIFY THE MAP VIA THIS (unless you synchronize around it!) It will result in unknown object visibility!
|
||||
*
|
||||
|
@ -146,9 +153,10 @@ class LockFreeObjectMap<K: Any, V> : ObjectMap<K, V?>, Cloneable, Serializable {
|
|||
* time this method is called. Use the [ObjectMap.Entries] constructor for nested or multithreaded iteration.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun keys(): Keys<K> {
|
||||
return mapREF[this].keys() as Keys<K>
|
||||
}
|
||||
override val keys: ObjectMap.Keys<K>
|
||||
get() {
|
||||
return mapREF[this].keys() as ObjectMap.Keys<K>
|
||||
}
|
||||
|
||||
/**
|
||||
* DO NOT MODIFY THE MAP VIA THIS (unless you synchronize around it!) It will result in unknown object visibility!
|
||||
|
@ -157,9 +165,10 @@ class LockFreeObjectMap<K: Any, V> : ObjectMap<K, V?>, Cloneable, Serializable {
|
|||
* time this method is called. Use the [ObjectMap.Entries] constructor for nested or multithreaded iteration.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun values(): Values<V?> {
|
||||
return mapREF[this].values() as Values<V?>
|
||||
}
|
||||
override val values: ObjectMap.Values<V>
|
||||
get() {
|
||||
return mapREF[this].values() as ObjectMap.Values<V>
|
||||
}
|
||||
|
||||
/**
|
||||
* DO NOT MODIFY THE MAP VIA THIS (unless you synchronize around it!) It will result in unknown object visibility!
|
||||
|
@ -168,15 +177,16 @@ class LockFreeObjectMap<K: Any, V> : ObjectMap<K, V?>, Cloneable, Serializable {
|
|||
* time this method is called. Use the [ObjectMap.Entries] constructor for nested or multithreaded iteration.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun entries(): Entries<K, V?> {
|
||||
return mapREF[this].entries() as Entries<K, V?>
|
||||
}
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
|
||||
get() {
|
||||
return mapREF[this].entries() as MutableSet<MutableMap.MutableEntry<K, V>>
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return mapREF[this] == other
|
||||
}
|
||||
|
||||
override fun equalsIdentity(other: Any?): Boolean {
|
||||
fun equalsIdentity(other: Any?): Boolean {
|
||||
return mapREF[this].equalsIdentity(other)
|
||||
}
|
||||
|
||||
|
@ -193,7 +203,7 @@ class LockFreeObjectMap<K: Any, V> : ObjectMap<K, V?>, Cloneable, Serializable {
|
|||
* is done by allocating new arrays, though for large arrays this can be faster than clearing the existing array.
|
||||
*/
|
||||
@Synchronized
|
||||
override fun clear(maximumCapacity: Int) {
|
||||
fun clear(maximumCapacity: Int) {
|
||||
mapREF[this].clear(maximumCapacity)
|
||||
}
|
||||
|
||||
|
@ -203,7 +213,7 @@ class LockFreeObjectMap<K: Any, V> : ObjectMap<K, V?>, Cloneable, Serializable {
|
|||
* If the map contains more items than the specified capacity, the next highest power of two capacity is used instead.
|
||||
*/
|
||||
@Synchronized
|
||||
override fun shrink(maximumCapacity: Int) {
|
||||
fun shrink(maximumCapacity: Int) {
|
||||
mapREF[this].shrink(maximumCapacity)
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ import java.util.*
|
|||
* @author Nathan Sweet
|
||||
* @author Tommy Ettinger
|
||||
*/
|
||||
class LongMap<V> : MutableMap<Long, V> {
|
||||
class LongMap<V> : MutableMap<Long, V?> {
|
||||
companion object {
|
||||
const val version = Collections.version
|
||||
}
|
||||
|
@ -87,16 +87,16 @@ class LongMap<V> : MutableMap<Long, V> {
|
|||
protected var mask: Int
|
||||
|
||||
@Transient
|
||||
private var entries1: Entries<V>? = null
|
||||
private var entries1: Entries<V?>? = null
|
||||
|
||||
@Transient
|
||||
private var entries2: Entries<V>? = null
|
||||
private var entries2: Entries<V?>? = null
|
||||
|
||||
@Transient
|
||||
private var values1: Values<V>? = null
|
||||
private var values1: Values<V?>? = null
|
||||
|
||||
@Transient
|
||||
private var values2: Values<V>? = null
|
||||
private var values2: Values<V?>? = null
|
||||
|
||||
@Transient
|
||||
private var keys1: Keys? = null
|
||||
|
@ -175,7 +175,7 @@ class LongMap<V> : MutableMap<Long, V> {
|
|||
}
|
||||
|
||||
|
||||
override fun put(key: Long, value: V): V? {
|
||||
override fun put(key: Long, value: V?): V? {
|
||||
if (key == 0L) {
|
||||
val oldValue = zeroValue
|
||||
zeroValue = value
|
||||
|
@ -198,7 +198,7 @@ class LongMap<V> : MutableMap<Long, V> {
|
|||
return null
|
||||
}
|
||||
|
||||
fun putAll(map: LongMap<out V>) {
|
||||
fun putAll(map: LongMap<out V?>) {
|
||||
ensureCapacity(map.size_)
|
||||
if (map.hasZeroValue) {
|
||||
put(0, map.zeroValue!!)
|
||||
|
@ -237,8 +237,8 @@ class LongMap<V> : MutableMap<Long, V> {
|
|||
return if (i >= 0) valueTable[i] else null
|
||||
}
|
||||
|
||||
operator fun get(key: Long, defaultValue: V?): V? {
|
||||
if (key == 0L) return if (hasZeroValue) zeroValue else defaultValue
|
||||
operator fun get(key: Long, defaultValue: V): V? {
|
||||
if (key == 0L) return if (hasZeroValue) zeroValue!! else defaultValue
|
||||
val i = locateKey(key)
|
||||
return if (i >= 0) valueTable[i] else defaultValue
|
||||
}
|
||||
|
@ -294,7 +294,7 @@ class LongMap<V> : MutableMap<Long, V> {
|
|||
return size_ == 0
|
||||
}
|
||||
|
||||
override fun putAll(from: Map<out Long, V>) {
|
||||
override fun putAll(from: Map<out Long, V?>) {
|
||||
ensureCapacity(from.size)
|
||||
from.entries.forEach { (k,v) ->
|
||||
put(k, v)
|
||||
|
@ -328,13 +328,13 @@ class LongMap<V> : MutableMap<Long, V> {
|
|||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<Long, V>>
|
||||
get() = entries() as MutableSet<MutableMap.MutableEntry<Long, V>>
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<Long, V?>>
|
||||
get() = entries() as MutableSet<MutableMap.MutableEntry<Long, V?>>
|
||||
override val keys: MutableSet<Long>
|
||||
get() = keys()
|
||||
override val size: Int
|
||||
get() = size_
|
||||
override val values: MutableCollection<V>
|
||||
override val values: MutableCollection<V?>
|
||||
get() = values()
|
||||
|
||||
override fun clear() {
|
||||
|
@ -346,7 +346,7 @@ class LongMap<V> : MutableMap<Long, V> {
|
|||
hasZeroValue = false
|
||||
}
|
||||
|
||||
override fun containsValue(value: V): Boolean {
|
||||
override fun containsValue(value: V?): Boolean {
|
||||
return containsValue(value, false)
|
||||
}
|
||||
|
||||
|
@ -488,7 +488,7 @@ class LongMap<V> : MutableMap<Long, V> {
|
|||
if (key != 0L) {
|
||||
val value: V? = valueTable[i]
|
||||
if (value == null) {
|
||||
if (other.get(key, ObjectMap.dummy as V?) != null) return false
|
||||
if (other.get(key, ObjectMap.dummy as V) != null) return false
|
||||
}
|
||||
else {
|
||||
if (value != other[key]) return false
|
||||
|
@ -517,7 +517,7 @@ class LongMap<V> : MutableMap<Long, V> {
|
|||
val n = keyTable.size
|
||||
while (i < n) {
|
||||
val key = keyTable[i]
|
||||
if (key != 0L && valueTable[i] !== other.get(key, ObjectMap.dummy as V?)) return false
|
||||
if (key != 0L && valueTable[i] !== other.get(key, ObjectMap.dummy as V)) return false
|
||||
i++
|
||||
}
|
||||
return true
|
||||
|
@ -588,22 +588,23 @@ class LongMap<V> : MutableMap<Long, V> {
|
|||
* If [Collections.allocateIterators] is false, the same iterator instance is returned each time this method is called.
|
||||
* Use the [Entries] constructor for nested or multithreaded iteration.
|
||||
*/
|
||||
fun values(): Values<V> {
|
||||
if (allocateIterators) return Values(this)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun values(): Values<V?> {
|
||||
if (allocateIterators) return Values(this as LongMap<V?>)
|
||||
if (values1 == null) {
|
||||
values1 = Values(this)
|
||||
values2 = Values(this)
|
||||
values1 = Values(this as LongMap<V?>)
|
||||
values2 = Values(this as LongMap<V?>)
|
||||
}
|
||||
if (!values1!!.valid) {
|
||||
values1!!.reset()
|
||||
values1!!.valid = true
|
||||
values2!!.valid = false
|
||||
return values1 as Values<V>
|
||||
return values1 as Values<V?>
|
||||
}
|
||||
values2!!.reset()
|
||||
values2!!.valid = true
|
||||
values1!!.valid = false
|
||||
return values2 as Values<V>
|
||||
return values2 as Values<V?>
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -255,7 +255,7 @@ open class ObjectIntMap<K: Any> : MutableMap<K, Int> {
|
|||
/**
|
||||
* Returns the value for the specified key, or the default value if the key is not in the map.
|
||||
*/
|
||||
operator fun get(key: K, defaultValue: Int?): Int? {
|
||||
open operator fun get(key: K, defaultValue: Int): Int {
|
||||
val i = locateKey(key)
|
||||
return if (i < 0) {
|
||||
defaultValue
|
||||
|
|
|
@ -59,7 +59,7 @@ import java.util.*
|
|||
* @author Nathan Sweet
|
||||
* @author Tommy Ettinger
|
||||
*/
|
||||
open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
||||
open class ObjectMap<K: Any, V> : MutableMap<K, V?> {
|
||||
|
||||
companion object {
|
||||
const val version = Collections.version
|
||||
|
@ -189,7 +189,7 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
|||
/**
|
||||
* Returns the old value associated with the specified key, or null.
|
||||
*/
|
||||
override fun put(key: K, value: V): V? {
|
||||
override fun put(key: K, value: V?): V? {
|
||||
var i = locateKey(key)
|
||||
if (i >= 0) { // Existing key was found.
|
||||
val oldValue = valueTable[i]
|
||||
|
@ -203,7 +203,7 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
|||
return null
|
||||
}
|
||||
|
||||
open fun putAll(from: ObjectMap<out K, out V>) {
|
||||
open fun putAll(from: ObjectMap<out K, out V?>) {
|
||||
ensureCapacity(from.mapSize)
|
||||
|
||||
val keyTable = from.keyTable
|
||||
|
@ -214,13 +214,13 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
|||
while (i < n) {
|
||||
key = keyTable[i]
|
||||
if (key != null) {
|
||||
put(key, valueTable[i]!!)
|
||||
put(key, valueTable[i])
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
override fun putAll(from: Map<out K, V>) {
|
||||
override fun putAll(from: Map<out K, V?>) {
|
||||
ensureCapacity(from.size)
|
||||
|
||||
from.forEach { (k, v) ->
|
||||
|
@ -255,7 +255,7 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
|||
/**
|
||||
* Returns the value for the specified key, or the default value if the key is not in the map.
|
||||
*/
|
||||
operator fun get(key: K, defaultValue: V?): V? {
|
||||
operator fun get(key: K, defaultValue: V): V? {
|
||||
val i = locateKey(key)
|
||||
return if (i < 0) {
|
||||
defaultValue
|
||||
|
@ -338,7 +338,7 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
|||
Arrays.fill(valueTable, null)
|
||||
}
|
||||
|
||||
override fun containsValue(value: V): Boolean {
|
||||
override fun containsValue(value: V?): Boolean {
|
||||
return containsValue(value, false)
|
||||
}
|
||||
|
||||
|
@ -452,7 +452,7 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
|||
if (key != null) {
|
||||
val value = valueTable[i]
|
||||
if (value == null) {
|
||||
if (other.get(key, dummy as V?) != null) return false
|
||||
if (other.get(key, dummy as V) != null) return false
|
||||
}
|
||||
else {
|
||||
if (value != other.get(key)) return false
|
||||
|
@ -478,7 +478,7 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
|||
val n = keyTable.size
|
||||
while (i < n) {
|
||||
val key: K? = keyTable[i]
|
||||
if (key != null && valueTable[i] !== other.get(key, dummy as V?)) return false
|
||||
if (key != null && valueTable[i] !== other.get(key, dummy as V)) return false
|
||||
i++
|
||||
}
|
||||
return true
|
||||
|
@ -523,8 +523,8 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
|||
return buffer.toString()
|
||||
}
|
||||
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
|
||||
get() = entries() as MutableSet<MutableMap.MutableEntry<K, V>>
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V?>>
|
||||
get() = entries() as MutableSet<MutableMap.MutableEntry<K, V?>>
|
||||
|
||||
|
||||
/**
|
||||
|
@ -553,7 +553,7 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
|||
return entries2 as Entries<K, V?>
|
||||
}
|
||||
|
||||
override val values: MutableCollection<V>
|
||||
override val values: MutableCollection<V?>
|
||||
get() = values()
|
||||
|
||||
/**
|
||||
|
@ -563,7 +563,7 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
|||
*
|
||||
* Use the [Values] constructor for nested or multithreaded iteration.
|
||||
*/
|
||||
open fun values(): Values<V> {
|
||||
open fun values(): Values<V?> {
|
||||
if (allocateIterators) return Values(this as ObjectMap<K, V?>)
|
||||
if (values1 == null) {
|
||||
values1 = Values(this as ObjectMap<K, V?>)
|
||||
|
@ -573,12 +573,12 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
|||
values1!!.reset()
|
||||
values1!!.valid = true
|
||||
values2!!.valid = false
|
||||
return values1 as Values<V>
|
||||
return values1 as Values<V?>
|
||||
}
|
||||
values2!!.reset()
|
||||
values2!!.valid = true
|
||||
values1!!.valid = false
|
||||
return values2 as Values<V>
|
||||
return values2 as Values<V?>
|
||||
}
|
||||
|
||||
override val keys: MutableSet<K>
|
||||
|
@ -601,17 +601,18 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
|||
keys1!!.reset()
|
||||
keys1!!.valid = true
|
||||
keys2!!.valid = false
|
||||
return keys1 as Keys<K>
|
||||
return keys1!!
|
||||
}
|
||||
keys2!!.reset()
|
||||
keys2!!.valid = true
|
||||
keys1!!.valid = false
|
||||
return keys2 as Keys<K>
|
||||
return keys2!!
|
||||
}
|
||||
|
||||
class Entry<K: Any, V>(val map: ObjectMap<K, V?>) : MutableMap.MutableEntry<K, V?> {
|
||||
override lateinit var key: K
|
||||
override var value: V? = null
|
||||
class Entry<K: Any, V>(val map: ObjectMap<K, V?>, index: Int) : MutableMap.MutableEntry<K, V?> {
|
||||
// we know there will be at least one
|
||||
override var key: K = map.keyTable[index]!!
|
||||
override var value: V? = map.valueTable[index]
|
||||
|
||||
override fun setValue(newValue: V?): V? {
|
||||
val oldValue = value
|
||||
|
@ -625,7 +626,7 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
abstract class MapIterator<K: Any, V, I>(val map: ObjectMap<K, V>) : Iterable<I>, MutableIterator<I> {
|
||||
abstract class MapIterator<K: Any, V, I>(val map: ObjectMap<K, V?>) : MutableIterator<I> {
|
||||
var hasNext = false
|
||||
var nextIndex = 0
|
||||
var currentIndex = 0
|
||||
|
@ -683,7 +684,14 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
|||
}
|
||||
|
||||
open class Entries<K: Any, V>(map: ObjectMap<K, V?>) : MutableSet<Entry<K, V?>>, MapIterator<K, V?, Entry<K, V?>>(map) {
|
||||
var entry = Entry<K, V?>(map)
|
||||
internal lateinit var entry: Entry<K, V?>
|
||||
|
||||
init {
|
||||
if (hasNext) {
|
||||
findNextIndex()
|
||||
entry = Entry(map, nextIndex)
|
||||
}
|
||||
}
|
||||
|
||||
/** Note the same entry instance is returned each time this method is called. */
|
||||
override fun next(): Entry<K, V?> {
|
||||
|
@ -776,7 +784,7 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
open class Values<V>(map: ObjectMap<*, V?>) : MutableCollection<V>, MapIterator<Any, V, V>(map as ObjectMap<Any, V>) {
|
||||
open class Values<V>(map: ObjectMap<*, V?>) : MutableCollection<V>, MapIterator<Any, V, V>(map as ObjectMap<Any, V?>) {
|
||||
override fun hasNext(): Boolean {
|
||||
if (!valid) throw RuntimeException("#iterator() cannot be used nested.")
|
||||
return hasNext
|
||||
|
|
|
@ -63,7 +63,7 @@ import dorkbox.collections.Collections.allocateIterators
|
|||
* @author Nathan Sweet
|
||||
* @author Tommy Ettinger
|
||||
*/
|
||||
class OrderedMap<K, V> : ObjectMap<K, V?> where K : Any, K : Comparable<K> {
|
||||
class OrderedMap<K, V> : ObjectMap<K, V> where K : Any, K : Comparable<K> {
|
||||
companion object {
|
||||
const val version = Collections.version
|
||||
}
|
||||
|
@ -132,14 +132,14 @@ class OrderedMap<K, V> : ObjectMap<K, V?> where K : Any, K : Comparable<K> {
|
|||
return null
|
||||
}
|
||||
|
||||
fun putAll(map: OrderedMap<K, out V?>) {
|
||||
fun putAll(map: OrderedMap<K, V>) {
|
||||
ensureCapacity(map.size)
|
||||
val keys = map.keys_
|
||||
var i = 0
|
||||
val n = map.keys_.size
|
||||
while (i < n) {
|
||||
val key = keys[i]
|
||||
put(key, map.get(key))
|
||||
put(key, map.get(key)!!) // we know this is value, because we checked it earlier
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
@ -169,7 +169,10 @@ class OrderedMap<K, V> : ObjectMap<K, V?> where K : Any, K : Comparable<K> {
|
|||
if (containsKey(after)) return false
|
||||
val index = keys_.indexOf(before)
|
||||
if (index == -1) return false
|
||||
super.put(after, super.remove(before))
|
||||
val prev = super.remove(before)
|
||||
if (prev != null) {
|
||||
super.put(after, prev)
|
||||
}
|
||||
keys_[index] = after
|
||||
return true
|
||||
}
|
||||
|
@ -186,7 +189,10 @@ class OrderedMap<K, V> : ObjectMap<K, V?> where K : Any, K : Comparable<K> {
|
|||
*/
|
||||
fun alterIndex(index: Int, after: K): Boolean {
|
||||
if (index < 0 || index >= size || containsKey(after)) return false
|
||||
super.put(after, super.remove(keys_[index]))
|
||||
val prev = super.remove(keys_[index])
|
||||
if (prev != null) {
|
||||
super.put(after, prev)
|
||||
}
|
||||
keys_[index] = after
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -182,7 +182,7 @@ class IntTests {
|
|||
assertTrue(map.size == 3)
|
||||
|
||||
val entries = map.entries()
|
||||
val keepEntry = IntMap.Entry<String?>()
|
||||
val keepEntry = IntMap.Entry<String?>(map)
|
||||
keepEntry.key = 1
|
||||
keepEntry.value = "1"
|
||||
|
||||
|
@ -326,7 +326,7 @@ class IntTests {
|
|||
assertTrue(map.size == 3)
|
||||
|
||||
val entries = map.entries()
|
||||
val keepEntry = IntIntMap.Entry()
|
||||
val keepEntry = IntIntMap.Entry(map)
|
||||
keepEntry.key = 1
|
||||
keepEntry.value = 1
|
||||
|
||||
|
@ -372,7 +372,7 @@ class IntTests {
|
|||
val map = map3()
|
||||
assertTrue(map.size == 3)
|
||||
|
||||
val keys = map.keys()
|
||||
val keys = map.keys
|
||||
assertTrue(keys.size == 3)
|
||||
|
||||
assertTrue(map[2] == "2")
|
||||
|
@ -400,7 +400,7 @@ class IntTests {
|
|||
val map = map3()
|
||||
assertTrue(map.size == 3)
|
||||
|
||||
val values = map.values()
|
||||
val values = map.values
|
||||
assertTrue(values.size == 3)
|
||||
|
||||
values.remove("2")
|
||||
|
@ -427,10 +427,10 @@ class IntTests {
|
|||
val map = map3()
|
||||
assertTrue(map.size == 3)
|
||||
|
||||
val entries = map.entries()
|
||||
val entries = map.entries
|
||||
assertTrue(entries.size == 3)
|
||||
|
||||
var toRemove: IntMap.Entry<String?>? = null
|
||||
var toRemove: MutableMap.MutableEntry<Int, String?>? = null
|
||||
val iter = entries.iterator()
|
||||
while (iter.hasNext()) {
|
||||
val entry = iter.next()
|
||||
|
@ -463,29 +463,6 @@ class IntTests {
|
|||
assertTrue(entries.size == 0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLFIntMapEntries2() {
|
||||
val map = map3()
|
||||
assertTrue(map.size == 3)
|
||||
|
||||
val entries = map.entries()
|
||||
val keepEntry = IntMap.Entry<String?>()
|
||||
keepEntry.key = 1
|
||||
keepEntry.value = "1"
|
||||
|
||||
val keep = listOf(keepEntry)
|
||||
entries.retainAll(keep)
|
||||
assertTrue(map.size == 1)
|
||||
assertTrue(map[1] == "1")
|
||||
|
||||
entries.clear()
|
||||
|
||||
assertTrue(map.isEmpty())
|
||||
assertTrue(entries.isEmpty())
|
||||
assertTrue(map.size == 0)
|
||||
assertTrue(entries.size == 0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIntSet() {
|
||||
val set = set()
|
||||
|
|
|
@ -163,7 +163,8 @@ class ObjectTests {
|
|||
assertTrue(map.size == 3)
|
||||
|
||||
val entries = map.entries()
|
||||
val keepEntry = ObjectMap.Entry<String, Int?>(map)
|
||||
entries.findNextIndex()
|
||||
val keepEntry = ObjectMap.Entry<String, Int?>(map, entries.nextIndex)
|
||||
keepEntry.key = "1"
|
||||
keepEntry.value = 1
|
||||
|
||||
|
|
Loading…
Reference in New Issue