跨平台c++ Coroutine,仿unity3d实现

不多说,贴代码:

  4 #include "stdafx.h"
  5 #include <list>
  6 #include <thread>  
  7 #include <chrono>
  8 
  9 struct ICoroutine
 10 {
 11     virtual void reset(){}
 12     virtual bool move_next(int & r, float & fv) { return false; }
 13     virtual ~ICoroutine() {}
 14 public:
 15     float mWaitSeconds;
 16 };
 17 
 18 template<typename T>
 19 struct _IGenerator : public ICoroutine
 20 {
 21     T* _stack;
 22     int _line;
 23     _IGenerator() :_stack(0), _line(-1) {}
 24     virtual void reset()
 25     {
 26         _line = -1;
 27     }
 28     void _push() { T* n = new T; *n = *static_cast<T*>(this); _stack = n; }
 29     bool _pop() { if (!_stack) return false; T* t = _stack; *static_cast<T*>(this) = *_stack; t->_stack = 0; delete t; return true; }
 30     ~_IGenerator() { while (_pop()); }
 31 };
 32 
 33 #define $coroutine(NAME) struct NAME : public _IGenerator<NAME>
 34 
 35 
 36 #define $begin virtual bool move_next(int& _rv, float& _rv2) { \
 37                       if(_line < 0) _line=0; \
 38                                               $START: switch(_line) { case 0:;
 39 
 40 #define $stop  } _line = 0; if(_pop()) goto $START; return false; }
 41 
 42 #define $restart(WITH) { _push(); _stack->_line = __LINE__; _line=0; WITH; goto $START; case __LINE__:; }
 43 
 44 #define $yield(V)     \
 45           do {\
 46               _line=__LINE__;\
 47               _rv = (V); return true; case __LINE__:;\
 48                     } while (0)
 49 
 50 #define $yield_f(V, V2)     \
 51           do {\
 52               _line=__LINE__;\
 53               _rv = (V); _rv2 = V2; return true; case __LINE__:;\
 54                               } while (0)
 55 
 56 
 57 enum CoroutineState
 58 { 
 59     CO_None, 
 60     CO_WaitForNextUpdate, 
 61     CO_WaitForSeconds,
 62     CO_Exit
 63 };
 64 
 65 class GScheduler
 66 {
 67 protected:
 68     std::list<ICoroutine *> mActivityGList;
 69     std::list<ICoroutine *> mWaitingGList;
 70     std::list<ICoroutine *> mDeadingGList;
 71 
 72     std::list<ICoroutine *> mGList;
 73 
 74     void DestroyAllCoroutine()
 75     {
 76         std::list<ICoroutine *>::iterator iter;
 77         for (iter = mGList.begin(); iter != mGList.end(); iter++)
 78         {
 79             ICoroutine * co = *iter;
 80             delete co;
 81         }
 82         mGList.clear();
 83         mDeadingGList.clear();
 84         mWaitingGList.clear();
 85         mActivityGList.clear();
 86     }
 87 public:
 88     ~GScheduler()
 89     {
 90         DestroyAllCoroutine();
 91     }
 92 
 93 
 94     template<typename T, typename T2>
 95     ICoroutine* StartCoroutine(T2 * tObj)
 96     {
 97         ICoroutine * gen = new T(tObj);
 98         mGList.push_back(gen);
 99         mActivityGList.push_back(gen);
100         return gen;
101     }
102     
103     void StopCoroutine(ICoroutine *)
104     {        
105     }
106 
107     void RestartAllCoroutine()
108     {
109         std::list<ICoroutine *>::iterator iter;
110         for (iter = mGList.begin(); iter != mGList.end(); iter++)
111         {
112             ICoroutine * co = *iter;
113             co->reset();
114             mActivityGList.push_back(co);
115         }
116     }
117 
118     void StopAllCoroutine()
119     {
120         mDeadingGList.clear();
121         mWaitingGList.clear();
122         mActivityGList.clear();
123     }
124     void UpdateAllCoroutine(float dt)
125     {
126         std::list<ICoroutine *>::iterator iter, next;
127         for (iter = mWaitingGList.begin(); iter != mWaitingGList.end();iter = next)
128         {
129             next = iter; next++;
130 
131             ICoroutine * co = *iter;
132             co->mWaitSeconds -= dt;
133             if (co->mWaitSeconds <= 0)
134             {
135                 next = mWaitingGList.erase(iter);
136                 mActivityGList.push_back(co);
137             }
138         }
139 
140         for (iter = mActivityGList.begin(); iter != mActivityGList.end(); iter = next)
141         {
142             next = iter; next++;
143 
144             ICoroutine * co = *iter;
145             
146             bool isDeading = false;
147 
148             int  retValue = 0;
149             float retFValue = 0;
150             if (!co->move_next(retValue, retFValue))
151             {
152                 isDeading = true;
153             }
154             CoroutineState state = (CoroutineState)retValue;
155             if (state == CO_Exit)
156             {
157                 isDeading = true;
158             }
159             else if (state == CO_WaitForNextUpdate)
160             {
161                 
162             }
163             else if (state == CO_WaitForSeconds)
164             {
165                 float seconds = retFValue;
166                 co->mWaitSeconds = seconds;
167                 next = mActivityGList.erase(iter);
168                 mWaitingGList.push_back(co);
169             }
170 
171             if (isDeading)
172             {
173                 next = mActivityGList.erase(iter);
174                 mDeadingGList.push_back(co);
175             }
176         }
177     }
178 };
179 //**********************************************************************************************************
//以下是测试程序: 180 class TestCoroutine1; 181 class TestCoroutine2; 182 class UIMain : public GScheduler 183 { 184 public: 185 UIMain() 186 { 187 } 188 void Enable() 189 { 190 RestartAllCoroutine(); 191 } 192 void Disable() 193 { 194 StopAllCoroutine(); 195 } 196 197 void Start() 198 { 199 ICoroutine *testCo = StartCoroutine<TestCoroutine1, UIMain>(this); 200 StartCoroutine<TestCoroutine2, UIMain>(this); 201 } 202 203 void Update(float dt) 204 { 205 UpdateAllCoroutine(dt); 206 } 207 208 void Test1(int v) 209 { 210 printf("Test1, v = %d\n", v); 211 } 212 void Test2(int v) 213 { 214 printf("Test2, v = %d\n", v); 215 } 216 }; 217 218 219 $coroutine(TestCoroutine1) 220 { 221 UIMain* n; 222 TestCoroutine1(UIMain* root = 0) : n(root) {} 223 int i = 0; 224 $begin 225 for (i = 0; i < 3; i++) 226 { 227 n->Test1(i); 228 $yield(CO_WaitForNextUpdate); 229 } 230 $yield(CO_Exit); 231 n->Test1(10); 232 $stop 233 }; 234 235 $coroutine(TestCoroutine2) 236 { 237 UIMain* n; 238 TestCoroutine2(UIMain* root = 0) : n(root) {} 239 int i = 0; 240 $begin 241 for (i = 3; i < 6; i++) 242 { 243 n->Test2(i); 244 $yield_f(CO_WaitForSeconds, 0.5f); 245 } 246 $yield(CO_Exit); 247 n->Test1(99); 248 $stop 249 }; 250 251 252 253 int _tmain(int argc, _TCHAR* argv[]) 254 { 255 UIMain uiMain; 256 257 uiMain.Enable(); 258 uiMain.Start(); 259 260 float dt = 0.05f; 261 float time = 0; 262 while (true) 263 { 264 uiMain.Update(dt); 265 std::this_thread::sleep_for(std::chrono::milliseconds((int)(dt*1000))); 266 time += dt; 267 if (time > 10) //10秒后重开协程 268 { 269 uiMain.Disable(); 270 uiMain.Enable(); //重新开始协程 271 time = 0; 272 } 273 } 274 return 0; 275 }

 

posted on 2015-08-27 16:28  chunlin  阅读(903)  评论(0编辑  收藏  举报

导航