Created
October 10, 2011 04:07
-
-
Save 7shi/1274612 to your computer and use it in GitHub Desktop.
コルーチンのコードを整理
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
#include "Coroutine.h" | |
_declspec(naked) int _fastcall mysetjmp(myjmp_buf *jbuf) { | |
_asm { | |
pop edx | |
mov [ecx ], edx | |
mov [ecx+ 4], esp | |
mov [ecx+ 8], ebp | |
mov [ecx+12], ebx | |
mov [ecx+16], edi | |
mov [ecx+20], esi | |
xor eax, eax | |
mov [ecx+24], eax | |
mov [ecx+28], eax | |
jmp edx | |
} | |
} | |
_declspec(naked) void _fastcall mylongjmp(myjmp_buf *jbuf, int value) { | |
_asm { | |
mov eax, edx | |
mov edx, ecx | |
mov esp, [edx+ 4] | |
mov edi, esp | |
mov esi, [edx+24] | |
mov ecx, [edx+28] | |
cld | |
rep movsb | |
mov ebp, [edx+ 8] | |
mov ebx, [edx+12] | |
mov edi, [edx+16] | |
mov esi, [edx+20] | |
jmp dword ptr [edx] | |
} | |
} | |
void save_stack(std::vector<char> *dest, unsigned long last, myjmp_buf *callee) { | |
callee->length = last - callee->esp; | |
dest->resize(callee->length); | |
callee->stack = &(*dest)[0]; | |
memcpy(callee->stack, (void *)callee->esp, callee->length); | |
} | |
std::stack<CoroutineBase *> coroutines; | |
CoroutineBase::~CoroutineBase() {} |
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
#pragma once | |
#include <vector> | |
#include <functional> | |
#include <stack> | |
typedef struct { | |
unsigned long eip, esp, ebp, ebx, edi, esi; | |
void *stack; | |
int length; | |
} myjmp_buf; | |
extern int _fastcall mysetjmp(myjmp_buf *jbuf); | |
extern void _fastcall mylongjmp(myjmp_buf *jbuf, int value); | |
extern void save_stack(std::vector<char> *dest, unsigned long last, myjmp_buf *callee); | |
class CoroutineBase { | |
public: | |
virtual ~CoroutineBase(); | |
}; | |
extern std::stack<CoroutineBase *> coroutines; | |
template <class T> class Coroutine : public CoroutineBase { | |
myjmp_buf caller, callee; | |
std::vector<char> stack; | |
std::function<void()> f; | |
int status; | |
unsigned long last; | |
void exec() { | |
f(); | |
mylongjmp(&caller, 2); | |
} | |
public: | |
T value; | |
Coroutine() : status(0) {} | |
Coroutine(const decltype(f) &f) : f(f), status(0) {} | |
void operator=(const decltype(f) &f) { this->f = f; } | |
bool operator()() { | |
if (status == 0) _alloca(32 * 1024); | |
switch (mysetjmp(&caller)) { | |
case 1: | |
return true; | |
case 2: | |
coroutines.pop(); | |
status = 3; | |
return false; | |
} | |
switch (status) { | |
case 0: | |
last = caller.esp; | |
status = 1; | |
coroutines.push(this); | |
exec(); | |
case 2: | |
if (caller.esp < callee.esp) | |
return false; | |
status = 1; | |
coroutines.push(this); | |
mylongjmp(&callee, 1); | |
} | |
return false; | |
} | |
T yield(T value) { | |
if (coroutines.top() == this) { | |
coroutines.pop(); | |
status = 2; | |
this->value = value; | |
if (mysetjmp(&callee) == 0) { | |
save_stack(&stack, last, &callee); | |
mylongjmp(&caller, 1); | |
} | |
} | |
return this->value; | |
} | |
}; | |
template <class T> T yield(T value) { | |
auto cr = dynamic_cast<Coroutine<T> *>(coroutines.top()); | |
return cr ? cr->yield(value) : T(); | |
} |
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
#include <iostream> | |
#include "Coroutine.h" | |
using namespace std; | |
void test() { | |
for (int i = 0; i <= 5; i++) | |
yield(i); | |
} | |
int main() { | |
Coroutine<int> cr = test; | |
while (cr()) | |
cout << cr.value << endl; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment