Commit | Line | Data |
---|---|---|
69ff08ff | 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> | |
e7195ab4 | 19 | #include <Standard_Handle.hxx> |
69ff08ff | 20 | #include <Standard_Transient.hxx> |
e7195ab4 | 21 | #include <Standard_OStream.hxx> |
69ff08ff | 22 | |
23 | #include <typeinfo> | |
24 | ||
0e9fe060 BB |
25 | // Auxiliary tools to check at compile time that class declared as base in |
26 | // DEFINE_STANDARD_RTTI* macro is actually a base class. | |
59e353b7 | 27 | #if ! defined(OCCT_CHECK_BASE_CLASS) |
71c810df | 28 | |
0e9fe060 BB |
29 | #if (defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || (__GNUC__ > 4))) |
30 | ||
71c810df | 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 | ||
0e9fe060 BB |
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 | ||
59e353b7 | 61 | #define OCCT_CHECK_BASE_CLASS(Class,Base) \ |
0e9fe060 | 62 | using direct_base_classes = opencascade::direct_base_class_as_tuple<std::tr2::direct_bases<Class>::type>::type; \ |
71c810df | 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); | |
0e9fe060 | 65 | |
71c810df | 66 | #elif (defined(_MSC_VER) && (_MSC_VER < 1600)) |
0e9fe060 | 67 | |
71c810df | 68 | // VC9 does not support static_assert and decltype at all |
59e353b7 | 69 | #define OCCT_CHECK_BASE_CLASS(Class,Base) |
71c810df | 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 | |
59e353b7 | 75 | #define OCCT_CHECK_BASE_CLASS(Class,Base) \ |
71c810df | 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 | |
59e353b7 | 82 | #define OCCT_CHECK_BASE_CLASS(Class,Base) \ |
0e9fe060 BB |
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 | ||
71c810df | 85 | #endif |
86 | ||
59e353b7 | 87 | #endif /* ! defined(OCCT_CHECK_BASE_CLASS) */ |
0e9fe060 | 88 | |
e7195ab4 | 89 | //! Helper macro to get instance of a type descriptor for a class in a legacy way. |
f5f4ebd0 | 90 | #define STANDARD_TYPE(theType) theType::get_type_descriptor() |
e7195ab4 | 91 | |
92 | //! Helper macro to be included in definition of the classes inheriting | |
f5f4ebd0 | 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) \ | |
e7195ab4 | 98 | public: \ |
99 | typedef Base base_type; \ | |
59e353b7 | 100 | static const char* get_type_name () { return #Class; OCCT_CHECK_BASE_CLASS(Class,Base) } \ |
f5f4ebd0 | 101 | static const Handle(Standard_Type)& get_type_descriptor () { return Standard_Type::Instance<Class>(); } \ |
71c810df | 102 | virtual const Handle(Standard_Type)& DynamicType() const Standard_OVERRIDE { return get_type_descriptor (); } |
e7195ab4 | 103 | |
f5f4ebd0 | 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; \ | |
59e353b7 | 111 | static const char* get_type_name () { return #Class; OCCT_CHECK_BASE_CLASS(Class,Base) } \ |
f5f4ebd0 | 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>(); } \ | |
71c810df | 118 | const Handle(Standard_Type)& Class::DynamicType() const { return STANDARD_TYPE(Class); } |
f5f4ebd0 | 119 | |
e7195ab4 | 120 | // forward declaration of type_instance class |
121 | namespace opencascade { | |
122 | template <typename T> | |
d9e90905 | 123 | class type_instance; |
e7195ab4 | 124 | } |
69ff08ff | 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) | |
154 | Standard_CString SystemName() const { return mySystemName; } | |
155 | ||
156 | //! Returns the given name of the class type (get_type_name) | |
157 | Standard_CString Name() const { return myName; } | |
158 | ||
159 | //! Returns the size of the class instance in bytes | |
160 | Standard_Size Size() const { return mySize; } | |
161 | ||
162 | //! Returns descriptor of the base class in the hierarchy | |
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> | |
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 | |
e7195ab4 | 196 | Standard_Type* Register (const char* theSystemName, const char* theName, |
197 | Standard_Size theSize, const Handle(Standard_Type)& theParent); | |
69ff08ff | 198 | |
199 | //! Destructor removes the type from the registry | |
200 | Standard_EXPORT ~Standard_Type (); | |
201 | ||
202 | // Define own RTTI | |
f5f4ebd0 | 203 | DEFINE_STANDARD_RTTIEXT(Standard_Type,Standard_Transient) |
69ff08ff | 204 | |
205 | private: | |
206 | ||
207 | //! Constructor is private | |
208 | Standard_Type (const char* theSystemName, const char* theName, | |
a0218ba1 | 209 | Standard_Size theSize, const Handle(Standard_Type)& theParent); |
69ff08ff | 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 | ||
d9e90905 | 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. | |
69ff08ff | 229 | template <typename T> |
d9e90905 | 230 | class type_instance |
69ff08ff | 231 | { |
d9e90905 | 232 | static Handle(Standard_Type) myInstance; |
233 | public: | |
69ff08ff | 234 | static const Handle(Standard_Type)& get (); |
235 | }; | |
236 | ||
237 | //! Specialization of type descriptor instance for void; returns null handle | |
238 | template <> | |
d9e90905 | 239 | class type_instance<void> |
69ff08ff | 240 | { |
d9e90905 | 241 | public: |
be5c3602 | 242 | static Handle(Standard_Type) get () { return 0; } |
69ff08ff | 243 | }; |
244 | ||
245 | // Implementation of static function returning instance of the | |
246 | // type descriptor | |
247 | template <typename T> | |
248 | const Handle(Standard_Type)& type_instance<T>::get () | |
249 | { | |
60a6678e | 250 | #if (defined(_MSC_VER) && _MSC_VER < 1900) || \ |
8bb8064e | 251 | (defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)) && \ |
252 | ! defined(__clang__) && ! defined(__INTEL_COMPILER)) | |
d9e90905 | 253 | // ensure that myInstance is instantiated |
254 | (void)myInstance; | |
8bb8064e | 255 | #endif |
d9e90905 | 256 | |
69ff08ff | 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 | ||
d9e90905 | 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). | |
60a6678e | 273 | #if (defined(_MSC_VER) && _MSC_VER < 1900) || \ |
d9e90905 | 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 | |
69ff08ff | 281 | } |
282 | ||
283 | //! Operator printing type descriptor to stream | |
284 | inline Standard_OStream& operator << (Standard_OStream& theStream, const Handle(Standard_Type)& theType) | |
285 | { | |
286 | theType->Print (theStream); | |
287 | return theStream; | |
288 | } | |
289 | ||
e7195ab4 | 290 | //! Definition of Handle_Standard_Type as typedef for compatibility |
291 | DEFINE_STANDARD_HANDLE(Standard_Type,Standard_Transient) | |
292 | ||
69ff08ff | 293 | #endif // _Standard_Type_HeaderFile |