summaryrefslogtreecommitdiff
path: root/docs/examples/actors/joins5.scala
blob: 220ce2a13112dbaaf93af73eb6f6ce707b86f991 (plain) (blame)
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
import scala.actors._
import scala.actors.Actor._

abstract class Producer[T] {

  /** A signal that the next value should be produced. */
  private val Next = new Object

  /** A label for an undefined state of the iterators. */
  private val Undefined = new Object

  protected def produce(x: T): unit = {
    coordinator ! Some(x)
    receive { case Next => }
  }
  protected def produceValues: unit

  def iterator = new Iterator[T] {
    private var current: Any = Undefined
    private def lookAhead = {
      if (current == Undefined) current = coordinator !? Next
      current
    }

    def hasNext: boolean = lookAhead match {
      case Some(x) => true
      case None => { coordinator ! Stop; false }
    }

    def next: T = lookAhead match {
      case Some(x) => current = Undefined; x.asInstanceOf[T]
    }
  }

  case object Stop
  class StopException extends Throwable

  /** A thread-based coordinator */
  private val coordinator: Actor = actor {
    try {
    while (true) {
      receive {
        case Next =>
          producer ! Next
          reply {
            receive { case x: Option[_] => x }
          }
        case Stop => throw new StopException
      }
    }
    } catch { case _: StopException => }
  }

  private val producer: Actor = actor {
    receive {
      case Next =>
        produceValues
        coordinator ! None
    }
  }
}

object Test extends Application {

  def from(m: int, n: int) = new Producer[int] {
    def produceValues = for (val i <- m until n) produce(i)
  }

  // note that it works from the main thread
  val it = from(1, 10).iterator
  while (it.hasNext) {
    Console.println(it.next)
  }
}

object Test2 extends Application {

  class Tree(val left: Tree, val elem: int, val right: Tree)
  def node(left: Tree, elem: int, right: Tree): Tree = new Tree(left, elem, right)
  def node(elem: int): Tree = node(null, elem, null)

  def tree = node(node(node(3), 4, node(6)), 8, node(node(9), 10, node(11)))

  class PreOrder(n: Tree) extends Producer[int] {
    def produceValues = traverse(n)
    def traverse(n: Tree) {
      if (n != null) {
        produce(n.elem)
        traverse(n.left)
        traverse(n.right)
      }
    }
  }

  class PostOrder(n: Tree) extends Producer[int] {
    def produceValues = traverse(n)
    def traverse(n: Tree) {
      if (n != null) {
        traverse(n.left)
        traverse(n.right)
        produce(n.elem)
      }
    }
  }

  class InOrder(n: Tree) extends Producer[int] {
    def produceValues = traverse(n)
    def traverse(n: Tree) {
      if (n != null) {
        traverse(n.left)
        produce(n.elem)
        traverse(n.right)
      }
    }
  }

  Debug.level = 3

  // note that it works from the main thread
  Console.print("PreOrder:")
  for (val x <- new PreOrder(tree).iterator) Console.print(" "+x)
  Console.print("\nPostOrder:")
  for (val x <- new PostOrder(tree).iterator) Console.print(" "+x)
  Console.print("\nInOrder:")
  for (val x <- new InOrder(tree).iterator) Console.print(" "+x)
  Console.print("\n")
}