117 lines
4.5 KiB
Kotlin
117 lines
4.5 KiB
Kotlin
/*
|
|
* 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.
|
|
*/
|
|
/*******************************************************************************
|
|
* Copyright 2011 LibGDX.
|
|
* Mario Zechner <badlogicgames></badlogicgames>@gmail.com>
|
|
* Nathan Sweet <nathan.sweet></nathan.sweet>@gmail.com>
|
|
*
|
|
* 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
|
|
|
|
/**
|
|
* An unordered map that uses identity comparison for the object keys. Null keys are not allowed. No allocation is done except
|
|
* when growing the table size.
|
|
*
|
|
*
|
|
* This class performs fast contains and remove (typically O(1), worst case O(n) but that is rare in practice). Add may be
|
|
* slightly slower, depending on hash collisions. Hashcodes are rehashed to reduce collisions and the need to resize. Load factors
|
|
* greater than 0.91 greatly increase the chances to resize to the next higher POT size.
|
|
*
|
|
*
|
|
* Unordered sets and maps are not designed to provide especially fast iteration. Iteration is faster with OrderedSet and
|
|
* OrderedMap.
|
|
*
|
|
*
|
|
* This implementation uses linear probing with the backward shift algorithm for removal. Hashcodes are rehashed using Fibonacci
|
|
* hashing, instead of the more common power-of-two mask, to better distribute poor hashCodes (see [Malte Skarupke's blog post](https://probablydance.com/2018/06/16/fibonacci-hashing-the-optimization-that-the-world-forgot-or-a-better-alternative-to-integer-modulo/)).
|
|
*
|
|
* Linear probing continues to work even when all hashCodes collide, just more slowly.
|
|
* @author Tommy Ettinger
|
|
* @author Nathan Sweet
|
|
*/
|
|
class IdentityMap<K: Any, V> : ObjectMap<K, V> {
|
|
companion object {
|
|
const val version = Collections.version
|
|
}
|
|
|
|
/** Creates a new map with an initial capacity of 51 and a load factor of 0.8. */
|
|
constructor() : super()
|
|
|
|
/**
|
|
* Creates a new map with a load factor of 0.8.
|
|
*
|
|
* @param initialCapacity The backing array size is initialCapacity / loadFactor, increased to the next power of two.
|
|
*/
|
|
constructor(initialCapacity: Int) : super(initialCapacity)
|
|
|
|
/**
|
|
* Creates a new map with the specified initial capacity and load factor. This map will hold initialCapacity items before
|
|
* growing the backing table.
|
|
*
|
|
* @param initialCapacity The backing array size is initialCapacity / loadFactor, increased to the next power of two.
|
|
*/
|
|
constructor(initialCapacity: Int, loadFactor: Float) : super(initialCapacity, loadFactor)
|
|
|
|
/** Creates a new map identical to the specified map. */
|
|
constructor(map: IdentityMap<K, V>) : super(map)
|
|
|
|
override fun place(item: Any): Int {
|
|
return (System.identityHashCode(item) * -0x61c8864680b583ebL ushr shift).toInt()
|
|
}
|
|
|
|
override fun locateKey(key: Any): Int {
|
|
val keyTable = keyTable
|
|
var i = place(key)
|
|
|
|
while (true) {
|
|
val other = keyTable[i] ?: return -(i + 1)
|
|
// Empty space is available.
|
|
if (other === key) return i // Same key was found.
|
|
i = (i + 1) and mask
|
|
}
|
|
}
|
|
|
|
override fun hashCode(): Int {
|
|
var h = size
|
|
val keyTable = keyTable
|
|
val valueTable = valueTable
|
|
var i = 0
|
|
val n = keyTable.size
|
|
|
|
while (i < n) {
|
|
val key = keyTable[i]
|
|
if (key != null) {
|
|
h += System.identityHashCode(key)
|
|
val value = valueTable[i]
|
|
if (value != null) h += value.hashCode()
|
|
}
|
|
i++
|
|
}
|
|
return h
|
|
}
|
|
}
|