| 501 | } |
| 502 | |
| 503 | static void manageJobStartedEvent(color_ostream& out) { |
| 504 | if (!df::global::world) |
| 505 | return; |
| 506 | |
| 507 | // iterate event handler callbacks |
| 508 | multimap<Plugin*, EventHandler> copy(handlers[EventType::JOB_STARTED].begin(), handlers[EventType::JOB_STARTED].end()); |
| 509 | |
| 510 | std::vector<int32_t> newStartedJobs; |
| 511 | newStartedJobs.reserve(startedJobs.size()); |
| 512 | |
| 513 | for (const auto jobPtr : df::global::world->jobs.list) { |
| 514 | // posting_index of -1 implies a worker has been assigned to a new job. |
| 515 | if (jobPtr->posting_index == -1) { |
| 516 | auto jobId = jobPtr->id; |
| 517 | newStartedJobs.push_back(jobId); |
| 518 | /* |
| 519 | * The startedJobs set peaks at the number of work-eligible citizens. |
| 520 | * This set is small enough to fit comfortably in the CPU caches, |
| 521 | * e.g., 200 workers * 4 bytes (jobId) = 800 bytes, |
| 522 | * ensuring better memory locality and thus more efficiency than a hashmap |
| 523 | * where memory access tends to be all over the place. |
| 524 | */ |
| 525 | if (!std::binary_search(startedJobs.begin(), startedJobs.end(), jobId)) { |
| 526 | for (auto &[_,handle] : copy) { |
| 527 | DEBUG(log,out).print("calling handler for job started event\n"); |
| 528 | run_handler(out, EventType::JOB_STARTED, handle, jobPtr); |
| 529 | } |
| 530 | } |
| 531 | } |
| 532 | } |
| 533 | startedJobs = std::move(newStartedJobs); |
| 534 | } |
| 535 | |
| 536 | /* |
| 537 | TODO: consider checking item creation / experience gain just in case |