-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
de2dff0
commit 7fecb82
Showing
5 changed files
with
181 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#pragma once | ||
|
||
#include <cstdint> | ||
|
||
namespace coro | ||
{ | ||
using HandleID = uint64_t; | ||
|
||
class handle | ||
{ | ||
public: | ||
handle() : id(id_gen++) { } | ||
virtual ~handle() = default; | ||
|
||
HandleID get_handle_id() { return id; } | ||
|
||
virtual void run() = 0; | ||
virtual void dump_backtrace(size_t) const { } | ||
|
||
private: | ||
HandleID id; | ||
inline static HandleID id_gen = 0; | ||
}; | ||
|
||
struct handle_wrapper | ||
{ | ||
HandleID id; | ||
handle* handle; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
#pragma once | ||
|
||
#include "handle.h" | ||
#include "task.h" | ||
#include <queue> | ||
#include <chrono> | ||
#include <vector> | ||
#include <algorithm> | ||
#include <thread> | ||
|
||
namespace coro | ||
{ | ||
class Loop | ||
{ | ||
using MS = std::chrono::milliseconds; | ||
using delayed_handle = std::pair<MS, handle_wrapper>; | ||
using clock = std::chrono::steady_clock; | ||
|
||
public: | ||
Loop() | ||
{ | ||
startup_time = std::chrono::duration_cast<MS>(clock::now().time_since_epoch()); | ||
} | ||
~Loop() = default; | ||
Loop(Loop const&) = delete; | ||
Loop(Loop&&) = delete; | ||
Loop& operator=(Loop const&) = delete; | ||
Loop& operator=(Loop&&) = delete; | ||
|
||
void call(handle& _handle) | ||
{ | ||
handles.push({ _handle.get_handle_id(), &_handle }); | ||
} | ||
|
||
template<typename Ret> | ||
void call(task<Ret>& _task) | ||
{ | ||
call(_task.promise()); | ||
} | ||
|
||
template<typename Rep, typename Period, typename Ret> | ||
void call_after(std::chrono::duration<Rep, Period> delay, task<Ret>& _task) | ||
{ | ||
auto t = std::chrono::duration_cast<MS>(delay) + now(); | ||
delayed_handles.emplace_back(t, handle_wrapper{ _task.promise().get_handle_id(), &_task.promise() }); | ||
std::ranges::push_heap(delayed_handles, std::ranges::greater{}, &delayed_handle::first); // min heap | ||
} | ||
|
||
void run_until_complete() | ||
{ | ||
while(!is_stop()) run_once(); | ||
} | ||
|
||
private: | ||
bool is_stop() | ||
{ | ||
return handles.empty() && delayed_handles.empty(); | ||
} | ||
|
||
void run_once() | ||
{ | ||
auto current = now(); | ||
while (!delayed_handles.empty()) | ||
{ | ||
auto&& [t, h] = delayed_handles[0]; | ||
if (t >= current) break; | ||
handles.push(h); | ||
std::ranges::pop_heap(delayed_handles, std::ranges::greater{}, &delayed_handle::first); | ||
delayed_handles.pop_back(); | ||
} | ||
|
||
for (size_t i = 0, n = handles.size(); i < n; i++) | ||
{ | ||
auto [id, h] = handles.front(); | ||
handles.pop(); | ||
h->run(); | ||
} | ||
} | ||
|
||
MS now() | ||
{ | ||
return std::chrono::duration_cast<MS>(clock::now().time_since_epoch()) - startup_time; | ||
} | ||
|
||
private: | ||
std::queue<handle_wrapper> handles; | ||
|
||
MS startup_time; | ||
std::vector<delayed_handle> delayed_handles; // minimum time heap | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
#include "coro/loop.h" | ||
#include "coro/task.h" | ||
|
||
using namespace coro; | ||
|
||
int main() | ||
{ | ||
auto t = []() -> task<int> { co_await dump_callstack(); co_return 1; }; | ||
|
||
auto sum = [&]() -> task<> { | ||
int sum = 0; | ||
for (int i = 0; i < 10; i++) | ||
sum += co_await t(); | ||
|
||
fmt::print("sum == {}: {}\n", sum, sum == 10); | ||
co_return; | ||
}(); | ||
|
||
//sum.promise().run(); | ||
|
||
Loop loop; | ||
fmt::print("create loop\n"); | ||
|
||
//loop.call(sum.promise()); | ||
loop.call(sum); | ||
fmt::print("push task sum into loop queue\n"); | ||
|
||
auto j = []() -> task<> { co_await dump_callstack(); }(); | ||
loop.call(j); | ||
fmt::print("push task j into loop queue\n"); | ||
|
||
auto k = []() -> task<int> { co_await dump_callstack(); co_return 2; }(); | ||
using namespace std::chrono_literals; | ||
loop.call_after(std::chrono::duration(1s), k); | ||
fmt::print("push task k into loop queue\n"); | ||
|
||
auto h = []() -> task<> { co_await dump_callstack(); }(); | ||
using namespace std::chrono_literals; | ||
loop.call_after(std::chrono::duration(2s), h); | ||
fmt::print("push task h into loop queue\n"); | ||
|
||
// add all tasks before this | ||
loop.run_until_complete(); | ||
|
||
return 0; | ||
} |