unit_map.hpp

Go to the documentation of this file.
00001 /* $Id: unit_map.hpp 26760 2008-05-21 19:26:59Z mordante $ */
00002 /*
00003    Copyright (C) 2006 - 2008 by Rusty Russell <rusty@rustcorp.com.au>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License version 2
00008    or at your option any later version.
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY.
00011 
00012    See the COPYING file for more details.
00013 */
00014 
00015 /** @file unit_map.hpp */
00016 
00017 #ifndef UNIT_MAP_H_INCLUDED
00018 #define UNIT_MAP_H_INCLUDED
00019 
00020 class unit;
00021 #include <cstring>
00022 #include "map.hpp"
00023 
00024 // We used to just open-code a std::map<location,unit>,
00025 // but as unit gained weight leading up to 1.1.3,
00026 // manipulating the map caused significant performance issues
00027 // for the AI, which had to actually move units for accurate
00028 // simulation with the new, more powerful filtering.
00029 // This class eases the transition, by providing a wrapper
00030 // which acts like a map of units, not unit pointers,
00031 // except implemented with pointers and hence providing
00032 // a cheap move function.
00033 //
00034 // Further extended to prevent invalidating iterators when
00035 // changes are made to the map, and to add more powerful iterators/
00036 // accessors.
00037 
00038 class unit_map
00039 {
00040 private:
00041     
00042     /**
00043      * Used so unit_map can keep a count of iterators and clean invalid pointers
00044      * when no iterators exist. Every iterator and accessor has a counter
00045      * instance.
00046      */
00047     struct iterator_counter {
00048         iterator_counter() : map_(NULL) {}
00049         iterator_counter(const unit_map* map) : map_(map)
00050             { map_->add_iter(); }
00051         
00052         iterator_counter(const iterator_counter& i) : map_(i.map_) {
00053             if (map_) map_->add_iter();
00054         }
00055         
00056         iterator_counter &operator =(const iterator_counter &that) {
00057             if (this == &that)
00058                 return *this;
00059     
00060             if (map_) map_->remove_iter();
00061     
00062             map_=that.map_;
00063             if (map_) map_->add_iter();
00064             
00065             return *this;
00066         }
00067 
00068         ~iterator_counter() {if (map_) map_->remove_iter(); }
00069     private:    
00070         const unit_map* map_;       
00071     };
00072 
00073     
00074 public:
00075     unit_map() : num_iters_(0), num_invalid_(0) { };
00076     unit_map(const unit_map &that);
00077     unit_map &operator =(const unit_map &that);
00078     /** A unit map with a copy of a single unit in it. */
00079     explicit unit_map(const gamemap::location &loc, const unit &u);
00080     ~unit_map();
00081     
00082     /**
00083      * Keyed with unit's underlying_id. bool flag is whether the following pair
00084      * pointer is valid. pointer to pair used to imitate a map<location, unit>
00085      */
00086     typedef std::map<std::string,std::pair<bool, std::pair<gamemap::location,unit>*> > umap;
00087     
00088     /** Maps locations to the underlying_id() of the unit at that location. */
00089     typedef std::map<gamemap::location, std::string> lmap;
00090         
00091     struct const_unit_iterator; 
00092     struct unit_xy_iterator;
00093     struct const_unit_xy_iterator;
00094     struct xy_accessor;
00095     struct const_xy_accessor;
00096 
00097     /**
00098      * For iterating over every unit. Iterator is valid as long as there is
00099      * there is a unit w/ matching underlying_id in the map.
00100      */
00101     struct unit_iterator
00102     {
00103         unit_iterator() { }
00104         
00105         unit_iterator(const unit_iterator &i) : counter(i.map_), i_(i.i_), map_(i.map_) { }
00106         unit_iterator(umap::iterator i, unit_map* map) : counter(map), i_(i), map_(map) { }
00107                     
00108         std::pair<gamemap::location,unit> *operator->() const;
00109         std::pair<gamemap::location,unit>& operator*() const;
00110 
00111         unit_iterator operator++();
00112         unit_iterator operator++(int);
00113         
00114 
00115         bool operator==(const unit_iterator &that) const
00116             { return that.i_ == this->i_; }
00117 
00118         bool operator!=(const unit_iterator &that) const
00119             { return that.i_ != this->i_; }
00120             
00121         bool valid() const
00122             { return i_ != map_->map_.end() && i_->second.first; }
00123             
00124         friend struct const_unit_iterator;
00125         friend struct unit_xy_iterator;
00126         friend struct const_unit_xy_iterator;
00127         friend struct xy_accessor;
00128         friend struct const_xy_accessor;
00129         
00130     private:
00131         iterator_counter counter;
00132         
00133         umap::iterator i_;
00134         unit_map* map_;
00135     };
00136     
00137     struct const_unit_iterator
00138     {
00139         const_unit_iterator(const unit_iterator &i) : counter(i.map_), i_(i.i_), map_(i.map_) { }
00140         
00141         const_unit_iterator() { }
00142                 
00143         const_unit_iterator(const const_unit_iterator &i) : counter(i.map_), i_(i.i_), map_(i.map_) { }
00144         const_unit_iterator(umap::const_iterator i, const unit_map* map): counter(map), i_(i), map_(map) { }
00145         
00146         const std::pair<gamemap::location,unit>* operator->() const;
00147         const std::pair<gamemap::location,unit>& operator*() const;
00148 
00149         const_unit_iterator operator++();
00150 
00151         const_unit_iterator operator++(int);
00152 
00153         const_unit_iterator operator--();
00154 
00155         bool operator==(const const_unit_iterator &that) const
00156             { return that.i_ == this->i_; }
00157 
00158         bool operator!=(const const_unit_iterator &that) const
00159             { return that.i_ != this->i_; }
00160             
00161         bool valid() const
00162             { return i_ != map_->map_.end() && i_->second.first; }
00163             
00164         friend struct const_unit_xy_iterator;
00165         friend struct const_xy_accessor;
00166         
00167     private:    
00168         iterator_counter counter;
00169                     
00170         umap::const_iterator i_;    
00171         const unit_map* map_;
00172     };
00173     
00174     typedef unit_iterator iterator;
00175     typedef const_unit_iterator const_iterator;
00176     
00177     /**
00178      * Similar to unit_iterator, except that becomes invalid if unit is moved
00179      * while the iterator points at it.
00180      */
00181     struct unit_xy_iterator
00182     {
00183         unit_xy_iterator(const unit_iterator &i);
00184         
00185         unit_xy_iterator() { }
00186                 
00187         unit_xy_iterator(const unit_xy_iterator &i) : counter(i.map_), i_(i.i_), map_(i.map_)
00188             { if (i.valid()) loc_ = i.loc_; }
00189             
00190         unit_xy_iterator(umap::iterator i, unit_map* map, gamemap::location loc): counter(map), i_(i), map_(map), loc_(loc) { }
00191         
00192         std::pair<gamemap::location,unit>* operator->() const;
00193         std::pair<gamemap::location,unit>& operator*() const;
00194 
00195         unit_xy_iterator operator++();
00196 
00197         unit_xy_iterator operator++(int);
00198 
00199         bool operator==(const unit_xy_iterator &that) const
00200             { return that.i_ == this->i_; }
00201 
00202         bool operator!=(const unit_xy_iterator &that) const
00203             { return that.i_ != this->i_; }
00204             
00205         bool valid() const;
00206             
00207         friend struct const_unit_xy_iterator;
00208         friend struct xy_accessor;
00209         friend struct const_xy_accessor;
00210         
00211     private:    
00212         iterator_counter counter;   
00213         
00214         umap::iterator i_;  
00215         unit_map* map_;
00216         
00217         gamemap::location loc_; 
00218     };
00219     
00220     struct const_unit_xy_iterator
00221     {
00222         const_unit_xy_iterator(const unit_iterator &i);
00223         const_unit_xy_iterator(const const_unit_iterator &i);
00224         
00225         const_unit_xy_iterator() { }
00226                             
00227         const_unit_xy_iterator(umap::const_iterator i, const unit_map* map, gamemap::location loc): counter(map), i_(i), map_(map), loc_(loc)  { }
00228                     
00229         const_unit_xy_iterator(const unit_xy_iterator &i) : counter(i.map_), i_(i.i_), map_(i.map_) 
00230             { if (i.valid()) loc_ = i.loc_; }           
00231         const_unit_xy_iterator(const const_unit_xy_iterator &i) : counter(i.map_), i_(i.i_), map_(i.map_)
00232             { if (i.valid()) loc_ = i.loc_; }
00233 
00234         const std::pair<gamemap::location,unit>* operator->() const;
00235         const std::pair<gamemap::location,unit>& operator*() const;
00236 
00237         const_unit_xy_iterator operator++();
00238 
00239         const_unit_xy_iterator operator++(int);
00240 
00241         bool operator==(const const_unit_xy_iterator &that) const
00242             { return that.i_ == this->i_; }
00243 
00244         bool operator!=(const const_unit_xy_iterator &that) const
00245             { return that.i_ != this->i_; }
00246             
00247         bool valid() const;
00248         
00249         friend struct const_xy_accessor;
00250         
00251     private:        
00252         iterator_counter counter;
00253         
00254         umap::const_iterator i_;    
00255         const unit_map* map_;
00256         
00257         gamemap::location loc_; 
00258     };
00259     
00260     /**
00261      * Used to access the unit at a given position. Is valid as long as any unit
00262      * is in that position. Can switch from invalid to valid.
00263      */
00264     struct xy_accessor
00265     {
00266         xy_accessor(const unit_iterator &i);
00267         xy_accessor(const unit_xy_iterator &i);     
00268         xy_accessor() { }
00269         
00270         std::pair<gamemap::location,unit>* operator->();
00271         std::pair<gamemap::location,unit>& operator*();
00272         
00273         bool valid();
00274         
00275     private:
00276         iterator_counter counter;
00277         
00278         umap::iterator i_;
00279         unit_map* map_;
00280                 
00281         gamemap::location loc_;     
00282     };
00283     
00284     struct const_xy_accessor
00285     {
00286         const_xy_accessor(const unit_iterator &i);
00287         const_xy_accessor(const unit_xy_iterator &i);
00288         const_xy_accessor(const const_unit_iterator &i);
00289         const_xy_accessor(const const_unit_xy_iterator &i);
00290                 
00291         const_xy_accessor() { }
00292         
00293         const std::pair<gamemap::location,unit>* operator->();
00294         const std::pair<gamemap::location,unit>& operator*();
00295         
00296         bool valid();
00297         
00298     private:
00299         iterator_counter counter;
00300         
00301         umap::const_iterator i_;
00302         const unit_map* map_;
00303                 
00304         gamemap::location loc_;     
00305     };
00306     
00307     /**
00308      * Return object can be implicitly converted to any of the other iterators
00309      * or accessors
00310      */
00311     unit_iterator find(const gamemap::location &loc) ;
00312     unit_iterator find(const std::string &id);
00313     
00314     /**
00315      * Return object can be implicity converted to any of the other const
00316      * iterators or accessors
00317      */
00318     const_unit_iterator find(const gamemap::location &loc) const;
00319     const_unit_iterator find(const std::string &id) const;
00320     
00321     size_t count(const gamemap::location &loc) const {
00322         return lmap_.count(loc);
00323     }
00324 
00325     /**
00326      * Return object can be implicitly converted to any of the other iterators
00327      * or accessors
00328      */
00329     unit_iterator begin();
00330 
00331     /**
00332      * Return object can be implicity converted to any of the other const
00333      * iterators or accessors
00334      */
00335     const_unit_iterator begin() const {
00336         umap::const_iterator i = map_.begin();
00337         while (i != map_.end() && !i->second.first) { 
00338             ++i; 
00339         }
00340         return const_unit_iterator(i, this);
00341     }
00342 
00343     /**
00344      * Return object can be implicitly converted to any of the other iterators
00345      * or accessors
00346      */
00347     unit_iterator end() {
00348         return iterator(map_.end(), this);
00349     }
00350 
00351     /**
00352      * Return object can be implicity converted to any of the other const
00353      * iterators or accessors
00354      */
00355     const_unit_iterator end() const {
00356         return const_iterator(map_.end(), this);
00357     }   
00358     
00359     size_t size() const {
00360         return lmap_.size();
00361     }
00362 
00363     void clear();
00364 
00365     /** Extract (like erase, but don't delete). */
00366     std::pair<gamemap::location,unit> *extract(const gamemap::location &loc);
00367 
00368     /**
00369      * Map owns pointer after this.  Loc must be currently empty. unit's
00370      * underlying_id should not be present in the map already
00371      */
00372     void add(std::pair<gamemap::location,unit> *p);
00373 
00374     /** Like add, but loc must be occupied (implicitly erased). */
00375     void replace(std::pair<gamemap::location,unit> *p);
00376 
00377     void erase(xy_accessor pos);
00378     size_t erase(const gamemap::location &loc);
00379 
00380     void swap(unit_map& o) {
00381         map_.swap(o.map_);
00382         lmap_.swap(o.lmap_);
00383     }
00384 
00385         
00386 private:
00387     /** Removes invalid entries in map_. Called automatically when safe and needed. */
00388     void clean_invalid();
00389     
00390     void invalidate(umap::iterator i) 
00391         {if(i == map_.end()) return; i->second.first = false; ++num_invalid_;} 
00392     void validate(umap::iterator i) 
00393         {if(i == map_.end()) return; i->second.first = true; --num_invalid_;}
00394     
00395     void delete_all();
00396     
00397     void add_iter() const { ++num_iters_; }
00398     void remove_iter() const { --num_iters_; }
00399 
00400     
00401     /**
00402      * Key: unit's underlying_id. bool indicates validity of pointer. pointer to
00403      * pair used to imitate a map<location, unit>
00404      */
00405     std::map<std::string,std::pair<bool, std::pair<gamemap::location,unit>*> > map_;
00406     
00407     /** location -> unit.underlying_id(). Unit_map is usually used as though it
00408      * is a map<location, unit> and so we need this map for efficient
00409      * access/modification.
00410      */
00411     std::map<gamemap::location, std::string> lmap_;
00412     
00413     mutable size_t num_iters_;
00414     size_t num_invalid_;
00415 };
00416 
00417 #endif  // UNIT_MAP_H_INCLUDED

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs