summaryrefslogtreecommitdiff
path: root/src/library/scala/collection/immutable/Map.scala
blob: b7478a4fb13d6ec74ec069854b6b94eb0fcc38a1 (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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
/*                     __                                               *\
**     ________ ___   / /  ___     Scala API                            **
**    / __/ __// _ | / /  / _ |    (c) 2003-2007, LAMP/EPFL             **
**  __\ \/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **
** /____/\___/_/ |_/____/_/ | |                                         **
**                          |/                                          **
\*                                                                      */

// $Id$


package scala.collection.immutable

import Predef._

/** <p>An object for creating immutable maps. These are implemented using
  *         <a href="HashMap.html">immutable hash maps</a>.
  *  </p>*/
object Map {
  def empty[A, B]: Map[A, B] = new EmptyMap[A, B]

  def apply[A, B](elems: (A, B)*) = empty[A, B] ++ elems
}

/** <p>
 *    This class defines the interface for immutable maps.  Operations
 *    on an immutable map leave the original map unchanged, and return
 *    a new map if needed.
 *  </p>
 *  <p>
 *    Concrete map implementations have to provide functionality for
 *    the abstract methods in <a href="../Map.html" target="contentFrame">
 *    <code>scala.collection.Map</code></a> as well as for
 *    <code>factory</code>, <code>update</code>, and <code>-</code>.
 *  </p>
 *
 *  @author  Matthias Zenger
 *  @author  Erik Stenman
 *  @author  Martin Odersky
 *  @version 1.2, 31/06/2006
 */
trait Map[A, +B] extends collection.Map[A, B] {

  /** This method returns a new map instance of the same class
   *  mapping keys of the same type to values of type <code>C</code>.
   */
  def empty[C]: Map[A, C]

  /** This method allows one to create a new map with an
   *  additional mapping from <code>key</code>
   *  to <code>value</code>. If the map contains already a
   *  mapping for <code>key</code>, it will be overridden by this
   *  function.
   *
   *  @param key   ...
   *  @param value ...
   *  @return      the created map
   *  @deprecated    use <code>+({A, B})</code> instead
   */
  def update [B1 >: B] (key: A, value: B1): Map[A, B1]

  /** Add a key/value pair to this map.
   *  @param    kv the key/value pair.
   *  @return   A new map with the new binding added to this map
   */
  def + [B1 >: B] (kv: (A, B1)): Map[A, B1] = update(kv._1, kv._2)

  /** Add two or more key/value pairs to this map.
   *  @param    kv1 the first key/value pair.
   *  @param    kv2 the second key/value pair.
   *  @param    kvs the remaining key/value pairs.
   *  @return   A new map with the new bindings added
   */
  def + [B1 >: B] (kv1: (A, B1), kv2: (A, B1), kvs: (A, B1)*): Map[A, B1] =
    this + kv1 + kv2 ++ kvs

  /** Add a sequence of key/value pairs to this map.
   *  @param    kvs the iterable object containing all key/value pairs.
   *  @return   A new map with the new bindings added
   */
  def ++ [B1 >: B] (kvs: Iterable[(A, B1)]): Map[A, B1] =
    ((this: Map[A, B1]) /: kvs) ((m, kv) => m + kv)

  /** Add a sequence of key/value pairs to this map.
   *  @param    kvs the iterator containing all key/value pairs.
   *  @return   A new map with the new bindings added
   */
  def ++ [B1 >: B] (kvs: Iterator[(A, B1)]): Map[A, B1] =
    ((this: Map[A, B1]) /: kvs) ((m, kv) => m + kv)

  /** Remove a key from this map
   *  @param    key the key to be removed
   *  @return   If the map does not contain a binding for <code>key</code>
   *            it is returned unchanged. Otherwise, return a new map
   *            without a binding for <code>key</code>
   */
  def - (key: A): Map[A, B]

  /** Remove two or more keys from this map
   *  @param    key1 the first key to be removed
   *  @param    key2 the second key to be removed
   *  @param    keys the remaining keys to be removed
   *  @return   A map without bindings for <code>keys</code>
   *            If the map is mutable, the bindings are removed in place
   *            and the map itself is returned.
   *            If the map is immutable, a new map with the bindings removed is returned.
   */
  def - (key1: A, key2: A, keys: A*): Map[A, B] =
    this - key1 - key2 -- keys

  /** Remove a sequence of keys from this map
   *  @param    keys the keys to be removed
   *  @return   A map without bindings for the given keys.
   *            If the map is mutable, the bindings are removed in place
   *            and the map itself is returned.
   *            If the map is immutable, a new map with the bindings removed is returned.
   */
  def -- (keys: Iterable[A]): Map[A, B] = this -- keys.elements

  /** Remove a sequence of keys from this map
   *  @param    keys the keys to be removed
   *  @return   A map without bindings for the given keys.
   *            If the map is mutable, the bindings are removed in place
   *            and the map itself is returned.
   *            If the map is immutable, a new map with the bindings removed is returned.
   */
  def -- (keys: Iterator[A]): Map[A, B] =
    (this /: keys) ((m, key) => m - key)


  /** The same map with a given default function */
  def withDefault[B1 >: B](d: A => B1): Map[A, B1] = new Map[A, B1] {
    def size = Map.this.size
    def get(key: A) = Map.this.get(key)
    def elements = Map.this.elements
    def empty[C] = Map.this.empty
    def update [B2 >: B1](key: A, value: B2): Map[A, B2] =
      Map.this.update(key, value) withDefault d
    def -(key: A): Map[A, B1] = Map.this - key withDefault d
    override def default(key: A): B1 = d(key)
  }

  /** The same map with a given default value */
  def withDefaultValue[B1 >: B](d: B1): Map[A, B1] = withDefault(x => d)

  /** This function transforms all the values of mappings contained
   *  in this map with function <code>f</code>.
   *
   *  @param f A function over keys and values
   *  @return  the updated map
   */
  def transform[C](f: (A, B) => C): Map[A, C] = {
    var res = empty[C]
    foreach { case (key, value) => res = res.update(key, f(key, value)) }
    res
  }

  /** This method removes all the mappings for which the predicate
   *  <code>p</code> returns <code>false</code>.
   *
   *  @param p A prediacte over key-value pairs
   *  @return  the updated map
   */
  override def filter(p: ((A, B)) => Boolean): Map[A, B] = {
    var res = this
    foreach {
      case kv @ (key, _) => if (!p(kv)) { res = res - key }
    }
    res
  }

  /** <p>
   *    This method defines syntactic sugar for adding a
   *    mapping. It is typically used in the following way:
   *  </p>
   *  <pre>
   *    map + key -> value
   *  </pre>
   *  @deprecated  use <code>+({A, B})</code> instead
   */
  @deprecated def +(key: A): MapTo = new MapTo(key)

  /** <code>incl</code> can be used to add many mappings at the same time
   *  to the map. The method assumes that a mapping is represented
   *  by a <code>Pair</code> object who's first component denotes the
   *  key, and who's second component refers to the value.
   *
   *  @param mappings ...
   *  @return         ...
   *  @deprecated   use <code>+</code> instead
   */
  @deprecated def incl[B1 >: B](mappings: (A, B1)*): Map[A, B1] = incl(mappings)

  /** <code>incl</code> can be used to add many mappings at the same time
   *  to the map. The method assumes that each mapping is represented
   *  by an Iterator over <code>Pair</code> objects who's first component
   *  denotes the key, and who's second component refers to the value.
   *
   *  @deprecated    use <code>++</code> instead
   */
  @deprecated def incl[B1 >: B](map: Iterable[(A, B1)]): Map[A, B1] = {
    val iter = map.elements
    var res: Map[A, B1] = this
    while (iter.hasNext) {
      val (key, value) = iter.next
      res = res.update(key, value)
    }
    res
  }

  /** This method will return a map where all the mappings
   *  for the given sequence of keys are removed from the map.
   *
   *  @param keys ...
   *  @return     the updated map
   *  @deprecated    use <code>-</code> instead
   */
  @deprecated def excl(keys: A*): Map[A, B] = excl(keys)

  /** This method removes all the mappings for keys provided by an
   *  iterator over the elements of the <code>keys</code> object.
   *
   *  @param keys ...
   *  @return     the updated map
   *  @deprecated    use <code>--</code> instead
   */
  @deprecated def excl(keys: Iterable[A]): Map[A, B] = {
    val iter = keys.elements
    var res = this
    while (iter.hasNext) {
      res = res - iter.next
    }
    res
  }

  /** This method controls how a mapping is represented in the string
   *  representation provided by method <code>toString</code>.
   *
   *  @param p ...
   *  @return  the string representation of a map entry
   */
  @deprecated def mappingToString[B1 >: B](p: (A, B1)) =
    p._1.toString() + " -> " + p._2

  /** @deprecated    use <code>+({A, B})</code> instead
   */
  @deprecated class MapTo(key: A) {
    def -> [B1 >: B](value: B1) = update(key, value)
  }
}