12
12
// /
13
13
// / \file
14
14
// /
15
- // / A 2 stage multi-map. Initially the multimap is mutable and can only be
16
- // / initialized. Once complete, the map is frozen and can be only used for map
17
- // / operations. It is guaranteed that all values are still in insertion order.
15
+ // / A 2 stage multi-map for use in contexts where one is iterating over an IR in
16
+ // / a read only way and then wants to use a multi-map for post-processing that
17
+ // / can support iteration in insertion order.
18
18
// /
19
- // / DISCUSSION: These restrictions flow from the internal implementation of the
20
- // / multi-map being a pair of keys, values. We form the map property by
21
- // / performing a stable_sort of the (key, value) in the process of freezing the
22
- // / map.
19
+ // / In the first stage, the multi-map can be initialized with new elements in a
20
+ // / purely additive fashion, but methods that rely on the map being frozen
21
+ // / (find, getRange(), erase, etc) assert.
22
+ // /
23
+ // / Once the user has finished iterating over the IR, the map is frozen and then
24
+ // / can only be used for map operations (find), erasing operations (erase), and
25
+ // / deterministic range iteration.
26
+ // /
27
+ // / This is accomplished by the internal implementation of the frozen multi map
28
+ // / just being an array of (key, value) pairs that when we freeze, we sort using
29
+ // / a stable sort on the key. Since we use a stable sort on the key, we know
30
+ // / that all of the individual multimap value arrays are still in insertion
31
+ // / order helping us avoid non-determinism like one must deal with when using
32
+ // / other maps.
23
33
// /
24
34
// ===----------------------------------------------------------------------===//
25
35
34
44
namespace swift {
35
45
36
46
template <typename Key, typename Value,
37
- typename VectorStorage = std::vector<std::pair<Key, Value>>>
47
+ typename VectorStorage = std::vector<std::pair<Key, Optional< Value> >>>
38
48
class FrozenMultiMap {
39
49
VectorStorage storage;
40
50
bool frozen = false ;
41
51
42
52
private:
43
53
struct PairToSecondElt ;
54
+ struct PairWithTypeErasedOptionalSecondElt ;
44
55
45
56
public:
46
57
using PairToSecondEltRange =
47
- TransformRange<ArrayRef<std::pair<Key, Value>>, PairToSecondElt>;
58
+ TransformRange<ArrayRef<std::pair<Key, Optional<Value>>>,
59
+ PairToSecondElt>;
48
60
49
61
FrozenMultiMap () = default ;
50
62
@@ -60,30 +72,61 @@ class FrozenMultiMap {
60
72
// inst as the first element.
61
73
auto start = std::lower_bound (
62
74
storage.begin (), storage.end (), std::make_pair (key, Value ()),
63
- [&](const std::pair<Key, Value> &p1, const std::pair<Key, Value> &p2) {
75
+ [&](const std::pair<Key, Optional<Value>> &p1,
76
+ const std::pair<Key, Optional<Value>> &p2) {
64
77
return p1.first < p2.first ;
65
78
});
66
- if (start == storage.end () || start->first != key) {
79
+
80
+ // If we did not find that first element or that key has a .none value
81
+ // (signaling that we erased it), return None.
82
+ if (start == storage.end () || start->first != key ||
83
+ !start->second .hasValue ()) {
67
84
return None;
68
85
}
69
86
70
87
// Ok, we found our first element. Now scan forward until we find a pair
71
88
// whose instruction is not our own instruction.
72
- auto end = find_if_not (
73
- start, storage.end (),
74
- [&](const std::pair<Key, Value> &pair) { return pair.first == key; });
89
+ auto end = find_if_not (start, storage.end (),
90
+ [&](const std::pair<Key, Optional<Value>> &pair) {
91
+ return pair.first == key;
92
+ });
75
93
unsigned count = std::distance (start, end);
76
- ArrayRef<std::pair<Key, Value>> slice (&*start, count);
94
+ ArrayRef<std::pair<Key, Optional< Value> >> slice (&*start, count);
77
95
return PairToSecondEltRange (slice, PairToSecondElt ());
78
96
}
79
97
98
+ bool erase (const Key &key) {
99
+ assert (isFrozen () &&
100
+ " Can not perform an erase operation until the map is frozen" );
101
+ // Since our array is sorted, we need to first find the first pair with our
102
+ // inst as the first element.
103
+ auto start = std::lower_bound (
104
+ storage.begin (), storage.end (), std::make_pair (key, Value ()),
105
+ [&](const std::pair<Key, Optional<Value>> &p1,
106
+ const std::pair<Key, Optional<Value>> &p2) {
107
+ return p1.first < p2.first ;
108
+ });
109
+
110
+ // If we did not find that first element or that key has a .none value
111
+ // (signaling that we erased it), return false.
112
+ if (start == storage.end () || start->first != key ||
113
+ !start->second .hasValue ()) {
114
+ return false ;
115
+ }
116
+
117
+ // Ok, we found our element. Just set its value to .none to signal it was
118
+ // destroyed and then return true.
119
+ start->second = None;
120
+ return true ;
121
+ }
122
+
80
123
bool isFrozen () const { return frozen; }
81
124
82
125
// / Set this map into its frozen state when we
83
126
void setFrozen () {
84
127
std::stable_sort (storage.begin (), storage.end (),
85
- [&](const std::pair<Key, Value> &lhs,
86
- const std::pair<Key, Value> &rhs) {
128
+ [&](const std::pair<Key, Optional< Value> > &lhs,
129
+ const std::pair<Key, Optional< Value> > &rhs) {
87
130
// Only compare the first entry so that we preserve
88
131
// insertion order.
89
132
return lhs.first < rhs.first ;
@@ -100,13 +143,14 @@ class FrozenMultiMap {
100
143
unsigned size () const { return storage.size (); }
101
144
bool empty () const { return storage.empty (); }
102
145
103
- struct iterator : std::iterator<std::forward_iterator_tag,
104
- std::pair<Key, PairToSecondEltRange>> {
146
+ struct iterator
147
+ : std::iterator<std::forward_iterator_tag,
148
+ std::pair<Key, Optional<PairToSecondEltRange>>> {
105
149
using base_iterator = typename decltype (storage)::iterator;
106
150
107
151
FrozenMultiMap ↦
108
152
base_iterator baseIter;
109
- Optional<std::pair<Key, PairToSecondEltRange>> currentValue;
153
+ Optional<std::pair<Key, Optional< PairToSecondEltRange> >> currentValue;
110
154
111
155
iterator (FrozenMultiMap &map, base_iterator iter)
112
156
: map(map), baseIter(iter), currentValue() {
@@ -123,21 +167,27 @@ class FrozenMultiMap {
123
167
}
124
168
125
169
// Otherwise, determine the next range that we are visiting.
126
- auto rangeEnd = std::find_if_not (std::next (baseIter), end,
127
- [&](const std::pair<Key, Value> &elt) {
128
- return elt.first == baseIter->first ;
129
- });
130
- unsigned count = std::distance (baseIter, rangeEnd);
131
- ArrayRef<std::pair<Key, Value>> slice (&*baseIter, count);
132
- currentValue = {baseIter->first ,
133
- PairToSecondEltRange (slice, PairToSecondElt ())};
170
+ auto rangeEnd =
171
+ std::find_if_not (std::next (baseIter), end,
172
+ [&](const std::pair<Key, Optional<Value>> &elt) {
173
+ return elt.first == baseIter->first ;
174
+ });
175
+
176
+ Optional<PairToSecondEltRange> resultRange;
177
+ if (baseIter->second .hasValue ()) {
178
+ unsigned count = std::distance (baseIter, rangeEnd);
179
+ ArrayRef<std::pair<Key, Optional<Value>>> slice (&*baseIter, count);
180
+ resultRange.emplace (slice, PairToSecondElt ());
181
+ }
182
+ currentValue = {baseIter->first , resultRange};
134
183
}
135
184
136
185
iterator &operator ++() {
137
- baseIter = std::find_if_not (std::next (baseIter), map.storage .end (),
138
- [&](const std::pair<Key, Value> &elt) {
139
- return elt.first == baseIter->first ;
140
- });
186
+ baseIter =
187
+ std::find_if_not (std::next (baseIter), map.storage .end (),
188
+ [&](const std::pair<Key, Optional<Value>> &elt) {
189
+ return elt.first == baseIter->first ;
190
+ });
141
191
updateCurrentValue ();
142
192
return *this ;
143
193
}
@@ -152,7 +202,7 @@ class FrozenMultiMap {
152
202
return tmp;
153
203
}
154
204
155
- std::pair<Key, PairToSecondEltRange> operator *() const {
205
+ std::pair<Key, Optional< PairToSecondEltRange> > operator *() const {
156
206
return *currentValue;
157
207
}
158
208
@@ -165,7 +215,19 @@ class FrozenMultiMap {
165
215
}
166
216
};
167
217
168
- using RangeType = llvm::iterator_range<iterator>;
218
+ struct ToNonErasedValues {
219
+ Optional<std::pair<Key, Optional<PairToSecondEltRange>>>
220
+ operator ()(std::pair<Key, Optional<PairToSecondEltRange>> pair) const {
221
+ if (!pair.second .hasValue ())
222
+ return None;
223
+ return pair;
224
+ }
225
+ };
226
+
227
+ using IgnoringErasedValueRangeType =
228
+ OptionalTransformRange<llvm::iterator_range<iterator>, ToNonErasedValues>;
229
+ using RangeType = TransformRange<IgnoringErasedValueRangeType,
230
+ PairWithTypeErasedOptionalSecondElt>;
169
231
170
232
// / Return a range of (key, ArrayRef<Value>) pairs. The keys are guaranteed to
171
233
// / be in key sorted order and the ArrayRef<Value> are in insertion order.
@@ -175,22 +237,36 @@ class FrozenMultiMap {
175
237
auto *self = const_cast <FrozenMultiMap *>(this );
176
238
iterator iter1 = iterator (*self, self->storage .begin ());
177
239
iterator iter2 = iterator (*self, self->storage .end ());
178
- return llvm::make_range (iter1, iter2);
240
+ auto baseRange = llvm::make_range (iter1, iter2);
241
+ auto optRange = makeOptionalTransformRange (baseRange, ToNonErasedValues ());
242
+ return makeTransformRange (optRange, PairWithTypeErasedOptionalSecondElt ());
179
243
}
180
244
};
181
245
182
246
template <typename Key, typename Value, typename Storage>
183
247
struct FrozenMultiMap <Key, Value, Storage>::PairToSecondElt {
184
248
PairToSecondElt () {}
185
249
186
- Value operator ()(const std::pair<Key, Value> &pair) const {
187
- return pair.second ;
250
+ Value operator ()(const std::pair<Key, Optional<Value>> &pair) const {
251
+ return *pair.second ;
252
+ }
253
+ };
254
+
255
+ template <typename Key, typename Value, typename Storage>
256
+ struct FrozenMultiMap <Key, Value,
257
+ Storage>::PairWithTypeErasedOptionalSecondElt {
258
+ PairWithTypeErasedOptionalSecondElt () {}
259
+
260
+ std::pair<Key, PairToSecondEltRange>
261
+ operator ()(const std::pair<Key, Optional<PairToSecondEltRange>> &pair) const {
262
+ return std::make_pair (pair.first , *pair.second );
188
263
}
189
264
};
190
265
191
266
template <typename Key, typename Value, unsigned SmallSize>
192
267
using SmallFrozenMultiMap =
193
- FrozenMultiMap<Key, Value, SmallVector<std::pair<Key, Value>, SmallSize>>;
268
+ FrozenMultiMap<Key, Value,
269
+ SmallVector<std::pair<Key, Optional<Value>>, SmallSize>>;
194
270
195
271
} // namespace swift
196
272
0 commit comments