intrusive list

来源:互联网 发布:主流的社交软件 编辑:程序博客网 时间:2024/06/05 17:15
/******************************************************************************** List.h*** By Patrick Wyatt - 5/16/2010****//******************************************************************************** WHAT IT IS** This module defines a linked-list implementation that uses "embedded"* links rather than separately allocated link-nodes as does STL and* more or less all other linked-list implementations.** Why is this cool:* 1. No additional memory allocations (malloc) required to link* an object into a linked list.* 2. Not necessary to traverse an additional pointer references* to get to the object being dereferenced.* 3. Probably most importantly, when objects get deleted, they* automatically unlink themselves from the lists they're* linked to, eliminating many common types of bugs.** HOW TO USE IT** Declare a structure that will be contained in one or more linked lists:* class CFoo {* LIST_LINK(CFoo) m_linkByData;* LIST_LINK(CFoo) m_linkByType;* int m_data;* int m_type;* ...* };** Declare list variables:* LIST_DECLARE(CFoo, m_linkByData) listByData;* LIST_DECLARE(CFoo, m_linkByType) listByType;* LIST_PTR(CFoo) m_listPtr = foo ? &listByData : &listByType;** Operations on links:* T * Prev ();* T * Next ();* void Unlink ();* bool IsLinked () const;** Operations on lists:* bool Empty () const;* void UnlinkAll ();* void DeleteAll ();** T * Head ();* T * Tail ();* T * Prev (T * node);* T * Next (T * node);** void InsertHead (T * node);* void InsertTail (T * node);* void InsertBefore (T * node, T * before);* void InsertAfter (T * node, T * after);** NOTES** Limitations:* All nodes must be allocated on (at least) two-byte boundaries* because the low bit is used as a sentinel to signal end-of-list.** Thanks to:* Something like this code was originally implemented by Mike* O'Brien in storm.dll for Diablo in 1995, and again at ArenaNet* for Guild Wars.****/#ifdef LIST_H#error "Header included more than once"#endif#define LIST_H/******************************************************************************** List definition macros****/// Define a linked list:// T = type of object being linked// link = member within object which is the link field#define LIST_DECLARE(T, link) TListDeclare<T, offsetof(T, link)>// Define a field within a structure that will be used to link it into a list#define LIST_LINK(T) TLink<T>// Define a pointer to a list#define LIST_PTR(T) TList<T> */******************************************************************************** TLink****///=============================================================================template<class T>class TLink {public:    ~TLink ();    TLink ();    bool IsLinked () const;    void Unlink ();    T * Prev ();    T * Next ();    const T * Prev () const;    const T * Next () const;    // For use by list-type classes, not user code;    // the alternative is to friend TList<T>, THash<T>,    // and (eventually) many other structures.    TLink (size_t offset);    void SetOffset (size_t offset);    TLink<T> * NextLink ();    TLink<T> * PrevLink ();    void InsertBefore (T * node, TLink<T> * nextLink);    void InsertAfter (T * node, TLink<T> * prevLink);private:    T * m_nextNode; // pointer to the next >object<    TLink<T> * m_prevLink; // pointer to the previous >link field<    void RemoveFromList ();    // Hide copy-constructor and assignment operator    TLink (const TLink &);    TLink & operator= (const TLink &);};//=============================================================================template<class T>TLink<T>::~TLink () {    RemoveFromList();}//=============================================================================template<class T>TLink<T>::TLink () {    // Mark this node as the end of the list, with no link offset    m_nextNode = (T *) ((size_t) this + 1 - 0);    m_prevLink = this;}//=============================================================================template<class T>TLink<T>::TLink (size_t offset) {    // Mark this node as the end of the list, with the link offset set    m_nextNode = (T *) ((size_t) this + 1 - offset);    m_prevLink = this;}//=============================================================================template<class T>void TLink<T>::SetOffset (size_t offset) {    // Mark this node as the end of the list, with the link offset set    m_nextNode = (T *) ((size_t) this + 1 - offset);    m_prevLink = this;}//=============================================================================template<class T>TLink<T> * TLink<T>::NextLink () {    // Calculate the offset from a node pointer to a link structure    size_t offset = (size_t) this - ((size_t) m_prevLink->m_nextNode & ~1);    // Get the link field for the next node    return (TLink<T> *) (((size_t) m_nextNode & ~1) + offset);}//=============================================================================template<class T>void TLink<T>::RemoveFromList () {    NextLink()->m_prevLink = m_prevLink;    m_prevLink->m_nextNode = m_nextNode;}//=============================================================================template<class T>void TLink<T>::InsertBefore (T * node, TLink<T> * nextLink) {    RemoveFromList();    m_prevLink = nextLink->m_prevLink;    m_nextNode = m_prevLink->m_nextNode;    nextLink->m_prevLink->m_nextNode = node;    nextLink->m_prevLink = this;}//=============================================================================template<class T>void TLink<T>::InsertAfter (T * node, TLink<T> * prevLink) {    RemoveFromList();    m_prevLink = prevLink;    m_nextNode = prevLink->m_nextNode;    prevLink->NextLink()->m_prevLink = this;    prevLink->m_nextNode = node;}//=============================================================================template<class T>bool TLink<T>::IsLinked () const {    return m_prevLink != this;}//=============================================================================template<class T>void TLink<T>::Unlink () {    RemoveFromList();    // Mark this node as the end of the list with no link offset    m_nextNode = (T *) ((size_t) this + 1);    m_prevLink = this;}//=============================================================================template<class T>TLink<T> * TLink<T>::PrevLink () {    return m_prevLink;}//=============================================================================template<class T>T * TLink<T>::Prev () {    T * prevNode = m_prevLink->m_prevLink->m_nextNode;    if ((size_t) prevNode & 1)        return NULL;    return prevNode;}//=============================================================================template<class T>const T * TLink<T>::Prev () const {    const T * prevNode = m_prevLink->m_prevLink->m_nextNode;    if ((size_t) prevNode & 1)        return NULL;    return prevNode;}//=============================================================================template<class T>T * TLink<T>::Next () {    if ((size_t) m_nextNode & 1)        return NULL;    return m_nextNode;}//=============================================================================template<class T>const T * TLink<T>::Next () const {    if ((size_t) m_nextNode & 1)        return NULL;    return m_nextNode;}/******************************************************************************** TList****///=============================================================================template<class T>class TList {public:    ~TList ();    TList ();    bool Empty () const;    void UnlinkAll ();    void DeleteAll ();    T * Head ();    T * Tail ();    const T * Head () const;    const T * Tail () const;    T * Prev (T * node);    T * Next (T * node);    const T * Prev (const T * node) const;    const T * Next (const T * node) const;    void InsertHead (T * node);    void InsertTail (T * node);    void InsertBefore (T * node, T * before);    void InsertAfter (T * node, T * after);private:    TLink<T> m_link;    size_t m_offset;    TList (size_t offset);    TLink<T> * GetLinkFromNode (const T * node) const;    template<class T, size_t offset> friend class TListDeclare;    // Hide copy-constructor and assignment operator    TList (const TList &);    TList & operator= (const TList &);};//=============================================================================template<class T>TList<T>::~TList () {    UnlinkAll();}//=============================================================================template<class T>TList<T>::TList () :    m_link(),    m_offset((size_t) -1){}//=============================================================================template<class T>TList<T>::TList (size_t offset) :    m_link(offset),    m_offset(offset){}//=============================================================================template<class T>bool TList<T>::Empty () const {    return m_link.Next() == NULL;}//=============================================================================template<class T>void TList<T>::UnlinkAll () {    for (;;) {        TLink<T> * link = m_link.PrevLink();        if (link == &m_link)            break;        link->Unlink();    }}//=============================================================================template<class T>void TList<T>::DeleteAll () {    while (T * node = m_link.Next())        delete node;}//=============================================================================template<class T>T * TList<T>::Head () {    return m_link.Next();}//=============================================================================template<class T>T * TList<T>::Tail () {    return m_link.Prev();}//=============================================================================template<class T>const T * TList<T>::Head () const {    return m_link.Next();}//=============================================================================template<class T>const T * TList<T>::Tail () const {    return m_link.Prev();}//=============================================================================template<class T>T * TList<T>::Prev (T * node) {    return GetLinkFromNode(node)->Prev();}//=============================================================================template<class T>const T * TList<T>::Prev (const T * node) const {    return GetLinkFromNode(node)->Prev();}//=============================================================================template<class T>T * TList<T>::Next (T * node) {    return GetLinkFromNode(node)->Next();}//=============================================================================template<class T>const T * TList<T>::Next (const T * node) const {    return GetLinkFromNode(node)->Next();}//=============================================================================template<class T>void TList<T>::InsertHead (T * node) {    InsertAfter(node, NULL);}//=============================================================================template<class T>void TList<T>::InsertTail (T * node) {    InsertBefore(node, NULL);}//=============================================================================template<class T>void TList<T>::InsertBefore (T * node, T * before) {    ASSERT(!((size_t) node & 1));    GetLinkFromNode(node)->InsertBefore(        node,        before ? GetLinkFromNode(before) : &m_link    );}//=============================================================================template<class T>void TList<T>::InsertAfter (T * node, T * after) {    ASSERT(!((size_t) node & 1));    GetLinkFromNode(node)->InsertAfter(        node,        after ? GetLinkFromNode(after) : &m_link    );}//=============================================================================template<class T>TLink<T> * TList<T>::GetLinkFromNode (const T * node) const {    ASSERT(m_offset != (size_t) -1);    return (TLink<T> *) ((size_t) node + m_offset);}/******************************************************************************** TListDeclare - declare a list with a known link offset****///=============================================================================template<class T, size_t offset>class TListDeclare : public TList<T> {public:    TListDeclare ();};//=============================================================================template<class T, size_t offset>TListDeclare<T, offset>::TListDeclare () : TList<T>(offset){}//===================================// MIT License//// Copyright (c) 2010 by Patrick Wyatt//// Permission is hereby granted, free of charge, to any person obtaining a copy// of this software and associated documentation files (the "Software"), to deal// in the Software without restriction, including without limitation the rights// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell// copies of the Software, and to permit persons to whom the Software is// furnished to do so, subject to the following conditions://// The above copyright notice and this permission notice shall be included in// all copies or substantial portions of the Software.//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN// THE SOFTWARE.//===================================


原创粉丝点击