greatly improve unit_map interface documentation

templatize unit_map iterators
This commit is contained in:
Chris Hopman 2009-02-17 08:34:58 +00:00
parent 4b2edc5906
commit 407a954eb8
2 changed files with 348 additions and 708 deletions

View file

@ -18,13 +18,13 @@
#include "unit_id.hpp"
#include "log.hpp"
#define ERR_NG LOG_STREAM(err, engine)
#define WRN_NG LOG_STREAM(warn, engine)
#define LOG_NG LOG_STREAM(info, engine)
#define DBG_NG LOG_STREAM(debug, engine)
typedef std::pair<std::string, std::pair<bool, std::pair<map_location, unit>*> > umap_pair;
unit& unit_map::node::get_unit() const { return ptr_->second; }
map_location& unit_map::node::get_location() const { return ptr_->first; }
unit_map::unit_map(const map_location &loc, const unit &u) :
map_(),
@ -35,352 +35,34 @@ unit_map::unit_map(const map_location &loc, const unit &u) :
add(new std::pair<map_location,unit>(loc, u));
}
unit_map::unit_map(const unit_map &that) :
unit_map::unit_map(const unit_map& that) :
/* Initialize to silence compiler warnings. */
map_(),
lmap_(),
num_iters_(0),
num_invalid_(0)
{
*this = that;
for (umap::const_iterator i = that.map_.begin(); i != that.map_.end(); i++) {
if (is_valid(i)) {
add(new std::pair<map_location,unit>(*i->second.ptr_));
}
}
}
unit_map &unit_map::operator=(const unit_map &that)
{
clear();
num_iters_ = 0;
num_invalid_ = 0;
for (umap::const_iterator i = that.map_.begin(); i != that.map_.end(); i++) {
if (i->second.first) {
add(new std::pair<map_location,unit>(i->second.second->first, i->second.second->second));
}
}
unit_map temp(that);
swap(temp);
return *this;
}
unit_map::~unit_map()
{
assert(num_iters_ == 0 && "dangling iterators will attempt to dereference an invalid pointer in destructor");
delete_all();
}
std::pair<map_location,unit>* unit_map::unit_iterator::operator->() const
{
assert(valid());
return i_->second.second;
}
std::pair<map_location,unit>& unit_map::unit_iterator::operator*() const
{
assert(valid());
return *i_->second.second;
}
unit_map::unit_iterator unit_map::unit_iterator::operator++() {
assert(i_ != map_->map_.end());
++i_;
while (i_ != map_->map_.end() && !valid()) {
++i_;
}
return *this;
}
unit_map::unit_iterator unit_map::unit_iterator::operator++(int){
assert(i_ != map_->map_.end());
umap::iterator iter(i_);
++i_;
while (i_ != map_->map_.end() && !valid()) {
++i_;
}
return unit_iterator(iter, map_);
}
// Due to unit <-> unit_map dependencies, must be out of line.
const std::pair<map_location,unit>* unit_map::const_unit_iterator::operator->() const
{
assert(valid());
return i_->second.second;
}
const std::pair<map_location,unit>& unit_map::const_unit_iterator::operator*() const
{
assert(valid());
return *i_->second.second;
}
unit_map::const_unit_iterator unit_map::const_unit_iterator::operator++() {
assert(i_ != map_->map_.end());
++i_;
while (i_ != map_->map_.end() && !valid()) {
++i_;
}
return *this;
}
unit_map::const_unit_iterator unit_map::const_unit_iterator::operator--() {
umap::const_iterator begin = map_->begin().i_;
assert(i_ != begin);
--i_;
while (i_ != begin && !valid()) {
--i_;
}
return *this;
}
unit_map::const_unit_iterator unit_map::const_unit_iterator::operator++(int){
assert(i_ != map_->map_.end());
umap::const_iterator iter(i_);
++i_;
while (i_ != map_->map_.end() && !valid()) {
++i_;
}
return const_unit_iterator(iter, map_);
}
unit_map::unit_xy_iterator::unit_xy_iterator(const unit_iterator &i) :
counter_(i.map_),
i_(i.i_),
map_(i.map_),
loc_(i.valid() ? i->first : map_location())
{
}
std::pair<map_location,unit>* unit_map::unit_xy_iterator::operator->() const
{
assert(valid());
return i_->second.second;
}
std::pair<map_location,unit>& unit_map::unit_xy_iterator::operator*() const
{
assert(valid());
return *i_->second.second;
}
unit_map::unit_xy_iterator unit_map::unit_xy_iterator::operator++() {
assert(i_ != map_->map_.end());
++i_;
while (i_ != map_->map_.end() && !valid()) {
++i_;
}
if (i_ != map_->map_.end()) {
loc_ = i_->second.second->first;
}
return *this;
}
unit_map::unit_xy_iterator unit_map::unit_xy_iterator::operator++(int){
assert(i_ != map_->map_.end());
umap::iterator iter(i_);
map_location pre_loc = loc_;
++i_;
while (i_ != map_->map_.end() && !valid()) {
++i_;
}
if (i_ != map_->map_.end()) {
loc_ = i_->second.second->first;
}
return unit_xy_iterator(iter, map_, pre_loc);
}
bool unit_map::unit_xy_iterator::valid() const {
return i_ != map_->map_.end() && i_->second.first && loc_ == i_->second.second->first;
}
unit_map::const_unit_xy_iterator::const_unit_xy_iterator(const unit_iterator &i) :
counter_(i.map_),
i_(i.i_),
map_(i.map_),
loc_(i.valid() ? i->first : map_location())
{
}
unit_map::const_unit_xy_iterator::const_unit_xy_iterator(const const_unit_iterator &i) :
counter_(i.map_),
i_(i.i_),
map_(i.map_),
loc_(i.valid() ? i->first : map_location())
{
}
const std::pair<map_location,unit>* unit_map::const_unit_xy_iterator::operator->() const {
assert(valid());
return i_->second.second;
}
const std::pair<map_location,unit>& unit_map::const_unit_xy_iterator::operator*() const {
assert(valid());
return *i_->second.second;
}
unit_map::const_unit_xy_iterator unit_map::const_unit_xy_iterator::operator++() {
assert(i_ != map_->map_.end());
++i_;
while (i_ != map_->map_.end() && !valid()) {
++i_;
}
if (i_ != map_->map_.end()) {
loc_ = i_->second.second->first;
}
return *this;
}
unit_map::const_unit_xy_iterator unit_map::const_unit_xy_iterator::operator++(int){
assert(i_ != map_->map_.end());
map_location pre_loc = loc_;
umap::const_iterator iter(i_);
++i_;
while (i_ != map_->map_.end() && !valid()) {
++i_;
}
if (i_ != map_->map_.end()) {
loc_ = i_->second.second->first;
}
return const_unit_xy_iterator(iter, map_, pre_loc);
}
bool unit_map::const_unit_xy_iterator::valid() const {
return i_ != map_->map_.end() && i_->second.first && loc_ == i_->second.second->first;
}
unit_map::xy_accessor::xy_accessor(const unit_iterator &i) :
counter_(i.map_),
i_(i.i_),
map_(i.map_),
loc_(i.valid() ? i->first : map_location())
{
}
unit_map::xy_accessor::xy_accessor(const unit_xy_iterator &i) :
counter_(i.map_),
i_(i.i_),
map_(i.map_),
loc_(i.valid() ? i->first : map_location())
{
}
std::pair<map_location,unit>* unit_map::xy_accessor::operator->() {
if (!valid()) { assert(0); }
return i_->second.second;
}
std::pair<map_location,unit>& unit_map::xy_accessor::operator*() {
if (!valid()) { assert(0); }
return *i_->second.second;
}
bool unit_map::xy_accessor::valid() {
if (i_->second.first && i_->second.second->first == loc_) {
return true;
}
unit_iterator u_iter = map_->find(loc_);
if (u_iter.valid()) {
i_ = u_iter.i_;
loc_ = i_->second.second->first;
return true;
}
return false;
}
unit_map::const_xy_accessor::const_xy_accessor(const const_unit_iterator &i) :
counter_(i.map_),
i_(i.i_),
map_(i.map_),
loc_(i.valid() ? i->first : map_location())
{
}
unit_map::const_xy_accessor::const_xy_accessor(const unit_iterator &i) :
counter_(i.map_),
i_(i.i_),
map_(i.map_),
loc_(i.valid() ? i->first : map_location())
{
}
unit_map::const_xy_accessor::const_xy_accessor(const const_unit_xy_iterator &i) :
counter_(i.map_),
i_(i.i_),
map_(i.map_),
loc_(i.valid() ? i->first : map_location())
{
}
unit_map::const_xy_accessor::const_xy_accessor(const unit_xy_iterator &i) :
counter_(i.map_),
i_(i.i_),
map_(i.map_),
loc_(i.valid() ? i->first : map_location())
{
}
const std::pair<map_location,unit>* unit_map::const_xy_accessor::operator->() {
if (!valid()) { assert(0); }
return i_->second.second;
}
const std::pair<map_location,unit>& unit_map::const_xy_accessor::operator*() {
if (!valid()) { assert(0); }
return *i_->second.second;
}
bool unit_map::const_xy_accessor::valid() {
if (i_->second.first && i_->second.second->first == loc_) {
return true;
}
const_unit_iterator u_iter = map_->find(loc_);
if (u_iter.valid()) {
i_ = u_iter.i_;
loc_ = i_->second.second->first;
return true;
}
return false;
}
unit_map::unit_iterator unit_map::find(const map_location &loc) {
lmap::const_iterator i = lmap_.find(loc);
@ -390,26 +72,26 @@ unit_map::unit_iterator unit_map::find(const map_location &loc) {
umap::iterator iter = map_.find(i->second);
assert(iter->second.first);
return unit_iterator(iter , this);
assert(is_valid(iter));
return unit_iterator(iter, this);
}
unit_map::const_unit_iterator unit_map::find(const map_location &loc) const {
lmap::const_iterator iter = lmap_.find(loc);
if (iter == lmap_.end()) {
lmap::const_iterator loc_iter = lmap_.find(loc);
if (loc_iter == lmap_.end()) {
return const_unit_iterator(map_.end(), this);
}
umap::const_iterator i = map_.find(iter->second);
umap::const_iterator iter = map_.find(loc_iter->second);
assert(i->second.first);
return const_unit_iterator(i , this);
assert(is_valid(iter));
return const_unit_iterator(iter, this);
}
unit_map::unit_iterator unit_map::find(const size_t &id) {
umap::iterator iter = map_.find(id);
if (iter == map_.end() || !iter->second.first) {
if (iter == map_.end() || !is_valid(iter)) {
return unit_iterator(map_.end(), this);
}
return unit_iterator(iter, this);
@ -417,7 +99,7 @@ unit_map::unit_iterator unit_map::find(const size_t &id) {
unit_map::const_unit_iterator unit_map::find(const size_t &id) const {
umap::const_iterator iter = map_.find(id);
if (iter == map_.end() || !iter->second.first) {
if (iter == map_.end() || !is_valid(iter)) {
return const_unit_iterator(map_.end(), this);
}
return const_unit_iterator(iter, this);
@ -428,9 +110,9 @@ struct match_unit_id {
{}
bool operator()(const unit_map::umap::value_type& val) const
{
if (!val.first)
if (!val.second.is_valid())
return false;
return val.second.second->second.id() == id_;
return val.second.get_unit().id() == id_;
}
private:
const std::string& id_;
@ -439,8 +121,8 @@ struct match_unit_id {
unit_map::unit_iterator unit_map::find(const std::string& id) {
WRN_NG << "Finding using id is slow operation\n";
umap::iterator iter = std::find_if(map_.begin(), map_.end(), match_unit_id(id));
if (iter == map_.end() || !iter->second.first) {
return unit_iterator(map_.end(), this);
if (iter == map_.end() || !is_valid(iter)) {
return end();
}
return unit_iterator(iter, this);
}
@ -448,38 +130,45 @@ unit_map::unit_iterator unit_map::find(const std::string& id) {
unit_map::const_unit_iterator unit_map::find(const std::string& id) const {
WRN_NG << "Finding using id is slow operation\n";
umap::const_iterator iter = std::find_if(map_.begin(), map_.end(), match_unit_id(id));
if (iter == map_.end() || !iter->second.first) {
return const_unit_iterator(map_.end(), this);
if (iter == map_.end() || !is_valid(iter)) {
return end();
}
return const_unit_iterator(iter, this);
}
unit_map::unit_iterator unit_map::begin() {
// clean if there are more invalid than valid, this block just needs to go somewhere that is likely to be
// called when num_iters_ == 0. This seems as good a place as any.
if (num_invalid_ > lmap_.size() && num_iters_ == 0) {
clean_invalid();
}
// This call just needs to go somewhere that is likely to be
// called when num_iters_ == 0. This seems as good a place as any.
clean_invalid();
umap::iterator i = map_.begin();
while (i != map_.end() && !i->second.first) {
++i;
}
return unit_iterator(i, this);
umap::iterator i = map_.begin();
while (i != map_.end() && !is_valid(i)) {
++i;
}
return unit_iterator(i, this);
}
unit_map::const_unit_iterator unit_map::begin() const {
umap::const_iterator i = map_.begin();
while (i != map_.end() && !is_valid(i)) {
++i;
}
return const_unit_iterator(i, this);
}
void unit_map::add(std::pair<map_location,unit> *p)
{
size_t unit_id = p->second.underlying_id();
unit_id_type unit_id = p->second.underlying_id();
umap::iterator iter = map_.find(unit_id);
if (iter == map_.end()) {
map_[unit_id] = std::make_pair(true, p);
} else if(!iter->second.first) {
iter->second.second = p;
map_[unit_id] = node(true, p);
} else if(!is_valid(iter)) {
iter->second.ptr_ = p;
validate(iter);
} else if(iter->second.second->first == p->first) {
} else if(iter->second.get_location() == p->first) {
replace(p);
return;
} else {
@ -487,10 +176,10 @@ void unit_map::add(std::pair<map_location,unit> *p)
" - " << p->second.id() <<
" - " << p->second.underlying_id() <<
" (" << p->first <<
") over " << iter->second.second->second.name() <<
" - " << iter->second.second->second.id() <<
" - " << iter->second.second->second.underlying_id() <<
" (" << iter->second.second->first <<
") over " << iter->second.get_unit().name() <<
" - " << iter->second.get_unit().id() <<
" - " << iter->second.get_unit().underlying_id() <<
" (" << iter->second.get_location() <<
"). The new unit will be assigned underlying_id="
<< (1 + n_unit::id_manager::instance().get_save_id())
<< " to prevent duplicate id conflicts.\n";
@ -517,9 +206,9 @@ void unit_map::replace(std::pair<map_location,unit> *p)
void unit_map::delete_all()
{
for (umap::iterator i = map_.begin(); i != map_.end(); ++i) {
if (i->second.first) {
DBG_NG << "Delete unit " << i->second.second->second.underlying_id() << "\n";
delete(i->second.second);
if (is_valid(i)) {
DBG_NG << "Delete unit " << i->second.get_unit().underlying_id() << "\n";
delete(i->second.ptr_);
}
}
@ -534,7 +223,7 @@ std::pair<map_location,unit> *unit_map::extract(const map_location &loc)
return NULL;
umap::iterator iter = map_.find(i->second);
std::pair<map_location,unit> *res = iter->second.second;
std::pair<map_location,unit> *res = iter->second.ptr_;
DBG_NG << "Extract unit " << i->second << "\n";
invalidate(iter);
@ -550,11 +239,11 @@ size_t unit_map::erase(const map_location &loc)
return 0;
umap::iterator iter = map_.find(i->second);
DBG_NG << "Replace unit " << i->second << "\n";
DBG_NG << "Erase unit " << i->second << "\n";
invalidate(iter);
delete iter->second.second;
delete iter->second.ptr_;
lmap_.erase(i);
return 1;
@ -574,11 +263,14 @@ void unit_map::clear()
}
void unit_map::clean_invalid() {
if (num_invalid_ < lmap_.size() || num_iters_ > 0)
return;
size_t num_cleaned = 0;
umap::iterator iter = map_.begin();
while (iter != map_.end()) {
if (!iter->second.first) {
if (!is_valid(iter)) {
map_.erase(iter++);
++num_cleaned;
} else {

View file

@ -18,22 +18,15 @@
#define UNIT_MAP_H_INCLUDED
class unit;
#include <cassert>
#include <cstring>
#include <boost/static_assert.hpp>
#include "map_location.hpp"
// We used to just open-code a std::map<location,unit>,
// but as unit gained weight leading up to 1.1.3,
// manipulating the map caused significant performance issues
// for the AI, which had to actually move units for accurate
// simulation with the new, more powerful filtering.
// This class eases the transition, by providing a wrapper
// which acts like a map of units, not unit pointers,
// except implemented with pointers and hence providing
// a cheap move function.
//
// Further extended to prevent invalidating iterators when
// changes are made to the map, and to add more powerful iterators/
// accessors.
// unit_map is used primarily as a map<location, unit>, but we need to be able to move a unit
// without copying it as the ai moves units a lot.
// Also, we want iterators to remain valid as much as reasonable as the underlying map is changed
// and we want a way to test an iterator for validity.
class unit_map
{
@ -41,415 +34,315 @@ private:
/**
* Used so unit_map can keep a count of iterators and clean invalid pointers
* when no iterators exist. Every iterator and accessor has a counter
* only when no iterators exist. Every iterator and accessor has a counter
* instance.
*/
struct iterator_counter {
iterator_counter() : map_(NULL) {}
iterator_counter(const unit_map* map) : map_(map)
{ map_->add_iter(); }
{ if (map_) map_->add_iter(); }
iterator_counter(const iterator_counter& i) : map_(i.map_) {
if (map_) map_->add_iter();
}
iterator_counter &operator =(const iterator_counter &that) {
if (this == &that)
return *this;
iterator_counter(const iterator_counter& i) : map_(i.map_)
{ if (map_) map_->add_iter(); }
iterator_counter& operator=(const iterator_counter &that) {
if (map_) map_->remove_iter();
map_=that.map_;
map_ = that.map_;
if (map_) map_->add_iter();
return *this;
}
~iterator_counter() {if (map_) map_->remove_iter(); }
~iterator_counter()
{if (map_) map_->remove_iter(); }
private:
const unit_map* map_;
};
struct node {
bool valid_;
std::pair<map_location, unit>* ptr_;
node(bool v, std::pair<map_location, unit>* p) : valid_(v), ptr_(p) { }
node() : valid_(0), ptr_(NULL) { }
bool is_valid() const { return valid_; }
bool& get_valid() { return valid_; }
unit& get_unit() const;
map_location& get_location() const;
};
public:
/** unit.underlying_id() type */
typedef size_t unit_id_type;
/** unit.underlying_id() -> unit_map::node . This requires that underlying_id() be unique (which is enforced in unit_map::add).*/
typedef std::map<unit_id_type,node> umap;
/** location -> unit.underlying_id() of the unit at that location */
typedef std::map<map_location, unit_id_type> lmap;
unit_map() : map_(), lmap_(), num_iters_(0), num_invalid_(0) { };
unit_map(const unit_map &that);
unit_map &operator =(const unit_map &that);
unit_map& operator=(const unit_map &that);
/** A unit map with a copy of a single unit in it. */
explicit unit_map(const map_location &loc, const unit &u);
unit_map(const map_location &loc, const unit &u);
~unit_map();
/**
* Keyed with unit's underlying_id. bool flag is whether the following pair
* pointer is valid. pointer to pair used to imitate a map<location, unit>
*/
typedef std::map<size_t,std::pair<bool, std::pair<map_location,unit>*> > umap;
/** Maps locations to the underlying_id() of the unit at that location. */
typedef std::map<map_location, size_t> lmap;
// ~~~ Begin iterator code ~~~
struct const_unit_iterator;
struct unit_xy_iterator;
struct const_unit_xy_iterator;
struct xy_accessor;
struct const_xy_accessor;
template <typename X, typename Y>
struct convertible;
/**
* For iterating over every unit. Iterator is valid as long as there is
* there is a unit w/ matching underlying_id in the map.
*/
struct unit_iterator
{
unit_iterator() :
counter_(),
i_(),
map_(0)
{ }
template <template <typename> class iter_policy, typename iter_types>
struct iterator_base {
typedef typename iter_types::map_type map_type;
typedef typename iter_types::iterator_type iterator_type;
typedef typename iter_types::value_type value_type;
typedef typename iter_types::reference_type reference_type;
typedef typename iter_types::pointer_type pointer_type;
unit_iterator(const unit_iterator &i) : counter_(i.map_), i_(i.i_), map_(i.map_) { }
unit_iterator(umap::iterator i, unit_map* map) : counter_(map), i_(i), map_(map) { }
iterator_base() : policy_(), counter_(), map_(NULL), i_() { }
iterator_base(iterator_type i, map_type* m) : policy_(i, m), counter_(m), map_(m), i_(i) { }
std::pair<map_location,unit> *operator->() const;
std::pair<map_location,unit>& operator*() const;
pointer_type operator->() const { assert(policy_.valid(i_, map_)); return i_->second.ptr_; }
reference_type operator*() const { assert(policy_.valid(i_, map_)); return *i_->second.ptr_; }
unit_iterator operator++();
unit_iterator operator++(int);
iterator_base& operator++();
iterator_base operator++(int);
iterator_base& operator--();
iterator_base operator--(int);
bool operator==(const unit_iterator &that) const
{ return that.i_ == this->i_; }
bool valid() const { return policy_.valid(i_, map_); }
bool operator!=(const unit_iterator &that) const
{ return that.i_ != this->i_; }
bool operator==(const iterator_base& rhs) const { return i_ == rhs.i_; }
bool operator!=(const iterator_base& rhs) const { return !operator==(rhs); }
bool valid() const
{ return i_ != map_->map_.end() && i_->second.first; }
template <template <typename> class that_policy, typename that_types>
iterator_base(const iterator_base<that_policy, that_types>& that) :
policy_(that.i_, that.map_),
counter_(that.counter_),
map_(that.map_),
i_(that.i_)
{
BOOST_STATIC_ASSERT(sizeof(convertible<that_policy<that_types>, iter_policy<iter_types> >) != 0);
BOOST_STATIC_ASSERT(sizeof(convertible<that_types, iter_types>) != 0);
}
friend struct const_unit_iterator;
friend struct unit_xy_iterator;
friend struct const_unit_xy_iterator;
friend struct xy_accessor;
friend struct const_xy_accessor;
private:
template <template <typename> class X, typename Y> friend class iterator_base;
template <typename X> friend class xy_accessor_base;
private:
iter_policy<iter_types> policy_;
iterator_counter counter_;
umap::iterator i_;
unit_map* map_;
map_type* map_;
iterator_type i_;
};
struct const_unit_iterator
{
const_unit_iterator(const unit_iterator &i) : counter_(i.map_), i_(i.i_), map_(i.map_) { }
const_unit_iterator() :
counter_(),
i_(),
map_(0)
{ }
const_unit_iterator(const const_unit_iterator &i) : counter_(i.map_), i_(i.i_), map_(i.map_) { }
const_unit_iterator(umap::const_iterator i, const unit_map* map): counter_(map), i_(i), map_(map) { }
const std::pair<map_location,unit>* operator->() const;
const std::pair<map_location,unit>& operator*() const;
const_unit_iterator operator++();
const_unit_iterator operator++(int);
const_unit_iterator operator--();
bool operator==(const const_unit_iterator &that) const
{ return that.i_ == this->i_; }
bool operator!=(const const_unit_iterator &that) const
{ return that.i_ != this->i_; }
bool valid() const
{ return i_ != map_->map_.end() && i_->second.first; }
friend struct const_unit_xy_iterator;
friend struct const_xy_accessor;
private:
iterator_counter counter_;
umap::const_iterator i_;
const unit_map* map_;
struct standard_iter_types {
typedef unit_map map_type;
typedef unit_map::umap::iterator iterator_type;
typedef std::pair<map_location, unit> value_type;
typedef value_type* pointer_type;
typedef value_type& reference_type;
};
struct const_iter_types {
typedef const unit_map map_type;
typedef unit_map::umap::const_iterator iterator_type;
typedef const std::pair<map_location, unit> value_type;
typedef value_type* pointer_type;
typedef value_type& reference_type;
};
template <typename iter_types>
struct unit_policy {
typedef typename iter_types::iterator_type iterator_type;
unit_policy() { }
unit_policy(const iterator_type& i, const unit_map* map) { }
void update(const iterator_type& i, const unit_map* map) { }
bool valid(const iterator_type& i, const unit_map* map) const { return i != map->map_.end() && i->second.is_valid(); }
};
template <typename iter_types>
struct unit_xy_policy {
typedef typename iter_types::iterator_type iterator_type;
unit_xy_policy() { }
unit_xy_policy(const iterator_type& i, const unit_map* map) : loc_(i->second.get_location()) { }
void update(iterator_type& iter, const unit_map* map) {
loc_ = iter->second.get_location();
}
bool valid(const iterator_type& iter, const unit_map* map) const {
return iter != map->map_.end() && iter->second.is_valid() && iter->second.get_location() == loc_;
}
private:
map_location loc_;
};
template <typename iter_types>
struct xy_accessor_base {
typedef typename iter_types::map_type map_type;
typedef typename iter_types::iterator_type iterator_type;
typedef typename iter_types::reference_type reference_type;
xy_accessor_base() : counter_(), loc_(), map_(NULL) { }
xy_accessor_base(const iterator_type& iter, const unit_map* map) : counter_(), loc_(iter->second.get_location()), map_(map) { }
template <typename that_types>
xy_accessor_base(const xy_accessor_base<that_types>& that) :
counter_(that.counter_),
loc_(that.loc_),
map_(that.map_)
{
BOOST_STATIC_ASSERT(sizeof(convertible<that_types, iter_types>) != 0);
}
template <typename that_types>
xy_accessor_base(const iterator_base<unit_policy, that_types>& that) :
counter_(that.counter_),
loc_(),
map_(that.map_)
{
BOOST_STATIC_ASSERT(sizeof(convertible<that_types, iter_types>) != 0);
if (that.valid()) loc_ = that->first;
}
iterator_base<unit_policy, iter_types> operator->() const { assert(valid()); return map_->find(loc_); }
reference_type operator*() const { assert(valid()); return *map_->find(loc_); }
bool operator==(const xy_accessor_base& rhs) { return loc_ == rhs.loc_; }
bool operator!=(const xy_accessor_base& rhs) { return !operator==(rhs); }
bool valid() const { return map_->find(loc_) != map_->end(); }
private:
iterator_counter counter_;
map_location loc_;
map_type* map_;
};
// ~~~ End iterator code ~~~
/**
* All iterators are invalidated on unit_map::clear(), unit_map::swap(), unit_map::delete_all(), etc.
* Several implicit conversion are supplied, you can convert from more restrictive to less restrictive.
* That is:
* non-const -> const
* unit_iter -> xy_unit_iter
* unit_iter -> xy_accessor
*/
/**
* unit_iterators iterate over all units in the unit_map. A unit_iterator is invalidated if
* unit_map::erase, unit_map::extract, or unit_map::replace are called with the location of the
* unit that the unit_iterator points to. It will become valid again if unit_map::add is called with
* a pair containing the unit that the iterator points to. Basically, as long as the unit is on the
* gamemap somewhere, the iterator will be valid.
*/
typedef iterator_base<unit_policy, standard_iter_types> unit_iterator;
typedef iterator_base<unit_policy, const_iter_types> const_unit_iterator;
/**
* unit_xy_iterators have all the constraints of unit_iterators and will also be invalidated if the unit
* is not at the same location as when the iterator first pointed at it. That is, as long as the unit stays
* in the same spot, the iterator is valid.
*/
typedef iterator_base<unit_xy_policy, standard_iter_types> unit__xy_iterator;
typedef iterator_base<unit_xy_policy, const_iter_types> const_unit_xy_iterator;
/**
* xy_accessors cannot be incremented or decremented. An xy_accessor is valid as long as there is a unit at
* the map_location that it is created at, and it allows access to the unit at that location.
*/
typedef xy_accessor_base<standard_iter_types> xy_accessor;
typedef xy_accessor_base<const_iter_types> const_xy_accessor;
/** provided as a convenience as unit_map used to be an std::map */
typedef unit_iterator iterator;
typedef const_unit_iterator const_iterator;
/**
* Similar to unit_iterator, except that becomes invalid if unit is moved
* while the iterator points at it.
*/
struct unit_xy_iterator
{
unit_xy_iterator(const unit_iterator &i);
unit_xy_iterator() :
counter_(),
i_(),
map_(0),
loc_()
{}
unit_xy_iterator(const unit_xy_iterator &i) :
counter_(i.map_),
i_(i.i_),
map_(i.map_),
loc_(i.valid() ? i.loc_ : map_location())
{
}
unit_xy_iterator(umap::iterator i, unit_map* map, map_location loc): counter_(map), i_(i), map_(map), loc_(loc) { }
std::pair<map_location,unit>* operator->() const;
std::pair<map_location,unit>& operator*() const;
unit_xy_iterator operator++();
unit_xy_iterator operator++(int);
bool operator==(const unit_xy_iterator &that) const
{ return that.i_ == this->i_; }
bool operator!=(const unit_xy_iterator &that) const
{ return that.i_ != this->i_; }
bool valid() const;
friend struct const_unit_xy_iterator;
friend struct xy_accessor;
friend struct const_xy_accessor;
private:
iterator_counter counter_;
umap::iterator i_;
unit_map* map_;
map_location loc_;
};
struct const_unit_xy_iterator
{
const_unit_xy_iterator(const unit_iterator &i);
const_unit_xy_iterator(const const_unit_iterator &i);
const_unit_xy_iterator() :
counter_(),
i_(),
map_(0),
loc_()
{
}
const_unit_xy_iterator(umap::const_iterator i, const unit_map* map, map_location loc): counter_(map), i_(i), map_(map), loc_(loc) { }
const_unit_xy_iterator(const unit_xy_iterator &i) :
counter_(i.map_),
i_(i.i_),
map_(i.map_),
loc_(i.valid() ? i.loc_ : map_location())
{
}
const_unit_xy_iterator(const const_unit_xy_iterator &i) :
counter_(i.map_),
i_(i.i_),
map_(i.map_),
loc_(i.valid() ? i.loc_ : map_location())
{
}
const std::pair<map_location,unit>* operator->() const;
const std::pair<map_location,unit>& operator*() const;
const_unit_xy_iterator operator++();
const_unit_xy_iterator operator++(int);
bool operator==(const const_unit_xy_iterator &that) const
{ return that.i_ == this->i_; }
bool operator!=(const const_unit_xy_iterator &that) const
{ return that.i_ != this->i_; }
bool valid() const;
friend struct const_xy_accessor;
private:
iterator_counter counter_;
umap::const_iterator i_;
const unit_map* map_;
map_location loc_;
};
/**
* Used to access the unit at a given position. Is valid as long as any unit
* is in that position. Can switch from invalid to valid.
* Lookups can be done by map_location, by unit::underlying_id(), or by unit::id().
* Looking up with unit::id() is slow.
* Returned iterators can be implicitly converted to the other types.
*/
struct xy_accessor
{
xy_accessor(const unit_iterator &i);
xy_accessor(const unit_xy_iterator &i);
xy_accessor() :
counter_(),
i_(),
map_(),
loc_()
{
}
std::pair<map_location,unit>* operator->();
std::pair<map_location,unit>& operator*();
bool valid();
private:
iterator_counter counter_;
umap::iterator i_;
unit_map* map_;
map_location loc_;
};
struct const_xy_accessor
{
const_xy_accessor(const unit_iterator &i);
const_xy_accessor(const unit_xy_iterator &i);
const_xy_accessor(const const_unit_iterator &i);
const_xy_accessor(const const_unit_xy_iterator &i);
const_xy_accessor() :
counter_(),
i_(),
map_(),
loc_()
{
}
const std::pair<map_location,unit>* operator->();
const std::pair<map_location,unit>& operator*();
bool valid();
private:
iterator_counter counter_;
umap::const_iterator i_;
const unit_map* map_;
map_location loc_;
};
/**
* Return object can be implicitly converted to any of the other iterators
* or accessors
*/
unit_iterator find(const map_location &loc) ;
unit_iterator find(const size_t& id);
unit_iterator find(const map_location& loc) ;
unit_iterator find(const unit_id_type& id);
unit_iterator find(const std::string& id);
/**
* Return object can be implicity converted to any of the other const
* iterators or accessors
*/
const_unit_iterator find(const map_location &loc) const;
const_unit_iterator find(const size_t& id) const;
const_unit_iterator find(const map_location& loc) const;
const_unit_iterator find(const unit_id_type& id) const;
const_unit_iterator find(const std::string& id) const;
size_t count(const map_location &loc) const {
return lmap_.count(loc);
}
size_t count(const map_location& loc) const { return lmap_.count(loc); }
/**
* Return object can be implicitly converted to any of the other iterators
* or accessors
* Return iterators are implicitly converted to other types as needed.
*/
unit_iterator begin();
const_unit_iterator begin() const;
/**
* Return object can be implicity converted to any of the other const
* iterators or accessors
*/
const_unit_iterator begin() const {
umap::const_iterator i = map_.begin();
while (i != map_.end() && !i->second.first) {
++i;
}
return const_unit_iterator(i, this);
}
/**
* Return object can be implicitly converted to any of the other iterators
* or accessors
*/
unit_iterator end() {
return iterator(map_.end(), this);
}
/**
* Return object can be implicity converted to any of the other const
* iterators or accessors
*/
const_unit_iterator end() const {
return const_iterator(map_.end(), this);
}
size_t size() const {
return lmap_.size();
}
unit_iterator end() { return iterator(map_.end(), this); }
const_unit_iterator end() const { return const_iterator(map_.end(), this); }
size_t size() const { return lmap_.size(); }
void clear();
/** Extract (like erase, but don't delete). */
std::pair<map_location,unit> *extract(const map_location &loc);
/**
* Map owns pointer after this. Loc must be currently empty. unit's
* underlying_id should not be present in the map already
* underlying_id should not be present in the map already.
*/
void add(std::pair<map_location,unit> *p);
/** Like add, but loc must be occupied (implicitly erased). */
void replace(std::pair<map_location,unit> *p);
/** Erases the pair<location, unit> of this location. */
void erase(xy_accessor pos);
size_t erase(const map_location &loc);
/** Extract (like erase, but don't delete). */
std::pair<map_location,unit>* extract(const map_location& loc);
/** Invalidates all iterators on both maps */
void swap(unit_map& o) {
map_.swap(o.map_);
lmap_.swap(o.lmap_);
std::swap(map_, o.map_);
std::swap(lmap_, o.lmap_);
std::swap(num_invalid_, o.num_invalid_);
}
private:
/** Removes invalid entries in map_. Called automatically when safe and needed. */
/** Removes invalid entries in map_ if safe and needed. */
void clean_invalid();
void invalidate(umap::iterator i)
{if(i == map_.end()) return; i->second.first = false; ++num_invalid_;}
void validate(umap::iterator i)
{if(i == map_.end()) return; i->second.first = true; --num_invalid_;}
void invalidate(umap::iterator& i)
{ if(i == map_.end()) return; i->second.get_valid() = false; ++num_invalid_; }
void validate(umap::iterator& i)
{ if(i == map_.end()) return; i->second.get_valid() = true; --num_invalid_; }
void delete_all();
void add_iter() const { ++num_iters_; }
void remove_iter() const { --num_iters_; }
bool is_valid(const umap::const_iterator& i) const { return i != map_.end() && i->second.is_valid(); }
/**
* Key: unit's underlying_id. bool indicates validity of pointer. pointer to
* pair used to imitate a map<location, unit>
* unit.underlying_id() -> unit_map::node
*/
umap map_;
@ -463,4 +356,59 @@ private:
size_t num_invalid_;
};
// define allowed conversions.
template <>
struct unit_map::convertible<unit_map::standard_iter_types, unit_map::const_iter_types> { };
template <typename T>
struct unit_map::convertible<T, T> { };
template <typename X, typename Y>
struct unit_map::convertible<unit_map::unit_policy<X>, unit_map::unit_policy<Y> > { };
template <typename X, typename Y>
struct unit_map::convertible<unit_map::unit_policy<X>, unit_map::unit_xy_policy<Y> > { };
template <typename X, typename Y>
struct unit_map::convertible<unit_map::unit_xy_policy<X>, unit_map::unit_xy_policy<Y> > { };
template <template <typename> class iter_policy, typename iter_types>
unit_map::iterator_base<iter_policy, iter_types>& unit_map::iterator_base<iter_policy, iter_types>::operator++() {
assert(i_ != map_->map_.end());
++i_;
while (i_ != map_->map_.end() && !i_->second.is_valid()) ++i_;
if (i_ != map_->map_.end()) policy_.update(i_, map_);
return *this;
}
template <template <typename> class iter_policy, typename iter_types>
unit_map::iterator_base<iter_policy, iter_types> unit_map::iterator_base<iter_policy, iter_types>::operator++(int) {
unit_map::iterator_base<iter_policy, iter_types> temp(*this);
operator++();
return temp;
}
template <template <typename> class iter_policy, typename iter_types>
unit_map::iterator_base<iter_policy, iter_types>& unit_map::iterator_base<iter_policy, iter_types>::operator--() {
assert(i_ != map_->map_.begin());
--i_;
while (i_ != map_->map_.begin() && !i_->second.is_valid()) --i_;
if (i_->second.is_valid()) policy_.update(i_, map_);
return *this;
}
template <template <typename> class iter_policy, typename iter_types>
unit_map::iterator_base<iter_policy, iter_types> unit_map::iterator_base<iter_policy, iter_types>::operator--(int) {
unit_map::iterator_base<iter_policy, iter_types> temp(*this);
operator--();
return temp;
}
#endif // UNIT_MAP_H_INCLUDED