OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimRtti.h
Go to the documentation of this file.
1 #ifndef RTTI_H
2 #define RTTI_H
3 
5 /*
6  RTTI_H: This file provides support for RTTI and generalized (virtual-base to derived and
7  separate hierarchy branches) casting. There is also support for RT obj creation
8  from type names.
9 
10  In order to enable these features for a class, two things should be done:
11 
12  1) insert the text TYPE_DATA (without ';') as the last item in the class-decl.
13  2) in the .C file where the class's implementation resides, insert the following (without';'):
14 
15  RTTI_DEF(classname,"RT classname") if the class has no bases with RTTI
16  RTTI_DEFn(classname,"RT classname",b1,...bn) if the class has bases b1,...bn with RTTI
17 
18  Use RTTI_DEF_INST instead of RTTI_DEF if you want to enable RT obj creation for classname.
19  You should provide then a public default ctor.
20 
21  RTTI is used via a class called RTTItypeid. A typeid describes a type of a class. typeids can be compared
22  with operator== and operator!= and can be retrieved from classes/pointers. They should provide all necessary
23  support for any kind of RTTI/casting, as described by the macros below (by RTTI-class we mean a class having RTTI,
24  as described above). The 'return type' of the macros is listed between quotes:
25 
26  'RTTItypeid'
27  STATIC_TYPE_INFO(T) T=RTTI-class name. Returns a RTTItypeid with T's type. if T hasn't RTTI, a
28  compile-time error occurs.
29  'RTTItypeid'
30  TYPE_INFO(p) p=ptr to a RTTI-class.
31  Returns the RTTItypeid of the class-obj p is really pointing at.
32  If *p hasn't RTTI, a compile-time error occurs.
33  If p==NULL, a special typeid for the NULL pointer is returned.
34  This typeid has the name (const char*) "NULL".
35  'T*'
36  PTR_CAST(T,p) T=RTTI-class, p=RTTI-class ptr.
37  Returns p cast to the type T as a T*, if cast is possible, else
38  returns NULL. If *p or T have no RTTI, a compile-time error occurs.
39  Note that p can point to virtual base classes. Casting between separate
40  branches of a class hierarchy is also supported, as long as all classes
41  have RTTI. Therefore PTR_CAST is a fully general and safe operator.
42  If p==NULL, the operator returns NULL.
43 
44  Some other macros. Not essential, provided mostly for convenience:
45  =================
46  const char*
47  STATIC_TYPE_NAME(T) T=RTTI-class name. Returns the name (const char*) of T's type.
48  Provided for convenience. Compile-time error if T hasn't RTTI.
49  const char*
50  TYPE_NAME(p) p=RTTI-class ptr. Returns the class name (char*) of real *p.
51  Provided for convenience. Compile-time error if *p hasn't RTTI.
52  int If p==NULL, "NULL" is returned.
53  DYN_CAST(t,p) t=RTTItypeid. p=RTTI-class ptr.
54  Returns 1 if p can indeed be cast to t, else returns 0.
55  Compile-time error if *p hasn't RTTI.
56  If p==NULL, 1 is returned (NULL can be cast to anything).
57  This operator is useful when we just want to check that a pointer can be cast to
58  a RTTItypeid variable (which can be created/selected at run-time). For creating a RTTItypeid,
59  construct a subclass of RTTItypeid called RTTIdyntypeid which allows construction from a const char*, i.e. from
60  a user specification and pass it to DYN_CAST.
61  DYN_TYPE can't return a typed pointer (since t is a RTTItypeid var and C++ has no 'real' type variables),
62  but returns a 1/0 indicating whether the cast is possible or not.
63  void*
64  UPTR_CAST(t,p) t=RTTItypeid. p=RTTI-class ptr.
65  Returns p cast to a void* if cast succeeds, else returns NULL.
66  Again, p can point to virtual-bases and casts between separate branches of a class dag
67  are supported. this operator is practically the 'untyped' version of PTR_CAST, offering
68  the extra feature that the type is expressed by a run-time type variable (RTTItypeid).
69  Compile-time error if *p hasn't RTTI.
70 
71 
72  Obsolete macros: This set of macros is based on Stroustrup. They are not general and safe
73  =============== (e.g. virtual-base to derived casts are trapped as compile-time errors and casts
74  between separate class-dag branches are incorrectly done without any warnings).
75  The above macros are including ALL functionality of these macros, which are
76  provided only for completeness:
77 
78  OLD_PTR_CAST(T,p) Like PTR_CAST(T,p), but without accepting p=ptr to virtual bases and performing
79  incorrect casts between separate branches of a class-dag.
80  OLD_UPTR_CAST(t,p) Like UPTR_CAST(t,p), but with same problems as above.
81  OLD_DYN_CAST(t,p) Like DYN_CAST(t,p), but with same problems as above.
82 
83 
84  RT Object Creation: This feature enables the user to create objects of a RT-selected type in a generic manner.
85  ================== Typically, we create/obtain a RT type (via a RTTItypeid t1). Then, having another RTTItypeid t2
86  (typically from the (STATIC_)TYPE_INFO of some ROOT class / ROOT* ptr, we call:
87 
88  ROOT* new_obj = (ROOT*)t2.create(t1);
89 
90  create() searches for t1 in the class DAG rooted at t2. If found, it creates a new obj of type
91  t1 and returns it as a '(void*)(t2*)'. For example, we know above that we get a ROOT* since
92  t2 is ROOT's RTTItypeid, so we can _safely_ cast the void* to ROOT. If create() can't make the t1
93  object (there's no such type or the type is not declared via RTTI_DEF_INST), it returns NULL.
94  This gives a fully generic typeid-based factory method for RT obj creation.
95 
96  REMARK: RTTI support adds some additional info, both static+virtual, to a class. The current implementation
97  ======= adds a static object and some static functions and 2 virtual functions to each class desiring RTTI.
98  This may of course cause potential name-clash problems. In order to avoid this, all added identifiers
99  in the RTTI system are prefixed with RTTI_ (see the TYPE_DATA macro).
100 
101  REMARK_2: There are two classes related to RTTI: RTTItypeid and RTTITypeinfo. A RTTItypeid is, as it says, an 'id for a type'
102  ======== It actually wraps a RTTITypeinfo*, where a RTTITypeinfo contains the actual encoding of a class type.
103  You can freely create/copy/destroy/manipulate RTTItypeid's, but you should NEVER deal directly
104  with RTTITypeinfo. A RTTITypeinfo should actually be created ONLY by the TYPE_DATA macros, as part of a class definition,
105  since the RTTITypeinfo encodes a type info for an EXISTING class. All type-related stuff should be therefore
106  handled via RTTItypeid's. If you really want to dynamically create a dummy typeid, use RTTIdyntypeid class.
107 
108  REMARK 3: All names introduced by this RTTI implementation (RTTItypeid,RTTIdyntypeid,RTTITypeinfo,etc)
109  ========= are prefixed by RTTI, to make this system easily acceptable by e.g. C++ environments which happen to
110  already support typeids.
111 
112 */
113 
114 
116 
117 #include <cstring> // for strdup,strcmp
118 #include <string> // for strdup,strcmp
120 #include <vector>
122 
123 class RTTITypeinfo;
124 
126  { // Main class for RTTI interface.
127  public:
128 
129  RTTItypeid(const RTTITypeinfo* p): theId(p) {}
130  RTTItypeid();
131  int operator==(RTTItypeid) const;
132  int operator!=(RTTItypeid) const;
133  const RTTITypeinfo* get_info() const { return theId; }
134  int can_cast(RTTItypeid) const; // 1 if the arg can be cast to this, else 0
135  const char* getname() const;
136  int num_subclasses() const; // Return # subclasses of this
137  RTTItypeid subclass(int) const; // Return ith subclass of this
138  int num_baseclasses() const; // Return # baseclasses of this
139  RTTItypeid baseclass(int) const; // Return ith baseclass of this
140  void* create(RTTItypeid) const; // Tries to create an instance of a subclass of this
141  // having of type given by the RTTItypeid arg. If ok, it returns it
142  // casted to the class-type of this and then to void*
143  int can_create() const; // Return 1 if this type is instantiable, else 0
144  RTTItypeid find_baseclass(const char* name)const;//
145  static RTTItypeid
146  null_type(); // the RTTItypeid for NULL ptrs
147 
148  protected:
149 
150  const RTTITypeinfo* theId; // RTTItypeid implementation (the only data-member)
151  };
152 
153 
154 class OSSIMDLLEXPORT RTTIdyntypeid : public RTTItypeid //Class for dynamic type creation from user strings.
155  { //Useful for creating typeids at RT for comparison
156  public: //purposes.
157  RTTIdyntypeid(const char*);
158  ~RTTIdyntypeid();
159  private:
160  static const RTTITypeinfo* a[];
161  };
162 
164 
165 class OSSIMDLLEXPORT RTTITypeinfo { //Implementation of type-related info
166  public:
167  typedef std::vector<const RTTITypeinfo*> SubtypesConstVector;
168 
169  RTTITypeinfo(const char* name, const RTTITypeinfo* bb[],
170  void* (*)(int,void*),void* (*)());
171  ~RTTITypeinfo();
172  const char* getname() const; //Returns name of this RTTITypeinfo
173  int same(const RTTITypeinfo*) const; //Compares 2 RTTITypeinfo objs
174  int can_cast(const RTTITypeinfo*) const; //1 if the arg can be cast to this, else 0
175  int has_base(const RTTITypeinfo*) const; //1 if this has the arg as some base, else 0
176 
177 
178  const RTTITypeinfo*
179  subclass(int=0) const; //get i-th subclass of this, if any, else NULL
180  int num_subclasses() const; //get # subclasses of this
181  void* create(const RTTITypeinfo*,const char*) const; //search for a subclass named char*,
182  //create obj of it and return it cast to
183  //the RTTITypeinfo* type, which is either
184  //this or a direct base of this.
185  int can_create() const; //Returns 1 if this type has a default ctor, else 0
186 
187  private:
188 
189  //char* n; //type name
190  std::string n;
191  const RTTITypeinfo** b; //base types (NULL-ended array of RTTITypeinfo's for this's direct bases)
192  int ns; //#subtypes of this type
194  //const RTTITypeinfo** subtypes; //types derived from this type
195  static const RTTITypeinfo null_type; //convenience type info for a 'null' type
196  void* (*new_obj)(); //func to create a new obj of this type
197  void* (*cast)(int,void*); //func to cast an obj of this type to
198  //ith baseclass of it or to itself
199 
200  void add_subtype(const RTTITypeinfo*);//adds a subtype to this's subtypes[]
201  void del_subtype(const RTTITypeinfo*);//dels a subtype from this's subtypes[]
202 
203  friend class RTTItypeid; //for null_type
204  };
205 
206 
207 
208 
209 inline int RTTITypeinfo::num_subclasses() const //Return # subclasses of this
210 {
211  return ns;
212 }
213 
214 inline const RTTITypeinfo* RTTITypeinfo::subclass(int i) const //Return ith subclass of this, else NULL;
215 {
216  return (i>=0 && i<ns)? subtypes[i]: 0;
217 }
218 
219 inline int RTTITypeinfo::same(const RTTITypeinfo* p) const //Compare 2 RTTITypeinfo's:
220 { //First, try to see if it's the same
221  return this==p || !strcmp(n.c_str(),p->n.c_str()); //'physical' RTTITypeinfo (which should be the case,
222 } //since we create them per-class and not per-obj).
223  //If this fails, still do a textual name comaprison.
224 
225 inline int RTTITypeinfo::can_cast(const RTTITypeinfo* p) const
226 {
227  return same(p) || p->has_base(this);
228 }
229 
230 inline int RTTITypeinfo::can_create() const
231 {
232  return new_obj!=0;
233 }
234 
236 //
237 // RTTItypeid methods:
238 //
239 
241 {
242  return &(RTTITypeinfo::null_type);
243 }
244 
246 {
247 }
248 
250 {
251  return theId->same(i.theId);
252 }
253 
255 {
256  return !(theId->same(i.theId));
257 }
258 
259 inline int RTTItypeid::can_cast(RTTItypeid i) const
260 {
261  return theId->can_cast(i.theId);
262 }
263 
264 
265 inline const char* RTTItypeid::getname() const
266 {
267  return theId->getname();
268 }
269 
270 inline int RTTItypeid::num_subclasses() const
271 {
272  return theId->num_subclasses();
273 }
274 
275 inline RTTItypeid RTTItypeid::subclass(int i) const
276 {
277  return theId->subclass(i);
278 }
279 
280 inline int RTTItypeid::num_baseclasses() const
281 {
282  int i;
283  for(i=0;theId->b[i];i++){}
284  return i;
285 }
286 
288 {
289  return theId->b[i];
290 }
291 
292 inline void* RTTItypeid::create(RTTItypeid t) const
293 {
294  return theId->create(theId,t.getname());
295 }
296 
297 inline int RTTItypeid::can_create() const
298 {
299  return theId->can_create();
300 }
301 
303 
304 
305 inline RTTIdyntypeid::RTTIdyntypeid(const char* c) : RTTItypeid(new RTTITypeinfo(c,a,0,0)) { } //create a dummy RTTITypeinfo
307 {
308  if(theId)
309  {
310  delete theId;
311  theId = 0;
312  }
313 } //delete the dummy RTTITypeinfo
314 
315 
317 
318 // 1. Main operators
319 #define STATIC_TYPE_INFO(T) T::RTTI_sinfo()
320 #define TYPE_INFO(p) ((p)? (p)->RTTI_vinfo() : RTTItypeid::null_type() )
321 #define PTR_CAST(T,p) ((p)? (T*)((p)->RTTI_cast(STATIC_TYPE_INFO(T))) : 0)
322 
323 
324 // 2. Convenience operators
325 #define STATIC_TYPE_NAME(T) (STATIC_TYPE_INFO(T).getname())
326 #define TYPE_NAME(p) ((p)? ((p)->RTTI_vinfo().getname()) : RTTItypeid::null_type().getname())
327 #define DYN_CAST(t,p) ((p)? ((p)->RTTI_cast((t))!=0) : 1)
328 #define UPTR_CAST(t,p) ((p)? ((p)->RTTI_cast((t))) : 0)
329 
330 // 3. Unsafe operators (see Stroustrup)
331 #define OLD_PTR_CAST(T,p) ((p)? ((STATIC_TYPE_INFO(T).can_cast((p)->RTTI_vinfo()))? (T*)p : 0) : 0)
332 #define OLD_UPTR_CAST(t,p) ((p)? ((t).can_cast((p)->RTTI_vinfo())? (void*)p : 0) : 0)
333 #define OLD_DYN_CAST(t,p) ((p)? ((t).can_cast((p)->RTTI_vinfo())? 1 : 0) : 1)
334 
335 
336 // Definition of TYPE_DATA for a RTTI-class: introduces one static RTTITypeinfo data-member
337 // and a couple of virtuals.
338 
339 #define TYPE_DATA \
340  protected: \
341  static const RTTITypeinfo RTTI_obj; \
342  static void* RTTI_scast(int,void*); \
343  static void* RTTI_new(); \
344  public: \
345  virtual RTTItypeid RTTI_vinfo() const { return &RTTI_obj; }\
346  static RTTItypeid RTTI_sinfo() { return &RTTI_obj; }\
347  virtual void* RTTI_cast(RTTItypeid);\
348  virtual const void* RTTI_cast(RTTItypeid)const;
349 
350 
351 
352 // Definition of auxiliary data-structs supporting RTTI for a class: defines the static RTTITypeinfo
353 // object of that class and its associated virtuals.
354 
355 // Auxiliary definition of the construction method:
356 #define RTTI_NEW(cls,name) void* cls::RTTI_new() { return new cls; } \
357  const RTTITypeinfo cls::RTTI_obj = RTTITypeinfo(name,RTTI_base_##cls,cls::RTTI_scast,cls::RTTI_new);
358 
359 #define RTTI_NO_NEW(cls,name) const RTTITypeinfo cls::RTTI_obj = RTTITypeinfo(name,RTTI_base_##cls,cls::RTTI_scast,0);
360 
361 
362 
364 //
365 // Top-level macros:
366 //
367 
368 #define RTTI_DEF_BASE(cls,name) \
369  static const RTTITypeinfo* RTTI_base_##cls [] = { 0 };\
370  void* cls::RTTI_cast(RTTItypeid t) \
371  { \
372  if (t == &RTTI_obj) return this; \
373  return 0; \
374  } \
375  const void* cls::RTTI_cast(RTTItypeid t)const \
376  { \
377  if (t == &RTTI_obj) return this; \
378  return 0; \
379  } \
380  void* cls::RTTI_scast(int /* i */,void* p) \
381  { cls* ptr = (cls*)p; return ptr; }
382 
383 
384 #define RTTI_DEF1_BASE(cls,name,b1) \
385  static const RTTITypeinfo* RTTI_base_##cls [] = \
386  { STATIC_TYPE_INFO(b1).get_info(),0 }; \
387  void* cls::RTTI_cast(RTTItypeid t) \
388  { \
389  if (t == &RTTI_obj) return this; \
390  void* ptr; \
391  if ((ptr=b1::RTTI_cast(t))) return ptr; \
392  return 0; \
393  } \
394  const void* cls::RTTI_cast(RTTItypeid t)const \
395  { \
396  if (t == &RTTI_obj) return this; \
397  const void* ptr; \
398  if ((ptr=b1::RTTI_cast(t))) return ptr; \
399  return 0; \
400  } \
401  void* cls::RTTI_scast(int i,void* p) \
402  { cls* ptr = (cls*)p; \
403  switch(i) \
404  { case 0: return (b1*)ptr; } \
405  return ptr; \
406  }
407 
408 
409 #define RTTI_DEF2_BASE(cls,name,b1,b2) \
410  static const RTTITypeinfo* RTTI_base_##cls [] = \
411  { STATIC_TYPE_INFO(b1).get_info(), \
412  STATIC_TYPE_INFO(b2).get_info(),0 }; \
413  void* cls::RTTI_cast(RTTItypeid t) \
414  { \
415  if (t == &RTTI_obj) return this; \
416  void* ptr; \
417  if ((ptr=b1::RTTI_cast(t))) return ptr; \
418  if ((ptr=b2::RTTI_cast(t))) return ptr; \
419  return 0; \
420  } \
421  const void* cls::RTTI_cast(RTTItypeid t)const \
422  { \
423  if (t == &RTTI_obj) return this; \
424  const void* ptr; \
425  if ((ptr=b1::RTTI_cast(t))) return ptr; \
426  if ((ptr=b2::RTTI_cast(t))) return ptr; \
427  return 0; \
428  } \
429  void* cls::RTTI_scast(int i,void* p) \
430  { cls* ptr = (cls*)p; \
431  switch(i) \
432  { case 0: return (b1*)ptr; \
433  case 1: return (b2*)ptr; \
434  } \
435  return ptr; \
436  }
437 
438 #define RTTI_DEF3_BASE(cls,name,b1,b2,b3) \
439  static const RTTITypeinfo* RTTI_base_##cls [] = \
440  { STATIC_TYPE_INFO(b1).get_info(), \
441  STATIC_TYPE_INFO(b2).get_info(), \
442  STATIC_TYPE_INFO(b3).get_info(), 0 }; \
443  void* cls::RTTI_cast(RTTItypeid t) \
444  { \
445  if (t == &RTTI_obj) return this; \
446  void* ptr; \
447  if ((ptr=b1::RTTI_cast(t))) return ptr; \
448  if ((ptr=b2::RTTI_cast(t))) return ptr; \
449  if ((ptr=b3::RTTI_cast(t))) return ptr; \
450  return 0; \
451  } \
452  const void* cls::RTTI_cast(RTTItypeid t)const \
453  { \
454  if (t == &RTTI_obj) return this; \
455  const void* ptr; \
456  if ((ptr=b1::RTTI_cast(t))) return ptr; \
457  if ((ptr=b2::RTTI_cast(t))) return ptr; \
458  if ((ptr=b3::RTTI_cast(t))) return ptr; \
459  return 0; \
460  } \
461  void* cls::RTTI_scast(int i,void* p) \
462  { cls* ptr = (cls*)p; \
463  switch(i) \
464  { case 0: return (b1*)ptr; \
465  case 1: return (b2*)ptr; \
466  case 2: return (b3*)ptr; \
467  } \
468  return ptr; \
469  }
470 
471 
472 
473 #define RTTI_DEF_INST(cls,name) \
474  RTTI_DEF_BASE(cls,name) \
475  RTTI_NEW(cls,name)
476 
477 #define RTTI_DEF(cls,name) \
478  RTTI_DEF_BASE(cls,name) \
479  RTTI_NO_NEW(cls,name)
480 
481 #define RTTI_DEF1_INST(cls,name,b1) \
482  RTTI_DEF1_BASE(cls,name,b1) \
483  RTTI_NEW(cls,name)
484 
485 #define RTTI_DEF1(cls,name,b1) \
486  RTTI_DEF1_BASE(cls,name,b1) \
487  RTTI_NO_NEW(cls,name)
488 
489 #define RTTI_DEF2_INST(cls,name,b1,b2) \
490  RTTI_DEF2_BASE(cls,name,b1,b2) \
491  RTTI_NEW(cls,name)
492 
493 #define RTTI_DEF2(cls,name,b1,b2) \
494  RTTI_DEF2_BASE(cls,name,b1,b2) \
495  RTTI_NO_NEW(cls,name)
496 
497 #define RTTI_DEF3_INST(cls,name,b1,b2,b3) \
498  RTTI_DEF3_BASE(cls,name,b1,b2,b3) \
499  RTTI_NEW(cls,name)
500 
501 #define RTTI_DEF3(cls,name,b1,b2,b3) \
502  RTTI_DEF3_BASE(cls,name,b1,b2,b3) \
503  RTTI_NO_NEW(cls,name)
504 
505 
506 #endif
507 
508 
509 
510 
511 
SubtypesConstVector subtypes
Definition: ossimRtti.h:193
void * create(const RTTITypeinfo *, const char *) const
Definition: ossimRtti.cpp:96
RTTIdyntypeid(const char *)
Definition: ossimRtti.h:305
#define OSSIMDLLEXPORT
bool operator!=(const ossimRefPtr< _Tp1 > &__a, const ossimRefPtr< _Tp2 > &__b) noexcept
Definition: ossimRefPtr.h:111
int same(const RTTITypeinfo *) const
Definition: ossimRtti.h:219
const RTTITypeinfo * theId
Definition: ossimRtti.h:150
std::string n
Definition: ossimRtti.h:190
int operator==(RTTItypeid) const
Definition: ossimRtti.h:249
int operator!=(RTTItypeid) const
Definition: ossimRtti.h:254
int num_baseclasses() const
Definition: ossimRtti.h:280
int can_cast(RTTItypeid) const
Definition: ossimRtti.h:259
RTTItypeid baseclass(int) const
Definition: ossimRtti.h:287
static const RTTITypeinfo null_type
Definition: ossimRtti.h:195
os2<< "> n<< " > nendobj n
int num_subclasses() const
Definition: ossimRtti.h:270
void *(* new_obj)()
Definition: ossimRtti.h:196
const char * getname() const
Definition: ossimRtti.h:265
void * create(RTTItypeid) const
Definition: ossimRtti.h:292
bool operator==(const ossimRefPtr< _Tp1 > &__a, const ossimRefPtr< _Tp2 > &__b) noexcept
Definition: ossimRefPtr.h:101
int can_create() const
Definition: ossimRtti.h:230
int can_cast(const RTTITypeinfo *) const
Definition: ossimRtti.h:225
int has_base(const RTTITypeinfo *) const
Definition: ossimRtti.cpp:88
const RTTITypeinfo * subclass(int=0) const
Definition: ossimRtti.h:214
std::vector< const RTTITypeinfo * > SubtypesConstVector
Definition: ossimRtti.h:167
RTTItypeid(const RTTITypeinfo *p)
Definition: ossimRtti.h:129
const RTTITypeinfo ** b
Definition: ossimRtti.h:191
const RTTITypeinfo * get_info() const
Definition: ossimRtti.h:133
RTTItypeid subclass(int) const
Definition: ossimRtti.h:275
static RTTItypeid null_type()
Definition: ossimRtti.h:240
int can_create() const
Definition: ossimRtti.h:297
int num_subclasses() const
Definition: ossimRtti.h:209
const char * getname() const
Definition: ossimRtti.cpp:67