9e7a3a6a5e4436b9bf60cd40d7b5d7a118771328
[occt.git] / src / Standard / Standard_Handle.hxx
1 // Copyright (c) 2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #ifndef _Standard_Handle_HeaderFile
15 #define _Standard_Handle_HeaderFile
16
17 #include <Standard_Address.hxx>
18 #include <Standard_Stream.hxx>
19 #include <Standard_Transient.hxx>
20
21 #include <type_traits>
22
23 class Standard_Transient;
24
25 //! Namespace opencascade is intended for low-level template classes and functions
26 namespace opencascade {
27
28   //! Namespace opencascade::std includes templates from C++11 std namespace used by
29   //! OCCT classes. These definitions are imported from std namespace, plus (on older 
30   //! compilers) from std::tr1, or implemented by custom code where neither std 
31   //! not std::tr1 provide necessary definitions.
32   namespace std
33   {
34   // import all available standard stuff from std namespace
35   using namespace ::std;
36
37 // for old MSVC compiler, some standard templates are defined in std::tr1 namespace,
38 // and some missing ones are implemented here
39 #if(defined(_MSC_VER) && (_MSC_VER < 1600))
40   using namespace ::std::tr1;
41   
42   // C++11 template class enable_if
43   template<bool Test, class Type = void>
44   struct enable_if
45   {// type is undefined for assumed !_Test
46   };
47
48   template<class _Type>
49   struct enable_if<true, _Type>
50   {// type is _Type for _Test
51     typedef _Type type;
52   };
53
54   template<bool Condition, typename TypeTrue, typename TypeFalse>
55   struct conditional
56   {
57     typedef TypeTrue type;
58   };
59
60   template<typename TypeTrue, typename TypeFalse>
61   struct conditional<false, TypeTrue, TypeFalse>
62   {
63     typedef TypeFalse type;
64   };
65
66 #endif
67
68   } // namespace opencascade::std
69
70   //! Trait yielding true if class T1 is base of T2 but not the same
71   template <class T1, class T2, class Dummy = void>
72   struct is_base_but_not_same : opencascade::std::is_base_of <T1, T2> {};
73
74   //! Explicit specialization of is_base_of trait to workaround the
75   //! requirement of type to be complete when T1 and T2 are the same.
76   template <class T1, class T2>
77   struct is_base_but_not_same <T1, T2, typename opencascade::std::enable_if <opencascade::std::is_same <T1, T2>::value>::type> : opencascade::std::false_type {};
78
79   //! Intrusive smart pointer for use with Standard_Transient class and its descendants.
80   //!
81   //! This class is similar to boost::intrusive_ptr<>. The reference counter
82   //! is part of the base class (Standard_Transient), thus creation of a handle
83   //! does not require allocation of additional memory for the counter.
84   //! All handles to the same object share the common counter; object is deleted
85   //! when the last handle pointing on it is destroyed. It is safe to create a new
86   //! handle from plain C pointer to the object already pointed by another handle.
87   //! The same object can be referenced by handles of different types (as soon as 
88   //! they are compatible with the object type).
89   //!
90   //! Handle has type cast operator to const reference to handle to the base
91   //! types, which allows it to be passed by reference in functions accepting 
92   //! reference to handle to base class, without copying.
93   //!
94   //! By default, the type cast operator is provided also for non-const reference.
95   //! These casts (potentially unsafe) can be disabled by defining macro
96   //! OCCT_HANDLE_NOCAST; if it is defined, generalized copy constructor
97   //! and assignment operators are defined allowing to initialize handle
98   //! of base type from handle to derived type.
99   //!
100   //! Weak pointers are not supported.
101   template <class T>
102   class handle
103   {
104   public:
105     //! STL-compliant typedef of contained type
106     typedef T element_type;
107
108   public:
109   
110     //! Empty constructor
111     handle () : entity(0) {}
112
113     //! Constructor from pointer to new object
114     handle (const T *thePtr) : entity(const_cast<T*>(thePtr))
115     {
116       BeginScope();
117     }
118
119     //! Copy constructor
120     handle (const handle& theHandle) : entity(theHandle.entity)
121     {
122       BeginScope();
123     }
124
125 #if(defined(_MSC_VER) && (_MSC_VER < 1600))
126 #else
127     //! Move constructor
128     handle (handle&& theHandle) : entity(theHandle.entity)
129     {
130       theHandle.entity = 0;
131     }
132 #endif
133
134     //! Destructor
135     ~handle ()
136     {
137       EndScope();
138     }
139
140     //! Nullify the handle
141     void Nullify()
142     {
143       EndScope();
144     }
145
146     //! Check for being null
147     bool IsNull() const { return entity == 0; } 
148
149     //! Reset by new pointer
150     void reset (T* thePtr)
151     {
152       Assign (thePtr);
153     }
154
155     //! Assignment operator
156     handle& operator= (const handle& theHandle)
157     {
158       Assign (theHandle.entity);
159       return *this;
160     }
161
162     //! Assignment to pointer
163     handle& operator= (const T* thePtr)
164     {
165       Assign (const_cast<T*>(thePtr));
166       return *this;
167     }
168
169 #if(defined(_MSC_VER) && (_MSC_VER < 1600))
170 #else
171     //! Move operator
172     handle& operator= (handle&& theHandle)
173     {
174       std::swap (this->entity, theHandle.entity);
175       return *this;
176     }
177 #endif
178
179     //! STL-like cast to pointer to referred object (note non-const).
180     //! @sa std::shared_ptr::get()
181     T* get() const { return static_cast<T*>(this->entity); }
182
183     //! Member access operator (note non-const)
184     T* operator-> () const { return static_cast<T*>(this->entity); }
185
186     //! Dereferencing operator (note non-const)
187     T& operator* () const { return *get(); }
188
189     //! Check for equality
190     template <class T2>
191     bool operator== (const handle<T2>& theHandle) const
192     { 
193       return get() == theHandle.get();
194     }
195
196     //! Check for equality
197     template <class T2>
198     bool operator== (const T2 *thePtr) const
199     { 
200       return get() == thePtr;
201     }
202
203     //! Check for equality
204     template <class T2>
205     friend bool operator== (const T2 *left, const handle& right)
206     {
207       return left == right.get();
208     }
209
210     //! Check for inequality
211     template <class T2>
212     bool operator!= (const handle<T2>& theHandle) const
213     {
214       return get() != theHandle.get();
215     }
216
217     //! Check for inequality
218     template <class T2>
219     bool operator!= (const T2 *thePtr) const
220     {
221       return get() != thePtr;
222     }
223
224     //! Check for inequality
225     template <class T2>
226     friend bool operator!= (const T2 *left, const handle& right)
227     {
228       return left != right.get();
229     }
230
231     //! Compare operator for possible use in std::map<> etc. 
232     template <class T2>
233     bool operator< (const handle<T2>& theHandle) const
234     { 
235       return get() < theHandle.get();
236     }
237
238     //! Down casting operator from handle to base type
239     template <class T2>
240     static typename opencascade::std::enable_if<is_base_but_not_same<T2, T>::value, handle>::type
241       DownCast (const handle<T2>& theObject)
242     {
243       return handle (dynamic_cast<T*>(const_cast<T2*>(theObject.get())));
244     }
245
246     //! Down casting operator from pointer to base type
247     template <class T2>
248     static typename opencascade::std::enable_if<is_base_but_not_same<T2, T>::value, handle>::type 
249       DownCast (const T2* thePtr)
250     {
251       return handle (dynamic_cast<T*>(const_cast<T2*>(thePtr)));
252     }
253
254     //! For compatibility, define down casting operator from non-base type, as deprecated
255     template <class T2>
256     Standard_DEPRECATED("down-casting from object of the same or unrelated type is meaningless")
257     static handle DownCast (const handle<T2>& theObject, typename opencascade::std::enable_if<!is_base_but_not_same<T2, T>::value, void*>::type = 0)
258     {
259       return handle (dynamic_cast<T*>(const_cast<T2*>(theObject.get())));
260     }
261
262     //! For compatibility, define down casting operator from non-base type, as deprecated
263     template <class T2>
264     Standard_DEPRECATED("down-casting from object of the same or unrelated type is meaningless")
265     static handle DownCast (const T2* thePtr, typename opencascade::std::enable_if<!is_base_but_not_same<T2, T>::value, void*>::type = 0)
266     {
267       return handle (dynamic_cast<T*>(const_cast<T2*>(thePtr)));
268     }
269
270 #if (defined(__clang__)) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1300) || \
271     (defined(_MSC_VER) && _MSC_VER >= 1800) || \
272     (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
273
274     //! Conversion to bool for use in conditional expressions
275     explicit operator bool () const
276     { 
277       return entity != nullptr;
278     }
279
280 #else /* fallback version for compilers not supporting explicit conversion operators (VC10, VC11, GCC below 4.5) */
281
282     //! Conversion to bool-compatible type for use in conditional expressions
283     operator Standard_Transient* handle::* () const
284     { 
285       return entity ? &handle::entity : 0;
286     }
287
288 #endif
289
290     // Support of conversions to handle of base type:
291     // - copy and move constructors and assignment operators if OCCT_HANDLE_NOCAST is defined
292     // - operators of upcast to const reference to base type otherwise
293 #if (defined(__clang__)) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1206) || \
294     (defined(_MSC_VER) && _MSC_VER >= 1800) || \
295     (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
296
297 #ifdef OCCT_HANDLE_NOCAST
298
299     //! Generalized copy constructor.
300     //! Constructs handle holding entity of base type (T) from the one which holds entity of derived type (T2).
301     template <class T2, typename = typename std::enable_if <is_base_but_not_same <T, T2>::value>::type>
302     handle (const handle<T2>& theHandle) :
303       entity(theHandle.entity)
304     {
305       BeginScope();
306     }
307
308     //! Generalized move constructor
309     template <class T2, typename = typename std::enable_if <is_base_but_not_same <T, T2>::value>::type>
310     handle (handle<T2>&& theHandle)
311       : entity(theHandle.entity)
312     {
313       theHandle.entity = 0;
314     }
315
316     //! Generalized assignment operator
317     template <class T2, typename = typename std::enable_if <is_base_but_not_same <T, T2>::value>::type>
318     handle operator = (const handle<T2>& theHandle)
319     {
320       Assign (theHandle.entity);
321       return *this;
322     }
323
324     //! Generalized move operator
325     template <class T2, typename = typename std::enable_if <is_base_but_not_same <T, T2>::value>::type>
326     handle& operator= (handle<T2>&& theHandle)
327     {
328       std::swap (this->entity, theHandle.entity);
329       return *this;
330     }
331
332 #else
333
334     //! Upcast to const reference to base type.
335     template <class T2, typename = typename std::enable_if<is_base_but_not_same<T2, T>::value>::type>
336     operator const handle<T2>& () const
337     {
338       return reinterpret_cast<const handle<T2>&>(*this);
339     }
340
341     //! Upcast to non-const reference to base type.
342     //! NB: this cast can be dangerous, but required for legacy code; see #26377
343     template <class T2, typename = typename std::enable_if<is_base_but_not_same<T2, T>::value>::type>
344     operator handle<T2>& ()
345     {
346       return reinterpret_cast<handle<T2>&>(*this);
347     }
348
349 #endif /* OCCT_HANDLE_NOCAST */
350
351 #else /* fallback version for compilers not supporting default arguments of function templates (VC10, VC11, GCC below 4.3) */
352
353 #ifdef OCCT_HANDLE_NOCAST
354
355     //! Generalized copy constructor.
356     //! Constructs handle holding entity of base type (T) from the one which holds entity of derived type (T2).
357     template <class T2>
358     handle (const handle<T2>& theHandle, typename std::enable_if <is_base_but_not_same <T, T2>::value>::type* = nullptr) :
359       entity(theHandle.entity)
360     {
361       BeginScope();
362     }
363
364 #if(defined(_MSC_VER) && (_MSC_VER < 1600))
365 #else
366     //! Generalized move constructor
367     template <class T2>
368     handle (handle<T2>&& theHandle, typename std::enable_if <is_base_but_not_same <T, T2>::value>::type* = nullptr)
369       : entity(theHandle.entity)
370     {
371       theHandle.entity = 0;
372     }
373 #endif
374
375     //! Generalized assignment operator.
376     template <class T2>
377     handle operator = (const handle<T2>& theHandle)
378     {
379       std::enable_if <is_base_but_not_same <T, T2>::value, void*>::type aTypeCheckHelperVar;
380       (void)aTypeCheckHelperVar;
381       Assign (theHandle.entity);
382       return *this;
383     }
384
385 #if(defined(_MSC_VER) && (_MSC_VER < 1600))
386 #else
387     //! Generalized move operator
388     template <class T2>
389     handle& operator= (handle<T2>&& theHandle)
390     {
391       std::enable_if <is_base_but_not_same <T, T2>::value, void*>::type aTypeCheckHelperVar;
392       (void)aTypeCheckHelperVar;
393       std::swap (this->entity, theHandle.entity);
394       return *this;
395     }
396 #endif
397
398 #else
399
400     //! Upcast to const reference to base type.
401     //! NB: this implementation will cause ambiguity errors on calls to overloaded
402     //! functions accepting handles to different types, since compatibility is 
403     //! checked in the cast code rather than ensured by SFINAE (possible with C++11)
404     template <class T2>
405     operator const handle<T2>& () const
406     {
407       // error "type is not a member of enable_if" will be generated if T2 is not sub-type of T
408       // (handle is being cast to const& to handle of non-base type)
409       return reinterpret_cast<typename opencascade::std::enable_if<is_base_but_not_same<T2, T>::value, const handle<T2>&>::type>(*this);
410     }
411
412     //! Upcast to non-const reference to base type.
413     //! NB: this cast can be dangerous, but required for legacy code; see #26377
414     template <class T2>
415     Standard_DEPRECATED("Passing non-const reference to handle of base type in function is unsafe; use variable of exact type")
416     operator handle<T2>& ()
417     {
418       // error "type is not a member of enable_if" will be generated if T2 is not sub-type of T
419       // (handle is being cast to const& to handle of non-base type)
420       return reinterpret_cast<typename opencascade::std::enable_if<is_base_but_not_same<T2, T>::value, handle<T2>&>::type>(*this);
421     }
422
423 #endif /* OCCT_HANDLE_NOCAST */
424
425 #endif /* compiler switch */
426
427   private:
428
429     //! Assignment
430     void Assign (Standard_Transient *thePtr)
431     {
432       if (thePtr == entity)
433         return;
434       EndScope();
435       entity = thePtr;
436       BeginScope();
437     }
438   
439     //! Increment reference counter of referred object 
440     void BeginScope()
441     {
442       if (entity != 0)
443         entity->IncrementRefCounter();
444     }
445
446     //! Decrement reference counter and if 0, destroy referred object
447     void EndScope()
448     {
449       if (entity != 0 && entity->DecrementRefCounter() == 0)
450         entity->Delete();
451       entity = 0;
452     }
453
454     template <class T2> friend class handle;
455
456   private:
457     Standard_Transient* entity;
458   };
459
460 } // namespace opencascade
461
462 //! Define Handle() macro
463 #define Handle(Class) opencascade::handle<Class>
464
465 //! Global method HashCode(), for use in hash maps
466 template <class T>
467 inline Standard_Integer HashCode (const Handle(T)& theHandle, const Standard_Integer theUpper)
468 {
469   return ::HashCode (const_cast<Standard_Address>(static_cast<const void*>(theHandle.get())), theUpper);
470 }
471
472 //! For compatibility with previous versions of OCCT, define Handle_Class alias for opencascade::handle<Class>.
473 #if (defined(_MSC_VER) && _MSC_VER >= 1800) 
474 //! For Visual Studio 2013+, define Handle_Class as non-template class to allow exporting this type in C++/CLI.
475 #define DEFINE_STANDARD_HANDLECLASS(C1,C2,BC) class C1; class Handle_##C1 : public Handle(C1) \
476 { \
477 public: \
478   Handle_##C1() {} \
479   Handle_##C1(Handle(C1)&& theHandle) : Handle(C1)(theHandle) {} \
480   template <class T2, typename = typename std::enable_if <std::is_base_of <C1,T2>::value>::type> \
481   inline Handle_##C1(const opencascade::handle<T2>& theOther) : Handle(C1)(theOther) {} \
482   template <class T2, typename = typename std::enable_if <std::is_base_of <C1,T2>::value>::type> \
483   inline Handle_##C1(const T2* theOther) : Handle(C1)(theOther) {} \
484   template<typename T> inline Handle_##C1& operator=(T theOther) { Handle(C1)::operator=(theOther); return *this; } \
485 };
486 #else
487 //! For other compilers, use simple typedef
488 #define DEFINE_STANDARD_HANDLECLASS(C1,C2,BC) class C1; typedef Handle(C1) Handle_##C1;
489 #endif
490
491 #define DEFINE_STANDARD_HANDLE(C1,C2) DEFINE_STANDARD_HANDLECLASS(C1,C2,Standard_Transient)
492 #define DEFINE_STANDARD_PHANDLE(C1,C2) DEFINE_STANDARD_HANDLECLASS(C1,C2,Standard_Persistent)
493
494 #endif