00001 /* 00002 * TypedHolder.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_HOLDER_HPP 00017 #define COH_TYPED_HOLDER_HPP 00018 00019 #include "coherence/lang/compatibility.hpp" 00020 00021 #include "coherence/lang/ChainedHandleElement.hpp" 00022 #include "coherence/lang/TypedHandle.hpp" 00023 00024 COH_OPEN_NAMESPACE2(coherence,lang) 00025 00026 class Object; 00027 template<class T> class MemberHolder; 00028 00029 /** 00030 * A handle implementation which supports referencing Objects as either 00031 * Handles or Views. TypedHolder can safely be used in place of View 00032 * but adds the ability to attempt a safe down cast to a Handle. This differs 00033 * from a const_cast in that the down cast will only succeed if the 00034 * TypedHolder had been assigned from a Handle, an assignment from a View 00035 * results in a TypedHolder whose down cast operation will fail with a 00036 * ClassCastException. 00037 * 00038 * TypedHolder is not for general use, instead it is a convenience handle type 00039 * which can be used for container like classes, which need to be able to 00040 * contain both Handles and Views. 00041 * 00042 * As with TypedHandles, TypedHolders are not thread-safe, and should not be 00043 * used in a multi-threaded context even if protected by external 00044 * synchronization. They should only be used as local variables. The most 00045 * common place where thread-safe holders are needed is for object data 00046 * members. For these cases the Coherence API includes a thread-safe variant 00047 * MemberHolder. 00048 * 00049 * @author mf 2008.01.09 00050 * 00051 * @see MemberHolder 00052 * @see WeakHolder 00053 * @see FinalHolder 00054 */ 00055 template<class T> 00056 class TypedHolder 00057 : public ChainedHandleElement 00058 { 00059 // ----- typedefs ------------------------------------------------------- 00060 00061 public: 00062 /** 00063 * The type of the values the holder can reference. 00064 */ 00065 typedef const T ValueType; 00066 00067 /** 00068 * The Handle type for the referenced Object. 00069 */ 00070 typedef typename T::Handle ValueHandle; 00071 00072 /** 00073 * The View type for the referenced Object. 00074 */ 00075 typedef typename T::View ValueView; 00076 00077 00078 // -------- constructors ------------------------------------------------ 00079 00080 public: 00081 /** 00082 * Construct a new TypedHolder referencing NULL via a handle. 00083 */ 00084 TypedHolder() 00085 : ChainedHandleElement(/*fView*/ false), m_cpo(NULL) 00086 { 00087 } 00088 00089 /** 00090 * Construct a new TypedHolder referencing the same Object (and in 00091 * the same manner) as the specified TypedHolder. 00092 * 00093 * @param that the TypedHolder to initialize from 00094 */ 00095 TypedHolder(const TypedHolder& that) 00096 : ChainedHandleElement(that, that.m_fView), m_cpo(that.m_cpo) 00097 { 00098 } 00099 00100 /** 00101 * Construct a new TypedHolder referencing specified Object via a 00102 * Handle or View. 00103 * 00104 * As a Handle is used, the TypedHolder can be used with the 00105 * cast<...::Handle>() method to retrieve the Handle from the Holder. 00106 * 00107 * @param that a Handle or View to the Object to reference 00108 */ 00109 template<class DT> TypedHolder(const TypedHandle<DT>& that) 00110 : ChainedHandleElement(that, constness<DT>::applied), 00111 m_cpo(get_pointer(that)) 00112 { 00113 } 00114 00115 /** 00116 * Construct a new TypedHolder referencing the same Object (and in 00117 * the same manner) as the specified TypedHolder. 00118 * 00119 * @param that the TypedHolder to initialize from 00120 */ 00121 template<class DT> TypedHolder(const TypedHolder<DT>& that) 00122 : ChainedHandleElement(that, that.m_fView), m_cpo(that.m_cpo) 00123 { 00124 } 00125 00126 /** 00127 * Construct a new TypedHolder referencing the supplied object. 00128 * 00129 * This method is primarily intended to support assignment from NULL, 00130 * though it will work with other pointers. 00131 * 00132 * @param po pointer to the Object to reference 00133 */ 00134 TypedHolder(T* po) 00135 : ChainedHandleElement(/*fView*/ false), 00136 m_cpo(po == NULL || po->_attach(/*fEscaped*/ false) == NULL 00137 ? NULL : po) 00138 { 00139 } 00140 00141 /** 00142 * Construct a new TypedHolder referencing the supplied object. 00143 * 00144 * @param po pointer to the Object to reference 00145 */ 00146 template<class DT> TypedHolder(DT* po) 00147 : ChainedHandleElement(/*fView*/ constness<DT>::applied), 00148 m_cpo(po == NULL || po->_attach(/*fEscaped*/ false) == NULL 00149 ? NULL : po) 00150 { 00151 } 00152 00153 /** 00154 * Destroy the TypedHolder. 00155 */ 00156 ~TypedHolder() 00157 { 00158 Action nAction = unlink(); 00159 if (nAction != ACTION_NONE) 00160 { 00161 safeDestruct(nAction); 00162 } 00163 } 00164 00165 00166 // ----- operators ------------------------------------------------------ 00167 00168 public: 00169 /** 00170 * Assign this TypedHolder to reference the same Object (and in the 00171 * same manner) as the specified TypedHolder. 00172 * 00173 * @param that the TypedHolder to assign from 00174 * 00175 * @return a reference to this TypedHolder 00176 */ 00177 TypedHolder& operator=(const TypedHolder& that) 00178 { 00179 set(get_pointer(that), that.m_fView, that); 00180 return *this; 00181 } 00182 00183 /** 00184 * Assign this TypedHolder to reference the same Object (and in the 00185 * same manner) as the specified TypedHolder. 00186 * 00187 * @param that the TypedHolder to assign from 00188 * 00189 * @return a reference to this TypedHolder 00190 */ 00191 template<class DT> TypedHolder& operator=(const TypedHolder<DT>& that) 00192 { 00193 set(get_pointer(that), that.m_fView, that); 00194 return *this; 00195 } 00196 00197 /** 00198 * Return a View to the referenced Object. 00199 * 00200 * @return a View to the referenced Object 00201 */ 00202 template<class PT> 00203 operator TypedHandle<const PT>() const 00204 { 00205 return TypedHandle<const PT>(m_cpo, *this); 00206 } 00207 00208 /** 00209 * Dereference this holder, returning <tt>T&</tt>. 00210 * 00211 * @return a raw <tt>T&</tt> reference to the referenced Object 00212 * 00213 * @throws NullPointerException if the this holder is @c NULL 00214 */ 00215 const T& operator*() const 00216 { 00217 const T* po = m_cpo; 00218 if (NULL == po) 00219 { 00220 coh_throw_npe(typeid(T)); 00221 } 00222 return *po; 00223 } 00224 00225 /** 00226 * Dereference the TypedHolder. 00227 * 00228 * @return a const pointer to the referenced Object 00229 */ 00230 const T* operator->() const 00231 { 00232 const T* po = m_cpo; 00233 if (NULL == po) 00234 { 00235 coh_throw_npe(typeid(T)); 00236 } 00237 return po; 00238 } 00239 00240 00241 // ----- helper methods ------------------------------------------------- 00242 00243 protected: 00244 /** 00245 * Return true if the holder contains a handle 00246 * 00247 * @return true iff the holder contains a handle 00248 */ 00249 bool isHandle() const 00250 { 00251 return m_fView == false; 00252 } 00253 00254 /** 00255 * Return a Handle to the referenced Object. 00256 * 00257 * @return a Handle to the referenced Object, or NULL if the Object is 00258 * referenced via a View 00259 */ 00260 TypedHandle<T> getHandle() const 00261 { 00262 if (m_fView) 00263 { 00264 return NULL; 00265 } 00266 // chain new handle from this 00267 return TypedHandle<T>(const_cast<T*>(m_cpo), *this); 00268 } 00269 00270 /** 00271 * Set the Holder to reference an Object via a Handle. 00272 * 00273 * @param h the Handle to the Object to reference 00274 */ 00275 void set(const T* cp, bool fView, const ChainedHandleElement& that) 00276 { 00277 // record old 00278 const T* cpo = m_cpo; 00279 bool fViewOld = m_fView; 00280 00281 // link to the new 00282 Action nAction = link(that); 00283 m_cpo = cp; 00284 m_fView = fView; 00285 00286 if (nAction != ACTION_NONE) 00287 { 00288 performAction(nAction, cpo, fViewOld); 00289 } 00290 } 00291 00292 /** 00293 * Perform the specified action. 00294 * 00295 * @param nAction the action to perform 00296 * @param po pointer to object on which to act 00297 * @param fView if po references a view 00298 */ 00299 void performAction(Action nAction, const T* cpo, bool fView) 00300 { 00301 switch (nAction) 00302 { 00303 case ACTION_ERROR: 00304 coh_throw_illegal_state("corrupted ChainedHandleElement"); 00305 case ACTION_FLIP: 00306 if (NULL != cpo) cpo->_attach(/*fEscaped*/ false); 00307 // fall through 00308 case ACTION_DETACH: 00309 if (NULL != cpo) 00310 { 00311 if (fView) 00312 { 00313 cpo->_detach(/*fEscaped*/ false); 00314 } 00315 else 00316 { 00317 const_cast<T*>(cpo)->_detach(/*fEscaped*/ false); 00318 } 00319 } 00320 // fall through 00321 case ACTION_NONE: 00322 default: 00323 break; 00324 } 00325 } 00326 00327 /** 00328 * Destruct the handle. 00329 * 00330 * Any exception occurring during distribution will simply be printed, 00331 * the intent of this function is for use during TypedHandle 00332 * destruction. It is not the common path and is pulled out to 00333 * encourage inlining of the destructor. 00334 */ 00335 void safeDestruct(Action nAction) 00336 { 00337 try 00338 { 00339 performAction(nAction, m_cpo, m_fView); 00340 } 00341 catch (const std::exception& e) 00342 { 00343 // Exception::View is not a known type within this file 00344 std::cerr << "Error during ~TypedHolder: " << e.what() << std::endl; 00345 return; // can't re-throw from within destructor 00346 } 00347 } 00348 00349 // ----- data members --------------------------------------------------- 00350 00351 protected: 00352 /** 00353 * The referenced Object. 00354 */ 00355 const T* m_cpo; 00356 00357 00358 // ----- friends -------------------------------------------------------- 00359 00360 /** 00361 * @internal 00362 */ 00363 template<class O> friend const O* get_pointer(const TypedHolder<O>& th); 00364 00365 /** 00366 * @internal 00367 */ 00368 template<class O> friend bool is_handle(const TypedHolder<O>& th); 00369 00370 /** 00371 * @internal 00372 */ 00373 template<class D, class H> friend D cast(const TypedHolder<H>& th, 00374 bool fTest); 00375 00376 /** 00377 * @internal 00378 */ 00379 template<class> friend class TypedHolder; 00380 00381 /** 00382 * @internal 00383 */ 00384 template<class> friend class MemberHolder; 00385 }; 00386 00387 00388 // ----- non-member operators and functions --------------------------------- 00389 00390 /** 00391 * Output a human-readable description of the given TypedHolder to the 00392 * specified stream. 00393 * 00394 * @param out the stream used to output the description 00395 * @param th the TypedHolder to describe 00396 * 00397 * @return the supplied stream 00398 */ 00399 template<class T> std::ostream& operator<<(std::ostream& out, 00400 const TypedHolder<T>& th) 00401 { 00402 out << (typename T::View) th; 00403 return out; 00404 } 00405 00406 /** 00407 * @internal 00408 * 00409 * Return the pointer associated with the TypedHolder. 00410 * 00411 * The lifetime of the Object referenced by the returned pointer 00412 * cannot be guaranteed beyond the lifetime of the Holder from 00413 * which it was obtained. Additionally if the associated handle is reassigned 00414 * the lifetime of the referenced Object is also undefined. 00415 * 00416 * @param th the Holder to used in retrieving the pointer. 00417 * 00418 * @return the pointer associated with the TypedHolder. 00419 */ 00420 template<class T> 00421 const T* get_pointer(const TypedHolder<T>& th) 00422 { 00423 return th.m_cpo; 00424 } 00425 00426 /** 00427 * Assign the specified holder to NULL. 00428 * 00429 * @param th the holder to clear 00430 */ 00431 template<class T> void clear_handle(TypedHolder<T>& th) 00432 { 00433 th = NULL; 00434 } 00435 00436 /** 00437 * Return true if the supplied holder equals NULL. 00438 * 00439 * @param th the holder to test 00440 * 00441 * @return true iff the supplied holder equals NULL 00442 */ 00443 template<class T> 00444 bool is_null(const TypedHolder<T>& th) 00445 { 00446 return th == NULL; 00447 } 00448 00449 /** 00450 * Return true if the supplied holder contains a handle 00451 * 00452 * @param th the holder to test 00453 * 00454 * @return true iff the supplied holder contains a handle 00455 */ 00456 template<class T> 00457 bool is_handle(const TypedHolder<T>& th) 00458 { 00459 return th.isHandle(); 00460 } 00461 00462 /** 00463 * Perform a dynamic cast the pointer associated with the TypedHolder 00464 * to a the specified handle/view type. 00465 * 00466 * @param th the TypedHolder from which to perform the cast 00467 * @param fThrow true if an exception is to be thrown on a failed cast 00468 * 00469 * @return the casted pointer, or NULL if the cast fails and fThrow is false 00470 * 00471 * @throws ClassCastException if the cast fails and fThrow is true 00472 */ 00473 template<class D, class T> 00474 D cast(const TypedHolder<T>& th, bool fThrow = true) 00475 { 00476 TypedHandle<T> h = th.getHandle(); 00477 if (NULL == h) 00478 { 00479 TypedHandle<const T> v = th; 00480 00481 if (NULL == v) 00482 { 00483 // from NULL to any type is allowed 00484 return D(); // NULL 00485 } 00486 00487 // input is a non-NULL view 00488 if (constness<typename D::ValueType>::applied) 00489 { 00490 // input type is a holder(view), output type is a view or holder 00491 // return a view and let it be converted if necessary to a holder 00492 // producing a holder(handle) can't happen from here, but we've 00493 // already proved that the input type is a view (NULL == h) 00494 TypedHandle<typename D::ValueType> vD( 00495 (typename D::ValueType*) get_pointer( 00496 cast<typename D::ValueType::View>(v, fThrow)), v); 00497 return vD; 00498 } 00499 else 00500 { 00501 // output type is a handle; input type is a view (error) 00502 if (fThrow) 00503 { 00504 coh_throw_const_cast(typeid(typename D::ValueType), typeid(*th)); 00505 } 00506 return D(); // NULL 00507 } 00508 } 00509 00510 // input type is a holder(handle), output type can be handle/view/holder; 00511 // cast from on the handle, and allow conversion to produce expected 00512 // result type 00513 return cast<typename D::ValueType::Handle>(h, fThrow); 00514 } 00515 00516 /** 00517 * Perform an instanceof check on a handle or view. 00518 * 00519 * @param th the TypedHolder from which to perform the test 00520 * 00521 * @return true if the supplied handle is an instance of the specified type 00522 */ 00523 template<class D, class T> 00524 bool instanceof(const TypedHolder<T>& th) 00525 { 00526 return NULL !=th && NULL != cast<D>(th, false); 00527 } 00528 00529 COH_CLOSE_NAMESPACE2 00530 00531 #endif // COH_TYPED_HOLDER_HPP