0027254: [Regression] 7.0 types initialization mechanism is not thread-safe on VS2013
[occt.git] / src / Standard / Standard_Type.hxx
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 //! Helper macro to get instance of a type descriptor for a class in a legacy way.
26 #define STANDARD_TYPE(theType) theType::get_type_descriptor()
27
28 //! Helper macro to be included in definition of the classes inheriting
29 //! Standard_Transient to enable use of OCCT RTTI.
30 //!
31 //! Inline version, does not require IMPLEMENT_STANDARD_RTTIEXT, but when used
32 //! for big hierarchies of classes may cause considerable increase of size of binaries.
33 #define DEFINE_STANDARD_RTTI_INLINE(Class,Base) \
34 public: \
35   typedef Base base_type; \
36   static const char* get_type_name () { return #Class; } \
37   static const Handle(Standard_Type)& get_type_descriptor () { return Standard_Type::Instance<Class>(); } \
38   virtual const Handle(Standard_Type)& DynamicType() const Standard_OVERRIDE \
39   { return STANDARD_TYPE(Class); }
40
41 //! Helper macro to be included in definition of the classes inheriting
42 //! Standard_Transient to enable use of OCCT RTTI.
43 //!
44 //! Out-of-line version, requires IMPLEMENT_STANDARD_RTTIEXT.
45 #define DEFINE_STANDARD_RTTIEXT(Class,Base) \
46 public: \
47   typedef Base base_type; \
48   static const char* get_type_name () { return #Class; } \
49   Standard_EXPORT static const Handle(Standard_Type)& get_type_descriptor (); \
50   Standard_EXPORT virtual const Handle(Standard_Type)& DynamicType() const Standard_OVERRIDE;
51
52 //! Defines implementation of type descriptor and DynamicType() function
53 #define IMPLEMENT_STANDARD_RTTIEXT(Class,Base) \
54   const Handle(Standard_Type)& Class::get_type_descriptor () { return Standard_Type::Instance<Class>(); } \
55   const Handle(Standard_Type)& Class::DynamicType() const { return get_type_descriptor(); }
56
57 // forward declaration of type_instance class
58 namespace opencascade {
59   template <typename T>
60   class type_instance;
61 }
62
63 //! This class provides legacy interface (type descriptor) to run-time type
64 //! information (RTTI) for OCCT classes inheriting from Standard_Transient.
65 //!
66 //! In addition to features provided by standard C++ RTTI (type_info), 
67 //! Standard_Type allows passing descriptor as an object and using it for 
68 //! analysis of the type:
69 //! - get descriptor of a parent class
70 //! - get user-defined name of the class
71 //! - get size of the object
72 //! 
73 //! Use static template method Instance() to get descriptor for a given type.
74 //! Objects supporting OCCT RTTI return their type descriptor by method DynamicType().
75 //! 
76 //! To be usable with OCCT type system, the class should provide:
77 //! - typedef base_type to its base class in the hierarchy
78 //! - method get_type_name() returning programmer-defined name of the class
79 //!   (as a statically allocated constant C string or string literal)
80 //!
81 //! Note that user-defined name is used since typeid.name() is usually mangled in 
82 //! compiler-dependent way.
83 //! 
84 //! Only single chain of inheritance is supported, with a root base class Standard_Transient.
85
86 class Standard_Type : public Standard_Transient
87 {
88 public:
89
90   //! Returns the system type name of the class (typeinfo.name)
91   Standard_CString SystemName() const { return mySystemName; }
92   
93   //! Returns the given name of the class type (get_type_name)
94   Standard_CString Name() const { return myName; }
95   
96   //! Returns the size of the class instance in bytes
97   Standard_Size Size() const { return mySize; }
98
99   //! Returns descriptor of the base class in the hierarchy
100   const Handle(Standard_Type)& Parent () const { return myParent; }
101   
102   //! Returns True if this type is the same as theOther, or inherits from theOther.
103   //! Note that multiple inheritance is not supported.
104   Standard_EXPORT Standard_Boolean SubType (const Handle(Standard_Type)& theOther) const;
105
106   //! Returns True if this type is the same as theOther, or inherits from theOther.
107   //! Note that multiple inheritance is not supported.
108   Standard_EXPORT Standard_Boolean SubType (const Standard_CString theOther) const;
109
110   //! Prints type (address of descriptor + name) to a stream
111   Standard_EXPORT void Print (Standard_OStream& theStream) const;
112
113   //! Template function returning instance of the type descriptor for an argument class.
114   //!
115   //! For optimization, each type is registered only once (due to use of the static variable).
116   //!
117   //! See helper macro DEFINE_STANDARD_RTTI for defining these items in the class.
118   template <class T>
119   static const Handle(Standard_Type)& Instance()
120   {
121     return opencascade::type_instance<T>::get();
122   }
123
124   //! Register a type; returns either new or existing descriptor.
125   //!
126   //! @param theSystemName name of the class as returned by typeid(class).name()
127   //! @param theName name of the class to be stored in Name field
128   //! @param theSize size of the class instance
129   //! @param theParent base class in the Transient hierarchy
130   //!
131   //! Note that this function is intended for use by opencascade::type_instance only. 
132   Standard_EXPORT static 
133     Standard_Type* Register (const char* theSystemName, const char* theName,
134                              Standard_Size theSize, const Handle(Standard_Type)& theParent);
135
136   //! Destructor removes the type from the registry
137   Standard_EXPORT ~Standard_Type ();
138
139   // Define own RTTI
140   DEFINE_STANDARD_RTTIEXT(Standard_Type,Standard_Transient)
141
142 private:
143
144   //! Constructor is private
145   Standard_Type (const char* theSystemName, const char* theName,
146                  Standard_Size theSize, const Handle(Standard_Type)& theParent);
147
148 private:
149   Standard_CString mySystemName;  //!< System name of the class (typeinfo.name)
150   Standard_CString myName;        //!< Given name of the class
151   Standard_Size mySize;           //!< Size of the class instance, in bytes
152   Handle(Standard_Type) myParent; //!< Type descriptor of parent class
153 };
154
155 namespace opencascade {
156
157   //! Template class providing instantiation of type descriptors as singletons.
158   //! The descriptors are defined as static variables in function get(), which
159   //! is essential to ensure that they are initialized in correct sequence.
160   //!
161   //! For compilers that do not provide thread-safe initialization of static
162   //! variables (C++11 feature, N2660), additional global variable is
163   //! defined for each type to hold its type descriptor. These globals ensure
164   //! that all types get initialized during the library loading and thus no 
165   //! concurrency occurs when type system is accessed from multiple threads.
166   template <typename T>
167   class type_instance
168   {
169     static Handle(Standard_Type) myInstance;
170   public:
171     static const Handle(Standard_Type)& get ();
172   };
173
174   //! Specialization of type descriptor instance for void; returns null handle
175   template <>
176   class type_instance<void>
177   {
178   public:
179     Standard_EXPORT static Handle(Standard_Type) get () { return 0; }
180   };
181
182   // Implementation of static function returning instance of the
183   // type descriptor
184   template <typename T>
185   const Handle(Standard_Type)& type_instance<T>::get ()
186   {
187 #if (defined(_MSC_VER) && _MSC_VER < 1900) || \
188     (defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)) && \
189      ! defined(__clang__) && ! defined(__INTEL_COMPILER))
190     // ensure that myInstance is instantiated
191     (void)myInstance;
192 #endif
193
194     // static variable inside function ensures that descriptors
195     // are initialized in correct sequence
196     static Handle(Standard_Type) anInstance =
197       Standard_Type::Register (typeid(T).name(), T::get_type_name(), sizeof(T), 
198                                type_instance<typename T::base_type>::get());
199     return anInstance;
200   }
201
202   // Static class field is defined to ensure initialization of all type
203   // descriptors at load time of the library on compilers not supporting N2660:
204   // - VC++ below 14 (VS 2015)
205   // - GCC below 4.3
206   // Intel compiler reports itself as GCC on Linux and VC++ on Windows,
207   // and is claimed to support N2660 on Linux and on Windows "in VS2015 mode".
208   // CLang should support N2660 since version 2.9, but it is not clear how to 
209   // check its version reliably (on Linux it says it is GCC 4.2).
210 #if (defined(_MSC_VER) && _MSC_VER < 1900) || \
211     (defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)) && \
212      ! defined(__clang__) && ! defined(__INTEL_COMPILER))
213
214   template <typename T>
215   Handle(Standard_Type) type_instance<T>::myInstance (get());
216
217 #endif
218 }
219
220 //! Operator printing type descriptor to stream
221 inline Standard_OStream& operator << (Standard_OStream& theStream, const Handle(Standard_Type)& theType) 
222 {
223   theType->Print (theStream);
224   return theStream;
225 }
226
227 //! Definition of Handle_Standard_Type as typedef for compatibility
228 DEFINE_STANDARD_HANDLE(Standard_Type,Standard_Transient)
229
230 #endif // _Standard_Type_HeaderFile