com.itangcent.common.utils.Extensible.kt Maven / Gradle / Ivy
package com.itangcent.common.utils
import java.util.concurrent.ConcurrentHashMap
/**
* An interface for objects that can have extensions added to them.
*/
interface Extensible {
/**
* Checks if the given attribute exists in the extensions.
*
* @param attr The attribute to check.
* @return `true` if the attribute exists, `false` otherwise.
*/
fun hasExt(attr: String): Boolean
/**
* Checks if any of the given attributes exist in the extensions.
*
* @param attr The attributes to check.
* @return `true` if any of the attributes exist, `false` otherwise.
*/
fun hasAnyExt(vararg attr: String): Boolean
/**
* Gets the value of the extension attribute with the given name.
*
* @param attr The name of the extension attribute.
* @return The value of the extension attribute, or `null` if it doesn't exist.
*/
fun getExt(attr: String): T?
/**
* Sets the value of the extension attribute with the given name.
*
* @param attr The name of the extension attribute.
* @param value The value to set.
*/
fun setExt(attr: String, value: Any?)
/**
* Gets all the extensions as a map of attribute names to values.
*
* @return A map of attribute names to values.
*/
fun exts(): Map?
}
/**
* An abstract implementation of the [Extensible] interface.
*/
abstract class AbstractExtensible : Extensible {
/**
* Gets the map of extension attributes.
*/
protected abstract fun map(): MutableMap?
/**
* Initializes the map of extension attributes.
*/
protected abstract fun initMap(): MutableMap
override fun hasExt(attr: String): Boolean {
return map()?.containsKey(attr) ?: false
}
override fun hasAnyExt(vararg attr: String): Boolean {
val map: MutableMap = map() ?: return false
return attr.any { map.containsKey(it) }
}
@Suppress("UNCHECKED_CAST")
override fun getExt(attr: String): T? {
return map()?.get(attr) as? T
}
override fun setExt(attr: String, value: Any?) {
var map = map()
if (map == null) {
map = initMap()
}
map[attr] = value
}
//no copy,please don't modify this map.
override fun exts(): Map? {
return map()
}
}
/**
* A [Extensible] implementation that is backed by a [HashMap].
*/
open class SimpleExtensible : AbstractExtensible() {
private var ext: LinkedHashMap? = null
override fun map(): HashMap? {
return ext
}
override fun initMap(): HashMap {
var map = this.ext
if (map == null) {
map = LinkedHashMap()
this.ext = map
}
return map
}
}
/**
* A [Extensible] implementation that supporting full concurrency of retrievals and
* high expected concurrency for updates.
*/
open class ConcurrentExtensible : AbstractExtensible() {
private var ext: ConcurrentHashMap? = null
override fun map(): ConcurrentHashMap? {
return ext
}
override fun initMap(): ConcurrentHashMap {
synchronized(this) {
var map = this.ext
if (map == null) {
map = ConcurrentHashMap()
this.ext = map
}
return map
}
}
}
/**
* Caches the value of the extension attribute with the given name.
*
* This function checks if the extension attribute with the given name exists.
* If it exists, it returns its value. If it does not exist, it evaluates the
* provided `value` lambda function to compute the value, sets it as the
* extension attribute value, and returns it.
*
* @param attr The name of the extension attribute.
* @param value The lambda function to compute the value if it does not exist.
* @return The value of the extension attribute, either from cache or computed.
*/
fun Extensible.cache(attr: String, value: () -> T?): T? {
return getExt(attr) ?: value().also { setExt(attr, it) }
}