Initial commit

This commit is contained in:
DBotThePony 2024-02-03 15:30:56 +07:00
commit 43c7fc093a
Signed by: DBot
GPG Key ID: DCC23B5715498507
61 changed files with 7756 additions and 0 deletions

42
.gitignore vendored Normal file
View File

@ -0,0 +1,42 @@
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

3
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

23
.idea/gradle.xml Normal file
View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/collect" />
<option value="$PROJECT_DIR$/core" />
<option value="$PROJECT_DIR$/guava" />
<option value="$PROJECT_DIR$/io" />
<option value="$PROJECT_DIR$/io-math" />
<option value="$PROJECT_DIR$/math" />
<option value="$PROJECT_DIR$/networking" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

6
.idea/kotlinc.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.8.0" />
</component>
</project>

7
.idea/misc.xml Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="temurin-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

46
build.gradle.kts Normal file
View File

@ -0,0 +1,46 @@
plugins {
kotlin("jvm") version "1.8.0"
`maven-publish`
}
repositories {
mavenCentral()
}
tasks.compileKotlin {
kotlinOptions {
jvmTarget = "17"
freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
freeCompilerArgs += "-Xjvm-default=all"
}
}
tasks.jar {
from(project(":core").sourceSets.main.get().output)
from(project(":io").sourceSets.main.get().output)
from(project(":io-math").sourceSets.main.get().output)
from(project(":math").sourceSets.main.get().output)
from(project(":collect").sourceSets.main.get().output)
from(project(":guava").sourceSets.main.get().output)
from(project(":networking").sourceSets.main.get().output)
}
subprojects {
apply(plugin = "maven-publish")
publishing {
repositories {
maven {
url = uri("sftp://maven@dbotthepony.ru:22/maven")
credentials {
val mavenUser: String by project
val mavenPassword: String by project
username = mavenUser
password = mavenPassword
}
}
}
}
}

40
collect/build.gradle.kts Normal file
View File

@ -0,0 +1,40 @@
plugins {
kotlin("jvm")
`maven-publish`
}
val collectVersion: String by project
val projectGroup: String by project
group = projectGroup
version = collectVersion
repositories {
mavenCentral()
}
dependencies {
testImplementation("org.jetbrains.kotlin:kotlin-test")
}
tasks.test {
useJUnitPlatform()
}
kotlin {
jvmToolchain(17)
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
from(components["java"])
pom {
dependencies {
implementation(kotlin("stdlib"))
}
}
}
}
}

View File

@ -0,0 +1,149 @@
package ru.dbotthepony.kommons.collect
import java.lang.ref.Reference
import java.util.*
import java.util.stream.Stream
import java.util.stream.StreamSupport
fun <T> Array<T>.stream(): Stream<T> = Arrays.stream(this)
@Suppress("unchecked_cast")
fun <T> Stream<T?>.filterNotNull(): Stream<T> {
return filter { it != null } as Stream<T>
}
@Suppress("unchecked_cast")
inline fun <reified T> Stream<*>.filterIsInstance(): Stream<T> {
return filter { it is T } as Stream<T>
}
inline fun <T> MutableList<out Reference<out T>>.forValidRefs(fn: (T) -> Unit) {
val iterator = listIterator()
for (value in iterator) {
val get = value.get()
if (get == null) {
iterator.remove()
} else {
fn.invoke(get)
}
}
}
inline fun <T> MutableList<out Reference<out T>>.forValidRefsBreak(fn: (T) -> Boolean) {
val iterator = listIterator()
for (value in iterator) {
val get = value.get()
if (get == null) {
iterator.remove()
} else {
if (fn.invoke(get)) {
break
}
}
}
}
fun <T> Stream<T>.asIterable(): Iterable<T> {
return object : Iterable<T> {
override fun iterator(): Iterator<T> {
return this@asIterable.iterator()
}
}
}
/**
* Returns applicable index to put [element] into [List] determined by [comparator], optionally specifying ranges as [fromIndex] and [toIndex]
*
* If [List] is not sorted, result of this function is undefined
*/
fun <E> List<E>.searchInsertionIndex(element: E, comparator: Comparator<in E>, fromIndex: Int = 0, toIndex: Int = size): Int {
require(toIndex >= fromIndex) { "Invalid range: to $toIndex >= from $fromIndex" }
require(fromIndex >= 0) { "Invalid from index: $fromIndex" }
require(toIndex >= 0) { "Invalid to index: $toIndex" }
require(fromIndex <= size) { "Invalid from index: $fromIndex (list size $size)" }
require(toIndex <= size) { "Invalid to index: $toIndex (list size $size)" }
if (fromIndex == size || fromIndex == toIndex || comparator.compare(element, this[fromIndex]) <= 0) {
return fromIndex
}
// линейный поиск если границы маленькие
if (toIndex - fromIndex <= 10) {
for (i in fromIndex + 1 until toIndex) {
val compare = comparator.compare(element, this[i])
if (compare <= 0) {
return i
}
}
return size
} else {
// двоичный поиск
var lower = fromIndex
var upper = toIndex - 1
while (upper - lower >= 10) {
val middle = (upper + lower) / 2
val compare = comparator.compare(element, this[middle])
if (compare == 0) {
return middle
} else if (compare < 0) {
upper = middle
} else {
lower = middle
}
}
return searchInsertionIndex(element, comparator, lower, upper + 1)
}
}
/**
* Inserts [element] into [MutableList] at index determined by [comparator]
*
* If [MutableList] is not sorted, result of this function is undefined
*/
fun <E> MutableList<E>.addSorted(element: E, comparator: Comparator<in E>) {
add(searchInsertionIndex(element, comparator), element)
}
private object NaturalComparator : Comparator<Comparable<Any>> {
override fun compare(o1: Comparable<Any>, o2: Comparable<Any>): Int {
return o1.compareTo(o2)
}
}
/**
* Inserts [element] into [MutableList] at index determined by comparing values themselves
*
* If [MutableList] is not sorted, result of this function is undefined
*/
fun <E : Comparable<E>> MutableList<E>.addSorted(element: E) {
add(searchInsertionIndex(element, NaturalComparator as Comparator<in E>), element)
}
fun <E> MutableCollection<E>.addAll(elements: Iterator<E>) {
for (item in elements) {
add(item)
}
}
fun <E> MutableCollection<E>.addAll(elements: Stream<out E>) {
for (item in elements) {
add(item)
}
}
fun <E> Iterable<E>.stream(): Stream<out E> {
return StreamSupport.stream(this.spliterator(), false)
}
fun <E> Iterator<E>.stream(): Stream<out E> {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(this, 0), false)
}

View File

@ -0,0 +1,41 @@
package ru.dbotthepony.kommons.collect
import java.util.EnumMap
import java.util.function.BooleanSupplier
import java.util.stream.Stream
class ConditionalEnumSet<T : Enum<T>>private constructor(private val backing: EnumMap<T, BooleanSupplier>, marker: Unit) : Set<T> {
constructor(clazz: Class<T>) : this(EnumMap(clazz), Unit)
constructor(map: Map<T, BooleanSupplier>) : this(EnumMap(map), Unit)
override val size: Int
get() = backing.values.stream().filter { it.asBoolean }.count().toInt()
override fun contains(element: T): Boolean {
return backing[element]?.asBoolean ?: false
}
override fun containsAll(elements: Collection<T>): Boolean {
return elements.all { contains(it) }
}
override fun isEmpty(): Boolean {
return backing.isEmpty() || backing.values.none { it.asBoolean }
}
override fun stream(): Stream<T> {
return backing.entries.stream().filter { it.value.asBoolean }.map { it.key }
}
override fun iterator(): Iterator<T> {
return backing.entries.iterator().filter { it.value.asBoolean }.map { it.key }
}
fun add(value: T, condition: BooleanSupplier) {
backing[value] = condition
}
fun remove(value: T): Boolean {
return backing.remove(value) != null
}
}

View File

@ -0,0 +1,89 @@
package ru.dbotthepony.kommons.collect
import java.util.function.BooleanSupplier
import java.util.stream.Stream
/**
* Set, with values appearing and disappearing by conditions
*/
class ConditionalSet<E : Any> : Set<E> {
private class Entry<E>(val value: E, var condition: BooleanSupplier)
private val backing = ArrayList<Entry<E>>()
private val mapped = HashMap<E, Entry<E>>()
override val size: Int
get() = backing.stream().filter { it.condition.asBoolean }.count().toInt()
override fun contains(element: E): Boolean {
return mapped[element]?.condition?.asBoolean ?: false
}
override fun containsAll(elements: Collection<E>): Boolean {
return elements.all { contains(it) }
}
override fun isEmpty(): Boolean {
return mapped.isEmpty() || mapped.values.stream().noneMatch { it.condition.asBoolean }
}
override fun stream(): Stream<E> {
return backing.stream().filter { it.condition.asBoolean }.map { it.value }
}
override fun iterator(): Iterator<E> {
return backing.iterator().filter { it.condition.asBoolean }.map { it.value }
}
fun actuallyContains(element: E): Boolean {
return element in mapped
}
fun add(element: E, condition: BooleanSupplier): Boolean {
if (element in mapped) return false
val entry = Entry(element, condition)
mapped[element] = entry
backing.add(entry)
return true
}
fun addFirst(element: E, condition: BooleanSupplier): Boolean {
if (element in mapped) return false
val entry = Entry(element, condition)
mapped[element] = entry
backing.add(0, entry)
return true
}
fun replace(element: E, condition: BooleanSupplier) {
val entry = mapped[element]
if (entry != null) {
entry.condition = condition
} else {
add(element, condition)
}
}
fun replaceFirst(element: E, condition: BooleanSupplier) {
val entry = mapped[element]
if (entry != null) {
entry.condition = condition
backing.remove(entry)
backing.add(0, entry)
} else {
addFirst(element, condition)
}
}
fun remove(element: E): Boolean {
val entry = mapped.remove(element)
if (entry != null) {
backing.remove(entry)
return true
}
return false
}
}

View File

@ -0,0 +1,62 @@
package ru.dbotthepony.kommons.collect
class ConditionalSupplierSet<T> : AbstractSet<T> {
// method without boxing
fun interface Condition {
fun check(): Boolean
}
private val getters: Array<Pair<Condition, () -> T>>
constructor(vararg getters: Pair<Condition, () -> T>) : super() {
this.getters = Array(getters.size) { getters[it] }
}
constructor(getters: List<Pair<Condition, () -> T>>) : super() {
this.getters = Array(getters.size) { getters[it] }
}
override val size: Int get() {
var i = 0
for (pair in getters) {
if (pair.first.check()) {
i++
}
}
return i
}
override fun iterator(): Iterator<T> {
return object : Iterator<T> {
val parent = getters.iterator()
private var pair: Pair<Condition, () -> T>? = null
private fun search() {
for (pair in parent) {
if (pair.first.check()) {
this.pair = pair
return
}
}
this.pair = null
}
init {
search()
}
override fun hasNext(): Boolean {
return pair != null
}
override fun next(): T {
val pair = pair ?: throw NoSuchElementException()
search()
return pair.second.invoke()
}
}
}
}

View File

@ -0,0 +1,315 @@
package ru.dbotthepony.kommons.collect
abstract class ProxiedMap<K, V>(protected val backingMap: MutableMap<K, V> = HashMap()) : MutableMap<K, V> {
protected abstract fun onClear()
protected abstract fun onValueAdded(key: K, value: V)
protected abstract fun onValueRemoved(key: K, value: V)
final override val size: Int
get() = backingMap.size
final override fun containsKey(key: K): Boolean {
return backingMap.containsKey(key)
}
final override fun containsValue(value: V): Boolean {
return backingMap.containsValue(value)
}
final override fun get(key: K): V? {
return backingMap[key]
}
final override fun isEmpty(): Boolean {
return backingMap.isEmpty()
}
final override val entries: MutableSet<MutableMap.MutableEntry<K, V>> by lazy {
object : MutableSet<MutableMap.MutableEntry<K, V>> {
override fun add(element: MutableMap.MutableEntry<K, V>): Boolean {
this@ProxiedMap[element.key] = element.value
return true
}
override fun addAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
for (value in elements) {
add(value)
}
return true
}
override fun clear() {
this@ProxiedMap.clear()
}
private val setParent = this@ProxiedMap.backingMap.entries
override fun iterator(): MutableIterator<MutableMap.MutableEntry<K, V>> {
return object : MutableIterator<MutableMap.MutableEntry<K, V>> {
private val parent = setParent.iterator()
private var last: MutableMap.MutableEntry<K, V>? = null
override fun hasNext(): Boolean {
return parent.hasNext()
}
override fun next(): MutableMap.MutableEntry<K, V> {
return parent.next().also { last = it }
}
override fun remove() {
val last = last ?: throw IllegalStateException("Never called next()")
parent.remove()
onValueRemoved(last.key, last.value)
}
}
}
override fun remove(element: MutableMap.MutableEntry<K, V>): Boolean {
if (setParent.remove(element)) {
onValueRemoved(element.key, element.value)
return true
}
return false
}
override fun removeAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
var any = false
for (element in elements) {
any = remove(element) || any
}
return any
}
override fun retainAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
val iterator = this.iterator()
var any = false
for (value in iterator) {
if (value !in elements) {
iterator.remove()
any = true
}
}
return any
}
override val size: Int
get() = setParent.size
override fun contains(element: MutableMap.MutableEntry<K, V>): Boolean {
return setParent.contains(element)
}
override fun containsAll(elements: Collection<MutableMap.MutableEntry<K, V>>): Boolean {
return setParent.containsAll(elements)
}
override fun isEmpty(): Boolean {
return setParent.isEmpty()
}
}
}
final override val keys: MutableSet<K> by lazy {
object : MutableSet<K> {
val parent = this@ProxiedMap.backingMap.keys
override fun add(element: K): Boolean {
throw UnsupportedOperationException()
}
override fun addAll(elements: Collection<K>): Boolean {
throw UnsupportedOperationException()
}
override fun clear() {
this@ProxiedMap.clear()
}
override fun iterator(): MutableIterator<K> {
return object : MutableIterator<K> {
private val parentIterator = parent.iterator()
private var last: K? = null
override fun hasNext(): Boolean {
return parentIterator.hasNext()
}
override fun next(): K {
return parentIterator.next().also { last = it }
}
override fun remove() {
val last = last ?: throw IllegalStateException("Never called next()")
val value = this@ProxiedMap[last] ?: throw ConcurrentModificationException()
parentIterator.remove()
onValueRemoved(last, value)
}
}
}
override fun remove(element: K): Boolean {
return this@ProxiedMap.remove(element) != null
}
override fun removeAll(elements: Collection<K>): Boolean {
var changes = false
for (element in elements) {
changes = remove(element) || changes
}
return changes
}
override fun retainAll(elements: Collection<K>): Boolean {
val iterator = this.iterator()
var any = false
for (element in iterator) {
if (element !in elements) {
iterator.remove()
any = true
}
}
return any
}
override val size: Int
get() = parent.size
override fun contains(element: K): Boolean {
return parent.contains(element)
}
override fun containsAll(elements: Collection<K>): Boolean {
return parent.containsAll(elements)
}
override fun isEmpty(): Boolean {
return parent.isEmpty()
}
}
}
final override val values: MutableCollection<V> by lazy {
object : MutableCollection<V> {
private val parent = this@ProxiedMap.backingMap.values
override val size: Int
get() = parent.size
override fun contains(element: V): Boolean {
return parent.contains(element)
}
override fun containsAll(elements: Collection<V>): Boolean {
return parent.containsAll(elements)
}
override fun isEmpty(): Boolean {
return parent.isEmpty()
}
override fun add(element: V): Boolean {
throw UnsupportedOperationException()
}
override fun addAll(elements: Collection<V>): Boolean {
throw UnsupportedOperationException()
}
override fun clear() {
this@ProxiedMap.clear()
}
override fun iterator(): MutableIterator<V> {
return object : MutableIterator<V> {
private val parentIterator = parent.iterator()
override fun hasNext(): Boolean {
return parentIterator.hasNext()
}
override fun next(): V {
return parentIterator.next()
}
override fun remove() {
parentIterator.remove()
}
}
}
override fun remove(element: V): Boolean {
val indexOf = this@ProxiedMap.backingMap.firstNotNullOfOrNull { if (it.value == element) it.key else null } ?: return false
this@ProxiedMap.remove(indexOf)
return true
}
override fun removeAll(elements: Collection<V>): Boolean {
var changes = false
for (element in elements) {
changes = remove(element) || changes
}
return changes
}
override fun retainAll(elements: Collection<V>): Boolean {
val iterator = this.iterator()
var changes = false
for (element in iterator) {
if (element !in elements) {
iterator.remove()
changes = true
}
}
return changes
}
}
}
override fun clear() {
onClear()
return backingMap.clear()
}
override fun put(key: K, value: V): V? {
val existing = backingMap.put(key, value)
if (existing == value) {
return existing
}
onValueAdded(key, value)
return existing
}
final override fun putAll(from: Map<out K, V>) {
for ((k, v) in from) {
this[k] = v
}
}
override fun remove(key: K): V? {
val removed = backingMap.remove(key)
if (removed != null) {
onValueRemoved(key, removed)
}
return removed
}
}

View File

@ -0,0 +1,421 @@
package ru.dbotthepony.kommons.collect
import java.util.*
import java.util.function.Predicate
import java.util.stream.Collector
import java.util.stream.Stream
import java.util.stream.StreamSupport
// Purpose of Stream API over Iterators is that it is simple enough for JIT to inline most of it,
// unlike actual Streams.
// We lose only one (actual) element of Stream API here: ability to parallelize work,
// except it doesn't (properly) work in Minecraft (Forge) either, due to classloader bug:
// https://github.com/MinecraftForge/EventBus/issues/44
// Aside parallel work, unimplemented Stream API elements can be easily implemented when required
private class FilteringIterator<T>(private val parent: Iterator<T>, private val predicate: Predicate<in T>, private var value: T) : MutableIterator<T> {
private var hasValue = true
private var returned = false
override fun hasNext(): Boolean {
return hasValue
}
override fun next(): T {
if (!hasValue) throw NoSuchElementException()
hasValue = false
returned = true
val value = this.value
while (parent.hasNext()) {
val next = parent.next()
if (predicate.test(next)) {
hasValue = true
this.value = next
break
}
}
return value
}
override fun remove() {
if (!returned) throw NoSuchElementException()
returned = false
(parent as MutableIterator<T>).remove()
}
}
private class MappingIterator<T, R>(private val parent: Iterator<T>, private val mapper: (T) -> R) : MutableIterator<R> {
override fun hasNext(): Boolean {
return parent.hasNext()
}
override fun next(): R {
return mapper.invoke(parent.next())
}
override fun remove() {
(parent as MutableIterator<T>).remove()
}
}
private class FlatMappingIterator<T, R>(private val parent: Iterator<T>, private val mapper: (T) -> Iterator<R>) : MutableIterator<R> {
private var current: Iterator<R> = mapper.invoke(parent.next())
private var last: Iterator<R>? = null
init {
while (!current.hasNext() && parent.hasNext()) {
current = mapper.invoke(parent.next())
}
}
override fun hasNext(): Boolean {
return current.hasNext()
}
override fun next(): R {
if (!current.hasNext())
throw NoSuchElementException()
val v = current.next()
last = current
while (!current.hasNext() && parent.hasNext()) {
current = mapper.invoke(parent.next())
}
return v
}
override fun remove() {
(last as MutableIterator<R>? ?: throw NoSuchElementException()).remove()
last = null
}
}
private class LimitingIterator<T>(private val parent: Iterator<T>, private val limit: Long) : Iterator<T> {
init {
require(limit > 0) { "Invalid limit $limit" }
}
private var found = 0L
override fun hasNext(): Boolean {
return found < limit && parent.hasNext()
}
override fun next(): T {
if (found >= limit)
throw NoSuchElementException()
return parent.next()
}
}
private class SkippingIterator<T>(private val parent: Iterator<T>, skip: Long) : MutableIterator<T> {
init {
require(skip >= 0) { "Invalid skip amount $skip" }
}
private var found = skip
private var returned = false
override fun hasNext(): Boolean {
while (parent.hasNext() && found > 0L) {
found--
parent.next()
}
return parent.hasNext()
}
override fun next(): T {
if (!hasNext())
throw NoSuchElementException()
val v = parent.next()
returned = true
return v
}
override fun remove() {
if (!returned) {
throw NoSuchElementException()
}
returned = false
(parent as MutableIterator<T>).remove()
}
}
fun <T> concatIterators(): MutableIterator<T> {
return listOf<T>().iterator() as MutableIterator<T>
}
fun <T> concatIterators(a: Iterator<T>): MutableIterator<T> {
return a as MutableIterator<T>
}
fun <T> concatIterators(iterators: Iterable<Iterator<T>>): MutableIterator<T> {
return iterators.iterator().flatMap { it }
}
fun <T> concatIterators(vararg iterators: Iterator<T>): MutableIterator<T> {
return iterators.iterator().flatMap { it }
}
/**
* Filters elements of [this] iterator
*
* Resulting [Iterator] is [MutableIterator] if [this] is
*/
fun <T> Iterator<T>.filter(condition: Predicate<in T>): MutableIterator<T> {
while (hasNext()) {
val v = next()
if (condition.test(v)) {
return FilteringIterator(this, condition, v)
}
}
return emptyIterator()
}
/**
* Maps elements of [this] iterator from values of [T] to [R] using function [mapper]
*
* Resulting [Iterator] is [MutableIterator] if [this] is
*/
fun <T, R> Iterator<T>.map(mapper: (T) -> R): MutableIterator<R> {
if (!hasNext()) {
return emptyIterator()
}
return MappingIterator(this, mapper)
}
/**
* Maps elements of [this] iterator from type [T] to other iterators of type [R] using function [mapper]
*
* Resulting [Iterator] is [MutableIterator] if [this] is
*/
fun <T, R> Iterator<T>.flatMap(mapper: (T) -> Iterator<R>): MutableIterator<R> {
if (!hasNext()) {
return emptyIterator()
}
return FlatMappingIterator(this, mapper)
}
inline fun <T> Iterator<T>.reduce(identity: T, reducer: (T, T) -> T): T {
var result = identity
while (hasNext()) result = reducer.invoke(result, next())
return result
}
fun <T> Iterator<T?>.filterNotNull(): MutableIterator<T> = filter { it != null } as MutableIterator<T>
inline fun <reified T> Iterator<*>.filterIsInstance(): MutableIterator<T> = filter { it is T } as MutableIterator<T>
fun <T> Iterator<T>.any(predicate: Predicate<in T>): Boolean {
while (hasNext())
if (predicate.test(next()))
return true
return false
}
inline fun <T> Iterator<T>.any(predicate: (T) -> Boolean): Boolean {
while (hasNext())
if (predicate.invoke(next()))
return true
return false
}
fun <T> Iterator<T>.all(predicate: Predicate<in T>): Boolean {
while (hasNext())
if (!predicate.test(next()))
return false
return true
}
inline fun <T> Iterator<T>.all(predicate: (T) -> Boolean): Boolean {
while (hasNext())
if (!predicate.invoke(next()))
return false
return true
}
fun <T> Iterator<T>.none(predicate: Predicate<in T>): Boolean {
while (hasNext())
if (predicate.test(next()))
return false
return true
}
inline fun <T> Iterator<T>.none(predicate: (T) -> Boolean): Boolean {
while (hasNext())
if (predicate.invoke(next()))
return false
return true
}
fun <T, A, R> Iterator<T>.collect(collector: Collector<T, A, R>): R {
val accumulator = collector.accumulator()
val instance = collector.supplier().get()
for (value in this) {
accumulator.accept(instance, value)
}
return collector.finisher().apply(instance)
}
fun <T> Iterator<T>.toList(expectedSize: Int = 16): MutableList<T> {
val result = ArrayList<T>(expectedSize)
result.addAll(this)
return result
}
fun <T> Iterator<T>.toImmutableList(expectedSize: Int = 16): List<T> {
if (!hasNext())
return emptyList()
return toList(expectedSize)
}
fun <T : Any> Iterator<T>.find(): Optional<T> {
if (hasNext()) {
return Optional.of(next())
}
return Optional.empty<T>()
}
fun <T> Iterator<T>.limit(limit: Long): Iterator<T> = LimitingIterator(this, limit)
fun <T> Iterator<T>.skip(skip: Long): Iterator<T> = if (skip == 0L) this else SkippingIterator(this, skip)
inline fun <T> Iterator<T>.forEach(action: (T) -> Unit) {
for (value in this) {
action.invoke(value)
}
}
fun <T : Any> Iterator<T>.min(comparator: Comparator<T>): Optional<T> {
if (!hasNext()) {
return Optional.empty<T>()
}
var min = next()
for (value in this) {
if (comparator.compare(min, value) > 0) {
min = value
}
}
return Optional.of(min)
}
fun <T : Any> Iterator<T>.max(comparator: Comparator<T>): Optional<T> {
if (!hasNext()) {
return Optional.empty<T>()
}
var max = next()
for (value in this) {
if (comparator.compare(max, value) < 0) {
max = value
}
}
return Optional.of(max)
}
fun <T> Iterator<T>.peek(peeker: (T) -> Unit): MutableIterator<T> {
return object : MutableIterator<T> {
override fun hasNext(): Boolean {
return this@peek.hasNext()
}
override fun next(): T {
return this@peek.next().also(peeker)
}
override fun remove() {
(this@peek as MutableIterator<T>).remove()
}
}
}
fun <T> Iterator<T>.maybe(): T? {
return if (hasNext())
next()
else
null
}
fun <T> emptyIterator(): MutableIterator<T> {
return emptyList<T>().iterator() as MutableIterator<T>
}
fun <T> iteratorOf(value: T): Iterator<T> {
return object : Iterator<T> {
private var next = true
private var v: T? = value
override fun hasNext(): Boolean {
return next
}
override fun next(): T {
if (!next)
throw NoSuchElementException()
val v = v
this.v = null
return v as T
}
}
}
fun <T> iteratorOf(vararg value: T): Iterator<T> {
return value.iterator()
}
fun <T> Iterator<T>.toStream(): Stream<T> {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(this, 0), false)
}
fun <T> Iterator<T>.allEqual(): Boolean {
if (hasNext()) {
val v = next()
while (hasNext()) {
if (v != next()) {
return false
}
}
return true
}
return false
}
fun <T> Iterator<T>.count(): Long {
var count = 0L
while (hasNext()) count++
return count
}

View File

@ -0,0 +1,43 @@
package ru.dbotthepony.kommons.collect
import java.util.concurrent.Future
import java.util.function.Supplier
import java.util.stream.Stream
class SupplierList<T> : AbstractList<T> {
private val getters: Array<Supplier<T>>
constructor(getters: Collection<Supplier<T>>) : super() {
val iterator = getters.iterator()
this.getters = Array(getters.size) { iterator.next() }
}
constructor(getters: Stream<Supplier<T>>) : super() {
this.getters = getters.toArray { arrayOfNulls<Supplier<T>>(it) }
}
constructor(vararg getters: Supplier<T>) : super() {
this.getters = Array(getters.size) { getters[it] }
}
constructor(size: Int, provider: (Int) -> Supplier<T>) {
this.getters = Array(size, provider)
}
override val size: Int
get() = getters.size
override fun get(index: Int): T {
return getters[index].get()
}
companion object {
fun <T> ofLazy(vararg values: Lazy<T>): SupplierList<T> {
return SupplierList(values.stream().map { Supplier { it.value } })
}
fun <T> ofFuture(vararg values: Future<T>): SupplierList<T> {
return SupplierList(values.stream().map { Supplier { it.get() } })
}
}
}

View File

@ -0,0 +1,55 @@
package ru.dbotthepony.kommons.collect
import java.util.Collections
import java.util.function.Supplier
import java.util.stream.Stream
class SupplierMap<K, T>(values: Stream<Pair<K, Supplier<T>>>) : Map<K, T> {
private val backing = HashMap<K, Supplier<T>>()
override val entries: Set<Map.Entry<K, T>>
override val keys: Set<K>
get() = backing.keys
override val size: Int
get() = entries.size
override val values: Collection<T>
init {
values.forEach {
backing[it.first] = it.second
}
entries = Collections.unmodifiableSet(HashSet(backing.entries.map { Entry(it.key, it.value) }))
this.values = SupplierList(backing.values)
}
override fun containsKey(key: K): Boolean {
return key in keys
}
override fun containsValue(value: T): Boolean {
return value in values
}
override fun get(key: K): T? {
return backing[key]?.get()
}
override fun isEmpty(): Boolean {
return entries.isEmpty()
}
constructor(vararg mValues: Pair<K, Supplier<T>>) : this((mValues as Array<Pair<K, Supplier<T>>>).stream())
constructor(mValues: Collection<Pair<K, Supplier<T>>>) : this(mValues.stream())
constructor(mValues: Map<K, Supplier<T>>) : this(mValues.entries.stream().map { it.key to it.value })
private inner class Entry(
override val key: K,
val getter: Supplier<T>
) : Map.Entry<K, T> {
override val value: T
get() = getter.get()
}
}

41
core/build.gradle.kts Normal file
View File

@ -0,0 +1,41 @@
plugins {
kotlin("jvm")
`maven-publish`
}
val coreVersion: String by project
val projectGroup: String by project
group = projectGroup
version = coreVersion
repositories {
mavenCentral()
}
dependencies {
testImplementation("org.jetbrains.kotlin:kotlin-test")
}
tasks.test {
useJUnitPlatform()
}
kotlin {
jvmToolchain(17)
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
from(components["java"])
pom {
dependencies {
implementation(kotlin("stdlib"))
}
}
}
}
}

View File

@ -0,0 +1,149 @@
package ru.dbotthepony.kommons.core
import ru.dbotthepony.kommons.event.ISubscriptable
import java.util.function.Consumer
import java.util.function.Supplier
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KMutableProperty0
import kotlin.reflect.KProperty
inline var <V> GetterSetter<V>.value: V
get() = get()
set(value) { accept(value) }
interface GetterSetter<V> : Supplier<V>, Consumer<V>, ReadWriteProperty<Any?, V> {
override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) {
accept(value)
}
override fun getValue(thisRef: Any?, property: KProperty<*>): V {
return get()
}
operator fun invoke(): V {
return get()
}
operator fun invoke(value: V) {
accept(value)
}
fun asGetterOnly(): GetterSetter<V> {
val self = this
return object : GetterSetter<V> {
override fun get(): V {
return self.get()
}
override fun accept(t: V) {
}
}
}
fun watch(watch: (old: V, new: V) -> Unit): GetterSetter<V> {
val self = this
return object : GetterSetter<V> by self {
override fun accept(t: V) {
val old = get()
self.accept(t)
watch.invoke(old, t)
}
}
}
companion object {
fun <V> of(getter: Supplier<V>, setter: Consumer<V>): GetterSetter<V> {
return object : GetterSetter<V> {
override fun get(): V {
return getter.get()
}
override fun accept(t: V) {
setter.accept(t)
}
}
}
fun <V> of(getter: () -> V, setter: (V) -> Unit): GetterSetter<V> {
return object : GetterSetter<V> {
override fun get(): V {
return getter.invoke()
}
override fun accept(t: V) {
setter.invoke(t)
}
}
}
fun <V> of(property: KMutableProperty0<V>): GetterSetter<V> {
return object : GetterSetter<V> {
override fun get(): V {
return property.get()
}
override fun accept(t: V) {
property.set(t)
}
}
}
fun <V> box(value: V): SentientGetterSetter<V> {
return object : SentientGetterSetter<V> {
private val subs = ISubscriptable.Impl<V>()
override fun addListener(listener: Consumer<V>): ISubscriptable.L {
return subs.addListener(listener)
}
private var value = value
override fun get(): V {
return value
}
override fun accept(t: V) {
this.value = t
subs.accept(t)
}
}
}
}
}
interface SentientGetterSetter<V> : GetterSetter<V>, ISubscriptable<V> {
override fun watch(watch: (old: V, new: V) -> Unit): SentientGetterSetter<V> {
val self = this
return object : SentientGetterSetter<V> by self {
override fun accept(t: V) {
val old = get()
self.accept(t)
watch.invoke(old, t)
}
}
}
}
operator fun <T> Supplier<T>.getValue(thisRef: Any?, property: KProperty<*>): T {
return get()
}
operator fun <T> Consumer<T>.setValue(thisRef: Any?, property: KProperty<*>, value: T) {
accept(value)
}
fun <V> KMutableProperty0<V>.asGetterSetter(watch: ((old: V, new: V) -> Unit)? = null): GetterSetter<V> {
return GetterSetter.of(this).let {
if (watch != null) {
it.watch(watch)
} else {
it
}
}
}
fun <V> KMutableProperty0<V>.asGetterOnly() = GetterSetter.of(Supplier { this.get() }, Consumer { /* do nothing */ })

View File

@ -0,0 +1,152 @@
package ru.dbotthepony.kommons.core
import java.util.function.Supplier
fun <T> KOptional(value: T) = KOptional.of(value)
fun KOptional(value: Boolean) = KOptional.of(value)
fun KOptional(value: Boolean?) = KOptional.of(value)
/**
* [java.util.Optional] supporting nulls
*
* This is done for structures, where value can be absent,
* or can be present, including literal "null" as possible present value,
* in more elegant solution than handling nullable Optionals
*/
class KOptional<T> private constructor(private val _value: T, val isPresent: Boolean) : Supplier<T> {
/**
* @throws NoSuchElementException
*/
val value: T get() {
if (isPresent) {
return _value
}
throw NoSuchElementException("No value is present")
}
inline fun ifPresent(block: (T) -> Unit): KOptional<T> {
if (isPresent) {
block.invoke(value)
}
return this
}
inline fun ifNotPresent(block: () -> Unit): KOptional<T> {
if (!isPresent) {
block.invoke()
}
return this
}
inline fun <R> map(block: (T) -> R): KOptional<R> {
if (isPresent) {
return of(block.invoke(value))
} else {
return empty()
}
}
@Suppress("NOTHING_TO_INLINE")
inline fun orElse(value: T): T {
if (isPresent) {
return this.value
} else {
return value
}
}
inline fun orElse(value: () -> T): T {
if (isPresent) {
return this.value
} else {
return value.invoke()
}
}
infix fun or(value: KOptional<T>): KOptional<T> {
if (isPresent) {
return this
} else {
return value
}
}
override fun equals(other: Any?): Boolean {
return this === other || other is KOptional<*> && isPresent == other.isPresent && _value == other._value
}
override fun hashCode(): Int {
return _value.hashCode() + 43839429
}
override fun toString(): String {
if (isPresent) {
return "KOptional[value = $value]"
} else {
return "KOptional[empty]"
}
}
override fun get(): T {
return value
}
// gson hack since type token can't diff between nullable and non-null types
@Deprecated("internal class")
internal class Nullable<T : Any?> private constructor()
@Deprecated("internal class")
internal class NotNull<T : Any> private constructor()
companion object {
private val EMPTY = KOptional(null, false)
private val NULL = KOptional(null, true)
private val TRUE = KOptional(true, true)
private val FALSE = KOptional(false, true)
@JvmStatic
fun <T> empty(): KOptional<T> {
return EMPTY as KOptional<T>
}
@JvmStatic
fun <T> of(value: T): KOptional<T> {
if (value == null) {
return NULL as KOptional<T>
} else {
return KOptional(value, true)
}
}
@JvmStatic
fun <T> ofNullable(value: T): KOptional<T> {
if (value == null) {
return EMPTY as KOptional<T>
} else {
return KOptional(value, true)
}
}
@JvmStatic
fun of(value: Boolean): KOptional<Boolean> {
if (value) {
return TRUE
} else {
return FALSE
}
}
@JvmStatic
fun of(value: Boolean?): KOptional<Boolean> {
if (value == null) {
return NULL as KOptional<Boolean>
} else if (value) {
return TRUE
} else {
return FALSE
}
}
}
}

View File

@ -0,0 +1,43 @@
package ru.dbotthepony.kommons.event
import ru.dbotthepony.kommons.util.BooleanConsumer
import java.util.function.Consumer
interface IBooleanSubscriptable : ISubscriptable<Boolean> {
@Deprecated("Use type specific listener")
override fun addListener(listener: Consumer<Boolean>): ISubscriptable.L {
return addListener(listener::accept)
}
fun addListener(listener: BooleanConsumer): ISubscriptable.L
class Impl : IBooleanSubscriptable, Consumer<Boolean>, BooleanConsumer {
private inner class L(val callback: BooleanConsumer) : ISubscriptable.L {
private var isRemoved = false
init {
subscribers.add(this)
}
override fun remove() {
if (!isRemoved) {
isRemoved = true
queue.add(this)
}
}
}
private val subscribers = LinkedHashSet<L>(0)
private val queue = ArrayList<L>(0)
override fun addListener(listener: BooleanConsumer): ISubscriptable.L {
return L(listener)
}
override fun accept(t: Boolean) {
queue.forEach { subscribers.remove(it) }
queue.clear()
subscribers.forEach { it.callback.accept(t) }
}
}
}

View File

@ -0,0 +1,43 @@
package ru.dbotthepony.kommons.event
import java.util.function.Consumer
import java.util.function.DoubleConsumer
interface IDoubleSubcripable : ISubscriptable<Double> {
@Deprecated("Use type specific listener")
override fun addListener(listener: Consumer<Double>): ISubscriptable.L {
return addListener(DoubleConsumer { listener.accept(it) })
}
fun addListener(listener: DoubleConsumer): ISubscriptable.L
class Impl : IDoubleSubcripable, Consumer<Double>, DoubleConsumer {
private inner class L(val callback: DoubleConsumer) : ISubscriptable.L {
private var isRemoved = false
init {
subscribers.add(this)
}
override fun remove() {
if (!isRemoved) {
isRemoved = true
queue.add(this)
}
}
}
private val subscribers = LinkedHashSet<L>(0)
private val queue = ArrayList<L>(0)
override fun addListener(listener: DoubleConsumer): ISubscriptable.L {
return L(listener)
}
override fun accept(t: Double) {
queue.forEach { subscribers.remove(it) }
queue.clear()
subscribers.forEach { it.callback.accept(t) }
}
}
}

View File

@ -0,0 +1,43 @@
package ru.dbotthepony.kommons.event
import ru.dbotthepony.kommons.util.FloatConsumer
import java.util.function.Consumer
interface IFloatSubcripable : ISubscriptable<Float> {
@Deprecated("Use type specific listener")
override fun addListener(listener: Consumer<Float>): ISubscriptable.L {
return addListener(listener::accept)
}
fun addListener(listener: FloatConsumer): ISubscriptable.L
class Impl : IFloatSubcripable, Consumer<Float>, FloatConsumer {
private inner class L(val callback: FloatConsumer) : ISubscriptable.L {
private var isRemoved = false
init {
subscribers.add(this)
}
override fun remove() {
if (!isRemoved) {
isRemoved = true
queue.add(this)
}
}
}
private val subscribers = LinkedHashSet<L>(0)
private val queue = ArrayList<L>(0)
override fun addListener(listener: FloatConsumer): ISubscriptable.L {
return L(listener)
}
override fun accept(t: Float) {
queue.forEach { subscribers.remove(it) }
queue.clear()
subscribers.forEach { it.callback.accept(t) }
}
}
}

View File

@ -0,0 +1,43 @@
package ru.dbotthepony.kommons.event
import java.util.function.Consumer
import java.util.function.IntConsumer
interface IIntSubcripable : ISubscriptable<Int> {
@Deprecated("Use type specific listener")
override fun addListener(listener: Consumer<Int>): ISubscriptable.L {
return addListener(IntConsumer { listener.accept(it) })
}
fun addListener(listener: IntConsumer): ISubscriptable.L
class Impl : IIntSubcripable, Consumer<Int>, IntConsumer {
private inner class L(val callback: IntConsumer) : ISubscriptable.L {
private var isRemoved = false
init {
subscribers.add(this)
}
override fun remove() {
if (!isRemoved) {
isRemoved = true
queue.add(this)
}
}
}
private val subscribers = LinkedHashSet<L>(0)
private val queue = ArrayList<L>(0)
override fun addListener(listener: IntConsumer): ISubscriptable.L {
return L(listener)
}
override fun accept(t: Int) {
queue.forEach { subscribers.remove(it) }
queue.clear()
subscribers.forEach { it.callback.accept(t) }
}
}
}

View File

@ -0,0 +1,43 @@
package ru.dbotthepony.kommons.event
import java.util.function.Consumer
import java.util.function.LongConsumer
interface ILongSubcripable : ISubscriptable<Long> {
@Deprecated("Use type specific listener")
override fun addListener(listener: Consumer<Long>): ISubscriptable.L {
return addListener(LongConsumer { listener.accept(it) })
}
fun addListener(listener: LongConsumer): ISubscriptable.L
class Impl : ILongSubcripable, Consumer<Long>, LongConsumer {
private inner class L(val callback: LongConsumer) : ISubscriptable.L {
private var isRemoved = false
init {
subscribers.add(this)
}
override fun remove() {
if (!isRemoved) {
isRemoved = true
queue.add(this)
}
}
}
private val subscribers = LinkedHashSet<L>(0)
private val queue = ArrayList<L>(0)
override fun addListener(listener: LongConsumer): ISubscriptable.L {
return L(listener)
}
override fun accept(t: Long) {
queue.forEach { subscribers.remove(it) }
queue.clear()
subscribers.forEach { it.callback.accept(t) }
}
}
}

View File

@ -0,0 +1,60 @@
package ru.dbotthepony.kommons.event
import java.util.function.Consumer
interface ISubscriptable<V> {
/**
* Listener token, allows to remove listener from subscriber list
*/
fun interface L {
/**
* Removes this listener
*/
fun remove()
}
fun addListener(listener: Consumer<V>): L
class Impl<V> : ISubscriptable<V>, Consumer<V> {
private inner class L(val callback: Consumer<V>) : ISubscriptable.L {
private var isRemoved = false
init {
subscribers.add(this)
}
override fun remove() {
if (!isRemoved) {
isRemoved = true
queue.add(this)
}
}
}
private val subscribers = LinkedHashSet<L>(0)
private val queue = ArrayList<L>(0)
override fun addListener(listener: Consumer<V>): ISubscriptable.L {
return L(listener)
}
override fun accept(t: V) {
queue.forEach { subscribers.remove(it) }
queue.clear()
subscribers.forEach { it.callback.accept(t) }
}
}
companion object : ISubscriptable<Nothing>, L {
@Suppress("unchecked_cast")
fun <T> empty(): ISubscriptable<T> {
return this as ISubscriptable<T>
}
override fun remove() {}
override fun addListener(listener: Consumer<Nothing>): L {
return this
}
}
}

View File

@ -0,0 +1,41 @@
package ru.dbotthepony.kommons.event
import java.util.function.Consumer
interface IUnitSubscripable : ISubscriptable<Unit> {
fun addListener(listener: Runnable): ISubscriptable.L
override fun addListener(listener: Consumer<Unit>): ISubscriptable.L {
return addListener(Runnable { listener.accept(Unit) })
}
class Impl : IUnitSubscripable, Runnable {
private inner class L(val callback: Runnable) : ISubscriptable.L {
private var isRemoved = false
init {
subscribers.add(this)
}
override fun remove() {
if (!isRemoved) {
isRemoved = true
queue.add(this)
}
}
}
private val subscribers = LinkedHashSet<L>(0)
private val queue = ArrayList<L>(0)
override fun addListener(listener: Runnable): ISubscriptable.L {
return L(listener)
}
override fun run() {
queue.forEach { subscribers.remove(it) }
queue.clear()
subscribers.forEach { it.callback.run() }
}
}
}

View File

@ -0,0 +1,7 @@
package ru.dbotthepony.kommons.util
import java.util.function.Consumer
fun interface BooleanConsumer : Consumer<Boolean> {
override fun accept(value: Boolean)
}

View File

@ -0,0 +1,38 @@
package ru.dbotthepony.kommons.util
import java.util.function.Supplier
fun <T> Comparator<T>.nullsFirst(): Comparator<T> {
return Comparator.nullsFirst(this)
}
fun <T> Comparator<T>.nullsLast(): Comparator<T> {
return Comparator.nullsLast(this)
}
class MappedComparator<T, O>(private val parent: Comparator<O>, private val mapper: (T) -> O) : Comparator<T> {
override fun compare(o1: T, o2: T): Int {
return parent.compare(mapper.invoke(o1), mapper.invoke(o2))
}
override fun equals(other: Any?): Boolean {
return other is MappedComparator<*, *> && parent == other.parent
}
override fun hashCode(): Int {
return parent.hashCode()
}
override fun toString(): String {
return "MappedComparator[$parent]"
}
}
fun <A, B> Comparator<A>.map(mapper: (B) -> A): Comparator<B> {
return MappedComparator(this, mapper)
}
fun <T> Comparator<T>.suppliers(): Comparator<Supplier<T>> {
return MappedComparator(this) { it.get() }
}

View File

@ -0,0 +1,7 @@
package ru.dbotthepony.kommons.util
import java.util.function.Consumer
fun interface FloatConsumer : Consumer<Float> {
override fun accept(value: Float)
}

View File

@ -0,0 +1,12 @@
package ru.dbotthepony.kommons.util
import java.util.function.Supplier
fun interface FloatSupplier : Supplier<Float> {
fun getAsFloat(): Float
@Deprecated("Use type-specific method", replaceWith = ReplaceWith("this.getAsFloat()"))
override fun get(): Float {
return getAsFloat()
}
}

14
gradle.properties Normal file
View File

@ -0,0 +1,14 @@
kotlin.code.style=official
projectGroup=ru.dbotthepony.kommons
guavaDepVersion=33.0.0
kommonsVersion=1.0
coreVersion=1.0
ioVersion=1.0
networkingVersion=1.0
mathVersion=1.0
collectVersion=1.0
guavaVersion=1.0

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,6 @@
#Sat Feb 03 12:42:21 KRAT 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

234
gradlew vendored Normal file
View File

@ -0,0 +1,234 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

89
gradlew.bat vendored Normal file
View File

@ -0,0 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

43
guava/build.gradle.kts Normal file
View File

@ -0,0 +1,43 @@
plugins {
kotlin("jvm")
`maven-publish`
}
val guavaVersion: String by project
val guavaDepVersion: String by project
val projectGroup: String by project
group = projectGroup
version = guavaVersion
repositories {
mavenCentral()
}
dependencies {
testImplementation("org.jetbrains.kotlin:kotlin-test")
implementation("com.google.guava:guava:$guavaDepVersion-jre")
}
tasks.test {
useJUnitPlatform()
}
kotlin {
jvmToolchain(17)
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
from(components["java"])
pom {
dependencies {
implementation(kotlin("stdlib"))
}
}
}
}
}

View File

@ -0,0 +1,54 @@
package ru.dbotthepony.kommons.collect
import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableMap
import com.google.common.collect.ImmutableMultimap
import com.google.common.collect.ImmutableSet
import java.util.function.Consumer
inline fun <T : Any> immutableList(size: Int, initializer: (index: Int) -> T): ImmutableList<T> {
require(size >= 0) { "Invalid list size $size" }
return when (size) {
0 -> ImmutableList.of()
1 -> ImmutableList.of(initializer(0))
else -> ImmutableList.Builder<T>().let {
for (i in 0 until size) {
it.add(initializer(i))
}
it.build()
}
}
}
inline fun <K : Any, V : Any> immutableMap(initializer: ImmutableMap.Builder<K, V>.() -> Unit): ImmutableMap<K, V> {
val builder = ImmutableMap.Builder<K, V>()
initializer.invoke(builder)
return builder.build()
}
inline fun <K : Any, V : Any> immutableMultimap(initializer: ImmutableMultimap.Builder<K, V>.() -> Unit): ImmutableMultimap<K, V> {
val builder = ImmutableMultimap.Builder<K, V>()
initializer.invoke(builder)
return builder.build()
}
inline fun <V : Any> immutableSet(initializer: Consumer<V>.() -> Unit): ImmutableSet<V> {
val builder = ImmutableSet.Builder<V>()
initializer.invoke(builder::add)
return builder.build()
}
inline fun <V : Any> immutableList(initializer: Consumer<V>.() -> Unit): ImmutableList<V> {
val builder = ImmutableList.Builder<V>()
initializer.invoke(builder::add)
return builder.build()
}
fun <V : Any> immutableList(a: V, vararg values: V): ImmutableList<V> {
val builder = ImmutableList.Builder<V>()
builder.add(a)
builder.addAll(values.iterator())
return builder.build()
}

44
io-math/build.gradle.kts Normal file
View File

@ -0,0 +1,44 @@
plugins {
kotlin("jvm")
`maven-publish`
}
val kommonsVersion: String by project
val projectGroup: String by project
group = projectGroup
version = kommonsVersion
repositories {
mavenCentral()
}
dependencies {
testImplementation("org.jetbrains.kotlin:kotlin-test")
implementation(project(":io"))
implementation(project(":math"))
}
tasks.test {
useJUnitPlatform()
}
kotlin {
jvmToolchain(17)
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
from(components["java"])
pom {
dependencies {
implementation(kotlin("stdlib"))
implementation(project(":io"))
implementation(project(":math"))
}
}
}
}
}

View File

@ -0,0 +1,23 @@
package ru.dbotthepony.kommons.io
import ru.dbotthepony.kommons.math.Decimal
import java.io.DataInputStream
import java.io.DataOutputStream
import java.io.InputStream
import java.io.OutputStream
fun InputStream.readDecimal(): Decimal {
val size = readVarInt()
require(size >= 0) { "Negative payload size: $size" }
val bytes = ByteArray(size)
read(bytes)
return Decimal.fromByteArray(bytes)
}
fun OutputStream.writeDecimal(value: Decimal) {
val bytes = value.toByteArray()
writeVarInt(bytes.size)
write(bytes)
}
val DecimalValueCodec = StreamCodec(DataInputStream::readDecimal, DataOutputStream::writeDecimal)

42
io/build.gradle.kts Normal file
View File

@ -0,0 +1,42 @@
plugins {
kotlin("jvm")
`maven-publish`
}
val ioVersion: String by project
val projectGroup: String by project
group = projectGroup
version = ioVersion
repositories {
mavenCentral()
}
dependencies {
testImplementation("org.jetbrains.kotlin:kotlin-test")
implementation(project(":core"))
}
tasks.test {
useJUnitPlatform()
}
kotlin {
jvmToolchain(17)
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
from(components["java"])
pom {
dependencies {
implementation(kotlin("stdlib"))
implementation(project(":core"))
}
}
}
}
}

View File

@ -0,0 +1,34 @@
package ru.dbotthepony.kommons.io
import java.io.DataInputStream
import java.io.DataOutputStream
class CollectionStreamCodec<E, C : MutableCollection<E>>(val elementCodec: IStreamCodec<E>, val collectionFactory: (Int) -> C) :
IStreamCodec<C> {
override fun read(stream: DataInputStream): C {
val size = stream.readVarInt()
if (size <= 0) {
return collectionFactory.invoke(0)
}
val collection = collectionFactory.invoke(size)
for (i in 0 until size) {
collection.add(elementCodec.read(stream))
}
return collection
}
override fun write(stream: DataOutputStream, value: C) {
stream.writeVarInt(value.size)
value.forEach { elementCodec.write(stream, it) }
}
override fun copy(value: C): C {
val new = collectionFactory.invoke(value.size)
value.forEach { new.add(elementCodec.copy(it)) }
return new
}
}

View File

@ -0,0 +1,48 @@
package ru.dbotthepony.kommons.io
import java.io.DataInputStream
import java.io.DataOutputStream
class EnumValueCodec<V : Enum<V>>(clazz: Class<out V>) : IStreamCodec<V> {
val clazz = searchClass(clazz)
val values: List<V> = listOf(*this.clazz.enumConstants!!)
val valuesMap = values.associateBy { it.name }
override fun read(stream: DataInputStream): V {
val id = stream.readVarInt()
return values.getOrNull(id) ?: throw NoSuchElementException("No such enum with index $id")
}
override fun write(stream: DataOutputStream, value: V) {
stream.writeVarInt(value.ordinal)
}
override fun copy(value: V): V {
return value
}
override fun compare(a: V, b: V): Boolean {
return a === b
}
companion object {
/**
* FIXME: enums with abstract methods which get compiled to subclasses, whose DO NOT expose "parent's" enum constants array
*
* is there an already existing solution?
*/
fun <V : Enum<V>> searchClass(clazz: Class<out V>): Class<out V> {
var search: Class<*> = clazz
while (search.enumConstants == null && search.superclass != null) {
search = search.superclass
}
if (search.enumConstants == null) {
throw ClassCastException("$clazz does not represent an enum or enum subclass")
}
return search as Class<out V>
}
}
}

View File

@ -0,0 +1,28 @@
package ru.dbotthepony.kommons.io
import java.io.DataInputStream
import java.io.DataOutputStream
/**
* Represents value which can be encoded onto or decoded from stream.
*
* Also provides [copy] and [compare] methods
*/
interface IStreamCodec<V> {
fun read(stream: DataInputStream): V
fun write(stream: DataOutputStream, value: V)
/**
* if value is immutable, return it right away
*/
fun copy(value: V): V
/**
* Optional equality check override. Utilized to determine whenever e.g. network value is different from new value
*
* By default uses [Any.equals]
*/
fun compare(a: V, b: V): Boolean {
return a == b
}
}

View File

@ -0,0 +1,151 @@
package ru.dbotthepony.kommons.io
import java.io.DataInput
import java.io.InputStream
import java.io.RandomAccessFile
import java.math.BigDecimal
import java.math.BigInteger
import java.util.function.IntSupplier
fun InputStream.readBigDecimal(): BigDecimal {
val scale = readInt()
val size = readVarInt()
require(size >= 0) { "Negative payload size: $size" }
val bytes = ByteArray(size)
read(bytes)
return BigDecimal(BigInteger(bytes), scale)
}
fun <S : InputStream, V, C : MutableCollection<V>> S.readCollection(reader: S.() -> V, factory: (Int) -> C): C {
val size = readVarInt()
val collection = factory.invoke(size)
for (i in 0 until size) {
collection.add(reader(this))
}
return collection
}
fun <S : InputStream, V> S.readCollection(reader: S.() -> V) = readCollection(reader, ::ArrayList)
fun InputStream.readInt(): Int {
if (this is DataInput) {
return readInt()
}
return (read() shl 24) or (read() shl 16) or (read() shl 8) or read()
}
fun InputStream.readLong(): Long {
if (this is DataInput) {
return readLong()
}
return (read().toLong() shl 48) or
(read().toLong() shl 40) or
(read().toLong() shl 32) or
(read().toLong() shl 24) or
(read().toLong() shl 16) or
(read().toLong() shl 8) or
read().toLong()
}
fun InputStream.readFloat() = Float.fromBits(readInt())
fun InputStream.readDouble() = Double.fromBits(readLong())
data class VarIntReadResult(val value: Int, val cells: Int)
data class VarLongReadResult(val value: Long, val cells: Int)
private fun readVarLongInfo(supplier: IntSupplier): VarLongReadResult {
var result = 0L
var read = supplier.asInt
var i = 1
while (true) {
result = (result shl 7) or (read.toLong() and 0x7F)
if (read and 0x80 == 0)
break
read = supplier.asInt
i++
}
return VarLongReadResult(result, i)
}
private fun readVarIntInfo(supplier: IntSupplier): VarIntReadResult {
val read = readVarLongInfo(supplier)
return VarIntReadResult(read.value.toInt(), read.cells)
}
private fun readVarInt(supplier: IntSupplier): Int {
return readVarIntInfo(supplier).value
}
private fun readVarLong(supplier: IntSupplier): Long {
return readVarLongInfo(supplier).value
}
private fun Int.fromSignedVar(): Int {
val sign = this and 1
if (sign == 0)
return this ushr 1
else
return -(this ushr 1) - 1
}
private fun VarIntReadResult.fromSignedVar(): VarIntReadResult {
val sign = this.value and 1
if (sign == 0)
return VarIntReadResult(this.value ushr 1, this.cells)
else
return VarIntReadResult(-(this.value ushr 1) - 1, this.cells)
}
private fun Long.fromSignedVar(): Long {
val sign = this and 1
if (sign == 0L)
return this ushr 1
else
return -(this ushr 1) - 1L
}
private fun VarLongReadResult.fromSignedVar(): VarLongReadResult {
val sign = this.value and 1
if (sign == 0L)
return VarLongReadResult(this.value ushr 1, this.cells)
else
return VarLongReadResult(-(this.value ushr 1) - 1, this.cells)
}
fun RandomAccessFile.readVarLong() = readVarLong(::readUnsignedByte)
fun RandomAccessFile.readVarInt() = readVarInt(::readUnsignedByte)
fun RandomAccessFile.readVarLongInfo() = readVarLongInfo(::readUnsignedByte)
fun RandomAccessFile.readVarIntInfo() = readVarIntInfo(::readUnsignedByte)
fun InputStream.readVarLong() = readVarLong(::read)
fun InputStream.readVarInt() = readVarInt(::read)
fun InputStream.readVarLongInfo() = readVarLongInfo(::read)
fun InputStream.readVarIntInfo() = readVarIntInfo(::read)
fun RandomAccessFile.readSignedVarLong() = readVarLong(::readUnsignedByte).fromSignedVar()
fun RandomAccessFile.readSignedVarInt() = readVarInt(::readUnsignedByte).fromSignedVar()
fun RandomAccessFile.readSignedVarLongInfo() = readVarLongInfo(::readUnsignedByte).fromSignedVar()
fun RandomAccessFile.readSignedVarIntInfo() = readVarIntInfo(::readUnsignedByte).fromSignedVar()
fun InputStream.readSignedVarLong() = readVarLong(::read).fromSignedVar()
fun InputStream.readSignedVarInt() = readVarInt(::read).fromSignedVar()
fun InputStream.readSignedVarLongInfo() = readVarLongInfo(::read).fromSignedVar()
fun InputStream.readSignedVarIntInfo() = readVarIntInfo(::read).fromSignedVar()
fun InputStream.readBinaryString(): String {
val size = readVarInt()
require(size >= 0) { "Negative payload size: $size" }
val bytes = ByteArray(size)
read(bytes)
return bytes.decodeToString()
}

View File

@ -0,0 +1,105 @@
package ru.dbotthepony.kommons.io
import java.io.DataOutput
import java.io.OutputStream
import java.io.RandomAccessFile
import java.math.BigDecimal
import java.util.function.IntConsumer
fun OutputStream.writeBigDecimal(value: BigDecimal) {
writeInt(value.scale())
val bytes = value.unscaledValue().toByteArray()
writeVarInt(bytes.size)
write(bytes)
}
fun <S : OutputStream, V> S.writeCollection(collection: Collection<V>, writer: S.(V) -> Unit) {
writeVarInt(collection.size)
for (value in collection) {
writer(this, value)
}
}
fun OutputStream.writeInt(value: Int) {
if (this is DataOutput) {
writeInt(value)
return
}
write(value ushr 24)
write(value ushr 16)
write(value ushr 8)
write(value)
}
fun OutputStream.writeLong(value: Long) {
if (this is DataOutput) {
writeLong(value)
return
}
write((value ushr 48).toInt())
write((value ushr 40).toInt())
write((value ushr 32).toInt())
write((value ushr 24).toInt())
write((value ushr 16).toInt())
write((value ushr 8).toInt())
write(value.toInt())
}
fun OutputStream.writeFloat(value: Float) = writeInt(value.toBits())
fun OutputStream.writeDouble(value: Double) = writeLong(value.toBits())
private fun writeVarLong(write: IntConsumer, value: Long): Int {
var value = value
var i = 0
do {
val toWrite = (value and 0x7F).toInt()
value = value ushr 7
if (value == 0L)
write.accept(toWrite)
else
write.accept(toWrite or 0x80)
i++
} while (value != 0L)
return i
}
private fun writeVarInt(write: IntConsumer, value: Int): Int {
return writeVarLong(write, value.toLong())
}
private fun Int.toSignedVar(): Int {
if (this >= 0)
return this shl 1
else
return (this shl 1) or 1
}
private fun Long.toSignedVar(): Long {
if (this >= 0)
return this shl 1
else
return ((-this - 1) shl 1) or 1L
}
fun RandomAccessFile.writeVarLong(value: Long) = writeVarLong(::write, value)
fun RandomAccessFile.writeVarInt(value: Int) = writeVarInt(::write, value)
fun OutputStream.writeVarLong(value: Long) = writeVarLong(::write, value)
fun OutputStream.writeVarInt(value: Int) = writeVarInt(::write, value)
fun RandomAccessFile.writeSignedVarLong(value: Long) = writeVarLong(::write, value.toSignedVar())
fun RandomAccessFile.writeSignedVarInt(value: Int) = writeVarInt(::write, value.toSignedVar())
fun OutputStream.writeSignedVarLong(value: Long) = writeVarLong(::write, value.toSignedVar())
fun OutputStream.writeSignedVarInt(value: Int) = writeVarInt(::write, value.toSignedVar())
fun OutputStream.writeBinaryString(input: String) {
val bytes = input.encodeToByteArray()
writeVarInt(bytes.size)
write(bytes)
}

View File

@ -0,0 +1,77 @@
package ru.dbotthepony.kommons.io
import java.io.DataInputStream
import java.io.DataOutputStream
import java.util.*
import kotlin.reflect.KClass
class StreamCodec<V>(
private val reader: (stream: DataInputStream) -> V,
private val writer: (stream: DataOutputStream, value: V) -> Unit,
private val copier: ((value: V) -> V) = { it },
private val comparator: ((a: V, b: V) -> Boolean) = { a, b -> a == b }
) : IStreamCodec<V> {
constructor(
reader: (stream: DataInputStream) -> V,
payloadSize: Long,
writer: (stream: DataOutputStream, value: V) -> Unit,
copier: ((value: V) -> V) = { it },
comparator: ((a: V, b: V) -> Boolean) = { a, b -> a == b }
) : this({ stream -> reader.invoke(stream) }, writer, copier, comparator)
val nullable = object : IStreamCodec<V?> {
override fun read(stream: DataInputStream): V? {
return if (stream.read() == 0) null else reader.invoke(stream)
}
override fun write(stream: DataOutputStream, value: V?) {
if (value === null) stream.write(0) else {
stream.write(1)
writer.invoke(stream, value)
}
}
override fun copy(value: V?): V? {
return if (value === null) null else copier.invoke(value)
}
override fun compare(a: V?, b: V?): Boolean {
if (a === null && b === null) return true
if (a === null || b === null) return false
return comparator.invoke(a, b)
}
}
override fun read(stream: DataInputStream): V {
return reader.invoke(stream)
}
override fun write(stream: DataOutputStream, value: V) {
writer.invoke(stream, value)
}
override fun copy(value: V): V {
return copier.invoke(value)
}
override fun compare(a: V, b: V): Boolean {
return comparator.invoke(a, b)
}
}
val NullValueCodec = StreamCodec({ _ -> null }, { _, _ -> })
val BooleanValueCodec = StreamCodec(DataInputStream::readBoolean, 1L, DataOutputStream::writeBoolean) { a, b -> a == b }
val ByteValueCodec = StreamCodec(DataInputStream::readByte, 1L, { s, v -> s.writeByte(v.toInt()) }) { a, b -> a == b }
val ShortValueCodec = StreamCodec(DataInputStream::readShort, 2L, { s, v -> s.writeShort(v.toInt()) }) { a, b -> a == b }
val IntValueCodec = StreamCodec(DataInputStream::readInt, 4L, DataOutputStream::writeInt) { a, b -> a == b }
val LongValueCodec = StreamCodec(DataInputStream::readLong, 8L, DataOutputStream::writeLong) { a, b -> a == b }
val FloatValueCodec = StreamCodec(DataInputStream::readFloat, 4L, DataOutputStream::writeFloat) { a, b -> a == b }
val DoubleValueCodec = StreamCodec(DataInputStream::readDouble, 8L, DataOutputStream::writeDouble) { a, b -> a == b }
val BigDecimalValueCodec = StreamCodec(DataInputStream::readBigDecimal, DataOutputStream::writeBigDecimal)
val UUIDValueCodec = StreamCodec({ s -> UUID(s.readLong(), s.readLong()) }, { s, v -> s.writeLong(v.mostSignificantBits); s.writeLong(v.leastSignificantBits) })
val VarIntValueCodec = StreamCodec(DataInputStream::readSignedVarInt, DataOutputStream::writeSignedVarInt) { a, b -> a == b }
val VarLongValueCodec = StreamCodec(DataInputStream::readSignedVarLong, DataOutputStream::writeSignedVarLong) { a, b -> a == b }
val BinaryStringCodec = StreamCodec(DataInputStream::readBinaryString, DataOutputStream::writeBinaryString)
fun <E : Enum<E>> Class<E>.codec() = EnumValueCodec(this)
fun <E : Enum<E>> KClass<E>.codec() = EnumValueCodec(this.java)

40
math/build.gradle.kts Normal file
View File

@ -0,0 +1,40 @@
plugins {
kotlin("jvm")
`maven-publish`
}
val mathVersion: String by project
val projectGroup: String by project
group = projectGroup
version = mathVersion
repositories {
mavenCentral()
}
dependencies {
testImplementation("org.jetbrains.kotlin:kotlin-test")
}
tasks.test {
useJUnitPlatform()
}
kotlin {
jvmToolchain(17)
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
from(components["java"])
pom {
dependencies {
implementation(kotlin("stdlib"))
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,53 @@
package ru.dbotthepony.kommons.math
class HSVColor(hue: Float, saturation: Float, value: Float) : Comparable<HSVColor> {
val hue = (hue % 360f).let { if (it < 0f) it + 360f else it }
val saturation = saturation.coerceIn(0f, 1f)
val value = value.coerceIn(0f, 1f)
override fun equals(other: Any?): Boolean {
return other === this || other is HSVColor && other.hue == hue && other.saturation == saturation && other.value == value
}
override fun hashCode(): Int {
return hue.hashCode() + saturation.hashCode() * 31 + value.hashCode() * 31 * 31
}
fun copy(hue: Float = this.hue, saturation: Float = this.saturation, value: Float = this.value): HSVColor {
return HSVColor(hue, saturation, value)
}
operator fun component1() = hue
operator fun component2() = saturation
operator fun component3() = value
fun toRGBA(alpha: Float = 1f): RGBAColor {
val valueMin = (1f - saturation) * value
val delta = (value - valueMin) * (hue % 60f) / 60f
val valueInc = valueMin + delta
val valueDec = value - delta
return when ((hue / 60f).toInt()) {
0 -> RGBAColor(value, valueInc, valueMin, alpha)
1 -> RGBAColor(valueDec, value, valueMin, alpha)
2 -> RGBAColor(valueMin, value, valueInc, alpha)
3 -> RGBAColor(valueMin, valueDec, value, alpha)
4 -> RGBAColor(valueInc, valueMin, value, alpha)
5 -> RGBAColor(value, valueMin, valueDec, alpha)
else -> throw IllegalStateException("whut")
}
}
override fun compareTo(other: HSVColor): Int {
return comparator.compare(this, other)
}
companion object {
@JvmField val WHITE = HSVColor(0f, 1f, 1f)
private val comparator = Comparator
.comparing(HSVColor::hue)
.thenComparing(HSVColor::saturation)
.thenComparing(HSVColor::value)
}
}

View File

@ -0,0 +1,299 @@
package ru.dbotthepony.kommons.math
import kotlin.math.roundToInt
private fun hex(value: Int): String {
require(value in 0 .. 255)
val v = value.toString(16)
if (v.length == 1)
return "0$v"
else
return v
}
class RGBAColor(red: Float, green: Float, blue: Float, alpha: Float = 1f) : Comparable<RGBAColor> {
constructor(r: Int, g: Int, b: Int) : this((r / 255f), (g / 255f), (b / 255f), 1f)
constructor(r: Int, g: Int, b: Int, a: Int) : this((r / 255f), (g / 255f), (b / 255f), (a / 255f))
constructor(r: Int, g: Int, b: Int, a: Float) : this((r / 255f), (g / 255f), (b / 255f), a)
val red = red.coerceIn(0f, 1f)
val green = green.coerceIn(0f, 1f)
val blue = blue.coerceIn(0f, 1f)
val alpha = alpha.coerceIn(0f, 1f)
val redInt get() = (red * 255f).roundToInt()
val greenInt get() = (green * 255f).roundToInt()
val blueInt get() = (blue * 255f).roundToInt()
val alphaInt get() = (alpha * 255f).roundToInt()
fun toRGBA(): Int {
return (redInt shl 24) or (greenInt shl 16) or (blueInt shl 8) or alphaInt
}
fun toARGB(): Int {
return (alphaInt shl 24) or (redInt shl 16) or (greenInt shl 8) or blueInt
}
fun toBGRA(): Int {
return (blueInt shl 24) or (greenInt shl 16) or (redInt shl 8) or alphaInt
}
val isFullyTransparent get() = alpha <= 0f
val isWhite: Boolean get() = red >= 1f && green >= 1f && blue >= 1f && alpha >= 1f
fun canRepresentHue(): Boolean {
val min = red.coerceAtMost(green).coerceAtMost(blue)
val max = red.coerceAtLeast(green).coerceAtLeast(blue)
return min != max
}
fun hue(ifNoHue: Float = 0f): Float {
val min = red.coerceAtMost(green).coerceAtMost(blue)
val max = red.coerceAtLeast(green).coerceAtLeast(blue)
if (min == max) {
return ifNoHue
}
val diff = max - min
return if (max == red && green >= blue) {
60f * (green - blue) / diff
} else if (max == red) {
60f * (green - blue) / diff + 360f
} else if (max == green) {
60f * (blue - red) / diff + 120f
} else if (max == blue) {
60f * (red - green) / diff + 240f
} else {
throw IllegalStateException("Whut $red $green $blue ($min / $max)")
}
}
fun toHSV(): HSVColor {
val min = red.coerceAtMost(green).coerceAtMost(blue)
val max = red.coerceAtLeast(green).coerceAtLeast(blue)
if (min == max) {
return HSVColor(0f, if (max == 0f) 0f else 1f - min / max, max)
}
val diff = max - min
val hue = if (max == red && green >= blue) {
60f * (green - blue) / diff
} else if (max == red) {
60f * (green - blue) / diff + 360f
} else if (max == green) {
60f * (blue - red) / diff + 120f
} else if (max == blue) {
60f * (red - green) / diff + 240f
} else {
throw IllegalStateException("Whut $red $green $blue ($min / $max)")
}
return HSVColor(hue, 1f - min / max, max)
}
fun toHexStringRGB(): String {
return "#${hex(redInt)}${hex(greenInt)}${hex(blueInt)}"
}
fun toHexStringRGBA(): String {
return "#${hex(redInt)}${hex(greenInt)}${hex(blueInt)}${hex(alphaInt)}"
}
fun toHexStringARGB(): String {
return "#${hex(alphaInt)}${hex(redInt)}${hex(greenInt)}${hex(blueInt)}"
}
override fun toString(): String {
return "RGBAColor[$red $green $blue $alpha]"
}
operator fun component1() = red
operator fun component2() = green
operator fun component3() = blue
operator fun component4() = alpha
fun toIntInv(): Int {
return (blueInt shl 16) or (greenInt shl 8) or redInt
}
fun toRGB(): Int {
return (redInt shl 16) or (greenInt shl 8) or blueInt
}
fun copy(red: Float = this.red, green: Float = this.green, blue: Float = this.blue, alpha: Float = this.alpha): RGBAColor {
return RGBAColor(red, green, blue, alpha)
}
override fun compareTo(other: RGBAColor): Int {
if (canRepresentHue() && other.canRepresentHue())
return hue().compareTo(other.hue()).let {
if (it != 0)
it
else
toHSV().compareTo(other.toHSV())
}
return comparator.compare(this, other)
}
override fun equals(other: Any?): Boolean {
return other === this || other is RGBAColor && comparator.compare(this, other) == 0
}
override fun hashCode(): Int {
return red.hashCode() + green.hashCode() * 31 + blue.hashCode() * 31 * 31 + alpha.hashCode() * 31 * 31 * 31
}
/*fun linearInterpolation(t: Float, other: RGBAColor, interpolateAlpha: Boolean = true): RGBAColor {
return RGBAColor(
linearInterpolation(t, red, other.red),
linearInterpolation(t, green, other.green),
linearInterpolation(t, blue, other.blue),
if (interpolateAlpha) linearInterpolation(t, alpha, other.alpha) else alpha,
)
}*/
operator fun times(other: RGBAColor): RGBAColor {
if (isWhite)
return other
else if (other.isWhite)
return this
return RGBAColor(red * other.red, green * other.green, blue * other.blue, alpha * other.alpha)
}
@Suppress("unused")
companion object {
private val comparator = Comparator
.comparing(RGBAColor::red)
.thenComparing(RGBAColor::green)
.thenComparing(RGBAColor::blue)
.thenComparing(RGBAColor::alpha)
@JvmField val TRANSPARENT_BLACK = RGBAColor(0f, 0f, 0f, 0f)
@JvmField val TRANSPARENT_WHITE = RGBAColor(1f, 1f, 1f, 0f)
@JvmField val BLACK = RGBAColor(0f, 0f, 0f)
@JvmField val WHITE = RGBAColor(1f, 1f, 1f)
@JvmField val RED = RGBAColor(1f, 0f, 0f)
@JvmField val GREEN = RGBAColor(0f, 1f, 0f)
@JvmField val LIGHT_GREEN = RGBAColor(136, 255, 124)
@JvmField val SLATE_GRAY = RGBAColor(64, 64, 64)
@JvmField val GRAY = rgb(0x2C2C2CL)
@JvmField val LIGHT_GRAY = rgb(0x7F7F7FL)
@JvmField val HEADING_TEXT = rgb(0x404040L)
@JvmField val LOW_POWER = RGBAColor(173, 41, 41)
@JvmField val FULL_POWER = RGBAColor(255, 242, 40)
@JvmField val LOW_MATTER = RGBAColor(0, 24, 148)
@JvmField val FULL_MATTER = RGBAColor(72, 90, 255)
@JvmField val LOW_PATTERNS = RGBAColor(44, 104, 57)
@JvmField val FULL_PATTERNS = RGBAColor(65, 255, 87)
@JvmField val HALF_TRANSPARENT = RGBAColor(1f, 1f, 1f, 0.5f)
@JvmField val REDDISH = RGBAColor(1f, 0.4f, 0.4f)
fun rgb(color: Int): RGBAColor {
val r = (color and 0xFF0000 ushr 16) / 255f
val g = (color and 0xFF00 ushr 8) / 255f
val b = (color and 0xFF) / 255f
return RGBAColor(r, g, b)
}
fun rgb(color: Long): RGBAColor {
val r = (color and 0xFF0000 ushr 16) / 255f
val g = (color and 0xFF00 ushr 8) / 255f
val b = (color and 0xFF) / 255f
return RGBAColor(r, g, b)
}
fun bgr(color: Int): RGBAColor {
val r = (color and 0xFF0000 ushr 16) / 255f
val g = (color and 0xFF00 ushr 8) / 255f
val b = (color and 0xFF) / 255f
return RGBAColor(b, g, r)
}
fun bgr(color: Long): RGBAColor {
val r = (color and 0xFF0000 ushr 16) / 255f
val g = (color and 0xFF00 ushr 8) / 255f
val b = (color and 0xFF) / 255f
return RGBAColor(b, g, r)
}
fun abgr(color: Int): RGBAColor {
val r = (color and -0x1000000 ushr 24) / 255f
val g = (color and 0xFF0000 ushr 16) / 255f
val b = (color and 0xFF00 ushr 8) / 255f
val a = (color and 0xFF) / 255f
return RGBAColor(a, b, g, r)
}
fun argb(color: Int): RGBAColor {
val a = (color and -0x1000000 ushr 24) / 255f
val r = (color and 0xFF0000 ushr 16) / 255f
val g = (color and 0xFF00 ushr 8) / 255f
val b = (color and 0xFF) / 255f
return RGBAColor(r, g, b, a)
}
private val hexChars = HashSet<Char>()
init {
"#0123456789abcdefABCDEF".forEach { hexChars.add(it) }
}
fun isHexCharacter(char: Char): Boolean {
return char in hexChars
}
private val shorthandRGBHex = Regex("#?([0-9abcdef])([0-9abcdef])([0-9abcdef])", RegexOption.IGNORE_CASE)
private val longhandRGBHex = Regex("#?([0-9abcdef]{2})([0-9abcdef]{2})([0-9abcdef]{2})", RegexOption.IGNORE_CASE)
private val shorthandRGBAHex = Regex("#?([0-9abcdef])([0-9abcdef])([0-9abcdef])([0-9abcdef])", RegexOption.IGNORE_CASE)
private val longhandRGBAHex = Regex("#?([0-9abcdef]{2})([0-9abcdef]{2})([0-9abcdef]{2})([0-9abcdef]{2})", RegexOption.IGNORE_CASE)
fun fromHexStringRGB(value: String): RGBAColor? {
if (value.length == 3 || value.length == 4) {
val match = shorthandRGBHex.find(value) ?: return null
val red = match.groupValues[1].toIntOrNull(16) ?: return null
val green = match.groupValues[2].toIntOrNull(16) ?: return null
val blue = match.groupValues[3].toIntOrNull(16) ?: return null
return RGBAColor(red * 16, green * 16, blue * 16)
} else if (value.length == 6 || value.length == 7) {
val match = longhandRGBHex.find(value) ?: return null
val red = match.groupValues[1].toIntOrNull(16) ?: return null
val green = match.groupValues[2].toIntOrNull(16) ?: return null
val blue = match.groupValues[3].toIntOrNull(16) ?: return null
return RGBAColor(red, green, blue)
} else {
return null
}
}
fun fromHexStringRGBA(value: String): RGBAColor? {
if (value.length == 4 || value.length == 5) {
val match = shorthandRGBAHex.find(value) ?: return null
val red = match.groupValues[1].toIntOrNull(16) ?: return null
val green = match.groupValues[2].toIntOrNull(16) ?: return null
val blue = match.groupValues[3].toIntOrNull(16) ?: return null
val alpha = match.groupValues[4].toIntOrNull(16) ?: return null
return RGBAColor(red * 16, green * 16, blue * 16, alpha * 16)
} else if (value.length == 8 || value.length == 9) {
val match = longhandRGBAHex.find(value) ?: return null
val red = match.groupValues[1].toIntOrNull(16) ?: return null
val green = match.groupValues[2].toIntOrNull(16) ?: return null
val blue = match.groupValues[3].toIntOrNull(16) ?: return null
val alpha = match.groupValues[4].toIntOrNull(16) ?: return null
return RGBAColor(red, green, blue, alpha)
} else {
return null
}
}
}
}

View File

@ -0,0 +1,47 @@
plugins {
kotlin("jvm")
`maven-publish`
}
val networkingVersion: String by project
val projectGroup: String by project
group = projectGroup
version = networkingVersion
repositories {
mavenCentral()
}
dependencies {
testImplementation("org.jetbrains.kotlin:kotlin-test")
implementation(project(":core"))
implementation(project(":io"))
implementation(project(":collect"))
}
tasks.test {
useJUnitPlatform()
}
kotlin {
jvmToolchain(17)
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
from(components["java"])
pom {
dependencies {
implementation(kotlin("stdlib"))
implementation(project(":core"))
implementation(project(":io"))
implementation(project(":collect"))
}
}
}
}
}

View File

@ -0,0 +1,5 @@
package ru.dbotthepony.kommons.networking
enum class ChangesetAction {
CLEAR, ADD, REMOVE
}

View File

@ -0,0 +1,41 @@
package ru.dbotthepony.kommons.networking
interface FieldAccess<V> {
fun read(): V
fun write(value: V)
}
interface FloatFieldAccess : FieldAccess<Float> {
override fun write(value: Float)
@Deprecated("Use type specific method", replaceWith = ReplaceWith("this.readFloat()"))
override fun read() = readFloat()
fun readFloat(): Float
}
interface DoubleFieldAccess : FieldAccess<Double> {
override fun write(value: Double)
@Deprecated("Use type specific method", replaceWith = ReplaceWith("this.readDouble()"))
override fun read() = readDouble()
fun readDouble(): Double
}
interface IntFieldAccess : FieldAccess<Int> {
override fun write(value: Int)
@Deprecated("Use type specific method", replaceWith = ReplaceWith("this.readInt()"))
override fun read() = readInt()
fun readInt(): Int
}
interface LongFieldAccess : FieldAccess<Long> {
override fun write(value: Long)
@Deprecated("Use type specific method", replaceWith = ReplaceWith("this.readLong()"))
override fun read() = readLong()
fun readLong(): Long
}
interface BooleanFieldAccess : FieldAccess<Boolean> {
override fun write(value: Boolean)
@Deprecated("Use type specific method", replaceWith = ReplaceWith("this.readBoolean()"))
override fun read() = readBoolean()
fun readBoolean(): Boolean
}

View File

@ -0,0 +1,50 @@
package ru.dbotthepony.kommons.networking
fun interface FieldGetter<V> {
fun invoke(field: FieldAccess<V>): V
}
fun interface FloatFieldGetter : FieldGetter<Float> {
fun invoke(field: FloatFieldAccess): Float
@Deprecated("Use type specific invoke")
override fun invoke(field: FieldAccess<Float>): Float {
return invoke(field as FloatFieldAccess)
}
}
fun interface DoubleFieldGetter : FieldGetter<Double> {
fun invoke(field: DoubleFieldAccess): Double
@Deprecated("Use type specific invoke")
override fun invoke(field: FieldAccess<Double>): Double {
return invoke(field as DoubleFieldAccess)
}
}
fun interface IntFieldGetter : FieldGetter<Int> {
fun invoke(field: IntFieldAccess): Int
@Deprecated("Use type specific invoke")
override fun invoke(field: FieldAccess<Int>): Int {
return invoke(field as IntFieldAccess)
}
}
fun interface LongFieldGetter : FieldGetter<Long> {
fun invoke(field: LongFieldAccess): Long
@Deprecated("Use type specific invoke")
override fun invoke(field: FieldAccess<Long>): Long {
return invoke(field as LongFieldAccess)
}
}
fun interface BooleanFieldGetter : FieldGetter<Boolean> {
fun invoke(field: BooleanFieldAccess): Boolean
@Deprecated("Use type specific invoke")
override fun invoke(field: FieldAccess<Boolean>): Boolean {
return invoke(field as BooleanFieldAccess)
}
}

View File

@ -0,0 +1,50 @@
package ru.dbotthepony.kommons.networking
fun interface FieldSetter<V> {
fun invoke(value: V, access: FieldAccess<V>, setByRemote: Boolean)
}
fun interface FloatFieldSetter : FieldSetter<Float> {
fun invoke(value: Float, access: FloatFieldAccess, setByRemote: Boolean)
@Deprecated("Use type specific invoke")
override fun invoke(value: Float, access: FieldAccess<Float>, setByRemote: Boolean) {
invoke(value, access as FloatFieldAccess, setByRemote)
}
}
fun interface DoubleFieldSetter : FieldSetter<Double> {
fun invoke(value: Double, access: DoubleFieldAccess, setByRemote: Boolean)
@Deprecated("Use type specific invoke")
override fun invoke(value: Double, access: FieldAccess<Double>, setByRemote: Boolean) {
invoke(value, access as DoubleFieldAccess, setByRemote)
}
}
fun interface IntFieldSetter : FieldSetter<Int> {
fun invoke(value: Int, access: IntFieldAccess, setByRemote: Boolean)
@Deprecated("Use type specific invoke")
override fun invoke(value: Int, access: FieldAccess<Int>, setByRemote: Boolean) {
invoke(value, access as IntFieldAccess, setByRemote)
}
}
fun interface LongFieldSetter : FieldSetter<Long> {
fun invoke(value: Long, access: LongFieldAccess, setByRemote: Boolean)
@Deprecated("Use type specific invoke")
override fun invoke(value: Long, access: FieldAccess<Long>, setByRemote: Boolean) {
invoke(value, access as LongFieldAccess, setByRemote)
}
}
fun interface BooleanFieldSetter : FieldSetter<Boolean> {
fun invoke(value: Boolean, access: BooleanFieldAccess, setByRemote: Boolean)
@Deprecated("Use type specific invoke")
override fun invoke(value: Boolean, access: FieldAccess<Boolean>, setByRemote: Boolean) {
invoke(value, access as BooleanFieldAccess, setByRemote)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,173 @@
package ru.dbotthepony.kommons.networking
import ru.dbotthepony.kommons.event.IBooleanSubscriptable
import ru.dbotthepony.kommons.event.IDoubleSubcripable
import ru.dbotthepony.kommons.event.IFloatSubcripable
import ru.dbotthepony.kommons.event.IIntSubcripable
import ru.dbotthepony.kommons.event.ILongSubcripable
import ru.dbotthepony.kommons.event.ISubscriptable
import ru.dbotthepony.kommons.util.FloatSupplier
import java.io.DataInputStream
import java.io.DataOutputStream
import java.util.function.BooleanSupplier
import java.util.function.DoubleSupplier
import java.util.function.IntSupplier
import java.util.function.LongSupplier
import java.util.function.Supplier
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
sealed interface IField<V> : ReadOnlyProperty<Any?, V>, Supplier<V>, () -> V, ISubscriptable<V> {
fun observe(): Boolean
fun markDirty()
fun markDirty(endpoint: FieldSynchronizer.Endpoint)
val value: V
val isRemoved: Boolean
fun remove()
fun write(stream: DataOutputStream, endpoint: FieldSynchronizer.Endpoint)
fun read(stream: DataInputStream)
override fun getValue(thisRef: Any?, property: KProperty<*>): V {
return this.value
}
override fun get(): V {
return value
}
override fun invoke(): V {
return value
}
}
interface IFloatProperty {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Float
}
sealed interface IFloatField : IField<Float>, FloatSupplier, IFloatSubcripable {
val float: Float
val property: IFloatProperty
override val value: Float
get() = float
@Deprecated("Use type specific Supplier interface")
override fun get(): Float {
return float
}
override fun getAsFloat(): Float {
return float
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Float {
return float
}
}
interface IDoubleProperty {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Double
}
sealed interface IDoubleField : IField<Double>, DoubleSupplier, IDoubleSubcripable {
val double: Double
val property: IDoubleProperty
@Deprecated("Use type specific Supplier interface")
override fun get(): Double {
return double
}
override val value: Double
get() = double
override fun getAsDouble(): Double {
return double
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Double {
return double
}
}
interface IIntProperty {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Int
}
sealed interface IIntField : IField<Int>, IntSupplier, IIntSubcripable {
val int: Int
val property: IIntProperty
@Deprecated("Use type specific Supplier interface")
override fun get(): Int {
return int
}
override val value: Int
get() = int
override fun getAsInt(): Int {
return int
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Int {
return int
}
}
interface ILongProperty {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Long
}
sealed interface ILongField : IField<Long>, LongSupplier, ILongSubcripable {
val long: Long
val property: ILongProperty
@Deprecated("Use type specific Supplier interface")
override fun get(): Long {
return long
}
override val value: Long
get() = long
override fun getAsLong(): Long {
return long
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Long {
return long
}
}
interface IBooleanProperty {
operator fun getValue(thisRef: Any?, property: KProperty<*>): Boolean
}
sealed interface IBooleanField : IField<Boolean>, BooleanSupplier, IBooleanSubscriptable {
val boolean: Boolean
val property: IBooleanProperty
@Deprecated("Use type specific Supplier interface")
override fun get(): Boolean {
return boolean
}
override val value: Boolean
get() = boolean
override fun getAsBoolean(): Boolean {
return boolean
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean {
return boolean
}
}

View File

@ -0,0 +1,23 @@
package ru.dbotthepony.kommons.networking
data class MapChangeset<out K, out V>(
val action: ChangesetAction,
val key: K?,
val value: V?
) {
inline fun map(add: (K, V) -> Unit, remove: (K) -> Unit) {
when (action) {
ChangesetAction.ADD -> add.invoke(key!!, value!!)
ChangesetAction.REMOVE -> remove.invoke(key!!)
else -> {}
}
}
inline fun map(add: (K, V) -> Unit, remove: (K) -> Unit, clear: () -> Unit) {
when (action) {
ChangesetAction.CLEAR -> clear.invoke()
ChangesetAction.ADD -> add.invoke(key!!, value!!)
ChangesetAction.REMOVE -> remove.invoke(key!!)
}
}
}

View File

@ -0,0 +1,165 @@
package ru.dbotthepony.kommons.networking
import ru.dbotthepony.kommons.util.FloatConsumer
import ru.dbotthepony.kommons.core.SentientGetterSetter
import ru.dbotthepony.kommons.util.BooleanConsumer
import java.util.function.DoubleConsumer
import java.util.function.IntConsumer
import java.util.function.LongConsumer
import kotlin.reflect.KProperty
sealed interface IMutableField<V> : IField<V>, SentientGetterSetter<V> {
override fun getValue(thisRef: Any?, property: KProperty<*>): V {
return this.value
}
override var value: V
override fun accept(t: V) {
value = t
}
override fun invoke(): V {
return this.value
}
}
interface IMutableFloatProperty : IFloatProperty {
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Float)
}
sealed interface IMutableFloatField : IMutableField<Float>, IFloatField, FloatConsumer {
override var float: Float
override val property: IMutableFloatProperty
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.float"))
override var value: Float
get() = float
set(value) { float = value }
override fun accept(t: Float) {
float = t
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Float {
return float
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Float) {
float = value
}
}
interface IMutableDoubleProperty : IDoubleProperty {
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Double)
}
sealed interface IMutableDoubleField : IMutableField<Double>, IDoubleField, DoubleConsumer {
override var double: Double
override val property: IMutableDoubleProperty
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.double"))
override var value: Double
get() = double
set(value) { double = value }
override fun accept(t: Double) {
double = t
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Double {
return double
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Double) {
double = value
}
}
interface IMutableIntProperty : IIntProperty {
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int)
}
sealed interface IMutableIntField : IMutableField<Int>, IIntField, IntConsumer {
override var int: Int
override val property: IMutableIntProperty
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.int"))
override var value: Int
get() = int
set(value) { int = value }
override fun accept(t: Int) {
int = t
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Int {
return int
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) {
int = value
}
}
interface IMutableLongProperty : ILongProperty {
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Long)
}
sealed interface IMutableLongField : IMutableField<Long>, ILongField, LongConsumer {
override var long: Long
override val property: IMutableLongProperty
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.long"))
override var value: Long
get() = long
set(value) { long = value }
override fun accept(t: Long) {
long = t
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Long {
return long
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Long) {
long = value
}
}
interface IMutableBooleanProperty : IBooleanProperty {
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean)
}
sealed interface IMutableBooleanField : IMutableField<Boolean>, IBooleanField, BooleanConsumer {
override var boolean: Boolean
override val property: IMutableBooleanProperty
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.boolean"))
override var value: Boolean
get() = boolean
set(value) { boolean = value }
override fun accept(t: Boolean) {
boolean = t
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun getValue(thisRef: Any?, property: KProperty<*>): Boolean {
return boolean
}
@Deprecated("Use type specific property", replaceWith = ReplaceWith("this.property"))
override fun setValue(thisRef: Any?, property: KProperty<*>, value: Boolean) {
boolean = value
}
}

View File

@ -0,0 +1,22 @@
package ru.dbotthepony.kommons.networking
data class SetChangeset<out V>(
val action: ChangesetAction,
val value: V?
) {
inline fun map(add: (V) -> Unit, remove: (V) -> Unit) {
when (action) {
ChangesetAction.ADD -> add.invoke(value!!)
ChangesetAction.REMOVE -> remove.invoke(value!!)
else -> {}
}
}
inline fun map(add: (V) -> Unit, remove: (V) -> Unit, clear: () -> Unit) {
when (action) {
ChangesetAction.CLEAR -> clear.invoke()
ChangesetAction.ADD -> add.invoke(value!!)
ChangesetAction.REMOVE -> remove.invoke(value!!)
}
}
}

14
settings.gradle.kts Normal file
View File

@ -0,0 +1,14 @@
plugins {
//kotlin("jvm") version "1.9.21"
id("org.gradle.toolchains.foojay-resolver-convention") version "0.5.0"
}
rootProject.name = "kommons"
include("core")
include("networking")
include("io")
include("math")
include("io-math")
include("collect")
include("guava")