00001 /* 00002 * TypedHandle.hpp 00003 * 00004 * Copyright (c) 2000, 2010, 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 <iostream> 00024 #include <functional> 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 Action nAction = unlink(); 00146 if (nAction != ACTION_NONE) 00147 { 00148 safeDestruct(nAction); 00149 } 00150 } 00151 00152 00153 // ----- operators ------------------------------------------------------ 00154 00155 public: 00156 /** 00157 * Dereference this handle, returning <tt>T&</tt>. 00158 * 00159 * @return a raw <tt>T&</tt> reference to the referenced Object 00160 * 00161 * @throws NullPointerException if the this handle is @c NULL 00162 */ 00163 T& operator*() const 00164 { 00165 T* po = m_o; 00166 if (NULL == po) 00167 { 00168 coh_throw_npe(typeid(T)); 00169 } 00170 return *po; 00171 } 00172 00173 /** 00174 * Dereference this handle, returning <tt>T*</tt>. 00175 * 00176 * @return a raw <tt>T*</tt> pointer to the referenced Object 00177 * 00178 * @throws NullPointerException if the this handle is @c NULL 00179 */ 00180 T* operator->() const 00181 { 00182 T* po = m_o; 00183 if (NULL == po) 00184 { 00185 coh_throw_npe(typeid(T)); 00186 } 00187 return po; 00188 } 00189 00190 /** 00191 * Assign this TypedHandle another Object to reference. 00192 */ 00193 TypedHandle<T>& operator=(const TypedHandle<T>& h) 00194 { 00195 set(h.get(), h); 00196 return *this; 00197 } 00198 00199 /** 00200 * Assign this TypedHandle from a handle to a derived type. 00201 */ 00202 template<class DT> 00203 TypedHandle<T>& operator=(const TypedHandle<DT>& h) 00204 { 00205 // *** PLEASE READ IF YOU GET BUILD ERRORS HERE **** 00206 // A build error in this call indicates that you've attempted to 00207 // assign two non-compatible handle types, or simply trying to 00208 // assign a View to a Handle. Check your compiler output which 00209 // should state what line in your triggered this template 00210 // instantiation, that is the code which has the error. 00211 00212 set(get_pointer(h), h); 00213 return *this; 00214 } 00215 00216 /** 00217 * Compare two handles with "less-than" predicate. This is only an 00218 * identity based comparison, and does not take the value into account. 00219 */ 00220 template<class AT> 00221 bool operator<(const TypedHandle<AT>& h) const 00222 { 00223 return ((const Object*) m_o) < ((const Object*) get_pointer(h)); 00224 } 00225 00226 00227 // ----- helper methods ------------------------------------------------- 00228 00229 protected: // protected to prevent easily misunderstandings such as 00230 // hMap.get() which might be interpreted as a call on a map 00231 00232 /** 00233 * Return pointer without null checking. 00234 * Does NOT throw NullPointerException. 00235 * 00236 * One should use <code>h.get()</code> to get raw T* pointer. 00237 * Please do not use neither <code>&*h</code> (as it may throw 00238 * NullPointerException) nor <code>(T*)h</code> (as it may perform 00239 * unsafe unchecked type cast). 00240 */ 00241 T* get() const 00242 { 00243 return m_o; 00244 } 00245 00246 /** 00247 * Set the TypedHandle to attach to the supplied pointer. 00248 * Any existing attachment will be detached. 00249 * 00250 * @param o the address of the object to point to or NULL 00251 */ 00252 TypedHandle<T>& set(T* o, const ChainedHandleElement& that) 00253 { 00254 T* pOld = m_o; 00255 00256 Action nAction = link(that); 00257 m_o = o; 00258 00259 if (nAction != ACTION_NONE) 00260 { 00261 performAction(nAction, pOld); 00262 } 00263 00264 return *this; 00265 } 00266 00267 /** 00268 * Perform the specified action. 00269 * 00270 * @param nAction the action to perform 00271 * @param po pointer to object on which to act 00272 */ 00273 void performAction(Action nAction, T* po) 00274 { 00275 switch (nAction) 00276 { 00277 case ACTION_ERROR: 00278 coh_throw_illegal_state("corrupted ChainedHandleElement"); 00279 case ACTION_FLIP: 00280 if (po) ((const T*) po)->_attach(/*fEscaped*/ false); 00281 // fall through 00282 case ACTION_DETACH: 00283 if (po) po->_detach(/*fEscaped*/ false); 00284 // fall through 00285 case ACTION_NONE: 00286 default: 00287 break; 00288 } 00289 } 00290 00291 /** 00292 * Destruct the handle. 00293 * 00294 * Any exception occurring during destruction will simply be printed, 00295 * the intent of this function is for use during TypedHandle 00296 * destruction. It is not the common path and is pulled out to 00297 * encourage inlining of the destructor. 00298 */ 00299 void safeDestruct(Action nAction) 00300 { 00301 try 00302 { 00303 performAction(nAction, m_o); 00304 } 00305 catch (const std::exception& e) 00306 { 00307 // Exception::View is not a known type within this file 00308 std::cerr << "Error during ~TypedHandle: " << e.what() << std::endl; 00309 return; // can't re-throw from within destructor 00310 } 00311 } 00312 00313 // ----- functors ------------------------------------------------------- 00314 00315 protected: 00316 /** 00317 * The binary functor that compares objects pointed by the handles 00318 * with the "less-than" operator. 00319 */ 00320 template<class RT> 00321 class value_less_functor 00322 : public std::binary_function<RT, RT, bool> 00323 { 00324 public: 00325 /** 00326 * Compare values pointed by the specified handles with 00327 * "less-than" operator. 00328 */ 00329 bool operator()(const TypedHandle<RT>& h1, 00330 const TypedHandle<RT>& h2) const 00331 { 00332 return h1 && h1->operator<(h2); 00333 } 00334 }; 00335 00336 /** 00337 * The binary functor that compares values pointed by the handles for 00338 * equality. 00339 */ 00340 template<class RT> 00341 class value_equal_functor 00342 : public std::binary_function<RT, RT, bool> 00343 { 00344 public: 00345 /** 00346 * Compare values pointed by the specified handles for 00347 * equality. 00348 */ 00349 bool operator()(const TypedHandle<RT>& h1, 00350 const TypedHandle<RT>& h2) const 00351 { 00352 return h1 == h2 || (h1 && h1->equals(h2)); 00353 } 00354 }; 00355 00356 /** 00357 * Value based hash functor which is compatible with both the SGI and 00358 * MS style hash containers. 00359 */ 00360 template<class RT> 00361 class value_hash_functor 00362 : public std::unary_function<RT, size32_t> 00363 { 00364 public: 00365 // parameters for MS style hash table 00366 enum {bucket_size = 4, min_buckets = 8}; 00367 00368 /** 00369 * Hash computation function for MS and SGI style hash containers. 00370 * 00371 * @param h the handle to hash 00372 * 00373 * @return the hash of the handle 00374 */ 00375 size32_t operator()(const TypedHandle<RT>& h) const 00376 { 00377 return h ? h->hashCode() : 0; 00378 } 00379 00380 /** 00381 * Ordering function for MS style hash containers. 00382 * 00383 * @param h1 the first handle to compare 00384 * @param h2 the second handle to compare 00385 * 00386 * @return true iff *h1 < *h2 00387 */ 00388 bool operator()(const TypedHandle<RT>& h1, 00389 const TypedHandle<RT>& h2) const 00390 { 00391 return h1 && h1->operator<(h2); 00392 } 00393 }; 00394 00395 00396 /** 00397 * Identity based hash functor which is compatible with both the SGI 00398 * and MS style hash containers. 00399 */ 00400 template<class RT> class identity_hash_functor 00401 : public std::unary_function<RT, size32_t> 00402 { 00403 public: 00404 // parameters for MS style hash table 00405 enum {bucket_size = 4, min_buckets = 8}; 00406 00407 /** 00408 * Hash computation function for MS and SGI style hash containers. 00409 * 00410 * @param h the handle to hash 00411 * 00412 * @return the hash of the handle 00413 */ 00414 size32_t operator()(const TypedHandle<RT>& h) const 00415 { 00416 return (size32_t) get_pointer(h); 00417 } 00418 00419 /** 00420 * Ordering function for MS style hash containers. 00421 * 00422 * @param h1 the first handle to compare 00423 * @param h2 the second handle to compare 00424 * 00425 * @return true iff h1 < h2 00426 */ 00427 bool operator()(const TypedHandle<RT>& h1, 00428 const TypedHandle<RT>& h2) const 00429 { 00430 return get_pointer(h1) < get_pointer(h2); 00431 } 00432 }; 00433 00434 public: 00435 /** 00436 * Functor allowing handles to be used within STL sorted containers, 00437 * such as std::map and std::set, and to have their equivalence checks 00438 * delegated to the Objects they reference. 00439 */ 00440 typedef value_less_functor<T> value_compare; 00441 00442 /** 00443 * Functor allowing handles to be used within hash containers, such as 00444 * the SGI and MS style hash_map and hash_set, and to have their 00445 * equivalence checks delegated to the Objects they reference. 00446 */ 00447 typedef value_equal_functor<T> value_equal; 00448 00449 /** 00450 * Functor allowing handles to be used within hash containers, such as 00451 * the SGI as MS style hash_map and hash_set, and to have their hash 00452 * computation be based on the value of the referenced Object. 00453 */ 00454 typedef value_hash_functor<T> value_hasher; 00455 00456 /** 00457 * Functor allowing handles to be used within hash containers, such as 00458 * the SGI as MS style hash_map and hash_set, and to have their hash 00459 * computation be based on their identity, i.e. the reference they 00460 * contain. 00461 */ 00462 typedef identity_hash_functor<T> identity_hasher; 00463 00464 00465 // ----- data members --------------------------------------------------- 00466 00467 protected: 00468 /** 00469 * Pointer to the referenced object. 00470 */ 00471 T* m_o; 00472 00473 00474 // ---- friends --------------------------------------------------------- 00475 00476 /** 00477 * @internal 00478 */ 00479 template<class O> friend O* get_pointer(const TypedHandle<O>& h); 00480 00481 /** 00482 * @internal 00483 */ 00484 template<class D, class O> friend D cast(const TypedHandle<O>& th, 00485 bool fThrow); 00486 00487 /** 00488 * @internal 00489 */ 00490 template<class> friend class TypedHandle; 00491 }; 00492 00493 00494 // ----- non-member operators and functions --------------------------------- 00495 00496 /** 00497 * Output a human-readable description of the given TypedHandle<T> to the 00498 * specified stream. 00499 * 00500 * @param out the stream used to output the description 00501 * @param v the TypedHandle<T> to describe 00502 * 00503 * @return the supplied stream 00504 */ 00505 template<class T> 00506 std::ostream& operator<<(std::ostream& out, const TypedHandle<T>& v) 00507 { 00508 if (NULL == v) 00509 { 00510 out << "NULL"; 00511 } 00512 else 00513 { 00514 v->toStream(out); 00515 } 00516 return out; 00517 } 00518 00519 /** 00520 * @internal 00521 * 00522 * Return the pointer associated with the TypedHandle. 00523 * 00524 * The lifetime of the Object referenced by the returned pointer 00525 * cannot be guaranteed beyond the lifetime of the Handle from 00526 * which it was obtained. Additionally if the associated handle is reassigned 00527 * the lifetime of the referenced Object is also undefined. 00528 * 00529 * @param h the Handle to used in retrieving the pointer. 00530 * 00531 * @return the pointer associated with the TypedHandle. 00532 */ 00533 template<class T> 00534 T* get_pointer(const TypedHandle<T>& h) 00535 { 00536 return h.get(); 00537 } 00538 00539 /** 00540 * Assign the specified handle to NULL. In most cases h = NULL is sufficient 00541 * but for some handle types there may be ambiguity which would require 00542 * knowledge of the Handle type, i.e. <code>hString = (String::Handle) NULL; 00543 * </code>. While the prior example will work just fine 00544 * <code>clear_handle(hString)</code> performs the same function without 00545 * requiring the explicit type cast in user code, and works the same for all 00546 * handle types. 00547 * 00548 * @param h the handle to clear 00549 */ 00550 template<class T> 00551 void clear_handle(TypedHandle<T>& h) 00552 { 00553 h = NULL; 00554 } 00555 00556 /** 00557 * Return true if the supplied handle equals NULL. 00558 * 00559 * @param h the handle to test 00560 * 00561 * @return true iff the supplied handle equals NULL 00562 */ 00563 template<class T> 00564 bool is_null(const TypedHandle<T>& h) 00565 { 00566 return h == NULL; 00567 } 00568 00569 /** 00570 * Perform a dynamic cast the pointer associated with the TypedHandle 00571 * to a the specified handle/view type. 00572 * 00573 * @param th the TypedHandle from which to perform the cast 00574 * @param fThrow true if an exception is to be thrown on a failed cast 00575 * 00576 * @return the casted pointer, or NULL if the cast fails and fThrow is false 00577 * 00578 * @throws ClassCastException if the cast fails and fThrow of is true 00579 */ 00580 template<class D, class T> 00581 D cast(const TypedHandle<T>& th, bool fThrow = true) 00582 { 00583 if (NULL == th) 00584 { 00585 return D(); // NULL 00586 } 00587 00588 typedef typename D::ValueType DT; 00589 DT* pD; 00590 if (assignment<DT, T>::allowed) 00591 { 00592 // free compile time cast 00593 pD = assignment<DT, T>::safe(get_pointer(th)); 00594 } 00595 else // runtime cast 00596 { 00597 pD = (DT*) th->_cast(&typeid(DT)); // quick optimistic cast attempt 00598 if (NULL == pD) 00599 { 00600 // fall back on slower dynamic cast 00601 pD = dynamic_cast<DT*>(get_pointer(th)); 00602 } 00603 } 00604 00605 if (NULL == pD) 00606 { 00607 if (fThrow) 00608 { 00609 coh_throw_class_cast(typeid(DT), typeid(*th)); 00610 } 00611 return D(); // NULL 00612 } 00613 00614 if (constness<T>::applied) 00615 { 00616 // from View to View or Holder(View) 00617 return TypedHandle<DT>(pD, th); 00618 } 00619 00620 // from Handle to Handle, View, or Holder(Handle) 00621 TypedHandle<typename DT::Handle::ValueType> hD( 00622 const_cast<typename DT::Handle::ValueType*>(pD), th); 00623 return hD; 00624 } 00625 00626 /** 00627 * Perform an instanceof check on a handle or view. 00628 * 00629 * @param th the TypedHandle from which to perform the test 00630 * 00631 * @return true if the supplied handle is an instance of the specified type 00632 */ 00633 template<class DT, class T> 00634 bool instanceof(const TypedHandle<T>& th) 00635 { 00636 return NULL != th && 00637 (assignment<typename DT::ValueType, T>::allowed || 00638 th->_cast(&typeid(DT)) || 00639 dynamic_cast<typename DT::ValueType*>(get_pointer(th))); 00640 } 00641 00642 COH_CLOSE_NAMESPACE2 00643 00644 #endif // COH_TYPED_HANDLE_HPP