-
Notifications
You must be signed in to change notification settings - Fork 29
/
Fork.scala
151 lines (126 loc) · 4.77 KB
/
Fork.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package com.thoughtworks.dsl.keywords
import java.io.{PrintStream, PrintWriter}
import java.util.concurrent.atomic.AtomicInteger
import com.thoughtworks.dsl.Dsl
import com.thoughtworks.dsl.Dsl.{!!, Keyword}
import com.thoughtworks.dsl.keywords.Catch.CatchDsl
import com.thoughtworks.enableMembersIf
import scala.collection._
import scala.collection.generic.CanBuildFrom
import scala.collection.mutable.Builder
import scala.language.implicitConversions
final case class Fork[Element](elements: Traversable[Element]) extends AnyVal with Keyword[Fork[Element], Element]
object Fork {
@enableMembersIf(scala.util.Properties.versionNumberString.matches("""^2\.1(1|2)\..*$"""))
private[Fork] object Scala211Or212 {
type Factory[-A, +C] = scala.collection.generic.CanBuildFrom[Nothing, A, C]
@inline
def flatMapBreakOut[Element, Domain, DomainElement](
fa: Traversable[Element],
f: Element => GenTraversableOnce[DomainElement])(implicit factory: Factory[DomainElement, Domain]): Domain = {
fa.flatMap(f)(collection.breakOut(factory))
}
@inline
def newBuilder[A, C](implicit factory: Factory[A, C]): Builder[A, C] = {
factory()
}
}
@enableMembersIf(scala.util.Properties.versionNumberString.matches("""^2\.13\..*$"""))
private[Fork] object Scala213 {
@inline
def flatMapBreakOut[Element, Domain, DomainElement](
fa: Traversable[Element],
f: Element => GenTraversableOnce[DomainElement])(implicit factory: Factory[DomainElement, Domain]): Domain = {
factory.fromSpecific(new View.FlatMap(fa, f))
}
@inline
def newBuilder[A, C](implicit factory: Factory[A, C]): Builder[A, C] = {
factory.newBuilder
}
}
import Scala211Or212._
import Scala213._
implicit def implicitFork[Element](elements: Traversable[Element]): Fork[Element] = Fork[Element](elements)
final case class MultipleException(throwableSet: Set[Throwable])
extends RuntimeException("Multiple exceptions found") {
override def toString: String = throwableSet.mkString("\n")
override def printStackTrace(): Unit = {
for (throwable <- throwableSet) {
throwable.printStackTrace()
}
}
override def printStackTrace(s: PrintStream): Unit = {
for (throwable <- throwableSet) {
throwable.printStackTrace(s)
}
}
override def printStackTrace(s: PrintWriter): Unit = {
for (throwable <- throwableSet) {
throwable.printStackTrace(s)
}
}
override def getStackTrace: Array[StackTraceElement] = synchronized {
super.getStackTrace match {
case null =>
setStackTrace(throwableSet.view.flatMap(_.getStackTrace).toArray)
super.getStackTrace
case stackTrace =>
stackTrace
}
}
override def fillInStackTrace(): this.type = {
this
}
}
implicit def forkContinuationDsl[NarrowElement, LeftDomain, WidenElement, RightDomain](
implicit eachDsl: Dsl[Each[NarrowElement], LeftDomain, NarrowElement],
booleanEachDsl: Dsl[Each[Boolean], LeftDomain, Boolean],
isTraversableOnce: RightDomain => TraversableOnce[WidenElement],
canBuildFrom: Factory[WidenElement, RightDomain],
continueDsl: Dsl[Continue, LeftDomain, Nothing],
catchDsl: CatchDsl[LeftDomain, LeftDomain, Unit]
): Dsl[Fork[NarrowElement], LeftDomain !! RightDomain, NarrowElement] =
new Dsl[Fork[NarrowElement], LeftDomain !! RightDomain, NarrowElement] {
def cpsApply(fork: Fork[NarrowElement],
mapper: NarrowElement => LeftDomain !! RightDomain): LeftDomain !! RightDomain = _ {
val builder: mutable.Builder[WidenElement, RightDomain] = newBuilder[WidenElement, RightDomain]
val exceptionBuilder = Set.newBuilder[Throwable]
val counter = new AtomicInteger(1)
if (!Each(Seq(true, false))) {
val element = !Each(fork.elements)
counter.incrementAndGet()
try {
builder ++= !Shift(mapper(element));
()
} catch {
case MultipleException(throwableSet) =>
exceptionBuilder ++= throwableSet;
()
case e: Throwable =>
exceptionBuilder += e;
()
} finally {
if (counter.decrementAndGet() > 0) {
!Continue
}
}
} else {
if (counter.decrementAndGet() > 0) {
!Continue
}
}
val exceptions = exceptionBuilder.result()
if (exceptions.isEmpty) {
builder.result()
} else {
val i = exceptions.iterator
val firstException = i.next()
if (i.hasNext) {
throw MultipleException(exceptions)
} else {
throw firstException
}
}
}
}
}