Skip to content

Instantly share code, notes, and snippets.

@theanalyst
Created April 19, 2022 20:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save theanalyst/e94fa8e3d0196bb7110e3974aacf4b79 to your computer and use it in GitHub Desktop.
Save theanalyst/e94fa8e3d0196bb7110e3974aacf4b79 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <functional>
#include <string_view>
#include <mutex>
#include <map>
#include <thread>
#include <chrono>
#include <future>
template <typename ...Args>
class ObserverMgr
{
public:
using observer_tag_t = uint64_t;
using callback_fn_t = std::function<void(Args...)>;
observer_tag_t addObserver(callback_fn_t&& cb)
{
std::lock_guard lg{observer_mtx};
callbacks.emplace(++index, std::forward<callback_fn_t>(cb));
std::cout << "Added Observer: " << index << "\n";
return index;
}
void removeObserver(observer_tag_t i)
{
std::lock_guard lg{observer_mtx};
std::cout << "Removed Observer: " << index << "\n";
callbacks.erase(i);
}
void handleChange(Args&&... args)
{
{
std::lock_guard lg{observer_mtx};
for (auto it : callbacks) {
callback_futures.emplace_back(std::async(std::launch::async,
it.second,
std::forward<Args>(args)...));;
}
}
callback_futures.erase(std::remove_if(callback_futures.begin(),
callback_futures.end(),
[](std::future<void>& fut) {
return (fut.wait_for(std::chrono::seconds(0)) == std::future_status::ready);
}),
callback_futures.end());
}
private:
std::mutex observer_mtx;
observer_tag_t index = 0;
std::map<observer_tag_t, callback_fn_t> callbacks;
std::vector<std::future<void>> callback_futures;
};
enum class Status {
SCHEDULED,
SUCCESS,
FAILURE
};
int main(int argc, char *argv[])
{
ObserverMgr<Status,std::string_view> mgr;
auto tag = mgr.addObserver([](Status s, std::string_view str) {
switch (s) {
case Status::SCHEDULED:
std::cout << "Scheduled tag: " << str << "\n";
break;
case Status::SUCCESS:
std::cout << "Success! tag: " << str << "\n";
break;
case Status::FAILURE: [[fallthrough]];
default:
std::cerr << "Failed scheduling tag: " << str << "\n";
}
});
auto tag2 = mgr.addObserver([](Status s, std::string_view str) {
using namespace std::chrono_literals;
std::this_thread::sleep_for(20s);
std::cout << "Tracked tag: " << str << "\n";
});
mgr.handleChange(Status::SCHEDULED, "item1");
std::cout << "Doing Something else in the main thread!" << std::endl;
mgr.handleChange(Status::FAILURE, "item0");
mgr.removeObserver(tag2);
mgr.handleChange(Status::SUCCESS, "item3");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment