intrusive list

/******************************************************************************
*
* 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.
//===================================


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值