/
PriorityMapLike.scala
142 lines (122 loc) · 5.2 KB
/
PriorityMapLike.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
package de.ummels.prioritymap
import scala.collection.GenTraversableOnce
import scala.collection.immutable._
/** A template trait for immutable priority maps.
* To create a concrete priority map, you need to implement the following methods
* in addition to those of `MapLike`:
*
* {{{
* implicit def ordering: Ordering[B]
* def +(kv: (A, B)): This
* def rangeImpl(from: Option[B], until: Option[B]): This
* }}}
*
* The iterator returned by `iterator` should generate key/value pairs in the
* order specified by the implicit ordering on values.
*
* Concrete classes may also override other methods for efficiency.
*/
trait PriorityMapLike[A, B, +This <: PriorityMapLike[A, B, This] with PriorityMap[A, B]]
extends MapLike[A, B, This] { self =>
implicit def ordering: Ordering[B]
/** Adds a key/value binding to this priority map.
*
* @param kv the key/value pair
* @return a new priority map with the new binding added to this priority map
*/
def +(kv: (A, B)): This
/** Adds a key/value binding to this priority map.
*
* @param key the key
* @param value the value
* @return a new priority map with the new binding added to this map
*/
def updated(key: A, value: B): This = this + (key -> value)
/** Adds two or more key/value bindings to this priority map.
*
* @param kv1 the first key/value pair to add
* @param kv2 the second key/value pair to add
* @param kvs the remaining key/value pairs to add
* @return a new priority map with the new bindings added to this map
*/
def +(kv1: (A, B), kv2: (A, B), kvs: (A, B)*): This =
this + kv1 + kv2 ++ kvs
/** Adds a number of key/value bindings to this priority map.
*
* @param kvs a traversable object consisting of key/value pairs
* @return a new priority map with the new bindings added to this map
*/
def ++(kvs: GenTraversableOnce[(A, B)]): This =
((repr: This) /: kvs)(_ + _)
/** Merges a number of key/value bindings into this priority map.
*
* If a key is contained in both this map and the given bindings, computes
* the new value by applying the given merge function to the existing value
* and the new value.
*
* @param kvs a traversable object consisting of key/value pairs
* @param f the merge function
* @return a new priority map with the new bindings merged into this map
*/
def merged(kvs: GenTraversableOnce[(A, B)])(f: (B, B) => B): This =
((repr: This) /: kvs) { (m, kv) =>
val (k, v2) = kv
m.get(k) match {
case None => m + kv
case Some(v1) => m + (k -> f(v1, v2))
}
}
/** Transforms this map by applying a function to every retrieved value.
*
* @param f the function used to transform values of this map
* @return a new priority map that maps every key of this map
* to `f(this(key))`
*/
def mapValues[C](f: B => C)(implicit ord: Ordering[C]): PriorityMap[A, C] =
map { case (a, b) => (a, f(b)) }
/** Returns a new priority map of the same type as this priority map that
* only contains values between the given optional bounds.
*
* @param from the lower-bound (inclusive) on values or
* `None` if there is no lower bound
* @param until the upper-bound (exclusive) on values or
* `None` if there is no upper bound
*/
def rangeImpl(from: Option[B], until: Option[B]): This
/** Returns a new priority map of the same type as this priority map that
* only contains values greater than or equal to the given lower bound.
*
* @param from the lower-bound (inclusive) on values
*/
def from(from: B): This = rangeImpl(Some(from), None)
/** Returns a new priority map of the same type as this priority map that
* only contains values smaller than the given upper bound.
*
* @param until the upper-bound (exclusive) on values
*/
def until(until: B): This = rangeImpl(None, Some(until))
/** Returns a new priority map of the same type as this priority map that
* only contains values between the given bounds.
*
* @param from the lower-bound (inclusive) on values
* @param until the upper-bound (exclusive) on values
*/
def range(from: B, until: B): This = rangeImpl(Some(from), Some(until))
/** Optionally returns the first key of this priority map. */
def firstKey: Option[A] = headOption map (_._1)
/** Optionally returns the last key of this priority map. */
def lastKey: Option[A] = lastOption map (_._1)
/** Optionally returns the first value of this priority map. */
def firstValue: Option[B] = headOption map (_._2)
/** Optionally returns the last value of this priority map. */
def lastValue: Option[B] = lastOption map (_._2)
/** Returns the values of this priority map as a sorted set. */
def valueSet: SortedSet[B] = SortedSet.empty[B] ++ values
override protected[this] def newBuilder = new PriorityMapBuilder[A, B, This](empty)
override def filterKeys(p: A => Boolean): PriorityMap[A, B] =
new FilteredKeys(p) with PriorityMap.Default[A, B] {
implicit def ordering: Ordering[B] = self.ordering
def rangeImpl(from: Option[B], until: Option[B]) =
self.rangeImpl(from, until).filterKeys(p)
}
}