Provide the way to specify implicit default for a readonly or mutable map.
Refactor: rename default key and value providers.
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
package kotlin
|
||||
|
||||
import kotlin.platform.platformName
|
||||
|
||||
|
||||
/**
|
||||
* Exception thrown when the map does not contain the corresponding key.
|
||||
*/
|
||||
public class KeyMissingException(message: String): RuntimeException(message)
|
||||
|
||||
|
||||
//private inline fun <K, V> Map<K, V>.getOrDefault(key: K, defaultValue: () -> V): V {
|
||||
// val value = get(key)
|
||||
// if (value == null && !containsKey(key)) {
|
||||
// return defaultValue()
|
||||
// } else {
|
||||
// return value as V
|
||||
// }
|
||||
//}
|
||||
|
||||
public fun <K, V> Map<K, V>.getOrImplicitDefault(key: K): V {
|
||||
if (this is MapWithDefault)
|
||||
return this.getOrImplicitDefault(key)
|
||||
|
||||
return getOrElse(key, { throw KeyMissingException("Key $key is missing in the map.") })
|
||||
}
|
||||
|
||||
public fun <K, V> Map<K, V>.withDefault(default: (key: K) -> V): Map<K, V> =
|
||||
when (this) {
|
||||
is MapWithDefault -> this.map.withDefault(default)
|
||||
else -> MapWithDefaultImpl(this, default)
|
||||
}
|
||||
|
||||
platformName("withDefaultMutable")
|
||||
public fun <K, V> MutableMap<K, V>.withDefault(default: (key: K) -> V): MutableMap<K, V> =
|
||||
when (this) {
|
||||
is MutableMapWithDefault -> this.map.withDefault(default)
|
||||
else -> MutableMapWithDefaultImpl(this, default)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private interface MapWithDefault<K, out V>: Map<K, V> {
|
||||
public val map: Map<K, V>
|
||||
public fun getOrImplicitDefault(key: K): V
|
||||
}
|
||||
|
||||
private interface MutableMapWithDefault<K, V>: MutableMap<K, V>, MapWithDefault<K, V> {
|
||||
public override val map: MutableMap<K, V>
|
||||
}
|
||||
|
||||
|
||||
private class MapWithDefaultImpl<K, out V>(public override val map: Map<K,V>, private val default: (key: K) -> V) : MapWithDefault<K, V> {
|
||||
override fun equals(other: Any?): Boolean = map.equals(other)
|
||||
override fun hashCode(): Int = map.hashCode()
|
||||
override fun toString(): String = map.toString()
|
||||
override fun size(): Int = map.size()
|
||||
override fun isEmpty(): Boolean = map.isEmpty()
|
||||
override fun containsKey(key: Any?): Boolean = map.containsKey(key)
|
||||
override fun containsValue(value: Any?): Boolean = map.containsValue(value)
|
||||
override fun get(key: Any?): V? = map.get(key)
|
||||
override fun keySet(): Set<K> = map.keySet()
|
||||
override fun values(): Collection<V> = map.values()
|
||||
override fun entrySet(): Set<Map.Entry<K, V>> = map.entrySet()
|
||||
|
||||
override fun getOrImplicitDefault(key: K): V = map.getOrElse(key, { default(key) })
|
||||
}
|
||||
|
||||
private class MutableMapWithDefaultImpl<K, V>(public override val map: MutableMap<K, V>, private val default: (key: K) -> V): MutableMapWithDefault<K, V> {
|
||||
override fun equals(other: Any?): Boolean = map.equals(other)
|
||||
override fun hashCode(): Int = map.hashCode()
|
||||
override fun toString(): String = map.toString()
|
||||
override fun size(): Int = map.size()
|
||||
override fun isEmpty(): Boolean = map.isEmpty()
|
||||
override fun containsKey(key: Any?): Boolean = map.containsKey(key)
|
||||
override fun containsValue(value: Any?): Boolean = map.containsValue(value)
|
||||
override fun get(key: Any?): V? = map.get(key)
|
||||
override fun keySet(): MutableSet<K> = map.keySet()
|
||||
override fun values(): MutableCollection<V> = map.values()
|
||||
override fun entrySet(): MutableSet<MutableMap.MutableEntry<K, V>> = map.entrySet()
|
||||
|
||||
override fun put(key: K, value: V): V? = map.put(key, value)
|
||||
override fun remove(key: Any?): V? = map.remove(key)
|
||||
override fun putAll(m: Map<out K, V>) = map.putAll(m)
|
||||
override fun clear() = map.clear()
|
||||
|
||||
override fun getOrImplicitDefault(key: K): V = map.getOrElse(key, { default(key) })
|
||||
}
|
||||
|
||||
@@ -61,8 +61,8 @@ public object Delegates {
|
||||
* @param default the function returning the value of the property for a given object if it's missing from the given map.
|
||||
*/
|
||||
public fun mapVar<T>(map: MutableMap<in String, Any?>,
|
||||
default: (thisRef: Any?, desc: String) -> T = defaultValueProvider): ReadWriteProperty<Any?, T> {
|
||||
return FixedMapVar<Any?, String, T>(map, defaultKeyProvider, default)
|
||||
default: (thisRef: Any?, desc: String) -> T = throwKeyNotFound): ReadWriteProperty<Any?, T> {
|
||||
return FixedMapVar<Any?, String, T>(map, propertyNameSelector, default)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,8 +72,8 @@ public object Delegates {
|
||||
* @param default the function returning the value of the property for a given object if it's missing from the given map.
|
||||
*/
|
||||
public fun mapVal<T>(map: Map<in String, Any?>,
|
||||
default: (thisRef: Any?, desc: String) -> T = defaultValueProvider): ReadOnlyProperty<Any?, T> {
|
||||
return FixedMapVal<Any?, String, T>(map, defaultKeyProvider, default)
|
||||
default: (thisRef: Any?, desc: String) -> T = throwKeyNotFound): ReadOnlyProperty<Any?, T> {
|
||||
return FixedMapVal<Any?, String, T>(map, propertyNameSelector, default)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,12 +157,6 @@ private class BlockingLazyVal<T>(lock: Any?, private val initializer: () -> T) :
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception thrown by the default implementation of property delegates which store values in a map
|
||||
* when the map does not contain the corresponding key.
|
||||
*/
|
||||
public class KeyMissingException(message: String): RuntimeException(message)
|
||||
|
||||
/**
|
||||
* Implements the core logic for a property delegate that stores property values in a map.
|
||||
* @param T the type of the object that owns the delegated property.
|
||||
@@ -217,8 +211,8 @@ public abstract class MapVar<T, K, V>() : MapVal<T, K, V>(), ReadWriteProperty<T
|
||||
}
|
||||
}
|
||||
|
||||
private val defaultKeyProvider:(PropertyMetadata) -> String = {it.name}
|
||||
private val defaultValueProvider:(Any?, Any?) -> Nothing = {thisRef, key -> throw KeyMissingException("The value for key $key is missing from $thisRef.")}
|
||||
private val propertyNameSelector: (PropertyMetadata) -> String = {it.name}
|
||||
private val throwKeyNotFound: (Any?, Any?) -> Nothing = {thisRef, key -> throw KeyMissingException("The value for key $key is missing from $thisRef.")}
|
||||
|
||||
/**
|
||||
* Implements a read-only property delegate that stores the property values in a given map instance and uses the given
|
||||
@@ -229,7 +223,7 @@ private val defaultValueProvider:(Any?, Any?) -> Nothing = {thisRef, key -> thro
|
||||
*/
|
||||
public open class FixedMapVal<T, K, out V>(private val map: Map<in K, Any?>,
|
||||
private val key: (PropertyMetadata) -> K,
|
||||
private val default: (ref: T, key: K) -> V = defaultValueProvider) : MapVal<T, K, V>() {
|
||||
private val default: (ref: T, key: K) -> V = throwKeyNotFound) : MapVal<T, K, V>() {
|
||||
protected override fun map(ref: T): Map<in K, Any?> {
|
||||
return map
|
||||
}
|
||||
@@ -252,7 +246,7 @@ public open class FixedMapVal<T, K, out V>(private val map: Map<in K, Any?>,
|
||||
*/
|
||||
public open class FixedMapVar<T, K, V>(private val map: MutableMap<in K, Any?>,
|
||||
private val key: (PropertyMetadata) -> K,
|
||||
private val default: (ref: T, key: K) -> V = defaultValueProvider) : MapVar<T, K, V>() {
|
||||
private val default: (ref: T, key: K) -> V = throwKeyNotFound) : MapVar<T, K, V>() {
|
||||
protected override fun map(ref: T): MutableMap<in K, Any?> {
|
||||
return map
|
||||
}
|
||||
|
||||
@@ -1,23 +1,14 @@
|
||||
package kotlin.properties
|
||||
|
||||
import java.io.Serializable
|
||||
import kotlin.platform.platformName
|
||||
|
||||
// extensions for Map and MutableMap
|
||||
|
||||
public fun <V> Map<in String, *>.get(thisRef: Any?, property: PropertyMetadata): V {
|
||||
val value = this.get(property.name)
|
||||
if (value == null && !containsKey(property.name))
|
||||
defaultValueProvider(thisRef, property.name)
|
||||
return value as V
|
||||
}
|
||||
public fun <V> Map<in String, *>.get(thisRef: Any?, property: PropertyMetadata): V = getOrImplicitDefault(property.name) as V
|
||||
|
||||
platformName("getVar")
|
||||
public fun <V> MutableMap<in String, in V>.get(thisRef: Any?, property: PropertyMetadata): V {
|
||||
val value = this.get(property.name)
|
||||
if (value == null && !containsKey(property.name))
|
||||
defaultValueProvider(thisRef, property.name)
|
||||
return value as V
|
||||
}
|
||||
public fun <V> MutableMap<in String, in V>.get(thisRef: Any?, property: PropertyMetadata): V = getOrImplicitDefault(property.name) as V
|
||||
|
||||
public fun <V> MutableMap<in String, in V>.set(thisRef: Any?, property: PropertyMetadata, value: V) {
|
||||
this.put(property.name, value)
|
||||
@@ -25,6 +16,8 @@ public fun <V> MutableMap<in String, in V>.set(thisRef: Any?, property: Property
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Map accessors
|
||||
|
||||
public interface MapAccessor<KMap, in KAccess, out V>
|
||||
@@ -34,7 +27,7 @@ public interface MapAccessor<KMap, in KAccess, out V>
|
||||
/** Returns `true` if the map contains the specified [key]. */
|
||||
public fun containsKey(key: KAccess): Boolean
|
||||
|
||||
/** Returns the value corresponding to the given [key], or the value provided with [default] function if such a key is not present in the map. */
|
||||
/** Returns the value corresponding to the given [key], or the default value if such a key is not present in the map. */
|
||||
public fun getOrDefault(key: KAccess): V
|
||||
|
||||
public open fun withDefault<V>(default: (KMap) -> V): MapAccessor<KMap, KAccess, V>
|
||||
@@ -49,12 +42,12 @@ public interface MutableMapAccessor<KMap, in KAccess, V>: MapAccessor<KMap, KAcc
|
||||
}
|
||||
|
||||
|
||||
public fun <V> Map<in String, V>.forProperties(): MapAccessor<String, PropertyMetadata, V> = MapAccessorImpl(this, defaultKeyProvider)
|
||||
public fun <V> Map<in String, V>.forProperties(): MapAccessor<String, PropertyMetadata, V> = MapAccessorImpl(this, propertyNameSelector)
|
||||
|
||||
// todo: inline keyselector into anonymous object
|
||||
public fun <K, V> Map<in K, V>.forProperties(keySelector: (PropertyMetadata) -> K): MapAccessor<K, PropertyMetadata, V> = MapAccessorImpl(this, keySelector)
|
||||
|
||||
public fun <V> MutableMap<in String, V>.forProperties(): MutableMapAccessor<String, PropertyMetadata, V> = MutableMapAccessorImpl(this, defaultKeyProvider)
|
||||
public fun <V> MutableMap<in String, V>.forProperties(): MutableMapAccessor<String, PropertyMetadata, V> = MutableMapAccessorImpl(this, propertyNameSelector)
|
||||
|
||||
// todo: inline keyselector into anonymous object
|
||||
public fun <K, V> MutableMap<in K, V>.forProperties(keySelector: (PropertyMetadata) -> K): MutableMapAccessor<K, PropertyMetadata, V> = MutableMapAccessorImpl(this, keySelector)
|
||||
@@ -75,25 +68,18 @@ public fun <K, V> MutableMapAccessor<K, PropertyMetadata, in V>.set(thisRef: Any
|
||||
|
||||
// MapAccessor implementations
|
||||
|
||||
private open class MapAccessorImpl<KMap, in KAccess, out V>(public override val map: Map<in KMap, V>, public val transform: (KAccess) -> KMap, public val default: (KMap) -> V = { k1 -> defaultValueProvider(map, k1) })
|
||||
private open class MapAccessorImpl<KMap, in KAccess, out V>(public override val map: Map<in KMap, V>, public val transform: (KAccess) -> KMap, public val default: (KMap) -> V = { key -> throwKeyNotFound(map, key) })
|
||||
: MapAccessor<KMap, KAccess, V> {
|
||||
|
||||
override fun containsKey(key: KAccess): Boolean = map.containsKey(transform(key))
|
||||
|
||||
override fun getOrDefault(key: KAccess): V {
|
||||
val key1 = transform(key)
|
||||
val value = map.get(key1)
|
||||
if (value == null && !map.containsKey(key1))
|
||||
return default(key1)
|
||||
else
|
||||
return value as V
|
||||
}
|
||||
override fun getOrDefault(key: KAccess): V = transform(key).let { map.getOrElse(it, { default(it) }) }
|
||||
|
||||
override fun withDefault<V>(default: (KMap) -> V): MapAccessor<KMap, KAccess, V> = MapAccessorImpl<KMap, KAccess, V>(map as Map<in KMap, V>, transform, default)
|
||||
}
|
||||
|
||||
|
||||
private class MutableMapAccessorImpl<KMap, in KAccess, V>(public override val map: MutableMap<in KMap, V>, transform: (KAccess) -> KMap, default: (KMap) -> V = { k1 -> defaultValueProvider(map, k1) })
|
||||
private class MutableMapAccessorImpl<KMap, in KAccess, V>(public override val map: MutableMap<in KMap, V>, transform: (KAccess) -> KMap, default: (KMap) -> V = { key -> throwKeyNotFound(map, key) })
|
||||
: MapAccessorImpl<KMap, KAccess, V>(map, transform, default), MutableMapAccessor<KMap, KAccess, V> {
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user