signal-caster.h 4.59 KB
Newer Older
Thomas Moulard's avatar
Thomas Moulard committed
1
2
3
4
5
// -*- c++-mode -*-
// Copyright 2010 François Bleibel Thomas Moulard, Olivier Stasse
//

#ifndef DYNAMIC_GRAPH_SIGNAL_CASTER_HH
Bergé's avatar
Bergé committed
6
7
8
9
#define DYNAMIC_GRAPH_SIGNAL_CASTER_HH
#include <map>
#include <typeinfo>
#include <vector>
Thomas Moulard's avatar
Thomas Moulard committed
10

Bergé's avatar
Bergé committed
11
12
13
14
15
16
#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>
Thomas Moulard's avatar
Thomas Moulard committed
17

Bergé's avatar
Bergé committed
18
#include "dynamic-graph/exception-signal.h"
19
#include <dynamic-graph/dynamic-graph-api.h>
Joseph Mirabel's avatar
Joseph Mirabel committed
20
#include <dynamic-graph/linear-algebra.h>
Thomas Moulard's avatar
Thomas Moulard committed
21

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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;
Thomas Moulard's avatar
Thomas Moulard committed
45

46
47
48
49
50
51
52
53
  /// 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);
  /// 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,
54
                    caster_type caster);
55
56
57
58
59
60
  /// 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;
Thomas Moulard's avatar
Thomas Moulard committed
61

62
63
private:
  /// Container for the three cast functions.
64
  typedef boost::tuple<displayer_type, caster_type>
65
      cast_functions_type;
66

67
68
  /// \brief Retrieve cast structure from its name.
  cast_functions_type &getCast(const std::string &type_name);
Thomas Moulard's avatar
Thomas Moulard committed
69

70
71
72
  /// This map associates the typename of objects and the corresponding
  /// using boost::function with 'compatible' syntax
  std::map<std::string, cast_functions_type> functions_;
73

74
  std::map<std::string, const std::type_info *> type_info_;
Thomas Moulard's avatar
Thomas Moulard committed
75

76
77
78
79
80
private:
  explicit SignalCaster();
  /// Pointer to the unique instance of the class.
  static SignalCaster *instance_;
};
Thomas Moulard's avatar
Thomas Moulard committed
81

82
83
84
85
86
87
88
89
/// 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,
90
                              SignalCaster::displayer_type displayer,
91
92
                              SignalCaster::caster_type caster) {
    SignalCaster::getInstance()->registerCast(type, displayer, caster);
Thomas Moulard's avatar
Thomas Moulard committed
93
  }
94
};
Thomas Moulard's avatar
Thomas Moulard committed
95

96
97
98
99
100
101
102
/// 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);
}
Thomas Moulard's avatar
Thomas Moulard committed
103

104
105
106
template <typename T> T signal_cast(std::istringstream &iss) {
  return boost::any_cast<T>(SignalCaster::getInstance()->cast(typeid(T), iss));
}
Bergé's avatar
Bergé committed
107

Joseph Mirabel's avatar
Joseph Mirabel committed
108
109
110
111
112
113
114
115
116
117
118
/// Template class used to display a signal value.
template <typename T> struct signal_trace {
inline static void run(const T &value, std::ostream &os) { os << value << '\n'; }
};

/// Template specialization of signal_trace for Eigen objects
template <typename Derived> struct signal_trace<Eigen::DenseBase<Derived> > {
inline static void run(const Eigen::DenseBase<Derived> &value, std::ostream &os) {
  static const Eigen::IOFormat row_format (Eigen::StreamPrecision,
      Eigen::DontAlignCols, ", ", ", ", "", "", "", "\n");
  os << value.format(row_format);
119
}
Joseph Mirabel's avatar
Joseph Mirabel committed
120
121
};

122
} // end of namespace dynamicgraph.
Thomas Moulard's avatar
Thomas Moulard committed
123

124
#endif //! DYNAMIC_GRAPH_SIGNAL_CASTER_HH