test_typeid.cxx
Go to the documentation of this file.
1 /**
2  * The idea is that there are objects of a base interface IComponent
3  * which may also implement some other interface, here IPort. The
4  * objects are initially known through IComponent and a templated
5  * function, transfer(), must be called on these objects but through a
6  * middle sublcass which contains some needed type info, here Port<T>.
7  *
8  * The solution is to create a context (CallTransfer and
9  * CallTransferT<> structs) which knows the type T and then register a
10  * number of instances of this context using the type_info::name() of
11  * the instantiated T.
12  *
13  * Then, the base interface IPort has a pure abstract method to return
14  * the type_info::name() supplied by the subclass. This is used to
15  * look up the corresponding context which takes the base IPort
16  * objects and dynamic_cast's them to the needed subclass.
17  */
18 
19 #include "WireCellUtil/Testing.h"
20 #include "WireCellUtil/Interface.h"
21 #include <iostream>
22 #include <typeinfo>
23 #include <map>
24 #include <string>
25 
26 using namespace std;
27 
28 
29 struct IPort {
30  virtual ~IPort() {};
31  virtual std::string port_type_name() const = 0;
32 };
33 
34 template<typename T>
35 struct Port : public IPort {
36  typedef T port_type;
37  virtual ~Port() {}
38  virtual std::string port_type_name() const {
39  return typeid(port_type).name();
40  }
41  virtual bool put(const port_type& in) { return false; }
42  virtual bool get(port_type& out) const { return false; }
43  virtual T make() const { return 0; }
44 };
45 
46 struct SubI : public Port<int> {
47  virtual ~SubI() {}
48  virtual bool get(port_type& out) const {
49  out = 42;
50  cerr << "SubI::get(" << out << ")" << endl;
51  return true;
52  }
53 };
54 struct SubF : public Port<float> {
55  virtual ~SubF() {}
56  virtual bool get(port_type& out) const {
57  out = 6.9;
58  cerr << "SubF::get(" << out << ")" << endl;
59  return true;
60  }
61 };
62 
63 struct SubFIn : public Port<float> {
64  virtual ~SubFIn() {}
65  virtual bool put(const port_type& in) {
66  cerr << "SubFIn::put(" << in << ")" << endl;
67  return true;
68  }
69  virtual bool get(port_type& out) const {
70  cerr << "SubIn::get() can not provide data" << endl;
71  return true;
72  }
73 
74 };
75 
76 struct SubFOut : public Port<float> {
77  virtual ~SubFOut() {}
78  virtual bool put(const port_type& in) {
79  cerr << "SubFOut::put(" << in << ") can not accept data" << endl;
80  return false;
81  }
82  virtual bool get(port_type& out) const {
83  out = 6.9;
84  cerr << "SubFOut::get(" << out << ")" << endl;
85  return true;
86  }
87 };
88 
89 
90 template<typename A, typename B>
91 bool transfer(const A& a, B& b)
92 {
93  cerr << "transfer: "
94  << typeid(A).name() << "<->" << typeid(a).name() << " "
95  << typeid(B).name() << "<->" << typeid(b).name() << endl;
96 
97 
98  if (a.port_type_name() != b.port_type_name()) {
99  cerr << "Port type mismatch: "
100  << a.port_type_name() << " != " << b.port_type_name() << endl;
101  return false;
102  }
103  typename A::port_type dat;
104  if (!a.get(dat)) {
105  cerr << "Failed to get output of type " << a.port_type_name() << endl;
106  return false;
107  }
108  if (!b.put(dat)) {
109  cerr << "Failed to put input of type " << b.port_type_name() << endl;
110  return false;
111  }
112  return true;
113 }
114 
115 struct CallTransfer {
116  virtual ~CallTransfer() {}
117  virtual bool call(const IPort& a, IPort& b) = 0;
118 };
119 
120 template<typename T>
121 struct CallTransferT : public CallTransfer{
122  typedef T port_type;
123  virtual ~CallTransferT() {}
125  return typeid(port_type).name();
126  }
127  bool call(const IPort& a, IPort& b) {
128  const Port<port_type>* pa = dynamic_cast<const Port<port_type>*>(&a);
129  Port<port_type>* pb = dynamic_cast<Port<port_type>*>(&b);
130  return transfer(*pa, *pb);
131  }
132 };
133 
134 
135 static map<string, CallTransfer*> callers;
136 
137 template<typename T>
139 {
141  callers[ct->port_type_name()] = ct;
142 }
143 
145 {
146  const IPort* port = dynamic_cast<const IPort*>(&comp);
147  if (!port) { return nullptr; }
148  return callers[port->port_type_name()];
149 }
150 
151 
152 int main()
153 {
154 
155  IPort* si = new SubI;
156  IPort* sf = new SubF;
157  IPort* sfi = new SubFIn;
158  IPort* sfo = new SubFOut;
159 
160  cout << "typeid(si) = " << typeid(si).name() << endl;
161  cout << "typeid(*si) = " << typeid(*si).name() << endl;
162  cout << "typeid(sf) = " << typeid(sf).name() << endl;
163  cout << "typeid(*sf) = " << typeid(*sf).name() << endl;
164  cout << "typeid(sfo) = " << typeid(sfo).name() << endl;
165  cout << "typeid(*sfo) = " << typeid(*sfo).name() << endl;
166  cout << "typeid(sfi) = " << typeid(sfi).name() << endl;
167  cout << "typeid(*sfi) = " << typeid(*sfi).name() << endl;
168 
169  cout << "typeid(SubI::port_type) = " << typeid(SubI::port_type).name() << endl;
170  cout << "typeid(SubF::port_type) = " << typeid(SubF::port_type).name() << endl;
171  cout << "typeid(SubFOut::port_type) = " << typeid(SubFOut::port_type).name() << endl;
172  cout << "typeid(SubFIn::port_type) = " << typeid(SubFIn::port_type).name() << endl;
173 
174  cout << "si->type_name() = " << si->port_type_name() << endl;
175  cout << "sf->type_name() = " << sf->port_type_name() << endl;
176  cout << "sfo->type_name() = " << sfo->port_type_name() << endl;
177  cout << "sfi->type_name() = " << sfi->port_type_name() << endl;
178 
179  // given just Port*, how to know what to dynamic_cast to???
180  Port<float>* bfi = dynamic_cast<Port<float>*>(sfi);
181  Port<float>* bfo = dynamic_cast<Port<float>*>(sfo);
182  Assert(bfi);
183  Assert(bfo);
184  Assert(transfer(*bfo, *bfi));
185 
186  // okay, like this:
187  register_caller<int>();
188  register_caller<float>();
189 
190  IPort* ci = new SubFIn;
191  IPort* co = new SubFOut;
192 
193 
194 
195  CallTransfer* ct = get_caller(*ci);
196  Assert(ct);
197  Assert(ct->call(*co, *ci));
198 
199  return 0;
200 }
static QCString name
Definition: declinfo.cpp:673
virtual ~Port()
Definition: test_typeid.cxx:37
T port_type
Definition: test_typeid.cxx:36
virtual ~CallTransfer()
int main()
virtual ~IPort()
Definition: test_typeid.cxx:30
std::string string
Definition: nybbler.cc:12
virtual bool call(const IPort &a, IPort &b)=0
bool transfer(const A &a, B &b)
Definition: test_typeid.cxx:91
virtual std::string port_type_name() const =0
virtual bool put(const port_type &in)
Definition: test_typeid.cxx:78
STL namespace.
comp
Definition: dbjson.py:31
virtual bool put(const port_type &in)
Definition: test_typeid.cxx:65
virtual ~CallTransferT()
#define Assert
Definition: Testing.h:7
virtual ~SubFIn()
Definition: test_typeid.cxx:64
virtual bool put(const port_type &in)
Definition: test_typeid.cxx:41
virtual ~SubFOut()
Definition: test_typeid.cxx:77
std::string port_type_name() const
static const double pb
Definition: Units.h:90
void register_caller()
virtual std::string port_type_name() const
Definition: test_typeid.cxx:38
virtual ~SubF()
Definition: test_typeid.cxx:55
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1124
virtual ~SubI()
Definition: test_typeid.cxx:47
virtual T make() const
Definition: test_typeid.cxx:43
CallTransfer * get_caller(const IPort &comp)
bool call(const IPort &a, IPort &b)
#define A
Definition: memgrp.cpp:38
static bool * b
Definition: config.cpp:1043
static map< string, CallTransfer * > callers
QTextStream & endl(QTextStream &s)