coherence/lang/TypedHolder.hpp

00001 /*
00002 * TypedHolder.hpp
00003 *
00004 * Copyright (c) 2000, 2009, 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
Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.