(svn r27950) -Merge: Documentation updates from 1.7 branch
[openttd.git] / src / core / multimap.hpp
blobe90667714173be0310160265719ac899ac0f8748
1 /* $Id$ */
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
8 */
10 /** @file multimap.hpp Multimap with deterministic ordering of items with equal keys. */
12 #ifndef MULTIMAP_HPP
13 #define MULTIMAP_HPP
15 #include <map>
16 #include <list>
18 template<typename Tkey, typename Tvalue, typename Tcompare>
19 class MultiMap;
21 /**
22 * STL-style iterator for MultiMap.
23 * @tparam Tmap_iter Iterator type for the map in the MultiMap.
24 * @tparam Tlist_iter Iterator type for the lists in the MultiMap.
25 * @tparam Tkey Key type of the MultiMap.
26 * @tparam Tvalue Value type of the MultMap.
27 * @tparam Tcompare Comparator type for keys of the MultiMap.
29 template<class Tmap_iter, class Tlist_iter, class Tkey, class Tvalue, class Tcompare>
30 class MultiMapIterator {
31 protected:
32 friend class MultiMap<Tkey, Tvalue, Tcompare>;
33 typedef MultiMapIterator<Tmap_iter, Tlist_iter, Tkey, Tvalue, Tcompare> Self;
35 Tlist_iter list_iter; ///< Iterator pointing to current position in the current list of items with equal keys.
36 Tmap_iter map_iter; ///< Iterator pointing to the position of the current list of items with equal keys in the map.
38 /**
39 * Flag to show that the iterator has just "walked" a step in the map.
40 * We cannot check the current list for that as we might have reached end() of the map. In that case we'd need to
41 * set list_iter to some sort of "invalid" state, but that's impossible as operator== yields undefined behaviour
42 * if the iterators don't belong to the same list and there is no list at end(). So if we created a static empty
43 * list and an "invalid" iterator in that we could not determine if the iterator is invalid while it's valid. We
44 * 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
45 * just introduce an extra flag.
47 bool list_valid;
49 public:
50 /**
51 * Simple, dangerous constructor to allow later assignment with operator=.
53 MultiMapIterator() : list_valid(false) {}
55 /**
56 * Constructor to allow possibly const iterators to be assigned from possibly
57 * non-const map iterators. You can assign end() like this.
58 * @tparam Tnon_const Iterator type assignable to Tmap_iter (which might be const).
59 * @param mi One such iterator.
61 template<class Tnon_const>
62 MultiMapIterator(Tnon_const mi) : map_iter(mi), list_valid(false) {}
64 /**
65 * Constructor to allow specifying an exact position in map and list. You cannot
66 * construct end() like this as the constructor will actually check li and mi->second
67 * for list_valid.
68 * @param mi Iterator in the map.
69 * @param li Iterator in the list.
71 MultiMapIterator(Tmap_iter mi, Tlist_iter li) : list_iter(li), map_iter(mi)
73 this->list_valid = (this->list_iter != this->map_iter->second.begin());
76 /**
77 * Assignment iterator like constructor with the same signature.
78 * @tparam Tnon_const Iterator type assignable to Tmap_iter (which might be const).
79 * @param mi One such iterator.
80 * @return This iterator.
82 template<class Tnon_const>
83 Self &operator=(Tnon_const mi)
85 this->map_iter = mi;
86 this->list_valid = false;
87 return *this;
90 /**
91 * Dereference operator. Works just like usual STL operator*() on various containers.
92 * Doesn't do a lot of checks for sanity, just like STL.
93 * @return The value associated with the item this iterator points to.
95 Tvalue &operator*() const
97 assert(!this->map_iter->second.empty());
98 return this->list_valid ?
99 this->list_iter.operator*() :
100 this->map_iter->second.begin().operator*();
104 * Same as operator*(), but returns a pointer.
105 * @return Pointer to the value this iterator points to.
107 Tvalue *operator->() const
109 assert(!this->map_iter->second.empty());
110 return this->list_valid ?
111 this->list_iter.operator->() :
112 this->map_iter->second.begin().operator->();
115 inline const Tmap_iter &GetMapIter() const { return this->map_iter; }
116 inline const Tlist_iter &GetListIter() const { return this->list_iter; }
117 inline bool ListValid() const { return this->list_valid; }
119 const Tkey &GetKey() const { return this->map_iter->first; }
122 * Prefix increment operator. Increment the iterator and set it to the
123 * next item in the MultiMap. This either increments the list iterator
124 * or the map iterator and sets list_valid accordingly.
125 * @return This iterator after incrementing.
127 Self &operator++()
129 assert(!this->map_iter->second.empty());
130 if (this->list_valid) {
131 if (++this->list_iter == this->map_iter->second.end()) {
132 ++this->map_iter;
133 this->list_valid = false;
135 } else {
136 this->list_iter = ++(this->map_iter->second.begin());
137 if (this->list_iter == this->map_iter->second.end()) {
138 ++this->map_iter;
139 } else {
140 this->list_valid = true;
143 return *this;
147 * Postfix increment operator. Same as prefix increment, but return the
148 * previous state.
149 * @param dummy param to mark postfix.
150 * @return This iterator before incrementing.
152 Self operator++(int)
154 Self tmp = *this;
155 this->operator++();
156 return tmp;
160 * Prefix decrement operator. Decrement the iterator and set it to the
161 * previous item in the MultiMap.
162 * @return This iterator after decrementing.
164 Self &operator--()
166 assert(!this->map_iter->second.empty());
167 if (!this->list_valid) {
168 --this->map_iter;
169 this->list_iter = this->map_iter->second.end();
170 assert(!this->map_iter->second.empty());
173 this->list_valid = (--this->list_iter != this->map_iter->second.begin());
174 return *this;
178 * Postfix decrement operator. Same as prefix decrement, but return the
179 * previous state.
180 * @param dummy param to mark postfix.
181 * @return This iterator before decrementing.
183 Self operator--(int)
185 Self tmp = *this;
186 this->operator--();
187 return tmp;
191 /* Generic comparison functions for const/non-const MultiMap iterators and map iterators */
194 * Compare two MultiMap iterators. Iterators are equal if
195 * 1. Their map iterators are equal.
196 * 2. They agree about list_valid.
197 * 3. If list_valid they agree about list_iter.
198 * Lots of template parameters to make all possible const and non-const types of MultiMap iterators
199 * (on maps with const and non-const values) comparable to each other.
200 * @param iter1 First iterator to compare.
201 * @param iter2 Second iterator to compare.
202 * @return If iter1 and iter2 are equal.
204 template<class Tmap_iter1, class Tlist_iter1, class Tmap_iter2, class Tlist_iter2, class Tkey, class Tvalue1, class Tvalue2, class Tcompare>
205 bool operator==(const MultiMapIterator<Tmap_iter1, Tlist_iter1, Tkey, Tvalue1, Tcompare> &iter1, const MultiMapIterator<Tmap_iter2, Tlist_iter2, Tkey, Tvalue2, Tcompare> &iter2)
207 if (iter1.GetMapIter() != iter2.GetMapIter()) return false;
208 if (!iter1.ListValid()) return !iter2.ListValid();
209 return iter2.ListValid() ?
210 iter1.GetListIter() == iter2.GetListIter() : false;
214 * Inverse of operator==().
215 * Lots of template parameters to make all possible const and non-const types of MultiMap iterators
216 * (on maps with const and non-const values) comparable to each other.
217 * @param iter1 First iterator to compare.
218 * @param iter2 Second iterator to compare.
219 * @return If iter1 and iter2 are not equal.
221 template<class Tmap_iter1, class Tlist_iter1, class Tmap_iter2, class Tlist_iter2, class Tkey, class Tvalue1, class Tvalue2, class Tcompare>
222 bool operator!=(const MultiMapIterator<Tmap_iter1, Tlist_iter1, Tkey, Tvalue1, Tcompare> &iter1, const MultiMapIterator<Tmap_iter2, Tlist_iter2, Tkey, Tvalue2, Tcompare> &iter2)
224 return !(iter1 == iter2);
228 * Check if a MultiMap iterator is at the begin of a list pointed to by the given map iterator.
229 * Lots of template parameters to make all possible const and non-const types of MultiMap iterators
230 * (on maps with const and non-const values) comparable to all possible types of map iterators.
231 * @param iter1 MultiMap iterator.
232 * @param iter2 Map iterator.
233 * @return If iter1 points to the begin of the list pointed to by iter2.
235 template<class Tmap_iter1, class Tlist_iter1, class Tmap_iter2, class Tkey, class Tvalue, class Tcompare >
236 bool operator==(const MultiMapIterator<Tmap_iter1, Tlist_iter1, Tkey, Tvalue, Tcompare> &iter1, const Tmap_iter2 &iter2)
238 return !iter1.ListValid() && iter1.GetMapIter() == iter2;
242 * Inverse of operator==() with same signature.
243 * @param iter1 MultiMap iterator.
244 * @param iter2 Map iterator.
245 * @return If iter1 doesn't point to the begin of the list pointed to by iter2.
247 template<class Tmap_iter1, class Tlist_iter1, class Tmap_iter2, class Tkey, class Tvalue, class Tcompare >
248 bool operator!=(const MultiMapIterator<Tmap_iter1, Tlist_iter1, Tkey, Tvalue, Tcompare> &iter1, const Tmap_iter2 &iter2)
250 return iter1.ListValid() || iter1.GetMapIter() != iter2;
254 * Same as operator==() with reversed order of arguments.
255 * @param iter2 Map iterator.
256 * @param iter1 MultiMap iterator.
257 * @return If iter1 points to the begin of the list pointed to by iter2.
259 template<class Tmap_iter1, class Tlist_iter1, class Tmap_iter2, class Tkey, class Tvalue, class Tcompare >
260 bool operator==(const Tmap_iter2 &iter2, const MultiMapIterator<Tmap_iter1, Tlist_iter1, Tkey, Tvalue, Tcompare> &iter1)
262 return !iter1.ListValid() && iter1.GetMapIter() == iter2;
266 * Same as operator!=() with reversed order of arguments.
267 * @param iter2 Map iterator.
268 * @param iter1 MultiMap iterator.
269 * @return If iter1 doesn't point to the begin of the list pointed to by iter2.
271 template<class Tmap_iter1, class Tlist_iter1, class Tmap_iter2, class Tkey, class Tvalue, class Tcompare >
272 bool operator!=(const Tmap_iter2 &iter2, const MultiMapIterator<Tmap_iter1, Tlist_iter1, Tkey, Tvalue, Tcompare> &iter1)
274 return iter1.ListValid() || iter1.GetMapIter() != iter2;
279 * Hand-rolled multimap as map of lists. Behaves mostly like a list, but is sorted
280 * by Tkey so that you can easily look up ranges of equal keys. Those ranges are
281 * internally ordered in a deterministic way (contrary to STL multimap). All
282 * STL-compatible members are named in STL style, all others are named in OpenTTD
283 * style.
285 template<typename Tkey, typename Tvalue, typename Tcompare = std::less<Tkey> >
286 class MultiMap : public std::map<Tkey, std::list<Tvalue>, Tcompare > {
287 public:
288 typedef typename std::list<Tvalue> List;
289 typedef typename List::iterator ListIterator;
290 typedef typename List::const_iterator ConstListIterator;
292 typedef typename std::map<Tkey, List, Tcompare > Map;
293 typedef typename Map::iterator MapIterator;
294 typedef typename Map::const_iterator ConstMapIterator;
296 typedef MultiMapIterator<MapIterator, ListIterator, Tkey, Tvalue, Tcompare> iterator;
297 typedef MultiMapIterator<ConstMapIterator, ConstListIterator, Tkey, const Tvalue, Tcompare> const_iterator;
300 * Erase the value pointed to by an iterator. The iterator may be invalid afterwards.
301 * @param it Iterator pointing at some value.
302 * @return Iterator to the element after the deleted one (or invalid).
304 iterator erase(iterator it)
306 List &list = it.map_iter->second;
307 assert(!list.empty());
308 if (it.list_valid) {
309 it.list_iter = list.erase(it.list_iter);
310 /* This can't be the first list element as otherwise list_valid would have
311 * to be false. So the list cannot be empty here. */
312 if (it.list_iter == list.end()) {
313 ++it.map_iter;
314 it.list_valid = false;
316 } else {
317 list.erase(list.begin());
318 if (list.empty()) this->Map::erase(it.map_iter++);
320 return it;
324 * Insert a value at the end of the range with the specified key.
325 * @param key Key to be inserted at.
326 * @param val Value to be inserted.
328 void Insert(const Tkey &key, const Tvalue &val)
330 List &list = (*this)[key];
331 list.push_back(val);
332 assert(!list.empty());
336 * Count all items in this MultiMap. This involves iterating over the map.
337 * @return Number of items in the MultiMap.
339 size_t size() const
341 size_t ret = 0;
342 for (ConstMapIterator it = this->Map::begin(); it != this->Map::end(); ++it) {
343 ret += it->second.size();
345 return ret;
349 * Count the number of ranges with equal keys in this MultiMap.
350 * @return Number of ranges with equal keys.
352 size_t MapSize() const
354 return this->Map::size();
358 * Get a pair of iterators specifying a range of items with equal keys.
359 * @param key Key to look for.
360 * @return Range of items with given key.
362 std::pair<iterator, iterator> equal_range(const Tkey &key)
364 MapIterator begin(this->lower_bound(key));
365 if (begin != this->Map::end() && begin->first == key) {
366 MapIterator end = begin;
367 return std::make_pair(begin, ++end);
369 return std::make_pair(begin, begin);
373 * Get a pair of constant iterators specifying a range of items with equal keys.
374 * @param key Key to look for.
375 * @return Constant range of items with given key.
377 std::pair<const_iterator, const_iterator> equal_range(const Tkey &key) const
379 ConstMapIterator begin(this->lower_bound(key));
380 if (begin != this->Map::end() && begin->first == key) {
381 ConstMapIterator end = begin;
382 return std::make_pair(begin, ++end);
384 return std::make_pair(begin, begin);
388 #endif /* MULTIMAP_HPP */