From 9f0810f723a9bcf4396c4264215ceb44cf267431 Mon Sep 17 00:00:00 2001 From: Roman Elizarov Date: Tue, 27 Jun 2017 12:16:49 +0300 Subject: [PATCH] Pull implementations up from AbstractCoroutineContextElemenet Fixes KT-18671 --- .../experimental/CoroutineContext.kt | 25 +++++++++++- .../experimental/CoroutineContextImpl.kt | 38 ++----------------- .../kotlin-stdlib-runtime-merged.txt | 21 ++++++++++ .../reference-public-api/kotlin-stdlib.txt | 21 ++++++++++ 4 files changed, 69 insertions(+), 36 deletions(-) diff --git a/libraries/stdlib/src/kotlin/coroutines/experimental/CoroutineContext.kt b/libraries/stdlib/src/kotlin/coroutines/experimental/CoroutineContext.kt index 6d21ed81a78..19b0153eb2c 100644 --- a/libraries/stdlib/src/kotlin/coroutines/experimental/CoroutineContext.kt +++ b/libraries/stdlib/src/kotlin/coroutines/experimental/CoroutineContext.kt @@ -40,7 +40,20 @@ public interface CoroutineContext { * Returns a context containing elements from this context and elements from other [context]. * The elements from this context with the same key as in the other one are dropped. */ - public operator fun plus(context: CoroutineContext): CoroutineContext + public operator fun plus(context: CoroutineContext): CoroutineContext = + if (context === EmptyCoroutineContext) this else // fast path -- avoid lambda creation + context.fold(this) { acc, element -> + val removed = acc.minusKey(element.key) + if (removed === EmptyCoroutineContext) element else { + // make sure interceptor is always last in the context (and thus is fast to get when present) + val interceptor = removed[ContinuationInterceptor] + if (interceptor == null) CombinedContext(removed, element) else { + val left = removed.minusKey(ContinuationInterceptor) + if (left === EmptyCoroutineContext) CombinedContext(element, interceptor) else + CombinedContext(CombinedContext(left, element), interceptor) + } + } + } /** * Returns a context containing elements from this context, but without an element with @@ -57,6 +70,16 @@ public interface CoroutineContext { * A key of this coroutine context element. */ public val key: Key<*> + + @Suppress("UNCHECKED_CAST") + public override operator fun get(key: Key): E? = + if (this.key === key) this as E else null + + public override fun fold(initial: R, operation: (R, Element) -> R): R = + operation(initial, this) + + public override fun minusKey(key: Key<*>): CoroutineContext = + if (this.key === key) EmptyCoroutineContext else this } /** diff --git a/libraries/stdlib/src/kotlin/coroutines/experimental/CoroutineContextImpl.kt b/libraries/stdlib/src/kotlin/coroutines/experimental/CoroutineContextImpl.kt index 749cfb0edd2..634298f9d62 100644 --- a/libraries/stdlib/src/kotlin/coroutines/experimental/CoroutineContextImpl.kt +++ b/libraries/stdlib/src/kotlin/coroutines/experimental/CoroutineContextImpl.kt @@ -22,20 +22,7 @@ import kotlin.coroutines.experimental.CoroutineContext.* * Base class for [CoroutineContext.Element] implementations. */ @SinceKotlin("1.1") -public abstract class AbstractCoroutineContextElement(public override val key: Key<*>) : Element { - @Suppress("UNCHECKED_CAST") - public override operator fun get(key: Key): E? = - if (this.key === key) this as E else null - - public override fun fold(initial: R, operation: (R, Element) -> R): R = - operation(initial, this) - - public override operator fun plus(context: CoroutineContext): CoroutineContext = - plusImpl(context) - - public override fun minusKey(key: Key<*>): CoroutineContext = - if (this.key === key) EmptyCoroutineContext else this -} +public abstract class AbstractCoroutineContextElement(public override val key: Key<*>) : Element /** * An empty coroutine context. @@ -50,11 +37,11 @@ public object EmptyCoroutineContext : CoroutineContext { public override fun toString(): String = "EmptyCoroutineContext" } -//--------------------- private impl --------------------- +//--------------------- internal impl --------------------- // this class is not exposed, but is hidden inside implementations // this is a left-biased list, so that `plus` works naturally -private class CombinedContext(val left: CoroutineContext, val element: Element) : CoroutineContext { +internal class CombinedContext(val left: CoroutineContext, val element: Element) : CoroutineContext { override fun get(key: Key): E? { var cur = this while (true) { @@ -71,9 +58,6 @@ private class CombinedContext(val left: CoroutineContext, val element: Element) public override fun fold(initial: R, operation: (R, Element) -> R): R = operation(left.fold(initial, operation), element) - public override operator fun plus(context: CoroutineContext): CoroutineContext = - plusImpl(context) - public override fun minusKey(key: Key<*>): CoroutineContext { element[key]?.let { return left } val newLeft = left.minusKey(key) @@ -113,19 +97,3 @@ private class CombinedContext(val left: CoroutineContext, val element: Element) if (acc.isEmpty()) element.toString() else acc + ", " + element } + "]" } - -private fun CoroutineContext.plusImpl(context: CoroutineContext): CoroutineContext = - if (context === EmptyCoroutineContext) this else // fast path -- avoid lambda creation - context.fold(this) { acc, element -> - val removed = acc.minusKey(element.key) - if (removed === EmptyCoroutineContext) element else { - // make sure interceptor is always last in the context (and thus is fast to get when present) - val interceptor = removed[ContinuationInterceptor] - if (interceptor == null) CombinedContext(removed, element) else { - val left = removed.minusKey(ContinuationInterceptor) - if (left === EmptyCoroutineContext) CombinedContext(element, interceptor) else - CombinedContext(CombinedContext(left, element), interceptor) - } - } - } - diff --git a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt index dcf531f72b4..99fe7df8718 100644 --- a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt +++ b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt @@ -1959,6 +1959,13 @@ public abstract interface class kotlin/coroutines/experimental/ContinuationInter public abstract fun interceptContinuation (Lkotlin/coroutines/experimental/Continuation;)Lkotlin/coroutines/experimental/Continuation; } +public final class kotlin/coroutines/experimental/ContinuationInterceptor$DefaultImpls { + public static fun fold (Lkotlin/coroutines/experimental/ContinuationInterceptor;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public static fun get (Lkotlin/coroutines/experimental/ContinuationInterceptor;Lkotlin/coroutines/experimental/CoroutineContext$Key;)Lkotlin/coroutines/experimental/CoroutineContext$Element; + public static fun minusKey (Lkotlin/coroutines/experimental/ContinuationInterceptor;Lkotlin/coroutines/experimental/CoroutineContext$Key;)Lkotlin/coroutines/experimental/CoroutineContext; + public static fun plus (Lkotlin/coroutines/experimental/ContinuationInterceptor;Lkotlin/coroutines/experimental/CoroutineContext;)Lkotlin/coroutines/experimental/CoroutineContext; +} + public final class kotlin/coroutines/experimental/ContinuationInterceptor$Key : kotlin/coroutines/experimental/CoroutineContext$Key { } @@ -1969,8 +1976,22 @@ public abstract interface class kotlin/coroutines/experimental/CoroutineContext public abstract fun plus (Lkotlin/coroutines/experimental/CoroutineContext;)Lkotlin/coroutines/experimental/CoroutineContext; } +public final class kotlin/coroutines/experimental/CoroutineContext$DefaultImpls { + public static fun plus (Lkotlin/coroutines/experimental/CoroutineContext;Lkotlin/coroutines/experimental/CoroutineContext;)Lkotlin/coroutines/experimental/CoroutineContext; +} + public abstract interface class kotlin/coroutines/experimental/CoroutineContext$Element : kotlin/coroutines/experimental/CoroutineContext { + public abstract fun fold (Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public abstract fun get (Lkotlin/coroutines/experimental/CoroutineContext$Key;)Lkotlin/coroutines/experimental/CoroutineContext$Element; public abstract fun getKey ()Lkotlin/coroutines/experimental/CoroutineContext$Key; + public abstract fun minusKey (Lkotlin/coroutines/experimental/CoroutineContext$Key;)Lkotlin/coroutines/experimental/CoroutineContext; +} + +public final class kotlin/coroutines/experimental/CoroutineContext$Element$DefaultImpls { + public static fun fold (Lkotlin/coroutines/experimental/CoroutineContext$Element;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public static fun get (Lkotlin/coroutines/experimental/CoroutineContext$Element;Lkotlin/coroutines/experimental/CoroutineContext$Key;)Lkotlin/coroutines/experimental/CoroutineContext$Element; + public static fun minusKey (Lkotlin/coroutines/experimental/CoroutineContext$Element;Lkotlin/coroutines/experimental/CoroutineContext$Key;)Lkotlin/coroutines/experimental/CoroutineContext; + public static fun plus (Lkotlin/coroutines/experimental/CoroutineContext$Element;Lkotlin/coroutines/experimental/CoroutineContext;)Lkotlin/coroutines/experimental/CoroutineContext; } public abstract interface class kotlin/coroutines/experimental/CoroutineContext$Key { diff --git a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib.txt b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib.txt index 37418ea7266..63842327512 100644 --- a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib.txt +++ b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib.txt @@ -1778,6 +1778,13 @@ public abstract interface class kotlin/coroutines/experimental/ContinuationInter public abstract fun interceptContinuation (Lkotlin/coroutines/experimental/Continuation;)Lkotlin/coroutines/experimental/Continuation; } +public final class kotlin/coroutines/experimental/ContinuationInterceptor$DefaultImpls { + public static fun fold (Lkotlin/coroutines/experimental/ContinuationInterceptor;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public static fun get (Lkotlin/coroutines/experimental/ContinuationInterceptor;Lkotlin/coroutines/experimental/CoroutineContext$Key;)Lkotlin/coroutines/experimental/CoroutineContext$Element; + public static fun minusKey (Lkotlin/coroutines/experimental/ContinuationInterceptor;Lkotlin/coroutines/experimental/CoroutineContext$Key;)Lkotlin/coroutines/experimental/CoroutineContext; + public static fun plus (Lkotlin/coroutines/experimental/ContinuationInterceptor;Lkotlin/coroutines/experimental/CoroutineContext;)Lkotlin/coroutines/experimental/CoroutineContext; +} + public final class kotlin/coroutines/experimental/ContinuationInterceptor$Key : kotlin/coroutines/experimental/CoroutineContext$Key { } @@ -1788,8 +1795,22 @@ public abstract interface class kotlin/coroutines/experimental/CoroutineContext public abstract fun plus (Lkotlin/coroutines/experimental/CoroutineContext;)Lkotlin/coroutines/experimental/CoroutineContext; } +public final class kotlin/coroutines/experimental/CoroutineContext$DefaultImpls { + public static fun plus (Lkotlin/coroutines/experimental/CoroutineContext;Lkotlin/coroutines/experimental/CoroutineContext;)Lkotlin/coroutines/experimental/CoroutineContext; +} + public abstract interface class kotlin/coroutines/experimental/CoroutineContext$Element : kotlin/coroutines/experimental/CoroutineContext { + public abstract fun fold (Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public abstract fun get (Lkotlin/coroutines/experimental/CoroutineContext$Key;)Lkotlin/coroutines/experimental/CoroutineContext$Element; public abstract fun getKey ()Lkotlin/coroutines/experimental/CoroutineContext$Key; + public abstract fun minusKey (Lkotlin/coroutines/experimental/CoroutineContext$Key;)Lkotlin/coroutines/experimental/CoroutineContext; +} + +public final class kotlin/coroutines/experimental/CoroutineContext$Element$DefaultImpls { + public static fun fold (Lkotlin/coroutines/experimental/CoroutineContext$Element;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object; + public static fun get (Lkotlin/coroutines/experimental/CoroutineContext$Element;Lkotlin/coroutines/experimental/CoroutineContext$Key;)Lkotlin/coroutines/experimental/CoroutineContext$Element; + public static fun minusKey (Lkotlin/coroutines/experimental/CoroutineContext$Element;Lkotlin/coroutines/experimental/CoroutineContext$Key;)Lkotlin/coroutines/experimental/CoroutineContext; + public static fun plus (Lkotlin/coroutines/experimental/CoroutineContext$Element;Lkotlin/coroutines/experimental/CoroutineContext;)Lkotlin/coroutines/experimental/CoroutineContext; } public abstract interface class kotlin/coroutines/experimental/CoroutineContext$Key {