Commit 35a6272f authored by Francois Bleibel's avatar Francois Bleibel
Browse files

Implemented dynamic casting facility from signals to std::streams

* New class SignalCaster
* Re-added the get, set and trace commands to signals
parent 9dd7ed09
......@@ -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
......
/*
* 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_ */
......@@ -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);
......
......@@ -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 );
......
......@@ -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());
}
}
/* -------------------------------------------------------------------------- */
......
......@@ -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}
......
/*
* 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
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment