| 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 | { |
| 126 | return this->entity == theHandle.entity; |
| 127 | } |
| 128 | |
| 129 | //! Check for equality |
| 130 | bool operator== (const Standard_Transient *thePtr) const |
| 131 | { |
| 132 | return this->entity == thePtr; |
| 133 | } |
| 134 | |
| 135 | //! Check for equality |
| 136 | friend bool operator== (const Standard_Transient *left, const handle& right) |
| 137 | { |
| 138 | return left == right.entity; |
| 139 | } |
| 140 | |
| 141 | //! Check for inequality |
| 142 | template <class T2> |
| 143 | bool operator!= (const handle<T2>& theHandle) const |
| 144 | { |
| 145 | return this->entity != theHandle.entity; |
| 146 | } |
| 147 | |
| 148 | //! Check for inequality |
| 149 | bool operator!= (const Standard_Transient *thePtr) const |
| 150 | { |
| 151 | return this->entity != thePtr; |
| 152 | } |
| 153 | |
| 154 | //! Check for inequality |
| 155 | friend bool operator!= (const Standard_Transient *left, const handle& right) |
| 156 | { |
| 157 | return left != right.entity; |
| 158 | } |
| 159 | |
| 160 | //! Down casting operator |
| 161 | template <class T2> |
| 162 | static handle DownCast (const handle<T2>& theObject) |
| 163 | { |
| 164 | return handle (dynamic_cast<T*>(const_cast<T2*>(theObject.get()))); |
| 165 | } |
| 166 | |
| 167 | //! Down casting operator |
| 168 | template <class T2> |
| 169 | static handle DownCast (const T2* thePtr) |
| 170 | { |
| 171 | return handle (dynamic_cast<T*>(const_cast<T2*>(thePtr))); |
| 172 | } |
| 173 | |
| 174 | #if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800) || (defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3) |
| 175 | |
| 176 | //! Upcast to const reference to base type. |
| 177 | template <class T2, typename = typename std::enable_if<std::is_base_of<T2, T>::value>::type> |
| 178 | operator const handle<T2>& () const |
| 179 | { |
| 180 | return reinterpret_cast<const handle<T2>&>(*this); |
| 181 | } |
| 182 | |
| 183 | //! Upcast to non-const reference to base type. |
| 184 | //! NB: this cast can be dangerous, see #26377 |
| 185 | template <class T2, typename = typename std::enable_if<std::is_base_of<T2, T>::value>::type> |
| 186 | operator handle<T2>& () |
| 187 | { |
| 188 | return reinterpret_cast<handle<T2>&>(*this); |
| 189 | } |
| 190 | |
| 191 | #else /* fallback version for compilers not supporting default arguments of function templates (VC10, VC11, GCC below 4.3) */ |
| 192 | |
| 193 | //! Upcast to const reference to base type. |
| 194 | //! NB: this implementation will cause ambiguity errors on calls to overloaded |
| 195 | //! functions accepting handles to different types, since compatibility is |
| 196 | //! checked in the cast code rather than ensured by SFINAE (possible with C++11) |
| 197 | template <class T2> |
| 198 | operator const handle<T2>& () const |
| 199 | { |
| 200 | // error "type is not a member of enable_if" will be generated if T2 is not sub-type of T |
| 201 | // (handle is being cast to const& to handle of non-base type) |
| 202 | return reinterpret_cast<typename std::enable_if<std::is_base_of<T2, T>::value, const handle<T2>&>::type>(*this); |
| 203 | } |
| 204 | |
| 205 | //! Upcast to non-const reference to base type. |
| 206 | //! NB: this cast can be dangerous, see #26377 |
| 207 | template <class T2> |
| 208 | operator handle<T2>& () |
| 209 | { |
| 210 | // error "type is not a member of enable_if" will be generated if T2 is not sub-type of T |
| 211 | // (handle is being cast to const& to handle of non-base type) |
| 212 | return reinterpret_cast<typename std::enable_if<std::is_base_of<T2, T>::value, handle<T2>&>::type>(*this); |
| 213 | } |
| 214 | |
| 215 | #endif |
| 216 | |
| 217 | private: |
| 218 | |
| 219 | //! Assignment |
| 220 | void Assign (Standard_Transient *thePtr) |
| 221 | { |
| 222 | if (thePtr == entity) |
| 223 | return; |
| 224 | EndScope(); |
| 225 | entity = thePtr; |
| 226 | BeginScope(); |
| 227 | } |
| 228 | |
| 229 | //! Increment reference counter of referred object |
| 230 | void BeginScope() |
| 231 | { |
| 232 | if (entity != 0) |
| 233 | entity->IncrementRefCounter(); |
| 234 | } |
| 235 | |
| 236 | //! Decrement reference counter and if 0, destroy referred object |
| 237 | void EndScope() |
| 238 | { |
| 239 | if (entity != 0 && entity->DecrementRefCounter() == 0) |
| 240 | entity->Delete(); |
| 241 | entity = 0; |
| 242 | } |
| 243 | |
| 244 | template <class T2> friend class handle; |
| 245 | |
| 246 | private: |
| 247 | Standard_Transient* entity; |
| 248 | }; |
| 249 | |
| 250 | } // namespace opencascade |
| 251 | |
| 252 | //! Define Handle() macro |
| 253 | #define Handle(Class) opencascade::handle<Class> |
| 254 | |
| 255 | //! Global method HashCode(), for use in hash maps |
| 256 | template <class T> |
| 257 | inline Standard_Integer HashCode (const Handle(T)& theHandle, const Standard_Integer theUpper) |
| 258 | { |
| 259 | return ::HashCode (const_cast<Standard_Address>(static_cast<const void*>(theHandle.get())), theUpper); |
| 260 | } |
| 261 | |
| 262 | //! For compatibility with previous versions of OCCT, defines typedef opencascade::handle<Class> Handle(Class) |
| 263 | #define DEFINE_STANDARD_HANDLECLASS(C1,C2,BC) typedef Handle(C1) Handle_##C1; |
| 264 | #define DEFINE_STANDARD_HANDLE(C1,C2) DEFINE_STANDARD_HANDLECLASS(C1,C2,Standard_Transient) |
| 265 | #define DEFINE_STANDARD_PHANDLE(C1,C2) DEFINE_STANDARD_HANDLECLASS(C1,C2,Standard_Persistent) |
| 266 | |
| 267 | #endif |