/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #ifndef __ASYNC_CALL_QUEUE__ #define __ASYNC_CALL_QUEUE__ #include "async/future.h" #include "thread/thread.h" #include "thread/mutex.h" #include "container/nlist.h" namespace GS { namespace ASync { /*! @short Asynchronous call queue. @author Emmanuel Julien (ejulien@owloh.com) */ class CallQueue { struct BaseCall { virtual void Execute() = 0; virtual ~BaseCall() {} }; Threading::Mutex queue_mutex; List call_queue; /// Post a call to the queue. void Queue(BaseCall *m) { Threading::MutexLock lock(&queue_mutex); call_queue.Append(m); } private: // Call a member function, ignore the return value. template struct MemberCall : public BaseCall { I i; F fn; void Execute() { (i->*fn)(); } MemberCall(I _i, F _fn) : i(_i), fn(_fn) {} }; template struct MemberCall1 : public BaseCall { I i; F fn; A1 a1; void Execute() { (i->*fn)(a1); } MemberCall1(I _i, F _fn, const A1 &_a1) : i(_i), fn(_fn), a1(_a1) {} }; template struct MemberCall2 : public BaseCall { I i; F fn; A1 a1; A2 a2; void Execute() { (i->*fn)(a1, a2); } MemberCall2(I _i, F _fn, const A1 &_a1, const A2 &_a2) : i(_i), fn(_fn), a1(_a1), a2(_a2) {} }; template struct MemberCall3 : public BaseCall { I i; F fn; A1 a1; A2 a2; A3 a3; void Execute() { (i->*fn)(a1, a2, a3); } MemberCall3(I _i, F _fn, const A1 &_a1, const A2 &_a2, const A3 &_a3) : i(_i), fn(_fn), a1(_a1), a2(_a2), a3(_a3) {} }; template struct MemberCall4 : public BaseCall { I i; F fn; A1 a1; A2 a2; A3 a3; A4 a4; void Execute() { (i->*fn)(a1, a2, a3, a4); } MemberCall4(I _i, F _fn, const A1 &_a1, const A2 &_a2, const A3 &_a3, const A4 &_a4) : i(_i), fn(_fn), a1(_a1), a2(_a2), a3(_a3), a4(_a4) {} }; public: template void QueueMemberCall(I i, F fn) { Queue(new MemberCall (i, fn)); } template void QueueMemberCall(I i, F fn, const A1 &a1) { Queue(new MemberCall1 (i, fn, a1)); } template void QueueMemberCall(I i, F fn, const A1 &a1, const A2 &a2) { Queue(new MemberCall2 (i, fn, a1, a2)); } template void QueueMemberCall(I i, F fn, const A1 &a1, const A2 &a2, const A3 &a3) { Queue(new MemberCall3 (i, fn, a1, a2, a3)); } template void QueueMemberCall(I i, F fn, const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4) { Queue(new MemberCall4 (i, fn, a1, a2, a3, a4)); } private: // Generic return value calls. template struct RValMemberCall : public BaseCall { Future &future; I i; F fn; void Execute() { future.Set((i->*fn)()); } RValMemberCall(Future &_future, I _i, F _fn) : future(_future), i(_i), fn(_fn) {} }; template struct RValMemberCall1 : public BaseCall { Future &future; I i; F fn; A1 a1; void Execute() { future.Set((i->*fn)(a1)); } RValMemberCall1(Future &_future, I _i, F _fn, const A1 &_a1) : future(_future), i(_i), fn(_fn), a1(_a1) {} }; template struct RValMemberCall2 : public BaseCall { Future &future; I i; F fn; A1 a1; A2 a2; void Execute() { future.Set((i->*fn)(a1, a2)); } RValMemberCall2(Future &_future, I _i, F _fn, const A1 &_a1, const A2 &_a2) : future(_future), i(_i), fn(_fn), a1(_a1), a2(_a2) {} }; template struct RValMemberCall3 : public BaseCall { Future &future; I i; F fn; A1 a1; A2 a2; A3 a3; void Execute() { future.Set((i->*fn)(a1, a2, a3)); } RValMemberCall3(Future &_future, I _i, F _fn, const A1 &_a1, const A2 &_a2, const A3 &_a3) : future(_future), i(_i), fn(_fn), a1(_a1), a2(_a2), a3(_a3) {} }; template struct RValMemberCall4 : public BaseCall { Future &future; I i; F fn; A1 a1; A2 a2; A3 a3; A4 a4; void Execute() { future.Set((i->*fn)(a1, a2, a3, a4)); } RValMemberCall4(Future &_future, I _i, F _fn, const A1 &_a1, const A2 &_a2, const A3 &_a3, const A4 &_a4) : future(_future), i(_i), fn(_fn), a1(_a1), a2(_a2), a3(_a3), a4(_a4) {} }; // No return value specialized calls. template struct RValMemberCall : public BaseCall { Future &future; I i; F fn; void Execute() { (i->*fn)(); future.Set(); } RValMemberCall(Future &_future, I _i, F _fn) : future(_future), i(_i), fn(_fn) {} }; template struct RValMemberCall1 : public BaseCall { Future &future; I i; F fn; A1 a1; void Execute() { (i->*fn)(a1); future.Set(); } RValMemberCall1(Future &_future, I _i, F _fn, const A1 &_a1) : future(_future), i(_i), fn(_fn), a1(_a1) {} }; template struct RValMemberCall2 : public BaseCall { Future &future; I i; F fn; A1 a1; A2 a2; void Execute() { (i->*fn)(a1, a2); future.Set(); } RValMemberCall2(Future &_future, I _i, F _fn, const A1 &_a1, const A2 &_a2) : future(_future), i(_i), fn(_fn), a1(_a1), a2(_a2) {} }; template struct RValMemberCall3 : public BaseCall { Future &future; I i; F fn; A1 a1; A2 a2; A3 a3; void Execute() { (i->*fn)(a1, a2, a3); future.Set(); } RValMemberCall3(Future &_future, I _i, F _fn, const A1 &_a1, const A2 &_a2, const A3 &_a3) : future(_future), i(_i), fn(_fn), a1(_a1), a2(_a2), a3(_a3) {} }; template struct RValMemberCall4 : public BaseCall { Future &future; I i; F fn; A1 a1; A2 a2; A3 a3; A4 a4; void Execute() { (i->*fn)(a1, a2, a3, a4); future.Set(); } RValMemberCall4(Future &_future, I _i, F _fn, const A1 &_a1, const A2 &_a2, const A3 &_a3, const A4 &_a4) : future(_future), i(_i), fn(_fn), a1(_a1), a2(_a2), a3(_a3), a4(_a4) {} }; public: /// Queue a member call, return the value in a future. template void QueueMemberCall(Future &f, I i, F fn) { Queue(new RValMemberCall (f, i, fn)); } template void QueueMemberCall(Future &f, I i, F fn, const A1 &a1) { Queue(new RValMemberCall1 (f, i, fn, a1)); } template void QueueMemberCall(Future &f, I i, F fn, const A1 &a1, const A2 &a2) { Queue(new RValMemberCall2 (f, i, fn, a1, a2)); } template void QueueMemberCall(Future &f, I i, F fn, const A1 &a1, const A2 &a2, const A3 &a3) { Queue(new RValMemberCall3 (f, i, fn, a1, a2, a3)); } template void QueueMemberCall(Future &f, I i, F fn, const A1 &a1, const A2 &a2, const A3 &a3, const A4 &a4) { Queue(new RValMemberCall4 (f, i, fn, a1, a2, a3, a4)); } public: bool Execute() { BaseCall *c = NULL; { Threading::MutexLock lock(&queue_mutex); if (call_queue.GetCount() == 0) return false; c = call_queue[0]; call_queue.RemoveAt(0); } if (c) { c->Execute(); delete c; } return asbool(c); } void ExecuteAll() { while (Execute() == true) {} } }; } // ASync } // GS #endif // __ASYNC_CALL_QUEUE__