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/>.
10 /** @file multimap.hpp Multimap with deterministic ordering of items with equal keys. */
18 template<typename Tkey
, typename Tvalue
, typename Tcompare
>
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
{
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.
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.
51 * Simple, dangerous constructor to allow later assignment with operator=.
53 MultiMapIterator() : list_valid(false) {}
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) {}
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
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());
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
)
86 this->list_valid
= false;
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.
129 assert(!this->map_iter
->second
.empty());
130 if (this->list_valid
) {
131 if (++this->list_iter
== this->map_iter
->second
.end()) {
133 this->list_valid
= false;
136 this->list_iter
= ++(this->map_iter
->second
.begin());
137 if (this->list_iter
== this->map_iter
->second
.end()) {
140 this->list_valid
= true;
147 * Postfix increment operator. Same as prefix increment, but return the
149 * @param dummy param to mark postfix.
150 * @return This iterator before incrementing.
160 * Prefix decrement operator. Decrement the iterator and set it to the
161 * previous item in the MultiMap.
162 * @return This iterator after decrementing.
166 assert(!this->map_iter
->second
.empty());
167 if (!this->list_valid
) {
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());
178 * Postfix decrement operator. Same as prefix decrement, but return the
180 * @param dummy param to mark postfix.
181 * @return This iterator before decrementing.
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
285 template<typename Tkey
, typename Tvalue
, typename Tcompare
= std::less
<Tkey
> >
286 class MultiMap
: public std::map
<Tkey
, std::list
<Tvalue
>, Tcompare
> {
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());
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()) {
314 it
.list_valid
= false;
317 list
.erase(list
.begin());
318 if (list
.empty()) this->Map::erase(it
.map_iter
++);
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
];
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.
342 for (ConstMapIterator it
= this->Map::begin(); it
!= this->Map::end(); ++it
) {
343 ret
+= it
->second
.size();
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 */