Merge branch 'unit_map_fixes'

This commit is contained in:
Alexander van Gessel 2013-11-26 19:22:08 +01:00
commit ffc68170fe
2 changed files with 136 additions and 258 deletions

View file

@ -33,19 +33,13 @@ static lg::log_domain log_engine("engine");
unit_map::unit_map()
: umap_()
, lmap_()
, ilist_()
, the_end_()
{
init_end();
}
unit_map::unit_map(const unit_map& that)
: umap_()
, lmap_()
, ilist_()
, the_end_()
{
init_end();
for (const_unit_iterator i = that.begin(); i != that.end(); ++i) {
add(i->get_location(), *i);
}
@ -62,18 +56,16 @@ void unit_map::swap(unit_map &o) {
std::swap(umap_, o.umap_);
std::swap(lmap_, o.lmap_);
std::swap(ilist_, o.ilist_);
std::swap(the_end_, o.the_end_);
}
unit_map::~unit_map() {
clear(true);
}
unit_map::t_ilist::iterator unit_map::begin_core() const {
unit_map::t_umap::iterator unit_map::begin_core() const {
self_check();
t_ilist::iterator i = ilist_.begin();
while (i != the_end_ && (i->unit == NULL)) { ++i; }
t_umap::iterator i = umap_.begin();
while (i != umap_.end() && (i->second.unit == NULL)) { ++i; }
return i;
}
@ -92,32 +84,32 @@ std::pair<unit_map::unit_iterator, bool> unit_map::move(const map_location &src,
//Find the unit at the src location
t_lmap::iterator i = lmap_.find(src);
if(i == lmap_.end()) { return std::make_pair(make_unit_iterator(the_end_), false);}
if(i == lmap_.end()) { return std::make_pair(make_unit_iterator(i), false);}
t_ilist::iterator lit(i->second);
t_umap::iterator uit(i->second);
if(src == dst){ return std::make_pair(make_unit_iterator(lit),true);}
if(src == dst){ return std::make_pair(make_unit_iterator(uit), true);}
//Fail if there is no unit to move
unit *p = lit->unit;
if(p == NULL){ return std::make_pair(make_unit_iterator(lit), false);}
unit *p = uit->second.unit;
if(p == NULL){ return std::make_pair(make_unit_iterator(uit), false);}
p->set_location(dst);
lmap_.erase(i);
std::pair<t_lmap::iterator,bool> res = lmap_.insert(std::make_pair(dst, lit));
std::pair<t_lmap::iterator,bool> res = lmap_.insert(std::make_pair(dst, uit));
//Fail and don't move if the destination is already occupied
if(res.second == false) {
p->set_location(src);
lmap_.insert(std::make_pair(src, lit));
return std::make_pair(make_unit_iterator(lit), false);
lmap_.insert(std::make_pair(src, uit));
return std::make_pair(make_unit_iterator(uit), false);
}
self_check();
return std::make_pair(make_unit_iterator(lit), true);
return std::make_pair(make_unit_iterator(uit), true);
}
@ -125,9 +117,9 @@ std::pair<unit_map::unit_iterator, bool> unit_map::move(const map_location &src,
It needs to succeed on the insertion to the umap and to the lmap
otherwise all operations are reverted.
1. Insert a unit_pod into the list
2. Try insertion into the umap and remove the list item on failure
3. Try insertion in the lmap and remove the umap and the list item on failure
1. Construct a unit_pod
2. Try insertion into the umap
3. Try insertion in the lmap and remove the umap entry on failure
The one oddity is that to facilitate non-invalidating iterators the list
sometimes has NULL pointers which should be used when they correspond
@ -143,29 +135,25 @@ std::pair<unit_map::unit_iterator, bool> unit_map::insert(unit *p) {
if (!loc.valid()) {
ERR_NG << "Trying to add " << p->name()
<< " - " << p->id() << " at an invalid location; Discarding.\n";
return std::make_pair(make_unit_iterator(the_end_), false);
return std::make_pair(make_unit_iterator(umap_.end()), false);
}
unit_pod upod;
upod.unit = p;
upod.deleted_uid = unit_id;
ilist_.push_front(upod);
t_ilist::iterator lit(ilist_.begin());
DBG_NG << "Adding unit " << p->underlying_id() << " - " << p->id()
<< " to location: (" << loc << ")\n";
std::pair<t_umap::iterator, bool> uinsert = umap_.insert(std::make_pair(unit_id, lit ));
std::pair<t_umap::iterator, bool> uinsert = umap_.insert(std::make_pair(unit_id, upod ));
if (! uinsert.second) {
//If the UID is empty reinsert the unit in the same list element
if ( uinsert.first->second->unit == NULL) {
ilist_.pop_front();
lit = uinsert.first->second;
lit->unit = p;
assert(lit->ref_count != 0);
//If the pod is empty reinsert the unit in the same list element
if ( uinsert.first->second.unit == NULL) {
unit_pod &opod = uinsert.first->second;
opod.unit = p;
assert(opod.ref_count != 0);
} else {
unit *q = uinsert.first->second->unit;
unit *q = uinsert.first->second.unit;
ERR_NG << "Trying to add " << p->name()
<< " - " << p->id() << " - " << p->underlying_id()
<< " (" << loc << ") over " << q->name()
@ -176,7 +164,7 @@ std::pair<unit_map::unit_iterator, bool> unit_map::insert(unit *p) {
<< " to prevent duplicate id conflicts.\n";
p->clone(false);
uinsert = umap_.insert(std::make_pair(p->underlying_id(), lit ));
uinsert = umap_.insert(std::make_pair(p->underlying_id(), upod ));
int guard(0);
while (!uinsert.second && (++guard < 1e6) ) {
if(guard % 10 == 9){
@ -188,33 +176,32 @@ std::pair<unit_map::unit_iterator, bool> unit_map::insert(unit *p) {
"\nThank you for your help in fixing this bug.\n";
}
p->clone(false);
uinsert = umap_.insert(std::make_pair(p->underlying_id(), lit )); }
uinsert = umap_.insert(std::make_pair(p->underlying_id(), upod )); }
if (!uinsert.second) {
throw "One million collisions in unit_map"; }
throw game::error("One million collisions in unit_map"); }
}
}
std::pair<t_lmap::iterator,bool> linsert = lmap_.insert(std::make_pair(loc, lit ));
std::pair<t_lmap::iterator,bool> linsert = lmap_.insert(std::make_pair(loc, uinsert.first ));
//Fail if the location is occupied
if(! linsert.second) {
if(lit->ref_count == 0) {
if(upod.ref_count == 0) {
//Undo a virgin insertion
ilist_.pop_front();
umap_.erase(uinsert.first);
} else {
//undo a reinsertion
uinsert.first->second->unit = NULL;
uinsert.first->second.unit = NULL;
}
DBG_NG << "Trying to add " << p->name()
<< " - " << p->id() << " at location ("<<loc <<"); Occupied by "
<<(linsert.first->second)->unit->name()<< " - " << linsert.first->second->unit->id() <<"\n";
<<(linsert.first->second->second).unit->name()<< " - " << linsert.first->second->second.unit->id() <<"\n";
return std::make_pair(make_unit_iterator(the_end_), false);
return std::make_pair(make_unit_iterator(umap_.end()), false);
}
self_check();
return std::make_pair( make_unit_iterator( lit ), true);
return std::make_pair( make_unit_iterator( uinsert.first ), true);
}
std::pair<unit_map::unit_iterator, bool> unit_map::replace(const map_location &l, const unit &u) {
@ -231,13 +218,16 @@ std::pair<unit_map::unit_iterator, bool> unit_map::replace(const map_location &l
size_t unit_map::num_iters() const {
///Add up number of extant iterators
size_t num_iters(0);
t_ilist::const_iterator ii(ilist_.begin());
for( ; ii != the_end_ ; ++ii){
if(ii->ref_count < 0) {
t_umap::const_iterator ui = umap_.begin();
t_umap::const_iterator uend = umap_.end();
for( ; ui != uend ; ++ui){
if(ui->second.ref_count < 0) {
//Somewhere, someone generated 2^31 iterators to this unit
bool a_reference_counter_overflowed(false);
assert(a_reference_counter_overflowed); }
num_iters += ii->ref_count; }
assert(a_reference_counter_overflowed);
}
num_iters += ui->second.ref_count;
}
return num_iters;
}
@ -245,16 +235,15 @@ size_t unit_map::num_iters() const {
void unit_map::clear(bool force) {
assert(force || (num_iters() == 0));
for (t_ilist::iterator i = ilist_.begin(); i != the_end_; ++i) {
for (t_umap::iterator i = umap_.begin(); i != umap_.end(); ++i) {
if (is_valid(i)) {
DBG_NG << "Delete unit " << i->unit->underlying_id() << "\n";
delete i->unit;
DBG_NG << "Delete unit " << i->second.unit->underlying_id() << "\n";
delete i->second.unit;
}
}
lmap_.clear();
umap_.clear();
ilist_.clear();
}
unit *unit_map::extract(const map_location &loc) {
@ -262,24 +251,20 @@ unit *unit_map::extract(const map_location &loc) {
t_lmap::iterator i = lmap_.find(loc);
if (i == lmap_.end()) { return NULL; }
t_ilist::iterator lit(i->second);
t_umap::iterator uit(i->second);
unit *u = lit->unit;
unit *u = uit->second.unit;
size_t uid( u->underlying_id() );
DBG_NG << "Extract unit " << uid << " - " << u->id()
<< " from location: (" << loc << ")\n";
if(lit->ref_count == 0){
assert(lit != the_end_);
if(umap_.erase(uid) != 1){
error_recovery_externally_changed_uid(lit); }
ilist_.erase( lit );
assert(uit->first == uit->second.unit->underlying_id());
if(uit->second.ref_count == 0){
umap_.erase(uit);
} else {
//Soft extraction keeps the old lit item if any iterators reference it
lit->unit = NULL;
lit->deleted_uid = uid;
assert( uid != 0);
uit->second.unit = NULL;
}
lmap_.erase(i);
@ -288,41 +273,6 @@ unit *unit_map::extract(const map_location &loc) {
return u;
}
/** error_recovery_externally_changed_uid is called when an attempt is made to
delete a umap_ element, which fails because the underlying_id() has been changed externally.
It searches the entire umap_ to for a matching ilist_ element to erase.
*/
void unit_map::error_recovery_externally_changed_uid(t_ilist::iterator const & lit) const {
std::string name, id ;
size_t uid;
if(lit->unit != NULL){
unit const * u(lit->unit);
name = u->name();
id = u->id();
uid = u->underlying_id();
} else {
name = "unknown";
id = "unknown";
uid = lit->deleted_uid;
}
t_umap::iterator uit(umap_.begin());
for(; uit != umap_.end(); ++uit){
if(uit->second == lit){ break; }
}
std::stringstream oldidss;
if (uit != umap_.end()) {
size_t olduid = uit->first ;
umap_.erase(uit);
oldidss << olduid;
} else {
oldidss << "unknown";
}
ERR_NG << "Extracting " << name << " - " << id
<< " from unit map. Underlying ID changed from "<< oldidss.str() << " to " << uid
<< " between insertion and extraction, requiring an exhaustive search of umap_.\n";
}
size_t unit_map::erase(const map_location &loc) {
self_check();
@ -335,12 +285,14 @@ size_t unit_map::erase(const map_location &loc) {
unit_map::unit_iterator unit_map::find(size_t id) {
self_check();
t_umap::iterator i(umap_.find(id));
if((i != umap_.end()) && i->second->unit==NULL){ i = umap_.end() ;}
return make_unit_iterator<t_umap::iterator>( i ); }
if((i != umap_.end()) && i->second.unit==NULL){ i = umap_.end() ;}
return make_unit_iterator<t_umap::iterator>( i );
}
unit_map::unit_iterator unit_map::find(const map_location &loc) {
self_check();
return make_unit_iterator<t_lmap::iterator>(lmap_.find(loc) ); }
return make_unit_iterator<t_lmap::iterator>(lmap_.find(loc) );
}
unit_map::unit_iterator unit_map::find_leader(int side) {
unit_map::iterator i = begin(), i_end = end();
@ -384,53 +336,40 @@ std::vector<unit_map::const_unit_iterator> unit_map::find_leaders(int side)const
#ifdef DEBUG
bool unit_map::self_check() const {
bool found_the_end(false), good(true);
t_ilist::const_iterator lit(ilist_.begin());
for(; lit != ilist_.end(); ++lit){
if(lit == the_end_){ found_the_end = true; continue; }
if(lit->ref_count < 0){
good=false;
ERR_NG << "unit_map list element ref_count <0 is " << lit->ref_count<<"\n"; }
if(lit->unit != NULL){
lit->unit->id(); //crash if bad pointer
} else {
if(lit->ref_count <= 0){
good=false;
ERR_NG << "unit_map list element ref_count <=0 is " << lit->ref_count<<", when unit deleted.\n"; }
if(lit->deleted_uid <= 0 ){
good=false;
ERR_NG << "unit_map list element deleted_uid <=0 is " << lit->deleted_uid<<"\n"; }
}
}
if(!found_the_end){
good=false;
ERR_NG << "unit_map list the_end_ is missing. " <<"\n";}
bool good(true);
t_umap::const_iterator uit(umap_.begin());
for(; uit != umap_.end(); ++uit){
if(uit->second.ref_count < 0){
good=false;
ERR_NG << "unit_map pod ref_count <0 is " << uit->second.ref_count<<"\n";
}
if(uit->second.unit != NULL){
uit->second.unit->id(); //crash if bad pointer
}
if(uit->first <= 0){
good=false;
ERR_NG << "unit_map umap uid <=0 is " << uit->first <<"\n"; }
if(uit->second == the_end_ ){
good=false;
ERR_NG << "unit_map umap element == the_end_ "<<"\n"; }
if(uit->second->unit == NULL && uit->second->ref_count == 0 ){
good=false;
ERR_NG << "unit_map umap unit==NULL when refcount == 0 uid="<<uit->second->deleted_uid<<"\n";
ERR_NG << "unit_map umap uid <=0 is " << uit->first <<"\n";
}
if(uit->second->unit && uit->second->unit->underlying_id() != uit->first){
if(uit->second.unit == NULL && uit->second.ref_count == 0 ){
good=false;
ERR_NG << "unit_map umap uid("<<uit->first<<") != underlying_id()["<< uit->second->unit->underlying_id()<< "]\n"; }
ERR_NG << "unit_map umap unit==NULL when refcount == 0\n";
}
if(uit->second.unit && uit->second.unit->underlying_id() != uit->first){
good=false;
ERR_NG << "unit_map umap uid("<<uit->first<<") != underlying_id()["<< uit->second.unit->underlying_id()<< "]\n";
}
}
t_lmap::const_iterator locit(lmap_.begin());
for(; locit != lmap_.end(); ++locit){
if(locit->second == the_end_ ){
if(locit->second == umap_.end() ){
good=false;
ERR_NG << "unit_map lmap element == the_end_ "<<"\n"; }
if(locit->first != locit->second->unit->get_location()){
ERR_NG << "unit_map lmap element == umap_.end() "<<"\n";
}
if(locit->first != locit->second->second.unit->get_location()){
good=false;
ERR_NG << "unit_map lmap location != unit->get_location() " <<"\n"; }
ERR_NG << "unit_map lmap location != unit->get_location() " <<"\n";
}
}
//assert(good);
return good;
@ -442,8 +381,8 @@ bool unit_map::has_unit(const unit * const u)
{
assert(u);
BOOST_FOREACH(const unit_pod& item, ilist_) {
if(item.unit == u) {
BOOST_FOREACH(const t_umap::value_type& item, umap_) {
if(item.second.unit == u) {
return true;
}
}

View file

@ -23,6 +23,7 @@
#include <cassert>
#include <list>
#include <map>
#include <boost/unordered_map.hpp>
class unit;
@ -33,12 +34,12 @@ class unit;
* stay valid even if WML modifies or moves units on the fly. They even stay
* valid if a unit is erased from the map and another unit with the same
* underlying id is inserted in the map. In other words it is a doubly indexed ordered map
with persistent iterators (that never invalidate)
* with persistent iterators (that never invalidate)
@note The unit_map is implemented as 2 unordered maps storing iterators from a list of reference counted pointers to units.
The unordered maps provide O(1) find times. The list allows arbitrary ordering of units (not yet implemented).
@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.
The unordered map provides O(1) find times. The ordered map ensures ordering of units by underlying_id.
The reference counting is what guarantees the persistent iterators.
Storing an iterator prevents only that dead unit's list location from being recovered.
Storing an iterator prevents only that dead unit's id-map entry from being recovered.
@note Prefered usages for tight loops follows.
Use the std::pair<iterator, bool> format which checks the preconditions and returns
@ -82,8 +83,8 @@ if(try_add.second){i = try_add.first;}
* iterated upon may be skipped or visited twice.
* @note Iterators prevent ghost units from being collected. So they should
* never be stored into data structures, as it will cause slowdowns!
@note By popular demand iterators are effectively permanent. They are handles and not iterators.
Any access might cause a full lookup. Keeping iterators around holds onto memory.
* @note By popular demand iterators are effectively permanent. They are handles and not iterators.
* Any access might cause a full lookup. Keeping iterators around holds onto memory.
*/
class unit_map {
/// The pointer to the unit and a reference counter to record the number of extant iterators
@ -93,25 +94,19 @@ class unit_map {
unit_pod()
: unit(NULL)
, ref_count()
, deleted_uid(0)
{
}
class unit * unit;
mutable n_ref_counter::t_ref_counter<signed int> ref_count;
unsigned deleted_uid; ///UID of the deleted, moved, added, or otherwise invalidated iterator to facilitate a new lookup.
};
/// A list pointing to unit and their reference counters. Dead units have a unit pointer equal to NULL.
/// The list element is remove iff the reference counter equals zero and there are no more
///Map of underlying_id to unit and a reference counter. Dead units have a unit pointer equal to NULL.
///The map entry is removed iff the reference counter equals zero and there are no more
///iterators pointing to this unit.
typedef std::list<unit_pod> t_ilist;
///Maps of id and location to list iterator.
///@note list iterators never invalidate due to resizing or deletion.
typedef boost::unordered_map<size_t, t_ilist::iterator> t_umap;
typedef boost::unordered_map<map_location, t_ilist::iterator> t_lmap;
typedef std::map<size_t, unit_pod> t_umap;
///Map of location to umap iterator.
typedef boost::unordered_map<map_location, t_umap::iterator> t_lmap;
public:
@ -119,13 +114,13 @@ public:
struct standard_iter_types {
typedef unit_map container_type;
typedef unit_map::t_ilist::iterator iterator_type;
typedef unit_map::t_umap::iterator iterator_type;
typedef unit value_type;
};
struct const_iter_types {
typedef unit_map const container_type;
typedef unit_map::t_ilist::iterator iterator_type;
typedef unit_map::t_umap::iterator iterator_type;
typedef const unit value_type;
};
@ -170,12 +165,6 @@ public:
}
private:
///Construct an iterator from the uid map
iterator_base(t_umap::iterator ui, container_type *m) : i_(ui->second), tank_(m) {
inc();
valid_exit();
}
///Construct an iterator from the location map
iterator_base(t_lmap::iterator ui, container_type *m) : i_(ui->second), tank_(m) {
inc();
@ -186,19 +175,11 @@ public:
pointer operator->() const {
assert(valid());
tank_->self_check();
return i_->unit; }
return i_->second.unit; }
reference operator*() const {
tank_->self_check();
#if 0
// debug!
if(!valid()){
if(!tank_){std::cerr<<"tank is NULL"<<"\n";}
if(i_==the_end()){std::cerr<<"i_ is the end"<<"\n";}
if(i_->unit==NULL){std::cerr<<"i_ unit is NULL with uid="<<i_->deleted_uid<<"\n";}
}
#endif
assert(valid());
return *i_->unit; }
return *i_->second.unit; }
iterator_base& operator++() {
assert( valid_entry() );
@ -206,7 +187,7 @@ public:
iterator_type new_i(i_);
do{
++new_i;
}while ((new_i->unit == NULL) && (new_i != the_end() )) ;
}while ((new_i->second.unit == NULL) && (new_i != the_map().end() )) ;
dec();
i_ = new_i;
inc();
@ -221,13 +202,13 @@ public:
}
iterator_base& operator--() {
assert( tank_ && i_ != the_list().begin() );
assert( tank_ && i_ != the_map().begin() );
tank_->self_check();
iterator_type begin(the_list().begin());
iterator_type begin(the_map().begin());
dec();
do {
--i_ ;
}while(i_ != begin && (i_->unit == NULL));
}while(i_ != begin && (i_->second.unit == NULL));
inc();
valid_exit();
@ -242,64 +223,44 @@ public:
bool valid() const {
if(valid_for_dereference()) {
if(i_->unit == NULL){
recover_unit_iterator(); }
return i_->unit != NULL;
return i_->second.unit != NULL;
}
return false; }
return false;
}
bool operator==(const iterator_base &rhs) const { return (tank_ == rhs.tank_) && ( i_ == rhs.i_ ); }
bool operator!=(const iterator_base &rhs) const { return !operator==(rhs); }
// container_type* get_map() const { return tank_; }
template<typename Y> friend struct iterator_base;
private:
bool valid_for_dereference() const { return (tank_ != NULL) && (i_ != the_end()); }
bool valid_entry() const { return ((tank_ != NULL) && (i_ != the_end())) ; }
bool valid_for_dereference() const { return (tank_ != NULL) && (i_ != the_map().end()); }
bool valid_entry() const { return ((tank_ != NULL) && (i_ != the_map().end())) ; }
void valid_exit() const {
if(tank_ != NULL) {
assert(!the_list().empty());
assert(i_ != the_list().end());
if(i_ != the_end()){
assert(i_->ref_count > 0);
} else {
assert(i_->ref_count == 1);
}
}}
bool valid_ref_count() const { return (tank_ != NULL) && (i_ != the_end()) ; }
if((tank_ != NULL) && i_ != the_map().end()){
assert(i_->second.ref_count > 0);
}
}
bool valid_ref_count() const { return (tank_ != NULL) && (i_ != the_map().end()) ; }
///Increment the reference counter
void inc() { if(valid_ref_count()) { ++(i_->ref_count); } }
void inc() { if(valid_ref_count()) { ++(i_->second.ref_count); } }
///Decrement the reference counter
///Delete the list element and the dangling umap reference if the unit is gone and the reference counter is zero
///@note this deletion will advance i_ to the next list element.
///Delete the umap entry if the unit is gone and the reference counter is zero
///@note this deletion will advance i_ to the next umap entry.
void dec() {
if( valid_ref_count() ){
assert(i_->ref_count != 0);
if( (--(i_->ref_count) == 0) && (i_->unit == NULL) ){
if(tank_->umap_.erase(i_->deleted_uid) != 1){
tank_->error_recovery_externally_changed_uid(i_); }
i_ = the_list().erase(i_);
} } }
unit_map::t_ilist & the_list() const { return tank_->ilist_; }
///Returns the sentinel at the end of the list.
///This provides a stable unit_iterator for hoisting out of loops
iterator_type the_end() const { return tank_->the_end_; }
/**
* Attempt to find a deleted unit in the unit_map, by looking up the stored UID.
* @pre deleted_uid != 0
*/
void recover_unit_iterator() const {
assert(i_->deleted_uid != 0);
iterator_base new_this( tank_->find( i_->deleted_uid ));
const_cast<iterator_base *>(this)->operator=( new_this );
assert(i_->second.ref_count != 0);
if( (--(i_->second.ref_count) == 0) && (i_->second.unit == NULL) ){
iterator_type old = i_++;
tank_->umap_.erase(old);
}
}
}
unit_map::t_umap & the_map() const { return tank_->umap_; }
friend class unit_map;
iterator_type i_; ///local iterator
@ -342,8 +303,8 @@ public:
unit_iterator begin() { return make_unit_iterator( begin_core() ); }
const_unit_iterator begin() const { return make_const_unit_iterator( begin_core() ); }
unit_iterator end() { return make_unit_iterator(the_end_); }
const_unit_iterator end() const { return make_const_unit_iterator(the_end_); }
unit_iterator end() { return make_unit_iterator(umap_.end()); }
const_unit_iterator end() const { return make_const_unit_iterator(umap_.end()); }
size_t size() const { return lmap_.size(); }
size_t num_iters() const ;
@ -429,62 +390,40 @@ public:
bool has_unit(const unit * const u);
private:
///Creates and inserts a unit_pod called the_end_ as a sentinel in the ilist
void init_end(){
assert(ilist_.empty());
unit_pod upod;
upod.unit = NULL;
upod.deleted_uid = 0;
++upod.ref_count; //dummy count
ilist_.push_front(upod);
the_end_ = ilist_.begin();
};
t_umap::iterator begin_core() const ;
t_ilist::iterator begin_core() const ;
bool is_valid(const t_ilist::const_iterator &i) const {
return i != the_end_ && is_found(i) && (i->unit != NULL); }
bool is_valid(const t_umap::const_iterator &i) const {
return is_found(i) && (i->second->unit != NULL); }
return is_found(i) && (i->second.unit != NULL);
}
bool is_valid(const t_lmap::const_iterator &i) const {
return is_found(i) && (i->second->unit != NULL); }
return is_found(i) && (i->second->second.unit != NULL);
}
bool is_found(const t_ilist::const_iterator &i) const { return i != ilist_.end(); }
bool is_found(const t_umap::const_iterator &i) const { return i != umap_.end() ; }
bool is_found(const t_umap::const_iterator &i) const { return i != umap_.end(); }
bool is_found(const t_lmap::const_iterator &i) const { return i != lmap_.end(); }
template <typename X>
unit_map::unit_iterator make_unit_iterator(X const & i) {
if (!is_found( i )) { return unit_iterator(the_end_, this); }
return unit_iterator(i , this); }
if (!is_found( i )) { return unit_iterator(umap_.end(), this); }
return unit_iterator(i , this);
}
template <typename X>
unit_map::const_unit_iterator make_const_unit_iterator(X const & i) const {
if (!is_found( i )) { return const_unit_iterator(the_end_, this); }
return const_unit_iterator(i , this); }
///Finds and deletes the umap_ item associated with @a lit when the underlying_id()
///has been changed externally after insertion and before extraction
void error_recovery_externally_changed_uid(t_ilist::iterator const & lit) const;
if (!is_found( i )) { return const_unit_iterator(umap_.end(), this); }
return const_unit_iterator(i , this);
}
/**
* underlying_id -> ilist::iterator. This requires that underlying_id be
* underlying_id -> unit_pod. This requires that underlying_id be
* unique (which is enforced in unit_map::insert).
*/
mutable t_umap umap_;
/**
* location -> ilist::iterator.
* location -> umap::iterator.
*/
t_lmap lmap_;
/**
* List of unit pointers and reference counts for the iterators
*/
mutable t_ilist ilist_;
/// The last list item, a sentinel that allows BOOST::foreach to hoist end()
t_ilist::iterator the_end_;
};
template <typename T>