1 // Copyright (c) 1991-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14 
15 #ifndef _Standard_Type_HeaderFile
16 #define _Standard_Type_HeaderFile
17 
18 #include <Standard.hxx>
19 #include <Standard_Handle.hxx>
20 #include <Standard_Transient.hxx>
21 #include <Standard_OStream.hxx>
22 
23 #include <typeinfo>
24 
25 // Auxiliary tools to check at compile time that class declared as base in
26 // DEFINE_STANDARD_RTTI* macro is actually a base class.
27 #if ! defined(OCCT_CHECK_BASE_CLASS)
28 
29 #if (defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || (__GNUC__ > 4)))
30 
31 // For GCC 4.7+, more strict check is possible -- ensuring that base class
32 // is direct base -- using non-standard C++ reflection functionality.
33 
34 #include <tr2/type_traits>
35 #include <tuple>
36 
37 namespace opencascade
38 {
39   template<typename T>
40   struct direct_base_class_as_tuple {};
41 
42   template<typename ... Ts>
43   struct direct_base_class_as_tuple<std::tr2::__reflection_typelist<Ts...> >
44   {
45     typedef std::tuple<Ts...> type;
46   };
47 
48   template <typename T, typename Tuple>
49   struct has_type;
50 
51   template <typename T>
52   struct has_type<T, std::tuple<> > : std::false_type {};
53 
54   template <typename T, typename U, typename... Ts>
55   struct has_type<T, std::tuple<U, Ts...> > : has_type<T, std::tuple<Ts...> > {};
56 
57   template <typename T, typename... Ts>
58   struct has_type<T, std::tuple<T, Ts...> > : std::true_type {};
59 }
60 
61 #define OCCT_CHECK_BASE_CLASS(Class,Base) \
62   using direct_base_classes = opencascade::direct_base_class_as_tuple<std::tr2::direct_bases<Class>::type>::type; \
63   static_assert(opencascade::has_type<Base, direct_base_classes>::type::value, "OCCT RTTI definition is incorrect: " #Base " is not direct base class of " #Class); \
64   static_assert(&get_type_name == &Class::get_type_name, "OCCT RTTI definition is misplaced: current class is not " #Class);
65 
66 #elif (defined(_MSC_VER) && (_MSC_VER < 1600))
67 
68 // VC9 does not support static_assert and decltype at all
69 #define OCCT_CHECK_BASE_CLASS(Class,Base)
70 
71 #elif (defined(_MSC_VER) && (_MSC_VER >= 1900))
72 
73 // VC14+ allow using address of member functions in static checks,
74 // that allows checking for the current type being correctly named in the macro
75 #define OCCT_CHECK_BASE_CLASS(Class,Base) \
76   static_assert(opencascade::is_base_but_not_same<Base, Class>::value, "OCCT RTTI definition is incorrect: " #Base " is not base class of " #Class); \
77   static_assert(&get_type_name == &Class::get_type_name, "OCCT RTTI definition is misplaced: current class is not " #Class);
78 
79 #else
80 
81 // by default, check only the base class
82 #define OCCT_CHECK_BASE_CLASS(Class,Base) \
83   static_assert(opencascade::is_base_but_not_same<Base, Class>::value, "OCCT RTTI definition is incorrect: " #Base " is not base class of " #Class);
84 
85 #endif
86 
87 #endif /* ! defined(OCCT_CHECK_BASE_CLASS) */
88 
89 //! Helper macro to get instance of a type descriptor for a class in a legacy way.
90 #define STANDARD_TYPE(theType) theType::get_type_descriptor()
91 
92 //! Helper macro to be included in definition of the classes inheriting
93 //! Standard_Transient to enable use of OCCT RTTI.
94 //!
95 //! Inline version, does not require IMPLEMENT_STANDARD_RTTIEXT, but when used
96 //! for big hierarchies of classes may cause considerable increase of size of binaries.
97 #define DEFINE_STANDARD_RTTI_INLINE(Class,Base) \
98 public: \
99   typedef Base base_type; \
100   static const char* get_type_name () { return #Class; OCCT_CHECK_BASE_CLASS(Class,Base) } \
101   static const Handle(Standard_Type)& get_type_descriptor () { return Standard_Type::Instance<Class>(); } \
102   virtual const Handle(Standard_Type)& DynamicType() const Standard_OVERRIDE { return get_type_descriptor (); }
103 
104 //! Helper macro to be included in definition of the classes inheriting
105 //! Standard_Transient to enable use of OCCT RTTI.
106 //!
107 //! Out-of-line version, requires IMPLEMENT_STANDARD_RTTIEXT.
108 #define DEFINE_STANDARD_RTTIEXT(Class,Base) \
109 public: \
110   typedef Base base_type; \
111   static const char* get_type_name () { return #Class; OCCT_CHECK_BASE_CLASS(Class,Base) } \
112   Standard_EXPORT static const Handle(Standard_Type)& get_type_descriptor (); \
113   Standard_EXPORT virtual const Handle(Standard_Type)& DynamicType() const Standard_OVERRIDE;
114 
115 //! Defines implementation of type descriptor and DynamicType() function
116 #define IMPLEMENT_STANDARD_RTTIEXT(Class,Base) \
117   const Handle(Standard_Type)& Class::get_type_descriptor () { return Standard_Type::Instance<Class>(); } \
118   const Handle(Standard_Type)& Class::DynamicType() const { return STANDARD_TYPE(Class); }
119 
120 // forward declaration of type_instance class
121 namespace opencascade {
122   template <typename T>
123   class type_instance;
124 }
125 
126 //! This class provides legacy interface (type descriptor) to run-time type
127 //! information (RTTI) for OCCT classes inheriting from Standard_Transient.
128 //!
129 //! In addition to features provided by standard C++ RTTI (type_info),
130 //! Standard_Type allows passing descriptor as an object and using it for
131 //! analysis of the type:
132 //! - get descriptor of a parent class
133 //! - get user-defined name of the class
134 //! - get size of the object
135 //!
136 //! Use static template method Instance() to get descriptor for a given type.
137 //! Objects supporting OCCT RTTI return their type descriptor by method DynamicType().
138 //!
139 //! To be usable with OCCT type system, the class should provide:
140 //! - typedef base_type to its base class in the hierarchy
141 //! - method get_type_name() returning programmer-defined name of the class
142 //!   (as a statically allocated constant C string or string literal)
143 //!
144 //! Note that user-defined name is used since typeid.name() is usually mangled in
145 //! compiler-dependent way.
146 //!
147 //! Only single chain of inheritance is supported, with a root base class Standard_Transient.
148 
149 class Standard_Type : public Standard_Transient
150 {
151 public:
152 
153   //! Returns the system type name of the class (typeinfo.name)
SystemName() const154   Standard_CString SystemName() const { return mySystemName; }
155 
156   //! Returns the given name of the class type (get_type_name)
Name() const157   Standard_CString Name() const { return myName; }
158 
159   //! Returns the size of the class instance in bytes
Size() const160   Standard_Size Size() const { return mySize; }
161 
162   //! Returns descriptor of the base class in the hierarchy
Handle(Standard_Type)163   const Handle(Standard_Type)& Parent () const { return myParent; }
164 
165   //! Returns True if this type is the same as theOther, or inherits from theOther.
166   //! Note that multiple inheritance is not supported.
167   Standard_EXPORT Standard_Boolean SubType (const Handle(Standard_Type)& theOther) const;
168 
169   //! Returns True if this type is the same as theOther, or inherits from theOther.
170   //! Note that multiple inheritance is not supported.
171   Standard_EXPORT Standard_Boolean SubType (const Standard_CString theOther) const;
172 
173   //! Prints type (address of descriptor + name) to a stream
174   Standard_EXPORT void Print (Standard_OStream& theStream) const;
175 
176   //! Template function returning instance of the type descriptor for an argument class.
177   //!
178   //! For optimization, each type is registered only once (due to use of the static variable).
179   //!
180   //! See helper macro DEFINE_STANDARD_RTTI for defining these items in the class.
181   template <class T>
Handle(Standard_Type)182   static const Handle(Standard_Type)& Instance()
183   {
184     return opencascade::type_instance<T>::get();
185   }
186 
187   //! Register a type; returns either new or existing descriptor.
188   //!
189   //! @param theSystemName name of the class as returned by typeid(class).name()
190   //! @param theName name of the class to be stored in Name field
191   //! @param theSize size of the class instance
192   //! @param theParent base class in the Transient hierarchy
193   //!
194   //! Note that this function is intended for use by opencascade::type_instance only.
195   Standard_EXPORT static
196     Standard_Type* Register (const char* theSystemName, const char* theName,
197                              Standard_Size theSize, const Handle(Standard_Type)& theParent);
198 
199   //! Destructor removes the type from the registry
200   Standard_EXPORT ~Standard_Type ();
201 
202   // Define own RTTI
203   DEFINE_STANDARD_RTTIEXT(Standard_Type,Standard_Transient)
204 
205 private:
206 
207   //! Constructor is private
208   Standard_Type (const char* theSystemName, const char* theName,
209                  Standard_Size theSize, const Handle(Standard_Type)& theParent);
210 
211 private:
212   Standard_CString mySystemName;  //!< System name of the class (typeinfo.name)
213   Standard_CString myName;        //!< Given name of the class
214   Standard_Size mySize;           //!< Size of the class instance, in bytes
215   Handle(Standard_Type) myParent; //!< Type descriptor of parent class
216 };
217 
218 namespace opencascade {
219 
220   //! Template class providing instantiation of type descriptors as singletons.
221   //! The descriptors are defined as static variables in function get(), which
222   //! is essential to ensure that they are initialized in correct sequence.
223   //!
224   //! For compilers that do not provide thread-safe initialization of static
225   //! variables (C++11 feature, N2660), additional global variable is
226   //! defined for each type to hold its type descriptor. These globals ensure
227   //! that all types get initialized during the library loading and thus no
228   //! concurrency occurs when type system is accessed from multiple threads.
229   template <typename T>
230   class type_instance
231   {
232     static Handle(Standard_Type) myInstance;
233   public:
234     static const Handle(Standard_Type)& get ();
235   };
236 
237   //! Specialization of type descriptor instance for void; returns null handle
238   template <>
239   class type_instance<void>
240   {
241   public:
get()242     static Handle(Standard_Type) get () { return 0; }
243   };
244 
245   // Implementation of static function returning instance of the
246   // type descriptor
247   template <typename T>
Handle(Standard_Type)248   const Handle(Standard_Type)& type_instance<T>::get ()
249   {
250 #if (defined(_MSC_VER) && _MSC_VER < 1900) || \
251     (defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)) && \
252      ! defined(__clang__) && ! defined(__INTEL_COMPILER))
253     // ensure that myInstance is instantiated
254     (void)myInstance;
255 #endif
256 
257     // static variable inside function ensures that descriptors
258     // are initialized in correct sequence
259     static Handle(Standard_Type) anInstance =
260       Standard_Type::Register (typeid(T).name(), T::get_type_name(), sizeof(T),
261                                type_instance<typename T::base_type>::get());
262     return anInstance;
263   }
264 
265   // Static class field is defined to ensure initialization of all type
266   // descriptors at load time of the library on compilers not supporting N2660:
267   // - VC++ below 14 (VS 2015)
268   // - GCC below 4.3
269   // Intel compiler reports itself as GCC on Linux and VC++ on Windows,
270   // and is claimed to support N2660 on Linux and on Windows "in VS2015 mode".
271   // CLang should support N2660 since version 2.9, but it is not clear how to
272   // check its version reliably (on Linux it says it is GCC 4.2).
273 #if (defined(_MSC_VER) && _MSC_VER < 1900) || \
274     (defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)) && \
275      ! defined(__clang__) && ! defined(__INTEL_COMPILER))
276 
277   template <typename T>
278   Handle(Standard_Type) type_instance<T>::myInstance (get());
279 
280 #endif
281 }
282 
283 //! Operator printing type descriptor to stream
operator <<(Standard_OStream & theStream,const Handle (Standard_Type)& theType)284 inline Standard_OStream& operator << (Standard_OStream& theStream, const Handle(Standard_Type)& theType)
285 {
286   theType->Print (theStream);
287   return theStream;
288 }
289 
290 //! Definition of Handle_Standard_Type as typedef for compatibility
291 DEFINE_STANDARD_HANDLE(Standard_Type,Standard_Transient)
292 
293 #endif // _Standard_Type_HeaderFile
294