/** Inserts the unit pointed to by @a p into the unit_map. It needs to succeed on the insertion to the umap and to the lmap otherwise all operations are reverted. 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 to uids previously used. */ std::pair<unit_map::unit_iterator, bool> unit_map::insert(unit_ptr p) { self_check(); assert(p); size_t unit_id = p->underlying_id(); const map_location &loc = p->get_location(); 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(umap_.end()), false); } unit_pod upod; upod.unit = p ; 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, upod )); if (! uinsert.second) { //If the pod is empty reinsert the unit in the same list element if (!uinsert.first->second.unit) { unit_pod &opod = uinsert.first->second; opod.unit = p ; assert(opod.ref_count != 0); } else { unit_ptr q = uinsert.first->second.unit; ERR_NG << "Trying to add " << p->name() << " - " << p->id() << " - " << p->underlying_id() << " (" << loc << ") over " << q->name() << " - " << q->id() << " - " << q->underlying_id() << " (" << q->get_location() << ")."; p->clone(false); ERR_NG << "The new unit was assigned underlying_id=" << p->underlying_id() << " to prevent duplicate id conflicts.\n"; uinsert = umap_.insert(std::make_pair(p->underlying_id(), upod )); int guard(0); while (!uinsert.second && (++guard < 1e6) ) { if(guard % 10 == 9){ ERR_NG << "\n\nPlease Report this error to https://gna.org/bugs/index.php?18591 " "\nIn addition to the standard details of operating system and wesnoth version " "and how it happened, please answer the following questions " "\n 1. Were you playing multi-player?" "\n 2. Did you start/restart/reload the game/scenario?" "\nThank you for your help in fixing this bug.\n"; } p->clone(false); uinsert = umap_.insert(std::make_pair(p->underlying_id(), upod )); } if (!uinsert.second) { throw game::error("One million collisions in unit_map"); } } } 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(upod.ref_count == 0) { //Undo a virgin insertion umap_.erase(uinsert.first); } else { //undo a reinsertion uinsert.first->second.unit.reset(); } DBG_NG << "Trying to add " << p->name() << " - " << p->id() << " at location ("<<loc <<"); Occupied by " <<(linsert.first->second->second).unit->name()<< " - " << linsert.first->second->second.unit->id() <<"\n"; return std::make_pair(make_unit_iterator(umap_.end()), false); } self_check(); return std::make_pair( make_unit_iterator( uinsert.first ), true); }
static bool find_if_matches_uid_helper(const unit_ptr & ptr, size_t uid) { return ptr->underlying_id() == uid; }