From 218bb17cc456772cf28cf15700ee32c7e8e819f7 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Tue, 22 Aug 2023 11:35:00 +0700 Subject: [PATCH] Faster filtering and flatmapping iterators --- .../mc/otm/core/collect/StreamyIterators.kt | 189 +++++++++--------- 1 file changed, 89 insertions(+), 100 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/StreamyIterators.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/StreamyIterators.kt index 5377de346..3a925efff 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/StreamyIterators.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/StreamyIterators.kt @@ -1,11 +1,15 @@ package ru.dbotthepony.mc.otm.core.collect +import it.unimi.dsi.fastutil.ints.Int2IntFunction +import it.unimi.dsi.fastutil.ints.IntIterator +import it.unimi.dsi.fastutil.ints.IntIterators import it.unimi.dsi.fastutil.objects.ObjectIterators import ru.dbotthepony.mc.otm.core.addAll import java.util.Optional import java.util.Spliterator import java.util.Spliterators import java.util.function.BinaryOperator +import java.util.function.IntPredicate import java.util.function.Predicate import java.util.function.Supplier import java.util.stream.Collector @@ -21,68 +25,43 @@ import java.util.stream.StreamSupport // Aside parallel work, unimplemented Stream API elements can be easily implemented when required -/** - * Filters elements of [parent] iterator - * - * Resulting [Iterator] is [MutableIterator] if [parent] is - */ -class FilteringIterator(private val parent: Iterator, private val predicate: Predicate) : MutableIterator { - private var foundValue: Any? = Companion +private class FilteringIterator(private val parent: Iterator, private val predicate: Predicate) : MutableIterator { + private var value: T = parent.next() + private var hasValue = true private var returned = false override fun hasNext(): Boolean { - if (foundValue === Companion) { - while (parent.hasNext()) { - val next = parent.next() - - if (predicate.test(next)) { - foundValue = next - return true - } - } - - return false - } - - return true + return hasValue } - @Suppress("unchecked_cast") override fun next(): T { - var foundValue = foundValue + if (!hasValue) throw NoSuchElementException() + hasValue = false + returned = true - if (foundValue === Companion) { - if (!hasNext()) { - throw NoSuchElementException() - } + val value = this.value - foundValue = this.foundValue + while (parent.hasNext()) { + val next = parent.next() - if (foundValue === Companion) { - throw ConcurrentModificationException() + if (predicate.test(next)) { + hasValue = true + this.value = next + break } } - this.foundValue = Companion - returned = true - return foundValue as T + return value } override fun remove() { if (!returned) throw NoSuchElementException() - (parent as MutableIterator).remove() returned = false + (parent as MutableIterator).remove() } - - private companion object } -/** - * Maps elements of [parent] iterator from values of [T] to [R] using function [mapper] - * - * Resulting [Iterator] is [MutableIterator] if [parent] is - */ -class MappingIterator(private val parent: Iterator, private val mapper: (T) -> R) : MutableIterator { +private class MappingIterator(private val parent: Iterator, private val mapper: (T) -> R) : MutableIterator { override fun hasNext(): Boolean { return parent.hasNext() } @@ -96,29 +75,28 @@ class MappingIterator(private val parent: Iterator, private val mapper: } } -/** - * Maps elements of [parent] iterator from type [T] to other iterators of type [R] using function [mapper] - * - * Resulting [Iterator] is [MutableIterator] if [parent] is - */ -class FlatMappingIterator(private val parent: Iterator, private val mapper: (T) -> Iterator) : MutableIterator { - private var current: Iterator? = null +private class FlatMappingIterator(private val parent: Iterator, private val mapper: (T) -> Iterator) : MutableIterator { + private var current: Iterator = mapper.invoke(parent.next()) private var last: Iterator? = null + private var hasNext = current.hasNext() override fun hasNext(): Boolean { - while (current?.hasNext() != true && parent.hasNext()) { - current = mapper.invoke(parent.next()) - } - - return current?.hasNext() == true + return hasNext } override fun next(): R { - if (!hasNext()) + if (!hasNext) throw NoSuchElementException() - val v = current!!.next() + val v = current.next() last = current + hasNext = false + + while (!hasNext && parent.hasNext()) { + current = mapper.invoke(parent.next()) + hasNext = current.hasNext() + } + return v } @@ -128,12 +106,7 @@ class FlatMappingIterator(private val parent: Iterator, private val map } } -/** - * Limits amount of values returned by [parent] iterator to return at most [limit] values - * - * Resulting [Iterator] is [MutableIterator] if [parent] is - */ -class LimitingIterator(private val parent: Iterator, private val limit: Long) : Iterator { +private class LimitingIterator(private val parent: Iterator, private val limit: Long) : Iterator { init { require(limit > 0) { "Invalid limit $limit" } } @@ -152,12 +125,7 @@ class LimitingIterator(private val parent: Iterator, private val limit: Lo } } -/** - * Skips (discards) up to [skip] values returned by [parent] iterator - * - * Resulting [Iterator] is [MutableIterator] if [parent] is - */ -class SkippingIterator(private val parent: Iterator, skip: Long) : MutableIterator { +private class SkippingIterator(private val parent: Iterator, skip: Long) : MutableIterator { init { require(skip >= 0) { "Invalid skip amount $skip" } } @@ -214,71 +182,92 @@ fun concatIterators(vararg iterators: Iterator): MutableIterator { * * Resulting [Iterator] is [MutableIterator] if [this] is */ -fun Iterator.filter(condition: Predicate) = FilteringIterator(this, condition) +fun Iterator.filter(condition: Predicate): MutableIterator { + if (!hasNext()) { + return emptyIterator() + } + + return FilteringIterator(this, condition) +} /** * Maps elements of [this] iterator from values of [T] to [R] using function [mapper] * * Resulting [Iterator] is [MutableIterator] if [this] is */ -fun Iterator.map(mapper: (T) -> R) = MappingIterator(this, mapper) +fun Iterator.map(mapper: (T) -> R): MutableIterator { + if (!hasNext()) { + return emptyIterator() + } -/** - * Maps elements of [this] iterator from values of [T] to [R] using function [mapper] - * - * Resulting [Iterator] is [MutableIterator] if [this] is - */ -fun Iterator.map(mapper: java.util.function.Function) = MappingIterator(this, mapper::apply) + 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 Iterator.flatMap(mapper: (T) -> Iterator) = FlatMappingIterator(this, mapper) +fun Iterator.flatMap(mapper: (T) -> Iterator): MutableIterator { + if (!hasNext()) { + return emptyIterator() + } -/** - * 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 Iterator.flatMap(mapper: java.util.function.Function>) = FlatMappingIterator(this, mapper::apply) + return FlatMappingIterator(this, mapper) +} -fun Iterator.reduce(identity: T, reducer: (T, T) -> T): T { +inline fun Iterator.reduce(identity: T, reducer: (T, T) -> T): T { var result = identity - for (value in this) result = reducer.invoke(result, value) + while (hasNext()) result = reducer.invoke(result, next()) return result } -fun Iterator.reduce(identity: T, reducer: BinaryOperator): T = reduce(identity, reducer::apply) fun Iterator.filterNotNull(): MutableIterator = filter { it != null } as MutableIterator fun Iterator.any(predicate: Predicate): Boolean { - for (value in this) { - if (predicate.test(value)) { + while (hasNext()) + if (predicate.test(next())) + return true + + return false +} + +inline fun Iterator.any(predicate: (T) -> Boolean): Boolean { + while (hasNext()) + if (predicate.invoke(next())) return true - } - } return false } fun Iterator.all(predicate: Predicate): Boolean { - for (value in this) { - if (!predicate.test(value)) { + while (hasNext()) + if (!predicate.test(next())) + return false + + return true +} + +inline fun Iterator.all(predicate: (T) -> Boolean): Boolean { + while (hasNext()) + if (!predicate.invoke(next())) return false - } - } return true } fun Iterator.none(predicate: Predicate): Boolean { - for (value in this) { - if (predicate.test(value)) { + while (hasNext()) + if (predicate.test(next())) + return false + + return true +} + +inline fun Iterator.none(predicate: (T) -> Boolean): Boolean { + while (hasNext()) + if (predicate.invoke(next())) return false - } - } return true } @@ -308,8 +297,8 @@ fun Iterator.find(): Optional { return Optional.empty() } -fun Iterator.limit(limit: Long) = LimitingIterator(this, limit) -fun Iterator.skip(skip: Long) = if (skip == 0L) this else SkippingIterator(this, skip) +fun Iterator.limit(limit: Long): Iterator = LimitingIterator(this, limit) +fun Iterator.skip(skip: Long): Iterator = if (skip == 0L) this else SkippingIterator(this, skip) inline fun Iterator.forEach(action: (T) -> Unit) { for (value in this) {