Skip to content

Instantly share code, notes, and snippets.

@jclay
Last active June 23, 2023 06:06
Show Gist options
  • Save jclay/a5bb9dcf7044201833a48cdf80536f26 to your computer and use it in GitHub Desktop.
Save jclay/a5bb9dcf7044201833a48cdf80536f26 to your computer and use it in GitHub Desktop.
int demo_modes() {
static int counter = 0;
auto increment_counter = [] {
counter++;
println("count: {}", counter);
};
// Timer ticks every 100ms and prints the latest count
auto t = RepeatingTimer(Milliseconds(100), increment_counter);
// Enter the selfish run loop and stop being selfish after 1 second
CFRunLoopRunInMode(
/* mode */ kSelfishMode,
/* seconds to run in this mode */ Seconds(1).ToSecondsF(),
/* returnAfterSourceHandled */ false);
return 0;
}
struct RepeatingTimer {
using Callback = std::function<void()>;
RepeatingTimer(TimeDelta interval, Callback callback)
: callback_holder_(std::move(callback)), interval_(interval) {
CFRunLoopTimerContext timerContext = {
.version = 0,
.info = &callback_holder_,
.retain = nullptr,
.release = nullptr,
.copyDescription = nullptr,
};
timer_ref_ = AdoptCFRef(CFRunLoopTimerCreate(
/* allocator */ kCFAllocatorDefault,
/* fireDate */ CFAbsoluteTimeGetCurrent(),
/* interval */ interval_.ToSecondsF(),
/* flags */ 0,
/* order */ 0,
/* callout */ &TimerCallbackTrampoline,
/* context */ &timerContext));
CFRunLoopAddTimer(CFRunLoopGetMain(), timer_ref_, kCFRunLoopCommonModes);
}
~RepeatingTimer() {
// Detach the timer, the `ScopedCFTypeRef` will release the ref on the timer after.
CFRunLoopRemoveTimer(CFRunLoopGetMain(), timer_ref_, kCFRunLoopCommonModes);
}
// Move only
RepeatingTimer(RepeatingTimer&&) = default;
RepeatingTimer& operator=(RepeatingTimer&&) = default;
RepeatingTimer(const RepeatingTimer&) = delete;
RepeatingTimer& operator=(const RepeatingTimer&) = delete;
private:
struct CallbackHolder {
void Run() { cb_(); }
Callback cb_;
};
// Called every `interval_` seconds by the CFRunLoop
static void TimerCallbackTrampoline(CFRunLoopTimerRef timer, void* info) {
// Cast the opaque pointer back to our callback, and run.
static_cast<CallbackHolder*>(info)->Run();
}
CallbackHolder callback_holder_;
TimeDelta interval_;
ScopedCFTypeRef<CFRunLoopTimerRef> timer_ref_;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment