00001 /* 00002 * TypedHandle.hpp 00003 * 00004 * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. 00005 * 00006 * Oracle is a registered trademarks of Oracle Corporation and/or its 00007 * affiliates. 00008 * 00009 * This software is the confidential and proprietary information of Oracle 00010 * Corporation. You shall not disclose such confidential and proprietary 00011 * information and shall use it only in accordance with the terms of the 00012 * license agreement you entered into with Oracle. 00013 * 00014 * This notice may not be removed or altered. 00015 */ 00016 #ifndef COH_TYPED_HANDLE_HPP 00017 #define COH_TYPED_HANDLE_HPP 00018 00019 #include "coherence/lang/compatibility.hpp" 00020 00021 #include "coherence/lang/ChainedHandleElement.hpp" 00022 00023 #include <functional> 00024 #include <ostream> 00025 #include <stddef.h> 00026 #include <typeinfo> 00027 00028 COH_OPEN_NAMESPACE2(coherence,lang) 00029 00030 class Object; 00031 00032 /** 00033 * Reference counting "smart pointer" class for use with Coherence managed 00034 * objects. Managed objects manage their own life cycle, rather the relying on 00035 * user code to identify when they should be deleted. The TypedHandle class 00036 * can be used with any class implementing the coherence::lang::Object 00037 * interface. 00038 * 00039 * By convention each Object implementation will include two typedefs for 00040 * TypedHandle to make their usage easier. For instance the class "Foo" would 00041 * define Foo::Handle as a TypedHandle<Foo>. The second typedef is called a 00042 * View, and is analogous to a pointer to a const, that is Foo::View is 00043 * TypedHandle<const Foo>. 00044 * 00045 * TypedHandles are not thread-safe, and should not be used in a multi-threaded 00046 * context even if protected by external synchronization. They should only be 00047 * used as local variables. The most common place where thread-safe handles are 00048 * needed is for object data members. For these cases the Coherence API 00049 * includes thread-safe handles/views, namely MemberHandle/View and 00050 * WeakHandle/View. 00051 * 00052 * @see Object 00053 * @see MemberHandle 00054 * @see MemberView 00055 * @see WeakHandle 00056 * @see WeakView 00057 * @see FinalHandle 00058 * @see FinalView 00059 * 00060 * @author mf 2007.07.05 00061 */ 00062 template<class T> 00063 class TypedHandle 00064 : public ChainedHandleElement 00065 { 00066 // ----- typedefs ------------------------------------------------------- 00067 00068 public: 00069 /** 00070 * A concrete object type that is referenced by this handle. 00071 */ 00072 typedef T ValueType; 00073 00074 00075 // ----- constructors --------------------------------------------------- 00076 00077 public: 00078 /** 00079 * Construct a handle that references NULL. 00080 */ 00081 TypedHandle<T>() 00082 : ChainedHandleElement(constness<T>::applied), m_o(NULL) 00083 { 00084 } 00085 00086 /** 00087 * Construct a handle that references given Object. 00088 * 00089 * @param po a pointer to the Object to reference 00090 */ 00091 TypedHandle<T>(T* po) 00092 : ChainedHandleElement(constness<T>::applied), 00093 m_o(po == NULL || po->_attach(/*fEscaped*/ false) == NULL 00094 ? NULL : po) 00095 { 00096 } 00097 00098 /** 00099 * Construct a handle which is linked to another chained element type. 00100 * This is used for chaining Holders to Handles. 00101 * 00102 * @param po the pointer to assign from 00103 * @param that the "owner" of that pointer 00104 */ 00105 TypedHandle<T>(T* po, const ChainedHandleElement& that) 00106 : ChainedHandleElement(that, constness<T>::applied), m_o(po) 00107 { 00108 } 00109 00110 /** 00111 * Construct a handle from a handle to a derived type. New handle will 00112 * reference the same Object that the given handle. 00113 * 00114 * @param that another handle 00115 */ 00116 template<class DT> TypedHandle<T>(const TypedHandle<DT>& that) 00117 : ChainedHandleElement(that, constness<T>::applied), 00118 m_o(get_pointer(that)) 00119 { 00120 // *** PLEASE READ IF YOU GET BUILD ERRORS HERE **** 00121 // A build error in this call indicates that you've attempted to 00122 // assign two non-compatible handle types, or simply trying to 00123 // assign a View to a Handle. Check your compiler output which 00124 // should state what line in your triggered this template 00125 // instantiation, that is the code which has the error. 00126 } 00127 00128 /** 00129 * Construct a handle from another handle. New handle will reference 00130 * the same Object that the given handle. 00131 * 00132 * @param that another handle 00133 */ 00134 TypedHandle<T>(const TypedHandle<T>& that) 00135 : ChainedHandleElement(that, constness<T>::applied), 00136 m_o(that.get()) 00137 { 00138 } 00139 00140 /** 00141 * Destruct this handle. 00142 */ 00143 ~TypedHandle<T>() 00144 { 00145 // manually inlined unlink logic allows use of constness<T>::applied 00146 // which should result in the elseif being compiled out for Views 00147 if (this == m_prev /* implies && this == m_next */) 00148 { 00149 if (m_o) performAction(action_detach); 00150 } 00151 // COH-9499 - removed m_prev and m_next m_fView pre-checks due to 00152 // compiler issues with GCC 4.1 00153 else if (m_o && !constness<T>::applied && scan()) 00154 { 00155 performAction(action_flip); 00156 } 00157 // else; action_none 00158 00159 // unlink self from chain 00160 m_prev->m_next = m_next; 00161 m_next->m_prev = m_prev; 00162 } 00163 00164 00165 // ----- operators ------------------------------------------------------ 00166 00167 public: 00168 /** 00169 * Dereference this handle, returning <tt>T&</tt>. 00170 * 00171 * @return a raw <tt>T&</tt> reference to the referenced Object 00172 * 00173 * @throws NullPointerException if the this handle is @c NULL 00174 */ 00175 T& operator*() const 00176 { 00177 T* po = m_o; 00178 if (NULL == po) 00179 { 00180 coh_throw_npe(typeid(T)); 00181 } 00182 return *po; 00183 } 00184 00185 /** 00186 * Dereference this handle, returning <tt>T*</tt>. 00187 * 00188 * @return a raw <tt>T*</tt> pointer to the referenced Object 00189 * 00190 * @throws NullPointerException if the this handle is @c NULL 00191 */ 00192 T* operator->() const 00193 { 00194 T* po = m_o; 00195 if (NULL == po) 00196 { 00197 coh_throw_npe(typeid(T)); 00198 } 00199 return po; 00200 } 00201 00202 /** 00203 * Assign this TypedHandle another Object to reference. 00204 */ 00205 TypedHandle<T>& operator=(const TypedHandle<T>& h) 00206 { 00207 set(h.get(), h); 00208 return *this; 00209 } 00210 00211 /** 00212 * Assign this TypedHandle from a handle to a derived type. 00213 */ 00214 template<class DT> 00215 TypedHandle<T>& operator=(const TypedHandle<DT>& h) 00216 { 00217 // *** PLEASE READ IF YOU GET BUILD ERRORS HERE **** 00218 // A build error in this call indicates that you've attempted to 00219 // assign two non-compatible handle types, or simply trying to 00220 // assign a View to a Handle. Check your compiler output which 00221 // should state what line in your triggered this template 00222 // instantiation, that is the code which has the error. 00223 00224 set(get_pointer(h), h); 00225 return *this; 00226 } 00227 00228 /** 00229 * Compare two handles with "less-than" predicate. This is only an 00230 * identity based comparison, and does not take the value into account. 00231 */ 00232 template<class AT> 00233 bool operator<(const TypedHandle<AT>& h) const 00234 { 00235 return ((const Object*) m_o) < ((const Object*) get_pointer(h)); 00236 } 00237 00238 00239 // ----- helper methods ------------------------------------------------- 00240 00241 protected: // protected to prevent easily misunderstandings such as 00242 // hMap.get() which might be interpreted as a call on a map 00243 00244 /** 00245 * Return pointer without null checking. 00246 * Does NOT throw NullPointerException. 00247 * 00248 * One should use <code>h.get()</code> to get raw T* pointer. 00249 * Please do not use neither <code>&*h</code> (as it may throw 00250 * NullPointerException) nor <code>(T*)h</code> (as it may perform 00251 * unsafe unchecked type cast). 00252 */ 00253 T* get() const 00254 { 00255 return m_o; 00256 } 00257 00258 /** 00259 * Set the TypedHandle to attach to the supplied pointer. 00260 * Any existing attachment will be detached. 00261 * 00262 * @param o the address of the object to point to or NULL 00263 */ 00264 void set(T* o, const ChainedHandleElement& that) 00265 { 00266 // manually inlined link logic allows use of constness<T>::applied 00267 // which should result in the elseif being compiled out for Views 00268 if (this == m_prev /* implies && this == m_next */) 00269 { 00270 if (m_o) performAction(action_detach); 00271 } 00272 // COH-9499 - removed m_prev and m_next m_fView pre-checks due to 00273 // compiler issues with GCC 4.1 00274 else if (m_o && !constness<T>::applied && scan()) 00275 { 00276 performAction(action_flip); 00277 } 00278 // else; action_none 00279 00280 // unlink self from chain 00281 m_prev->m_next = m_next; 00282 m_next->m_prev = m_prev; 00283 00284 // link self into new chain 00285 m_prev = &that; 00286 m_next = that.m_next; 00287 00288 m_next->m_prev = that.m_next = this; 00289 00290 m_o = o; 00291 } 00292 00293 /** 00294 * Perform the specified action. 00295 * 00296 * @param nAction the action to perform 00297 */ 00298 void performAction(Action nAction) 00299 { 00300 switch (nAction) 00301 { 00302 case action_flip: 00303 ((const T*) m_o)->_attach(/*fEscaped*/ false); 00304 // fall through 00305 case action_detach: 00306 m_o->_detach(/*fEscaped*/ false); 00307 // fall through 00308 case action_none: 00309 default: 00310 break; 00311 } 00312 } 00313 00314 // ----- functors ------------------------------------------------------- 00315 00316 protected: 00317 /** 00318 * The binary functor that compares objects pointed by the handles 00319 * with the "less-than" operator. 00320 */ 00321 template<class RT> 00322 class value_less_functor 00323 : public std::binary_function<RT, RT, bool> 00324 { 00325 public: 00326 /** 00327 * Compare values pointed by the specified handles with 00328 * "less-than" operator. 00329 */ 00330 bool operator()(const TypedHandle<RT>& h1, 00331 const TypedHandle<RT>& h2) const 00332 { 00333 return h1 && h1->operator<(h2); 00334 } 00335 }; 00336 00337 /** 00338 * The binary functor that compares values pointed by the handles for 00339 * equality. 00340 */ 00341 template<class RT> 00342 class value_equal_functor 00343 : public std::binary_function<RT, RT, bool> 00344 { 00345 public: 00346 /** 00347 * Compare values pointed by the specified handles for 00348 * equality. 00349 */ 00350 bool operator()(const TypedHandle<RT>& h1, 00351 const TypedHandle<RT>& h2) const 00352 { 00353 return h1 == h2 || (h1 && h1->equals(h2)); 00354 } 00355 }; 00356 00357 /** 00358 * Value based hash functor which is compatible with both the SGI and 00359 * MS style hash containers. 00360 */ 00361 template<class RT> 00362 class value_hash_functor 00363 : public std::unary_function<RT, size32_t> 00364 { 00365 public: 00366 // parameters for MS style hash table 00367 enum {bucket_size = 4, min_buckets = 8}; 00368 00369 /** 00370 * Hash computation function for MS and SGI style hash containers. 00371 * 00372 * @param h the handle to hash 00373 * 00374 * @return the hash of the handle 00375 */ 00376 size32_t operator()(const TypedHandle<RT>& h) const 00377 { 00378 return h ? h->hashCode() : 0; 00379 } 00380 00381 /** 00382 * Ordering function for MS style hash containers. 00383 * 00384 * @param h1 the first handle to compare 00385 * @param h2 the second handle to compare 00386 * 00387 * @return true iff *h1 < *h2 00388 */ 00389 bool operator()(const TypedHandle<RT>& h1, 00390 const TypedHandle<RT>& h2) const 00391 { 00392 return h1 && h1->operator<(h2); 00393 } 00394 }; 00395 00396 00397 /** 00398 * Identity based hash functor which is compatible with both the SGI 00399 * and MS style hash containers. 00400 */ 00401 template<class RT> class identity_hash_functor 00402 : public std::unary_function<RT, size32_t> 00403 { 00404 public: 00405 // parameters for MS style hash table 00406 enum {bucket_size = 4, min_buckets = 8}; 00407 00408 /** 00409 * Hash computation function for MS and SGI style hash containers. 00410 * 00411 * @param h the handle to hash 00412 * 00413 * @return the hash of the handle 00414 */ 00415 size32_t operator()(const TypedHandle<RT>& h) const 00416 { 00417 return (size32_t) get_pointer(h); 00418 } 00419 00420 /** 00421 * Ordering function for MS style hash containers. 00422 * 00423 * @param h1 the first handle to compare 00424 * @param h2 the second handle to compare 00425 * 00426 * @return true iff h1 < h2 00427 */ 00428 bool operator()(const TypedHandle<RT>& h1, 00429 const TypedHandle<RT>& h2) const 00430 { 00431 return get_pointer(h1) < get_pointer(h2); 00432 } 00433 }; 00434 00435 public: 00436 /** 00437 * Functor allowing handles to be used within STL sorted containers, 00438 * such as std::map and std::set, and to have their equivalence checks 00439 * delegated to the Objects they reference. 00440 */ 00441 typedef value_less_functor<T> value_compare; 00442 00443 /** 00444 * Functor allowing handles to be used within hash containers, such as 00445 * the SGI and MS style hash_map and hash_set, and to have their 00446 * equivalence checks delegated to the Objects they reference. 00447 */ 00448 typedef value_equal_functor<T> value_equal; 00449 00450 /** 00451 * Functor allowing handles to be used within hash containers, such as 00452 * the SGI as MS style hash_map and hash_set, and to have their hash 00453 * computation be based on the value of the referenced Object. 00454 */ 00455 typedef value_hash_functor<T> value_hasher; 00456 00457 /** 00458 * Functor allowing handles to be used within hash containers, such as 00459 * the SGI as MS style hash_map and hash_set, and to have their hash 00460 * computation be based on their identity, i.e. the reference they 00461 * contain. 00462 */ 00463 typedef identity_hash_functor<T> identity_hasher; 00464 00465 00466 // ----- data members --------------------------------------------------- 00467 00468 protected: 00469 /** 00470 * Pointer to the referenced object. 00471 */ 00472 T* m_o; 00473 00474 00475 // ---- friends --------------------------------------------------------- 00476 00477 /** 00478 * @internal 00479 */ 00480 template<class O> friend O* get_pointer(const TypedHandle<O>& h); 00481 00482 /** 00483 * @internal 00484 */ 00485 template<class D, class O> friend D cast(const TypedHandle<O>& th, 00486 bool fThrow); 00487 00488 /** 00489 * @internal 00490 */ 00491 template<class> friend class TypedHandle; 00492 }; 00493 00494 00495 // ----- non-member operators and functions --------------------------------- 00496 00497 /** 00498 * Output a human-readable description of the given TypedHandle<T> to the 00499 * specified stream. 00500 * 00501 * @param out the stream used to output the description 00502 * @param v the TypedHandle<T> to describe 00503 * 00504 * @return the supplied stream 00505 */ 00506 template <typename Char, typename Traits, class T> 00507 COH_INLINE std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, const TypedHandle<T>& v) 00508 { 00509 if (NULL == v) 00510 { 00511 out << "NULL"; 00512 } 00513 else 00514 { 00515 out << *v; 00516 } 00517 return out; 00518 } 00519 00520 /** 00521 * @internal 00522 * 00523 * Return the pointer associated with the TypedHandle. 00524 * 00525 * The lifetime of the Object referenced by the returned pointer 00526 * cannot be guaranteed beyond the lifetime of the Handle from 00527 * which it was obtained. Additionally if the associated handle is reassigned 00528 * the lifetime of the referenced Object is also undefined. 00529 * 00530 * @param h the Handle to used in retrieving the pointer. 00531 * 00532 * @return the pointer associated with the TypedHandle. 00533 */ 00534 template<class T> 00535 T* get_pointer(const TypedHandle<T>& h) 00536 { 00537 return h.get(); 00538 } 00539 00540 /** 00541 * Assign the specified handle to NULL. In most cases h = NULL is sufficient 00542 * but for some handle types there may be ambiguity which would require 00543 * knowledge of the Handle type, i.e. <code>hString = (String::Handle) NULL; 00544 * </code>. While the prior example will work just fine 00545 * <code>clear_handle(hString)</code> performs the same function without 00546 * requiring the explicit type cast in user code, and works the same for all 00547 * handle types. 00548 * 00549 * @param h the handle to clear 00550 */ 00551 template<class T> 00552 void clear_handle(TypedHandle<T>& h) 00553 { 00554 h = NULL; 00555 } 00556 00557 /** 00558 * Return true if the supplied handle equals NULL. 00559 * 00560 * @param h the handle to test 00561 * 00562 * @return true iff the supplied handle equals NULL 00563 */ 00564 template<class T> 00565 bool is_null(const TypedHandle<T>& h) 00566 { 00567 return h == NULL; 00568 } 00569 00570 /** 00571 * Perform a dynamic cast the pointer associated with the TypedHandle 00572 * to a the specified handle/view type. 00573 * 00574 * @param th the TypedHandle from which to perform the cast 00575 * @param fThrow true if an exception is to be thrown on a failed cast 00576 * 00577 * @return the casted pointer, or NULL if the cast fails and fThrow is false 00578 * 00579 * @throws ClassCastException if the cast fails and fThrow of is true 00580 */ 00581 template<class D, class T> 00582 D cast(const TypedHandle<T>& th, bool fThrow = true) 00583 { 00584 if (NULL == th) 00585 { 00586 return D(); // NULL 00587 } 00588 00589 typedef typename D::ValueType DT; 00590 typedef typename DT::this_spec DTS; 00591 DT* pD; 00592 if (assignment<DT, T>::allowed) 00593 { 00594 // free compile time cast 00595 pD = assignment<DT, T>::safe(get_pointer(th)); 00596 } 00597 else // runtime cast 00598 { 00599 pD = (DT*) th->_cast(COH_CLASS_ID(DTS)); 00600 } 00601 00602 if (NULL == pD) 00603 { 00604 if (fThrow) 00605 { 00606 coh_throw_class_cast(typeid(DT), typeid(*th)); 00607 } 00608 return D(); // NULL 00609 } 00610 00611 if (constness<T>::applied) 00612 { 00613 // from View to View or Holder(View) 00614 return TypedHandle<DT>(pD, th); 00615 } 00616 00617 // from Handle to Handle, View, or Holder(Handle) 00618 TypedHandle<typename DT::Handle::ValueType> hD( 00619 const_cast<typename DT::Handle::ValueType*>(pD), th); 00620 return hD; 00621 } 00622 00623 /** 00624 * Perform an instanceof check on a handle or view. 00625 * 00626 * @param th the TypedHandle from which to perform the test 00627 * 00628 * @return true if the supplied handle is an instance of the specified type 00629 */ 00630 template<class DT, class T> 00631 bool instanceof(const TypedHandle<T>& th) 00632 { 00633 typedef typename DT::ValueType::this_spec DTS; 00634 return NULL != th && 00635 (assignment<typename DT::ValueType, T>::allowed || 00636 th->_cast(COH_CLASS_ID(DTS))); 00637 } 00638 00639 COH_CLOSE_NAMESPACE2 00640 00641 #endif // COH_TYPED_HANDLE_HPP