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