#include <afxtempl.h>
template <class T>
class CMyTypedPtrList : public CTypedPtrList<CPtrList, T*>
{
public:
// Construction
CMyTypedPtrList (bool ownsElements = false)
{
bOwnsElements = ownsElements;
}
CMyTypedPtrList (const CMyTypedPtrList<T>& rhs)
{
*this = rhs;
}
// Implementation
virtual ~CMyTypedPtrList()
{
RemoveAll();
}
// Attributes
public:
// Operations
public:
// Overrides
CMyTypedPtrList<T>& operator=(const CMyTypedPtrList<T>& rhs)
{
if (this != &rhs)
{
RemoveAll();
bOwnsElements = rhs.bOwnsElements;
POSITION pos_rhs = rhs.GetHeadPosition();
while ( pos_rhs != NULL )
{
T* t = rhs.GetNext(pos_rhs);
if (rhs.bOwnsElements)
AddTail(new T(*t)); // we need to take our own copy!
else
AddTail(t);
}
}
return *this;
}
void RemoveAll ()
{
if (bOwnsElements)
{
POSITION pos = GetHeadPosition();
while (pos)
{
T *t = GetNext(pos);
delete t;
t=NULL;
}
}
CTypedPtrList<CPtrList, T*>::RemoveAll();
}
enum eSortType { ASCENDING, DESCENDING };
void Sort (eSortType SortType = ASCENDING)
{
CMyTypedPtrList<T> listTmp (*this);
RemoveAll ();
POSITION pos = listTmp.GetHeadPosition();
while ( pos != NULL )
{
T* t = listTmp.GetNext(pos);
if (bOwnsElements)
AddSorted(new T(*t));
else
AddSorted(t);
}
if (SortType == DESCENDING)
{
for (int i=0, j=GetCount ()-1; i < j; i++, j--)
Swap (i,j);
}
}
void AddSorted(T* pNewItem)
{
ASSERT(AfxIsValidAddress(pNewItem, sizeof(T)));
T* pItem;
POSITION pos;
int i;
// advance to the appropriate spot for insertion
for(i=0,pos = GetHeadPosition(); pos != NULL; i++)
{
pItem = GetAt(pos);
// don't advance pos if we're inserting
if (*pNewItem < *pItem)
break;
GetNext(pos);
}
// this results in equal items being in reverse order of addition
if ( pos == NULL )
AddTail(pNewItem);
else
if ( i == 0 )
AddHead(pNewItem);
else
InsertBefore(pos, pNewItem);
}
bool MoveUp(int nCurrentPosn)
{
if (nCurrentPosn > 0)
{
return Swap (nCurrentPosn-1, nCurrentPosn);
}
return false;
}
bool MoveDown(int nCurrentPosn)
{
if (nCurrentPosn < (GetCount()-1))
{
return Swap (nCurrentPosn, nCurrentPosn+1);
}
return false;
}
bool Swap (int nPosn1, int nPosn2)
{
if (nPosn1 != nPosn2)
{
POSITION pos1 = FindIndex(nPosn1);
POSITION pos2 = FindIndex(nPosn2);
if ((pos1 != NULL) && (pos2 != NULL))
{
T *pt1 = GetAt(pos1);
T *pt2 = GetAt(pos2);
SetAt (pos2, pt1);
SetAt (pos1, pt2);
return true;
}
}
return false;
}
POSITION Find (const T* rhs)
{
POSITION pos = GetHeadPosition();
while (pos)
{
T *t= GetAt(pos);
if(*t == *rhs)
return pos;
GetNext (pos);
}
return NULL;
}
bool operator==(const CMyTypedPtrList<T>& rhs)
{
POSITION pos = GetHeadPosition();
POSITION pos_rhs = GetHeadPosition();
while ((pos != NULL) && (pos_rhs != NULL))
{
T *t = GetNext(pos);
T *t_rhs = GetNext(pos_rhs);
if(*t != *t_rhs)
return false;
}
return true;
}
bool operator!=(const CMyTypedPtrList<T>& rhs)
{
return !(*this == rhs);
}
bool operator<(const CMyTypedPtrList<T>& rhs)
{
bool bIsLess = true;
POSITION pos = GetHeadPosition();
POSITION pos_rhs = GetHeadPosition();
while ((pos != NULL) && (pos_rhs != NULL))
{
T *t = GetNext(pos);
T *t_rhs = GetNext(pos_rhs);
if(*t_rhs < *t)
return false;
}
return true;
}
protected:
private:
bool bOwnsElements;
};
///////////////////////////////////////////////////////
class CMyStringPtrList : public CMyTypedPtrList<CString>
{
public:
CMyStringPtrList (bool ownsElements = false):CMyTypedPtrList<CString>(ownsElements){}
virtual ~CMyStringPtrList (){}
enum { SPLIT_ALL = -1, JOIN_ALL = -1};
// Notes:
// If nLimit = -1 then split the whole string (default)
// or you can get the first 'n' tokens
// If bKeepEmptyToken is true then an empty string will be kept
// i.e. an empty token is encountered when there are two or more consecutive
// delimiters
// eg: The string: "GEORGE,IS,A,,,,DOOD" when split with bKeepEmptyToken = true
// will result in a list of tokens...
// GEORGE
// IS
// A
// <empty>
// <empty>
// <empty>
// DOOD
int Split (const CString& sBuf, TCHAR cDelim, int nLimit = SPLIT_ALL, bool bKeepEmptyToken=true)
{
CString sDelim (cDelim);
return Split (sBuf, sDelim, nLimit, bKeepEmptyToken);
}
int Split (const CString& sBuf, const CString& sDelim, int nLimit = SPLIT_ALL, bool bKeepEmptyToken=true)
{
// if nLimit == 0 then it means that do not split!
// Can't think why someone would want to do this
// but func. must behave predictably!
if (nLimit == 0)
{
AddTail (new CString (sBuf));
return GetCount ();
}
CString sTemp (sBuf);
int nCount = 0;
int posn = sTemp.Find (sDelim);
while (posn != -1)
{
CString *s = new CString (sTemp.Mid (0, posn));
if (!s->IsEmpty() || bKeepEmptyToken)
AddTail (s);
else
delete s;
++nCount;
if ((nLimit != SPLIT_ALL) && (nCount == nLimit))
{
return GetCount ();
}
// chop off the token (from left), & get the remainder of string
sTemp = sTemp.Right (sTemp.GetLength() - sDelim.GetLength () - posn);
posn = sTemp.Find (sDelim);
}
if (!sTemp.IsEmpty () || bKeepEmptyToken)
AddTail (new CString (sTemp));
return GetCount ();
}
int Join (CString& sRetBuf, const TCHAR cDelim, int nLimit = JOIN_ALL, bool bIncludeEmptyToken=true)
{
CString sDelim (cDelim);
return (sRetBuf, sDelim, nLimit, bIncludeEmptyToken);
}
int Join (CString& sRetBuf, const CString& sDelim, int nLimit = JOIN_ALL, bool bIncludeEmptyToken=true)
{
POSITION pos = GetHeadPosition ();
int nCount=0;
while (pos)
{
// if nLimit = 0 then we do nothing!
if ((nLimit != JOIN_ALL) && (nCount == nLimit))
break;
CString *s = GetNext (pos);
if (!s->IsEmpty () || bIncludeEmptyToken)
sRetBuf += *s;
++nCount;
// do not add a delim after LAST element
if (( (nLimit == JOIN_ALL) && (nCount < GetCount()) ) ||
( nCount < nLimit ))
sRetBuf += sDelim;
}
// return the string length!
return sRetBuf.GetLength();
}
// didn't want to complicate things with throwing exceptions here
// so a simple solution is to return an empty string
// then user can check against the func NOSTRING(...);
const CString& operator[](int index)
{
ASSERT (index < GetCount ());
if (index < GetCount ())
{
POSITION pos = FindIndex (index);
if (pos)
return *(GetAt (pos));
}
return m_sEmptyString;
}
bool NOSTRING(const CString& rhs) { return &m_sEmptyString == &rhs; }
private:
CString m_sEmptyString;
};
Put above code in header file and link it with your code.
How to use in another application which is linked with your dll?
CString sRecord;
CMyStringPtrList aStringList( TRUE );
aStringList.Split( sRecord,';');
// trim spaces
for ( int x = 0; x < aStringList.GetCount(); x++ ) {
((CString*)&aStringList[x])->TrimLeft();
((CString*)&aStringList[x])->TrimRight();
}
SetAccount(aStringList[0]);
SetAmmount(aStringList[1]);
No new, no delete!!!