The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
map.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2009 by Rusty Russell <[email protected]>
3  Copyright (C) 2010 - 2016 by Guillaume Melquiond <[email protected]>
4  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /** @file */
17 
18 #ifndef UNIT_MAP_H_INCLUDED
19 #define UNIT_MAP_H_INCLUDED
20 
22 #include "map/location.hpp"
23 #include "units/ptr.hpp"
24 
25 #include <cassert>
26 #include <list>
27 #include <map>
28 #include <boost/unordered_map.hpp>
29 
30 //#define DEBUG_UNIT_MAP
31 
32 /**
33  * Container associating units to locations.
34  * An indirection location -> underlying_id -> unit ensures that iterators
35  * stay valid even if WML modifies or moves units on the fly. They even stay
36  * valid if a unit is erased from the map and another unit with the same
37  * underlying id is inserted in the map. In other words it is a doubly indexed ordered map
38  * with persistent iterators (that never invalidate)
39 
40  @note The unit_map is implemented as 2 maps, one unordered map that stores iterators from the ordered map of reference counted pointers to units.
41  The unordered map provides O(1) find times. The ordered map ensures ordering of units by underlying_id.
42  The reference counting is what guarantees the persistent iterators.
43  Storing an iterator prevents only that dead unit's id-map entry from being recovered.
44 
45 @note Prefered usages for tight loops follows.
46 Use the std::pair<iterator, bool> format which checks the preconditions and returns
47 false in the bool to indicate failure with no change to the unit_map. true indicates success and the new iterator is in first.
48 Storing the result iterator prevents the old iterator from entering the fallback recovery code.
49 This is faster than the old methodology of find to check if empty, insert and then find to check for success.
50 It is the same method as std::map uses, the C++ way.
51 
52 unit_iterator i; //results are stored here
53 
54 Add
55 std::pair<unit_iterator, bool> try_add(units->add(loc, unit));
56 if(try_add.second){i = try_add.first;}
57 
58 Move
59 std::pair<unit_iterator, bool> try_add(units->move(src, dst));
60 if(try_add.second){i = try_add.first;}
61 
62 Insert
63 std::pair<unit_iterator, bool> try_add(units->insert(unitp));
64 if(try_add.second){i = try_add.first;}
65 
66 Replace (preferred over erase and then add)
67 std::pair<unit_iterator, bool> try_add(units->move(loc, unit));
68 if(try_add.second){i = try_add.first;}
69 
70 
71 
72 
73  @note The previous implementation was 2 binary tree based maps one the location map pointing to the other.
74  Lookups were O(2*log(N)) and O(log(N)). Order was implicit in the id map choosen as the base.
75  Persistence was provided by reference counting all iterators collectively and only recovering space when
76  there were no iterators outstanding. Even 1 iterator being stored caused a leak, because
77  all space for dead units is not recovered.
78 
79  * @note Units are owned by the container.
80  * @note The indirection does not involve map lookups whenever an iterator
81  * is dereferenced, it just causes a pointer indirection. The downside
82  * is that incrementing iterator is not O(1).
83  * @note The code does not involve any magic, so units moved while being
84  * iterated upon may be skipped or visited twice.
85  * @note Iterators prevent ghost units from being collected. So they should
86  * never be stored into data structures, as it will cause slowdowns!
87  * @note By popular demand iterators are effectively permanent. They are handles and not iterators.
88  * Any access might cause a full lookup. Keeping iterators around holds onto memory.
89  */
90 class unit_map {
91  /// The pointer to the unit and a reference counter to record the number of extant iterators
92  /// pointing to this unit.
93  struct unit_pod {
94 
96  : unit()
97  , ref_count()
98  {
99  }
100 
103  };
104 
105  ///Map of underlying_id to unit and a reference counter. Dead units have a unit pointer equal to nullptr.
106  ///The map entry is removed iff the reference counter equals zero and there are no more
107  ///iterators pointing to this unit.
108  typedef std::map<size_t, unit_pod> t_umap;
109  ///Map of location to umap iterator.
110  typedef boost::unordered_map<map_location, t_umap::iterator> t_lmap;
111 
112 public:
113 
114 // ~~~ Begin iterator code ~~~
115 
119  typedef unit value_type;
120  };
121 
123  typedef unit_map const container_type;
125  typedef const unit value_type;
126  };
127 
128  template<typename iter_types>
130  {
131  typedef std::forward_iterator_tag iterator_category;
132  typedef int difference_type;
133  typedef typename iter_types::value_type value_type;
135  typedef value_type& reference;
136  typedef typename iter_types::container_type container_type;
137  typedef typename iter_types::iterator_type iterator_type;
138 
140 
141  iterator_base(): i_(), tank_(nullptr) { }
142 
143  iterator_base(iterator_type i, container_type *m) : i_(i), tank_(m) {
144  inc();
145  valid_exit();
146  }
147 
148  iterator_base(const iterator_base &that) : i_(that.i_), tank_(that.tank_) {
149  inc();
150  valid_exit();
151  }
152 
154  if(*this != that){
155  dec();
156  tank_ = that.tank_;
157  i_ = that.i_;
158  inc();
159  valid_exit();
160  }
161  return *this;
162  }
163 
166  }
167 
168  private:
169  ///Construct an iterator from the location map
170  iterator_base(t_lmap::iterator ui, container_type *m) : i_(ui->second), tank_(m) {
171  inc();
172  valid_exit();
173  }
174 
175  public:
176  pointer operator->() const {
177  assert(valid());
178  tank_->self_check();
179  return i_->second.unit; }
180  pointer get_shared_ptr() const { // This is exactly the same as operator-> but it's slightly more readable, and can replace &*iter syntax easily.
181  assert(valid());
182  tank_->self_check();
183  return i_->second.unit; }
184  reference operator*() const {
185  tank_->self_check();
186  assert(valid());
187  return *i_->second.unit; }
188 
190  assert( valid_entry() );
191  tank_->self_check();
192  iterator_type new_i(i_);
193  do{
194  ++new_i;
195  }while ((new_i != the_map().end()) && (!new_i->second.unit)) ;
196  dec();
197  i_ = new_i;
198  inc();
199  valid_exit();
200  return *this;
201  }
202 
204  iterator_base temp(*this);
205  operator++();
206  return temp;
207  }
208 
210  assert( tank_ && i_ != the_map().begin() );
211  tank_->self_check();
212  iterator_type begin(the_map().begin());
213  dec();
214  do {
215  --i_ ;
216  }while(i_ != begin && (!i_->second.unit));
217  inc();
218 
219  valid_exit();
220  return *this;
221  }
222 
224  iterator_base temp(*this);
225  operator--();
226  return temp;
227  }
228 
229  bool valid() const {
230  return (valid_for_dereference() && i_->second.unit);
231  }
232 
233  explicit operator bool() const
234  { return valid(); }
235 
236  bool operator==(const iterator_base &rhs) const { return (tank_ == rhs.tank_) && ( i_ == rhs.i_ ); }
237  bool operator!=(const iterator_base &rhs) const { return !operator==(rhs); }
238 
239  template<typename Y> friend struct iterator_base;
240 
241  private:
242  bool valid_for_dereference() const { return (tank_ != nullptr) && (i_ != the_map().end()); }
243  bool valid_entry() const { return ((tank_ != nullptr) && (i_ != the_map().end())) ; }
244  void valid_exit() const {
245  if((tank_ != nullptr) && i_ != the_map().end()){
246  assert(i_->second.ref_count > 0);
247  }
248  }
249  bool valid_ref_count() const { return (tank_ != nullptr) && (i_ != the_map().end()) ; }
250 
251  ///Increment the reference counter
252  void inc() { if(valid_ref_count()) { ++(i_->second.ref_count); } }
253 
254  ///Decrement the reference counter
255  ///Delete the umap entry if the unit is gone and the reference counter is zero
256  ///@note this deletion will advance i_ to the next umap entry.
257  void dec() {
258  if( valid_ref_count() ){
259  assert(i_->second.ref_count != 0);
260  if( (--(i_->second.ref_count) == 0) && (!i_->second.unit) ){
261  iterator_type old = i_++;
262  tank_->umap_.erase(old);
263  }
264  }
265  }
266 
267  unit_map::t_umap & the_map() const { return tank_->umap_; }
268 
269  friend class unit_map;
270 
271  iterator_type i_; ///local iterator
272  container_type* tank_; ///the unit_map for i_
273  };
274 
275 
276 // ~~~ End iterator code ~~~
277 
278 
279  unit_map();
280  unit_map(const unit_map &that);
281  unit_map& operator=(const unit_map &that);
282 
283  ~unit_map();
284  void swap(unit_map& o);
285 
288 
289  // Provided as a convenience, since unit_map used to be an std::map.
290  typedef unit_iterator iterator;
291  typedef const_unit_iterator const_iterator;
292 
293  unit_iterator find(size_t id);
294  unit_iterator find(const map_location &loc);
295 
296  const_unit_iterator find(const map_location &loc) const { return const_cast<unit_map *>(this)->find(loc); }
297  const_unit_iterator find(size_t id) const { return const_cast<unit_map *>(this)->find(id); }
298 
299  unit_iterator find_leader(int side);
300  const_unit_iterator find_leader(int side) const { return const_cast<unit_map *>(this)->find_leader(side); }
301  unit_iterator find_first_leader(int side);
302 
303  std::vector<unit_iterator> find_leaders(int side);
304  std::vector<const_unit_iterator> find_leaders(int side) const;
305 
306  size_t count(const map_location& loc) const { return lmap_.count(loc); }
307 
308  unit_iterator begin() { return make_unit_iterator( begin_core() ); }
309  const_unit_iterator begin() const { return make_const_unit_iterator( begin_core() ); }
310 
311  unit_iterator end() { return make_unit_iterator(umap_.end()); }
312  const_unit_iterator end() const { return make_const_unit_iterator(umap_.end()); }
313 
314  size_t size() const { return lmap_.size(); }
315  size_t num_iters() const ;
316 
317  void clear(bool force = false);
318 
319  /**
320  * Adds a copy of unit @a u at location @a l of the map.
321  @return std::pair<unit_iterator, bool> a bool indicating success and
322  an iterator pointing to the new unit, or the unit already occupying location.
323  @note It is 3 times as fast to attempt to insert a unit at @a l and check for
324  success than it is to verify that the location is empty, insert the unit check the
325  location for the unit.
326  */
327  std::pair<unit_iterator, bool> add(const map_location &l, const unit &u);
328 
329  /**
330  * Adds the unit to the map.
331  @return std::pair<unit_iterator, bool> a bool indicating success and
332  an iterator pointing to the new unit, or the unit already occupying location.
333  @note It is 3 times as fast to attempt to insert a unit at @a l and check for
334  success than it is to verify that the location is empty, insert the unit check the
335  location for the unit.
336  * @note If the unit::underlying_id is already in use, a new one
337  * will be generated.
338  * @note The map takes ownership of the pointed object, only if it succeeds.
339  */
340  std::pair<unit_iterator, bool> insert(unit_ptr p);
341 
342  /**
343  * Moves a unit from location @a src to location @a dst.
344  @return std::pair<unit_iterator, bool> a bool indicating success and
345  an iterator pointing to the new unit, or the unit already occupying location.
346  @note It is 3 times as fast to attempt to insert a unit at @a l and check for
347  success than it is to verify that the location is empty, insert the unit check the
348  location for the unit.
349  */
350  std::pair<unit_iterator, bool> move(const map_location &src, const map_location &dst);
351 
352  /**
353  * Works like unit_map::add; but @a l is emptied first, if needed.
354  @return std::pair<unit_iterator, bool> a bool indicating success and
355  an iterator pointing to the new unit, or the unit already occupying location.
356  */
357  std::pair<unit_iterator, bool> replace(const map_location &l, const unit &u);
358 
359  /**
360  * Erases the unit at location @a l, if any.
361  * @returns the number of erased units (0 or 1).
362  */
363  size_t erase(const map_location &l);
364 
365  /**
366  * Erases a unit given by a pointer or an iterator.
367  * @pre The unit is on the map.
368  */
369  template <typename T>
370  size_t erase(const T &iter);
371 
372  /**
373  * Extracts a unit from the map.
374  * The unit is no longer owned by the map.
375  * It can be reinserted later, if needed.
376  */
377  unit_ptr extract(const map_location &loc);
378 
379  ///Checks invariants. For debugging purposes only. Doesn't do anything in non-debug mode.
380  bool self_check() const
381 #ifndef DEBUG_UNIT_MAP
382  { return true; }
383 #else
384  ;
385 #endif
386 
387  /**
388  * Is the unit in the map?
389  *
390  * @pre @p u != @c nullptr
391  *
392  * @param u Pointer to the unit to find.
393  *
394  * @returns True if found, false otherwise.
395  */
396  bool has_unit(const unit * const u) const ;
397 
398 private:
399  t_umap::iterator begin_core() const ;
400 
401  bool is_valid(const t_umap::const_iterator &i) const {
402  return is_found(i) && (i->second.unit != nullptr);
403  }
404  bool is_valid(const t_lmap::const_iterator &i) const {
405  return is_found(i) && (i->second->second.unit != nullptr);
406  }
407 
408  bool is_found(const t_umap::const_iterator &i) const { return i != umap_.end(); }
409  bool is_found(const t_lmap::const_iterator &i) const { return i != lmap_.end(); }
410 
411  template <typename X>
413  if (!is_found( i )) { return unit_iterator(umap_.end(), this); }
414  return unit_iterator(i , this);
415  }
416  template <typename X>
418  if (!is_found( i )) { return const_unit_iterator(umap_.end(), this); }
419  return const_unit_iterator(i , this);
420  }
421 
422  /**
423  * underlying_id -> unit_pod. This requires that underlying_id be
424  * unique (which is enforced in unit_map::insert).
425  */
426  mutable t_umap umap_;
427 
428  /**
429  * location -> umap::iterator.
430  */
431  t_lmap lmap_;
432 
433 };
434 
435 template <typename T>
436 size_t unit_map::erase(const T& iter) {
437  assert(iter.valid());
438 
439  return erase(iter->get_location());
440 }
441 
442 
443 
444 #endif // UNIT_MAP_H_INCLUDED
iter_types::container_type container_type
Definition: map.hpp:136
unit_map::t_umap::iterator iterator_type
Definition: map.hpp:124
void dec()
Decrement the reference counter Delete the umap entry if the unit is gone and the reference counter i...
Definition: map.hpp:257
std::vector< unit_iterator > find_leaders(int side)
Definition: map.cpp:319
unit_iterator end()
Definition: map.hpp:311
size_t size() const
Definition: map.hpp:314
iterator_base< standard_iter_types > unit_iterator
Definition: map.hpp:286
Definition: unit.hpp:95
unit_map & operator=(const unit_map &that)
Definition: map.cpp:46
boost::intrusive_ptr< value_type > pointer
Definition: map.hpp:134
size_t count(const map_location &loc) const
Definition: map.hpp:306
unit_iterator find_leader(int side)
Definition: map.cpp:297
boost::unordered_map< map_location, t_umap::iterator > t_lmap
Map of location to umap iterator.
Definition: map.hpp:110
t_lmap lmap_
location -> umap::iterator.
Definition: map.hpp:431
bool is_found(const t_lmap::const_iterator &i) const
Definition: map.hpp:409
bool operator==(const iterator_base &rhs) const
Definition: map.hpp:236
iter_types::iterator_type iterator_type
Definition: map.hpp:137
const_unit_iterator find_leader(int side) const
Definition: map.hpp:300
unit_iterator begin()
Definition: map.hpp:308
bool valid_ref_count() const
Definition: map.hpp:249
bool self_check() const
Checks invariants. For debugging purposes only. Doesn't do anything in non-debug mode.
Definition: map.hpp:380
n_ref_counter::t_ref_counter< signed int > ref_count
Definition: map.hpp:102
GLenum src
Definition: glew.h:2392
unit_map const container_type
Definition: map.hpp:123
iterator_base< const_iter_types > const_unit_iterator
Definition: map.hpp:287
unit_map::const_unit_iterator make_const_unit_iterator(X const &i) const
Definition: map.hpp:417
reference operator*() const
Definition: map.hpp:184
const_unit_iterator find(size_t id) const
Definition: map.hpp:297
const unit value_type
Definition: map.hpp:125
unit_map::t_umap::iterator iterator_type
Definition: map.hpp:118
GLdouble l
Definition: glew.h:6966
void valid_exit() const
Definition: map.hpp:244
t_umap umap_
underlying_id -> unit_pod.
Definition: map.hpp:426
const_unit_iterator find(const map_location &loc) const
Definition: map.hpp:296
iterator_base(const iterator_base &that)
Definition: map.hpp:148
const_unit_iterator const_iterator
Definition: map.hpp:291
pointer operator->() const
Definition: map.hpp:176
bool is_found(const t_umap::const_iterator &i) const
Definition: map.hpp:408
pointer get_shared_ptr() const
Definition: map.hpp:180
std::pair< unit_iterator, bool > insert(unit_ptr p)
Adds the unit to the map.
Definition: map.cpp:126
iterator_base & operator=(const iterator_base &that)
Definition: map.hpp:153
iterator_base operator--(int)
Definition: map.hpp:223
GLenum GLenum dst
Definition: glew.h:2392
void clear(bool force=false)
Definition: map.cpp:235
bool is_valid(const t_umap::const_iterator &i) const
Definition: map.hpp:401
const_unit_iterator end() const
Definition: map.hpp:312
iterator_base(iterator_type i, container_type *m)
Definition: map.hpp:143
GLfloat GLfloat p
Definition: glew.h:12766
std::pair< unit_iterator, bool > replace(const map_location &l, const unit &u)
Works like unit_map::add; but l is emptied first, if needed.
Definition: map.cpp:207
iterator_base(t_lmap::iterator ui, container_type *m)
Construct an iterator from the location map.
Definition: map.hpp:170
std::pair< unit_iterator, bool > add(const map_location &l, const unit &u)
Adds a copy of unit u at location l of the map.
Definition: map.cpp:70
Encapsulates the map of the game.
Definition: location.hpp:38
unit_iterator iterator
Definition: map.hpp:290
void swap(unit_map &o)
Definition: map.cpp:52
unit_ptr unit
Definition: map.hpp:101
t_umap::iterator begin_core() const
Definition: map.cpp:63
unit_iterator find_first_leader(int side)
Definition: map.cpp:306
unit_map::t_umap & the_map() const
Definition: map.hpp:267
iterator_base & operator--()
Definition: map.hpp:209
void inc()
Increment the reference counter.
Definition: map.hpp:252
std::map< size_t, unit_pod > t_umap
Map of underlying_id to unit and a reference counter.
Definition: map.hpp:108
size_t i
Definition: function.cpp:1057
const_unit_iterator begin() const
Definition: map.hpp:309
iterator_base & operator++()
Definition: map.hpp:189
bool has_unit(const unit *const u) const
Is the unit in the map?
Definition: map.cpp:379
bool is_valid(const t_lmap::const_iterator &i) const
Definition: map.hpp:404
iterator_type i_
Definition: map.hpp:271
std::pair< unit_iterator, bool > move(const map_location &src, const map_location &dst)
Moves a unit from location src to location dst.
Definition: map.cpp:79
unit_map::unit_iterator make_unit_iterator(X const &i)
Definition: map.hpp:412
size_t erase(const map_location &l)
Erases the unit at location l, if any.
Definition: map.cpp:277
bool operator!=(const iterator_base &rhs) const
Definition: map.hpp:237
The pointer to the unit and a reference counter to record the number of extant iterators pointing to ...
Definition: map.hpp:93
bool valid_entry() const
Definition: map.hpp:243
const GLdouble * m
Definition: glew.h:6968
std::forward_iterator_tag iterator_category
Definition: map.hpp:131
container_type * tank_
local iterator
Definition: map.hpp:272
unit_ptr extract(const map_location &loc)
Extracts a unit from the map.
Definition: map.cpp:249
unit_map()
Definition: map.cpp:31
Container associating units to locations.
Definition: map.hpp:90
~unit_map()
Definition: map.cpp:59
unit_iterator find(size_t id)
Definition: map.cpp:285
bool valid() const
Definition: map.hpp:229
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
iter_types::value_type value_type
Definition: map.hpp:133
iterator_base operator++(int)
Definition: map.hpp:203
bool valid_for_dereference() const
Definition: map.hpp:242
size_t num_iters() const
Definition: map.cpp:218
value_type & reference
Definition: map.hpp:135