3 * @brief Template implementation for EventQueue - type-safe function enqueuing with futures
10 #include "EventQueue.h"
14 * @brief Enqueue function for immediate asynchronous execution
15 * @tparam F Function type (auto-deduced)
16 * @tparam Args Variadic argument types (auto-deduced)
17 * @param func Callable object to execute asynchronously
18 * @param args Arguments to forward to the function
19 * @return std::future<ReturnType> Future containing the function result
21 * Enqueues a function for immediate execution in the event loop thread.
22 * Uses perfect forwarding to preserve argument types and std::packaged_task
23 * to provide future-based result retrieval. The function is wrapped in a
24 * void task for uniform queue handling while preserving the original
25 * return type through the future mechanism.
27 * Key implementation details:
28 * - **Perfect forwarding**: Preserves value categories and reference types
29 * - **Type erasure**: Wraps typed task in void task for uniform storage
30 * - **Thread safety**: Protected by mutex during queue insertion
31 * - **Immediate execution**: Inserted at front of queue (whenUs = 0)
32 * - **Always notify**: Signals condition variable regardless of queue state
35 * // Enqueue lambda with capture
36 * auto future1 = queue.enqueueFunction([x = 42](int y) { return x + y; }, 8);
38 * // Enqueue free function
39 * auto future2 = queue.enqueueFunction(std::sin, 3.14159);
42 * int result1 = future1.get(); // 50
43 * double result2 = future2.get(); // ~0.0
46 * @note Thread-safe operation with automatic notification
47 * @note Function executes in event loop thread context
48 * @warning Future must be retrieved before function object destruction
50 * @see \ref swt::EventQueue "EventQueue", \ref swt::Promise "Promise"
52 template<typename F, typename... Args>
53 auto EventQueue::enqueueFunction(F&& func, Args&&... args) -> std::future<decltype(func(args...))> {
54 using ReturnType = decltype(func(args...));
56 // Bind arguments to function using perfect forwarding
57 auto boundTask = std::bind(std::forward<F>(func), std::forward<Args>(args)...);
59 // Create packaged_task for typed result handling
60 auto packagedTask = std::packaged_task<ReturnType()>(boundTask);
61 auto future = packagedTask.get_future();
63 // Wrap in void task for type-erased queue storage
64 auto voidTask = std::packaged_task<void()>([task = std::move(packagedTask)]() mutable {
69 std::lock_guard<std::mutex> lock(iMutex);
70 int64_t whenUs = 0; // IMMEDIATE EXECUTION - front of queue
72 // Insert at beginning for immediate execution (highest priority)
73 mQueue.emplace_front(std::move(voidTask), whenUs);
76 // ALWAYS notify condition variable to wake up event loop thread
77 mQueueChanged.notify_one();
83 * @brief Enqueue function for delayed asynchronous execution
84 * @tparam F Function type (auto-deduced)
85 * @tparam Args Variadic argument types (auto-deduced)
86 * @param delayMs Delay in milliseconds before execution
87 * @param func Callable object to execute asynchronously
88 * @param args Arguments to forward to the function
89 * @return std::future<ReturnType> Future containing the function result
91 * Enqueues a function for delayed execution in the event loop thread.
92 * The function will be executed after the specified delay, maintaining
93 * proper ordering with other delayed tasks. Uses binary search insertion
94 * to maintain chronological order in the queue without full sorting.
96 * Key implementation details:
97 * - **Timed execution**: Calculates absolute execution time from current uptime
98 * - **Ordered insertion**: Uses std::upper_bound for efficient sorted insertion
99 * - **Binary search**: O(log n) insertion instead of O(n log n) full sort
100 * - **Conditional notification**: Only notifies if event loop is started
101 * - **Microsecond precision**: Internal timing uses microseconds for accuracy
104 * // Execute function after 1 second delay
105 * auto future = queue.enqueueFunctionDelayed(1000, []() {
106 * return "Hello after delay!";
109 * // Execute with arguments after 500ms delay
110 * auto future2 = queue.enqueueFunctionDelayed(500,
111 * [](int x, int y) { return x * y; }, 6, 7);
113 * // Get results (will block until execution time)
114 * std::string result1 = future.get(); // "Hello after delay!"
115 * int result2 = future2.get(); // 42
118 * @note Thread-safe operation with efficient ordered insertion
119 * @note Delay is measured from when function is enqueued
120 * @note Only notifies condition variable if event loop is started
122 * @see \ref swt::EventQueue "EventQueue", \ref swt::Promise "Promise"
124 template<typename F, typename... Args>
125 auto EventQueue::enqueueFunctionDelayed(int64_t delayMs, F&& func, Args&&... args) -> std::future<decltype(func(args...))> {
126 using ReturnType = decltype(func(args...));
128 // Bind arguments to function using perfect forwarding
129 auto boundTask = std::bind(std::forward<F>(func), std::forward<Args>(args)...);
131 // Create packaged_task for typed result handling
132 auto packagedTask = std::packaged_task<ReturnType()>(boundTask);
133 auto future = packagedTask.get_future();
135 // Wrap in void task for type-erased queue storage
136 auto voidTask = std::packaged_task<void()>([task = std::move(packagedTask)]() mutable {
141 std::lock_guard<std::mutex> lock(iMutex);
143 // Calculate absolute execution time in microseconds
144 int64_t whenUs = uptimeMicros() + (delayMs * 1000);
146 // Insert at correct chronological position using binary search
147 auto insertPos = std::upper_bound(mQueue.begin(), mQueue.end(), whenUs,
148 [](int64_t time, const QueueItem& item) {
149 return time < item.whenUs;
152 // Insert at calculated position maintaining sorted order
153 mQueue.emplace(insertPos, std::move(voidTask), whenUs);
156 // Only notify if event loop is started to avoid spurious wakeups
158 mQueueChanged.notify_one();
165 * @brief Create and enqueue promise for manual resolution
166 * @tparam T Value type for the promise
167 * @return swt::Promise<T> New promise object for manual control
169 * Creates a new promise that can be resolved manually from any thread.
170 * The promise callbacks will execute in the event loop thread when
171 * the promise is resolved or rejected.
173 * @see \ref swt::Promise "Promise"
176 Promise<T> EventQueue::enqueuePromise() {