ATL3: CSimpleList template

As seen in Attila (note: ATL7 offers similar functionality with their new CAtlList template).

Using CSimpleList<T> requires T to have a meaningful default ctor, copy ctor, and assignment operator.  The Sort method requires T::operator<.  The Find and RemoveDups methods require T::operator==.

Usage:

ATLX::CSimpleList<CMyClass> list1;
ATLX::CSimpleList<float> list2;
#pragma once

namespace ATLX 
{

template<class T>
class CSimpleList
{
    struct node
    {
        T t;
        node* pPrev;
        node* pNext;

        node() { pPrev = pNext = 0; }
    };

    int m_nCount;
    node* m_pHead;
    node* m_pTail;

public:

    // Initializers

    CSimpleList()
    { m_nCount = 0;
    m_pHead = m_pTail = 0; }

    CSimpleList(const CSimpleList<T>& src)
    { m_nCount = 0;
    m_pHead = m_pTail = 0;
    (*this) = src; }

    CSimpleList& operator=(const CSimpleList<T>& src)
    { RemoveAll();
    Append(src);
    return (*this); }

    ~CSimpleList()
    { RemoveAll(); }

    // Accessors

    int Count() const
    { return m_nCount; }

    bool IsEmpty() const
    { return (m_nCount==0); }

    struct iterator
    {
        node* ptr;

        iterator() 
        { ptr = 0; }

        iterator(node* p) 
        { ptr = p; }

        iterator(const iterator& x) 
        { ptr = x.ptr; }

        T& operator*() 
        { ATLASSERT(ptr); 
        return (ptr->t); }

        T* operator->() // hack to avoid T::operator& -- t must be first member in struct node
        { ATLASSERT(ptr); 
        return reinterpret_cast<T*>(ptr); }

        iterator& operator++() 
        { ATLASSERT(ptr); 
        ptr = ptr->pNext; 
        return (*this); }

        iterator& operator--() 
        { ATLASSERT(ptr); 
        ptr = ptr->pPrev; 
        return (*this); }

        iterator operator++(int) 
        { ATLASSERT(ptr); 
        iterator old = ptr; 
        ptr = ptr->pNext; 
        return old; }

        iterator operator--(int) 
        { ATLASSERT(ptr); 
        iterator old = ptr; 
        ptr = ptr->pPrev; 
        return old; }

        bool operator==(const iterator& x) const 
        { return (ptr==x.ptr) ? (true) : (false); }

        bool operator!=(const iterator& x) const 
        { return (ptr==x.ptr) ? (false) : (true); }
    };

    iterator Head() const
    { return iterator(m_pHead); }

    iterator Tail() const
    { return iterator(m_pTail); }

    iterator Begin() const
    { return iterator(m_pHead); }

    iterator End() const
    { return iterator(0); }

    iterator Find(const T& t) const
    {
        for(iterator p = Begin(); p != End(); ++p)
            if (*p == t) // requires meaningful T::operator==
                return p;

        return 0;
    }

    // Operations

    void Add(const T& t)
    {
        InsertAt(End(),t);
    }

    void InsertAt(const iterator& p, const T& t)
    {
        // Insert "t" in front of "p" (between pX and pY)
        node* pX = (p.ptr) ? (p.ptr->pPrev) : (m_pTail);
        node* pY = p.ptr;

        m_nCount++;
        node* pNew = new node;
        ATLASSERT(pNew);

        pNew->t = t;
        pNew->pPrev = pX;
        pNew->pNext = pY;

        if (pX)
            pX->pNext = pNew;

        if (pY) 
            pY->pPrev = pNew;

        if (!m_pHead || !pX) 
            m_pHead = pNew;

        if (!m_pTail || !pY) 
            m_pTail = pNew;
    }

    void Append(const CSimpleList<T>& src)
    {
        for(iterator p = src.Begin(); p != src.End(); ++p)
            Add(*p);
    }

    void RemoveAt(const iterator& p)
    {
        node* pn = p.ptr;
        if (!pn) return;

        if (pn->pPrev) pn->pPrev->pNext = pn->pNext;
        else m_pHead = pn->pNext;

        if (pn->pNext) pn->pNext->pPrev = pn->pPrev;
        else m_pTail = pn->pPrev;

        delete pn;
        m_nCount--;
    }

    void RemoveAll()
    { 
        while (!IsEmpty()) 
            RemoveAt(Tail()); 
    }

    //todo: test!
    void RemoveDuplicates()
    {
        // Remove duplicate entries (as determined by T::operator==)
        for(iterator p = Begin(); p != End(); ++p)
        {
            iterator p2 = p;
            while (++p2 != End())
            {
                if (*p2 == *p)
                { RemoveAt(p2); p2 = p; }
            }
        }
    }

    void Swap(const iterator& p1, const iterator& p2)
    {
        node* pn1 = p1.ptr;
        node* pn2 = p2.ptr;
        if (!pn1 || !pn2) return;

        T* pt = (T*)_alloca(sizeof(T));

        ::CopyMemory(pt,&pn1->t,sizeof(T));
        ::CopyMemory(&pn1->t,&pn2->t,sizeof(T));
        ::CopyMemory(&pn2->t,pt,sizeof(T));
    }

    void Sort()
    {
        // Non-destructive swap-sort (as deterined by T::operator<)
        bool bDone = false;
        while (!bDone)
        {
            bDone = true;
            for(iterator p = Begin(); p != End(); ++p)
            {
                iterator p2 = p; ++p2;
                if (p2 == End()) break;

                if (*p2 < *p) 
                {
                    Swap(p,p2);
                    bDone = false;
                }
            }
        }
    }

};

} // namespace