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/>.
8 /** @file multimap.hpp Multimap with deterministic ordering of items with equal keys. */
13 template<typename Tkey
, typename Tvalue
, typename Tcompare
>
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
{
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.
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.
46 * Simple, dangerous constructor to allow later assignment with operator=.
48 MultiMapIterator() : list_valid(false) {}
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) {}
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
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());
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
)
81 this->list_valid
= false;
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*();
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.
124 assert(!this->map_iter
->second
.empty());
125 if (this->list_valid
) {
126 if (++this->list_iter
== this->map_iter
->second
.end()) {
128 this->list_valid
= false;
131 this->list_iter
= ++(this->map_iter
->second
.begin());
132 if (this->list_iter
== this->map_iter
->second
.end()) {
135 this->list_valid
= true;
142 * Postfix increment operator. Same as prefix increment, but return the
144 * @param dummy param to mark postfix.
145 * @return This iterator before incrementing.
155 * Prefix decrement operator. Decrement the iterator and set it to the
156 * previous item in the MultiMap.
157 * @return This iterator after decrementing.
161 assert(!this->map_iter
->second
.empty());
162 if (!this->list_valid
) {
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());
173 * Postfix decrement operator. Same as prefix decrement, but return the
175 * @param dummy param to mark postfix.
176 * @return This iterator before decrementing.
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
280 template<typename Tkey
, typename Tvalue
, typename Tcompare
= std::less
<Tkey
> >
281 class MultiMap
: public std::map
<Tkey
, std::list
<Tvalue
>, Tcompare
> {
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());
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()) {
309 it
.list_valid
= false;
312 list
.erase(list
.begin());
313 if (list
.empty()) this->Map::erase(it
.map_iter
++);
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
];
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.
337 for (ConstMapIterator it
= this->Map::begin(); it
!= this->Map::end(); ++it
) {
338 ret
+= it
->second
.size();
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 */