87 lines
2.8 KiB
Kotlin
87 lines
2.8 KiB
Kotlin
package ru.dbotthepony.kstarbound
|
|
|
|
import com.google.common.collect.ImmutableMap
|
|
import com.google.gson.Gson
|
|
import com.google.gson.GsonBuilder
|
|
import com.google.gson.TypeAdapter
|
|
import com.google.gson.TypeAdapterFactory
|
|
import com.google.gson.reflect.TypeToken
|
|
import com.google.gson.stream.JsonReader
|
|
import ru.dbotthepony.kstarbound.api.IStarboundFile
|
|
import ru.dbotthepony.kstarbound.util.KOptional
|
|
import java.util.Arrays
|
|
import java.util.concurrent.Callable
|
|
import java.util.concurrent.ForkJoinPool
|
|
import java.util.concurrent.ForkJoinTask
|
|
import java.util.stream.Stream
|
|
import kotlin.reflect.KProperty
|
|
|
|
inline fun <reified T> GsonBuilder.registerTypeAdapter(adapter: TypeAdapter<T>): GsonBuilder {
|
|
return registerTypeAdapter(T::class.java, adapter)
|
|
}
|
|
|
|
inline fun <reified T> GsonBuilder.registerTypeAdapter(noinline factory: (Gson) -> TypeAdapter<T>): GsonBuilder {
|
|
val token = TypeToken.get(T::class.java)
|
|
|
|
return registerTypeAdapterFactory(object : TypeAdapterFactory {
|
|
override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
|
|
if (type == token) {
|
|
return factory(gson) as TypeAdapter<T>
|
|
}
|
|
|
|
return null
|
|
}
|
|
})
|
|
}
|
|
|
|
fun <T> Array<T>.stream(): Stream<T> = Arrays.stream(this)
|
|
|
|
operator fun <T> ThreadLocal<T>.getValue(thisRef: Any, property: KProperty<*>): T {
|
|
return get()
|
|
}
|
|
|
|
operator fun <T> ThreadLocal<T>.setValue(thisRef: Any, property: KProperty<*>, value: T) {
|
|
set(value)
|
|
}
|
|
|
|
operator fun <K, V> ImmutableMap.Builder<K, V>.set(key: K, value: V): ImmutableMap.Builder<K, V> = put(key, value)
|
|
|
|
fun String.sintern(): String = Starbound.STRINGS.intern(this)
|
|
|
|
inline fun <reified T> Gson.fromJson(reader: JsonReader): T? = fromJson<T>(reader, T::class.java)
|
|
|
|
/**
|
|
* guarantees even distribution of tasks while also preserving encountered order of elements
|
|
*/
|
|
fun <T> Collection<IStarboundFile>.batch(executor: ForkJoinPool, batchSize: Int = 16, mapper: (IStarboundFile) -> KOptional<T>): Stream<T> {
|
|
require(batchSize >= 1) { "Invalid batch size: $batchSize" }
|
|
|
|
if (batchSize == 1 || size <= batchSize) {
|
|
val tasks = ArrayList<ForkJoinTask<KOptional<T>>>()
|
|
|
|
for (listedFile in this) {
|
|
tasks.add(executor.submit(Callable { mapper.invoke(listedFile) }))
|
|
}
|
|
|
|
return tasks.stream().map { it.join() }.filter { it.isPresent }.map { it.value }
|
|
}
|
|
|
|
val batches = ArrayList<ForkJoinTask<List<KOptional<T>>>>()
|
|
var batch = ArrayList<IStarboundFile>(batchSize)
|
|
|
|
for (listedFile in this) {
|
|
batch.add(listedFile)
|
|
|
|
if (batch.size >= batchSize) {
|
|
val mbatch = batch
|
|
batches.add(executor.submit(Callable { mbatch.map { mapper.invoke(it) } }))
|
|
batch = ArrayList(batchSize)
|
|
}
|
|
}
|
|
|
|
if (batch.isNotEmpty())
|
|
batches.add(executor.submit(Callable { batch.map { mapper.invoke(it) } }))
|
|
|
|
return batches.stream().flatMap { it.join().stream() }.filter { it.isPresent }.map { it.value }
|
|
}
|