coherence/lang/TypedHandle.hpp

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