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}