mirror of
https://github.com/tursom/TursomServer.git
synced 2024-12-29 14:30:55 +08:00
Merge branch 'master' of github.com:tursom/TursomServer
This commit is contained in:
commit
c6f57a88cd
@ -377,4 +377,32 @@ inline fun <reified T : Any?> Any.assert(action: T.() -> Unit): Boolean {
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
val Class<*>.allFields: List<Field>
|
||||
get() {
|
||||
var clazz = this
|
||||
val list = ArrayList<Field>()
|
||||
while (clazz != Any::class.java) {
|
||||
list.addAll(clazz.declaredFields)
|
||||
clazz = clazz.superclass
|
||||
}
|
||||
list.addAll(clazz.declaredFields)
|
||||
return list
|
||||
}
|
||||
|
||||
fun Class<*>.forAllFields(action: (Field) -> Unit) {
|
||||
var clazz = this
|
||||
while (clazz != Any::class.java) {
|
||||
clazz.declaredFields.forEach(action)
|
||||
clazz = clazz.superclass
|
||||
}
|
||||
clazz.declaredFields.forEach(action)
|
||||
}
|
||||
|
||||
fun <T, R> Iterable<T>.firstNotNull(selector: (T) -> R): R? {
|
||||
forEach {
|
||||
return selector(it) ?: return@forEach
|
||||
}
|
||||
return null
|
||||
}
|
@ -1,271 +1,284 @@
|
||||
package cn.tursom.core.datastruct
|
||||
|
||||
import cn.tursom.core.cast
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
class ArrayMap<K : Comparable<K>, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
@Volatile
|
||||
private var arr: Array<Node<K, V>?> = Array(initialCapacity) { null }
|
||||
@Volatile
|
||||
private var end = 0
|
||||
open class ArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
@Volatile
|
||||
protected var arr: Array<Node<K, V>?> = Array(initialCapacity) { null }
|
||||
|
||||
override val size: Int get() = end
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> = EntrySet(this)
|
||||
override val keys: MutableSet<K> = KeySet(this)
|
||||
override val values: MutableCollection<V> = ValueCollection(this)
|
||||
@Volatile
|
||||
protected var end = 0
|
||||
|
||||
/**
|
||||
* @param key 查找的键
|
||||
* @return 键所在的下标
|
||||
* @return < 0 如果键不存在, -${return} - 1 为如果插入应插入的下标
|
||||
*/
|
||||
fun search(key: K): Int {
|
||||
if (end == 0) return -1
|
||||
return arr.binarySearch(key, 0, end)
|
||||
override val size: Int get() = end
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> = EntrySet(this)
|
||||
override val keys: MutableSet<K> = KeySet(this)
|
||||
override val values: MutableCollection<V> = ValueCollection(this)
|
||||
|
||||
/**
|
||||
* @param key 查找的键
|
||||
* @return 键所在的下标
|
||||
* @return < 0 如果键不存在, -${return} - 1 为如果插入应插入的下标
|
||||
*/
|
||||
open fun search(key: K): Int {
|
||||
if (end == 0) return -1
|
||||
for (index in 0 until end) {
|
||||
if ((arr[index] ?: continue).key == key) {
|
||||
return index
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
infix fun getFromIndex(index: Int): V? {
|
||||
return if (index < 0) null
|
||||
else arr[index]?.value
|
||||
}
|
||||
|
||||
override fun first(): V? = getFromIndex(0)
|
||||
|
||||
override fun clear() {
|
||||
end = 0
|
||||
}
|
||||
|
||||
override operator fun set(key: K, value: V) {
|
||||
setAndGet(key, value)
|
||||
}
|
||||
|
||||
override fun setAndGet(key: K, value: V): V? {
|
||||
@Suppress("SENSELESS_COMPARISON")
|
||||
if (key == null) return null
|
||||
// 首先查找得到目标所在的下标
|
||||
val index = search(key)
|
||||
var prev: V? = null
|
||||
if (index < 0) {
|
||||
// 下标小于零表示不存在,直接插入数据
|
||||
insert(key, value, -index - 1)
|
||||
} else {
|
||||
val node = arr[index]
|
||||
if (node != null) {
|
||||
prev = node.value
|
||||
node.value = value
|
||||
} else arr[index] = Node(key, value)
|
||||
}
|
||||
return prev
|
||||
}
|
||||
|
||||
override infix fun putAll(from: Map<out K, V>) {
|
||||
from.forEach { (key, value) ->
|
||||
val index = search(key)
|
||||
if (index < 0) arr[end++] = Node(key, value)
|
||||
else {
|
||||
val node = arr[index]
|
||||
if (node != null) node.value = value
|
||||
else arr[index] = Node(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override infix fun delete(key: K): V? {
|
||||
val index = search(key)
|
||||
return delete(index)
|
||||
}
|
||||
|
||||
override infix fun containsKey(key: K): Boolean = search(key) >= 0
|
||||
|
||||
override infix fun containsValue(value: V): Boolean {
|
||||
arr.forEach {
|
||||
if (it?.value == value) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override infix operator fun get(key: K): V? = getNode(key)?.value
|
||||
override fun isEmpty(): Boolean = end == 0
|
||||
|
||||
fun copy(): ArrayMap<K, V> {
|
||||
val clone = ArrayMap<K, V>(0)
|
||||
clone.arr = Array(end) { arr[it]?.let { Node(it.key, it.value) } }
|
||||
clone.end = end
|
||||
return clone
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
if (end == 0) return "{}"
|
||||
val sb = StringBuilder("{${arr[0]}")
|
||||
for (i in 1 until end) {
|
||||
sb.append(", ")
|
||||
sb.append(arr[i])
|
||||
}
|
||||
sb.append("}")
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
private fun getNode(key: K): Node<K, V>? {
|
||||
@Suppress("SENSELESS_COMPARISON")
|
||||
if (key == null) return null
|
||||
val index = search(key)
|
||||
return if (index < 0) null
|
||||
else arr[index]
|
||||
}
|
||||
|
||||
private fun resize(newSize: Int = if (arr.isNotEmpty()) arr.size * 2 else 1) {
|
||||
arr = arr.copyOf(newSize)
|
||||
}
|
||||
|
||||
private fun insert(key: K, value: V, index: Int): V? {
|
||||
if (end == arr.size) resize()
|
||||
System.arraycopy(arr, index, arr, index + 1, end - index)
|
||||
arr[index] = Node(key, value)
|
||||
end++
|
||||
return value
|
||||
}
|
||||
|
||||
private infix fun delete(index: Int): V? {
|
||||
if (index in 0 until end) {
|
||||
val oldNode = arr[index]
|
||||
System.arraycopy(arr, index + 1, arr, index, end - index - 1)
|
||||
end--
|
||||
return oldNode?.value
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
class Node<K, V>(
|
||||
override val key: K,
|
||||
@Volatile override var value: V
|
||||
) : MutableMap.MutableEntry<K, V>, Comparable<K> {
|
||||
override fun toString(): String = "$key=$value"
|
||||
override fun setValue(newValue: V): V = value.also { value = newValue }
|
||||
override fun compareTo(other: K): Int {
|
||||
return if (key is Comparable<*>) {
|
||||
key.cast<Comparable<K>>().compareTo(other)
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class EntrySet<K, V>(private val map: ArrayMap<K, V>) : MutableSet<MutableMap.MutableEntry<K, V>> {
|
||||
override val size: Int get() = map.size
|
||||
override fun contains(element: MutableMap.MutableEntry<K, V>): Boolean = map[element.key] == element.value
|
||||
override fun isEmpty(): Boolean = map.isEmpty()
|
||||
override fun iterator(): MutableIterator<MutableMap.MutableEntry<K, V>> = MapIterator(map)
|
||||
override fun clear() = map.clear()
|
||||
|
||||
override fun containsAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
|
||||
elements.forEach {
|
||||
if (!contains(it)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
infix fun getFromIndex(index: Int): V? {
|
||||
return if (index < 0) null
|
||||
else arr[index]?.value
|
||||
override fun add(element: MutableMap.MutableEntry<K, V>): Boolean {
|
||||
map[element.key] = element.value
|
||||
return true
|
||||
}
|
||||
|
||||
override fun first(): V? = getFromIndex(0)
|
||||
|
||||
override fun clear() {
|
||||
end = 0
|
||||
override fun addAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
|
||||
elements.forEach { add(it) }
|
||||
return true
|
||||
}
|
||||
|
||||
override operator fun set(key: K, value: V) {
|
||||
setAndGet(key, value)
|
||||
override fun remove(element: MutableMap.MutableEntry<K, V>): Boolean {
|
||||
val index = map.search(element.key)
|
||||
val value = map.getFromIndex(index)
|
||||
return if (value == element.value) {
|
||||
map.delete(index)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun setAndGet(key: K, value: V): V? {
|
||||
@Suppress("SENSELESS_COMPARISON")
|
||||
if (key == null) return null
|
||||
// 首先查找得到目标所在的下标
|
||||
val index = search(key)
|
||||
var prev: V? = null
|
||||
if (index < 0) {
|
||||
// 下标小于零表示不存在,直接插入数据
|
||||
insert(key, value, -index - 1)
|
||||
} else {
|
||||
val node = arr[index]
|
||||
if (node != null) {
|
||||
prev = node.value
|
||||
node.value = value
|
||||
} else arr[index] = Node(key, value)
|
||||
}
|
||||
return prev
|
||||
override fun removeAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
|
||||
elements.forEach { remove(it) }
|
||||
return true
|
||||
}
|
||||
|
||||
override infix fun putAll(from: Map<out K, V>) {
|
||||
from.forEach { (key, value) ->
|
||||
val index = search(key)
|
||||
if (index < 0) arr[end++] = Node(key, value)
|
||||
else {
|
||||
val node = arr[index]
|
||||
if (node != null) node.value = value
|
||||
else arr[index] = Node(key, value)
|
||||
}
|
||||
}
|
||||
arr.sort()
|
||||
override fun retainAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
|
||||
val contains = elements.filter { map[it.key] == it.value }
|
||||
map.clear()
|
||||
map.resize(contains.size)
|
||||
addAll(contains)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
class MapIterator<K, V>(private val map: ArrayMap<K, V>) : MutableIterator<MutableMap.MutableEntry<K, V>> {
|
||||
private var index = 0
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
@Suppress("ControlFlowWithEmptyBody")
|
||||
while (++index < map.arr.size && index < map.end && map.arr[index] == null);
|
||||
index--
|
||||
return index < map.end
|
||||
}
|
||||
|
||||
override infix fun delete(key: K): V? {
|
||||
val index = search(key)
|
||||
return delete(index)
|
||||
override fun next(): MutableMap.MutableEntry<K, V> = map.arr[index++]!!
|
||||
|
||||
override fun remove() {
|
||||
map.delete(index)
|
||||
index--
|
||||
}
|
||||
}
|
||||
|
||||
class KeySet<K>(private val map: ArrayMap<K, *>) : MutableSet<K> {
|
||||
override val size: Int get() = map.size
|
||||
override fun contains(element: K): Boolean = map.containsKey(element)
|
||||
override fun isEmpty(): Boolean = size == 0
|
||||
override fun iterator(): MutableIterator<K> = KeyIterator(map)
|
||||
|
||||
override fun containsAll(elements: Collection<K>): Boolean {
|
||||
elements.forEach {
|
||||
if (!map.containsKey(it)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override infix fun containsKey(key: K): Boolean = search(key) >= 0
|
||||
|
||||
override infix fun containsValue(value: V): Boolean {
|
||||
arr.forEach {
|
||||
if (it?.value == value) return true
|
||||
}
|
||||
return false
|
||||
override fun add(element: K): Boolean = false
|
||||
override fun addAll(elements: Collection<K>): Boolean = false
|
||||
override fun clear() = map.clear()
|
||||
override fun retainAll(elements: Collection<K>): Boolean = map.entries.retainAll(elements.map { map.getNode(it) }.filterNotNull())
|
||||
override fun remove(element: K): Boolean = map.remove(element) != null
|
||||
override fun removeAll(elements: Collection<K>): Boolean {
|
||||
elements.forEach { remove(it) }
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
override infix operator fun get(key: K): V? = getNode(key)?.value
|
||||
override fun isEmpty(): Boolean = end == 0
|
||||
class KeyIterator<K>(map: ArrayMap<K, *>) : MutableIterator<K> {
|
||||
private val iterator = map.iterator()
|
||||
override fun hasNext(): Boolean = iterator.hasNext()
|
||||
override fun next(): K = iterator.next().key
|
||||
override fun remove() = iterator.remove()
|
||||
}
|
||||
|
||||
fun copy(): ArrayMap<K, V> {
|
||||
val clone = ArrayMap<K, V>(0)
|
||||
clone.arr = Array(end) { arr[it]?.let { Node(it.key, it.value) } }
|
||||
clone.end = end
|
||||
return clone
|
||||
class ValueCollection<V>(private val map: ArrayMap<*, V>) : MutableCollection<V> {
|
||||
override val size: Int get() = map.size
|
||||
override fun contains(element: V): Boolean = map.containsValue(element)
|
||||
override fun isEmpty(): Boolean = size == 0
|
||||
override fun iterator(): MutableIterator<V> = ValueIterator(map)
|
||||
override fun add(element: V): Boolean = false
|
||||
override fun addAll(elements: Collection<V>): Boolean = false
|
||||
override fun clear() = map.clear()
|
||||
override fun remove(element: V): Boolean = false
|
||||
override fun removeAll(elements: Collection<V>): Boolean = false
|
||||
override fun retainAll(elements: Collection<V>): Boolean = false
|
||||
|
||||
override fun containsAll(elements: Collection<V>): Boolean {
|
||||
elements.forEach {
|
||||
if (!map.containsValue(it)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
if (end == 0) return "{}"
|
||||
val sb = StringBuilder("{${arr[0]}")
|
||||
for (i in 1 until end) {
|
||||
sb.append(", ")
|
||||
sb.append(arr[i])
|
||||
}
|
||||
sb.append("}")
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
private fun getNode(key: K): Node<K, V>? {
|
||||
@Suppress("SENSELESS_COMPARISON")
|
||||
if (key == null) return null
|
||||
val index = search(key)
|
||||
return if (index < 0) null
|
||||
else arr[index]
|
||||
}
|
||||
|
||||
private fun resize(newSize: Int = if (arr.isNotEmpty()) arr.size * 2 else 1) {
|
||||
arr = arr.copyOf(newSize)
|
||||
}
|
||||
|
||||
private fun insert(key: K, value: V, index: Int): V? {
|
||||
if (end == arr.size) resize()
|
||||
System.arraycopy(arr, index, arr, index + 1, end - index)
|
||||
arr[index] = Node(key, value)
|
||||
end++
|
||||
return value
|
||||
}
|
||||
|
||||
private infix fun delete(index: Int): V? {
|
||||
if (index in 0 until end) {
|
||||
val oldNode = arr[index]
|
||||
System.arraycopy(arr, index + 1, arr, index, end - index - 1)
|
||||
end--
|
||||
return oldNode?.value
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
class Node<K : Comparable<K>, V>(
|
||||
override val key: K,
|
||||
@Volatile override var value: V
|
||||
) : Comparable<K>, MutableMap.MutableEntry<K, V> {
|
||||
override fun compareTo(other: K): Int = key.compareTo(other)
|
||||
override fun toString(): String = "$key=$value"
|
||||
override fun setValue(newValue: V): V = value.also { value = newValue }
|
||||
}
|
||||
|
||||
|
||||
class EntrySet<K : Comparable<K>, V>(private val map: ArrayMap<K, V>) : MutableSet<MutableMap.MutableEntry<K, V>> {
|
||||
override val size: Int get() = map.size
|
||||
override fun contains(element: MutableMap.MutableEntry<K, V>): Boolean = map[element.key] == element.value
|
||||
override fun isEmpty(): Boolean = map.isEmpty()
|
||||
override fun iterator(): MutableIterator<MutableMap.MutableEntry<K, V>> = MapIterator(map)
|
||||
override fun clear() = map.clear()
|
||||
|
||||
override fun containsAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
|
||||
elements.forEach {
|
||||
if (!contains(it)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun add(element: MutableMap.MutableEntry<K, V>): Boolean {
|
||||
map[element.key] = element.value
|
||||
return true
|
||||
}
|
||||
|
||||
override fun addAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
|
||||
elements.forEach { add(it) }
|
||||
return true
|
||||
}
|
||||
|
||||
override fun remove(element: MutableMap.MutableEntry<K, V>): Boolean {
|
||||
val index = map.search(element.key)
|
||||
val value = map.getFromIndex(index)
|
||||
return if (value == element.value) {
|
||||
map.delete(index)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun removeAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
|
||||
elements.forEach { remove(it) }
|
||||
return true
|
||||
}
|
||||
|
||||
override fun retainAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
|
||||
val contains = elements.filter { map[it.key] == it.value }
|
||||
map.clear()
|
||||
map.resize(contains.size)
|
||||
addAll(contains)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
class MapIterator<K : Comparable<K>, V>(private val map: ArrayMap<K, V>) : MutableIterator<MutableMap.MutableEntry<K, V>> {
|
||||
private var index = 0
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
@Suppress("ControlFlowWithEmptyBody")
|
||||
while (++index < map.arr.size && index < map.end && map.arr[index] == null);
|
||||
index--
|
||||
return index < map.end
|
||||
}
|
||||
|
||||
override fun next(): MutableMap.MutableEntry<K, V> = map.arr[index++]!!
|
||||
|
||||
override fun remove() {
|
||||
map.delete(index)
|
||||
index--
|
||||
}
|
||||
}
|
||||
|
||||
class KeySet<K : Comparable<K>>(private val map: ArrayMap<K, *>) : MutableSet<K> {
|
||||
override val size: Int get() = map.size
|
||||
override fun contains(element: K): Boolean = map.containsKey(element)
|
||||
override fun isEmpty(): Boolean = size == 0
|
||||
override fun iterator(): MutableIterator<K> = KeyIterator(map)
|
||||
|
||||
override fun containsAll(elements: Collection<K>): Boolean {
|
||||
elements.forEach {
|
||||
if (!map.containsKey(it)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun add(element: K): Boolean = false
|
||||
override fun addAll(elements: Collection<K>): Boolean = false
|
||||
override fun clear() = map.clear()
|
||||
override fun retainAll(elements: Collection<K>): Boolean = map.entries.retainAll(elements.map { map.getNode(it) }.filterNotNull())
|
||||
override fun remove(element: K): Boolean = map.remove(element) != null
|
||||
override fun removeAll(elements: Collection<K>): Boolean {
|
||||
elements.forEach { remove(it) }
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
class KeyIterator<K : Comparable<K>>(map: ArrayMap<K, *>) : MutableIterator<K> {
|
||||
private val iterator = map.iterator()
|
||||
override fun hasNext(): Boolean = iterator.hasNext()
|
||||
override fun next(): K = iterator.next().key
|
||||
override fun remove() = iterator.remove()
|
||||
}
|
||||
|
||||
class ValueCollection<V>(private val map: ArrayMap<*, V>) : MutableCollection<V> {
|
||||
override val size: Int get() = map.size
|
||||
override fun contains(element: V): Boolean = map.containsValue(element)
|
||||
override fun isEmpty(): Boolean = size == 0
|
||||
override fun iterator(): MutableIterator<V> = ValueIterator(map)
|
||||
override fun add(element: V): Boolean = false
|
||||
override fun addAll(elements: Collection<V>): Boolean = false
|
||||
override fun clear() = map.clear()
|
||||
override fun remove(element: V): Boolean = false
|
||||
override fun removeAll(elements: Collection<V>): Boolean = false
|
||||
override fun retainAll(elements: Collection<V>): Boolean = false
|
||||
|
||||
override fun containsAll(elements: Collection<V>): Boolean {
|
||||
elements.forEach {
|
||||
if (!map.containsValue(it)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
class ValueIterator<V>(map: ArrayMap<*, V>) : MutableIterator<V> {
|
||||
private val iterator = map.iterator()
|
||||
override fun hasNext(): Boolean = iterator.hasNext()
|
||||
override fun next(): V = iterator.next().value
|
||||
override fun remove() = iterator.remove()
|
||||
}
|
||||
class ValueIterator<V>(map: ArrayMap<*, V>) : MutableIterator<V> {
|
||||
private val iterator = map.iterator()
|
||||
override fun hasNext(): Boolean = iterator.hasNext()
|
||||
override fun next(): V = iterator.next().value
|
||||
override fun remove() = iterator.remove()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
package cn.tursom.core.datastruct
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
class ComparableArrayMap<K : Comparable<K>, V>(initialCapacity: Int = 16) : ArrayMap<K, V>(initialCapacity) {
|
||||
/**
|
||||
* @param key 查找的键
|
||||
* @return 键所在的下标
|
||||
* @return < 0 如果键不存在, -${return} - 1 为如果插入应插入的下标
|
||||
*/
|
||||
override fun search(key: K): Int {
|
||||
if (end == 0) return -1
|
||||
return arr.binarySearch(key, 0, end)
|
||||
}
|
||||
|
||||
override infix fun putAll(from: Map<out K, V>) {
|
||||
from.forEach { (key, value) ->
|
||||
val index = search(key)
|
||||
if (index < 0) arr[end++] = Node(key, value)
|
||||
else {
|
||||
val node = arr[index]
|
||||
if (node != null) node.value = value
|
||||
else arr[index] = Node(key, value)
|
||||
}
|
||||
}
|
||||
arr.sort()
|
||||
}
|
||||
}
|
203
src/main/kotlin/cn/tursom/core/datastruct/ParallelArrayMap.kt
Normal file
203
src/main/kotlin/cn/tursom/core/datastruct/ParallelArrayMap.kt
Normal file
@ -0,0 +1,203 @@
|
||||
package cn.tursom.core.datastruct
|
||||
|
||||
import cn.tursom.core.cast
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
open class ParallelArrayMap<K, V>(initialCapacity: Int = 16) : SimpMap<K, V> {
|
||||
@Volatile
|
||||
protected var arr: Array<Any?> = Array(initialCapacity) { null }
|
||||
|
||||
@Volatile
|
||||
protected var arrValue: Array<Any?> = Array(initialCapacity) { null }
|
||||
|
||||
@Volatile
|
||||
protected var end = 0
|
||||
|
||||
override val size: Int get() = end
|
||||
|
||||
@Suppress("LeakingThis")
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<K, V>> = EntrySet(this)
|
||||
override val keys: MutableSet<K> get() = arrValue.asList().subList(0, end).toMutableSet().cast()
|
||||
override val values: MutableCollection<V> get() = arrValue.asList().cast<MutableList<V>>().subList(0, end)
|
||||
|
||||
/**
|
||||
* @param key 查找的键
|
||||
* @return 键所在的下标
|
||||
* @return < 0 如果键不存在, -${return} - 1 为如果插入应插入的下标
|
||||
*/
|
||||
open fun search(key: K): Int {
|
||||
if (end == 0) return -1
|
||||
for (index in 0 until end) {
|
||||
if ((arr[index] ?: continue) == key) {
|
||||
return index
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
private fun resize(newSize: Int = if (arr.isNotEmpty()) arr.size * 2 else 1) {
|
||||
arr = arr.copyOf(newSize)
|
||||
arrValue = arrValue.copyOf(newSize)
|
||||
}
|
||||
|
||||
override fun setAndGet(key: K, value: V): V? {
|
||||
var index = search(key)
|
||||
if (index < 0 || index >= end) {
|
||||
if (end == arr.size) {
|
||||
resize()
|
||||
}
|
||||
index = end++
|
||||
arr[index] = key
|
||||
}
|
||||
return setByIndex(index, value)
|
||||
}
|
||||
|
||||
override fun set(key: K, value: V) {
|
||||
setAndGet(key, value)
|
||||
}
|
||||
|
||||
fun setByIndex(index: Int, value: V): V? {
|
||||
val oldValue = arrValue[end]
|
||||
arrValue[index] = value
|
||||
return oldValue.cast()
|
||||
}
|
||||
|
||||
override fun delete(key: K): V? {
|
||||
return deleteByIndex(search(key))
|
||||
}
|
||||
|
||||
fun deleteByIndex(index: Int): V? {
|
||||
if (index < 0 || index >= end) return null
|
||||
val oldValue = arrValue[index]
|
||||
System.arraycopy(arr, index + 1, arr, index, end - index - 1)
|
||||
System.arraycopy(arrValue, index + 1, arrValue, index, end - index - 1)
|
||||
end--
|
||||
return oldValue.cast()
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
end = 0
|
||||
}
|
||||
|
||||
override fun first(): V? {
|
||||
return if (end <= 0) {
|
||||
null
|
||||
} else {
|
||||
arrValue[0].cast()
|
||||
}
|
||||
}
|
||||
|
||||
override fun containsKey(key: K): Boolean {
|
||||
return search(key) >= 0
|
||||
}
|
||||
|
||||
override fun containsValue(value: V): Boolean {
|
||||
if (end == 0) return false
|
||||
for (index in 0 until end) {
|
||||
if ((arrValue[index] ?: continue) == value) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun get(key: K): V? {
|
||||
return getByIndex(search(key))
|
||||
}
|
||||
|
||||
fun getKeyByIndex(index: Int): K? {
|
||||
return if (index < 0 || index >= end) {
|
||||
null
|
||||
} else {
|
||||
arr[index].cast()
|
||||
}
|
||||
}
|
||||
|
||||
fun getByIndex(index: Int): V? {
|
||||
return if (index < 0 || index >= end) {
|
||||
null
|
||||
} else {
|
||||
arrValue[index].cast()
|
||||
}
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean = end <= 0
|
||||
|
||||
class EntrySet<K, V>(private val map: ParallelArrayMap<K, V>) : MutableSet<MutableMap.MutableEntry<K, V>> {
|
||||
override val size: Int get() = map.size
|
||||
override fun contains(element: MutableMap.MutableEntry<K, V>): Boolean = map[element.key] == element.value
|
||||
override fun isEmpty(): Boolean = map.isEmpty()
|
||||
override fun iterator(): MutableIterator<MutableMap.MutableEntry<K, V>> = MapIterator(map)
|
||||
override fun clear() = map.clear()
|
||||
|
||||
override fun containsAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
|
||||
elements.forEach {
|
||||
if (!contains(it)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun add(element: MutableMap.MutableEntry<K, V>): Boolean {
|
||||
map[element.key] = element.value
|
||||
return true
|
||||
}
|
||||
|
||||
override fun addAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
|
||||
elements.forEach { add(it) }
|
||||
return true
|
||||
}
|
||||
|
||||
override fun remove(element: MutableMap.MutableEntry<K, V>): Boolean {
|
||||
val index = map.search(element.key)
|
||||
val value = map.getByIndex(index)
|
||||
return if (value == element.value) {
|
||||
map.deleteByIndex(index)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun removeAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
|
||||
elements.forEach { remove(it) }
|
||||
return true
|
||||
}
|
||||
|
||||
override fun retainAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
|
||||
val contains = elements.filter { map[it.key] == it.value }
|
||||
map.clear()
|
||||
map.resize(contains.size)
|
||||
addAll(contains)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
class MapIterator<K, V>(private val map: ParallelArrayMap<K, V>) : MutableIterator<MutableMap.MutableEntry<K, V>> {
|
||||
private var index = 0
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
@Suppress("ControlFlowWithEmptyBody")
|
||||
while (++index < map.arr.size && index < map.end && map.arr[index] == null);
|
||||
index--
|
||||
return index < map.end
|
||||
}
|
||||
|
||||
override fun next(): MutableMap.MutableEntry<K, V> = ParallelArrayMapEntry(map, index++)
|
||||
|
||||
override fun remove() {
|
||||
map.deleteByIndex(index)
|
||||
index--
|
||||
}
|
||||
}
|
||||
|
||||
class ParallelArrayMapEntry<K, V>(
|
||||
val map: ParallelArrayMap<K, V>,
|
||||
val index: Int
|
||||
) : MutableMap.MutableEntry<K, V> {
|
||||
override val key: K get() = map.getKeyByIndex(index).cast()
|
||||
override val value: V get() = map.getByIndex(index).cast()
|
||||
override fun setValue(newValue: V): V {
|
||||
return map.setByIndex(index, newValue).cast()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package cn.tursom.core.stream.impl
|
||||
|
||||
import java.io.InputStream
|
||||
|
||||
class JavaInputStreamProxy(
|
||||
val inputStream: cn.tursom.core.stream.InputStream
|
||||
) : InputStream() {
|
||||
override fun read(): Int = inputStream.read()
|
||||
override fun read(b: ByteArray, off: Int, len: Int): Int = inputStream.read(b, off, len)
|
||||
|
||||
override fun skip(n: Long): Long {
|
||||
inputStream.skip(n)
|
||||
return n
|
||||
}
|
||||
}
|
@ -1,6 +1,20 @@
|
||||
dependencies {
|
||||
implementation project(":")
|
||||
implementation project(":utils")
|
||||
api project(":utils:xml")
|
||||
|
||||
// kotlin 协程
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1'
|
||||
//implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1'
|
||||
// kotlin 反射
|
||||
//implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
|
||||
// OkHttp
|
||||
implementation("com.squareup.okhttp3:okhttp:3.14.1")
|
||||
//implementation("com.squareup.okhttp3:okhttp:3.14.1")
|
||||
//implementation group: 'cglib', name: 'cglib', version: '3.3.0'
|
||||
// https://mvnrepository.com/artifact/com.squareup.retrofit2/converter-gson
|
||||
api group: 'com.squareup.retrofit2', name: 'converter-gson', version: '2.9.0'
|
||||
// https://mvnrepository.com/artifact/com.squareup.retrofit2/retrofit
|
||||
compile group: 'com.squareup.retrofit2', name: 'retrofit', version: '2.9.0'
|
||||
|
||||
// https://mvnrepository.com/artifact/org.jsoup/jsoup
|
||||
api group: 'org.jsoup', name: 'jsoup', version: '1.13.1'
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
package cn.tursom.http
|
||||
|
||||
import retrofit2.Call
|
||||
import retrofit2.CallAdapter
|
||||
import retrofit2.Retrofit
|
||||
import java.lang.reflect.Type
|
||||
import java.util.concurrent.CompletableFuture
|
||||
|
||||
object BlockingCallAdapterFactory : CallAdapter.Factory() {
|
||||
override fun get(
|
||||
returnType: Type,
|
||||
annotations: Array<Annotation>,
|
||||
retrofit: Retrofit
|
||||
): CallAdapter<out Any?, out Any?>? {
|
||||
if (getRawType(returnType) == Call::class.java) return null
|
||||
if (getRawType(returnType) == CompletableFuture::class.java) return null
|
||||
if (annotations.any { it is retrofit2.SkipCallbackExecutor }) return null
|
||||
return object : CallAdapter<Any?, Any?> {
|
||||
override fun responseType(): Type = returnType
|
||||
override fun adapt(call: Call<Any?>): Any? = call.execute().body()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package cn.tursom.http
|
||||
|
||||
import cn.tursom.core.isInheritanceFrom
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.ResponseBody
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Node
|
||||
import retrofit2.Converter
|
||||
import retrofit2.Retrofit
|
||||
import java.lang.reflect.Type
|
||||
|
||||
object HtmlConverterFactory : Converter.Factory() {
|
||||
override fun responseBodyConverter(
|
||||
type: Type,
|
||||
annotations: Array<Annotation>,
|
||||
retrofit: Retrofit
|
||||
): Converter<ResponseBody, out Node>? {
|
||||
return if (type is Class<*> && Document::class.java.isInheritanceFrom(type)) {
|
||||
DocumentResponseBodyConverter(retrofit.baseUrl().uri().toString())
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun requestBodyConverter(
|
||||
type: Type,
|
||||
parameterAnnotations: Array<Annotation>,
|
||||
methodAnnotations: Array<Annotation>,
|
||||
retrofit: Retrofit
|
||||
): Converter<in Node, RequestBody>? {
|
||||
return if (type is Class<*> && type::class.java.isInheritanceFrom(Node::class.java)) {
|
||||
NodeRequestBodyConverter
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
class DocumentResponseBodyConverter(
|
||||
private val baseUri: String
|
||||
) : Converter<ResponseBody, Document> {
|
||||
override fun convert(value: ResponseBody): Document {
|
||||
return Jsoup.parse(value.string(), baseUri)
|
||||
}
|
||||
}
|
||||
|
||||
object NodeRequestBodyConverter : Converter<Node, RequestBody> {
|
||||
override fun convert(value: Node): RequestBody {
|
||||
return RequestBody.create(MediaType.parse("text/html; charset=utf-8"), value.outerHtml())
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package cn.tursom.http
|
||||
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.ResponseBody
|
||||
import retrofit2.Converter
|
||||
import retrofit2.Retrofit
|
||||
import java.lang.reflect.Type
|
||||
|
||||
object StringConverterFactory : Converter.Factory() {
|
||||
override fun responseBodyConverter(
|
||||
type: Type,
|
||||
annotations: Array<Annotation>,
|
||||
retrofit: Retrofit
|
||||
): Converter<ResponseBody, *>? {
|
||||
return if (type == String::class.java) {
|
||||
StringResponseBodyConverter
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun requestBodyConverter(
|
||||
type: Type,
|
||||
parameterAnnotations: Array<Annotation>,
|
||||
methodAnnotations: Array<Annotation>,
|
||||
retrofit: Retrofit
|
||||
): Converter<*, RequestBody>? {
|
||||
return if (type == String::class.java) {
|
||||
StringRequestBodyConverter
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
object StringResponseBodyConverter : Converter<ResponseBody, String> {
|
||||
override fun convert(value: ResponseBody): String? {
|
||||
return value.string()
|
||||
}
|
||||
}
|
||||
|
||||
object StringRequestBodyConverter : Converter<String, RequestBody> {
|
||||
override fun convert(value: String): RequestBody {
|
||||
return RequestBody.create(MediaType.parse("text/plain; charset=utf-8"), value)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package cn.tursom.http
|
||||
|
||||
import cn.tursom.core.isInheritanceFrom
|
||||
import cn.tursom.utils.xml.Xml
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.ResponseBody
|
||||
import org.dom4j.Document
|
||||
import org.dom4j.Node
|
||||
import retrofit2.Converter
|
||||
import retrofit2.Retrofit
|
||||
import java.lang.reflect.Type
|
||||
|
||||
object XmlConverterFactory : Converter.Factory() {
|
||||
override fun responseBodyConverter(
|
||||
type: Type,
|
||||
annotations: Array<Annotation>,
|
||||
retrofit: Retrofit
|
||||
): Converter<ResponseBody, out Node>? {
|
||||
return if (type is Class<*> && Document::class.java.isInheritanceFrom(type)) {
|
||||
DocumentResponseBodyConverter
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun requestBodyConverter(
|
||||
type: Type,
|
||||
parameterAnnotations: Array<Annotation>,
|
||||
methodAnnotations: Array<Annotation>,
|
||||
retrofit: Retrofit
|
||||
): Converter<in Node, RequestBody>? {
|
||||
return if (type is Class<*> && type.isInheritanceFrom(Node::class.java)) {
|
||||
NodeRequestBodyConverter
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
object DocumentResponseBodyConverter : Converter<ResponseBody, Document> {
|
||||
override fun convert(value: ResponseBody): Document {
|
||||
return Xml.saxReader.read(value.string().reader())
|
||||
}
|
||||
}
|
||||
|
||||
object NodeRequestBodyConverter : Converter<Node, RequestBody> {
|
||||
override fun convert(value: Node): RequestBody {
|
||||
return RequestBody.create(MediaType.parse("text/xml; charset=utf-8"), value.asXML())
|
||||
}
|
||||
}
|
||||
}
|
@ -14,15 +14,13 @@ import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
@Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
object AsyncHttpRequest {
|
||||
|
||||
val defaultClient: OkHttpClient = OkHttpClient().newBuilder()
|
||||
.retryOnConnectionFailure(true)
|
||||
.build()
|
||||
val socketClient: OkHttpClient = proxyClient()
|
||||
val httpProxyClient: OkHttpClient =
|
||||
proxyClient(port = 8080, type = Proxy.Type.HTTP)
|
||||
|
||||
|
||||
|
||||
fun proxyClient(
|
||||
host: String = "127.0.0.1",
|
||||
port: Int = 1080,
|
||||
@ -31,13 +29,13 @@ object AsyncHttpRequest {
|
||||
.proxy(Proxy(type, InetSocketAddress(host, port) as SocketAddress))
|
||||
.retryOnConnectionFailure(true)
|
||||
.build()
|
||||
|
||||
private suspend fun sendRequest(call: Call): Response = suspendCoroutine {
|
||||
|
||||
suspend fun sendRequest(call: Call): Response = suspendCoroutine {
|
||||
call.enqueue(object : Callback {
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
it.resumeWithException(e)
|
||||
}
|
||||
|
||||
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
it.resume(response)
|
||||
}
|
||||
|
196
utils/async-http/src/test/kotlin/cn/tursom/http/test.kt
Normal file
196
utils/async-http/src/test/kotlin/cn/tursom/http/test.kt
Normal file
@ -0,0 +1,196 @@
|
||||
package cn.tursom.http
|
||||
|
||||
import cn.tursom.utils.coroutine.MainDispatcher
|
||||
import cn.tursom.utils.gson
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jsoup.nodes.Document
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import retrofit2.create
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Path
|
||||
import retrofit2.http.Query
|
||||
|
||||
|
||||
interface CoroutineLocalTest {
|
||||
@GET("/")
|
||||
suspend fun test(): Document
|
||||
|
||||
@GET("/status")
|
||||
suspend fun status(): List<RoomStatus>
|
||||
|
||||
@GET("status/{db}")
|
||||
suspend fun status(@Path("db") db: String): RoomStatus
|
||||
|
||||
@GET("room/v1/Room/get_info")
|
||||
suspend fun getRoomInfo(@Query("id") roomId: Int, @Query("from") from: String = "room"): String
|
||||
}
|
||||
|
||||
suspend fun main() {
|
||||
MainDispatcher.init()
|
||||
val retrofit = Retrofit.Builder()
|
||||
//.baseUrl("http://tursom.cn:15015")
|
||||
//.baseUrl("https://www.baidu.com")
|
||||
.baseUrl("https://api.live.bilibili.com")
|
||||
.addCallAdapterFactory(BlockingCallAdapterFactory)
|
||||
.addConverterFactory(StringConverterFactory)
|
||||
.addConverterFactory(HtmlConverterFactory)
|
||||
.addConverterFactory(XmlConverterFactory)
|
||||
.addConverterFactory(GsonConverterFactory.create(gson))
|
||||
.build()
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
launch {
|
||||
println(Thread.currentThread().name)
|
||||
}
|
||||
val coroutineLocalTest: CoroutineLocalTest = retrofit.create()
|
||||
//println(coroutineLocalTest.status())
|
||||
println(coroutineLocalTest.getRoomInfo(801580))
|
||||
}.join()
|
||||
}
|
||||
|
||||
data class RoomStatus(
|
||||
val connected: Boolean,
|
||||
val db: String,
|
||||
val liveUser: LiveUser,
|
||||
val living: Boolean,
|
||||
val recvCount: Int,
|
||||
val roomId: Int,
|
||||
val roomInfo: RoomInfo,
|
||||
val totalCount: Int
|
||||
)
|
||||
|
||||
data class LiveUser(
|
||||
val info: Info,
|
||||
val level: Level,
|
||||
val san: Int
|
||||
)
|
||||
|
||||
data class RoomInfo(
|
||||
val allow_change_area_time: Int,
|
||||
val allow_upload_cover_time: Int,
|
||||
val area_id: Int,
|
||||
val area_name: String,
|
||||
val area_pendants: String,
|
||||
val attention: Int,
|
||||
val background: String,
|
||||
val battle_id: Int,
|
||||
val description: String,
|
||||
val hot_words: List<String>,
|
||||
val hot_words_status: Int,
|
||||
val is_anchor: Int,
|
||||
val is_portrait: Boolean,
|
||||
val is_strict_room: Boolean,
|
||||
val keyframe: String,
|
||||
val live_status: Int,
|
||||
val live_time: String,
|
||||
val new_pendants: NewPendants,
|
||||
val old_area_id: Int,
|
||||
val online: Int,
|
||||
val parent_area_id: Int,
|
||||
val parent_area_name: String,
|
||||
val pendants: String,
|
||||
val pk_id: Int,
|
||||
val pk_status: Int,
|
||||
val room_id: Int,
|
||||
val room_silent_level: Int,
|
||||
val room_silent_second: Int,
|
||||
val room_silent_type: String,
|
||||
val short_id: Int,
|
||||
val studio_info: StudioInfo,
|
||||
val tags: String,
|
||||
val title: String,
|
||||
val uid: Int,
|
||||
val up_session: String,
|
||||
val user_cover: String,
|
||||
val verify: String
|
||||
)
|
||||
|
||||
data class Info(
|
||||
val face: String,
|
||||
val gender: Int,
|
||||
val identification: Int,
|
||||
val mobile_verify: Int,
|
||||
val official_verify: OfficialVerify,
|
||||
val platform_user_level: Int,
|
||||
val rank: String,
|
||||
val uid: Int,
|
||||
val uname: String,
|
||||
val vip_type: Int
|
||||
)
|
||||
|
||||
data class Level(
|
||||
val anchor_score: Int,
|
||||
val color: Int,
|
||||
val cost: Int,
|
||||
val master_level: MasterLevel,
|
||||
val rcost: Long,
|
||||
val svip: Int,
|
||||
val svip_time: String,
|
||||
val uid: Int,
|
||||
val update_time: String,
|
||||
val user_level: Int,
|
||||
val user_score: String,
|
||||
val vip: Int,
|
||||
val vip_time: String
|
||||
)
|
||||
|
||||
data class OfficialVerify(
|
||||
val desc: String,
|
||||
val role: Int,
|
||||
val type: Int
|
||||
)
|
||||
|
||||
data class MasterLevel(
|
||||
val anchor_score: Int,
|
||||
val color: Int,
|
||||
val current: List<Int>,
|
||||
val level: Int,
|
||||
val master_level_color: Int,
|
||||
val next: List<Int>,
|
||||
val sort: String,
|
||||
val upgrade_score: Int
|
||||
)
|
||||
|
||||
data class NewPendants(
|
||||
val badge: Badge,
|
||||
val frame: Frame,
|
||||
val mobile_frame: MobileFrame
|
||||
)
|
||||
|
||||
data class StudioInfo(
|
||||
val master_list: List<Any>,
|
||||
val status: Int
|
||||
)
|
||||
|
||||
data class Badge(
|
||||
val desc: String,
|
||||
val name: String,
|
||||
val position: Double,
|
||||
val value: String
|
||||
)
|
||||
|
||||
data class Frame(
|
||||
val area: Int,
|
||||
val area_old: Int,
|
||||
val bg_color: String,
|
||||
val bg_pic: String,
|
||||
val desc: String,
|
||||
val name: String,
|
||||
val position: Int,
|
||||
val use_old_area: Boolean,
|
||||
val value: String
|
||||
)
|
||||
|
||||
data class MobileFrame(
|
||||
val area: Int,
|
||||
val area_old: Int,
|
||||
val bg_color: String,
|
||||
val bg_pic: String,
|
||||
val desc: String,
|
||||
val name: String,
|
||||
val position: Int,
|
||||
val use_old_area: Boolean,
|
||||
val value: String
|
||||
)
|
@ -0,0 +1,11 @@
|
||||
package cn.tursom.utils.coroutine
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
class CoroutineContextScope(override val coroutineContext: CoroutineContext) : CoroutineScope {
|
||||
companion object {
|
||||
suspend fun get() = CoroutineContextScope(coroutineContext)
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package cn.tursom.utils.coroutine
|
||||
|
||||
import cn.tursom.core.cast
|
||||
import cn.tursom.core.toHexString
|
||||
import kotlinx.coroutines.Job
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
open class CoroutineLocal<T> {
|
||||
open suspend fun get(): T? {
|
||||
var attach: MutableMap<CoroutineLocal<*>, Any?>? = coroutineContext[CoroutineLocalContext]
|
||||
if (attach == null) {
|
||||
if (injectCoroutineLocalContext()) {
|
||||
attach = coroutineContext[CoroutineLocalContext]
|
||||
}
|
||||
if (attach == null) {
|
||||
val job = coroutineContext[Job] ?: return null
|
||||
attach = attachMap[job]
|
||||
}
|
||||
}
|
||||
return attach?.get(this)?.cast()
|
||||
}
|
||||
|
||||
open suspend infix fun set(value: T): Boolean {
|
||||
var attach: MutableMap<CoroutineLocal<*>, Any?>? = coroutineContext[CoroutineLocalContext]
|
||||
if (attach == null) {
|
||||
if (injectCoroutineLocalContext()) {
|
||||
attach = coroutineContext[CoroutineLocalContext]
|
||||
}
|
||||
if (attach == null) {
|
||||
val job = coroutineContext[Job] ?: return false
|
||||
attach = attachMap[job]
|
||||
if (attach == null) {
|
||||
attach = HashMap()
|
||||
attachMap[job] = attach
|
||||
job.invokeOnCompletion {
|
||||
attachMap.remove(job)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
attach[this] = value
|
||||
return true
|
||||
}
|
||||
|
||||
override fun toString(): String = "CoroutineLocal@${hashCode().toHexString(false)}"
|
||||
|
||||
companion object {
|
||||
private val attachMap = ConcurrentHashMap<CoroutineContext, MutableMap<CoroutineLocal<*>, Any?>>()
|
||||
override fun toString(): String = attachMap.toString()
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package cn.tursom.utils.coroutine
|
||||
|
||||
import cn.tursom.core.cast
|
||||
import kotlinx.coroutines.ThreadContextElement
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
open class CoroutineLocalContext(
|
||||
private val mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) }
|
||||
) : CoroutineContext.Element, ThreadContextElement<MutableMap<CoroutineLocal<*>, Any?>>, MutableMap<CoroutineLocal<*>, Any?> {
|
||||
override val key: CoroutineContext.Key<*> get() = Key
|
||||
private var map: MutableMap<CoroutineLocal<*>, Any?> = mapBuilder()
|
||||
|
||||
override fun toString(): String {
|
||||
return "CoroutineLocalContext$map"
|
||||
}
|
||||
|
||||
companion object Key : CoroutineContext.Key<CoroutineLocalContext>
|
||||
|
||||
override fun restoreThreadContext(context: CoroutineContext, oldState: MutableMap<CoroutineLocal<*>, Any?>) {
|
||||
map = oldState
|
||||
}
|
||||
|
||||
override fun updateThreadContext(context: CoroutineContext): MutableMap<CoroutineLocal<*>, Any?> {
|
||||
val oldState = map
|
||||
map = mapBuilder()
|
||||
return oldState
|
||||
}
|
||||
|
||||
@JvmName("getTyped")
|
||||
operator fun <T> get(key: CoroutineLocal<T>): T? = map[key].cast()
|
||||
operator fun <T> set(key: CoroutineLocal<T>, value: T?): T? = map.put(key, value).cast()
|
||||
|
||||
override val size: Int get() = map.size
|
||||
override fun containsKey(key: CoroutineLocal<*>): Boolean = map.containsKey(key)
|
||||
override fun containsValue(value: Any?): Boolean = map.containsValue(value)
|
||||
override fun get(key: CoroutineLocal<*>): Any? = map[key]
|
||||
override fun isEmpty(): Boolean = map.isEmpty()
|
||||
override val entries: MutableSet<MutableMap.MutableEntry<CoroutineLocal<*>, Any?>> get() = map.entries
|
||||
override val keys: MutableSet<CoroutineLocal<*>> get() = map.keys
|
||||
override val values: MutableCollection<Any?> get() = map.values
|
||||
override fun clear() = map.clear()
|
||||
override fun put(key: CoroutineLocal<*>, value: Any?): Any? = map.put(key, value)
|
||||
override fun putAll(from: Map<out CoroutineLocal<*>, Any?>) = map.putAll(from)
|
||||
override fun remove(key: CoroutineLocal<*>): Any? = map.remove(key)
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package cn.tursom.utils.coroutine
|
||||
|
||||
import cn.tursom.core.cast
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
class CoroutineLocalContinuation(
|
||||
private val completion: Continuation<*>
|
||||
) : Continuation<Any?> by completion.cast() {
|
||||
override val context: CoroutineContext = completion.context + if (completion.context[CoroutineLocalContext] == null) {
|
||||
CoroutineLocalContext()
|
||||
} else {
|
||||
EmptyCoroutineContext
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package cn.tursom.utils.coroutine
|
||||
|
||||
import cn.tursom.core.cast
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
class CoroutineScopeContext(
|
||||
var coroutineScope: CoroutineScope = GlobalScope
|
||||
) : CoroutineContext.Element {
|
||||
override val key: CoroutineContext.Key<*> get() = Companion
|
||||
|
||||
override fun toString(): String = "CoroutineScopeContext(coroutineScope=$coroutineScope)"
|
||||
|
||||
companion object : CoroutineContext.Key<CoroutineScopeContext>, CoroutineLocal<CoroutineScope>() {
|
||||
override suspend fun get(): CoroutineScope = coroutineContext[this]?.coroutineScope ?: super.get()
|
||||
?: coroutineContext[Job]?.let {
|
||||
if (it is CoroutineScope) {
|
||||
it.cast<CoroutineScope>()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} ?: CoroutineContextScope(coroutineContext)
|
||||
|
||||
override suspend infix fun set(value: CoroutineScope): Boolean {
|
||||
val coroutineScopeContext = coroutineContext[this]
|
||||
return if (coroutineScopeContext != null) {
|
||||
coroutineScopeContext.coroutineScope = value
|
||||
true
|
||||
} else {
|
||||
super.set(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package cn.tursom.utils.coroutine
|
||||
|
||||
import cn.tursom.core.SimpThreadLocal
|
||||
import cn.tursom.core.cast
|
||||
import kotlinx.coroutines.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
object CurrentThreadCoroutineScope {
|
||||
private val eventLoopThreadLocal: SimpThreadLocal<CoroutineDispatcher> = SimpThreadLocal {
|
||||
newBlockingEventLoop()
|
||||
}
|
||||
|
||||
private suspend fun getCoroutineScope(): CoroutineScope {
|
||||
val eventLoop = eventLoopThreadLocal.get()
|
||||
val coroutineScopeContext = CoroutineScopeContext()
|
||||
val newBlockingCoroutine = newBlockingCoroutine(
|
||||
coroutineContext + coroutineScopeContext + Dispatchers.Unconfined,
|
||||
Thread.currentThread(),
|
||||
eventLoop
|
||||
)
|
||||
coroutineScopeContext.coroutineScope = newBlockingCoroutine
|
||||
return newBlockingCoroutine
|
||||
}
|
||||
|
||||
suspend fun launch(
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
block: suspend CoroutineScope.() -> Unit
|
||||
): Job {
|
||||
val coroutineScope = getCoroutineScope()
|
||||
//coroutineScope.launch(start = start, block = block)
|
||||
coroutineScope.start(start, block = block)
|
||||
return coroutineScope as Job
|
||||
}
|
||||
|
||||
private val EventLoop = Class.forName("kotlinx.coroutines.EventLoop")
|
||||
private val EventLoopShouldBeProcessedFromContext = EventLoop.methods
|
||||
.first { it.name == "shouldBeProcessedFromContext" }
|
||||
.apply { isAccessible = true }
|
||||
|
||||
private val BlockingEventLoop = Class.forName("kotlinx.coroutines.BlockingEventLoop")
|
||||
private val BlockingEventLoopConstructor = BlockingEventLoop
|
||||
.getConstructor(Thread::class.java)
|
||||
.apply { isAccessible = true }
|
||||
|
||||
private fun newBlockingEventLoop(thread: Thread = Thread.currentThread()): CoroutineDispatcher {
|
||||
return BlockingEventLoopConstructor.newInstance(thread) as CoroutineDispatcher
|
||||
}
|
||||
|
||||
private val BlockingCoroutine = Class.forName("kotlinx.coroutines.BlockingCoroutine")
|
||||
private val BlockingCoroutineConstructor = BlockingCoroutine.constructors[0].apply { isAccessible = true }
|
||||
private val BlockingCoroutineStart = BlockingCoroutine.methods.first { it.name == "start" && it.parameters.size == 3 }.apply { isAccessible = true }
|
||||
private val BlockingCoroutineJoinBlocking = BlockingCoroutine.methods.first { it.name == "joinBlocking" }.apply { isAccessible = true }
|
||||
//private val BlockingCoroutineOnCompleted = BlockingCoroutine.methods.first { it.name == "onCompleted" }.apply { isAccessible = true }
|
||||
|
||||
private fun newBlockingCoroutine(
|
||||
coroutineContext: CoroutineContext,
|
||||
thread: Thread = Thread.currentThread(),
|
||||
eventLoop: CoroutineDispatcher
|
||||
): CoroutineScope {
|
||||
return BlockingCoroutineConstructor.newInstance(coroutineContext, thread, eventLoop).cast()
|
||||
}
|
||||
|
||||
private fun <T> CoroutineScope.start(
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
receiver: CoroutineScope = this,
|
||||
block: suspend CoroutineScope.() -> T
|
||||
) {
|
||||
BlockingCoroutineStart.invoke(this, start, receiver, block)
|
||||
}
|
||||
|
||||
private fun <T> CoroutineScope.joinBlocking(): T {
|
||||
return BlockingCoroutineJoinBlocking.invoke(this).cast()
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package cn.tursom.utils.coroutine
|
||||
|
||||
import kotlinx.coroutines.InternalCoroutinesApi
|
||||
import kotlinx.coroutines.MainCoroutineDispatcher
|
||||
import kotlinx.coroutines.internal.MainDispatcherFactory
|
||||
|
||||
@Suppress("unused")
|
||||
@InternalCoroutinesApi
|
||||
class MainCoroutineDispatcherFactory : MainDispatcherFactory {
|
||||
override val loadPriority: Int = 1
|
||||
|
||||
override fun createDispatcher(allFactories: List<MainDispatcherFactory>): MainCoroutineDispatcher = MainDispatcher
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package cn.tursom.utils.coroutine
|
||||
|
||||
import cn.tursom.core.cast
|
||||
import kotlinx.coroutines.ExecutorCoroutineDispatcher
|
||||
import kotlinx.coroutines.MainCoroutineDispatcher
|
||||
import kotlinx.coroutines.asCoroutineDispatcher
|
||||
import java.io.Closeable
|
||||
import java.lang.reflect.Field
|
||||
import java.lang.reflect.Modifier
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
object MainDispatcher : MainCoroutineDispatcher(), Closeable {
|
||||
private val loaded = AtomicBoolean(false)
|
||||
private val dispatcher: ExecutorCoroutineDispatcher = Executors.newSingleThreadExecutor {
|
||||
thread(start = false, block = it::run, name = "MainDispatcher", isDaemon = false)
|
||||
}.asCoroutineDispatcher()
|
||||
private var oldDispatcher: MainCoroutineDispatcher? = null
|
||||
private val mainDispatcherLoader: Class<*> = Class.forName("kotlinx.coroutines.internal.MainDispatcherLoader")
|
||||
private val dispatcherField: Field = mainDispatcherLoader.getDeclaredField("dispatcher").also { dispatcher ->
|
||||
dispatcher.isAccessible = true
|
||||
val mf: Field = Field::class.java.getDeclaredField("modifiers")
|
||||
mf.isAccessible = true
|
||||
mf.setInt(dispatcher, dispatcher.modifiers and Modifier.FINAL.inv())
|
||||
}
|
||||
|
||||
fun init() {
|
||||
if (loaded.compareAndSet(false, true)) {
|
||||
oldDispatcher = dispatcherField.get(null).cast()
|
||||
dispatcherField.set(null, this)
|
||||
}
|
||||
}
|
||||
|
||||
fun resume() {
|
||||
if (loaded.compareAndSet(true, false) && oldDispatcher != null) {
|
||||
dispatcherField.set(null, oldDispatcher)
|
||||
}
|
||||
}
|
||||
|
||||
override val immediate: MainCoroutineDispatcher get() = this
|
||||
|
||||
override fun dispatch(context: CoroutineContext, block: Runnable) {
|
||||
dispatcher.dispatch(context, block)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
dispatcher.close()
|
||||
}
|
||||
}
|
229
utils/src/main/kotlin/cn/tursom/utils/coroutine/utils.kt
Normal file
229
utils/src/main/kotlin/cn/tursom/utils/coroutine/utils.kt
Normal file
@ -0,0 +1,229 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package cn.tursom.utils.coroutine
|
||||
|
||||
import cn.tursom.core.cast
|
||||
import cn.tursom.core.forAllFields
|
||||
import cn.tursom.core.isInheritanceFrom
|
||||
import kotlinx.coroutines.*
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
|
||||
fun CoroutineScope.launchWithCoroutineLocalContext(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
|
||||
block: suspend CoroutineScope.() -> Unit
|
||||
): Job {
|
||||
return launch(context + CoroutineLocalContext(mapBuilder), start, block)
|
||||
}
|
||||
|
||||
@Suppress("DeferredIsResult")
|
||||
fun <T> CoroutineScope.asyncWithCoroutineLocalContext(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
|
||||
block: suspend CoroutineScope.() -> T
|
||||
): Deferred<T> {
|
||||
return async(context + CoroutineLocalContext(mapBuilder), start, block)
|
||||
}
|
||||
|
||||
suspend fun <T> withCoroutineLocalContext(
|
||||
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
|
||||
block: suspend CoroutineScope.() -> T
|
||||
): T {
|
||||
return withContext(CoroutineLocalContext(mapBuilder), block)
|
||||
}
|
||||
|
||||
@Throws(InterruptedException::class)
|
||||
fun <T> runBlockingWithCoroutineLocalContext(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
|
||||
block: suspend CoroutineScope.() -> T
|
||||
): T {
|
||||
return runBlocking(context + CoroutineLocalContext(mapBuilder), block)
|
||||
}
|
||||
|
||||
fun CoroutineScope.launchWithCoroutineScopeContext(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
block: suspend CoroutineScope.() -> Unit
|
||||
): Job {
|
||||
return launch(context + CoroutineScopeContext(this), start, block)
|
||||
}
|
||||
|
||||
@Suppress("DeferredIsResult")
|
||||
fun <T> CoroutineScope.asyncWithCoroutineScopeContext(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
block: suspend CoroutineScope.() -> T
|
||||
): Deferred<T> {
|
||||
return async(context + CoroutineScopeContext(this), start, block)
|
||||
}
|
||||
|
||||
fun CoroutineScope.launchWithCoroutineLocalAndCoroutineScopeContext(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
|
||||
block: suspend CoroutineScope.() -> Unit
|
||||
): Job {
|
||||
return launch(context + CoroutineLocalContext(mapBuilder) + CoroutineScopeContext(this), start, block)
|
||||
}
|
||||
|
||||
@Suppress("DeferredIsResult")
|
||||
fun <T> CoroutineScope.asyncWithCoroutineLocalAndCoroutineScopeContext(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
|
||||
block: suspend CoroutineScope.() -> T
|
||||
): Deferred<T> {
|
||||
return async(context + CoroutineLocalContext(mapBuilder) + CoroutineScopeContext(this), start, block)
|
||||
}
|
||||
|
||||
@Throws(InterruptedException::class)
|
||||
fun <T> runBlockingWithCoroutineLocalAndCoroutineScopeContext(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
|
||||
block: suspend CoroutineScope.() -> T
|
||||
): T {
|
||||
return runBlocking(context + CoroutineLocalContext(mapBuilder) + CoroutineScopeContext()) {
|
||||
CoroutineScopeContext set this
|
||||
block()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun CoroutineScope.launchWithEnhanceContext(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
|
||||
block: suspend CoroutineScope.() -> Unit
|
||||
): Job {
|
||||
return launch(context + CoroutineLocalContext(mapBuilder), start, block)
|
||||
}
|
||||
|
||||
@Suppress("DeferredIsResult")
|
||||
fun <T> CoroutineScope.asyncWithEnhanceContext(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
|
||||
block: suspend CoroutineScope.() -> T
|
||||
): Deferred<T> {
|
||||
return async(context + CoroutineLocalContext(mapBuilder), start, block)
|
||||
}
|
||||
|
||||
@Throws(InterruptedException::class)
|
||||
fun <T> runBlockingWithEnhanceContext(
|
||||
context: CoroutineContext = EmptyCoroutineContext,
|
||||
mapBuilder: () -> MutableMap<CoroutineLocal<*>, Any?> = { HashMap(4) },
|
||||
block: suspend CoroutineScope.() -> T
|
||||
): T {
|
||||
return runBlocking(context + CoroutineLocalContext(mapBuilder)) {
|
||||
block()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun <T> runWithCoroutineLocalContext(
|
||||
block: suspend () -> T
|
||||
): T {
|
||||
val continuation: Any? = getContinuation()
|
||||
val coroutineLocalContinuation = if (continuation is Continuation<*>) {
|
||||
CoroutineLocalContinuation(continuation.cast())
|
||||
} else {
|
||||
return continuation.cast()
|
||||
}
|
||||
return (block.cast<(Any?) -> T>()).invoke(coroutineLocalContinuation)
|
||||
}
|
||||
|
||||
suspend fun <T> runWithCoroutineLocal(
|
||||
block: suspend () -> T
|
||||
): T {
|
||||
if (coroutineContext[CoroutineLocalContext] == null) {
|
||||
return runWithCoroutineLocalContext(block)
|
||||
}
|
||||
return block()
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun getContinuation(continuation: Continuation<*>): Continuation<*> {
|
||||
return continuation
|
||||
}
|
||||
|
||||
suspend inline fun getContinuation(): Continuation<*> {
|
||||
val getContinuation: (continuation: Continuation<*>) -> Continuation<*> = ::getContinuation
|
||||
return (getContinuation.cast<suspend () -> Continuation<*>>()).invoke()
|
||||
}
|
||||
|
||||
suspend fun injectCoroutineContext(
|
||||
coroutineContext: CoroutineContext,
|
||||
key: CoroutineContext.Key<out CoroutineContext.Element>? = null
|
||||
): Boolean {
|
||||
return if (key == null || coroutineContext[key] == null) {
|
||||
getContinuation().injectCoroutineContext(coroutineContext, key)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun injectCoroutineLocalContext(coroutineLocalContext: CoroutineLocalContext? = null): Boolean {
|
||||
return if (coroutineContext[CoroutineLocalContext] == null) {
|
||||
getContinuation().injectCoroutineLocalContext(coroutineLocalContext)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fun Continuation<*>.injectCoroutineLocalContext(
|
||||
coroutineLocalContext: CoroutineLocalContext? = null
|
||||
): Boolean {
|
||||
return if (context[CoroutineLocalContext] == null) {
|
||||
injectCoroutineContext(coroutineLocalContext ?: CoroutineLocalContext(), CoroutineLocalContext)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private val BaseContinuationImpl = Class.forName("kotlin.coroutines.jvm.internal.BaseContinuationImpl")
|
||||
private val BaseContinuationImplCompletion = BaseContinuationImpl.getDeclaredField("completion").apply { isAccessible = true }
|
||||
fun Continuation<*>.injectCoroutineContext(
|
||||
coroutineContext: CoroutineContext,
|
||||
key: CoroutineContext.Key<out CoroutineContext.Element>? = null
|
||||
): Boolean {
|
||||
if (key != null && context[key] != null) return true
|
||||
if (BaseContinuationImpl.isInstance(this)) {
|
||||
BaseContinuationImplCompletion.get(this).cast<Continuation<*>>().injectCoroutineContext(coroutineContext, key)
|
||||
}
|
||||
combinedContext(context)
|
||||
if (context[CoroutineLocalContext] != null) return true
|
||||
javaClass.forAllFields {
|
||||
if (!it.type.isInheritanceFrom(CoroutineContext::class.java)) {
|
||||
return@forAllFields
|
||||
}
|
||||
it.isAccessible = true
|
||||
it.set(this, it.get(this).cast<CoroutineContext>() + coroutineContext)
|
||||
}
|
||||
return context[CoroutineLocalContext] != null
|
||||
}
|
||||
|
||||
private val combinedContextClass = Class.forName("kotlin.coroutines.CombinedContext")
|
||||
private val left = combinedContextClass.getDeclaredField("left").apply { isAccessible = true }
|
||||
|
||||
fun combinedContext(coroutineContext: CoroutineContext): Boolean {
|
||||
if (!combinedContextClass.isInstance(coroutineContext)) return false
|
||||
if (coroutineContext[CoroutineLocalContext] == null) {
|
||||
val leftObj = left.get(coroutineContext).cast<CoroutineContext>()
|
||||
left.set(coroutineContext, leftObj + CoroutineLocalContext())
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
//fun CoroutineScope.runOnUiThread(action: suspend CoroutineScope.() -> Unit): Job {
|
||||
// return launch(Dispatchers.Main, block = action)
|
||||
//}
|
||||
|
||||
suspend fun <T> runOnUiThread(coroutineContext: CoroutineContext = EmptyCoroutineContext, action: suspend CoroutineScope.() -> T): T {
|
||||
return withContext(coroutineContext + Dispatchers.Main, action)
|
||||
}
|
@ -0,0 +1 @@
|
||||
cn.tursom.utils.coroutine.MainDispatcherFactory
|
@ -0,0 +1,62 @@
|
||||
package cn.tursom.utils.coroutine
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import kotlin.coroutines.ContinuationInterceptor
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
val testCoroutineLocal = CoroutineLocal<Int>()
|
||||
|
||||
suspend fun testCustomContext() {
|
||||
testCoroutineLocal.set(1)
|
||||
testInlineCustomContext()
|
||||
}
|
||||
|
||||
suspend fun testInlineCustomContext() {
|
||||
println(coroutineContext)
|
||||
println("===================")
|
||||
}
|
||||
|
||||
annotation class Request(val url: String, val method: String = "GET")
|
||||
|
||||
interface CoroutineLocalTest {
|
||||
@Request("http://tursom.cn:15015/living")
|
||||
suspend fun test(): String
|
||||
}
|
||||
|
||||
class Test : CoroutineScope by MainScope() {
|
||||
suspend fun test() {
|
||||
testCoroutineLocal.set(1)
|
||||
println(coroutineContext)
|
||||
coroutineScope {
|
||||
println(coroutineContext)
|
||||
delay(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object R : () -> R {
|
||||
override fun invoke(): R = this
|
||||
}
|
||||
|
||||
val threadLocal = ThreadLocal<String>()
|
||||
|
||||
fun main() = runBlocking {
|
||||
println(coroutineContext[ContinuationInterceptor])
|
||||
MainDispatcher.init()
|
||||
runOnUiThread(threadLocal.asContextElement()) {
|
||||
threadLocal.set("hello")
|
||||
//Test().test()
|
||||
//println(testCoroutineLocal.get())
|
||||
println(threadLocal.get())
|
||||
println(coroutineContext)
|
||||
launch(Dispatchers.Main) {
|
||||
println(threadLocal.get())
|
||||
println(coroutineContext)
|
||||
}
|
||||
//runOnUiThread {
|
||||
// println(coroutineContext)
|
||||
// println(testCoroutineLocal.get())
|
||||
//}
|
||||
}
|
||||
MainDispatcher.close()
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
dependencies {
|
||||
// 解析XML
|
||||
implementation group: 'dom4j', name: 'dom4j', version: '1.6.1'
|
||||
// 解析XML https://mvnrepository.com/artifact/org.dom4j/dom4j
|
||||
compile group: 'org.dom4j', name: 'dom4j', version: '2.1.3'
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user