00001 /* 00002 * TypedHolder.hpp 00003 * 00004 * Copyright (c) 2000, 2014, 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 (m_cpo && nAction != action_none) 00160 { 00161 performAction(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 // link to the new 00278 Action nAction = link(that); 00279 if (m_cpo && nAction != action_none) 00280 { 00281 performAction(nAction); 00282 } 00283 m_cpo = cp; 00284 m_fView = fView; 00285 } 00286 00287 /** 00288 * Perform the specified action. 00289 * 00290 * @param nAction the action to perform 00291 */ 00292 void performAction(Action nAction) 00293 { 00294 switch (nAction) 00295 { 00296 case action_flip: 00297 m_cpo->_attach(/*fEscaped*/ false); 00298 // fall through 00299 case action_detach: 00300 if (m_fView) 00301 { 00302 m_cpo->_detach(/*fEscaped*/ false); 00303 } 00304 else 00305 { 00306 const_cast<T*>(m_cpo)->_detach(/*fEscaped*/ false); 00307 } 00308 // fall through 00309 case action_none: 00310 default: 00311 break; 00312 } 00313 } 00314 00315 00316 // ----- data members --------------------------------------------------- 00317 00318 protected: 00319 /** 00320 * The referenced Object. 00321 */ 00322 const T* m_cpo; 00323 00324 00325 // ----- friends -------------------------------------------------------- 00326 00327 /** 00328 * @internal 00329 */ 00330 template<class O> friend const O* get_pointer(const TypedHolder<O>& th); 00331 00332 /** 00333 * @internal 00334 */ 00335 template<class O> friend bool is_handle(const TypedHolder<O>& th); 00336 00337 /** 00338 * @internal 00339 */ 00340 template<class D, class H> friend D cast(const TypedHolder<H>& th, 00341 bool fTest); 00342 00343 /** 00344 * @internal 00345 */ 00346 template<class> friend class TypedHolder; 00347 00348 /** 00349 * @internal 00350 */ 00351 template<class> friend class MemberHolder; 00352 }; 00353 00354 00355 // ----- non-member operators and functions --------------------------------- 00356 00357 /** 00358 * Output a human-readable description of the given TypedHolder to the 00359 * specified stream. 00360 * 00361 * @param out the stream used to output the description 00362 * @param th the TypedHolder to describe 00363 * 00364 * @return the supplied stream 00365 */ 00366 template<class T> std::ostream& operator<<(std::ostream& out, 00367 const TypedHolder<T>& th) 00368 { 00369 out << (typename T::View) th; 00370 return out; 00371 } 00372 00373 /** 00374 * @internal 00375 * 00376 * Return the pointer associated with the TypedHolder. 00377 * 00378 * The lifetime of the Object referenced by the returned pointer 00379 * cannot be guaranteed beyond the lifetime of the Holder from 00380 * which it was obtained. Additionally if the associated handle is reassigned 00381 * the lifetime of the referenced Object is also undefined. 00382 * 00383 * @param th the Holder to used in retrieving the pointer. 00384 * 00385 * @return the pointer associated with the TypedHolder. 00386 */ 00387 template<class T> 00388 const T* get_pointer(const TypedHolder<T>& th) 00389 { 00390 return th.m_cpo; 00391 } 00392 00393 /** 00394 * Assign the specified holder to NULL. 00395 * 00396 * @param th the holder to clear 00397 */ 00398 template<class T> void clear_handle(TypedHolder<T>& th) 00399 { 00400 th = NULL; 00401 } 00402 00403 /** 00404 * Return true if the supplied holder equals NULL. 00405 * 00406 * @param th the holder to test 00407 * 00408 * @return true iff the supplied holder equals NULL 00409 */ 00410 template<class T> 00411 bool is_null(const TypedHolder<T>& th) 00412 { 00413 return th == NULL; 00414 } 00415 00416 /** 00417 * Return true if the supplied holder contains a handle 00418 * 00419 * @param th the holder to test 00420 * 00421 * @return true iff the supplied holder contains a handle 00422 */ 00423 template<class T> 00424 bool is_handle(const TypedHolder<T>& th) 00425 { 00426 return th.isHandle(); 00427 } 00428 00429 /** 00430 * Perform a dynamic cast the pointer associated with the TypedHolder 00431 * to a the specified handle/view type. 00432 * 00433 * @param th the TypedHolder from which to perform the cast 00434 * @param fThrow true if an exception is to be thrown on a failed cast 00435 * 00436 * @return the casted pointer, or NULL if the cast fails and fThrow is false 00437 * 00438 * @throws ClassCastException if the cast fails and fThrow is true 00439 */ 00440 template<class D, class T> 00441 D cast(const TypedHolder<T>& th, bool fThrow = true) 00442 { 00443 TypedHandle<T> h = th.getHandle(); 00444 if (NULL == h) 00445 { 00446 TypedHandle<const T> v = th; 00447 00448 if (NULL == v) 00449 { 00450 // from NULL to any type is allowed 00451 return D(); // NULL 00452 } 00453 00454 // input is a non-NULL view 00455 if (constness<typename D::ValueType>::applied) 00456 { 00457 // input type is a holder(view), output type is a view or holder 00458 // return a view and let it be converted if necessary to a holder 00459 // producing a holder(handle) can't happen from here, but we've 00460 // already proved that the input type is a view (NULL == h) 00461 TypedHandle<typename D::ValueType> vD( 00462 (typename D::ValueType*) get_pointer( 00463 cast<typename D::ValueType::View>(v, fThrow)), v); 00464 return vD; 00465 } 00466 else 00467 { 00468 // output type is a handle; input type is a view (error) 00469 if (fThrow) 00470 { 00471 coh_throw_const_cast(typeid(typename D::ValueType), typeid(*th)); 00472 } 00473 return D(); // NULL 00474 } 00475 } 00476 00477 // input type is a holder(handle), output type can be handle/view/holder; 00478 // cast from on the handle, and allow conversion to produce expected 00479 // result type 00480 return cast<typename D::ValueType::Handle>(h, fThrow); 00481 } 00482 00483 /** 00484 * Perform an instanceof check on a handle or view. 00485 * 00486 * @param th the TypedHolder from which to perform the test 00487 * 00488 * @return true if the supplied handle is an instance of the specified type 00489 */ 00490 template<class D, class T> 00491 bool instanceof(const TypedHolder<T>& th) 00492 { 00493 return NULL !=th && NULL != cast<D>(th, false); 00494 } 00495 00496 COH_CLOSE_NAMESPACE2 00497 00498 #endif // COH_TYPED_HOLDER_HPP