Skip to content

Instantly share code, notes, and snippets.

@LYP951018
Last active May 30, 2017 12:49
Show Gist options
  • Save LYP951018/88eb616b939f19dad90bd6b087baa4d9 to your computer and use it in GitHub Desktop.
Save LYP951018/88eb616b939f19dad90bd6b087baa4d9 to your computer and use it in GitHub Desktop.
NaiveFuture
#include <variant>
#include <functional>
#include <memory>
#include <iostream>
#include <thread>
#include <chrono>
#include <stdexcept>
#include <Windows.h>
using Win32Handle = std::unique_ptr<void, void (*)(void *) noexcept>;
Win32Handle MakeWin32Handle(void *handle)
{
return Win32Handle{handle, +[](void *h) noexcept {::CloseHandle(h);}};
}
struct Done {};
template <typename T>
struct Payload
{
Win32Handle Event;
std::function<T()> Func;
std::variant<std::monostate, std::exception_ptr, T, Done> Data;
template <typename F>
Payload(F f)
: Func{std::move(f)},
Event{MakeWin32Handle(::CreateEventW({}, FALSE, FALSE, {}))}
{
assert(Event);
}
};
template <typename T>
class Future
{
public:
T get()
{
const auto waitResult = WaitForSingleObject(payload_->Event.get(), INFINITE);
if (waitResult == WAIT_OBJECT_0)
{
switch (payload_->Data.index())
{
case 1:
done();
std::rethrow_exception(std::get<1>(payload_->Data));
case 2:
{
const auto result = std::get<2>(std::move(payload_->Data));
done();
return result;
}
default:
std::terminate();
}
}
else
{
throw std::system_error{static_cast<int>(::GetLastError()), std::system_category()};
}
}
~Future()
{
if (payload_->Data.index() != 3) {
WaitForSingleObject(payload_->Event.get(), INFINITE);
done();
}
}
Future(std::unique_ptr<Payload<T>> payload)
: payload_{std::move(payload)}
{
}
private:
void done()
{
payload_->Data = Done{};
}
template <typename F>
friend Future<T> Async(F f);
std::unique_ptr<Payload<T>> payload_;
};
template <typename F>
Future<std::invoke_result_t<F>> Async(F f)
{
using Result = std::invoke_result_t<F>;
auto payload = std::make_unique<Payload<Result>>(std::move(f));
::QueueUserWorkItem(+[](void *param) -> DWORD {
const auto p = static_cast<Payload<Result> *>(param);
{
try
{
p->Data = std::invoke(p->Func);
}
catch (...)
{
p->Data = std::current_exception();
}
}
SetEvent(p->Event.get());
return 0;
}, payload.get(), WT_EXECUTEDEFAULT);
return Future{std::move(payload)};
}
int main()
{
using namespace std::literals;
auto f = Async([]() {
std::cout << "Hello, world!";
std::this_thread::sleep_for(3s);
return 2;
});
//std::this_thread::sleep_for(3s);
//std::cout << f.get();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment