coherence/lang/ChainedHandleElement.hpp

00001 /*
00002 * ChainedHandleElement.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_CHAINED_HANDLE_ELEMENT_HPP
00017 #define COH_CHAINED_HANDLE_ELEMENT_HPP
00018 
00019 #include "coherence/lang/compatibility.hpp"
00020 
00021 #include <stdlib.h>
00022 
00023 COH_OPEN_NAMESPACE2(coherence,lang)
00024 
00025 /**
00026 * @internal
00027 *
00028 * The base class for TypedHandles, allowing for reference chaining.  Reference
00029 * chaining is not thread-safe and thus may only be used for handles which are
00030 * not shared across threads.
00031 *
00032 * @author mf  2008.10.20
00033 */
00034 class ChainedHandleElement
00035     {
00036     protected:
00037         /**
00038         * Action to take on unlinking
00039         */
00040         typedef enum
00041             {
00042             ACTION_NONE   = 0, // no action required, chain still exists
00043             ACTION_FLIP   = 1, // unlink last handle from handle->view chain
00044             ACTION_DETACH = 2, // unlink final element of chain
00045             ACTION_ERROR  = 3  // corrupted chain, raise error
00046             } Action;
00047 
00048 
00049     // ----- constructors ---------------------------------------------------
00050 
00051     protected:
00052         /**
00053         * Create an independent element.
00054         */
00055         ChainedHandleElement(bool fView)
00056             : m_fView(fView)
00057             {
00058             // new chain
00059             m_prev = m_next = this;
00060             }
00061 
00062         /**
00063         * Create a dependent element, adding it to a chain.
00064         */
00065         ChainedHandleElement(const ChainedHandleElement& that, bool fView)
00066             : m_prev(&that), m_next(that.m_next), m_fView(fView)
00067             {
00068             // add self to chain
00069             m_next->m_prev = m_prev->m_next = this;
00070             }
00071 
00072         /**
00073         * Create an optionally dependent element.
00074         */
00075         ChainedHandleElement(const ChainedHandleElement* that, bool fView)
00076             : m_fView(fView)
00077             {
00078             if (that)
00079                 {
00080                 // add self to chain
00081                 m_prev = that;
00082                 m_next = that->m_next;
00083                 m_next->m_prev = m_prev->m_next = this;
00084                 }
00085             else
00086                 {
00087                 // new chain
00088                 m_prev = m_next = this;
00089                 }
00090             }
00091 
00092         /**
00093         * No destructor, derived class must perform unlink and take resulting
00094         * action.
00095         */
00096         //~ChainedHandleElement()
00097 
00098 
00099     // ----- ChainedHandleElement interface ---------------------------------
00100 
00101     protected:
00102         /**
00103         * Unlink this element from the chain.
00104         *
00105         * @return the action to be taken
00106         */
00107         Action unlink()
00108             {
00109             Action nAction = this == m_prev
00110                 ? this == m_next ? ACTION_DETACH : ACTION_ERROR
00111                 : !m_fView && m_prev->m_fView && m_next->m_fView && scan()
00112                     ? ACTION_FLIP : ACTION_NONE;
00113 
00114             // unlink self from chain
00115             m_prev->m_next = m_next;
00116             m_next->m_prev = m_prev;
00117 
00118             // empty chain
00119             m_prev = m_next = this;
00120 
00121             return nAction;
00122             }
00123 
00124         /**
00125         * Link this element to a new chain.
00126         *
00127         * @param that  the element to link to
00128         *
00129         * @return the action to be taken
00130         */
00131         Action link(const ChainedHandleElement& that)
00132             {
00133             Action nAction = this == m_prev
00134                 ? this == m_next ? ACTION_DETACH : ACTION_ERROR
00135                 : !m_fView && m_prev->m_fView && m_next->m_fView && scan()
00136                     ? ACTION_FLIP : ACTION_NONE;
00137 
00138             // unlink self from chain
00139             m_prev->m_next = m_next;
00140             m_next->m_prev = m_prev;
00141 
00142             // link self into new chain
00143             m_prev = &that;
00144             m_next = that.m_next;
00145 
00146             m_next->m_prev = that.m_next = this;
00147 
00148             return nAction;
00149             }
00150 
00151         /**
00152         * Scan the chain for additional handles.
00153         *
00154         * The caller must be a handle, and have found views on both sides.
00155         *
00156         * @return true if this is the only handle in the chain
00157         */
00158         bool scan()
00159             {
00160             // The current element must be a handle, so we can scan the list
00161             // until we encounter a handle; if it is this element then there
00162             // are no other handles present. While this is a potentially
00163             // expensive call it is also rarely occurs on a non-trivial chain.
00164             // Since you cannot assign a Handle from a View this will only
00165             // happen if multiple Views are injected in the middle of a handle
00166             // chain. Overall this minimal rare cost is more than worth it as
00167             // it allows chaining of Handles and Views, which removes the far
00168             // more expensive (potentially atomic) reference count increment
00169             // for the common pattern of passing a Handle to a function which
00170             // takes a View.
00171             ChainedHandleElement const* pElm;
00172             for (pElm = m_prev; pElm->m_fView; pElm = pElm->m_prev);
00173             return pElm == this;
00174             }
00175 
00176 
00177     // ----- blocked methods ------------------------------------------------
00178 
00179     private:
00180         /**
00181         * Blocked dynamic allocation.
00182         */
00183         static void* operator new(size_t cb);
00184 
00185 
00186     // ----- data members ---------------------------------------------------
00187 
00188     protected:
00189         /**
00190         * The previous element in the chain.
00191         */
00192         mutable ChainedHandleElement const* m_prev;
00193 
00194         /**
00195         * The next element in the chain.
00196         */
00197         mutable ChainedHandleElement const* m_next;
00198 
00199         /**
00200         * Flag indicating if the associated handle is a view.
00201         */
00202         bool m_fView;
00203     };
00204 
00205 COH_CLOSE_NAMESPACE2
00206 
00207 #endif // COH_CHAINED_HANDLE_ELEMENT_HPP
Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.