blob: 479ab9a8570197b89d3b84e83f9f71bdff732228 (
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
|
package scala.reflect
package base
/** Attachments is a generalization of Position. Typically it stores a Position of a tree, but this can be extended to
* encompass arbitrary payloads. Payloads are stored in type-indexed slots, which can be read with `get[T]` and written
* with `update[T]` and `remove[T]`.
*
* Attachments always carry positions because we don't want to introduce an additional field for attachments in `Tree`
* imposing an unnecessary memory tax because of something that will not be used in most cases.
*/
abstract class Attachments { self =>
/** The position type of this attachment */
type Pos >: Null
/** The underlying position */
def pos: Pos
/** Creates a copy of this attachment with the position replaced by `newPos` */
def withPos(newPos: Pos): Attachments { type Pos = self.Pos }
/** The underlying payload with the guarantee that no two elements have the same type. */
def all: Set[Any] = Set.empty
private def matchesTag[T: ClassTag](datum: Any) =
classTag[T].runtimeClass == datum.getClass
/** An underlying payload of the given class type `T`. */
def get[T: ClassTag]: Option[T] =
(all filter matchesTag[T]).headOption.asInstanceOf[Option[T]]
/** Creates a copy of this attachment with the payload slot of T added/updated with the provided value.
*
* Replaces an existing payload of the same type, if exists.
*/
def update[T: ClassTag](attachment: T): Attachments { type Pos = self.Pos } =
new NonemptyAttachments(this.pos, remove[T].all + attachment)
/** Creates a copy of this attachment with the payload of the given class type `T` removed. */
def remove[T: ClassTag]: Attachments { type Pos = self.Pos } = {
val newAll = all filterNot matchesTag[T]
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)
}
}
|