0031668: Visualization - WebGL sample doesn't work on Emscripten 1.39
[occt.git] / src / Standard / Standard_Type.hxx
CommitLineData
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
37namespace 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 98public: \
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) \
109public: \
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
121namespace 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
149class Standard_Type : public Standard_Transient
150{
151public:
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
205private:
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
211private:
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
218namespace 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
284inline 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
291DEFINE_STANDARD_HANDLE(Standard_Type,Standard_Transient)
292
69ff08ff 293#endif // _Standard_Type_HeaderFile