EventManager: be smarter about removing things while iterating.

develop
expwnent 2013-10-20 23:16:21 -04:00
parent c409289ee4
commit 4dbcee9560
1 changed files with 27 additions and 41 deletions

@ -66,20 +66,15 @@ int32_t DFHack::EventManager::registerTick(EventHandler handler, int32_t when, P
} }
static void removeFromTickQueue(EventHandler getRidOf) { static void removeFromTickQueue(EventHandler getRidOf) {
//shenanigans to avoid concurrent modification for ( auto j = tickQueue.find(getRidOf.freq); j != tickQueue.end(); ) {
bool didSomething; if ( (*j).first > getRidOf.freq )
do {
didSomething = false;
for ( auto j = tickQueue.find(getRidOf.freq); j != tickQueue.end(); j++ ) {
if ( (*j).first > getRidOf.freq )
break;
if ( (*j).second != getRidOf )
continue;
tickQueue.erase(j);
didSomething = true;
break; break;
if ( (*j).second != getRidOf ) {
j++;
continue;
} }
} while (didSomething); j = tickQueue.erase(j);
}
} }
void DFHack::EventManager::unregister(EventType::EventType e, EventHandler handler, Plugin* plugin) { void DFHack::EventManager::unregister(EventType::EventType e, EventHandler handler, Plugin* plugin) {
@ -91,10 +86,9 @@ void DFHack::EventManager::unregister(EventType::EventType e, EventHandler handl
i++; i++;
continue; continue;
} }
handlers[e].erase(i); i = handlers[e].erase(i);
if ( e == EventType::TICK ) if ( e == EventType::TICK )
removeFromTickQueue(handler); removeFromTickQueue(handler);
i = handlers[e].find(plugin); //loop in case the same handler is in there multiple times
} }
} }
@ -289,14 +283,15 @@ static void manageTickEvent(color_ostream& out) {
if ( toRemove.empty() ) if ( toRemove.empty() )
return; return;
for ( auto a = handlers[EventType::TICK].begin(); a != handlers[EventType::TICK].end(); ) { for ( auto a = handlers[EventType::TICK].begin(); a != handlers[EventType::TICK].end(); ) {
//handlerToPlugin[(*a).second] = (*a).first; EventHandler handle = (*a).second;
if ( toRemove.find((*a).second) == toRemove.end() ) { if ( toRemove.find(handle) == toRemove.end() ) {
a++; a++;
continue; continue;
} }
Plugin* plug = (*a).first; a = handlers[EventType::TICK].erase(a);
handlers[EventType::TICK].erase(a); toRemove.erase(handle);
a = handlers[EventType::TICK].find(plug); if ( toRemove.empty() )
break;
} }
} }
@ -537,48 +532,39 @@ static void manageBuildingEvent(color_ostream& out) {
nextBuilding = *df::global::building_next_id; nextBuilding = *df::global::building_next_id;
//now alert people about destroyed buildings //now alert people about destroyed buildings
unordered_set<int32_t> toDelete; for ( auto a = buildings.begin(); a != buildings.end(); ) {
for ( auto a = buildings.begin(); a != buildings.end(); a++ ) {
int32_t id = *a; int32_t id = *a;
int32_t index = df::building::binsearch_index(df::global::world->buildings.all,id); int32_t index = df::building::binsearch_index(df::global::world->buildings.all,id);
if ( index != -1 ) if ( index != -1 ) {
a++;
continue; continue;
toDelete.insert(id); }
for ( auto b = copy.begin(); b != copy.end(); b++ ) { for ( auto b = copy.begin(); b != copy.end(); b++ ) {
EventHandler bob = (*b).second; EventHandler bob = (*b).second;
bob.eventHandler(out, (void*)id); bob.eventHandler(out, (void*)id);
} }
a = buildings.erase(a);
} }
for ( auto a = toDelete.begin(); a != toDelete.end(); a++ ) {
int32_t id = *a;
buildings.erase(id);
}
//out.print("Sent building event.\n %d", __LINE__);
} }
static void manageConstructionEvent(color_ostream& out) { static void manageConstructionEvent(color_ostream& out) {
//unordered_set<df::construction*> constructionsNow(df::global::world->constructions.begin(), df::global::world->constructions.end()); //unordered_set<df::construction*> constructionsNow(df::global::world->constructions.begin(), df::global::world->constructions.end());
multimap<Plugin*,EventHandler> copy(handlers[EventType::CONSTRUCTION].begin(), handlers[EventType::CONSTRUCTION].end()); multimap<Plugin*,EventHandler> copy(handlers[EventType::CONSTRUCTION].begin(), handlers[EventType::CONSTRUCTION].end());
unordered_set<df::coord> toDelete; for ( auto a = constructions.begin(); a != constructions.end(); ) {
for ( auto a = constructions.begin(); a != constructions.end(); a++ ) {
df::construction& construction = (*a).second; df::construction& construction = (*a).second;
if ( df::construction::find(construction.pos) != NULL ) if ( df::construction::find(construction.pos) != NULL ) {
a++;
continue; continue;
}
//construction removed //construction removed
toDelete.insert((*a).first);
//out.print("Removed construction (%d,%d,%d)\n", construction.pos.x,construction.pos.y,construction.pos.z); //out.print("Removed construction (%d,%d,%d)\n", construction.pos.x,construction.pos.y,construction.pos.z);
for ( auto b = copy.begin(); b != copy.end(); b++ ) { for ( auto b = copy.begin(); b != copy.end(); b++ ) {
EventHandler handle = (*b).second; EventHandler handle = (*b).second;
handle.eventHandler(out, (void*)&construction); handle.eventHandler(out, (void*)&construction);
} }
} a = constructions.erase(a);
for ( auto a = toDelete.begin(); a != toDelete.end(); a++ ) {
constructions.erase(*a);
} }
//for ( auto a = constructionsNow.begin(); a != constructionsNow.end(); a++ ) { //for ( auto a = constructionsNow.begin(); a != constructionsNow.end(); a++ ) {