Code polish
This commit is contained in:
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
|
* 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.
|
* 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
|
val keys = keyTable
|
||||||
var i = size_ - 1
|
var i = size_ - 1
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
|
@ -246,6 +246,7 @@ class ArrayMap<K: Any, V> : MutableMap<K, V?>{
|
||||||
i--
|
i--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return defaultValue
|
return defaultValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -626,7 +627,7 @@ class ArrayMap<K: Any, V> : MutableMap<K, V?>{
|
||||||
val key = keys[i] as K
|
val key = keys[i] as K
|
||||||
val value = values[i]
|
val value = values[i]
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
if (other.get(key, dummy as V?) != null) {
|
if (other.get(key, dummy as V) != null) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -656,7 +657,7 @@ class ArrayMap<K: Any, V> : MutableMap<K, V?>{
|
||||||
var i = 0
|
var i = 0
|
||||||
val n = size_
|
val n = size_
|
||||||
while (i < n) {
|
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++
|
i++
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -787,11 +788,17 @@ class ArrayMap<K: Any, V> : MutableMap<K, V?>{
|
||||||
return keys2!!
|
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)
|
private lateinit var entry: Entry<K, V?>
|
||||||
var index = 0
|
internal var index = 0
|
||||||
var valid = true
|
internal var valid = true
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (hasNext()) {
|
||||||
|
entry = Entry(map)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun hasNext(): Boolean {
|
override fun hasNext(): Boolean {
|
||||||
if (!valid) throw RuntimeException("#iterator() cannot be used nested.")
|
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 (index >= map.size_) throw NoSuchElementException(index.toString())
|
||||||
if (!valid) throw RuntimeException("#iterator() cannot be used nested.")
|
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++]
|
entry.value = map.valueTable[index++]
|
||||||
return entry
|
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?> {
|
class Entry<K: Any, V>(val map: ArrayMap<K, V>) : MutableMap.MutableEntry<K, V?> {
|
||||||
override lateinit var key: K
|
// we know there will be at least one
|
||||||
override var value: V? = null
|
override var key: K = map.keyTable[0]!!
|
||||||
|
override var value: V? = map.valueTable[0]
|
||||||
|
|
||||||
override fun setValue(newValue: V?): V? {
|
override fun setValue(newValue: V?): V? {
|
||||||
val oldValue = value
|
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?>
|
private val map: ArrayMap<Any, V?>
|
||||||
var index = 0
|
var index = 0
|
||||||
var valid = true
|
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>
|
private val map: ArrayMap<K, Any>
|
||||||
var index = 0
|
var index = 0
|
||||||
var valid = true
|
var valid = true
|
||||||
|
|
|
@ -238,8 +238,8 @@ open class IntMap<V> : MutableMap<Int, V> {
|
||||||
return if (i >= 0) valueTable[i] else null
|
return if (i >= 0) valueTable[i] else null
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun get(key: Int, defaultValue: V?): V? {
|
operator fun get(key: Int, defaultValue: V): V? {
|
||||||
if (key == 0) return if (hasZeroValue) zeroValue else defaultValue
|
if (key == 0) return if (hasZeroValue) zeroValue!! else defaultValue
|
||||||
val i = locateKey(key)
|
val i = locateKey(key)
|
||||||
return if (i >= 0) valueTable[i] else defaultValue
|
return if (i >= 0) valueTable[i] else defaultValue
|
||||||
}
|
}
|
||||||
|
@ -489,7 +489,7 @@ open class IntMap<V> : MutableMap<Int, V> {
|
||||||
if (key != 0) {
|
if (key != 0) {
|
||||||
val value: V? = valueTable[i]
|
val value: V? = valueTable[i]
|
||||||
if (value == null) {
|
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 {
|
else {
|
||||||
if (value != other[key]) return false
|
if (value != other[key]) return false
|
||||||
|
@ -518,7 +518,7 @@ open class IntMap<V> : MutableMap<Int, V> {
|
||||||
val n = keyTable.size
|
val n = keyTable.size
|
||||||
while (i < n) {
|
while (i < n) {
|
||||||
val key = keyTable[i]
|
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++
|
i++
|
||||||
}
|
}
|
||||||
return true
|
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
|
* @param key key whose mapping is to be removed from the map
|
||||||
*
|
*
|
||||||
* @return the previous value associated with <tt>key</tt>, or
|
* @return the previous value associated with [key]
|
||||||
* <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>.)
|
|
||||||
*/
|
*/
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun remove(key: K): V? {
|
override fun remove(key: K): V {
|
||||||
val value = forwardHashMap.remove(key)
|
val value = forwardHashMap.remove(key)
|
||||||
reverseHashMap.remove(value)
|
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
|
* 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
|
@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
|
// 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)
|
hashMap = HashMap(initialCapacity, loadFactor)
|
||||||
}
|
}
|
||||||
|
|
||||||
val map: MutableMap<K, V>
|
private val map: MutableMap<K, V>
|
||||||
get() {
|
get() {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
return mapREF[this] as MutableMap<K, V>
|
return mapREF[this] as MutableMap<K, V>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override val size: Int
|
override val size: Int
|
||||||
|
@ -114,16 +114,14 @@ class LockFreeHashMap<K: Any, V> : MutableMap<K, V?>, Cloneable, Serializable {
|
||||||
return map.keys
|
return map.keys
|
||||||
}
|
}
|
||||||
|
|
||||||
override val values: MutableCollection<V?>
|
override val values: MutableCollection<V>
|
||||||
get() {
|
get() {
|
||||||
@Suppress("UNCHECKED_CAST")
|
return map.values
|
||||||
return map.values as MutableCollection<V?>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V?>>
|
override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
|
||||||
get() {
|
get() {
|
||||||
@Suppress("UNCHECKED_CAST")
|
return map.entries
|
||||||
return map.entries as MutableSet<MutableMap.MutableEntry<K, V?>>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isEmpty(): Boolean {
|
override fun isEmpty(): Boolean {
|
||||||
|
@ -136,7 +134,7 @@ class LockFreeHashMap<K: Any, V> : MutableMap<K, V?>, Cloneable, Serializable {
|
||||||
return mapREF[this].containsKey(key)
|
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
|
// use the SWP to get a lock-free get of the value
|
||||||
return mapREF[this].containsValue(value)
|
return mapREF[this].containsValue(value)
|
||||||
}
|
}
|
||||||
|
@ -147,7 +145,7 @@ class LockFreeHashMap<K: Any, V> : MutableMap<K, V?>, Cloneable, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun put(key: K, value: V?): V? {
|
override fun put(key: K, value: V): V? {
|
||||||
return hashMap.put(key, value)
|
return hashMap.put(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +166,7 @@ class LockFreeHashMap<K: Any, V> : MutableMap<K, V?>, Cloneable, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun putAll(from: Map<out K, V?>) {
|
override fun putAll(from: Map<out K, V>) {
|
||||||
hashMap.putAll(from)
|
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
|
* @param key key whose mapping is to be removed from the map
|
||||||
*
|
*
|
||||||
* @return the previous value associated with <tt>key</tt>, or
|
* @return the previous value associated with [key]
|
||||||
* <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>.)
|
|
||||||
*/
|
*/
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun remove(key: Int): V? {
|
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
|
* 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.
|
* the capacity. [OrderedMap] provides much faster iteration.
|
||||||
*/
|
*/
|
||||||
class LockFreeIntMap<V> : IntMap<V>, Cloneable, Serializable {
|
class LockFreeIntMap<V> : MutableMap<Int, V>, Cloneable, Serializable {
|
||||||
|
|
||||||
@Volatile
|
@Volatile
|
||||||
private var hashMap: IntMap<V>
|
private var hashMap: IntMap<V>
|
||||||
|
@ -107,7 +107,11 @@ class LockFreeIntMap<V> : IntMap<V>, Cloneable, Serializable {
|
||||||
return value.containsKey(key)
|
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
|
// use the SWP to get a lock-free get of the value
|
||||||
return mapREF[this].containsValue(value, identity)
|
return mapREF[this].containsValue(value, identity)
|
||||||
}
|
}
|
||||||
|
@ -130,7 +134,7 @@ class LockFreeIntMap<V> : IntMap<V>, Cloneable, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun putAll(from: IntMap<out V>) {
|
override fun putAll(from: Map<out Int, V>) {
|
||||||
hashMap.putAll(from)
|
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
|
* 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.
|
* time this method is called. Use the [ObjectMap.Entries] constructor for nested or multithreaded iteration.
|
||||||
*/
|
*/
|
||||||
override fun keys(): Keys {
|
override val keys: IntMap.Keys
|
||||||
return mapREF[this].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!
|
* 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.
|
* time this method is called. Use the [ObjectMap.Entries] constructor for nested or multithreaded iteration.
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun values(): Values<V> {
|
override val values: IntMap.Values<V>
|
||||||
return mapREF[this].values() as 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!
|
* 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.
|
* time this method is called. Use the [ObjectMap.Entries] constructor for nested or multithreaded iteration.
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun entries(): Entries<V?> {
|
override val entries: MutableSet<MutableMap.MutableEntry<Int, V>>
|
||||||
return mapREF[this].entries() as Entries<V?>
|
get() {
|
||||||
}
|
return mapREF[this].entries() as MutableSet<MutableMap.MutableEntry<Int, V>>
|
||||||
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
return mapREF[this] == other
|
return mapREF[this] == other
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun equalsIdentity(other: Any?): Boolean {
|
fun equalsIdentity(other: Any?): Boolean {
|
||||||
return mapREF[this].equalsIdentity(other)
|
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.
|
* is done by allocating new arrays, though for large arrays this can be faster than clearing the existing array.
|
||||||
*/
|
*/
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun clear(maximumCapacity: Int) {
|
fun clear(maximumCapacity: Int) {
|
||||||
mapREF[this].clear(maximumCapacity)
|
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.
|
* If the map contains more items than the specified capacity, the next highest power of two capacity is used instead.
|
||||||
*/
|
*/
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun shrink(maximumCapacity: Int) {
|
fun shrink(maximumCapacity: Int) {
|
||||||
mapREF[this].shrink(maximumCapacity)
|
mapREF[this].shrink(maximumCapacity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,10 +36,10 @@ import java.util.concurrent.atomic.*
|
||||||
*/
|
*/
|
||||||
class LockFreeObjectBiMap<K: Any, V: Any> : MutableMap<K, V>, Cloneable, Serializable {
|
class LockFreeObjectBiMap<K: Any, V: Any> : MutableMap<K, V>, Cloneable, Serializable {
|
||||||
@Volatile
|
@Volatile
|
||||||
private var forwardHashMap: MutableMap<K, V>
|
private var forwardHashMap: ObjectMap<K, V>
|
||||||
|
|
||||||
@Volatile
|
@Volatile
|
||||||
private var reverseHashMap: MutableMap<V, K>
|
private var reverseHashMap: ObjectMap<V, K>
|
||||||
|
|
||||||
private val inverse: LockFreeObjectBiMap<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)
|
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.forwardHashMap = forwardHashMap
|
||||||
this.reverseHashMap = reverseHashMap
|
this.reverseHashMap = reverseHashMap
|
||||||
this.inverse = inverse
|
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
|
// Recommended for best performance while adhering to the "single writer principle". Must be static-final
|
||||||
private val forwardREF = AtomicReferenceFieldUpdater.newUpdater(
|
private val forwardREF = AtomicReferenceFieldUpdater.newUpdater(
|
||||||
LockFreeObjectBiMap::class.java, MutableMap::class.java, "forwardHashMap"
|
LockFreeObjectBiMap::class.java, ObjectMap::class.java, "forwardHashMap"
|
||||||
)
|
)
|
||||||
private val reverseREF = AtomicReferenceFieldUpdater.newUpdater(
|
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
|
* @param key key whose mapping is to be removed from the map
|
||||||
*
|
*
|
||||||
* @return the previous value associated with <tt>key</tt>, or
|
* @return the previous value associated with [key] or [defaultReturnValue] if it doesn't exist
|
||||||
* <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>.)
|
|
||||||
*/
|
*/
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun remove(key: K): Int? {
|
override fun remove(key: K): Int {
|
||||||
val value = forwardHashMap.remove(key)
|
val value = forwardHashMap.remove(key)
|
||||||
reverseHashMap.remove(value)
|
reverseHashMap.remove(value)
|
||||||
return value
|
return value ?: defaultReturnValue
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value to which the specified key is mapped,
|
* 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
|
* 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.)
|
* 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
|
* 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
|
* The [containsKey][HashMap.containsKey] operation may be used to
|
||||||
* distinguish these two cases.
|
* distinguish these two cases.
|
||||||
*
|
*
|
||||||
|
@ -319,8 +317,7 @@ class LockFreeObjectIntBiMap<K: Any> : MutableMap<K, Int>, Cloneable, Serializab
|
||||||
*/
|
*/
|
||||||
override operator fun get(key: K): Int {
|
override operator fun get(key: K): Int {
|
||||||
// use the SWP to get a lock-free get of the value
|
// use the SWP to get a lock-free get of the value
|
||||||
@Suppress("UNCHECKED_CAST")
|
return forwardREF[this][key] ?: defaultReturnValue
|
||||||
return (forwardREF[this] as ObjectIntMap<K>)[key] as Int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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
|
* 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.
|
* 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
|
@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
|
// 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
|
// 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)
|
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
|
// use the SWP to get a lock-free get of the value
|
||||||
return mapREF[this].containsValue(value, identity)
|
return mapREF[this].containsValue(value, identity)
|
||||||
}
|
}
|
||||||
|
@ -120,7 +125,7 @@ class LockFreeObjectMap<K: Any, V> : ObjectMap<K, V?>, Cloneable, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun put(key: K, value: V?): V? {
|
override fun put(key: K, value: V): V? {
|
||||||
return hashMap.put(key, value)
|
return hashMap.put(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +135,7 @@ class LockFreeObjectMap<K: Any, V> : ObjectMap<K, V?>, Cloneable, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun putAll(from: ObjectMap<out K, out V?>) {
|
override fun putAll(from: Map<out K, V>) {
|
||||||
hashMap.putAll(from)
|
hashMap.putAll(from)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,6 +144,8 @@ class LockFreeObjectMap<K: Any, V> : ObjectMap<K, V?>, Cloneable, Serializable {
|
||||||
hashMap.clear()
|
hashMap.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DO NOT MODIFY THE MAP VIA THIS (unless you synchronize around it!) It will result in unknown object visibility!
|
* 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.
|
* time this method is called. Use the [ObjectMap.Entries] constructor for nested or multithreaded iteration.
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun keys(): Keys<K> {
|
override val keys: ObjectMap.Keys<K>
|
||||||
return mapREF[this].keys() as 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!
|
* 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.
|
* time this method is called. Use the [ObjectMap.Entries] constructor for nested or multithreaded iteration.
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun values(): Values<V?> {
|
override val values: ObjectMap.Values<V>
|
||||||
return mapREF[this].values() as 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!
|
* 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.
|
* time this method is called. Use the [ObjectMap.Entries] constructor for nested or multithreaded iteration.
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun entries(): Entries<K, V?> {
|
override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
|
||||||
return mapREF[this].entries() as Entries<K, V?>
|
get() {
|
||||||
}
|
return mapREF[this].entries() as MutableSet<MutableMap.MutableEntry<K, V>>
|
||||||
|
}
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
return mapREF[this] == other
|
return mapREF[this] == other
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun equalsIdentity(other: Any?): Boolean {
|
fun equalsIdentity(other: Any?): Boolean {
|
||||||
return mapREF[this].equalsIdentity(other)
|
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.
|
* is done by allocating new arrays, though for large arrays this can be faster than clearing the existing array.
|
||||||
*/
|
*/
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun clear(maximumCapacity: Int) {
|
fun clear(maximumCapacity: Int) {
|
||||||
mapREF[this].clear(maximumCapacity)
|
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.
|
* If the map contains more items than the specified capacity, the next highest power of two capacity is used instead.
|
||||||
*/
|
*/
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun shrink(maximumCapacity: Int) {
|
fun shrink(maximumCapacity: Int) {
|
||||||
mapREF[this].shrink(maximumCapacity)
|
mapREF[this].shrink(maximumCapacity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ import java.util.*
|
||||||
* @author Nathan Sweet
|
* @author Nathan Sweet
|
||||||
* @author Tommy Ettinger
|
* @author Tommy Ettinger
|
||||||
*/
|
*/
|
||||||
class LongMap<V> : MutableMap<Long, V> {
|
class LongMap<V> : MutableMap<Long, V?> {
|
||||||
companion object {
|
companion object {
|
||||||
const val version = Collections.version
|
const val version = Collections.version
|
||||||
}
|
}
|
||||||
|
@ -87,16 +87,16 @@ class LongMap<V> : MutableMap<Long, V> {
|
||||||
protected var mask: Int
|
protected var mask: Int
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
private var entries1: Entries<V>? = null
|
private var entries1: Entries<V?>? = null
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
private var entries2: Entries<V>? = null
|
private var entries2: Entries<V?>? = null
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
private var values1: Values<V>? = null
|
private var values1: Values<V?>? = null
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
private var values2: Values<V>? = null
|
private var values2: Values<V?>? = null
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
private var keys1: Keys? = null
|
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) {
|
if (key == 0L) {
|
||||||
val oldValue = zeroValue
|
val oldValue = zeroValue
|
||||||
zeroValue = value
|
zeroValue = value
|
||||||
|
@ -198,7 +198,7 @@ class LongMap<V> : MutableMap<Long, V> {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun putAll(map: LongMap<out V>) {
|
fun putAll(map: LongMap<out V?>) {
|
||||||
ensureCapacity(map.size_)
|
ensureCapacity(map.size_)
|
||||||
if (map.hasZeroValue) {
|
if (map.hasZeroValue) {
|
||||||
put(0, map.zeroValue!!)
|
put(0, map.zeroValue!!)
|
||||||
|
@ -237,8 +237,8 @@ class LongMap<V> : MutableMap<Long, V> {
|
||||||
return if (i >= 0) valueTable[i] else null
|
return if (i >= 0) valueTable[i] else null
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun get(key: Long, defaultValue: V?): V? {
|
operator fun get(key: Long, defaultValue: V): V? {
|
||||||
if (key == 0L) return if (hasZeroValue) zeroValue else defaultValue
|
if (key == 0L) return if (hasZeroValue) zeroValue!! else defaultValue
|
||||||
val i = locateKey(key)
|
val i = locateKey(key)
|
||||||
return if (i >= 0) valueTable[i] else defaultValue
|
return if (i >= 0) valueTable[i] else defaultValue
|
||||||
}
|
}
|
||||||
|
@ -294,7 +294,7 @@ class LongMap<V> : MutableMap<Long, V> {
|
||||||
return size_ == 0
|
return size_ == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun putAll(from: Map<out Long, V>) {
|
override fun putAll(from: Map<out Long, V?>) {
|
||||||
ensureCapacity(from.size)
|
ensureCapacity(from.size)
|
||||||
from.entries.forEach { (k,v) ->
|
from.entries.forEach { (k,v) ->
|
||||||
put(k, v)
|
put(k, v)
|
||||||
|
@ -328,13 +328,13 @@ class LongMap<V> : MutableMap<Long, V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override val entries: MutableSet<MutableMap.MutableEntry<Long, V>>
|
override val entries: MutableSet<MutableMap.MutableEntry<Long, V?>>
|
||||||
get() = entries() as MutableSet<MutableMap.MutableEntry<Long, V>>
|
get() = entries() as MutableSet<MutableMap.MutableEntry<Long, V?>>
|
||||||
override val keys: MutableSet<Long>
|
override val keys: MutableSet<Long>
|
||||||
get() = keys()
|
get() = keys()
|
||||||
override val size: Int
|
override val size: Int
|
||||||
get() = size_
|
get() = size_
|
||||||
override val values: MutableCollection<V>
|
override val values: MutableCollection<V?>
|
||||||
get() = values()
|
get() = values()
|
||||||
|
|
||||||
override fun clear() {
|
override fun clear() {
|
||||||
|
@ -346,7 +346,7 @@ class LongMap<V> : MutableMap<Long, V> {
|
||||||
hasZeroValue = false
|
hasZeroValue = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun containsValue(value: V): Boolean {
|
override fun containsValue(value: V?): Boolean {
|
||||||
return containsValue(value, false)
|
return containsValue(value, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -488,7 +488,7 @@ class LongMap<V> : MutableMap<Long, V> {
|
||||||
if (key != 0L) {
|
if (key != 0L) {
|
||||||
val value: V? = valueTable[i]
|
val value: V? = valueTable[i]
|
||||||
if (value == null) {
|
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 {
|
else {
|
||||||
if (value != other[key]) return false
|
if (value != other[key]) return false
|
||||||
|
@ -517,7 +517,7 @@ class LongMap<V> : MutableMap<Long, V> {
|
||||||
val n = keyTable.size
|
val n = keyTable.size
|
||||||
while (i < n) {
|
while (i < n) {
|
||||||
val key = keyTable[i]
|
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++
|
i++
|
||||||
}
|
}
|
||||||
return true
|
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.
|
* 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.
|
* Use the [Entries] constructor for nested or multithreaded iteration.
|
||||||
*/
|
*/
|
||||||
fun values(): Values<V> {
|
@Suppress("UNCHECKED_CAST")
|
||||||
if (allocateIterators) return Values(this)
|
fun values(): Values<V?> {
|
||||||
|
if (allocateIterators) return Values(this as LongMap<V?>)
|
||||||
if (values1 == null) {
|
if (values1 == null) {
|
||||||
values1 = Values(this)
|
values1 = Values(this as LongMap<V?>)
|
||||||
values2 = Values(this)
|
values2 = Values(this as LongMap<V?>)
|
||||||
}
|
}
|
||||||
if (!values1!!.valid) {
|
if (!values1!!.valid) {
|
||||||
values1!!.reset()
|
values1!!.reset()
|
||||||
values1!!.valid = true
|
values1!!.valid = true
|
||||||
values2!!.valid = false
|
values2!!.valid = false
|
||||||
return values1 as Values<V>
|
return values1 as Values<V?>
|
||||||
}
|
}
|
||||||
values2!!.reset()
|
values2!!.reset()
|
||||||
values2!!.valid = true
|
values2!!.valid = true
|
||||||
values1!!.valid = false
|
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.
|
* 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)
|
val i = locateKey(key)
|
||||||
return if (i < 0) {
|
return if (i < 0) {
|
||||||
defaultValue
|
defaultValue
|
||||||
|
|
|
@ -59,7 +59,7 @@ import java.util.*
|
||||||
* @author Nathan Sweet
|
* @author Nathan Sweet
|
||||||
* @author Tommy Ettinger
|
* @author Tommy Ettinger
|
||||||
*/
|
*/
|
||||||
open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
open class ObjectMap<K: Any, V> : MutableMap<K, V?> {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val version = Collections.version
|
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.
|
* 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)
|
var i = locateKey(key)
|
||||||
if (i >= 0) { // Existing key was found.
|
if (i >= 0) { // Existing key was found.
|
||||||
val oldValue = valueTable[i]
|
val oldValue = valueTable[i]
|
||||||
|
@ -203,7 +203,7 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun putAll(from: ObjectMap<out K, out V>) {
|
open fun putAll(from: ObjectMap<out K, out V?>) {
|
||||||
ensureCapacity(from.mapSize)
|
ensureCapacity(from.mapSize)
|
||||||
|
|
||||||
val keyTable = from.keyTable
|
val keyTable = from.keyTable
|
||||||
|
@ -214,13 +214,13 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
||||||
while (i < n) {
|
while (i < n) {
|
||||||
key = keyTable[i]
|
key = keyTable[i]
|
||||||
if (key != null) {
|
if (key != null) {
|
||||||
put(key, valueTable[i]!!)
|
put(key, valueTable[i])
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun putAll(from: Map<out K, V>) {
|
override fun putAll(from: Map<out K, V?>) {
|
||||||
ensureCapacity(from.size)
|
ensureCapacity(from.size)
|
||||||
|
|
||||||
from.forEach { (k, v) ->
|
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.
|
* 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)
|
val i = locateKey(key)
|
||||||
return if (i < 0) {
|
return if (i < 0) {
|
||||||
defaultValue
|
defaultValue
|
||||||
|
@ -338,7 +338,7 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
||||||
Arrays.fill(valueTable, null)
|
Arrays.fill(valueTable, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun containsValue(value: V): Boolean {
|
override fun containsValue(value: V?): Boolean {
|
||||||
return containsValue(value, false)
|
return containsValue(value, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,7 +452,7 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
||||||
if (key != null) {
|
if (key != null) {
|
||||||
val value = valueTable[i]
|
val value = valueTable[i]
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
if (other.get(key, dummy as V?) != null) return false
|
if (other.get(key, dummy as V) != null) return false
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (value != other.get(key)) return false
|
if (value != other.get(key)) return false
|
||||||
|
@ -478,7 +478,7 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
||||||
val n = keyTable.size
|
val n = keyTable.size
|
||||||
while (i < n) {
|
while (i < n) {
|
||||||
val key: K? = keyTable[i]
|
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++
|
i++
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -523,8 +523,8 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
||||||
return buffer.toString()
|
return buffer.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
|
override val entries: MutableSet<MutableMap.MutableEntry<K, V?>>
|
||||||
get() = entries() as 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?>
|
return entries2 as Entries<K, V?>
|
||||||
}
|
}
|
||||||
|
|
||||||
override val values: MutableCollection<V>
|
override val values: MutableCollection<V?>
|
||||||
get() = values()
|
get() = values()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -563,7 +563,7 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
||||||
*
|
*
|
||||||
* Use the [Values] constructor for nested or multithreaded iteration.
|
* 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 (allocateIterators) return Values(this as ObjectMap<K, V?>)
|
||||||
if (values1 == null) {
|
if (values1 == null) {
|
||||||
values1 = Values(this as ObjectMap<K, V?>)
|
values1 = Values(this as ObjectMap<K, V?>)
|
||||||
|
@ -573,12 +573,12 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
||||||
values1!!.reset()
|
values1!!.reset()
|
||||||
values1!!.valid = true
|
values1!!.valid = true
|
||||||
values2!!.valid = false
|
values2!!.valid = false
|
||||||
return values1 as Values<V>
|
return values1 as Values<V?>
|
||||||
}
|
}
|
||||||
values2!!.reset()
|
values2!!.reset()
|
||||||
values2!!.valid = true
|
values2!!.valid = true
|
||||||
values1!!.valid = false
|
values1!!.valid = false
|
||||||
return values2 as Values<V>
|
return values2 as Values<V?>
|
||||||
}
|
}
|
||||||
|
|
||||||
override val keys: MutableSet<K>
|
override val keys: MutableSet<K>
|
||||||
|
@ -601,17 +601,18 @@ open class ObjectMap<K: Any, V> : MutableMap<K, V> {
|
||||||
keys1!!.reset()
|
keys1!!.reset()
|
||||||
keys1!!.valid = true
|
keys1!!.valid = true
|
||||||
keys2!!.valid = false
|
keys2!!.valid = false
|
||||||
return keys1 as Keys<K>
|
return keys1!!
|
||||||
}
|
}
|
||||||
keys2!!.reset()
|
keys2!!.reset()
|
||||||
keys2!!.valid = true
|
keys2!!.valid = true
|
||||||
keys1!!.valid = false
|
keys1!!.valid = false
|
||||||
return keys2 as Keys<K>
|
return keys2!!
|
||||||
}
|
}
|
||||||
|
|
||||||
class Entry<K: Any, V>(val map: ObjectMap<K, V?>) : MutableMap.MutableEntry<K, V?> {
|
class Entry<K: Any, V>(val map: ObjectMap<K, V?>, index: Int) : MutableMap.MutableEntry<K, V?> {
|
||||||
override lateinit var key: K
|
// we know there will be at least one
|
||||||
override var value: V? = null
|
override var key: K = map.keyTable[index]!!
|
||||||
|
override var value: V? = map.valueTable[index]
|
||||||
|
|
||||||
override fun setValue(newValue: V?): V? {
|
override fun setValue(newValue: V?): V? {
|
||||||
val oldValue = value
|
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 hasNext = false
|
||||||
var nextIndex = 0
|
var nextIndex = 0
|
||||||
var currentIndex = 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) {
|
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. */
|
/** Note the same entry instance is returned each time this method is called. */
|
||||||
override fun next(): Entry<K, V?> {
|
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 {
|
override fun hasNext(): Boolean {
|
||||||
if (!valid) throw RuntimeException("#iterator() cannot be used nested.")
|
if (!valid) throw RuntimeException("#iterator() cannot be used nested.")
|
||||||
return hasNext
|
return hasNext
|
||||||
|
|
|
@ -63,7 +63,7 @@ import dorkbox.collections.Collections.allocateIterators
|
||||||
* @author Nathan Sweet
|
* @author Nathan Sweet
|
||||||
* @author Tommy Ettinger
|
* @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 {
|
companion object {
|
||||||
const val version = Collections.version
|
const val version = Collections.version
|
||||||
}
|
}
|
||||||
|
@ -132,14 +132,14 @@ class OrderedMap<K, V> : ObjectMap<K, V?> where K : Any, K : Comparable<K> {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun putAll(map: OrderedMap<K, out V?>) {
|
fun putAll(map: OrderedMap<K, V>) {
|
||||||
ensureCapacity(map.size)
|
ensureCapacity(map.size)
|
||||||
val keys = map.keys_
|
val keys = map.keys_
|
||||||
var i = 0
|
var i = 0
|
||||||
val n = map.keys_.size
|
val n = map.keys_.size
|
||||||
while (i < n) {
|
while (i < n) {
|
||||||
val key = keys[i]
|
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++
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,7 +169,10 @@ class OrderedMap<K, V> : ObjectMap<K, V?> where K : Any, K : Comparable<K> {
|
||||||
if (containsKey(after)) return false
|
if (containsKey(after)) return false
|
||||||
val index = keys_.indexOf(before)
|
val index = keys_.indexOf(before)
|
||||||
if (index == -1) return false
|
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
|
keys_[index] = after
|
||||||
return true
|
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 {
|
fun alterIndex(index: Int, after: K): Boolean {
|
||||||
if (index < 0 || index >= size || containsKey(after)) return false
|
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
|
keys_[index] = after
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,7 +182,7 @@ class IntTests {
|
||||||
assertTrue(map.size == 3)
|
assertTrue(map.size == 3)
|
||||||
|
|
||||||
val entries = map.entries()
|
val entries = map.entries()
|
||||||
val keepEntry = IntMap.Entry<String?>()
|
val keepEntry = IntMap.Entry<String?>(map)
|
||||||
keepEntry.key = 1
|
keepEntry.key = 1
|
||||||
keepEntry.value = "1"
|
keepEntry.value = "1"
|
||||||
|
|
||||||
|
@ -326,7 +326,7 @@ class IntTests {
|
||||||
assertTrue(map.size == 3)
|
assertTrue(map.size == 3)
|
||||||
|
|
||||||
val entries = map.entries()
|
val entries = map.entries()
|
||||||
val keepEntry = IntIntMap.Entry()
|
val keepEntry = IntIntMap.Entry(map)
|
||||||
keepEntry.key = 1
|
keepEntry.key = 1
|
||||||
keepEntry.value = 1
|
keepEntry.value = 1
|
||||||
|
|
||||||
|
@ -372,7 +372,7 @@ class IntTests {
|
||||||
val map = map3()
|
val map = map3()
|
||||||
assertTrue(map.size == 3)
|
assertTrue(map.size == 3)
|
||||||
|
|
||||||
val keys = map.keys()
|
val keys = map.keys
|
||||||
assertTrue(keys.size == 3)
|
assertTrue(keys.size == 3)
|
||||||
|
|
||||||
assertTrue(map[2] == "2")
|
assertTrue(map[2] == "2")
|
||||||
|
@ -400,7 +400,7 @@ class IntTests {
|
||||||
val map = map3()
|
val map = map3()
|
||||||
assertTrue(map.size == 3)
|
assertTrue(map.size == 3)
|
||||||
|
|
||||||
val values = map.values()
|
val values = map.values
|
||||||
assertTrue(values.size == 3)
|
assertTrue(values.size == 3)
|
||||||
|
|
||||||
values.remove("2")
|
values.remove("2")
|
||||||
|
@ -427,10 +427,10 @@ class IntTests {
|
||||||
val map = map3()
|
val map = map3()
|
||||||
assertTrue(map.size == 3)
|
assertTrue(map.size == 3)
|
||||||
|
|
||||||
val entries = map.entries()
|
val entries = map.entries
|
||||||
assertTrue(entries.size == 3)
|
assertTrue(entries.size == 3)
|
||||||
|
|
||||||
var toRemove: IntMap.Entry<String?>? = null
|
var toRemove: MutableMap.MutableEntry<Int, String?>? = null
|
||||||
val iter = entries.iterator()
|
val iter = entries.iterator()
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
val entry = iter.next()
|
val entry = iter.next()
|
||||||
|
@ -463,29 +463,6 @@ class IntTests {
|
||||||
assertTrue(entries.size == 0)
|
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
|
@Test
|
||||||
fun testIntSet() {
|
fun testIntSet() {
|
||||||
val set = set()
|
val set = set()
|
||||||
|
|
|
@ -163,7 +163,8 @@ class ObjectTests {
|
||||||
assertTrue(map.size == 3)
|
assertTrue(map.size == 3)
|
||||||
|
|
||||||
val entries = map.entries()
|
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.key = "1"
|
||||||
keepEntry.value = 1
|
keepEntry.value = 1
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue