ATL3: CSimpleVector template

The ATL3 array template (CSimpleArray) is buggy and leaky -- don't use it (note: ATL7 finally repairs the bugs in CSimpleArray, and also offers a newer template, CAtlArray).

The CSimpleVector<> template requires T to have a meaningful default ctor, copy ctor, and assignment-operator. The Find method requires T to have a meaningful operator==.

ATLX::CSimpleVector<CMyClass> vec1;
ATLX::CSimpleVector<float,float> vec2;

In the above examples, vec1 will pass arguments by reference, but vec2 will pass arguments as float (not float&).

#pragma once

namespace ATLX
{

template<class T, class A=T&>
class CSimpleVector
{

// Implementaion
private:

   struct CInPlaceNewWrapper
   {
      T t;

      CInPlaceNewWrapper(const T& _t) : t(_t)
      { }
      void* operator new(size_t n, void* p) 
      { return p; }
   };

   T* m_pT;
   int m_nSize,m_nAllocSize;

// Initializers
public:

   CSimpleVector()
   {
      m_pT = 0;
      m_nSize = m_nAllocSize = 0;
   }

   CSimpleVector(const CSimpleVector<T,A>& src)
   {
      m_pT = 0;
      m_nSize = m_nAllocSize = 0;
      (*this) = src;
   }

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

   ~CSimpleVector()
   {
      RemoveAll();
      free(m_pT);
   }

// Accessors
public:

   int GetSize() const
   { return m_nSize; }

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

   T& operator[](int i) const
   { ATLASSERT(i >= 0 && i < m_nSize); 
     return (m_pT[i]); }

   void CopyTo(T* pt) const
   { ::CopyMemory(pt,m_pT,m_nSize*sizeof(T)); }

   int Find(A a) const
   {
      for(int i = 0; i < m_nSize; i++)
         if (m_pT[i] == a) // requires meaningful T::operator==
            return i;
      return -1;
   }

// Operations
public:

   void Reserve(int i)
   {
      ATLASSERT(i >= 0);
      if (i > 0)
      {
         // Expand the allocation
         if (i < m_nSize) i = m_nSize;
         m_pT = (T*)realloc(m_pT,i*sizeof(T));
         m_nAllocSize = i;
      }
      else // i == 0
      {
         // Trim the fat, if any
         if (m_nSize == 0)
         { free(m_pT); m_pT = 0; }
         else if (m_nSize < m_nAllocSize)
         { m_pT = (T*)realloc(m_pT,m_nSize*sizeof(T)); }
         m_nAllocSize = m_nSize;
      }
   }

   void Push(A a)
   {
      if (m_nSize == m_nAllocSize)
         Reserve((m_nAllocSize==0)?(4):(m_nAllocSize*2)); // first alloc == 4*sizeof(T)

      m_nSize++;
      new(m_pT+m_nSize-1) CInPlaceNewWrapper(a);
   }

   T Pop()
   {
      ATLASSERT(m_nSize != 0);
      T t = m_pT[m_nSize-1];

      m_pT[m_nSize-1].~T();
      m_nSize--;

      return t;
   }

   void Append(const CSimpleVector<T,A>& src)
   {
      for(int i = 0; i < src.GetSize(); i++)
         Push(src[i]);
   }

   void RemoveAll()
   {
      for(int i = 0; i < m_nSize; i++)
         m_pT[i].~T();
      m_nSize = 0;
   }

   void Swap(int x, int y)
   {
      ATLASSERT(x >= 0 && x < m_nSize);
      ATLASSERT(y >= 0 && y < m_nSize);

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

      ::CopyMemory(pt,&m_pT[x],sizeof(T));
      ::CopyMemory(&m_pT[x],&m_pT[y],sizeof(T));
      ::CopyMemory(&m_pT[y],pt,sizeof(T));

      free(pt);
   }

   void Sort()
   {
      // Non-destructive swap-sort (as deterined by T::operator<)
      bool bDone = false;
      while (!bDone)
      {
         bDone = true;
         for (int i=0; i < (m_nSize-1); i++)
         {
            if (m_pT[i+1] < m_pT[i]) 
            {
               Swap(i,i+1);
               bDone = false;
            }
         }
      }
   }

};

} // namespace