Merge branch 'unit_map_fixes'
This commit is contained in:
commit
ffc68170fe
2 changed files with 136 additions and 258 deletions
217
src/unit_map.cpp
217
src/unit_map.cpp
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
177
src/unit_map.hpp
177
src/unit_map.hpp
|
@ -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>
|
||||
|
|
Loading…
Add table
Reference in a new issue