00001 /* 00002 * TypedHandle.hpp 00003 * 00004 * Copyright (c) 2000, 2013, 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 Action nAction = link(that); 00255 if (nAction != action_none) 00256 { 00257 performAction(nAction); 00258 } 00259 m_o = o; 00260 return *this; 00261 } 00262 00263 /** 00264 * Perform the specified action. 00265 * 00266 * @param nAction the action to perform 00267 */ 00268 void performAction(Action nAction) 00269 { 00270 T* po = m_o; 00271 switch (nAction) 00272 { 00273 case action_error: 00274 coh_throw_illegal_state("corrupted ChainedHandleElement"); 00275 case action_flip: 00276 if (po) ((const T*) po)->_attach(/*fEscaped*/ false); 00277 // fall through 00278 case action_detach: 00279 if (po) po->_detach(/*fEscaped*/ false); 00280 // fall through 00281 case action_none: 00282 default: 00283 break; 00284 } 00285 } 00286 00287 /** 00288 * Destruct the handle. 00289 * 00290 * Any exception occurring during destruction will simply be printed, 00291 * the intent of this function is for use during TypedHandle 00292 * destruction. It is not the common path and is pulled out to 00293 * encourage inlining of the destructor. 00294 */ 00295 void safeDestruct(Action nAction) 00296 { 00297 try 00298 { 00299 performAction(nAction); 00300 } 00301 catch (const std::exception& e) 00302 { 00303 // Exception::View is not a known type within this file 00304 std::cerr << "Error during ~TypedHandle: " << e.what() << std::endl; 00305 return; // can't re-throw from within destructor 00306 } 00307 } 00308 00309 // ----- functors ------------------------------------------------------- 00310 00311 protected: 00312 /** 00313 * The binary functor that compares objects pointed by the handles 00314 * with the "less-than" operator. 00315 */ 00316 template<class RT> 00317 class value_less_functor 00318 : public std::binary_function<RT, RT, bool> 00319 { 00320 public: 00321 /** 00322 * Compare values pointed by the specified handles with 00323 * "less-than" operator. 00324 */ 00325 bool operator()(const TypedHandle<RT>& h1, 00326 const TypedHandle<RT>& h2) const 00327 { 00328 return h1 && h1->operator<(h2); 00329 } 00330 }; 00331 00332 /** 00333 * The binary functor that compares values pointed by the handles for 00334 * equality. 00335 */ 00336 template<class RT> 00337 class value_equal_functor 00338 : public std::binary_function<RT, RT, bool> 00339 { 00340 public: 00341 /** 00342 * Compare values pointed by the specified handles for 00343 * equality. 00344 */ 00345 bool operator()(const TypedHandle<RT>& h1, 00346 const TypedHandle<RT>& h2) const 00347 { 00348 return h1 == h2 || (h1 && h1->equals(h2)); 00349 } 00350 }; 00351 00352 /** 00353 * Value based hash functor which is compatible with both the SGI and 00354 * MS style hash containers. 00355 */ 00356 template<class RT> 00357 class value_hash_functor 00358 : public std::unary_function<RT, size32_t> 00359 { 00360 public: 00361 // parameters for MS style hash table 00362 enum {bucket_size = 4, min_buckets = 8}; 00363 00364 /** 00365 * Hash computation function for MS and SGI style hash containers. 00366 * 00367 * @param h the handle to hash 00368 * 00369 * @return the hash of the handle 00370 */ 00371 size32_t operator()(const TypedHandle<RT>& h) const 00372 { 00373 return h ? h->hashCode() : 0; 00374 } 00375 00376 /** 00377 * Ordering function for MS style hash containers. 00378 * 00379 * @param h1 the first handle to compare 00380 * @param h2 the second handle to compare 00381 * 00382 * @return true iff *h1 < *h2 00383 */ 00384 bool operator()(const TypedHandle<RT>& h1, 00385 const TypedHandle<RT>& h2) const 00386 { 00387 return h1 && h1->operator<(h2); 00388 } 00389 }; 00390 00391 00392 /** 00393 * Identity based hash functor which is compatible with both the SGI 00394 * and MS style hash containers. 00395 */ 00396 template<class RT> class identity_hash_functor 00397 : public std::unary_function<RT, size32_t> 00398 { 00399 public: 00400 // parameters for MS style hash table 00401 enum {bucket_size = 4, min_buckets = 8}; 00402 00403 /** 00404 * Hash computation function for MS and SGI style hash containers. 00405 * 00406 * @param h the handle to hash 00407 * 00408 * @return the hash of the handle 00409 */ 00410 size32_t operator()(const TypedHandle<RT>& h) const 00411 { 00412 return (size32_t) get_pointer(h); 00413 } 00414 00415 /** 00416 * Ordering function for MS style hash containers. 00417 * 00418 * @param h1 the first handle to compare 00419 * @param h2 the second handle to compare 00420 * 00421 * @return true iff h1 < h2 00422 */ 00423 bool operator()(const TypedHandle<RT>& h1, 00424 const TypedHandle<RT>& h2) const 00425 { 00426 return get_pointer(h1) < get_pointer(h2); 00427 } 00428 }; 00429 00430 public: 00431 /** 00432 * Functor allowing handles to be used within STL sorted containers, 00433 * such as std::map and std::set, and to have their equivalence checks 00434 * delegated to the Objects they reference. 00435 */ 00436 typedef value_less_functor<T> value_compare; 00437 00438 /** 00439 * Functor allowing handles to be used within hash containers, such as 00440 * the SGI and MS style hash_map and hash_set, and to have their 00441 * equivalence checks delegated to the Objects they reference. 00442 */ 00443 typedef value_equal_functor<T> value_equal; 00444 00445 /** 00446 * Functor allowing handles to be used within hash containers, such as 00447 * the SGI as MS style hash_map and hash_set, and to have their hash 00448 * computation be based on the value of the referenced Object. 00449 */ 00450 typedef value_hash_functor<T> value_hasher; 00451 00452 /** 00453 * Functor allowing handles to be used within hash containers, such as 00454 * the SGI as MS style hash_map and hash_set, and to have their hash 00455 * computation be based on their identity, i.e. the reference they 00456 * contain. 00457 */ 00458 typedef identity_hash_functor<T> identity_hasher; 00459 00460 00461 // ----- data members --------------------------------------------------- 00462 00463 protected: 00464 /** 00465 * Pointer to the referenced object. 00466 */ 00467 T* m_o; 00468 00469 00470 // ---- friends --------------------------------------------------------- 00471 00472 /** 00473 * @internal 00474 */ 00475 template<class O> friend O* get_pointer(const TypedHandle<O>& h); 00476 00477 /** 00478 * @internal 00479 */ 00480 template<class D, class O> friend D cast(const TypedHandle<O>& th, 00481 bool fThrow); 00482 00483 /** 00484 * @internal 00485 */ 00486 template<class> friend class TypedHandle; 00487 }; 00488 00489 00490 // ----- non-member operators and functions --------------------------------- 00491 00492 /** 00493 * Output a human-readable description of the given TypedHandle<T> to the 00494 * specified stream. 00495 * 00496 * @param out the stream used to output the description 00497 * @param v the TypedHandle<T> to describe 00498 * 00499 * @return the supplied stream 00500 */ 00501 template<class T> 00502 std::ostream& operator<<(std::ostream& out, const TypedHandle<T>& v) 00503 { 00504 if (NULL == v) 00505 { 00506 out << "NULL"; 00507 } 00508 else 00509 { 00510 v->toStream(out); 00511 } 00512 return out; 00513 } 00514 00515 /** 00516 * @internal 00517 * 00518 * Return the pointer associated with the TypedHandle. 00519 * 00520 * The lifetime of the Object referenced by the returned pointer 00521 * cannot be guaranteed beyond the lifetime of the Handle from 00522 * which it was obtained. Additionally if the associated handle is reassigned 00523 * the lifetime of the referenced Object is also undefined. 00524 * 00525 * @param h the Handle to used in retrieving the pointer. 00526 * 00527 * @return the pointer associated with the TypedHandle. 00528 */ 00529 template<class T> 00530 T* get_pointer(const TypedHandle<T>& h) 00531 { 00532 return h.get(); 00533 } 00534 00535 /** 00536 * Assign the specified handle to NULL. In most cases h = NULL is sufficient 00537 * but for some handle types there may be ambiguity which would require 00538 * knowledge of the Handle type, i.e. <code>hString = (String::Handle) NULL; 00539 * </code>. While the prior example will work just fine 00540 * <code>clear_handle(hString)</code> performs the same function without 00541 * requiring the explicit type cast in user code, and works the same for all 00542 * handle types. 00543 * 00544 * @param h the handle to clear 00545 */ 00546 template<class T> 00547 void clear_handle(TypedHandle<T>& h) 00548 { 00549 h = NULL; 00550 } 00551 00552 /** 00553 * Return true if the supplied handle equals NULL. 00554 * 00555 * @param h the handle to test 00556 * 00557 * @return true iff the supplied handle equals NULL 00558 */ 00559 template<class T> 00560 bool is_null(const TypedHandle<T>& h) 00561 { 00562 return h == NULL; 00563 } 00564 00565 /** 00566 * Perform a dynamic cast the pointer associated with the TypedHandle 00567 * to a the specified handle/view type. 00568 * 00569 * @param th the TypedHandle from which to perform the cast 00570 * @param fThrow true if an exception is to be thrown on a failed cast 00571 * 00572 * @return the casted pointer, or NULL if the cast fails and fThrow is false 00573 * 00574 * @throws ClassCastException if the cast fails and fThrow of is true 00575 */ 00576 template<class D, class T> 00577 D cast(const TypedHandle<T>& th, bool fThrow = true) 00578 { 00579 if (NULL == th) 00580 { 00581 return D(); // NULL 00582 } 00583 00584 typedef typename D::ValueType DT; 00585 DT* pD; 00586 if (assignment<DT, T>::allowed) 00587 { 00588 // free compile time cast 00589 pD = assignment<DT, T>::safe(get_pointer(th)); 00590 } 00591 else // runtime cast 00592 { 00593 pD = (DT*) th->_cast(&typeid(DT)); // quick optimistic cast attempt 00594 if (NULL == pD) 00595 { 00596 // fall back on slower dynamic cast 00597 pD = dynamic_cast<DT*>(get_pointer(th)); 00598 } 00599 } 00600 00601 if (NULL == pD) 00602 { 00603 if (fThrow) 00604 { 00605 coh_throw_class_cast(typeid(DT), typeid(*th)); 00606 } 00607 return D(); // NULL 00608 } 00609 00610 if (constness<T>::applied) 00611 { 00612 // from View to View or Holder(View) 00613 return TypedHandle<DT>(pD, th); 00614 } 00615 00616 // from Handle to Handle, View, or Holder(Handle) 00617 TypedHandle<typename DT::Handle::ValueType> hD( 00618 const_cast<typename DT::Handle::ValueType*>(pD), th); 00619 return hD; 00620 } 00621 00622 /** 00623 * Perform an instanceof check on a handle or view. 00624 * 00625 * @param th the TypedHandle from which to perform the test 00626 * 00627 * @return true if the supplied handle is an instance of the specified type 00628 */ 00629 template<class DT, class T> 00630 bool instanceof(const TypedHandle<T>& th) 00631 { 00632 return NULL != th && 00633 (assignment<typename DT::ValueType, T>::allowed || 00634 th->_cast(&typeid(DT)) || 00635 dynamic_cast<typename DT::ValueType*>(get_pointer(th))); 00636 } 00637 00638 COH_CLOSE_NAMESPACE2 00639 00640 #endif // COH_TYPED_HANDLE_HPP