001// SPDX-FileCopyrightText: 2018 Paul Schaub <vanitasvitae@fsfe.org> 002// 003// SPDX-License-Identifier: Apache-2.0 004 005package org.pgpainless.util; 006 007import javax.annotation.Nonnull; 008import java.util.Collection; 009import java.util.HashMap; 010import java.util.LinkedHashSet; 011import java.util.Map; 012import java.util.Set; 013 014public class MultiMap<K, V> { 015 016 private final Map<K, Set<V>> map; 017 018 public MultiMap() { 019 map = new HashMap<>(); 020 } 021 022 public MultiMap(@Nonnull MultiMap<K, V> other) { 023 this.map = new HashMap<>(); 024 for (K k : other.map.keySet()) { 025 map.put(k, new LinkedHashSet<>(other.map.get(k))); 026 } 027 } 028 029 public MultiMap(@Nonnull Map<K, Set<V>> content) { 030 this.map = new HashMap<>(content); 031 } 032 033 public int size() { 034 return map.size(); 035 } 036 037 public boolean isEmpty() { 038 return map.isEmpty(); 039 } 040 041 public boolean containsKey(K o) { 042 return map.containsKey(o); 043 } 044 045 public boolean containsValue(V o) { 046 for (Set<V> values : map.values()) { 047 if (values.contains(o)) return true; 048 } 049 return false; 050 } 051 052 public Set<V> get(K o) { 053 return map.get(o); 054 } 055 056 public void put(K k, V v) { 057 Set<V> values = map.get(k); 058 if (values == null) { 059 values = new LinkedHashSet<>(); 060 map.put(k, values); 061 } 062 values.add(v); 063 } 064 065 public void put(K k, Set<V> vs) { 066 for (V v : vs) { 067 put(k, v); 068 } 069 } 070 071 public void removeAll(K o) { 072 map.remove(o); 073 } 074 075 public void remove(K o, V v) { 076 Set<V> vs = map.get(o); 077 if (vs == null) return; 078 vs.remove(v); 079 } 080 081 public void putAll(MultiMap<K, V> other) { 082 for (K key : other.keySet()) { 083 put(key, other.get(key)); 084 } 085 } 086 087 public void clear() { 088 map.clear(); 089 } 090 091 public Set<K> keySet() { 092 return map.keySet(); 093 } 094 095 public Collection<Set<V>> values() { 096 return map.values(); 097 } 098 099 public Set<Map.Entry<K, Set<V>>> entrySet() { 100 return map.entrySet(); 101 } 102 103 @Override 104 public boolean equals(Object o) { 105 if (o == null) { 106 return false; 107 } 108 109 if (!(o instanceof MultiMap)) { 110 return false; 111 } 112 113 if (this == o) { 114 return true; 115 } 116 117 return map.equals(((MultiMap<?, ?>) o).map); 118 } 119 120 @Override 121 public int hashCode() { 122 return map.hashCode(); 123 } 124}