summaryrefslogtreecommitdiff
path: root/src/library/scala/reflect/base/Attachments.scala
blob: 43e870fc4f955e7df79519a76e10dbeb74cd1614 (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
package scala.reflect
package base

/** Attachments is a generalisation of Position.
 *  Typically it stores a Position of a tree, but this can be extended to encompass arbitrary payloads.
 *
 *  Attachments have to carry positions, because we don't want to introduce even a single additional field in Tree
 *  imposing an unnecessary memory tax because of something that will not be used in most cases.
 */
abstract class Attachments { self =>

  type Pos >: Null

  /** Gets the underlying position */
  def pos: Pos

  /** Creates a copy of this attachment with its position updated */
  def withPos(newPos: Pos): Attachments { type Pos = self.Pos }

  /** Gets the underlying payload */
  def all: Set[Any] = Set.empty

  def get[T: ClassTag]: Option[T] =
    (all find (_.getClass == classTag[T].runtimeClass)).asInstanceOf[Option[T]]

  /** Creates a copy of this attachment with its payload updated */
  def add(attachment: Any): Attachments { type Pos = self.Pos } =
    new NonemptyAttachments(this.pos, all + attachment)

  def remove[T: ClassTag]: Attachments { type Pos = self.Pos } = {
    val newAll = all filterNot (_.getClass == classTag[T].runtimeClass)
    if (newAll.isEmpty) pos.asInstanceOf[Attachments { type Pos = self.Pos }]
    else new NonemptyAttachments(this.pos, newAll)
  }

  private class NonemptyAttachments(override val pos: Pos, override val all: Set[Any]) extends Attachments {
    type Pos = self.Pos
    def withPos(newPos: Pos) = new NonemptyAttachments(newPos, all)
  }
}