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 | |
27 | //! Intrusive smart pointer for use with Standard_Transient class and its descendants. |
28 | //! |
29 | //! This class is similar to boost::intrusive_ptr<>, with additional |
30 | //! feature historically supported by Handles in OCCT: |
31 | //! it has type conversion to const reference to handle to the base types, |
32 | //! which allows it to be passed by reference |
33 | //! in functions accepring reference to handle to base class. |
34 | template <class T> |
35 | class handle |
36 | { |
37 | public: |
38 | //! STL-compliant typedef of contained type |
39 | typedef T element_type; |
40 | |
41 | public: |
42 | |
43 | //! Empty constructor |
44 | handle () : entity(0) {} |
45 | |
46 | //! Constructor from pointer to new object |
47 | handle (const T *thePtr) : entity(const_cast<T*>(thePtr)) |
48 | { |
49 | BeginScope(); |
50 | } |
51 | /* TODO: uncomment and remove const from method above |
52 | //! Constructor from const pointer to new object; |
53 | //! will raise exception if object's reference counter is zero |
54 | explicit handle (const T *thePtr) : entity(thePtr->This()) |
55 | { |
56 | BeginScope(); |
57 | } |
58 | */ |
59 | //! Copy constructor |
60 | handle (const handle& theHandle) : entity(theHandle.entity) |
61 | { |
62 | BeginScope(); |
63 | } |
64 | |
65 | //! Destructor |
66 | ~handle () |
67 | { |
68 | EndScope(); |
69 | } |
70 | |
71 | //! Nullify the handle |
72 | void Nullify() |
73 | { |
74 | EndScope(); |
75 | } |
76 | |
77 | //! Check for being null |
78 | bool IsNull() const { return entity == 0; } |
79 | |
80 | //! Reset by new pointer |
81 | void reset (T* thePtr) |
82 | { |
83 | Assign (thePtr); |
84 | } |
85 | |
86 | //! Assignment operator |
87 | handle& operator= (const handle& theHandle) |
88 | { |
89 | Assign (theHandle.entity); |
90 | return *this; |
91 | } |
92 | |
93 | //! Assignment to pointer |
94 | handle& operator= (const T* thePtr) |
95 | { |
96 | Assign (const_cast<T*>(thePtr)); |
97 | return *this; |
98 | } |
99 | /* uncomment along with constructor |
100 | //! Assignment to pointer to const object |
101 | handle& operator= (const T* thePtr) |
102 | { |
103 | Assign (thePtr->This()); |
104 | return *this; |
105 | } |
106 | */ |
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 | |
205 | //! Upcast to const reference to base type. |
d9e90905 |
206 | #if (defined(__clang__)) || (defined(__INTEL_COMPILER) && __INTEL_COMPILER >= 1206) || \ |
207 | (defined(_MSC_VER) && _MSC_VER >= 1800) || \ |
208 | (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) |
e7195ab4 |
209 | |
210 | //! Upcast to const reference to base type. |
211 | template <class T2, typename = typename std::enable_if<std::is_base_of<T2, T>::value>::type> |
212 | operator const handle<T2>& () const |
213 | { |
214 | return reinterpret_cast<const handle<T2>&>(*this); |
215 | } |
216 | |
217 | //! Upcast to non-const reference to base type. |
d1a67b9d |
218 | //! NB: this cast can be dangerous, but required for legacy code; see #26377 |
e7195ab4 |
219 | template <class T2, typename = typename std::enable_if<std::is_base_of<T2, T>::value>::type> |
220 | operator handle<T2>& () |
221 | { |
222 | return reinterpret_cast<handle<T2>&>(*this); |
223 | } |
224 | |
225 | #else /* fallback version for compilers not supporting default arguments of function templates (VC10, VC11, GCC below 4.3) */ |
226 | |
227 | //! Upcast to const reference to base type. |
228 | //! NB: this implementation will cause ambiguity errors on calls to overloaded |
229 | //! functions accepting handles to different types, since compatibility is |
230 | //! checked in the cast code rather than ensured by SFINAE (possible with C++11) |
231 | template <class T2> |
232 | operator const handle<T2>& () const |
233 | { |
234 | // error "type is not a member of enable_if" will be generated if T2 is not sub-type of T |
235 | // (handle is being cast to const& to handle of non-base type) |
236 | return reinterpret_cast<typename std::enable_if<std::is_base_of<T2, T>::value, const handle<T2>&>::type>(*this); |
237 | } |
238 | |
239 | //! Upcast to non-const reference to base type. |
d1a67b9d |
240 | //! NB: this cast can be dangerous, but required for legacy code; see #26377 |
e7195ab4 |
241 | template <class T2> |
242 | operator handle<T2>& () |
243 | { |
244 | // error "type is not a member of enable_if" will be generated if T2 is not sub-type of T |
245 | // (handle is being cast to const& to handle of non-base type) |
246 | return reinterpret_cast<typename std::enable_if<std::is_base_of<T2, T>::value, handle<T2>&>::type>(*this); |
247 | } |
248 | |
249 | #endif |
250 | |
251 | private: |
252 | |
253 | //! Assignment |
254 | void Assign (Standard_Transient *thePtr) |
255 | { |
256 | if (thePtr == entity) |
257 | return; |
258 | EndScope(); |
259 | entity = thePtr; |
260 | BeginScope(); |
261 | } |
262 | |
263 | //! Increment reference counter of referred object |
264 | void BeginScope() |
265 | { |
266 | if (entity != 0) |
267 | entity->IncrementRefCounter(); |
268 | } |
269 | |
270 | //! Decrement reference counter and if 0, destroy referred object |
271 | void EndScope() |
272 | { |
273 | if (entity != 0 && entity->DecrementRefCounter() == 0) |
274 | entity->Delete(); |
275 | entity = 0; |
276 | } |
277 | |
278 | template <class T2> friend class handle; |
279 | |
280 | private: |
281 | Standard_Transient* entity; |
282 | }; |
283 | |
284 | } // namespace opencascade |
285 | |
286 | //! Define Handle() macro |
287 | #define Handle(Class) opencascade::handle<Class> |
288 | |
289 | //! Global method HashCode(), for use in hash maps |
290 | template <class T> |
291 | inline Standard_Integer HashCode (const Handle(T)& theHandle, const Standard_Integer theUpper) |
292 | { |
293 | return ::HashCode (const_cast<Standard_Address>(static_cast<const void*>(theHandle.get())), theUpper); |
294 | } |
295 | |
35c0599a |
296 | //! For compatibility with previous versions of OCCT, defines typedef opencascade::handle<Class> Handle(Class) |
d1a67b9d |
297 | #define DEFINE_STANDARD_HANDLECLASS(C1,C2,BC) class C1; typedef Handle(C1) Handle_##C1; |
e7195ab4 |
298 | #define DEFINE_STANDARD_HANDLE(C1,C2) DEFINE_STANDARD_HANDLECLASS(C1,C2,Standard_Transient) |
299 | #define DEFINE_STANDARD_PHANDLE(C1,C2) DEFINE_STANDARD_HANDLECLASS(C1,C2,Standard_Persistent) |
300 | |
301 | #endif |