/** * osgEarth * Copyright Pelican Mapping * MIT License */ #pragma once #include #include #include #include #include namespace osgEarth { /** * Easy way to add a thread-safe callback to a class. * * Developer defines a callback, usually as a class member: * Callback onClick; * * User adds a callback: * instance->onClick([](int a) { ... }); * * Class fires a callback: * onClick(a); */ template class Callback { private: using Entry = typename std::pair>; mutable int uidgen = 0; mutable std::vector entries; mutable std::mutex mutex; mutable std::atomic_bool firing = { false }; public: //! Adds a callback function int operator()(std::function&& func) const { std::lock_guard lock(mutex); auto uid = ++uidgen; entries.emplace_back(uid, func); return uid; } //! Removed a callback function with the UID returned from () void remove(int uid) const { std::lock_guard lock(mutex); for (auto iter = entries.begin(); iter != entries.end(); ++iter) { if (iter->first == uid) { entries.erase(iter); break; } } } //! Executes all callback functions with the provided args template void fire(Args&&... args) const { if (firing.exchange(true) == false) { std::lock_guard lock(mutex); for (auto& e : entries) e.second(args...); firing = false; } } }; }