Pull implementations up from AbstractCoroutineContextElemenet

Fixes KT-18671
This commit is contained in:
Roman Elizarov
2017-06-27 12:16:49 +03:00
parent c9b14c5a45
commit 9f0810f723
4 changed files with 69 additions and 36 deletions
@@ -40,7 +40,20 @@ public interface CoroutineContext {
* Returns a context containing elements from this context and elements from other [context]. * 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. * 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 * 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. * A key of this coroutine context element.
*/ */
public val key: Key<*> public val key: Key<*>
@Suppress("UNCHECKED_CAST")
public override operator fun <E : Element> get(key: Key<E>): E? =
if (this.key === key) this as E else null
public override fun <R> 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
} }
/** /**
@@ -22,20 +22,7 @@ import kotlin.coroutines.experimental.CoroutineContext.*
* Base class for [CoroutineContext.Element] implementations. * Base class for [CoroutineContext.Element] implementations.
*/ */
@SinceKotlin("1.1") @SinceKotlin("1.1")
public abstract class AbstractCoroutineContextElement(public override val key: Key<*>) : Element { public abstract class AbstractCoroutineContextElement(public override val key: Key<*>) : Element
@Suppress("UNCHECKED_CAST")
public override operator fun <E : Element> get(key: Key<E>): E? =
if (this.key === key) this as E else null
public override fun <R> 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
}
/** /**
* An empty coroutine context. * An empty coroutine context.
@@ -50,11 +37,11 @@ public object EmptyCoroutineContext : CoroutineContext {
public override fun toString(): String = "EmptyCoroutineContext" public override fun toString(): String = "EmptyCoroutineContext"
} }
//--------------------- private impl --------------------- //--------------------- internal impl ---------------------
// this class is not exposed, but is hidden inside implementations // this class is not exposed, but is hidden inside implementations
// this is a left-biased list, so that `plus` works naturally // 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 <E : Element> get(key: Key<E>): E? { override fun <E : Element> get(key: Key<E>): E? {
var cur = this var cur = this
while (true) { while (true) {
@@ -71,9 +58,6 @@ private class CombinedContext(val left: CoroutineContext, val element: Element)
public override fun <R> fold(initial: R, operation: (R, Element) -> R): R = public override fun <R> fold(initial: R, operation: (R, Element) -> R): R =
operation(left.fold(initial, operation), element) operation(left.fold(initial, operation), element)
public override operator fun plus(context: CoroutineContext): CoroutineContext =
plusImpl(context)
public override fun minusKey(key: Key<*>): CoroutineContext { public override fun minusKey(key: Key<*>): CoroutineContext {
element[key]?.let { return left } element[key]?.let { return left }
val newLeft = left.minusKey(key) 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 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)
}
}
}
@@ -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 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 { 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 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 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 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 { public abstract interface class kotlin/coroutines/experimental/CoroutineContext$Key {
@@ -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 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 { 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 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 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 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 { public abstract interface class kotlin/coroutines/experimental/CoroutineContext$Key {