--- a/common/tool/tool_manager.cpp +++ b/common/tool/tool_manager.cpp @@ -532,11 +532,11 @@ if( st->cofunc ) st->Push(); + st->cofunc = new COROUTINE( tr.second ); + // as the state changes, the transition table has to be set up again st->transitions.clear(); - st->cofunc = new COROUTINE( tr.second ); - // got match? Run the handler. st->cofunc->Call( aEvent ); --- a/include/tool/coroutine.h +++ b/include/tool/coroutine.h @@ -27,10 +28,15 @@ #include -#include #include +#include -#include "delegate.h" +#if BOOST_VERSION <= 106000 +#include +#else +#include +#include +#endif /** * Class COROUNTINE. @@ -53,13 +59,12 @@ * See coroutine_example.cpp for sample code. */ -template +template class COROUTINE { public: COROUTINE() : - m_saved( NULL ), m_self( NULL ), m_stack( NULL ), m_stackSize( c_defaultStackSize ), - m_running( false ) + COROUTINE( nullptr ) { } @@ -69,8 +74,7 @@ */ template COROUTINE( T* object, ReturnType(T::* ptr)( ArgType ) ) : - m_func( object, ptr ), m_self( NULL ), m_saved( NULL ), m_stack( NULL ), - m_stackSize( c_defaultStackSize ), m_running( false ) + COROUTINE( std::bind( ptr, object, std::placeholders::_1 ) ) { } @@ -78,9 +82,15 @@ * Constructor * Creates a coroutine from a delegate object */ - COROUTINE( DELEGATE aEntry ) : - m_func( aEntry ), m_saved( NULL ), m_self( NULL ), m_stack( NULL ), - m_stackSize( c_defaultStackSize ), m_running( false ) + COROUTINE( std::function aEntry ) : + m_func( std::move( aEntry ) ), + m_running( false ), +#if BOOST_VERSION <= 106000 + m_stack( nullptr ), + m_stackSize( c_defaultStackSize ), +#endif + m_caller( nullptr ), + m_callee( nullptr ) { // Avoid not initialized members, and make static analysers quiet m_args = 0; @@ -89,18 +99,26 @@ ~COROUTINE() { - if( m_saved ) - delete m_saved; - #if BOOST_VERSION >= 105600 - if( m_self ) - delete m_self; + delete m_callee; #endif +#if BOOST_VERSION <= 106000 + delete m_caller; + if( m_stack ) free( m_stack ); +#endif } +private: +#if BOOST_VERSION <= 106000 + using context_type = boost::context::fcontext_t; +#else + using context_type = boost::context::execution_context; +#endif + +public: /** * Function Yield() * @@ -110,7 +128,12 @@ */ void Yield() { - jump( m_self, m_saved, 0 ); +#if BOOST_VERSION <= 106000 + jump( m_callee, m_caller, false ); +#else + auto result = (*m_caller)( this ); + *m_caller = std::move( std::get<0>( result ) ); +#endif } /** @@ -122,7 +145,11 @@ void Yield( ReturnType& aRetVal ) { m_retVal = aRetVal; - jump( m_self, m_saved, 0 ); +#if BOOST_VERSION <= 106000 + jump( m_callee, m_caller, false ); +#else + m_caller( this ); +#endif } /** @@ -130,9 +157,9 @@ * * Defines the entry point for the coroutine, if not set in the constructor. */ - void SetEntry( DELEGATE aEntry ) + void SetEntry( std::function aEntry ) { - m_func = aEntry; + m_func = std::move( aEntry ); } /* Function Call() @@ -143,6 +170,10 @@ */ bool Call( ArgType aArgs ) { + assert( m_callee == NULL ); + assert( m_caller == NULL ); + +#if BOOST_VERSION <= 106000 // fixme: Clean up stack stuff. Add a guard m_stack = malloc( c_defaultStackSize ); @@ -151,22 +182,32 @@ // correct the stack size m_stackSize -= ( (size_t) m_stack + m_stackSize - (size_t) sp ); - - assert( m_self == NULL ); - assert( m_saved == NULL ); +#endif m_args = &aArgs; -#if BOOST_VERSION >= 105600 - m_self = new boost::context::fcontext_t(); - *m_self = boost::context::make_fcontext( sp, m_stackSize, callerStub ); + +#if BOOST_VERSION < 105600 + m_callee = boost::context::make_fcontext( sp, m_stackSize, callerStub ); +#elif BOOST_VERSION <= 106000 + m_callee = new context_type( boost::context::make_fcontext( sp, m_stackSize, callerStub ) ); #else - m_self = boost::context::make_fcontext( sp, m_stackSize, callerStub ); + m_callee = new context_type( std::allocator_arg_t(), + boost::context::protected_fixedsize_stack( c_defaultStackSize ), &COROUTINE::callerStub ); +#endif + +#if BOOST_VERSION <= 106000 + m_caller = new context_type(); #endif - m_saved = new boost::context::fcontext_t(); m_running = true; + // off we go! - jump( m_saved, m_self, reinterpret_cast( this ) ); +#if BOOST_VERSION <= 106000 + jump( m_caller, m_callee, reinterpret_cast( this ) ); +#else + auto result = (*m_callee)( this ); + *m_callee = std::move( std::get<0>( result ) ); +#endif return m_running; } @@ -179,7 +220,12 @@ */ bool Resume() { - jump( m_saved, m_self, 0 ); +#if BOOST_VERSION <= 106000 + jump( m_caller, m_callee, false ); +#else + auto result = (*m_callee)( this ); + *m_callee = std::move( std::get<0>( result ) ); +#endif return m_running; } @@ -208,61 +254,66 @@ static const int c_defaultStackSize = 2000000; // fixme: make configurable /* real entry point of the coroutine */ +#if BOOST_VERSION <= 106000 static void callerStub( intptr_t aData ) +#else + static context_type callerStub( context_type caller, COROUTINE* cor ) +#endif { // get pointer to self +#if BOOST_VERSION <= 106000 COROUTINE* cor = reinterpret_cast*>( aData ); +#else + cor->m_caller = &caller; +#endif // call the coroutine method - cor->m_retVal = cor->m_func( *cor->m_args ); + cor->m_retVal = cor->m_func( *( cor->m_args ) ); cor->m_running = false; // go back to wherever we came from. - jump( cor->m_self, cor->m_saved, 0 ); // reinterpret_cast( this )); +#if BOOST_VERSION <= 106000 + jump( cor->m_callee, cor->m_caller, 0 ); +#else + return caller; +#endif } ///> Wrapper for jump_fcontext to assure compatibility between different boost versions - static inline intptr_t jump(boost::context::fcontext_t* aOld, boost::context::fcontext_t* aNew, +#if BOOST_VERSION <= 106000 + static inline intptr_t jump( context_type* aOld, context_type* aNew, intptr_t aP, bool aPreserveFPU = true ) { -#if BOOST_VERSION >= 105600 - return boost::context::jump_fcontext( aOld, *aNew, aP, aPreserveFPU ); -#else +#if BOOST_VERSION < 105600 return boost::context::jump_fcontext( aOld, aNew, aP, aPreserveFPU ); +#else + return boost::context::jump_fcontext( aOld, *aNew, aP, aPreserveFPU ); #endif } +#endif - template - struct strip_ref - { - typedef T result; - }; + std::function m_func; - template - struct strip_ref - { - typedef T result; - }; + bool m_running; - DELEGATE m_func; +#if BOOST_VERSION <= 106000 + ///< coroutine stack + void* m_stack; + + size_t m_stackSize; +#endif ///< pointer to coroutine entry arguments. Stripped of references ///< to avoid compiler errors. - typename strip_ref::result* m_args; + typename std::remove_reference::type* m_args; + ReturnType m_retVal; ///< saved caller context - boost::context::fcontext_t* m_saved; + context_type* m_caller; ///< saved coroutine context - boost::context::fcontext_t* m_self; - - ///< coroutine stack - void* m_stack; - - size_t m_stackSize; - - bool m_running; + context_type* m_callee; }; #endif --- a/include/tool/tool_base.h +++ b/include/tool/tool_base.h @@ -31,7 +32,7 @@ #include #include -#include +#include class EDA_ITEM; class TOOL_MANAGER; @@ -53,7 +54,9 @@ /// Unique identifier for tools typedef int TOOL_ID; -typedef DELEGATE TOOL_STATE_FUNC; + +using TOOL_STATE_FUNC = std::function; + /** * Class TOOL_BASE --- a/include/tool/tool_interactive.h +++ b/include/tool/tool_interactive.h @@ -113,7 +114,7 @@ void TOOL_INTERACTIVE::Go( int (T::* aStateFunc)( const TOOL_EVENT& ), const TOOL_EVENT_LIST& aConditions ) { - TOOL_STATE_FUNC sptr( static_cast( this ), aStateFunc ); + TOOL_STATE_FUNC sptr = std::bind( aStateFunc, static_cast( this ), std::placeholders::_1 ); goInternal( sptr, aConditions ); }