summaryrefslogtreecommitdiff
path: root/src/dotnet-library/scala/collection/immutable/Map.scala
blob: 65fd32379f3d995290c1a342689b8a3d6271a266 (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
/*                     __                                               *\
**     ________ ___   / /  ___     Scala API                            **
**    / __/ __// _ | / /  / _ |    (c) 2003-2006, LAMP/EPFL             **
**  __\ \/ /__/ __ |/ /__/ __ |                                         **
** /____/\___/_/ |_/____/_/ | |                                         **
**                          |/                                          **
\*                                                                      */

// $Id$


package scala.collection.immutable

import Predef._

/** <p>
 *    This class extends the <code>Map</code> interface of collections
 *    that unambiguously map keys to values (i.e. a key is mapped to at
 *    least one value).
 *  </p>
 *  <p>
 *    This class defines the interface for functional map implementations
 *    relying on immutable data structures.
 *  </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
 */
object Map {

  /** The empty map of this type; this is implemented as a treemap */
  def empty[A, B]: Map[A, B] = new EmptyMap[A, B]

  /** The canonical factory for this type
   */
  def apply[A, B](elems: {A, B}*) = empty[A, B] ++ elems
}

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)

  /** 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)
  }
}