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

E47891-01

coherence/lang/TypedHandle.hpp

00001 /*
00002 * TypedHandle.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_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             // manually inlined unlink logic allows use of constness<T>::applied
00146             // which should result in the elseif being compiled out for Views
00147             if (this == m_prev /* implies && this == m_next */)
00148                 {
00149                 if (m_o) performAction(action_detach);
00150                 }
00151             // COH-9499 - removed m_prev and m_next m_fView pre-checks due to
00152             // compiler issues with GCC 4.1
00153             else if (m_o && !constness<T>::applied && scan())
00154                 {
00155                 performAction(action_flip);
00156                 }
00157             // else; action_none
00158 
00159             // unlink self from chain
00160             m_prev->m_next = m_next;
00161             m_next->m_prev = m_prev;
00162             }
00163 
00164 
00165     // ----- operators ------------------------------------------------------
00166 
00167     public:
00168         /**
00169         * Dereference this handle, returning <tt>T&</tt>.
00170         *
00171         * @return a raw <tt>T&</tt> reference to the referenced Object
00172         *
00173         * @throws NullPointerException if the this handle is @c NULL
00174         */
00175         T& operator*() const
00176             {
00177             T* po = m_o;
00178             if (NULL == po)
00179                 {
00180                 coh_throw_npe(typeid(T));
00181                 }
00182             return *po;
00183             }
00184 
00185         /**
00186         * Dereference this handle, returning <tt>T*</tt>.
00187         *
00188         * @return a raw <tt>T*</tt> pointer to the referenced Object
00189         *
00190         * @throws NullPointerException if the this handle is @c NULL
00191         */
00192         T* operator->() const
00193             {
00194             T* po = m_o;
00195             if (NULL == po)
00196                 {
00197                 coh_throw_npe(typeid(T));
00198                 }
00199             return po;
00200             }
00201 
00202         /**
00203         * Assign this TypedHandle another Object to reference.
00204         */
00205         TypedHandle<T>& operator=(const TypedHandle<T>& h)
00206             {
00207             set(h.get(), h);
00208             return *this;
00209             }
00210 
00211         /**
00212         * Assign this TypedHandle from a handle to a derived type.
00213         */
00214         template<class DT>
00215         TypedHandle<T>& operator=(const TypedHandle<DT>& h)
00216             {
00217             //      *** PLEASE READ IF YOU GET BUILD ERRORS HERE ****
00218             // A build error in this call indicates that you've attempted to
00219             // assign two non-compatible handle types, or simply trying to
00220             // assign a View to a Handle.  Check your compiler output which
00221             // should state what line in your triggered this template
00222             // instantiation, that is the code which has the error.
00223 
00224             set(get_pointer(h), h);
00225             return *this;
00226             }
00227 
00228         /**
00229         * Compare two handles with "less-than" predicate.  This is only an
00230         * identity based comparison, and does not take the value into account.
00231         */
00232         template<class AT>
00233         bool operator<(const TypedHandle<AT>& h) const
00234             {
00235             return ((const Object*) m_o) < ((const Object*) get_pointer(h));
00236             }
00237 
00238 
00239     // ----- helper methods -------------------------------------------------
00240 
00241     protected: // protected to prevent easily misunderstandings such as
00242                // hMap.get() which might be interpreted as a call on a map
00243 
00244         /**
00245         * Return pointer without null checking.
00246         * Does NOT throw NullPointerException.
00247         *
00248         * One should use <code>h.get()</code> to get raw T* pointer.
00249         * Please do not use neither <code>&*h</code> (as it may throw
00250         * NullPointerException) nor <code>(T*)h</code> (as it may perform
00251         * unsafe unchecked type cast).
00252         */
00253         T* get() const
00254             {
00255             return m_o;
00256             }
00257 
00258         /**
00259         * Set the TypedHandle to attach to the supplied pointer.
00260         * Any existing attachment will be detached.
00261         *
00262         * @param o the address of the object to point to or NULL
00263         */
00264         void set(T* o, const ChainedHandleElement& that)
00265             {
00266             // manually inlined link logic allows use of constness<T>::applied
00267             // which should result in the elseif being compiled out for Views
00268             if (this == m_prev /* implies && this == m_next */)
00269                 {
00270                 if (m_o) performAction(action_detach);
00271                 }
00272             // COH-9499 - removed m_prev and m_next m_fView pre-checks due to
00273             // compiler issues with GCC 4.1
00274             else if (m_o && !constness<T>::applied && scan())
00275                 {
00276                 performAction(action_flip);
00277                 }
00278             // else; action_none
00279 
00280             // unlink self from chain
00281             m_prev->m_next = m_next;
00282             m_next->m_prev = m_prev;
00283 
00284             // link self into new chain
00285             m_prev = &that;
00286             m_next = that.m_next;
00287 
00288             m_next->m_prev = that.m_next = this;
00289 
00290             m_o = o;
00291             }
00292 
00293         /**
00294         * Perform the specified action.
00295         *
00296         * @param nAction  the action to perform
00297         */
00298         void performAction(Action nAction)
00299             {
00300             switch (nAction)
00301                 {
00302                 case action_flip:
00303                     ((const T*) m_o)->_attach(/*fEscaped*/ false);
00304                     // fall through
00305                 case action_detach:
00306                     m_o->_detach(/*fEscaped*/ false);
00307                     // fall through
00308                 case action_none:
00309                 default:
00310                     break;
00311                 }
00312             }
00313 
00314     // ----- functors -------------------------------------------------------
00315 
00316     protected:
00317         /**
00318         * The binary functor that compares objects pointed by the handles
00319         * with the "less-than" operator.
00320         */
00321         template<class RT>
00322         class value_less_functor
00323             : public std::binary_function<RT, RT, bool>
00324             {
00325             public:
00326                 /**
00327                 * Compare values pointed by the specified handles with
00328                 * "less-than" operator.
00329                 */
00330                 bool operator()(const TypedHandle<RT>& h1,
00331                                 const TypedHandle<RT>& h2) const
00332                     {
00333                     return h1 && h1->operator<(h2);
00334                     }
00335             };
00336 
00337         /**
00338         * The binary functor that compares values pointed by the handles for
00339         * equality.
00340         */
00341         template<class RT>
00342         class value_equal_functor
00343             : public std::binary_function<RT, RT, bool>
00344             {
00345             public:
00346                 /**
00347                 * Compare values pointed by the specified handles for
00348                 * equality.
00349                 */
00350                 bool operator()(const TypedHandle<RT>& h1,
00351                                      const TypedHandle<RT>& h2) const
00352                     {
00353                     return h1 == h2 || (h1 && h1->equals(h2));
00354                     }
00355                 };
00356 
00357         /**
00358         * Value based hash functor which is compatible with both the SGI and
00359         * MS style hash containers.
00360         */
00361         template<class RT>
00362         class value_hash_functor
00363             : public std::unary_function<RT, size32_t>
00364             {
00365             public:
00366                 // parameters for MS style hash table
00367                 enum {bucket_size = 4, min_buckets = 8};
00368 
00369             /**
00370             * Hash computation function for MS and SGI style hash containers.
00371             *
00372             * @param h the handle to hash
00373             *
00374             * @return the hash of the handle
00375             */
00376             size32_t operator()(const TypedHandle<RT>& h) const
00377                 {
00378                 return h ? h->hashCode() : 0;
00379                 }
00380 
00381             /**
00382             * Ordering function for MS style hash containers.
00383             *
00384             * @param h1 the first handle to compare
00385             * @param h2 the second handle to compare
00386             *
00387             * @return true iff *h1 < *h2
00388             */
00389             bool operator()(const TypedHandle<RT>& h1,
00390                     const TypedHandle<RT>& h2) const
00391                 {
00392                 return h1 && h1->operator<(h2);
00393                 }
00394             };
00395 
00396 
00397         /**
00398         * Identity based hash functor which is compatible with both the SGI
00399         * and MS style hash containers.
00400         */
00401         template<class RT> class identity_hash_functor
00402             : public std::unary_function<RT, size32_t>
00403             {
00404             public:
00405             // parameters for MS style hash table
00406             enum {bucket_size = 4, min_buckets = 8};
00407 
00408             /**
00409             * Hash computation function for MS and SGI style hash containers.
00410             *
00411             * @param h the handle to hash
00412             *
00413             * @return the hash of the handle
00414             */
00415             size32_t operator()(const TypedHandle<RT>& h) const
00416                 {
00417                 return (size32_t) get_pointer(h);
00418                 }
00419 
00420             /**
00421             * Ordering function for MS style hash containers.
00422             *
00423             * @param h1 the first handle to compare
00424             * @param h2 the second handle to compare
00425             *
00426             * @return true iff h1 < h2
00427             */
00428             bool operator()(const TypedHandle<RT>& h1,
00429                             const TypedHandle<RT>& h2) const
00430                 {
00431                 return get_pointer(h1) < get_pointer(h2);
00432                 }
00433             };
00434 
00435     public:
00436         /**
00437         * Functor allowing handles to be used within STL sorted containers,
00438         * such as std::map and std::set, and to have their equivalence checks
00439         * delegated to the Objects they reference.
00440         */
00441         typedef value_less_functor<T> value_compare;
00442 
00443         /**
00444         * Functor allowing handles to be used within hash containers, such as
00445         * the SGI and MS style hash_map and hash_set, and to have their
00446         * equivalence checks delegated to the Objects they reference.
00447         */
00448         typedef value_equal_functor<T> value_equal;
00449 
00450         /**
00451         * Functor allowing handles to be used within hash containers, such as
00452         * the SGI as MS style hash_map and hash_set, and to have their hash
00453         * computation be based on the value of the referenced Object.
00454         */
00455         typedef value_hash_functor<T> value_hasher;
00456 
00457         /**
00458         * Functor allowing handles to be used within hash containers, such as
00459         * the SGI as MS style hash_map and hash_set, and to have their hash
00460         * computation be based on their identity, i.e. the reference they
00461         * contain.
00462         */
00463         typedef identity_hash_functor<T> identity_hasher;
00464 
00465 
00466     // ----- data members ---------------------------------------------------
00467 
00468     protected:
00469         /**
00470         * Pointer to the referenced object.
00471         */
00472         T* m_o;
00473 
00474 
00475     // ---- friends ---------------------------------------------------------
00476 
00477     /**
00478     * @internal
00479     */
00480     template<class O> friend O* get_pointer(const TypedHandle<O>& h);
00481 
00482     /**
00483     * @internal
00484     */
00485     template<class D, class O> friend D cast(const TypedHandle<O>& th,
00486             bool fThrow);
00487 
00488     /**
00489     * @internal
00490     */
00491     template<class> friend class TypedHandle;
00492     };
00493 
00494 
00495 // ----- non-member operators and functions ---------------------------------
00496 
00497 /**
00498 * Output a human-readable description of the given TypedHandle<T> to the
00499 * specified stream.
00500 *
00501 * @param out  the stream used to output the description
00502 * @param v    the TypedHandle<T> to describe
00503 *
00504 * @return the supplied stream
00505 */
00506 template<class T>
00507 std::ostream& operator<<(std::ostream& out, const TypedHandle<T>& v)
00508     {
00509     if (NULL == v)
00510         {
00511         out << "NULL";
00512         }
00513     else
00514         {
00515         v->toStream(out);
00516         }
00517     return out;
00518     }
00519 
00520 /**
00521 * @internal
00522 *
00523 * Return the pointer associated with the TypedHandle.
00524 *
00525 * The lifetime of the Object referenced by the returned pointer
00526 * cannot be guaranteed beyond the lifetime of the Handle from
00527 * which it was obtained. Additionally if the associated handle is reassigned
00528 * the lifetime of the referenced Object is also undefined.
00529 *
00530 * @param h the Handle to used in retrieving the pointer.
00531 *
00532 * @return the pointer associated with the TypedHandle.
00533 */
00534 template<class T>
00535 T* get_pointer(const TypedHandle<T>& h)
00536     {
00537     return h.get();
00538     }
00539 
00540 /**
00541 * Assign the specified handle to NULL. In most cases h = NULL is sufficient
00542 * but for some handle types there may be ambiguity which would require
00543 * knowledge of the Handle type, i.e. <code>hString = (String::Handle) NULL;
00544 * </code>. While the prior example will work just fine
00545 * <code>clear_handle(hString)</code> performs the same function without
00546 * requiring the explicit type cast in user code, and works the same for all
00547 * handle types.
00548 *
00549 * @param h the handle to clear
00550 */
00551 template<class T>
00552 void clear_handle(TypedHandle<T>& h)
00553     {
00554     h = NULL;
00555     }
00556 
00557 /**
00558 * Return true if the supplied handle equals NULL.
00559 *
00560 * @param h  the handle to test
00561 *
00562 * @return true iff the supplied handle equals NULL
00563 */
00564 template<class T>
00565 bool is_null(const TypedHandle<T>& h)
00566     {
00567     return h == NULL;
00568     }
00569 
00570 /**
00571 * Perform a dynamic cast the pointer associated with the TypedHandle
00572 * to a the specified handle/view type.
00573 *
00574 * @param th      the TypedHandle from which to perform the cast
00575 * @param fThrow  true if an exception is to be thrown on a failed cast
00576 *
00577 * @return the casted pointer, or NULL if the cast fails and fThrow is false
00578 *
00579 * @throws ClassCastException if the cast fails and fThrow of is true
00580 */
00581 template<class D, class T>
00582 D cast(const TypedHandle<T>& th, bool fThrow = true)
00583     {
00584     if (NULL == th)
00585         {
00586         return D(); // NULL
00587         }
00588 
00589     typedef typename D::ValueType DT;
00590     typedef typename DT::this_spec DTS;
00591     DT* pD;
00592     if (assignment<DT, T>::allowed)
00593         {
00594         // free compile time cast
00595         pD = assignment<DT, T>::safe(get_pointer(th));
00596         }
00597     else // runtime cast
00598         {
00599         pD = (DT*) th->_cast(COH_CLASS_ID(DTS));
00600         }
00601 
00602     if (NULL == pD)
00603         {
00604         if (fThrow)
00605             {
00606             coh_throw_class_cast(typeid(DT), typeid(*th));
00607             }
00608         return D(); // NULL
00609         }
00610 
00611     if (constness<T>::applied)
00612         {
00613         // from View to View or Holder(View)
00614         return TypedHandle<DT>(pD, th);
00615         }
00616 
00617     // from Handle to Handle, View, or Holder(Handle)
00618     TypedHandle<typename DT::Handle::ValueType> hD(
00619             const_cast<typename DT::Handle::ValueType*>(pD), th);
00620     return hD;
00621     }
00622 
00623 /**
00624 * Perform an instanceof check on a handle or view.
00625 *
00626 * @param th  the TypedHandle from which to perform the test
00627 *
00628 * @return true if the supplied handle is an instance of the specified type
00629 */
00630 template<class DT, class T>
00631 bool instanceof(const TypedHandle<T>& th)
00632     {
00633     typedef typename DT::ValueType::this_spec DTS;
00634     return NULL != th &&
00635         (assignment<typename DT::ValueType, T>::allowed ||
00636          th->_cast(COH_CLASS_ID(DTS)));
00637     }
00638 
00639 COH_CLOSE_NAMESPACE2
00640 
00641 #endif // COH_TYPED_HANDLE_HPP
Copyright © 2000, 2014, Oracle and/or its affiliates. All rights reserved.