00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "unit_id.hpp"
00020 #include "foreach.hpp"
00021 #include "log.hpp"
00022 #include "unit.hpp"
00023
00024 #include <functional>
00025 #include "unit_map.hpp"
00026
00027 static lg::log_domain log_engine("engine");
00028 #define ERR_NG LOG_STREAM(err, log_engine)
00029 #define WRN_NG LOG_STREAM(warn, log_engine)
00030 #define LOG_NG LOG_STREAM(info, log_engine)
00031 #define DBG_NG LOG_STREAM(debug, log_engine)
00032
00033 unit_map::unit_map()
00034 : umap_()
00035 , lmap_()
00036 , ilist_()
00037 , the_end_()
00038 {
00039 init_end();
00040 }
00041
00042 unit_map::unit_map(const unit_map& that)
00043 : umap_()
00044 , lmap_()
00045 , ilist_()
00046 , the_end_()
00047 {
00048 init_end();
00049 for (const_unit_iterator i = that.begin(); i != that.end(); ++i) {
00050 add(i->get_location(), *i);
00051 }
00052 }
00053
00054 unit_map &unit_map::operator=(const unit_map &that) {
00055 unit_map temp(that);
00056 swap(temp);
00057 return *this;
00058 }
00059
00060 void unit_map::swap(unit_map &o) {
00061 assert(num_iters()==0 && o.num_iters() == 0);
00062
00063 std::swap(umap_, o.umap_);
00064 std::swap(lmap_, o.lmap_);
00065 std::swap(ilist_, o.ilist_);
00066 std::swap(the_end_, o.the_end_);
00067 }
00068
00069 unit_map::~unit_map() {
00070 clear(true);
00071 }
00072
00073 unit_map::t_ilist::iterator unit_map::begin_core() const {
00074 self_check();
00075 t_ilist::iterator i = ilist_.begin();
00076 while (i != the_end_ && (i->unit == NULL)) { ++i; }
00077 return i;
00078 }
00079
00080 std::pair<unit_map::unit_iterator, bool> unit_map::add(const map_location &l, const unit &u) {
00081 self_check();
00082 unit *p = new unit(u);
00083 p->set_location(l);
00084 std::pair<unit_map::unit_iterator, bool> res( insert(p) );
00085 if(res.second == false) { delete p; }
00086 return res;
00087 }
00088
00089 std::pair<unit_map::unit_iterator, bool> unit_map::move(const map_location &src, const map_location &dst) {
00090 self_check();
00091 DBG_NG << "Unit map: Moving unit from " << src << " to " << dst << "\n";
00092
00093
00094 t_lmap::iterator i = lmap_.find(src);
00095 if(i == lmap_.end()) { return std::make_pair(make_unit_iterator(the_end_), false);}
00096
00097 t_ilist::iterator lit(i->second);
00098
00099 if(src == dst){ return std::make_pair(make_unit_iterator(lit),true);}
00100
00101
00102 unit *p = lit->unit;
00103 if(p == NULL){ return std::make_pair(make_unit_iterator(lit), false);}
00104
00105 p->set_location(dst);
00106
00107
00108 lmap_.erase(i);
00109
00110 std::pair<t_lmap::iterator,bool> res = lmap_.insert(std::make_pair(dst, lit));
00111
00112
00113 if(res.second == false) {
00114 p->set_location(src);
00115 lmap_.insert(std::make_pair(src, lit));
00116 return std::make_pair(make_unit_iterator(lit), false);
00117 }
00118
00119 self_check();
00120
00121 return std::make_pair(make_unit_iterator(lit), true);
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137 std::pair<unit_map::unit_iterator, bool> unit_map::insert(unit *p) {
00138 self_check();
00139 assert(p);
00140
00141 size_t unit_id = p->underlying_id();
00142 const map_location &loc = p->get_location();
00143
00144 if (!loc.valid()) {
00145 ERR_NG << "Trying to add " << p->name()
00146 << " - " << p->id() << " at an invalid location; Discarding.\n";
00147 return std::make_pair(make_unit_iterator(the_end_), false);
00148 }
00149
00150 unit_pod upod;
00151 upod.unit = p;
00152 upod.deleted_uid = unit_id;
00153 ilist_.push_front(upod);
00154 t_ilist::iterator lit(ilist_.begin());
00155
00156 DBG_NG << "Adding unit " << p->underlying_id() << " - " << p->id()
00157 << " to location: (" << loc << ")\n";
00158
00159 std::pair<t_umap::iterator, bool> uinsert = umap_.insert(std::make_pair(unit_id, lit ));
00160
00161 if (! uinsert.second) {
00162
00163 if ( uinsert.first->second->unit == NULL) {
00164 ilist_.pop_front();
00165 lit = uinsert.first->second;
00166 lit->unit = p;
00167 assert(lit->ref_count != 0);
00168 } else {
00169 unit *q = uinsert.first->second->unit;
00170 ERR_NG << "Trying to add " << p->name()
00171 << " - " << p->id() << " - " << p->underlying_id()
00172 << " (" << loc << ") over " << q->name()
00173 << " - " << q->id() << " - " << q->underlying_id()
00174 << " (" << q->get_location()
00175 << "). The new unit will be assigned underlying_id="
00176 << (1 + n_unit::id_manager::instance().get_save_id())
00177 << " to prevent duplicate id conflicts.\n";
00178
00179 p->clone(false);
00180 uinsert = umap_.insert(std::make_pair(p->underlying_id(), lit ));
00181 int guard(0);
00182 while (!uinsert.second && (++guard < 1e6) ) {
00183 if(guard % 10 == 9){
00184 ERR_NG << "\n\nPlease Report this error to https://gna.org/bugs/index.php?18591 "
00185 "\nIn addition to the standard details of operating system and wesnoth version "
00186 "and how it happened, please answer the following questions "
00187 "\n 1. Were you playing mutli-player?"
00188 "\n 2. Did you start/restart/reload the game/scenario?"
00189 "\nThank you for your help in fixing this bug.\n";
00190 }
00191 p->clone(false);
00192 uinsert = umap_.insert(std::make_pair(p->underlying_id(), lit )); }
00193 if (!uinsert.second) {
00194 throw "One million collisions in unit_map"; }
00195 }
00196 }
00197
00198 std::pair<t_lmap::iterator,bool> linsert = lmap_.insert(std::make_pair(loc, lit ));
00199
00200
00201 if(! linsert.second) {
00202 if(lit->ref_count == 0) {
00203
00204 ilist_.pop_front();
00205
00206 umap_.erase(uinsert.first);
00207 } else {
00208
00209 uinsert.first->second->unit = NULL;
00210 }
00211 DBG_NG << "Trying to add " << p->name()
00212 << " - " << p->id() << " at location ("<<loc <<"); Occupied by "
00213 <<(linsert.first->second)->unit->name()<< " - " << linsert.first->second->unit->id() <<"\n";
00214
00215 return std::make_pair(make_unit_iterator(the_end_), false);
00216 }
00217
00218 self_check();
00219 return std::make_pair( make_unit_iterator( lit ), true);
00220 }
00221
00222 std::pair<unit_map::unit_iterator, bool> unit_map::replace(const map_location &l, const unit &u) {
00223 self_check();
00224
00225
00226
00227
00228 map_location loc = l;
00229 erase(loc);
00230 return add(loc, u);
00231 }
00232
00233 size_t unit_map::num_iters() const {
00234
00235 size_t num_iters(0);
00236 t_ilist::const_iterator ii(ilist_.begin());
00237 for( ; ii != the_end_ ; ++ii){
00238 if(ii->ref_count < 0) {
00239
00240 bool a_reference_counter_overflowed(false);
00241 assert(a_reference_counter_overflowed); }
00242 num_iters += ii->ref_count; }
00243
00244 return num_iters;
00245 }
00246
00247 void unit_map::clear(bool force) {
00248 assert(force || (num_iters() == 0));
00249
00250 for (t_ilist::iterator i = ilist_.begin(); i != the_end_; ++i) {
00251 if (is_valid(i)) {
00252 DBG_NG << "Delete unit " << i->unit->underlying_id() << "\n";
00253 delete i->unit;
00254 }
00255 }
00256
00257 lmap_.clear();
00258 umap_.clear();
00259 ilist_.clear();
00260 }
00261
00262 unit *unit_map::extract(const map_location &loc) {
00263 self_check();
00264 t_lmap::iterator i = lmap_.find(loc);
00265 if (i == lmap_.end()) { return NULL; }
00266
00267 t_ilist::iterator lit(i->second);
00268
00269 unit *u = lit->unit;
00270 size_t uid( u->underlying_id() );
00271
00272 DBG_NG << "Extract unit " << uid << " - " << u->id()
00273 << " from location: (" << loc << ")\n";
00274
00275 if(lit->ref_count == 0){
00276 assert(lit != the_end_);
00277 if(umap_.erase(uid) != 1){
00278 error_recovery_externally_changed_uid(lit); }
00279 ilist_.erase( lit );
00280 } else {
00281
00282 lit->unit = NULL;
00283 lit->deleted_uid = uid;
00284 assert( uid != 0);
00285 }
00286
00287 lmap_.erase(i);
00288 self_check();
00289
00290 return u;
00291 }
00292
00293
00294
00295
00296
00297 void unit_map::error_recovery_externally_changed_uid(t_ilist::iterator const & lit) const {
00298 std::string name, id ;
00299 size_t uid;
00300 if(lit->unit != NULL){
00301 unit const * u(lit->unit);
00302 name = u->name();
00303 id = u->id();
00304 uid = u->underlying_id();
00305 } else {
00306 name = "unknown";
00307 id = "unknown";
00308 uid = lit->deleted_uid;
00309 }
00310 t_umap::iterator uit(umap_.begin());
00311 for(; uit != umap_.end(); ++uit){
00312 if(uit->second == lit){ break; }
00313 }
00314 std::stringstream oldidss;
00315 if (uit != umap_.end()) {
00316 size_t olduid = uit->first ;
00317 umap_.erase(uit);
00318 oldidss << olduid;
00319 } else {
00320 oldidss << "unknown";
00321 }
00322
00323 ERR_NG << "Extracting " << name << " - " << id
00324 << " from unit map. Underlying ID changed from "<< oldidss.str() << " to " << uid
00325 << " between insertion and extraction, requiring an exhaustive search of umap_.\n";
00326 }
00327
00328
00329 size_t unit_map::erase(const map_location &loc) {
00330 self_check();
00331 unit *u = extract(loc);
00332 if (!u) return 0;
00333 delete u;
00334 return 1;
00335 }
00336
00337 unit_map::unit_iterator unit_map::find(size_t id) {
00338 self_check();
00339 t_umap::iterator i(umap_.find(id));
00340 if((i != umap_.end()) && i->second->unit==NULL){ i = umap_.end() ;}
00341 return make_unit_iterator<t_umap::iterator>( i ); }
00342
00343 unit_map::unit_iterator unit_map::find(const map_location &loc) {
00344 self_check();
00345 return make_unit_iterator<t_lmap::iterator>(lmap_.find(loc) ); }
00346
00347 unit_map::unit_iterator unit_map::find_leader(int side) {
00348 unit_map::iterator i = begin(), i_end = end();
00349 for (; i != i_end; ++i) {
00350 if (static_cast<int>(i->side()) == side && i->can_recruit())
00351 return i;
00352 }
00353 return i_end;
00354 }
00355
00356 unit_map::unit_iterator unit_map::find_first_leader(int side) {
00357 unit_map::iterator i = begin(), i_end = end();
00358 unit_map::iterator first_leader = end();
00359
00360 for (; i != i_end; ++i) {
00361 if (static_cast<int>(i->side()) == side && i->can_recruit()){
00362 if ((first_leader == end()) || (i->underlying_id() < first_leader->underlying_id()) )
00363 first_leader = i;
00364 }
00365 }
00366 return first_leader;
00367 }
00368
00369 std::vector<unit_map::unit_iterator> unit_map::find_leaders(int side) {
00370 unit_map::unit_iterator i = begin(), i_end = end();
00371 std::vector<unit_map::unit_iterator> leaders;
00372 for(;i != i_end; ++i){
00373 if(static_cast<int>(i->side()) == side && i->can_recruit()){
00374 leaders.push_back(i);
00375 }
00376 }
00377 return leaders;
00378 }
00379 std::vector<unit_map::const_unit_iterator> unit_map::find_leaders(int side)const{
00380 const std::vector<unit_map::unit_iterator> &leaders = const_cast<unit_map*>(this)->find_leaders(side);
00381 std::vector<unit_map::const_unit_iterator> const_leaders;
00382 std::copy(leaders.begin(), leaders.end(), std::back_inserter(const_leaders));
00383 return const_leaders;
00384 }
00385
00386 #ifdef DEBUG
00387
00388 bool unit_map::self_check() const {
00389 bool found_the_end(false), good(true);
00390 t_ilist::const_iterator lit(ilist_.begin());
00391 for(; lit != ilist_.end(); ++lit){
00392 if(lit == the_end_){ found_the_end = true; continue; }
00393 if(lit->ref_count < 0){
00394 good=false;
00395 ERR_NG << "unit_map list element ref_count <0 is " << lit->ref_count<<"\n"; }
00396 if(lit->unit != NULL){
00397 lit->unit->id();
00398 } else {
00399 if(lit->ref_count <= 0){
00400 good=false;
00401 ERR_NG << "unit_map list element ref_count <=0 is " << lit->ref_count<<", when unit deleted.\n"; }
00402 if(lit->deleted_uid <= 0 ){
00403 good=false;
00404 ERR_NG << "unit_map list element deleted_uid <=0 is " << lit->deleted_uid<<"\n"; }
00405 }
00406 }
00407
00408 if(!found_the_end){
00409 good=false;
00410 ERR_NG << "unit_map list the_end_ is missing. " <<"\n";}
00411
00412 t_umap::const_iterator uit(umap_.begin());
00413 for(; uit != umap_.end(); ++uit){
00414 if(uit->first <= 0){
00415 good=false;
00416 ERR_NG << "unit_map umap uid <=0 is " << uit->first <<"\n"; }
00417 if(uit->second == the_end_ ){
00418 good=false;
00419 ERR_NG << "unit_map umap element == the_end_ "<<"\n"; }
00420 if(uit->second->unit == NULL && uit->second->ref_count == 0 ){
00421 good=false;
00422 ERR_NG << "unit_map umap unit==NULL when refcount == 0 uid="<<uit->second->deleted_uid<<"\n";
00423 }
00424 if(uit->second->unit && uit->second->unit->underlying_id() != uit->first){
00425 good=false;
00426 ERR_NG << "unit_map umap uid("<<uit->first<<") != underlying_id()["<< uit->second->unit->underlying_id()<< "]\n"; }
00427 }
00428 t_lmap::const_iterator locit(lmap_.begin());
00429 for(; locit != lmap_.end(); ++locit){
00430 if(locit->second == the_end_ ){
00431 good=false;
00432 ERR_NG << "unit_map lmap element == the_end_ "<<"\n"; }
00433 if(locit->first != locit->second->unit->get_location()){
00434 good=false;
00435 ERR_NG << "unit_map lmap location != unit->get_location() " <<"\n"; }
00436 }
00437
00438 return good;
00439 }
00440
00441 #endif
00442
00443 bool unit_map::has_unit(const unit * const u)
00444 {
00445 assert(u);
00446
00447 foreach(const unit_pod& item, ilist_) {
00448 if(item.unit == u) {
00449 return true;
00450 }
00451 }
00452 return false;
00453 }