Fix: Don't allow right-click to close world generation progress window. (#13084)
[openttd-github.git] / src / core / multimap.hpp
blob9a646414d17624119b2a0ff677ca0cc0f0ff8dd3
1 /*
2 * This file is part of OpenTTD.
3 * OpenTTD 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, version 2.
4 * OpenTTD 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.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
8 /** @file multimap.hpp Multimap with deterministic ordering of items with equal keys. */
10 #ifndef MULTIMAP_HPP
11 #define MULTIMAP_HPP
13 template<typename Tkey, typename Tvalue, typename Tcompare>
14 class MultiMap;
16 /**
17 * STL-style iterator for MultiMap.
18 * @tparam Tmap_iter Iterator type for the map in the MultiMap.
19 * @tparam Tlist_iter Iterator type for the lists in the MultiMap.
20 * @tparam Tkey Key type of the MultiMap.
21 * @tparam Tvalue Value type of the MultMap.
22 * @tparam Tcompare Comparator type for keys of the MultiMap.
24 template<class Tmap_iter, class Tlist_iter, class Tkey, class Tvalue, class Tcompare>
25 class MultiMapIterator {
26 protected:
27 friend class MultiMap<Tkey, Tvalue, Tcompare>;
28 typedef MultiMapIterator<Tmap_iter, Tlist_iter, Tkey, Tvalue, Tcompare> Self;
30 Tlist_iter list_iter; ///< Iterator pointing to current position in the current list of items with equal keys.
31 Tmap_iter map_iter; ///< Iterator pointing to the position of the current list of items with equal keys in the map.
33 /**
34 * Flag to show that the iterator has just "walked" a step in the map.
35 * We cannot check the current list for that as we might have reached end() of the map. In that case we'd need to
36 * set list_iter to some sort of "invalid" state, but that's impossible as operator== yields undefined behaviour
37 * if the iterators don't belong to the same list and there is no list at end(). So if we created a static empty
38 * list and an "invalid" iterator in that we could not determine if the iterator is invalid while it's valid. We
39 * can also not determine if the map iterator is valid while we don't have the map; so in the end it's easiest to
40 * just introduce an extra flag.
42 bool list_valid;
44 public:
45 /**
46 * Simple, dangerous constructor to allow later assignment with operator=.
48 MultiMapIterator() : list_valid(false) {}
50 /**
51 * Constructor to allow possibly const iterators to be assigned from possibly
52 * non-const map iterators. You can assign end() like this.
53 * @tparam Tnon_const Iterator type assignable to Tmap_iter (which might be const).
54 * @param mi One such iterator.
56 template<class Tnon_const>
57 MultiMapIterator(Tnon_const mi) : map_iter(mi), list_valid(false) {}
59 /**
60 * Constructor to allow specifying an exact position in map and list. You cannot
61 * construct end() like this as the constructor will actually check li and mi->second
62 * for list_valid.
63 * @param mi Iterator in the map.
64 * @param li Iterator in the list.
66 MultiMapIterator(Tmap_iter mi, Tlist_iter li) : list_iter(li), map_iter(mi)
68 this->list_valid = (this->list_iter != this->map_iter->second.begin());
71 /**
72 * Assignment iterator like constructor with the same signature.
73 * @tparam Tnon_const Iterator type assignable to Tmap_iter (which might be const).
74 * @param mi One such iterator.
75 * @return This iterator.
77 template<class Tnon_const>
78 Self &operator=(Tnon_const mi)
80 this->map_iter = mi;
81 this->list_valid = false;
82 return *this;
85 /**
86 * Dereference operator. Works just like usual STL operator*() on various containers.
87 * Doesn't do a lot of checks for sanity, just like STL.
88 * @return The value associated with the item this iterator points to.
90 Tvalue &operator*() const
92 assert(!this->map_iter->second.empty());
93 return this->list_valid ?
94 this->list_iter.operator*() :
95 this->map_iter->second.begin().operator*();
98 /**
99 * Same as operator*(), but returns a pointer.
100 * @return Pointer to the value this iterator points to.
102 Tvalue *operator->() const
104 assert(!this->map_iter->second.empty());
105 return this->list_valid ?
106 this->list_iter.operator->() :
107 this->map_iter->second.begin().operator->();
110 inline const Tmap_iter &GetMapIter() const { return this->map_iter; }
111 inline const Tlist_iter &GetListIter() const { return this->list_iter; }
112 inline bool ListValid() const { return this->list_valid; }
114 const Tkey &GetKey() const { return this->map_iter->first; }
117 * Prefix increment operator. Increment the iterator and set it to the
118 * next item in the MultiMap. This either increments the list iterator
119 * or the map iterator and sets list_valid accordingly.
120 * @return This iterator after incrementing.
122 Self &operator++()
124 assert(!this->map_iter->second.empty());
125 if (this->list_valid) {
126 if (++this->list_iter == this->map_iter->second.end()) {
127 ++this->map_iter;
128 this->list_valid = false;
130 } else {
131 this->list_iter = ++(this->map_iter->second.begin());
132 if (this->list_iter == this->map_iter->second.end()) {
133 ++this->map_iter;
134 } else {
135 this->list_valid = true;
138 return *this;
142 * Postfix increment operator. Same as prefix increment, but return the
143 * previous state.
144 * @param dummy param to mark postfix.
145 * @return This iterator before incrementing.
147 Self operator++(int)
149 Self tmp = *this;
150 this->operator++();
151 return tmp;
155 * Prefix decrement operator. Decrement the iterator and set it to the
156 * previous item in the MultiMap.
157 * @return This iterator after decrementing.
159 Self &operator--()
161 assert(!this->map_iter->second.empty());
162 if (!this->list_valid) {
163 --this->map_iter;
164 this->list_iter = this->map_iter->second.end();
165 assert(!this->map_iter->second.empty());
168 this->list_valid = (--this->list_iter != this->map_iter->second.begin());
169 return *this;
173 * Postfix decrement operator. Same as prefix decrement, but return the
174 * previous state.
175 * @param dummy param to mark postfix.
176 * @return This iterator before decrementing.
178 Self operator--(int)
180 Self tmp = *this;
181 this->operator--();
182 return tmp;
186 /* Generic comparison functions for const/non-const MultiMap iterators and map iterators */
189 * Compare two MultiMap iterators. Iterators are equal if
190 * 1. Their map iterators are equal.
191 * 2. They agree about list_valid.
192 * 3. If list_valid they agree about list_iter.
193 * Lots of template parameters to make all possible const and non-const types of MultiMap iterators
194 * (on maps with const and non-const values) comparable to each other.
195 * @param iter1 First iterator to compare.
196 * @param iter2 Second iterator to compare.
197 * @return If iter1 and iter2 are equal.
199 template<class Tmap_iter1, class Tlist_iter1, class Tmap_iter2, class Tlist_iter2, class Tkey, class Tvalue1, class Tvalue2, class Tcompare>
200 bool operator==(const MultiMapIterator<Tmap_iter1, Tlist_iter1, Tkey, Tvalue1, Tcompare> &iter1, const MultiMapIterator<Tmap_iter2, Tlist_iter2, Tkey, Tvalue2, Tcompare> &iter2)
202 if (iter1.GetMapIter() != iter2.GetMapIter()) return false;
203 if (!iter1.ListValid()) return !iter2.ListValid();
204 return iter2.ListValid() ?
205 iter1.GetListIter() == iter2.GetListIter() : false;
209 * Inverse of operator==().
210 * Lots of template parameters to make all possible const and non-const types of MultiMap iterators
211 * (on maps with const and non-const values) comparable to each other.
212 * @param iter1 First iterator to compare.
213 * @param iter2 Second iterator to compare.
214 * @return If iter1 and iter2 are not equal.
216 template<class Tmap_iter1, class Tlist_iter1, class Tmap_iter2, class Tlist_iter2, class Tkey, class Tvalue1, class Tvalue2, class Tcompare>
217 bool operator!=(const MultiMapIterator<Tmap_iter1, Tlist_iter1, Tkey, Tvalue1, Tcompare> &iter1, const MultiMapIterator<Tmap_iter2, Tlist_iter2, Tkey, Tvalue2, Tcompare> &iter2)
219 return !(iter1 == iter2);
223 * Check if a MultiMap iterator is at the begin of a list pointed to by the given map iterator.
224 * Lots of template parameters to make all possible const and non-const types of MultiMap iterators
225 * (on maps with const and non-const values) comparable to all possible types of map iterators.
226 * @param iter1 MultiMap iterator.
227 * @param iter2 Map iterator.
228 * @return If iter1 points to the begin of the list pointed to by iter2.
230 template<class Tmap_iter1, class Tlist_iter1, class Tmap_iter2, class Tkey, class Tvalue, class Tcompare >
231 bool operator==(const MultiMapIterator<Tmap_iter1, Tlist_iter1, Tkey, Tvalue, Tcompare> &iter1, const Tmap_iter2 &iter2)
233 return !iter1.ListValid() && iter1.GetMapIter() == iter2;
237 * Inverse of operator==() with same signature.
238 * @param iter1 MultiMap iterator.
239 * @param iter2 Map iterator.
240 * @return If iter1 doesn't point to the begin of the list pointed to by iter2.
242 template<class Tmap_iter1, class Tlist_iter1, class Tmap_iter2, class Tkey, class Tvalue, class Tcompare >
243 bool operator!=(const MultiMapIterator<Tmap_iter1, Tlist_iter1, Tkey, Tvalue, Tcompare> &iter1, const Tmap_iter2 &iter2)
245 return iter1.ListValid() || iter1.GetMapIter() != iter2;
249 * Same as operator==() with reversed order of arguments.
250 * @param iter2 Map iterator.
251 * @param iter1 MultiMap iterator.
252 * @return If iter1 points to the begin of the list pointed to by iter2.
254 template<class Tmap_iter1, class Tlist_iter1, class Tmap_iter2, class Tkey, class Tvalue, class Tcompare >
255 bool operator==(const Tmap_iter2 &iter2, const MultiMapIterator<Tmap_iter1, Tlist_iter1, Tkey, Tvalue, Tcompare> &iter1)
257 return !iter1.ListValid() && iter1.GetMapIter() == iter2;
261 * Same as operator!=() with reversed order of arguments.
262 * @param iter2 Map iterator.
263 * @param iter1 MultiMap iterator.
264 * @return If iter1 doesn't point to the begin of the list pointed to by iter2.
266 template<class Tmap_iter1, class Tlist_iter1, class Tmap_iter2, class Tkey, class Tvalue, class Tcompare >
267 bool operator!=(const Tmap_iter2 &iter2, const MultiMapIterator<Tmap_iter1, Tlist_iter1, Tkey, Tvalue, Tcompare> &iter1)
269 return iter1.ListValid() || iter1.GetMapIter() != iter2;
274 * Hand-rolled multimap as map of lists. Behaves mostly like a list, but is sorted
275 * by Tkey so that you can easily look up ranges of equal keys. Those ranges are
276 * internally ordered in a deterministic way (contrary to STL multimap). All
277 * STL-compatible members are named in STL style, all others are named in OpenTTD
278 * style.
280 template<typename Tkey, typename Tvalue, typename Tcompare = std::less<Tkey> >
281 class MultiMap : public std::map<Tkey, std::list<Tvalue>, Tcompare > {
282 public:
283 typedef typename std::list<Tvalue> List;
284 typedef typename List::iterator ListIterator;
285 typedef typename List::const_iterator ConstListIterator;
287 typedef typename std::map<Tkey, List, Tcompare > Map;
288 typedef typename Map::iterator MapIterator;
289 typedef typename Map::const_iterator ConstMapIterator;
291 typedef MultiMapIterator<MapIterator, ListIterator, Tkey, Tvalue, Tcompare> iterator;
292 typedef MultiMapIterator<ConstMapIterator, ConstListIterator, Tkey, const Tvalue, Tcompare> const_iterator;
295 * Erase the value pointed to by an iterator. The iterator may be invalid afterwards.
296 * @param it Iterator pointing at some value.
297 * @return Iterator to the element after the deleted one (or invalid).
299 iterator erase(iterator it)
301 List &list = it.map_iter->second;
302 assert(!list.empty());
303 if (it.list_valid) {
304 it.list_iter = list.erase(it.list_iter);
305 /* This can't be the first list element as otherwise list_valid would have
306 * to be false. So the list cannot be empty here. */
307 if (it.list_iter == list.end()) {
308 ++it.map_iter;
309 it.list_valid = false;
311 } else {
312 list.erase(list.begin());
313 if (list.empty()) this->Map::erase(it.map_iter++);
315 return it;
319 * Insert a value at the end of the range with the specified key.
320 * @param key Key to be inserted at.
321 * @param val Value to be inserted.
323 void Insert(const Tkey &key, const Tvalue &val)
325 List &list = (*this)[key];
326 list.push_back(val);
327 assert(!list.empty());
331 * Count all items in this MultiMap. This involves iterating over the map.
332 * @return Number of items in the MultiMap.
334 size_t size() const
336 size_t ret = 0;
337 for (ConstMapIterator it = this->Map::begin(); it != this->Map::end(); ++it) {
338 ret += it->second.size();
340 return ret;
344 * Count the number of ranges with equal keys in this MultiMap.
345 * @return Number of ranges with equal keys.
347 size_t MapSize() const
349 return this->Map::size();
353 * Get a pair of iterators specifying a range of items with equal keys.
354 * @param key Key to look for.
355 * @return Range of items with given key.
357 std::pair<iterator, iterator> equal_range(const Tkey &key)
359 MapIterator begin(this->lower_bound(key));
360 if (begin != this->Map::end() && begin->first == key) {
361 MapIterator end = begin;
362 return std::make_pair(begin, ++end);
364 return std::make_pair(begin, begin);
368 * Get a pair of constant iterators specifying a range of items with equal keys.
369 * @param key Key to look for.
370 * @return Constant range of items with given key.
372 std::pair<const_iterator, const_iterator> equal_range(const Tkey &key) const
374 ConstMapIterator begin(this->lower_bound(key));
375 if (begin != this->Map::end() && begin->first == key) {
376 ConstMapIterator end = begin;
377 return std::make_pair(begin, ++end);
379 return std::make_pair(begin, begin);
383 #endif /* MULTIMAP_HPP */