Debounce.cc 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. #include "Debounce.hh"
  2. #ifdef __wasm32__
  3. extern "C" void on_timeout(void *ctx) {
  4. Debounce *debounce = (Debounce *)ctx;
  5. debounce->notify();
  6. }
  7. #endif
  8. std::shared_ptr<Debounce> Debounce::getShared() {
  9. static std::weak_ptr<Debounce> sharedInstance;
  10. std::shared_ptr<Debounce> shared = sharedInstance.lock();
  11. if (!shared) {
  12. shared = std::make_shared<Debounce>();
  13. sharedInstance = shared;
  14. }
  15. return shared;
  16. }
  17. Debounce::Debounce() {
  18. mRunning = true;
  19. #ifndef __wasm32__
  20. mThread = std::thread([this] () {
  21. loop();
  22. });
  23. #endif
  24. }
  25. Debounce::~Debounce() {
  26. mRunning = false;
  27. #ifndef __wasm32__
  28. mWaitSignal.notify();
  29. mThread.join();
  30. #endif
  31. }
  32. void Debounce::add(void *key, std::function<void()> cb) {
  33. std::unique_lock<std::mutex> lock(mMutex);
  34. mCallbacks.emplace(key, cb);
  35. }
  36. void Debounce::remove(void *key) {
  37. std::unique_lock<std::mutex> lock(mMutex);
  38. mCallbacks.erase(key);
  39. }
  40. void Debounce::trigger() {
  41. std::unique_lock<std::mutex> lock(mMutex);
  42. #ifdef __wasm32__
  43. notifyIfReady();
  44. #else
  45. mWaitSignal.notify();
  46. #endif
  47. }
  48. #ifndef __wasm32__
  49. void Debounce::loop() {
  50. while (mRunning) {
  51. mWaitSignal.wait();
  52. if (!mRunning) {
  53. break;
  54. }
  55. notifyIfReady();
  56. }
  57. }
  58. #endif
  59. void Debounce::notifyIfReady() {
  60. if (!mRunning) {
  61. return;
  62. }
  63. // If we haven't seen an event in more than the maximum wait time, notify callbacks immediately
  64. // to ensure that we don't wait forever. Otherwise, wait for the minimum wait time and batch
  65. // subsequent fast changes. This also means the first file change in a batch is notified immediately,
  66. // separately from the rest of the batch. This seems like an acceptable tradeoff if the common case
  67. // is that only a single file was updated at a time.
  68. auto time = std::chrono::steady_clock::now();
  69. if ((time - mLastTime) > std::chrono::milliseconds(MAX_WAIT_TIME)) {
  70. mLastTime = time;
  71. notify();
  72. } else {
  73. wait();
  74. }
  75. }
  76. void Debounce::wait() {
  77. #ifdef __wasm32__
  78. clear_timeout(mTimeout);
  79. mTimeout = set_timeout(MIN_WAIT_TIME, this);
  80. #else
  81. auto status = mWaitSignal.waitFor(std::chrono::milliseconds(MIN_WAIT_TIME));
  82. if (mRunning && (status == std::cv_status::timeout)) {
  83. notify();
  84. }
  85. #endif
  86. }
  87. void Debounce::notify() {
  88. std::unique_lock<std::mutex> lock(mMutex);
  89. mLastTime = std::chrono::steady_clock::now();
  90. for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
  91. auto cb = it->second;
  92. cb();
  93. }
  94. #ifndef __wasm32__
  95. mWaitSignal.reset();
  96. #endif
  97. }