diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 8de004e6d5e3e700b715f8185674f5237e445cb6..8ffeba6a52871439ed65091bf0e5d6dfed1cfd92 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -27,6 +27,7 @@ signal-ptr.t.cpp signal.t.cpp time-dependency.h time-dependency.t.cpp +signal-caster.h ) # Recreate correct path for the headers diff --git a/include/dynamic-graph/signal-caster.h b/include/dynamic-graph/signal-caster.h new file mode 100644 index 0000000000000000000000000000000000000000..2c2f6990c61784b7a0a9f2fd006e98b33db8a4db --- /dev/null +++ b/include/dynamic-graph/signal-caster.h @@ -0,0 +1,93 @@ +/* + * SignalCaster.h + * + * Created on: Jun 14, 2010 + * Author: blue + */ + +#ifndef SIGNALCASTER_H_ +#define SIGNALCASTER_H_ + +#include <map> +#include <typeinfo> +#include <boost/function/function1.hpp> +#include <boost/function/function2.hpp> +#include <boost/any.hpp> +#include <boost/tuple/tuple.hpp> +#include <iostream> + +namespace dynamicgraph { + +/*! This class allows serialization of a number of objects into (disp) and from + * (cast) std i/o streams. The transformation is done at run-time, i.e. SignalCaster + * doesn't know about the type of objects it casts to. It also allows registering of + * user-defined casts. A cast is identified by the compiler + * The mapping from a type to a serialization function is dynamic, hence it is more + * complex than a typical template-based compile-time resolve. So disp, cast and + * trace are costly functions and should be used as such. + */ +class SignalCaster { +public: + SignalCaster(); + virtual ~SignalCaster(); + + /*! Typedef of displayer functions that take an encapsulated 'any' object + * and displays, cast, or trace it on an output stream (serialization). + */ + typedef boost::function2<void, const boost::any&, std::ostream&> displayer_type; + typedef boost::function1<boost::any, std::istringstream&> caster_type; + typedef boost::function2<void, const boost::any&, std::ostream&> tracer_type; + + /// Displays an object using a registered displayer function + void disp(const boost::any& object, std::ostream& os); + /// Traces an object using a registered trace function + void trace(const boost::any& object, std::ostream& os); + /// Casts an object using a registered cast function + boost::any cast(const std::type_info&, std::istringstream& iss); + /// Registers a cast + void registerCast(const std::type_info& type, displayer_type displayer, + caster_type caster, tracer_type tracer); + /// Unregisters a cast + void unregisterCast(const std::type_info& type); + /// Checks if there is a displayer registered with type_name + bool existsCast(const std::type_info& type); +private: + /// Container for the three cast functions + typedef boost::tuple<displayer_type, caster_type, tracer_type> cast_functions_type; + /*! This map associates the typename of objects and the corresponding + * using boost::function with 'compatible' syntax + */ + std::map<std::string, cast_functions_type> functions_; +}; + + +/// The library-wide instance of SignalCaster +extern SignalCaster g_caster; + +/* + * The SignalCast registerer class. Can be used to automatically register a cast when instanced. + */ +class SignalCastRegisterer { +public: + SignalCastRegisterer(const std::type_info& type, SignalCaster::displayer_type displayer, + SignalCaster::caster_type caster, SignalCaster::tracer_type tracer); +}; + +/*! + * Global signal cast template (helper) functions + * + * Using these avoid using the typeid() operator and keeps the implementation + * details hidden. + */ +template<typename T> void signal_disp(const T& value, std::ostream& os) + { g_caster.disp(value, os); } + +template<typename T> T signal_cast(std::istringstream& iss) + { return boost::any_cast<T>(g_caster.cast(typeid(T), iss)); } + +template<typename T> void signal_trace(const T& value, std::ostream& os) + { g_caster.trace(value, os); } + +} // namespace dynamicgraph + +#endif /* SIGNALCASTER_H_ */ diff --git a/include/dynamic-graph/signal-ptr.t.cpp b/include/dynamic-graph/signal-ptr.t.cpp index ceb82f97233d3d197198e75740f27af5698e1d88..73da85fc278bc305cfff7c223ab4d6633fffbcab 100644 --- a/include/dynamic-graph/signal-ptr.t.cpp +++ b/include/dynamic-graph/signal-ptr.t.cpp @@ -123,7 +123,7 @@ plug( SignalBase<Time>* unknown_ref ) } catch(...) { - dgTDEBUG(25) << "FFatal error."<< std::endl; + dgTDEBUG(25) << "Fatal error."<< std::endl; transmitAbstract = false; DG_THROW ExceptionSignal( ExceptionSignal::PLUG_IMPOSSIBLE, "Compl. Uncompatible types for plugin.", @@ -236,8 +236,8 @@ display( std::ostream& os ) const } else { - if(! isAbstractPluged()) os << " UNPLUGED"; - else if(autoref()) os << " AUTOPLUGED"; + if(! isAbstractPluged()) os << " UNPLUGGED"; + else if(autoref()) os << " AUTOPLUGGED"; } dgTDEBUGOUT(25); diff --git a/include/dynamic-graph/signal.h b/include/dynamic-graph/signal.h index e3a282afe572b588ea4cb9ae6645525d99c39147..551c46efc2de1b75167307bcbdc92628ddcdd7e5 100644 --- a/include/dynamic-graph/signal.h +++ b/include/dynamic-graph/signal.h @@ -95,6 +95,11 @@ protected: Signal( std::string name ); virtual ~Signal( void ) {} + /* --- Generic In/Out function --- */ + virtual void get( std::ostream& value ) const; + virtual void set( std::istringstream& value ) ; + virtual void trace( std::ostream& os ) const; + /* --- Generic Set function --- */ virtual void setConstant( const T& t ); virtual void setReference( const T* t,Mutex *mutexref=NULL ); diff --git a/include/dynamic-graph/signal.t.cpp b/include/dynamic-graph/signal.t.cpp index 5ca90661737ef3d2a4d1cdb8cf494ebf2bf88480..9286e40244c86bb8bc82cef485c3d1b702b4014b 100644 --- a/include/dynamic-graph/signal.t.cpp +++ b/include/dynamic-graph/signal.t.cpp @@ -24,6 +24,7 @@ #include <dynamic-graph/signal.h> +#include <dynamic-graph/signal-caster.h> #undef VP_TEMPLATE_DEBUG_MODE #define VP_TEMPLATE_DEBUG_MODE 0 @@ -54,52 +55,52 @@ Signal( std::string name ) /* -------------------------------------------------------------------------- */ -//template< class T,class Time > -//void Signal<T,Time>:: -//set( std::istringstream& stringValue ) -//{ -// try -// { -// (*this) = sotSignalCast<T>::cast( stringValue ); -// } -// catch DG_RETHROW -// catch (...) -// { SOT_THROW ExceptionSignal( ExceptionSignal::SET_IMPOSSIBLE, -// "Set operation not possible with this signal. ", -// "(bad cast while setting %s).",this->getName().c_str()); -// } -// -//} -// -//template< class T,class Time > -//void Signal<T,Time>:: -//get( std::ostream& os ) const -//{ -// try { sotSignalCast<T>::disp( this->accessCopy(),os ); } -// catch DG_RETHROW -// catch (...) -// { SOT_THROW ExceptionSignal( ExceptionSignal::SET_IMPOSSIBLE, -// "get operation not possible with this signal. ", -// "(bad cast while getting value from %s).", -// SignalBase<Time>::getName().c_str()); -// } -// -//} -// -//template< class T,class Time > -//void Signal<T,Time>:: -//trace( std::ostream& os ) const -//{ -// try { sotSignalCast<T>::trace( this->accessCopy(),os ); } -// catch DG_RETHROW -// catch (...) -// { SOT_THROW ExceptionSignal( ExceptionSignal::SET_IMPOSSIBLE, -// "TRACE operation not possible with this signal. ", -// "(bad cast while getting value from %s).", -// SignalBase<Time>::getName().c_str()); -// } -// -//} +template< class T,class Time > +void Signal<T,Time>:: +set( std::istringstream& stringValue ) +{ + try + { + (*this) = signal_cast<T>( stringValue ); + } + catch DG_RETHROW + catch (...) + { DG_THROW ExceptionSignal( ExceptionSignal::SET_IMPOSSIBLE, + "Set operation not possible with this signal. ", + "(bad cast while setting %s).",this->getName().c_str()); + } + +} + +template< class T,class Time > +void Signal<T,Time>:: +get( std::ostream& os ) const +{ + try { signal_disp<T>( this->accessCopy(),os ); } + catch DG_RETHROW + catch (...) + { DG_THROW ExceptionSignal( ExceptionSignal::SET_IMPOSSIBLE, + "get operation not possible with this signal. ", + "(bad cast while getting value from %s).", + SignalBase<Time>::getName().c_str()); + } + +} + +template< class T,class Time > +void Signal<T,Time>:: +trace( std::ostream& os ) const +{ + try { signal_trace<T>( this->accessCopy(),os ); } + catch DG_RETHROW + catch (...) + { DG_THROW ExceptionSignal( ExceptionSignal::SET_IMPOSSIBLE, + "TRACE operation not possible with this signal. ", + "(bad cast while getting value from %s).", + SignalBase<Time>::getName().c_str()); + } + +} /* -------------------------------------------------------------------------- */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3161df42b2c64f5a264c4477b57de826a4934cf3..4d63eb70237293e23d8629e20f3ed88e15c4735f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,6 +23,7 @@ ADD_LIBRARY(${LIBRARY_NAME} exception/exception-signal.cpp signal/signal-array.cpp + signal/signal-caster.cpp ) SET_TARGET_PROPERTIES(${LIBRARY_NAME} diff --git a/src/signal/signal-caster.cpp b/src/signal/signal-caster.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0ad45ffd29e3ea8a11f7ce37a4a65829b1271825 --- /dev/null +++ b/src/signal/signal-caster.cpp @@ -0,0 +1,99 @@ +/* + * SignalCaster.cpp + * + * Created on: Jun 14, 2010 + * Author: blue + */ + +#include <dynamic-graph/signal-caster.h> +#include <dynamic-graph/dynamic-graph-api.h> +#include <exception> +#include <boost/lambda/bind.hpp> +#include <string> +#include <sstream> +#include <algorithm> + +using namespace std; +using namespace boost; + +namespace dynamicgraph { + +SignalCaster::SignalCaster() { + // nothing to initialize +} + +SignalCaster::~SignalCaster() { + // no special cleanup to do +} + +void SignalCaster::registerCast(const type_info& type, SignalCaster::displayer_type displayer, + SignalCaster::caster_type caster, SignalCaster::tracer_type tracer) { + if ( existsCast(type) ) + throw ( 1 ); //TODO: throw "cast already registered for type" exception + functions_[type.name()] = cast_functions_type(displayer,caster, tracer); +} + +void SignalCaster::unregisterCast(const std::type_info& type) { + size_t n = functions_.erase(type.name()); + if ( 0 == n ) // erase did not find element + throw ( 1 ); // TODO: throw Cast not registered exception +} + +bool SignalCaster::existsCast(const type_info& type) { + return functions_.find(type.name()) != functions_.end(); +} + +void SignalCaster::disp(const any& object, ostream& os) { + const char* type_name = object.type().name(); + map<string, cast_functions_type>::iterator it = + functions_.find(type_name); + if ( it == functions_.end() ) + throw 1;; //TODO: throw "cast not registered" exception + (*it).second.get<0>()(object, os); // call display function (tuple index 0) +} + +void SignalCaster::trace(const any& object, ostream& os) { + const char* type_name = object.type().name(); + map<string, cast_functions_type>::iterator it = + functions_.find(type_name); + if ( it == functions_.end() ) + throw 1;; //TODO: throw "cast not registered" exception + (*it).second.get<2>()(object, os); // call trace function (tuple index 2) +} + +any SignalCaster::cast(const type_info& type, istringstream& iss) { + const char* type_name = type.name(); + map<string, cast_functions_type>::iterator it = functions_.find(type_name); + if ( it == functions_.end() ) + throw 1;; //TODO: throw "cast not registered" exception + return (*it).second.get<1>()(iss); // call cast function (tuple index 1) +} + + +/// The global instance of the caster class. +DYNAMICGRAPH_EXPORT SignalCaster g_caster; + +SignalCastRegisterer::SignalCastRegisterer(const std::type_info& type, SignalCaster::displayer_type displayer, + SignalCaster::caster_type caster, SignalCaster::tracer_type tracer) +{ + g_caster.registerCast(type, displayer, caster, tracer); +} + +/// Default casts, such as casts already supported by std::iostream +template<typename T> class DefaultCastRegisterer : public SignalCastRegisterer { +public: + DefaultCastRegisterer() : SignalCastRegisterer(typeid(T), disp, cast, trace) {} + static boost::any cast(istringstream& iss) { T inst; iss >> inst; return inst; } + static void disp(const any& object, ostream& os) { os << any_cast<T>(object) << endl;; } + static void trace(const any& object, ostream& os) { disp(object,os); } +}; + +/// Registers useful casts +namespace { + DefaultCastRegisterer<double> double_reg; + DefaultCastRegisterer<int> int_reg; + DefaultCastRegisterer<unsigned int> uint_reg; +} + +} // namespace dynamicgraph +