author | wenzelm |
Sat, 20 May 2023 17:18:44 +0200 | |
changeset 78085 | dd7bb7f99ad5 |
parent 76538 | 0bab4c751478 |
child 78429 | 103a81e60126 |
permissions | -rw-r--r-- |
59136 | 1 |
/* Title: Pure/Concurrent/par_list.scala |
2 |
Author: Makarius |
|
3 |
||
4 |
Parallel list combinators. |
|
5 |
*/ |
|
6 |
||
7 |
||
8 |
package isabelle |
|
9 |
||
10 |
||
75393 | 11 |
object Par_List { |
12 |
def managed_results[A, B]( |
|
13 |
f: A => B, |
|
14 |
xs: List[A], |
|
15 |
sequential: Boolean = false |
|
16 |
) : List[Exn.Result[B]] = { |
|
73512
e52a9b208481
support sequential LaTeX jobs: more robust when TeX installation is self-installing packages etc.;
wenzelm
parents:
73367
diff
changeset
|
17 |
if (sequential || xs.isEmpty || xs.tail.isEmpty) xs.map(x => Exn.capture { f(x) }) |
59136 | 18 |
else { |
61590 | 19 |
val state = Synchronized[(List[Future[B]], Boolean)]((Nil, false)) |
59136 | 20 |
|
21 |
def cancel_other(self: Int = -1): Unit = |
|
61562 | 22 |
state.change { case (futures, canceled) => |
59136 | 23 |
if (!canceled) { |
61562 | 24 |
for ((future, i) <- futures.iterator.zipWithIndex if i != self) |
73367 | 25 |
future.cancel() |
59136 | 26 |
} |
61562 | 27 |
(futures, true) |
59136 | 28 |
} |
29 |
||
30 |
try { |
|
31 |
state.change(_ => |
|
32 |
(xs.iterator.zipWithIndex.map({ case (x, self) => |
|
61562 | 33 |
Future.fork { |
34 |
Exn.capture { f(x) } match { |
|
35 |
case Exn.Exn(exn) => cancel_other(self); throw exn |
|
36 |
case Exn.Res(res) => res |
|
37 |
} |
|
59136 | 38 |
} |
39 |
}).toList, false)) |
|
40 |
||
61562 | 41 |
state.value._1.map(_.join_result) |
59136 | 42 |
} |
43 |
finally { cancel_other() } |
|
44 |
} |
|
73512
e52a9b208481
support sequential LaTeX jobs: more robust when TeX installation is self-installing packages etc.;
wenzelm
parents:
73367
diff
changeset
|
45 |
} |
59136 | 46 |
|
73512
e52a9b208481
support sequential LaTeX jobs: more robust when TeX installation is self-installing packages etc.;
wenzelm
parents:
73367
diff
changeset
|
47 |
def map[A, B](f: A => B, xs: List[A], sequential: Boolean = false): List[B] = |
e52a9b208481
support sequential LaTeX jobs: more robust when TeX installation is self-installing packages etc.;
wenzelm
parents:
73367
diff
changeset
|
48 |
Exn.release_first(managed_results(f, xs, sequential = sequential)) |
59136 | 49 |
|
76538 | 50 |
private class Found(val res: Any) extends Exception |
51 |
||
75393 | 52 |
def get_some[A, B](f: A => Option[B], xs: List[A]): Option[B] = { |
59136 | 53 |
val results = |
54 |
managed_results( |
|
55 |
(x: A) => f(x) match { case None => () case Some(y) => throw new Found(y) }, xs) |
|
76537 | 56 |
results.collectFirst({ |
76538 | 57 |
case Exn.Exn(found) if found.isInstanceOf[Found] => |
58 |
found.asInstanceOf[Found].res.asInstanceOf[B] |
|
76537 | 59 |
}) match { |
59136 | 60 |
case None => Exn.release_first(results); None |
61 |
case some => some |
|
62 |
} |
|
63 |
} |
|
64 |
||
65 |
def find_some[A](P: A => Boolean, xs: List[A]): Option[A] = |
|
66 |
get_some((x: A) => if (P(x)) Some(x) else None, xs) |
|
67 |
||
59137 | 68 |
def exists[A](P: A => Boolean, xs: List[A]): Boolean = find_some(P, xs).isDefined |
59136 | 69 |
def forall[A](P: A => Boolean, xs: List[A]): Boolean = !exists((x: A) => !P(x), xs) |
70 |
} |