e7195ab4 |
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 { |
26 | |
4796758e |
27 | //! Trait yielding true if class T1 is base of T2 but not the same |
28 | template <class T1, class T2, class Dummy = void> |
29 | struct is_base_but_not_same : std::is_base_of <T1, T2> {}; |
30 | |
31 | //! Explicit specialization of is_base_of trait to workaround the |
32 | //! requirement of type to be complete when T1 and T2 are the same. |
33 | template <class T1, class T2> |
34 | struct is_base_but_not_same <T1, T2, typename std::enable_if <std::is_same <T1, T2>::value>::type> : std::false_type {}; |
35 | |
e7195ab4 |
36 | //! Intrusive smart pointer for use with Standard_Transient class and its descendants. |
37 | //! |
38 | //! This class is similar to boost::intrusive_ptr<>, with additional |
39 | //! feature historically supported by Handles in OCCT: |
40 | //! it has type conversion to const reference to handle to the base types, |
41 | //! which allows it to be passed by reference |
4796758e |
42 | //! in functions accepting reference to handle to base class. |
43 | //! |
44 | //! These casts (potentially unsafe) can be disabled by defining macro |
45 | //! OCCT_HANDLE_NOCAST; if it is defined, generalized copy constructor |
46 | //! and assignment operators are defined allowing to initialize handle |
47 | //! of base type from handle to derived type. |
e7195ab4 |
48 | template <class T> |
49 | class handle |
50 | { |
51 | public: |
52 | //! STL-compliant typedef of contained type |
53 | typedef T element_type; |
54 | |
55 | public: |
56 | |
57 | //! Empty constructor |
58 | handle () : entity(0) {} |
59 | |
60 | //! Constructor from pointer to new object |
61 | handle (const T *thePtr) : entity(const_cast<T*>(thePtr)) |
62 | { |
63 | BeginScope(); |
64 | } |
4796758e |
65 | |
e7195ab4 |
66 | //! Copy constructor |
67 | handle (const handle& theHandle) : entity(theHandle.entity) |
68 | { |
69 | BeginScope(); |
70 | } |
71 | |
72 | //! Destructor |
73 | ~handle () |
74 | { |
75 | EndScope(); |
76 | } |
77 | |
78 | //! Nullify the handle |
79 | void Nullify() |
80 | { |
81 | EndScope(); |
82 | } |
83 | |
84 | //! Check for being null |
85 | bool IsNull() const { return entity == 0; } |
86 | |
87 | //! Reset by new pointer |
88 | void reset (T* thePtr) |
89 | { |
90 | Assign (thePtr); |
91 | } |
92 | |
93 | //! Assignment operator |
94 | handle& operator= (const handle& theHandle) |
95 | { |
96 | Assign (theHandle.entity); |
97 | return *this; |
98 | } |
99 | |
100 | //! Assignment to pointer |
101 | handle& operator= (const T* thePtr) |
102 | { |
103 | Assign (const_cast<T*>(thePtr)); |
104 | return *this; |
105 | } |
4796758e |
106 | |
e7195ab4 |
107 | //! STL-like cast to pointer to referred object |
108 | const T* get () const { return static_cast<const T*>(this->entity); } |
109 | |
110 | //! STL-like cast to pointer to referred object |
111 | T* get () { return static_cast<T*>(this->entity); } |
112 | |
113 | //! Member access operator (note non-const) |
114 | T* operator-> () const { return static_cast<T*>(this->entity); } |
115 | |
116 | //! Dereferencing operator |
117 | T& operator* () { return *get(); } |
118 | |
119 | //! Const dereferencing operator |
120 | const T& operator*() const { return *get(); } |
121 | |
122 | //! Check for equality |
123 | template <class T2> |
124 | bool operator== (const handle<T2>& theHandle) const |
125 | { |
e8862cf4 |
126 | return get() == theHandle.get(); |
e7195ab4 |
127 | } |
128 | |
129 | //! Check for equality |
e8862cf4 |
130 | template <class T2> |
131 | bool operator== (const T2 *thePtr) const |
e7195ab4 |
132 | { |
e8862cf4 |
133 | return get() == thePtr; |
e7195ab4 |
134 | } |
135 | |
136 | //! Check for equality |
e8862cf4 |
137 | template <class T2> |
138 | friend bool operator== (const T2 *left, const handle& right) |
e7195ab4 |
139 | { |
e8862cf4 |
140 | return left == right.get(); |
e7195ab4 |
141 | } |
142 | |
143 | //! Check for inequality |
144 | template <class T2> |
145 | bool operator!= (const handle<T2>& theHandle) const |
146 | { |
e8862cf4 |
147 | return get() != theHandle.get(); |
e7195ab4 |
148 | } |
149 | |
150 | //! Check for inequality |
e8862cf4 |
151 | template <class T2> |
152 | bool operator!= (const T2 *thePtr) const |
e7195ab4 |
153 | { |
e8862cf4 |
154 | return get() != thePtr; |
e7195ab4 |
155 | } |
156 | |
157 | //! Check for inequality |
e8862cf4 |
158 | template <class T2> |
159 | friend bool operator!= (const T2 *left, const handle& right) |
e7195ab4 |
160 | { |
e8862cf4 |
161 | return left != right.get(); |
e7195ab4 |
162 | } |
163 | |
d1a67b9d |
164 | //! Compare operator for possible use in std::map<> etc. |
165 | template <class T2> |
166 | bool operator< (const handle<T2>& theHandle) const |
167 | { |
168 | return get() < theHandle.get(); |
169 | } |
170 | |
e7195ab4 |
171 | //! Down casting operator |
172 | template <class T2> |
173 | static handle DownCast (const handle<T2>& theObject) |
174 | { |
175 | return handle (dynamic_cast<T*>(const_cast<T2*>(theObject.get()))); |
176 | } |
177 | |
178 | //! Down casting operator |
179 | template <class T2> |
180 | static handle DownCast (const T2* thePtr) |
181 | { |
182 | return handle (dynamic_cast<T*>(const_cast<T2*>(thePtr))); |
183 | } |
184 | |
d9e90905 |
185 | #if (defined(__clang__)) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1300) || \ |
186 | (defined(_MSC_VER) && _MSC_VER >= 1800) || \ |
187 | (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) |
d1a67b9d |
188 | |
189 | //! Conversion to bool for use in conditional expressions |
190 | explicit operator bool () const |
191 | { |
192 | return entity != nullptr; |
193 | } |
194 | |
195 | #else /* fallback version for compilers not supporting explicit conversion operators (VC10, VC11, GCC below 4.5) */ |
196 | |
197 | //! Conversion to bool-compatible type for use in conditional expressions |
198 | operator Standard_Transient* handle::* () const |
199 | { |
200 | return entity ? &handle::entity : 0; |
201 | } |
202 | |
203 | #endif |
204 | |
4796758e |
205 | // Support of conversions to handle of base type: |
206 | // - copy and move constructors and assignment operators if OCCT_HANDLE_NOCAST is defined |
207 | // - operators of upcast to const reference to base type otherwise |
d9e90905 |
208 | #if (defined(__clang__)) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1206) || \ |
209 | (defined(_MSC_VER) && _MSC_VER >= 1800) || \ |
210 | (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) |
e7195ab4 |
211 | |
4796758e |
212 | #ifdef OCCT_HANDLE_NOCAST |
213 | |
214 | //! Generalized copy constructor. |
215 | //! Constructs handle holding entity of base type (T) from the one which holds entity of derived type (T2). |
216 | template <class T2, typename = typename std::enable_if <is_base_but_not_same <T, T2>::value>::type> |
217 | handle (const handle<T2>& theHandle) : |
218 | entity(theHandle.entity) |
219 | { |
220 | BeginScope(); |
221 | } |
222 | |
223 | //! Generalized assignment operator |
224 | template <class T2, typename = typename std::enable_if <is_base_but_not_same <T, T2>::value>::type> |
225 | handle operator = (const handle<T2>& theHandle) |
226 | { |
227 | Assign (theHandle.entity); |
228 | return *this; |
229 | } |
230 | |
231 | #else |
232 | |
e7195ab4 |
233 | //! Upcast to const reference to base type. |
4796758e |
234 | template <class T2, typename = typename std::enable_if<is_base_but_not_same<T2, T>::value>::type> |
e7195ab4 |
235 | operator const handle<T2>& () const |
236 | { |
237 | return reinterpret_cast<const handle<T2>&>(*this); |
238 | } |
239 | |
240 | //! Upcast to non-const reference to base type. |
d1a67b9d |
241 | //! NB: this cast can be dangerous, but required for legacy code; see #26377 |
4796758e |
242 | template <class T2, typename = typename std::enable_if<is_base_but_not_same<T2, T>::value>::type> |
e7195ab4 |
243 | operator handle<T2>& () |
244 | { |
245 | return reinterpret_cast<handle<T2>&>(*this); |
246 | } |
247 | |
4796758e |
248 | #endif /* OCCT_HANDLE_NOCAST */ |
249 | |
e7195ab4 |
250 | #else /* fallback version for compilers not supporting default arguments of function templates (VC10, VC11, GCC below 4.3) */ |
251 | |
4796758e |
252 | #ifdef OCCT_HANDLE_NOCAST |
253 | |
254 | //! Generalized copy constructor. |
255 | //! Constructs handle holding entity of base type (T) from the one which holds entity of derived type (T2). |
256 | template <class T2> |
257 | handle (const handle<T2>& theHandle, typename std::enable_if <is_base_but_not_same <T, T2>::value>::type* = nullptr) : |
258 | entity(theHandle.entity) |
259 | { |
260 | BeginScope(); |
261 | } |
262 | |
263 | //! Generalized assignment operator. |
264 | template <class T2> |
265 | handle operator = (const handle<T2>& theHandle) |
266 | { |
267 | std::enable_if <is_base_but_not_same <T, T2>::value, void*>::type aTypeCheckHelperVar; |
268 | (void)aTypeCheckHelperVar; |
269 | Assign (theHandle.entity); |
270 | return *this; |
271 | } |
272 | |
273 | #else |
274 | |
e7195ab4 |
275 | //! Upcast to const reference to base type. |
276 | //! NB: this implementation will cause ambiguity errors on calls to overloaded |
277 | //! functions accepting handles to different types, since compatibility is |
278 | //! checked in the cast code rather than ensured by SFINAE (possible with C++11) |
279 | template <class T2> |
280 | operator const handle<T2>& () const |
281 | { |
282 | // error "type is not a member of enable_if" will be generated if T2 is not sub-type of T |
283 | // (handle is being cast to const& to handle of non-base type) |
4796758e |
284 | return reinterpret_cast<typename std::enable_if<is_base_but_not_same<T2, T>::value, const handle<T2>&>::type>(*this); |
e7195ab4 |
285 | } |
286 | |
287 | //! Upcast to non-const reference to base type. |
d1a67b9d |
288 | //! NB: this cast can be dangerous, but required for legacy code; see #26377 |
e7195ab4 |
289 | template <class T2> |
aa00364d |
290 | Standard_DEPRECATED("Passing non-const reference to handle of base type in function is unsafe; use variable of exact type") |
e7195ab4 |
291 | operator handle<T2>& () |
292 | { |
293 | // error "type is not a member of enable_if" will be generated if T2 is not sub-type of T |
294 | // (handle is being cast to const& to handle of non-base type) |
4796758e |
295 | return reinterpret_cast<typename std::enable_if<is_base_but_not_same<T2, T>::value, handle<T2>&>::type>(*this); |
e7195ab4 |
296 | } |
297 | |
4796758e |
298 | #endif /* OCCT_HANDLE_NOCAST */ |
299 | |
300 | #endif /* compiler switch */ |
e7195ab4 |
301 | |
302 | private: |
303 | |
304 | //! Assignment |
305 | void Assign (Standard_Transient *thePtr) |
306 | { |
307 | if (thePtr == entity) |
308 | return; |
309 | EndScope(); |
310 | entity = thePtr; |
311 | BeginScope(); |
312 | } |
313 | |
314 | //! Increment reference counter of referred object |
315 | void BeginScope() |
316 | { |
317 | if (entity != 0) |
318 | entity->IncrementRefCounter(); |
319 | } |
320 | |
321 | //! Decrement reference counter and if 0, destroy referred object |
322 | void EndScope() |
323 | { |
324 | if (entity != 0 && entity->DecrementRefCounter() == 0) |
325 | entity->Delete(); |
326 | entity = 0; |
327 | } |
328 | |
329 | template <class T2> friend class handle; |
330 | |
331 | private: |
332 | Standard_Transient* entity; |
333 | }; |
334 | |
335 | } // namespace opencascade |
336 | |
337 | //! Define Handle() macro |
338 | #define Handle(Class) opencascade::handle<Class> |
339 | |
340 | //! Global method HashCode(), for use in hash maps |
341 | template <class T> |
342 | inline Standard_Integer HashCode (const Handle(T)& theHandle, const Standard_Integer theUpper) |
343 | { |
344 | return ::HashCode (const_cast<Standard_Address>(static_cast<const void*>(theHandle.get())), theUpper); |
345 | } |
346 | |
35c0599a |
347 | //! For compatibility with previous versions of OCCT, defines typedef opencascade::handle<Class> Handle(Class) |
d1a67b9d |
348 | #define DEFINE_STANDARD_HANDLECLASS(C1,C2,BC) class C1; typedef Handle(C1) Handle_##C1; |
e7195ab4 |
349 | #define DEFINE_STANDARD_HANDLE(C1,C2) DEFINE_STANDARD_HANDLECLASS(C1,C2,Standard_Transient) |
350 | #define DEFINE_STANDARD_PHANDLE(C1,C2) DEFINE_STANDARD_HANDLECLASS(C1,C2,Standard_Persistent) |
351 | |
352 | #endif |