godot.core.bridge.Dictionary.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of godot-library-release Show documentation
Show all versions of godot-library-release Show documentation
Contains godot api as kotlin classes and jvm cpp interaction code.
The newest version!
@file:Suppress("unused", "PackageDirectoryMismatch")
package godot.core
import godot.annotation.CoreTypeHelper
import godot.core.memory.MemoryManager
import godot.core.memory.TransferContext
import godot.util.MapIterator
import godot.util.VoidPtr
import godot.util.isNullable
import kotlincompile.definitions.GodotJvmBuildConfig
import kotlin.jvm.internal.Reflection
import kotlin.reflect.KClass
class Dictionary : NativeCoreType, MutableMap {
internal var keyVariantConverter: VariantConverter = VariantParser.NIL
internal var valueVariantConverter: VariantConverter = VariantParser.NIL
@PublishedApi
internal constructor(handle: VoidPtr) {
keyVariantConverter = VariantCaster.ANY
valueVariantConverter = VariantCaster.ANY
_handle = handle
MemoryManager.registerNativeCoreType(this, VariantParser.DICTIONARY)
}
constructor(keyClass: Class<*>, valueClass: Class<*>) : this(Reflection.getOrCreateKotlinClass(keyClass), Reflection.getOrCreateKotlinClass(valueClass))
@PublishedApi
internal constructor(keyClass: KClass<*>, valueClass: KClass<*>) {
val keyVariantConverter = variantMapper[keyClass]
val valueVariantConverter = variantMapper[valueClass]
if (GodotJvmBuildConfig.DEBUG) {
checkNotNull(keyVariantConverter) {
"Can't create a Dictionary with generic key ${keyClass}."
}
checkNotNull(valueVariantConverter) {
"Can't create a Dictionary with generic key ${valueClass}."
}
}
this.keyVariantConverter = keyVariantConverter!!
this.valueVariantConverter = valueVariantConverter!!
_handle = Bridge.engine_call_constructor()
MemoryManager.registerNativeCoreType(this, VariantParser.DICTIONARY)
}
//########################PUBLIC###############################
//PROPERTIES
override val size: Int
get() {
Bridge.engine_call_size(_handle)
return TransferContext.readReturnValue(VariantCaster.INT) as Int
}
override val keys: MutableSet
get() = object : AbstractMutableSet() {
override fun add(element: K): Boolean = throw UnsupportedOperationException("Add is not supported on keys")
override fun clear() {
[email protected]()
}
override operator fun contains(element: K): Boolean = containsKey(element)
override operator fun iterator(): MutableIterator {
val entryIterator = keys().iterator()
return object : MutableIterator {
override fun hasNext(): Boolean = entryIterator.hasNext()
override fun next(): K = entryIterator.next()
override fun remove() = throw UnsupportedOperationException("Remove is not supported on keys")
}
}
override fun remove(element: K): Boolean {
if (containsKey(element)) {
[email protected](element)
return true
}
return false
}
override val size: Int get() = [email protected]
}
override val values: MutableCollection
get() = object : AbstractMutableCollection() {
override fun add(element: V): Boolean =
throw UnsupportedOperationException("Add is not supported on values")
override fun clear() = [email protected]()
override operator fun contains(element: V): Boolean = containsValue(element)
override operator fun iterator(): MutableIterator {
val entryIterator = values().iterator()
return object : MutableIterator {
override fun hasNext(): Boolean = entryIterator.hasNext()
override fun next(): V = entryIterator.next()
override fun remove() = throw UnsupportedOperationException("Remove is not supported on values")
}
}
override val size: Int get() = [email protected]
}
override val entries: MutableSet>
get() = object : AbstractMutableSet>() {
override fun add(element: MutableMap.MutableEntry): Boolean {
val ret = has(element.key)
this@Dictionary[element.key] = element.value
return ret
}
override fun clear() {
[email protected]()
}
override operator fun contains(element: MutableMap.MutableEntry): Boolean {
val value = get(element.key, null)
if (value == element.value) {
return true
}
return false
}
override operator fun iterator(): MapIterator {
return MapIterator(
[email protected](),
this@Dictionary::get,
this@Dictionary::set,
this@Dictionary::erase
)
}
override fun remove(element: MutableMap.MutableEntry): Boolean {
val value = get(element.key, null)
if (value == element.value) {
[email protected](element.key)
return true
}
return false
}
override val size: Int get() = [email protected]
}
//CONSTRUCTOR
/**
* Create a shallow copy of the Dictionary
*/
constructor(other: Dictionary) {
keyVariantConverter = other.keyVariantConverter
valueVariantConverter = other.valueVariantConverter
_handle = other._handle
MemoryManager.registerNativeCoreType(this, VariantParser.DICTIONARY)
}
//API
/**
* Clear the dictionary, removing all key/value pairs.
*/
override fun clear() {
Bridge.engine_call_clear(_handle)
}
override fun containsKey(key: K) = contains(key)
override fun containsValue(value: V): Boolean {
values.forEach {
if (it == value)
return true
}
return false
}
/**
* Creates a copy of the dictionary, and returns it.
* The deep parameter causes inner dictionaries and arrays to be copied recursively, but does not apply to objects.
*/
fun duplicate(deep: Boolean): Dictionary {
TransferContext.writeArguments(VariantParser.BOOL to deep)
Bridge.engine_call_duplicate(_handle)
@Suppress("UNCHECKED_CAST")
return (TransferContext.readReturnValue(VariantParser.DICTIONARY) as Dictionary).also {
it.keyVariantConverter = keyVariantConverter
it.valueVariantConverter = valueVariantConverter
}
}
/**
* Erase a dictionary key/value pair by key. Doesn't return a Boolean like the GDScript version because the GDNative function doesn't return anything
*/
fun erase(key: K) {
TransferContext.writeArguments(keyVariantConverter to key)
Bridge.engine_call_erase(_handle)
}
fun findKey(value: V): K {
TransferContext.writeArguments(valueVariantConverter to value)
Bridge.engine_call_find_key(_handle)
@Suppress("UNCHECKED_CAST")
return TransferContext.readReturnValue(keyVariantConverter) as K
}
/**
* Returns the current value for the specified key in the Dictionary.
* If the key does not exist, the method returns the value of the optional default argument, or null if it is omitted.
*/
fun get(key: K, default: V?): V? {
TransferContext.writeArguments(keyVariantConverter to key, valueVariantConverter to default)
Bridge.engine_call_get(_handle)
@Suppress("UNCHECKED_CAST")
return TransferContext.readReturnValue(valueVariantConverter) as V?
}
/**
* Returns true if the dictionary has a given key.
* Note: This is equivalent to using the in operator as follows:
*/
fun has(key: K): Boolean {
TransferContext.writeArguments(keyVariantConverter to key)
Bridge.engine_call_has(_handle)
return TransferContext.readReturnValue(VariantParser.BOOL) as Boolean
}
/**
* Returns true if the dictionary has all of the keys in the given array.
*/
fun hasAll(keys: VariantArray): Boolean {
TransferContext.writeArguments(VariantParser.ARRAY to keys)
Bridge.engine_call_hasAll(_handle)
return TransferContext.readReturnValue(VariantParser.BOOL) as Boolean
}
/**
* Returns a hashed integer value representing the dictionary contents. This can be used to compare dictionaries by value
*/
fun hash(): Int {
Bridge.engine_call_hash(_handle)
return TransferContext.readReturnValue(VariantCaster.INT) as Int
}
/**
* Returns true if the dictionary is read-only. See [makeReadOnly]
*/
fun isReadOnly(): Boolean {
Bridge.engine_call_is_read_only(_handle)
return TransferContext.readReturnValue(VariantParser.BOOL) as Boolean
}
/**
* Returns true if the dictionary is empty.
*/
override fun isEmpty(): Boolean {
Bridge.engine_call_is_empty(_handle)
return TransferContext.readReturnValue(VariantParser.BOOL) as Boolean
}
/**
* Returns the list of keys in the Dictionary.
*/
fun keys(): VariantArray {
Bridge.engine_call_keys(_handle)
@Suppress("UNCHECKED_CAST")
return (TransferContext.readReturnValue(VariantParser.ARRAY) as VariantArray).also {
it.variantConverter = keyVariantConverter
}
}
fun makeReadOnly() {
Bridge.engine_call_make_read_only(_handle)
}
fun merge(dictionary: Dictionary, overwrite: Boolean = false) {
TransferContext.writeArguments(VariantParser.DICTIONARY to dictionary, VariantParser.BOOL to overwrite)
Bridge.engine_call_merge(_handle)
}
override fun put(key: K, value: V): V? {
val ret = get(key, null)
set(key, value)
return ret
}
override fun putAll(from: Map) {
from.forEach {
set(it.key, it.value)
}
}
override fun remove(key: K): V? {
val ret = get(key, null)
erase(key)
return ret
}
/**
* Returns the list of values in the Dictionary.
*/
fun values(): VariantArray {
Bridge.engine_call_values(_handle)
@Suppress("UNCHECKED_CAST")
return (TransferContext.readReturnValue(VariantParser.ARRAY) as VariantArray).also {
it.variantConverter = valueVariantConverter
}
}
//UTILITIES
override operator fun get(key: K): V {
TransferContext.writeArguments(keyVariantConverter to key)
Bridge.engine_call_operator_get(_handle)
@Suppress("UNCHECKED_CAST")
return TransferContext.readReturnValue(valueVariantConverter) as V
}
@CoreTypeHelper
inline fun get(key: K, block: V.() -> R): R {
val localCopy = this[key]
val ret = localCopy.block()
this[key] = localCopy
return ret
}
operator fun set(key: K, value: V) {
TransferContext.writeArguments(keyVariantConverter to key, valueVariantConverter to value)
Bridge.engine_call_operator_set(_handle)
}
operator fun contains(key: K): Boolean = has(key)
override fun equals(other: Any?): Boolean {
if (other == null || other !is Dictionary<*, *>) {
return false
}
TransferContext.writeArguments(VariantParser.DICTIONARY to this, VariantParser.DICTIONARY to other)
Bridge.engine_call_equals(_handle)
return TransferContext.readReturnValue(VariantParser.BOOL) as Boolean
}
override fun hashCode(): Int {
return _handle.hashCode()
}
override fun toString(): String {
return "Dictionary($size)"
}
@Suppress("FunctionName")
private object Bridge {
external fun engine_call_constructor(): VoidPtr
external fun engine_call_clear(_handle: VoidPtr)
external fun engine_call_duplicate(_handle: VoidPtr)
external fun engine_call_erase(_handle: VoidPtr)
external fun engine_call_find_key(_handle: VoidPtr)
external fun engine_call_get(_handle: VoidPtr)
external fun engine_call_has(_handle: VoidPtr)
external fun engine_call_hasAll(_handle: VoidPtr)
external fun engine_call_hash(_handle: VoidPtr)
external fun engine_call_is_empty(_handle: VoidPtr)
external fun engine_call_is_read_only(_handle: VoidPtr)
external fun engine_call_keys(_handle: VoidPtr)
external fun engine_call_make_read_only(_handle: VoidPtr)
external fun engine_call_merge(_handle: VoidPtr)
external fun engine_call_size(_handle: VoidPtr)
external fun engine_call_values(_handle: VoidPtr)
external fun engine_call_operator_get(_handle: VoidPtr)
external fun engine_call_operator_set(_handle: VoidPtr)
external fun engine_call_equals(_handle: VoidPtr)
}
companion object {
inline operator fun invoke(): Dictionary {
// The nullable check can't be inside the regular constructor because of Java
if (GodotJvmBuildConfig.DEBUG) {
if(isNullable() && K::class in notNullableVariantSet){
error("Can't create a Dictionary with generic key ${K::class} as nullable.")
}
if(isNullable() && V::class in notNullableVariantSet){
error("Can't create a Dictionary with generic value ${V::class} as nullable.")
}
}
return Dictionary(K::class, V::class)
}
}
}
inline fun dictionaryOf(vararg args: Pair) = Dictionary().also {
it.putAll(args)
}
/**
* Convert a Map into a Dictionary
*/
inline fun Map.toDictionary() = Dictionary().also {
it.putAll(this)
}