Commit 5452c703 authored by Guilhem Saurel's avatar Guilhem Saurel
Browse files

Merge branch 'cpp11' into release/4.3.0

parents 53a7bbf8 590bb017
......@@ -74,6 +74,7 @@ SET(${PROJECT_NAME}_HEADERS
include/${CUSTOM_HEADER_DIR}/signal.t.cpp
include/${CUSTOM_HEADER_DIR}/time-dependency.h
include/${CUSTOM_HEADER_DIR}/time-dependency.t.cpp
# Kept for a brittle backward compatiblity.
include/${CUSTOM_HEADER_DIR}/signal-caster.h
include/${CUSTOM_HEADER_DIR}/signal-cast-helper.h
include/${CUSTOM_HEADER_DIR}/all-signals.h
......@@ -117,8 +118,6 @@ SET(${PROJECT_NAME}_SOURCES
src/mt/process-list.cpp
src/signal/signal-array.cpp
src/signal/signal-caster.cpp
src/signal/signal-cast-helper.cpp
src/command/value.cpp
src/command/command.cpp
......
......@@ -23,14 +23,9 @@ class OutStringStream;
class PluginLoader;
class PoolStorage;
class SignalCaster;
class SignalCastRegisterer;
class Tracer;
class TracerRealTime;
template <typename T> class DefaultCastRegisterer;
template <typename T, typename Time> class Signal;
template <typename Time> class SignalArray;
......
......@@ -5,191 +5,7 @@
#ifndef DYNAMIC_GRAPH_SIGNAL_CASTER_HELPER_HH
#define DYNAMIC_GRAPH_SIGNAL_CASTER_HELPER_HH
#include <map>
#include <typeinfo>
#include <vector>
#include <boost/any.hpp>
#include <boost/format.hpp>
#include <boost/function/function1.hpp>
#include <boost/function/function2.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/tuple/tuple.hpp>
#include <dynamic-graph/eigen-io.h>
#include "dynamic-graph/exception-signal.h"
#include "dynamic-graph/signal-caster.h"
#include <dynamic-graph/dynamic-graph-api.h>
namespace dynamicgraph {
/* --- NON GENERIC CASTER ------------------------------------------------- */
/// This class can be used to register default casts, i.e. casts
/// already supported by the object to an std::iostream through the
/// operators >> and << .
template <typename T>
class DefaultCastRegisterer : public SignalCastRegisterer {
public:
DefaultCastRegisterer()
: SignalCastRegisterer(typeid(T), disp, cast, trace) {}
static boost::any cast(std::istringstream &iss);
static void disp(const boost::any &object, std::ostream &os) {
os << boost::any_cast<T>(object) << std::endl;
}
static void trace(const boost::any &object, std::ostream &os) {
disp(object, os);
}
};
/// A default version of the caster, to serialize directly from
/// std::in.
template <typename T>
boost::any DefaultCastRegisterer<T>::cast(std::istringstream &iss) {
T inst;
iss >> inst;
if (iss.fail()) {
boost::format fmt("failed to serialize %s ");
fmt % iss.str();
throw ExceptionSignal(ExceptionSignal::GENERIC, fmt.str());
}
return inst;
}
/* --- GENERIC CASTER ----------------------------------------------------- */
/*!
* This class is only used to group together static functions who differ by
* a template parameter. It is never actually instanced
* (the private constructor
* makes sure of that).
* Typical use of this class is to add the caster in the dg graph:
* dynamicgraph::SignalCastRegisterer sotCastRegisterer_TYPE
* (typeid(TYPE),
* SignalCast<TYPE>::disp_,
* SignalCast<TYPE>::cast_,
* SignalCast<TYPE>::trace_);
* NMSD: I don't really understand the use of this additional class. IMHO
* (comme on dit), it should be possible to rewrite the same-spec macros
* using specialization of the template class DefaultCastRegisterer. No?
*/
template <class T> class SignalCast {
public:
static T cast(std::istringstream &) { throw 1; }
static void disp(const T &, std::ostream &) { throw 1; }
static void trace(const T &t, std::ostream &os) { disp(t, os); }
public:
// adapter functions for SignalCast
static boost::any cast_(std::istringstream &stringValue) {
return boost::any_cast<T>(cast(stringValue));
}
static void disp_(const boost::any &t, std::ostream &os) {
disp(boost::any_cast<T>(t), os);
}
static void trace_(const boost::any &t, std::ostream &os) {
trace(boost::any_cast<T>(t), os);
}
private:
SignalCast() {}
};
} // namespace dynamicgraph
/* -------------------------------------------------------------------------- */
/* --- MACROS --------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* Declaration macro: one instance of each class needs to be present in
* order for casts to be registered.
*/
#define DG_SIGNAL_CAST_DECLARATION(TYPE) \
::dynamicgraph::SignalCastRegisterer sotCastRegisterer_##TYPE( \
typeid(TYPE), SignalCast<TYPE>::disp_, SignalCast<TYPE>::cast_, \
SignalCast<TYPE>::trace_)
#define DG_SIGNAL_CAST_DECLARATION_NAMED(TYPE, NAME) \
::dynamicgraph::SignalCastRegisterer sotCastRegisterer_##NAME( \
typeid(TYPE), SignalCast<TYPE>::disp_, SignalCast<TYPE>::cast_, \
SignalCast<TYPE>::trace_)
/* Standard definition macros: the three functions can be specified
* in the macros. To define then in the cpp, just put ';' in the args.
*/
#define DG_SIGNAL_CAST_FULL_DEFINITION(TYPE, CAST, DISP, TRACE) \
template <> class SignalCast<TYPE> { \
public: \
static TYPE cast(std::istringstream &iss) CAST \
static void disp(TYPE const &t, std::ostream &os) DISP \
static void trace(TYPE const &t, std::ostream &os) TRACE public \
: static boost::any cast_(std::istringstream &stringValue) { \
return boost::any_cast<TYPE>(cast(stringValue)); \
} \
static void disp_(const boost::any &t, std::ostream &os) { \
disp(boost::any_cast<TYPE>(t), os); \
} \
static void trace_(const boost::any &t, std::ostream &os) { \
trace(boost::any_cast<TYPE>(t), os); \
} \
}
/* Standard definition macros: the functions <cast> and <disp> have
* to be implemented in the cpp files. The function <trace> is
* implemented as a proxy on <disp>.
*/
#define DG_SIGNAL_CAST_DEFINITION_HPP(TYPE) \
DG_SIGNAL_CAST_FULL_DEFINITION(TYPE, ;, ;, { disp(t, os); })
/* Lazy definition: <cast> and <disp> are to proxys on the standard
* std input (>>) and output (<<). The function <trace> has to be
* implemented in the cpp.
*/
#define DG_SIGNAL_CAST_DEFINITION_TRACE_HPP(TYPE, TRACE) \
DG_SIGNAL_CAST_FULL_DEFINITION(TYPE, \
{ \
TYPE res; \
iss >> res; \
return res; \
}, \
{ os << t << std::endl; }, TRACE)
/* Lazy lazy definition: the three functions are implemented as
* proxys on std::io operation.
*/
#define DG_SIGNAL_CAST_DEFINITION(TYPE) \
DG_SIGNAL_CAST_FULL_DEFINITION(TYPE, \
{ \
TYPE res; \
iss >> res; \
return res; \
}, \
{ os << t << std::endl; }, { disp(t, os); })
/* Lazy definition of <cast> and <disp> with implementation of
* <trace> in the cpp.
*/
#define DG_SIGNAL_CAST_DEFINITION_TRACE(TYPE) \
DG_SIGNAL_CAST_FULL_DEFINITION(TYPE, \
{ \
TYPE res; \
iss >> res; \
return res; \
}, \
{ os << t << std::endl; }, \
;)
/* Macro to add the define SignalCast in the dg graph. Typical use is:
* DG_ADD_CASTER( Matrix,matrix )
*/
#define DG_ADD_CASTER(TYPE, ID) \
::dynamicgraph::SignalCastRegisterer sotCastRegisterer_##ID( \
typeid(TYPE), SignalCast<TYPE>::disp_, SignalCast<TYPE>::cast_, \
SignalCast<TYPE>::trace_)
#pragma warning "This file is now useless"
#endif // #ifndef DYNAMIC_GRAPH_SIGNAL_CASTER_HELPER_HH
......@@ -5,113 +5,134 @@
#ifndef DYNAMIC_GRAPH_SIGNAL_CASTER_HH
#define DYNAMIC_GRAPH_SIGNAL_CASTER_HH
#include <map>
#include <typeinfo>
#include <vector>
#include <boost/any.hpp>
#include <boost/format.hpp>
#include <boost/function/function1.hpp>
#include <boost/function/function2.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/tuple/tuple.hpp>
#include "dynamic-graph/exception-signal.h"
#include <dynamic-graph/dynamic-graph-api.h>
#include <dynamic-graph/linear-algebra.h>
#include <dynamic-graph/eigen-io.h>
namespace dynamicgraph {
/// This singleton 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 DYNAMIC_GRAPH_DLLAPI SignalCaster {
public:
virtual ~SignalCaster();
/// Destroy the unique instance.
static void destroy();
/// 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;
/// Get a reference to the unique object of the class.
static SignalCaster *getInstance(void);
/// 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);
/// Unregister 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) const;
/// Return the list of type names registered.
std::vector<std::string> listTypenames() const;
private:
/// Container for the three cast functions.
typedef boost::tuple<displayer_type, caster_type, tracer_type>
cast_functions_type;
/// \brief Retrieve cast structure from its name.
cast_functions_type &getCast(const std::string &type_name);
/// This map associates the typename of objects and the corresponding
/// using boost::function with 'compatible' syntax
std::map<std::string, cast_functions_type> functions_;
std::map<std::string, const std::type_info *> type_info_;
private:
explicit SignalCaster();
/// Pointer to the unique instance of the class.
static SignalCaster *instance_;
};
/// The SignalCast registerer class. Can be used to automatically
/// register a cast when instanced somewhere in a cpp file. Pass the
/// typeid () of the type you want to register a cast to as the first
/// argument. The code is provided here so the class does not need
/// to be exported.
class DYNAMIC_GRAPH_DLLAPI SignalCastRegisterer {
public:
inline SignalCastRegisterer(const std::type_info &type,
SignalCaster::displayer_type displayer,
SignalCaster::caster_type caster,
SignalCaster::tracer_type tracer) {
SignalCaster::getInstance()->registerCast(type, displayer, caster, tracer);
/// Inherit from this class if you want to keep default implementation for some
/// functions.
template <typename T> struct signal_io_base {
/// serialize a signal value.
inline static void disp (const T &value, std::ostream &os) { os << value; }
/// deserialize a signal value.
inline static T cast (std::istringstream &is) {
T inst;
is >> inst;
if (is.fail()) {
throw ExceptionSignal(ExceptionSignal::GENERIC,
"failed to serialize " + is.str());
}
return inst;
}
/// write a signal value to log file
inline static void trace(const T &value, std::ostream &os) { os << value; }
};
/// 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) {
SignalCaster::getInstance()->disp(value, os);
/// Inherit from this class if tracing is not implemented for a given type.
template <typename T> struct signal_io_unimplemented {
inline static void disp (const T &, std::ostream &) {
throw std::logic_error("this disp is not implemented.");
}
inline static T cast (std::istringstream &) {
throw std::logic_error("this cast is not implemented.");
}
inline static void trace(const T &, std::ostream &) {
throw std::logic_error("this trace is not implemented.");
}
};
/// Class used for I/O operations in Signal<T,Time>
template <typename T> struct signal_io : signal_io_base<T> {};
/// Template specialization of signal_disp for Eigen objects
template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
struct signal_io<Eigen::Matrix< _Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols > >
: signal_io_base <Eigen::Matrix< _Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols > >
{
typedef Eigen::Matrix< _Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols > matrix_type;
inline static void disp(const matrix_type &value, std::ostream &os) {
static const Eigen::IOFormat row_format (Eigen::StreamPrecision,
Eigen::DontAlignCols, " ", " ", "", "", "", "");
os << value.format(row_format);
}
template <typename T> T signal_cast(std::istringstream &iss) {
return boost::any_cast<T>(SignalCaster::getInstance()->cast(typeid(T), iss));
inline static void trace(const matrix_type &value, std::ostream &os) {
static const Eigen::IOFormat row_format (Eigen::StreamPrecision,
Eigen::DontAlignCols, "\t", "\t", "", "", "", "");
os << value.format(row_format);
}
};
/// Template specialization of signal_io for Eigen quaternion objects
template<typename _Scalar, int _Options>
struct signal_io<Eigen::Quaternion< _Scalar, _Options> >
: signal_io_base<Eigen::Quaternion< _Scalar, _Options> >
{
typedef Eigen::Quaternion< _Scalar, _Options> quat_type;
typedef Eigen::Matrix< _Scalar, 4, 1, _Options> matrix_type;
inline static void disp(const quat_type &value, std::ostream &os) {
signal_io<matrix_type>::disp(value.coeffs(), os);
}
template <typename T> void signal_trace(const T &value, std::ostream &os) {
SignalCaster::getInstance()->trace(value, os);
inline static quat_type cast (std::istringstream &is) {
return quat_type(signal_io<matrix_type>::cast(is));
}
inline static void trace(const quat_type &value, std::ostream &os) {
signal_io<matrix_type>::trace(value.coeffs(), os);
}
};
/// Template specialization of signal_io for std::string.
/// Do not print '\n' at the end.
template <> struct signal_io<std::string> : signal_io_base<std::string>
{
inline static std::string cast (std::istringstream &iss) { return iss.str(); }
};
/// Template specialization of signal_io for double
/// to workaround the limitations of the stream based approach.
///
/// When dealing with double: displaying a double on a stream
/// is *NOT* the opposite of reading a double from a stream.
///
/// In practice, it means that there is no way to read
/// a NaN, +inf, -inf from a stream!
///
/// To workaround this problem, parse special values manually
/// (the strings used are the one produces by displaying special
/// values on a stream).
template <> struct signal_io<double> : signal_io_base<double> {
inline static double cast (std::istringstream &iss) {
std::string tmp (iss.str());
if (tmp == "nan")
return std::numeric_limits<double>::quiet_NaN();
else if (tmp == "inf" || tmp == "+inf")
return std::numeric_limits<double>::infinity();
else if (tmp == "-inf")
return -1. * std::numeric_limits<double>::infinity();
try {
return boost::lexical_cast<double>(tmp);
} catch (boost::bad_lexical_cast &) {
boost::format fmt("failed to serialize %s (to double)");
fmt % tmp;
throw ExceptionSignal(ExceptionSignal::GENERIC, fmt.str());
}
}
};
} // end of namespace dynamicgraph.
#endif //! DYNAMIC_GRAPH_SIGNAL_CASTER_HH
......@@ -30,18 +30,18 @@ Signal<T, Time>::Signal(std::string name)
template <class T, class Time>
void Signal<T, Time>::set(std::istringstream &stringValue) {
(*this) = signal_cast<T>(stringValue);
(*this) = signal_io<T>::cast(stringValue);
}
template <class T, class Time>
void Signal<T, Time>::get(std::ostream &os) const {
signal_disp<T>(this->accessCopy(), os);
signal_io<T>::disp(this->accessCopy(), os);
}
template <class T, class Time>
void Signal<T, Time>::trace(std::ostream &os) const {
try {
signal_trace<T>(this->accessCopy(), os);
signal_io<T>::trace(this->accessCopy(), os);
} catch DG_RETHROW catch (...) {
DG_THROW ExceptionSignal(ExceptionSignal::SET_IMPOSSIBLE,
"TRACE operation not possible with this signal. ",
......
// -*- c++-mode -*-
// Copyright 2010 François Bleibel
// Thomas Moulard,
// Olivier Stasse,
// Nicolas Mansard
//
#include <algorithm>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/lambda/bind.hpp>
#include <dynamic-graph/dynamic-graph-api.h>
#include <dynamic-graph/exception-signal.h>
#include <dynamic-graph/linear-algebra.h>
#include <dynamic-graph/signal-cast-helper.h>
#include <dynamic-graph/signal-caster.h>
#include <exception>
#include <sstream>
#include <string>
namespace dynamicgraph {
// Define a custom implementation of the DefaultCastRegisterer
// to workaround the limitations of the stream based approach.
// When dealing with double: displaying a double on a stream
// is *NOT* the opposite of reading a double from a stream.
//
// In practice, it means that there is no way to read
// a NaN, +inf, -inf from a stream!
//
// To workaround this problem, parse special values manually
// (the strings used are the one produces by displaying special
// values on a stream).
template <>
inline boost::any DefaultCastRegisterer<double>::cast(std::istringstream &iss) {
std::string tmp;
iss >> tmp;
if (tmp == "nan")
return std::numeric_limits<double>::quiet_NaN();
else if (tmp == "inf" || tmp == "+inf")
return std::numeric_limits<double>::infinity();
else if (tmp == "-inf")
return -1. * std::numeric_limits<double>::infinity();
try {
return boost::lexical_cast<double>(tmp);
} catch (boost::bad_lexical_cast &) {
boost::format fmt("failed to serialize %s (to double)");
fmt % tmp;
throw ExceptionSignal(ExceptionSignal::GENERIC, fmt.str());
}
}
// for std::string, do not check failure. If input stream contains an
// empty string, iss.fail() returns true and an exception is thrown
template <>
inline boost::any
DefaultCastRegisterer<std::string>::cast(std::istringstream &iss) {
std::string inst(iss.str());
return inst;
}
// for std::string, do not add std::endl at the end of the stream.
template <>
inline void DefaultCastRegisterer<std::string>::disp(const boost::any &object,
std::ostream &os) {
os << boost::any_cast<std::string>(object);
}
/// Registers useful casts
namespace {
DefaultCastRegisterer<double> double_reg;
DefaultCastRegisterer<int> int_reg;
DefaultCastRegisterer<unsigned int> uint_reg;
DefaultCastRegisterer<bool> bool_reg;
DefaultCastRegisterer<dynamicgraph::Vector> vectorCastRegisterer;
DefaultCastRegisterer<dynamicgraph::Matrix> matrixCastRegisterer;
DefaultCastRegisterer<boost::posix_time::ptime> ptimeCastRegisterer;
DefaultCastRegisterer<std::string> stringCastRegisterer;
} // end of anonymous namespace.
} // namespace dynamicgraph
// -*- c++-mode -*-
// Copyright 2010 François Bleibel
// Thomas Moulard,
// Olivier Stasse
//
#include <algorithm>
#include <boost/lambda/bind.hpp>
#include <dynamic-graph/dynamic-graph-api.h>
#include <dynamic-graph/exception-signal.h>
#include <dynamic-graph/signal-caster.h>
#include <exception>
#include <sstream>
#include <string>
#include <dynamic-graph/linear-algebra.h>
namespace dynamicgraph {
SignalCaster::SignalCaster() {}
SignalCaster::~SignalCaster() {}
void SignalCaster::destroy() {
delete instance_;
instance_ = 0;
}
void SignalCaster::registerCast(const std::type_info &type,
SignalCaster::displayer_type displayer,
SignalCaster::caster_type caster,
SignalCaster::tracer_type tracer) {
if (existsCast(type)) {
// If type name has already been registered for same type, do not throw.
if (type_info_[type.name()] != &type) {
std::string typeName(type.name());
std::ostringstream os;
os << "cast already registered for typename " << typeName << "\n"
<< "and types differ: " << &type << " != " << type_info_[type.name()]
<< ".\n"
<< "A possible reason is that the dynamic"
<< " library defining this type\n"