boost::context fixes to make it compatible with boost 1.61

This commit is contained in:
Michael Steinberg 2016-07-05 00:14:32 +02:00 committed by Maciej Suminski
parent e7bbe27e36
commit 06d4894fdb
4 changed files with 122 additions and 68 deletions

View File

@ -522,7 +522,7 @@ void TOOL_MANAGER::dispatchInternal( const TOOL_EVENT& aEvent )
} }
} }
for( TOOL_STATE* st : m_toolState | boost::adaptors::map_values ) for( TOOL_STATE* st : ( m_toolState | boost::adaptors::map_values ) )
{ {
// no state handler in progress - check if there are any transitions (defined by // no state handler in progress - check if there are any transitions (defined by
// Go() method that match the event. // Go() method that match the event.
@ -536,11 +536,11 @@ void TOOL_MANAGER::dispatchInternal( const TOOL_EVENT& aEvent )
if( st->cofunc ) if( st->cofunc )
st->Push(); st->Push();
st->cofunc = new COROUTINE<int, const TOOL_EVENT&>( tr.second );
// as the state changes, the transition table has to be set up again // as the state changes, the transition table has to be set up again
st->transitions.clear(); st->transitions.clear();
st->cofunc = new COROUTINE<int, const TOOL_EVENT&>( tr.second );
// got match? Run the handler. // got match? Run the handler.
st->cofunc->Call( aEvent ); st->cofunc->Call( aEvent );

View File

@ -3,6 +3,7 @@
* *
* Copyright (C) 2013 CERN * Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch> * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -27,10 +28,14 @@
#include <cstdlib> #include <cstdlib>
#include <boost/context/fcontext.hpp>
#include <boost/version.hpp> #include <boost/version.hpp>
#include <type_traits>
#include "delegate.h" #if BOOST_VERSION <= 106000
#include <boost/context/fcontext.hpp>
#else
#include <boost/context/execution_context.hpp>
#endif
/** /**
* Class COROUNTINE. * Class COROUNTINE.
@ -53,13 +58,12 @@
* See coroutine_example.cpp for sample code. * See coroutine_example.cpp for sample code.
*/ */
template <class ReturnType, class ArgType> template <typename ReturnType, typename ArgType>
class COROUTINE class COROUTINE
{ {
public: public:
COROUTINE() : COROUTINE() :
m_saved( NULL ), m_self( NULL ), m_stack( NULL ), m_stackSize( c_defaultStackSize ), COROUTINE( nullptr )
m_running( false )
{ {
} }
@ -69,8 +73,7 @@ public:
*/ */
template <class T> template <class T>
COROUTINE( T* object, ReturnType(T::* ptr)( ArgType ) ) : COROUTINE( T* object, ReturnType(T::* ptr)( ArgType ) ) :
m_func( object, ptr ), m_self( NULL ), m_saved( NULL ), m_stack( NULL ), COROUTINE( std::bind( ptr, object, std::placeholders::_1 ) )
m_stackSize( c_defaultStackSize ), m_running( false )
{ {
} }
@ -78,9 +81,15 @@ public:
* Constructor * Constructor
* Creates a coroutine from a delegate object * Creates a coroutine from a delegate object
*/ */
COROUTINE( DELEGATE<ReturnType, ArgType> aEntry ) : COROUTINE( std::function<ReturnType(ArgType)> aEntry ) :
m_func( aEntry ), m_saved( NULL ), m_self( NULL ), m_stack( NULL ), m_func( std::move( aEntry ) ),
m_stackSize( c_defaultStackSize ), m_running( false ) 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 // Avoid not initialized members, and make static analysers quiet
m_args = 0; m_args = 0;
@ -89,18 +98,26 @@ public:
~COROUTINE() ~COROUTINE()
{ {
if( m_saved )
delete m_saved;
#if BOOST_VERSION >= 105600 #if BOOST_VERSION >= 105600
if( m_self ) delete m_callee;
delete m_self;
#endif #endif
#if BOOST_VERSION <= 106000
delete m_caller;
if( m_stack ) if( m_stack )
free( 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<COROUTINE*>;
#endif
public:
/** /**
* Function Yield() * Function Yield()
* *
@ -110,7 +127,12 @@ public:
*/ */
void Yield() 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 +144,11 @@ public:
void Yield( ReturnType& aRetVal ) void Yield( ReturnType& aRetVal )
{ {
m_retVal = 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 +156,9 @@ public:
* *
* Defines the entry point for the coroutine, if not set in the constructor. * Defines the entry point for the coroutine, if not set in the constructor.
*/ */
void SetEntry( DELEGATE<ReturnType, ArgType> aEntry ) void SetEntry( std::function<ReturnType(ArgType)> aEntry )
{ {
m_func = aEntry; m_func = std::move( aEntry );
} }
/* Function Call() /* Function Call()
@ -143,6 +169,10 @@ public:
*/ */
bool Call( ArgType aArgs ) bool Call( ArgType aArgs )
{ {
assert( m_callee == NULL );
assert( m_caller == NULL );
#if BOOST_VERSION <= 106000
// fixme: Clean up stack stuff. Add a guard // fixme: Clean up stack stuff. Add a guard
m_stack = malloc( c_defaultStackSize ); m_stack = malloc( c_defaultStackSize );
@ -151,22 +181,32 @@ public:
// correct the stack size // correct the stack size
m_stackSize -= ( (size_t) m_stack + m_stackSize - (size_t) sp ); m_stackSize -= ( (size_t) m_stack + m_stackSize - (size_t) sp );
#endif
assert( m_self == NULL );
assert( m_saved == NULL );
m_args = &aArgs; m_args = &aArgs;
#if BOOST_VERSION >= 105600
m_self = new boost::context::fcontext_t(); #if BOOST_VERSION < 105600
*m_self = boost::context::make_fcontext( sp, m_stackSize, callerStub ); 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 #else
m_self = boost::context::make_fcontext( sp, m_stackSize, callerStub ); m_callee = new context_type( std::allocator_arg_t(),
boost::context::fixedsize_stack( c_defaultStackSize ), &COROUTINE::callerStub );
#endif
#if BOOST_VERSION <= 106000
m_caller = new context_type();
#endif #endif
m_saved = new boost::context::fcontext_t();
m_running = true; m_running = true;
// off we go! // off we go!
jump( m_saved, m_self, reinterpret_cast<intptr_t>( this ) ); #if BOOST_VERSION <= 106000
jump( m_caller, m_callee, reinterpret_cast<intptr_t>( this ) );
#else
auto result = (*m_callee)( this );
*m_callee = std::move( std::get<0>( result ) );
#endif
return m_running; return m_running;
} }
@ -179,7 +219,12 @@ public:
*/ */
bool Resume() 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; return m_running;
} }
@ -208,61 +253,66 @@ private:
static const int c_defaultStackSize = 2000000; // fixme: make configurable static const int c_defaultStackSize = 2000000; // fixme: make configurable
/* real entry point of the coroutine */ /* real entry point of the coroutine */
#if BOOST_VERSION <= 106000
static void callerStub( intptr_t aData ) static void callerStub( intptr_t aData )
#else
static context_type callerStub( context_type caller, COROUTINE* cor )
#endif
{ {
// get pointer to self // get pointer to self
#if BOOST_VERSION <= 106000
COROUTINE<ReturnType, ArgType>* cor = reinterpret_cast<COROUTINE<ReturnType, ArgType>*>( aData ); COROUTINE<ReturnType, ArgType>* cor = reinterpret_cast<COROUTINE<ReturnType, ArgType>*>( aData );
#else
cor->m_caller = &caller;
#endif
// call the coroutine method // 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; cor->m_running = false;
// go back to wherever we came from. // go back to wherever we came from.
jump( cor->m_self, cor->m_saved, 0 ); // reinterpret_cast<intptr_t>( this )); #if BOOST_VERSION <= 106000
} jump( cor->m_callee, cor->m_caller, 0 );
///> 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,
intptr_t aP, bool aPreserveFPU = true )
{
#if BOOST_VERSION >= 105600
return boost::context::jump_fcontext( aOld, *aNew, aP, aPreserveFPU );
#else #else
return boost::context::jump_fcontext( aOld, aNew, aP, aPreserveFPU ); return caller;
#endif #endif
} }
template <typename T> ///> Wrapper for jump_fcontext to assure compatibility between different boost versions
struct strip_ref #if BOOST_VERSION <= 106000
static inline intptr_t jump( context_type* aOld, context_type* aNew,
intptr_t aP, bool aPreserveFPU = true )
{ {
typedef T result; #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 <typename T> std::function<ReturnType(ArgType)> m_func;
struct strip_ref<T&>
{
typedef T result;
};
DELEGATE<ReturnType, ArgType> m_func; bool m_running;
///< pointer to coroutine entry arguments. Stripped of references
///< to avoid compiler errors.
typename strip_ref<ArgType>::result* m_args;
ReturnType m_retVal;
///< saved caller context
boost::context::fcontext_t* m_saved;
///< saved coroutine context
boost::context::fcontext_t* m_self;
#if BOOST_VERSION <= 106000
///< coroutine stack ///< coroutine stack
void* m_stack; void* m_stack;
size_t m_stackSize; size_t m_stackSize;
#endif
bool m_running; ///< pointer to coroutine entry arguments. Stripped of references
///< to avoid compiler errors.
typename std::remove_reference<ArgType>::type* m_args;
ReturnType m_retVal;
///< saved caller context
context_type* m_caller;
///< saved coroutine context
context_type* m_callee;
}; };
#endif #endif

View File

@ -3,6 +3,7 @@
* *
* Copyright (C) 2013 CERN * Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch> * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -31,7 +32,7 @@
#include <tool/tool_event.h> #include <tool/tool_event.h>
#include <tool/tool_settings.h> #include <tool/tool_settings.h>
#include <tool/delegate.h> #include <functional>
class EDA_ITEM; class EDA_ITEM;
class TOOL_MANAGER; class TOOL_MANAGER;
@ -53,7 +54,9 @@ enum TOOL_TYPE
/// Unique identifier for tools /// Unique identifier for tools
typedef int TOOL_ID; typedef int TOOL_ID;
typedef DELEGATE<int, const TOOL_EVENT&> TOOL_STATE_FUNC;
using TOOL_STATE_FUNC = std::function<int(const TOOL_EVENT&)>;
/** /**
* Class TOOL_BASE * Class TOOL_BASE

View File

@ -3,6 +3,7 @@
* *
* Copyright (C) 2013 CERN * Copyright (C) 2013 CERN
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch> * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -113,7 +114,7 @@ template <class T>
void TOOL_INTERACTIVE::Go( int (T::* aStateFunc)( const TOOL_EVENT& ), void TOOL_INTERACTIVE::Go( int (T::* aStateFunc)( const TOOL_EVENT& ),
const TOOL_EVENT_LIST& aConditions ) const TOOL_EVENT_LIST& aConditions )
{ {
TOOL_STATE_FUNC sptr( static_cast<T*>( this ), aStateFunc ); TOOL_STATE_FUNC sptr = std::bind( aStateFunc, static_cast<T*>( this ), std::placeholders::_1 );
goInternal( sptr, aConditions ); goInternal( sptr, aConditions );
} }