|
| 1 | +/* |
| 2 | + * Scala (https://www.scala-lang.org) |
| 3 | + * |
| 4 | + * Copyright EPFL and Lightbend, Inc. |
| 5 | + * |
| 6 | + * Licensed under Apache License 2.0 |
| 7 | + * (http://www.apache.org/licenses/LICENSE-2.0). |
| 8 | + * |
| 9 | + * See the NOTICE file distributed with this work for |
| 10 | + * additional information regarding copyright ownership. |
| 11 | + */ |
| 12 | + |
| 13 | +package scala.collection.mutable |
| 14 | + |
| 15 | +import language.experimental.captureChecking |
| 16 | + |
| 17 | +/** A trait for mutable maps with multiple values assigned to a key. |
| 18 | + * |
| 19 | + * This class is typically used as a mixin. It turns maps which map `K` |
| 20 | + * to `Set[V]` objects into multimaps that map `K` to `V` objects. |
| 21 | + * |
| 22 | + * @example {{{ |
| 23 | + * // first import all necessary types from package `collection.mutable` |
| 24 | + * import collection.mutable.{ HashMap, MultiMap, Set } |
| 25 | + * |
| 26 | + * // to create a `MultiMap` the easiest way is to mixin it into a normal |
| 27 | + * // `Map` instance |
| 28 | + * val mm = new HashMap[Int, Set[String]] with MultiMap[Int, String] |
| 29 | + * |
| 30 | + * // to add key-value pairs to a multimap it is important to use |
| 31 | + * // the method `addBinding` because standard methods like `+` will |
| 32 | + * // overwrite the complete key-value pair instead of adding the |
| 33 | + * // value to the existing key |
| 34 | + * mm.addBinding(1, "a") |
| 35 | + * mm.addBinding(2, "b") |
| 36 | + * mm.addBinding(1, "c") |
| 37 | + * |
| 38 | + * // mm now contains `Map(2 -> Set(b), 1 -> Set(c, a))` |
| 39 | + * |
| 40 | + * // to check if the multimap contains a value there is method |
| 41 | + * // `entryExists`, which allows to traverse the including set |
| 42 | + * mm.entryExists(1, _ == "a") == true |
| 43 | + * mm.entryExists(1, _ == "b") == false |
| 44 | + * mm.entryExists(2, _ == "b") == true |
| 45 | + * |
| 46 | + * // to remove a previous added value there is the method `removeBinding` |
| 47 | + * mm.removeBinding(1, "a") |
| 48 | + * mm.entryExists(1, _ == "a") == false |
| 49 | + * }}} |
| 50 | + * |
| 51 | + * @define coll multimap |
| 52 | + * @define Coll `MultiMap` |
| 53 | + */ |
| 54 | +@deprecated("Use a scala.collection.mutable.MultiDict in the scala-collection-contrib module", "2.13.0") |
| 55 | +trait MultiMap[K, V] extends Map[K, Set[V]] { |
| 56 | + /** Creates a new set. |
| 57 | + * |
| 58 | + * Classes that use this trait as a mixin can override this method |
| 59 | + * to have the desired implementation of sets assigned to new keys. |
| 60 | + * By default this is `HashSet`. |
| 61 | + * |
| 62 | + * @return An empty set of values of type `V`. |
| 63 | + */ |
| 64 | + protected def makeSet: Set[V] = new HashSet[V] |
| 65 | + |
| 66 | + /** Assigns the specified `value` to a specified `key`. If the key |
| 67 | + * already has a binding to equal to `value`, nothing is changed; |
| 68 | + * otherwise a new binding is added for that `key`. |
| 69 | + * |
| 70 | + * @param key The key to which to bind the new value. |
| 71 | + * @param value The value to bind to the key. |
| 72 | + * @return A reference to this multimap. |
| 73 | + */ |
| 74 | + def addBinding(key: K, value: V): this.type = { |
| 75 | + get(key) match { |
| 76 | + case None => |
| 77 | + val set = makeSet |
| 78 | + set += value |
| 79 | + this(key) = set |
| 80 | + case Some(set) => |
| 81 | + set += value |
| 82 | + } |
| 83 | + this |
| 84 | + } |
| 85 | + |
| 86 | + /** Removes the binding of `value` to `key` if it exists, otherwise this |
| 87 | + * operation doesn't have any effect. |
| 88 | + * |
| 89 | + * If this was the last value assigned to the specified key, the |
| 90 | + * set assigned to that key will be removed as well. |
| 91 | + * |
| 92 | + * @param key The key of the binding. |
| 93 | + * @param value The value to remove. |
| 94 | + * @return A reference to this multimap. |
| 95 | + */ |
| 96 | + def removeBinding(key: K, value: V): this.type = { |
| 97 | + get(key) match { |
| 98 | + case None => |
| 99 | + case Some(set) => |
| 100 | + set -= value |
| 101 | + if (set.isEmpty) this -= key |
| 102 | + } |
| 103 | + this |
| 104 | + } |
| 105 | + |
| 106 | + /** Checks if there exists a binding to `key` such that it satisfies the predicate `p`. |
| 107 | + * |
| 108 | + * @param key The key for which the predicate is checked. |
| 109 | + * @param p The predicate which a value assigned to the key must satisfy. |
| 110 | + * @return A boolean if such a binding exists |
| 111 | + */ |
| 112 | + def entryExists(key: K, p: V => Boolean): Boolean = get(key) match { |
| 113 | + case None => false |
| 114 | + case Some(set) => set exists p |
| 115 | + } |
| 116 | +} |
0 commit comments