mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-06 08:00:10 +08:00
Improve ExceptionCollector.collect for better performance, close #1308
This commit is contained in:
parent
ef439f1dea
commit
71b128b06c
@ -12,9 +12,7 @@ package net.mamoe.mirai.utils
|
|||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
public class ExceptionCollector : Sequence<Throwable> {
|
public class ExceptionCollector {
|
||||||
|
|
||||||
// TODO: 2021/4/20 drop last
|
|
||||||
|
|
||||||
public constructor()
|
public constructor()
|
||||||
public constructor(initial: Throwable?) {
|
public constructor(initial: Throwable?) {
|
||||||
@ -29,20 +27,14 @@ public class ExceptionCollector : Sequence<Throwable> {
|
|||||||
|
|
||||||
@Volatile
|
@Volatile
|
||||||
private var last: Throwable? = null
|
private var last: Throwable? = null
|
||||||
|
private val hashCodes = mutableSetOf<Int>()
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
public fun collect(e: Throwable?) {
|
public fun collect(e: Throwable?) {
|
||||||
if (e == null) return
|
if (e == null) return
|
||||||
val last = last
|
val hashCode = e.stackTrace.contentHashCode()
|
||||||
if (last != null) {
|
if (!hashCodes.add(hashCode)) return // filter out duplications
|
||||||
last.itr().forEach { suppressed ->
|
// we can also check suppressed exceptions of [e] but actual influence would be slight.
|
||||||
if (suppressed.stackTrace.contentEquals(e.stackTrace)) {
|
|
||||||
// filter out useless duplicates.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
e.addSuppressed(last)
|
|
||||||
}
|
|
||||||
this.last = e
|
this.last = e
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,14 +64,18 @@ public class ExceptionCollector : Sequence<Throwable> {
|
|||||||
@DslMarker
|
@DslMarker
|
||||||
private annotation class TerminalOperation
|
private annotation class TerminalOperation
|
||||||
|
|
||||||
private fun Throwable.itr(): Iterator<Throwable> {
|
@TestOnly
|
||||||
return (sequenceOf(this) + this.suppressed.asSequence().flatMap { it.itr().asSequence() }).iterator()
|
public fun asSequence(): Sequence<Throwable> {
|
||||||
|
fun Throwable.itr(): Iterator<Throwable> {
|
||||||
|
return (sequenceOf(this) + this.suppressed.asSequence().flatMap { it.itr().asSequence() }).iterator()
|
||||||
|
}
|
||||||
|
|
||||||
|
return Sequence {
|
||||||
|
val last = getLast() ?: return@Sequence emptyList<Throwable>().iterator()
|
||||||
|
last.itr()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun iterator(): Iterator<Throwable> {
|
|
||||||
val last = getLast() ?: return emptyList<Throwable>().iterator()
|
|
||||||
return last.itr()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,6 +14,7 @@ import kotlin.test.assertEquals
|
|||||||
import kotlin.test.assertSame
|
import kotlin.test.assertSame
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
@OptIn(TestOnly::class)
|
||||||
internal class ExceptionCollectorTest {
|
internal class ExceptionCollectorTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -23,7 +24,7 @@ internal class ExceptionCollectorTest {
|
|||||||
collector.collect(IllegalArgumentException())
|
collector.collect(IllegalArgumentException())
|
||||||
|
|
||||||
assertTrue { collector.getLast() is IllegalArgumentException }
|
assertTrue { collector.getLast() is IllegalArgumentException }
|
||||||
assertEquals(1, collector.count())
|
assertEquals(1, collector.asSequence().count())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -35,7 +36,7 @@ internal class ExceptionCollectorTest {
|
|||||||
|
|
||||||
assertTrue { collector.getLast() is IllegalStateException }
|
assertTrue { collector.getLast() is IllegalStateException }
|
||||||
assertTrue { collector.getLast()!!.suppressed.single() is IllegalArgumentException }
|
assertTrue { collector.getLast()!!.suppressed.single() is IllegalArgumentException }
|
||||||
assertEquals(2, collector.count())
|
assertEquals(2, collector.asSequence().count())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -49,7 +50,7 @@ internal class ExceptionCollectorTest {
|
|||||||
assertTrue { collector.getLast() is IllegalStateException }
|
assertTrue { collector.getLast() is IllegalStateException }
|
||||||
assertTrue { collector.getLast()!!.suppressed.single() is IllegalArgumentException }
|
assertTrue { collector.getLast()!!.suppressed.single() is IllegalArgumentException }
|
||||||
assertTrue { collector.getLast()!!.suppressed.single()!!.suppressed.single() is StackOverflowError }
|
assertTrue { collector.getLast()!!.suppressed.single()!!.suppressed.single() is StackOverflowError }
|
||||||
assertEquals(3, collector.count())
|
assertEquals(3, collector.asSequence().count())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -62,9 +63,9 @@ internal class ExceptionCollectorTest {
|
|||||||
collector.collect(exception)
|
collector.collect(exception)
|
||||||
collector.collect(exception)
|
collector.collect(exception)
|
||||||
|
|
||||||
assertSame(exception, collector.last())
|
assertSame(exception, collector.asSequence().last())
|
||||||
assertEquals(0, collector.getLast()!!.suppressed.size)
|
assertEquals(0, collector.getLast()!!.suppressed.size)
|
||||||
assertEquals(1, collector.count())
|
assertEquals(1, collector.asSequence().count())
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -82,7 +83,7 @@ internal class ExceptionCollectorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertEquals(0, collector.getLast()!!.suppressed.size)
|
assertEquals(0, collector.getLast()!!.suppressed.size)
|
||||||
assertEquals(1, collector.count())
|
assertEquals(1, collector.asSequence().count())
|
||||||
assertSame(exceptions.first(), collector.getLast())
|
assertSame(exceptions.first(), collector.getLast())
|
||||||
assertEquals("#0", collector.getLast()!!.message)
|
assertEquals("#0", collector.getLast()!!.message)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user