Oracle Fusion Middleware C++ API Reference for Oracle Coherence
12c (12.1.2)

E26041-01

coherence/lang/TypedHandle.hpp

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
Copyright © 2000, 2013, Oracle and/or its affiliates. All rights reserved.