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
|
/*
* esodata - data structures and other things, of varying utility
* Copyright 2022, Ben Culkin
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package bjc.esodata;
import java.util.*;
import bjc.data.Pair;
/**
* Represents a map keyed by pairs, where you can look up all the items that
* have a particular left or right key value.
*
* NOTE: Using the keySet/values/entrySet views to modify the map will break the
* tracking invariants.
*
* @author bjcul
*
* @param <Left>
* @param <Right>
* @param <Value>
*/
public class PairMap<Left, Right, Value> implements Map<Pair<Left, Right>, Value> {
private Map<Pair<Left, Right>, Value> backing;
private Multimap<Left, Pair<Left, Right>> leftTracker;
private Multimap<Right, Pair<Left, Right>> rightTracker;
/**
* Create a new pair map.
*/
public PairMap() {
this.backing = new HashMap<>();
this.leftTracker = new TSetMultimap<>();
this.rightTracker = new TSetMultimap<>();
}
/**
* Get all of the key-pairs which contain the given left value.
*
* @param val The value to search for.
*
* @return All of the key-pairs containing the given value.
*/
public Set<Pair<Left, Right>> getLeft(Left val) {
return leftTracker.get(val);
}
/**
* Get all of the key-pairs which contain the given right value.
*
* @param val The value to search for.
*
* @return All of the key-pairs containing the given value.
*/
public Set<Pair<Left, Right>> getRight(Right val) {
return rightTracker.get(val);
}
/**
* Get a value without having to construct a pair callee-side
*
* @param lft The left value
* @param rght The right value.
*
* @return The value corresponding to the given key-pair, if one exists
*/
public Value biget(Left lft, Right rght) {
return backing.get(Pair.pair(lft, rght));
}
@Override
public int size() {
return backing.size();
}
@Override
public boolean isEmpty() {
return backing.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return backing.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return backing.containsKey(value);
}
@Override
public Value get(Object key) {
return backing.get(key);
}
@Override
public Value put(Pair<Left, Right> key, Value value) {
Value ret = backing.put(key, value);
leftTracker.add(key.getLeft(), key);
rightTracker.add(key.getRight(), key);
return ret;
}
@Override
public Value remove(Object key) {
@SuppressWarnings("unchecked")
Pair<Left, Right> actKey = (Pair<Left, Right>) key;
leftTracker.remove(actKey.getLeft(), actKey);
rightTracker.remove(actKey.getRight(), actKey);
return backing.remove(key);
}
@Override
public void putAll(Map<? extends Pair<Left, Right>, ? extends Value> m) {
for (Entry<? extends Pair<Left, Right>, ? extends Value> entry : m.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
@Override
public void clear() {
backing.clear();
leftTracker = new TSetMultimap<>();
rightTracker = new TSetMultimap<>();
}
// TODO: Update these to not break the tracking invariants
@Override
public Set<Pair<Left, Right>> keySet() {
return backing.keySet();
}
@Override
public Collection<Value> values() {
return backing.values();
}
@Override
public Set<Entry<Pair<Left, Right>, Value>> entrySet() {
return backing.entrySet();
}
}
|