CString源码

CString使用的是引用技术,可以共享数据(这个大家都知道),另外空的CStirng是指向一个固定的地址的(_afxInitData).
另外CStirng是有长度限制的2147483647(无符号int 的最大值).
数据格式
struct CStringData
{
 long nRefs; //引用记数
 int nDataLength; //字符使用长度
 int nAllocLength; //分配长度
 TCHAR* data() { return (TCHAR*)(this+1); } //存放字符串的地方
 //this+1 相当与是CStringData[1];所以TCHAR* data()指的是CStringData[1]的地址
};
基本和网络通讯的数据包差不多
typedef struct tagAnsMarketData //统一的应答结构
{
 WORD wStkNum; //数目
 char iData[1]; //数据
}ANS_MARKET_DATA,*PANS_MARKET_DATA;

下面是代码了
#include <windows.h>
#include <assert.h>
#include <stdlib.h>
#include <malloc.h>
#include <tchar.h>

string.h

#ifndef __JONES__STRING__
#define __JONES__STRING__

struct CStringData
{
 long nRefs; //引用记数
 int nDataLength; //字符使用长度
 int nAllocLength; //分配长度
 TCHAR* data() { return (TCHAR*)(this+1); } //存放字符串的地方
 //this+1 相当与是CStringData[1];所以TCHAR* data()指的是CStringData[1]的地址
};

class CString
{
public:
 //构造函数
 CString();
 CString(const CString& stringSrc);
 CString(TCHAR ch, int nLength =1);
 CString(LPCTSTR lpsz); // CString(LPCSTR lpsz); ANSI下版本
       //CString(LPCWSTR lpsz);UNICODE下版本
 CString(LPCTSTR lpch, int nLength); //CString(LPCSTR lpch, int nLength);ANSI下版本
          //CString(LPCWSTR lpch, int nLength);//UNICODE下版本
 CString(const unsigned char* psz);
 ~CString();
 //CStringData的属性
 int GetLength() const; //得到字符长度
 int GetAllocLength() const; //得到分配的内存长度
 BOOL IsEmpty() const; //判断字符长度是否为0
 operator LPCTSTR() const; //类型转换
 void Empty(); //清空CStringData
 //操作符重载
 const CString& operator=(const CString& stringSrc);
 const CString& operator=(LPCTSTR lpsz);
 const CString& operator=(TCHAR ch);
 const CString& operator+=(const CString& string);
 const CString& operator+=(TCHAR ch);
 const CString& operator+=(LPCTSTR lpsz);
 TCHAR operator[](int nIndex) const;

 friend CString operator+(const CString& string1,const CString& string2);
 friend CString operator+(const CString& string, TCHAR ch);
 friend CString operator+(TCHAR ch, const CString& string);
 friend CString operator+(const CString& string, LPCTSTR lpsz);
 friend CString operator+(LPCTSTR lpsz, const CString& string);

 //操作,脱离共享数据块
 int Delete(int nIndex, int nCount = 1);//删除从nIndex开始长度为nCount的数据
 int Insert(int nIndex, TCHAR ch); //插入一个字符
 int Insert(int nIndex, LPCTSTR pstr); //插入一个字符串
 int Replace(LPCTSTR lpszOld, LPCTSTR lpszNew); //替换数据
 int Replace(TCHAR chOld, TCHAR chNew); //替换数据
 int Remove(TCHAR chRemove); //移除一个字符
 void TrimRight(LPCTSTR lpszTargetList);
 void TrimRight(TCHAR chTarget);//去掉右边chTarget
 void TrimRight(); //去掉右边空格
 void TrimLeft(LPCTSTR lpszTargets);
 void TrimLeft(TCHAR chTarget); //去掉左边chTarget
 void TrimLeft(); //去掉左边空格
 //取某段字符串
 void SetAt(int nIndex, TCHAR ch);
 TCHAR GetAt(int nIndex) const;
 CString Mid(int nFirst) const; //取某段字符串
 CString Mid(int nFirst, int nCount) const; //取某段字符串
 CString Right(int nCount) const; //取右边字符串
 CString Left(int nCount) const; //取左边字符串
 void CString::MakeUpper(); //大写
 void CString::MakeLower(); //小写
 void CString::MakeReverse(); //????不知道干什么的 strrev
 //查找
 int Find(TCHAR ch) const;
 int Find(TCHAR ch, int nStart) const;
 int ReverseFind(TCHAR ch) const;
 int Find(LPCTSTR lpszSub) const;
 int Find(LPCTSTR lpszSub, int nStart) const;
 int FindOneOf(LPCTSTR lpszCharSet) const;//得到第一个匹配lpszCharSet中其中一个字符的位置 调用_tcspbrk
 //高级操作
 LPTSTR GetBuffer(int nMinBufLength); //重新分配内存,在拷贝原来的数据
 void ReleaseBuffer(int nNewLength=-1); //在[nNewLength]='/0',对内存大小没有改变
 LPTSTR GetBufferSetLength(int nNewLength); //重新分配内存,在拷贝原来的数据
 void FreeExtra(); //深拷贝自己,然后--原来的引用记数器
 LPTSTR LockBuffer(); //引用计数器=-1,加锁
 void UnlockBuffer(); //解锁,引用计数器=1
 //比较
 int Compare(LPCTSTR lpsz) const; //区分大小写比较
 int CompareNoCase(LPCTSTR lpsz) const; //不区分大小写比较
 //比较速度没有Compare快
 int Collate(LPCTSTR lpsz) const; //区分大小写比较
 int CollateNoCase(LPCTSTR lpsz) const; //不区分大小写比较
 //格式化字符串
 void Format(LPCTSTR lpszFormat, ...);//CSting中最长的函数了,完全是自己分析的(牛啊)

private:
 void Init();
 CStringData* GetData() const; //通过m_pchData-1 得到CStringData
 void AllocBuffer(int nLen); //给CStringData分配内存,不带记数器
 void CopyBeforeWrite(); //带引用记数的复制自己深拷贝
 void AllocBeforeWrite(int nLen); //给CStringData分配内存,带记数器
 void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData);//分配内存,并拷贝lpszSrcData内容
 //把nCopyIndex开始的nCopyLen长度的数据拷贝给dest,nExtraLen扩充的长度,次函数好像没下面用
 void AllocCopy(CString& dest, int nCopyLen, int nCopyIndex,int nExtraLen) const;
 void Release(); //--引用记数器并判断是否删除内存,如删除并初始化
 void FormatV(LPCTSTR lpszFormat, va_list argList);//格式化字符串
 void ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,
  int nSrc2Len, LPCTSTR lpszSrc2Data);//连接数据lpszSrc1Data+lpszSrc2Data
 void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData); //连接字符串

 static void  Release(CStringData* pData); //--引用记数器并判断是否删除内存
 static void FreeData(CStringData* pData); //释放内存
 static int SafeStrlen(LPCTSTR lpsz); //得到长度
 LPTSTR m_pchData; //指向CStringData的数据区
};

/*调用CString::Compare比较大小,如果比较中有CStirng的话用
调用operator LPCTSTR()转化类型为LPCTSTR
*/
bool operator==(const CString& s1, const CString& s2);
bool operator==(const CString& s1, LPCTSTR s2);
bool operator==(LPCTSTR s1, const CString& s2);
bool operator!=(const CString& s1, const CString& s2);
bool operator!=(const CString& s1, LPCTSTR s2);
bool operator!=(LPCTSTR s1, const CString& s2);
bool operator<(const CString& s1, const CString& s2);
bool operator<(const CString& s1, LPCTSTR s2);
bool operator<(LPCTSTR s1, const CString& s2);
bool operator>(const CString& s1, const CString& s2);
bool operator>(const CString& s1, LPCTSTR s2);
bool operator>(LPCTSTR s1, const CString& s2);
bool operator<=(const CString& s1, const CString& s2);
bool operator<=(const CString& s1, LPCTSTR s2);
bool operator<=(LPCTSTR s1, const CString& s2);
bool operator>=(const CString& s1, const CString& s2);
bool operator>=(const CString& s1, LPCTSTR s2);
bool operator>=(LPCTSTR s1, const CString& s2);

//
//检测lpsz是否有效,调用了IsBadStringPtr
BOOL AfxIsValidString(LPCTSTR lpsz, int nLength = -1);
//检测lp是否能读写权限,调用了IsBadReadPtr,IsBadStringPtr
BOOL AfxIsValidAddress(const void* lp,UINT nBytes, BOOL bReadWrite = TRUE);

//CStirng数组操作
void ConstructElements(CString* pElements, int nCount); //初始化CStirng数组
void DestructElements(CString* pElements, int nCount); //删除CStirng数组
void CopyElements(CString* pDest, const CString* pSrc, int nCount); //CString数组拷贝

#endif

string.cpp

#include "stdafx.h"
#include "string.h"

TCHAR afxChNil = '/0';
int _afxInitData[] = { -1, 0, 0, 0 }; //初始化CStringData的地址
CStringData* _afxDataNil = (CStringData*)&_afxInitData; //地址转化为CStringData*
LPCTSTR _afxPchNil = (LPCTSTR)(((BYTE*)&_afxInitData)+sizeof(CStringData));
const CString&  AfxGetEmptyString()  //建立一个空的CString
{ return *(CString*)&_afxPchNil; }

BOOL AfxIsValidString(LPCTSTR lpsz, int nLength /* = -1 */)
{
 if (lpsz == NULL)
  return FALSE;
 return ::IsBadStringPtr(lpsz, nLength) == 0;
}

BOOL AfxIsValidAddress(const void* lp, UINT nBytes,BOOL bReadWrite /* = TRUE */)
{
 return (lp != NULL && !IsBadReadPtr(lp, nBytes) &&
  (!bReadWrite !IsBadWritePtr((LPVOID)lp, nBytes)));
}

void CString::Init()
{ m_pchData=AfxGetEmptyString().m_pchData; }


CString::CString()
{ Init(); }

int CString::GetLength() const
{ return GetData()->nDataLength; }

int CString::GetAllocLength() const
{ return GetData()->nAllocLength; }

BOOL CString::IsEmpty() const
{ return GetData()->nDataLength == 0; }

CStringData* CString::GetData() const
{
 assert(m_pchData != NULL);
 return ((CStringData*)m_pchData)-1;
}

CString::operator LPCTSTR() const
{ return m_pchData; }

int CString::SafeStrlen(LPCTSTR lpsz)
{ return (lpsz == NULL) ? 0 : lstrlen(lpsz); }

void CString::AllocBuffer(int nLen)
{
 assert(nLen >= 0);
 assert(nLen <= 2147483647-1);    // (signed) int 的最大值

 if (nLen == 0)
  Init();
 else
 {
  CStringData* pData;
  {
   pData = (CStringData*)
    new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)];
   pData->nAllocLength = nLen;
  }
  pData->nRefs = 1;
  pData->data()[nLen] = '/0';
  pData->nDataLength = nLen;
  m_pchData = pData->data();
 }
}

void CString::FreeData(CStringData* pData)
{
 delete[] (BYTE*)pData;
}

void CString::CopyBeforeWrite()
{
 if (GetData()->nRefs > 1)
 {
  CStringData* pData = GetData();
  Release();
  AllocBuffer(pData->nDataLength);
  memcpy(m_pchData, pData->data(), (pData->nDataLength+1)*sizeof(TCHAR));
 }
 assert(GetData()->nRefs <= 1);
}

void CString::AllocBeforeWrite(int nLen)
{
 if (GetData()->nRefs > 1 nLen > GetData()->nAllocLength)
 {
  Release();
  AllocBuffer(nLen);
 }
 assert(GetData()->nRefs <= 1);
}

void CString::AssignCopy(int nSrcLen, LPCTSTR lpszSrcData)
{
 AllocBeforeWrite(nSrcLen);
 memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(TCHAR));
 GetData()->nDataLength = nSrcLen;
 m_pchData[nSrcLen] = '/0';
}

void CString::AllocCopy(CString& dest, int nCopyLen, int nCopyIndex,
  int nExtraLen) const
{
 int nNewLen = nCopyLen + nExtraLen;
 if (nNewLen == 0)
 {
  dest.Init();
 }
 else
 {
  dest.AllocBuffer(nNewLen);
  memcpy(dest.m_pchData, m_pchData+nCopyIndex, nCopyLen*sizeof(TCHAR));
 }
}


CString::~CString()
{
 if (GetData() != _afxDataNil)
 {
  if (InterlockedDecrement(&GetData()->nRefs) <= 0)
   FreeData(GetData());
 }
}


CString::CString(const CString& stringSrc)
{
 assert(stringSrc.GetData()->nRefs != 0);
 if (stringSrc.GetData()->nRefs >= 0)
 {
  assert(stringSrc.GetData() != _afxDataNil);
  m_pchData = stringSrc.m_pchData;
  InterlockedIncrement(&GetData()->nRefs);
 }
 else
 {
  Init();
  *this = stringSrc.m_pchData;
 }
}

CString::CString(LPCTSTR lpsz)
{
 Init();
 int nLen = SafeStrlen(lpsz);
 if (nLen != 0)
 {
  AllocBuffer(nLen);
  memcpy(m_pchData, lpsz, nLen*sizeof(TCHAR));
 }
}

CString::CString(LPCTSTR lpch, int nLength)
{
 Init();
 if (nLength != 0)
 {
  assert(AfxIsValidAddress(lpch, nLength, FALSE));
  AllocBuffer(nLength);
  memcpy(m_pchData, lpch, nLength*sizeof(TCHAR));
 }
}


void CString::Release()
{
 if (GetData() != _afxDataNil)
 {
  assert(GetData()->nRefs != 0);
  if (InterlockedDecrement(&GetData()->nRefs) <= 0)
   FreeData(GetData());
  Init();
 }
}

void CString::Release(CStringData* pData)
{
 if (pData != _afxDataNil)
 {
  assert(pData->nRefs != 0);
  if (InterlockedDecrement(&pData->nRefs) <= 0)
   FreeData(pData);
 }
}

void CString::Empty()
{
 if (GetData()->nDataLength == 0)
  return;
 if (GetData()->nRefs >= 0)
  Release();
 else
  *this = &afxChNil;
 assert(GetData()->nDataLength == 0);
 assert(GetData()->nRefs < 0 GetData()->nAllocLength == 0);
}


const CString& CString::operator=(const CString& stringSrc)
{
 if (m_pchData != stringSrc.m_pchData)
 {
  if ((GetData()->nRefs < 0 && GetData() != _afxDataNil)
   stringSrc.GetData()->nRefs < 0)
  {
   //新建一快数据
   AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
  }
  else
  {
   //只拷贝指针
   Release();
   assert(stringSrc.GetData() != _afxDataNil);
   m_pchData = stringSrc.m_pchData;
   InterlockedIncrement(&GetData()->nRefs);
  }
 }
 return *this;
}

const CString& CString::operator=(LPCTSTR lpsz)
{
 assert(lpsz == NULL AfxIsValidString(lpsz));
 AssignCopy(SafeStrlen(lpsz), lpsz);
 return *this;
}

const CString& CString::operator=(TCHAR ch)
{
 AssignCopy(1, &ch);
 return *this;
}


int CString::Delete(int nIndex, int nCount /* = 1 */)
{
 if (nIndex < 0)
  nIndex = 0;
 int nNewLength = GetData()->nDataLength;
 if (nCount > 0 && nIndex < nNewLength)
 {
  CopyBeforeWrite(); //脱离共享数据块,
  int nBytesToCopy = nNewLength - (nIndex + nCount) + 1;
  //移动数据
  memcpy(m_pchData + nIndex,
   m_pchData + nIndex + nCount, nBytesToCopy * sizeof(TCHAR));
  GetData()->nDataLength = nNewLength - nCount;
 }
 return nNewLength;
}


int CString::Insert(int nIndex, TCHAR ch)
{
 CopyBeforeWrite(); //脱离共享数据

 if (nIndex < 0)
  nIndex = 0;

 int nNewLength = GetData()->nDataLength;
 if (nIndex > nNewLength)
  nIndex = nNewLength;
 nNewLength++;

 if (GetData()->nAllocLength < nNewLength)
 { //动态分配内存,并拷贝原来的数据
  CStringData* pOldData = GetData();
  LPTSTR pstr = m_pchData;
  AllocBuffer(nNewLength);
  memcpy(m_pchData, pstr, (pOldData->nDataLength+1)*sizeof(TCHAR));
  CString::Release(pOldData);
 }
 //插入数据
 memcpy(m_pchData + nIndex + 1,
  m_pchData + nIndex, (nNewLength-nIndex)*sizeof(TCHAR));
 m_pchData[nIndex] = ch;
 GetData()->nDataLength = nNewLength;

 return nNewLength;
}


int CString::Insert(int nIndex, LPCTSTR pstr)
{
 if (nIndex < 0)
  nIndex = 0;

 int nInsertLength = SafeStrlen(pstr);
 int nNewLength = GetData()->nDataLength;
 if (nInsertLength > 0)
 {
  CopyBeforeWrite(); //脱离共享数据
  if (nIndex > nNewLength)
   nIndex = nNewLength;
  nNewLength += nInsertLength;

  if (GetData()->nAllocLength < nNewLength)
  { //动态分配内存,并拷贝原来的数据
   CStringData* pOldData = GetData();
   LPTSTR pstr = m_pchData;
   AllocBuffer(nNewLength);
   memcpy(m_pchData, pstr, (pOldData->nDataLength+1)*sizeof(TCHAR));
   CString::Release(pOldData);
  }

  //移动数据,留出插入的位move也可以
  memcpy(m_pchData + nIndex + nInsertLength,
   m_pchData + nIndex,
   (nNewLength-nIndex-nInsertLength+1)*sizeof(TCHAR));
  //插入数据
  memcpy(m_pchData + nIndex,
   pstr, nInsertLength*sizeof(TCHAR));
  GetData()->nDataLength = nNewLength;
 }

 return nNewLength;
}

int CString::Replace(TCHAR chOld, TCHAR chNew)
{
 int nCount = 0;
 if (chOld != chNew) //替换的不能相同
 {
  CopyBeforeWrite();
  LPTSTR psz = m_pchData;
  LPTSTR pszEnd = psz + GetData()->nDataLength;
  while (psz < pszEnd)
  {
   if (*psz == chOld) //替换
   {
    *psz = chNew;
    nCount++;
   }
   psz = _tcsinc(psz); //相当于++psz,考虑要UNICODE下版本才用的
  }
 }
 return nCount;
}

int CString::Replace(LPCTSTR lpszOld, LPCTSTR lpszNew)
{
 int nSourceLen = SafeStrlen(lpszOld);
 if (nSourceLen == 0) //要替换的不能为空
  return 0;
 int nReplacementLen = SafeStrlen(lpszNew);

 int nCount = 0;
 LPTSTR lpszStart = m_pchData;
 LPTSTR lpszEnd = m_pchData + GetData()->nDataLength;
 LPTSTR lpszTarget;
 while (lpszStart < lpszEnd) //检索要替换的个数
 {
  while ((lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL)
  {
   nCount++;
   lpszStart = lpszTarget + nSourceLen;
  }
  lpszStart += lstrlen(lpszStart) + 1;
 }

 
 if (nCount > 0)
 {
  CopyBeforeWrite();
  int nOldLength = GetData()->nDataLength;
  int nNewLength =  nOldLength + (nReplacementLen-nSourceLen)*nCount; //替换以后的长度
  if (GetData()->nAllocLength < nNewLength GetData()->nRefs > 1)
  { //超出原来的内存长度动态分配
   CStringData* pOldData = GetData();
   LPTSTR pstr = m_pchData;
   AllocBuffer(nNewLength);
   memcpy(m_pchData, pstr, pOldData->nDataLength*sizeof(TCHAR));
   CString::Release(pOldData);
  }
 
  lpszStart = m_pchData;
  lpszEnd = m_pchData + GetData()->nDataLength;

 
  while (lpszStart < lpszEnd) //这个循环好象没什么用
  {
   while ( (lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL) //开始替换
   {
    int nBalance = nOldLength - (lpszTarget - m_pchData + nSourceLen); //要往后移的长度
    //移动数据,留出插入的位
    memmove(lpszTarget + nReplacementLen, lpszTarget + nSourceLen,
     nBalance * sizeof(TCHAR));
    //插入替换数据
    memcpy(lpszTarget, lpszNew, nReplacementLen*sizeof(TCHAR));
    lpszStart = lpszTarget + nReplacementLen;
    lpszStart[nBalance] = '/0';
    nOldLength += (nReplacementLen - nSourceLen); //现有数据长度
   }
   lpszStart += lstrlen(lpszStart) + 1;
  }
  assert(m_pchData[nNewLength] == '/0');
  GetData()->nDataLength = nNewLength;
 }

 return nCount;
}


int CString::Remove(TCHAR chRemove)
{
 CopyBeforeWrite();

 LPTSTR pstrSource = m_pchData;
 LPTSTR pstrDest = m_pchData;
 LPTSTR pstrEnd = m_pchData + GetData()->nDataLength;

 while (pstrSource < pstrEnd)
 {
  if (*pstrSource != chRemove)
  {
   *pstrDest = *pstrSource; //把不移除的数据拷贝
   pstrDest = _tcsinc(pstrDest);
  }
  pstrSource = _tcsinc(pstrSource);//++pstrSource
 }
 *pstrDest = '/0';
 int nCount = pstrSource - pstrDest; //比较变态的计算替换个数,
 GetData()->nDataLength -= nCount;

 return nCount;
}


CString CString::Mid(int nFirst) const
{
 return Mid(nFirst, GetData()->nDataLength - nFirst);
}

CString CString::Mid(int nFirst, int nCount) const
{
 if (nFirst < 0)
  nFirst = 0;
 if (nCount < 0)
  nCount = 0;

 if (nFirst + nCount > GetData()->nDataLength)
  nCount = GetData()->nDataLength - nFirst;
 if (nFirst > GetData()->nDataLength)
  nCount = 0;

 assert(nFirst >= 0);
 assert(nFirst + nCount <= GetData()->nDataLength);

 //取去整个数据
 if (nFirst == 0 && nFirst + nCount == GetData()->nDataLength)
  return *this;
 
 CString dest;
 AllocCopy(dest, nCount, nFirst, 0);
 return dest;
}


CString CString::Right(int nCount) const
{
 if (nCount < 0)
  nCount = 0;
 if (nCount >= GetData()->nDataLength)
  return *this;

 CString dest;
 AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);
 return dest;
}

CString CString::Left(int nCount) const
{
 if (nCount < 0)
  nCount = 0;
 if (nCount >= GetData()->nDataLength)
  return *this;

 CString dest;
 AllocCopy(dest, nCount, 0, 0);
 return dest;
}


int CString::ReverseFind(TCHAR ch) const
{
 //从最后查找
 LPTSTR lpsz = _tcsrchr(m_pchData, (_TUCHAR) ch);
 return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
}

int CString::Find(TCHAR ch) const
{
 return Find(ch, 0);
}

int CString::Find(TCHAR ch, int nStart) const
{
 int nLength = GetData()->nDataLength;
 if (nStart >= nLength)
  return -1;

 LPTSTR lpsz = _tcschr(m_pchData + nStart, (_TUCHAR)ch);
 return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
}

int CString::Find(LPCTSTR lpszSub) const
{
 return Find(lpszSub, 0);
}

int CString::Find(LPCTSTR lpszSub, int nStart) const
{
 assert(AfxIsValidString(lpszSub));

 int nLength = GetData()->nDataLength;
 if (nStart > nLength)
  return -1;

 LPTSTR lpsz = _tcsstr(m_pchData + nStart, lpszSub);

 return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
}

int CString::FindOneOf(LPCTSTR lpszCharSet) const
{
 assert(AfxIsValidString(lpszCharSet));
 LPTSTR lpsz = _tcspbrk(m_pchData, lpszCharSet);
 return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
}

void CString::MakeUpper()
{
 CopyBeforeWrite();
 _tcsupr(m_pchData);
}

void CString::MakeLower()
{
 CopyBeforeWrite();
 _tcslwr(m_pchData);
}

void CString::MakeReverse()
{
 CopyBeforeWrite();
 _tcsrev(m_pchData);
}

void CString::SetAt(int nIndex, TCHAR ch)
{
 assert(nIndex >= 0);
 assert(nIndex < GetData()->nDataLength);

 CopyBeforeWrite();
 m_pchData[nIndex] = ch;
}

void CString::TrimRight(LPCTSTR lpszTargetList)
{
 CopyBeforeWrite();
 LPTSTR lpsz = m_pchData;
 LPTSTR lpszLast = NULL;

 while (*lpsz != '/0')
 {
  if (_tcschr(lpszTargetList, *lpsz) != NULL)
  {
   if (lpszLast == NULL)
    lpszLast = lpsz;
  }
  else
   lpszLast = NULL;
  lpsz = _tcsinc(lpsz);
 }

 if (lpszLast != NULL)
 {
  *lpszLast = '/0';
  GetData()->nDataLength = lpszLast - m_pchData;
 }
}

void CString::TrimRight(TCHAR chTarget)
{
 CopyBeforeWrite();
 LPTSTR lpsz = m_pchData;
 LPTSTR lpszLast = NULL;

 while (*lpsz != '/0')
 {
  if (*lpsz == chTarget)
  {
   if (lpszLast == NULL)
    lpszLast = lpsz;
  }
  else
   lpszLast = NULL;
  lpsz = _tcsinc(lpsz);
 }

 if (lpszLast != NULL)
 {
  *lpszLast = '/0';
  GetData()->nDataLength = lpszLast - m_pchData;
 }
}

void CString::TrimRight()
{
 CopyBeforeWrite();
 LPTSTR lpsz = m_pchData;
 LPTSTR lpszLast = NULL;

 while (*lpsz != '/0')
 {
  if (_istspace(*lpsz))
  {
   if (lpszLast == NULL)
    lpszLast = lpsz;
  }
  else
   lpszLast = NULL;
  lpsz = _tcsinc(lpsz);
 }

 if (lpszLast != NULL)
 {
  // truncate at trailing space start
  *lpszLast = '/0';
  GetData()->nDataLength = lpszLast - m_pchData;
 }
}

void CString::TrimLeft(LPCTSTR lpszTargets)
{
 // if we're not trimming anything, we're not doing any work
 if (SafeStrlen(lpszTargets) == 0)
  return;

 CopyBeforeWrite();
 LPCTSTR lpsz = m_pchData;

 while (*lpsz != '/0')
 {
  if (_tcschr(lpszTargets, *lpsz) == NULL)
   break;
  lpsz = _tcsinc(lpsz);
 }

 if (lpsz != m_pchData)
 {
  // fix up data and length
  int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
  memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
  GetData()->nDataLength = nDataLength;
 }
}

void CString::TrimLeft(TCHAR chTarget)
{
 CopyBeforeWrite();
 LPCTSTR lpsz = m_pchData;

 while (chTarget == *lpsz)
  lpsz = _tcsinc(lpsz);

 if (lpsz != m_pchData)
 {
  int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
  memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
  GetData()->nDataLength = nDataLength;
 }
}

void CString::TrimLeft()
{
 CopyBeforeWrite();
 LPCTSTR lpsz = m_pchData;

 while (_istspace(*lpsz))
  lpsz = _tcsinc(lpsz);

 if (lpsz != m_pchData)
 {
  int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
  memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
  GetData()->nDataLength = nDataLength;
 }
}

#define TCHAR_ARG   TCHAR
#define WCHAR_ARG   WCHAR
#define CHAR_ARG    char

struct _AFX_DOUBLE  { BYTE doubleBits[sizeof(double)]; };

#ifdef _X86_
 #define DOUBLE_ARG  _AFX_DOUBLE
#else
 #define DOUBLE_ARG  double
#endif

#define FORCE_ANSI      0x10000
#define FORCE_UNICODE   0x20000
#define FORCE_INT64     0x40000

void CString::FormatV(LPCTSTR lpszFormat, va_list argList)
{
 assert(AfxIsValidString(lpszFormat));

 va_list argListSave = argList;

 // make a guess at the maximum length of the resulting string
 int nMaxLen = 0;
 for (LPCTSTR lpsz = lpszFormat; *lpsz != '/0'; lpsz = _tcsinc(lpsz))
 {
  //查找%,对%%不在查找范围
  if (*lpsz != '%' *(lpsz = _tcsinc(lpsz)) == '%')
  {
   nMaxLen += _tclen(lpsz);
   continue;
  }

  int nItemLen = 0;

  //%后面的格式判断
  int nWidth = 0;
  for (; *lpsz != '/0'; lpsz = _tcsinc(lpsz))
  {
   if (*lpsz == '#')
    nMaxLen += 2;   // 16进制 '0x'
   else if (*lpsz == '*')
    nWidth = va_arg(argList, int);
   else if (*lpsz == '-' *lpsz == '+' *lpsz == '0'
    *lpsz == ' ')
    ;
   else // hit non-flag character
    break;
  }
  // get width and skip it
  if (nWidth == 0)
  {
   // width indicated by
   nWidth = _ttoi(lpsz);
   for (; *lpsz != '/0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
    ;
  }
  assert(nWidth >= 0);

  int nPrecision = 0;
  if (*lpsz == '.')
  {
   // skip past '.' separator (width.precision)
   lpsz = _tcsinc(lpsz);

   // get precision and skip it
   if (*lpsz == '*')
   {
    nPrecision = va_arg(argList, int);
    lpsz = _tcsinc(lpsz);
   }
   else
   {
    nPrecision = _ttoi(lpsz);
    for (; *lpsz != '/0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
     ;
   }
   assert(nPrecision >= 0);
  }

  // should be on type modifier or specifier
  int nModifier = 0;
  if (_tcsncmp(lpsz, _T("I64"), 3) == 0)
  {
   lpsz += 3;
   nModifier = FORCE_INT64;
#if !defined(_X86_) && !defined(_ALPHA_)
   // __int64 is only available on X86 and ALPHA platforms
   ASSERT(FALSE);
#endif
  }
  else
  {
   switch (*lpsz)
   {
   // modifiers that affect size
   case 'h':
    nModifier = FORCE_ANSI;
    lpsz = _tcsinc(lpsz);
    break;
   case 'l':
    nModifier = FORCE_UNICODE;
    lpsz = _tcsinc(lpsz);
    break;

   // modifiers that do not affect size
   case 'F':
   case 'N':
   case 'L':
    lpsz = _tcsinc(lpsz);
    break;
   }
  }

  // now should be on specifier
  switch (*lpsz | nModifier)
  {
  // single characters
  case 'c':
  case 'C':
   nItemLen = 2;
   va_arg(argList, TCHAR_ARG);
   break;
  case 'c'|FORCE_ANSI:
  case 'C'|FORCE_ANSI:
   nItemLen = 2;
   va_arg(argList, CHAR_ARG);
   break;
  case 'c'|FORCE_UNICODE:
  case 'C'|FORCE_UNICODE:
   nItemLen = 2;
   va_arg(argList, WCHAR_ARG);
   break;

  // strings
  case 's':
   {
    LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);
    if (pstrNextArg == NULL)
       nItemLen = 6;  // "(null)"
    else
    {
       nItemLen = lstrlen(pstrNextArg);
       nItemLen = max(1, nItemLen);
    }
   }
   break;

  case 'S':
   {
#ifndef _UNICODE
    LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
    if (pstrNextArg == NULL)
       nItemLen = 6;  // "(null)"
    else
    {
       nItemLen = wcslen(pstrNextArg);
       nItemLen = max(1, nItemLen);
    }
#else
    LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
    if (pstrNextArg == NULL)
       nItemLen = 6; // "(null)"
    else
    {
       nItemLen = lstrlenA(pstrNextArg);
       nItemLen = max(1, nItemLen);
    }
#endif
   }
   break;

  case 's'|FORCE_ANSI:
  case 'S'|FORCE_ANSI:
   {
    LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
    if (pstrNextArg == NULL)
       nItemLen = 6; // "(null)"
    else
    {
       nItemLen = lstrlenA(pstrNextArg);
       nItemLen = max(1, nItemLen);
    }
   }
   break;

  case 's'|FORCE_UNICODE:
  case 'S'|FORCE_UNICODE:
   {
    LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
    if (pstrNextArg == NULL)
       nItemLen = 6; // "(null)"
    else
    {
       nItemLen = wcslen(pstrNextArg);
       nItemLen = max(1, nItemLen);
    }
   }
   break;
  }

  // adjust nItemLen for strings
  if (nItemLen != 0)
  {
   if (nPrecision != 0)
    nItemLen = min(nItemLen, nPrecision);
   nItemLen = max(nItemLen, nWidth);
  }
  else
  {
   switch (*lpsz)
   {
   // integers
   case 'd':
   case 'i':
   case 'u':
   case 'x':
   case 'X':
   case 'o':
    if (nModifier & FORCE_INT64)
     va_arg(argList, __int64);
    else
     va_arg(argList, int);
    nItemLen = 32;
    nItemLen = max(nItemLen, nWidth+nPrecision);
    break;

   case 'e':
   case 'g':
   case 'G':
    va_arg(argList, DOUBLE_ARG);
    nItemLen = 128;
    nItemLen = max(nItemLen, nWidth+nPrecision);
    break;

   case 'f':
    {
     double f;
     LPTSTR pszTemp;

     // 312 == strlen("-1+(309 zeroes).")
     // 309 zeroes == max precision of a double
     // 6 == adjustment in case precision is not specified,
     //   which means that the precision defaults to 6
     pszTemp = (LPTSTR)_alloca(max(nWidth, 312+nPrecision+6));

     f = va_arg(argList, double);
     _stprintf( pszTemp, _T( "%*.*f" ), nWidth, nPrecision+6, f );
     nItemLen = _tcslen(pszTemp);
    }
    break;

   case 'p':
    va_arg(argList, void*);
    nItemLen = 32;
    nItemLen = max(nItemLen, nWidth+nPrecision);
    break;

   // no output
   case 'n':
    va_arg(argList, int*);
    break;

   default:
    assert(FALSE);  // unknown formatting option
   }
  }

  // adjust nMaxLen for output nItemLen
  nMaxLen += nItemLen;
 }

 GetBuffer(nMaxLen);
 //VERIFY(_vstprintf(m_pchData, lpszFormat, argListSave) <= GetAllocLength());
 _vstprintf(m_pchData, lpszFormat, argListSave);
 ReleaseBuffer();

 va_end(argListSave);
}

void CString::Format(LPCTSTR lpszFormat, ...)
{
 assert(AfxIsValidString(lpszFormat));

 va_list argList;
 va_start(argList, lpszFormat);
 FormatV(lpszFormat, argList);
 va_end(argList);
}

void CString::ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,int nSrc2Len, LPCTSTR lpszSrc2Data)
{
 int nNewLen = nSrc1Len + nSrc2Len;
 if (nNewLen != 0)
 {
  AllocBuffer(nNewLen);
  memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(TCHAR));
  memcpy(m_pchData+nSrc1Len, lpszSrc2Data, nSrc2Len*sizeof(TCHAR));
 }
}

void CString::ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)
{
 if (nSrcLen == 0)
  return;
 
 if (GetData()->nRefs > 1 GetData()->nDataLength + nSrcLen > GetData()->nAllocLength)
 {//动态分配
  CStringData* pOldData = GetData();
  ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData);
  assert(pOldData != NULL);
  CString::Release(pOldData);
 }
 else
 {//直接往后添加
  memcpy(m_pchData+GetData()->nDataLength, lpszSrcData, nSrcLen*sizeof(TCHAR));
  GetData()->nDataLength += nSrcLen;
  assert(GetData()->nDataLength <= GetData()->nAllocLength);
  m_pchData[GetData()->nDataLength] = '/0';
 }
}

const CString& CString::operator+=(LPCTSTR lpsz)
{
 assert(lpsz == NULL AfxIsValidString(lpsz));
 ConcatInPlace(SafeStrlen(lpsz), lpsz);
 return *this;
}

const CString& CString::operator+=(TCHAR ch)
{
 ConcatInPlace(1, &ch);
 return *this;
}

const CString& CString::operator+=(const CString& string)
{
 ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
 return *this;
}


LPTSTR CString::GetBuffer(int nMinBufLength)
{
 assert(nMinBufLength >= 0);
 if (GetData()->nRefs > 1 nMinBufLength > GetData()->nAllocLength)
 { //重新动态分配
  CStringData* pOldData = GetData();
  int nOldLen = GetData()->nDataLength;   // AllocBuffer will tromp it
  if (nMinBufLength < nOldLen)
   nMinBufLength = nOldLen;
  AllocBuffer(nMinBufLength);
  memcpy(m_pchData, pOldData->data(), (nOldLen+1)*sizeof(TCHAR));
  GetData()->nDataLength = nOldLen;
  CString::Release(pOldData);
 }
 assert(GetData()->nRefs <= 1);
 assert(m_pchData != NULL);
 return m_pchData;
}

void CString::ReleaseBuffer(int nNewLength)
{
 CopyBeforeWrite();  //脱离共享数据块,

 if (nNewLength == -1)
  nNewLength = lstrlen(m_pchData); // zero terminated

 assert(nNewLength <= GetData()->nAllocLength);
 GetData()->nDataLength = nNewLength;
 m_pchData[nNewLength] = '/0';
}

LPTSTR CString::GetBufferSetLength(int nNewLength)
{
 assert(nNewLength >= 0);

 GetBuffer(nNewLength);
 GetData()->nDataLength = nNewLength;
 m_pchData[nNewLength] = '/0';
 return m_pchData;
}

void CString::FreeExtra()
{
 assert(GetData()->nDataLength <= GetData()->nAllocLength);
 if (GetData()->nDataLength != GetData()->nAllocLength)
 {
  CStringData* pOldData = GetData();
  AllocBuffer(GetData()->nDataLength);
  memcpy(m_pchData, pOldData->data(), pOldData->nDataLength*sizeof(TCHAR));
  assert(m_pchData[GetData()->nDataLength] == '/0');
  CString::Release(pOldData);
 }
 assert(GetData() != NULL);
}

LPTSTR CString::LockBuffer()
{
 LPTSTR lpsz = GetBuffer(0);
 GetData()->nRefs = -1;
 return lpsz;
}

void CString::UnlockBuffer()
{
 assert(GetData()->nRefs == -1);
 if (GetData() != _afxDataNil)
  GetData()->nRefs = 1;
}


int CString::Compare(LPCTSTR lpsz) const
{
 assert(AfxIsValidString(lpsz));
 return _tcscmp(m_pchData, lpsz);
}

int CString::CompareNoCase(LPCTSTR lpsz) const
{
 assert(AfxIsValidString(lpsz));
 return _tcsicmp(m_pchData, lpsz);
}
 
// CString::Collate is often slower than Compare but is MBSC/Unicode
//  aware as well as locale-sensitive with respect to sort order.
int CString::Collate(LPCTSTR lpsz) const
{
 assert(AfxIsValidString(lpsz));
 return _tcscoll(m_pchData, lpsz);


int CString::CollateNoCase(LPCTSTR lpsz) const
{
 assert(AfxIsValidString(lpsz));
 return _tcsicoll(m_pchData, lpsz);


TCHAR CString::GetAt(int nIndex) const
{
 assert(nIndex >= 0);
 assert(nIndex < GetData()->nDataLength);
 return m_pchData[nIndex];
}


TCHAR CString::operator[](int nIndex) const
{
 assert(nIndex >= 0);
 assert(nIndex < GetData()->nDataLength);
 return m_pchData[nIndex];
}


CString operator+(const CString& string1, const CString& string2)
{
 CString s;
 s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData,
  string2.GetData()->nDataLength, string2.m_pchData);
 return s;
}

CString operator+(const CString& string, LPCTSTR lpsz)
{
 assert(lpsz == NULL AfxIsValidString(lpsz));
 CString s;
 s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData,
  CString::SafeStrlen(lpsz), lpsz);
 return s;
}

CString operator+(LPCTSTR lpsz, const CString& string)
{
 assert(lpsz == NULL AfxIsValidString(lpsz));
 CString s;
 s.ConcatCopy(CString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength,
  string.m_pchData);
 return s;
}

bool operator==(const CString& s1, const CString& s2)
{ return s1.Compare(s2) == 0; }

bool operator==(const CString& s1, LPCTSTR s2)
{ return s1.Compare(s2) == 0; }

bool operator==(LPCTSTR s1, const CString& s2)
{ return s2.Compare(s1) == 0; }

bool operator!=(const CString& s1, const CString& s2)
{ return s1.Compare(s2) != 0; }

bool operator!=(const CString& s1, LPCTSTR s2)
{ return s1.Compare(s2) != 0; }

bool operator!=(LPCTSTR s1, const CString& s2)
{ return s2.Compare(s1) != 0; }

bool operator<(const CString& s1, const CString& s2)
{ return s1.Compare(s2) < 0; }

bool operator<(const CString& s1, LPCTSTR s2)
{ return s1.Compare(s2) < 0; }

bool operator<(LPCTSTR s1, const CString& s2)
{ return s2.Compare(s1) > 0; }

bool operator>(const CString& s1, const CString& s2)
{ return s1.Compare(s2) > 0; }

bool operator>(const CString& s1, LPCTSTR s2)
{ return s1.Compare(s2) > 0; }

bool operator>(LPCTSTR s1, const CString& s2)
{ return s2.Compare(s1) < 0; }

bool operator<=(const CString& s1, const CString& s2)
{ return s1.Compare(s2) <= 0; }

bool operator<=(const CString& s1, LPCTSTR s2)
{ return s1.Compare(s2) <= 0; }

bool operator<=(LPCTSTR s1, const CString& s2)
{ return s2.Compare(s1) >= 0; }

bool operator>=(const CString& s1, const CString& s2)
{ return s1.Compare(s2) >= 0; }

bool operator>=(const CString& s1, LPCTSTR s2)
{ return s1.Compare(s2) >= 0; }

bool operator>=(LPCTSTR s1, const CString& s2)
{ return s2.Compare(s1) <= 0; }

void ConstructElements(CString* pElements, int nCount)
{
 assert(nCount == 0
  AfxIsValidAddress(pElements, nCount * sizeof(CString)));

 for (; nCount--; ++pElements)
  memcpy(pElements, &AfxGetEmptyString(), sizeof(*pElements));
}


void DestructElements(CString* pElements, int nCount)
{
 assert(nCount == 0
  AfxIsValidAddress(pElements, nCount * sizeof(CString)));

 for (; nCount--; ++pElements)
  pElements->~CString();
}

 

void CopyElements(CString* pDest, const CString* pSrc, int nCount)
{
 assert(nCount == 0
  AfxIsValidAddress(pDest, nCount * sizeof(CString)));
 assert(nCount == 0
  AfxIsValidAddress(pSrc, nCount * sizeof(CString)));

 for (; nCount--; ++pDest, ++pSrc)
  *pDest = *pSrc;
}

 网上也有个CString相关的类,叫CStringEx,大家也可以参考该类的写法。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
// ============================================================================= // FILE: StdString.h // AUTHOR: Joe O'Leary (with outside help noted in comments) // // If you find any bugs in this code, please let me know: // // [email protected] // http://www.joeo.net/stdstring.htm (a bit outdated) // // The latest version of this code should always be available at the // following link: // // http://www.joeo.net/code/StdString.zip (Dec 6, 2003) // // // REMARKS: // This header file declares the CStdStr template. This template derives // the Standard C++ Library basic_string<> template and add to it the // the following conveniences: // - The full MFC CString set of functions (including implicit cast) // - writing to/reading from COM IStream interfaces // - Functional objects for use in STL algorithms // // From this template, we intstantiate two classes: CStdStringA and // CStdStringW. The name "CStdString" is just a #define of one of these, // based upone the UNICODE macro setting // // This header also declares our own version of the MFC/ATL UNICODE-MBCS // conversion macros. Our version looks exactly like the Microsoft's to // facilitate portability. // // NOTE: // If you you use this in an MFC or ATL build, you should include either // afx.h or atlbase.h first, as appropriate. // // PEOPLE WHO HAVE CONTRIBUTED TO THIS CLASS: // // Several people have helped me iron out problems and othewise improve // this class. OK, this is a long list but in my own defense, this code // has undergone two major rewrites. Many of the improvements became // necessary after I rewrote the code as a template. Others helped me // improve the CString facade. // // Anyway, these people are (in chronological order): // // - Pete the Plumber (???) // - Julian Selman // - Chris (of Melbsys) // - Dave Plummer // - John C Sipos // - Chris Sells // - Nigel Nunn // - Fan Xia // - Matthew Williams // - Carl Engman // - Mark Zeren // - Craig Watson // - Rich Zuris // - Karim Ratib // - Chris Conti // - Baptiste Lepilleur // - Greg Pickles // - Jim Cline // - Jeff Kohn // - Todd Heckel // - Ullrich Poll?hne // - Joe Vitaterna // - Joe Woodbury // - Aaron (no last name) // - Joldakowski (???) // - Scott Hathaway // - Eric Nitzche // - Pablo Presedo // - Farrokh Nejadlotfi // - Jason Mills // - Igor Kholodov // - Mike Crusader // - John James // - Wang Haifeng // - Tim Dowty // - Arnt Witteveen // - Glen Maynard // - Paul DeMarco // - Bagira (full name?) // - Ronny Schulz // - Jakko Van Hunen // - Charles Godwin // - Henk Demper // - Greg Marr // - Bill Carducci // - Brian Groose // - MKingman // - Don Beusee // // REVISION HISTORY // // 2005-JAN-10 - Thanks to Don Beusee for pointing out the danger in mapping // length-checked formatting functions to non-length-checked // CRT equivalents. Also thanks to him for motivating me to // optimize my implementation of Replace() // // 2004-APR-22 - A big, big thank you to "MKingman" (whoever you are) for // finally spotting a silly little error in StdCodeCvt that // has been causing me (and users of CStdString) problems for // years in some relatively rare conversions. I had reversed // two length arguments. // // 2003-NOV-24 - Thanks to a bunch of people for helping me clean up many // compiler warnings (and yes, even a couple of actual compiler // errors). These include Henk Demper for figuring out how // to make the Intellisense work on with CStdString on VC6, // something I was never able to do. Greg Marr pointed out // a compiler warning about an unreferenced symbol and a // problem with my version of Load in MFC builds. Bill // Carducci took a lot of time with me to help me figure out // why some implementations of the Standard C++ Library were // returning error codes for apparently successful conversions // between ASCII and UNICODE. Finally thanks to Brian Groose // for helping me fix compiler signed unsigned warnings in // several functions. // // 2003-JUL-10 - Thanks to Charles Godwin for making me realize my 'FmtArg' // fixes had inadvertently broken the DLL-export code (which is // normally commented out. I had to move it up higher. Also // this helped me catch a bug in ssicoll that would prevent // compilation, otherwise. // // 2003-MAR-14 - Thanks to Jakko Van Hunen for pointing out a copy-and-paste // bug in one of the overloads of FmtArg. // // 2003-MAR-10 - Thanks to Ronny Schulz for (twice!) sending me some changes // to help CStdString build on SGI and for pointing out an // error in placement of my preprocessor macros for ssfmtmsg. // // 2002-NOV-26 - Thanks to Bagira for pointing out that my implementation of // SpanExcluding was not properly handling the case in which // the string did NOT contain any of the given characters // // 2002-OCT-21 - Many thanks to Paul DeMarco who was invaluable in helping me // get this code working with Borland's free compiler as well // as the Dev-C++ compiler (available free at SourceForge). // // 2002-SEP-13 - Thanks to Glen Maynard who helped me get rid of some loud // but harmless warnings that were showing up on g++. Glen // also pointed out that some pre-declarations of FmtArg<> // specializations were unnecessary (and no good on G++) // // 2002-JUN-26 - Thanks to Arnt Witteveen for pointing out that I was using // static_cast<> in a place in which I should have been using // reinterpret_cast<> (the ctor for unsigned char strings). // That's what happens when I don't unit-test properly! // Arnt also noticed that CString was silently correcting the // 'nCount' argument to Left() and Right() where CStdString was // not (and crashing if it was bad). That is also now fixed! // // 2002-FEB-25 - Thanks to Tim Dowty for pointing out (and giving me the fix // for) a conversion problem with non-ASCII MBCS characters. // CStdString is now used in my favorite commercial MP3 player! // // 2001-DEC-06 - Thanks to Wang Haifeng for spotting a problem in one of the // assignment operators (for _bstr_t) that would cause compiler // errors when refcounting protection was turned off. // // 2001-NOV-27 - Remove calls to operator!= which involve reverse_iterators // due to a conflict with the rel_ops operator!=. Thanks to // John James for pointing this out. // // 2001-OCT-29 - Added a minor range checking fix for the Mid function to // make it as forgiving as CString's version is. Thanks to // Igor Kholodov for noticing this. // - Added a specialization of std::swap for CStdString. Thanks // to Mike Crusader for suggesting this! It's commented out // because you're not supposed to inject your own code into the // 'std' namespace. But if you don't care about that, it's // there if you want it // - Thanks to Jason Mills for catching a case where CString was // more forgiving in the Delete() function than I was. // // 2001-JUN-06 - I was violating the Standard name lookup rules stated // in [14.6.2(3)]. None of the compilers I've tried so // far apparently caught this but HP-UX aCC 3.30 did. The // fix was to add 'this->' prefixes in many places. // Thanks to Farrokh Nejadlotfi for this! // // 2001-APR-27 - StreamLoad was calculating the number of BYTES in one // case, not characters. Thanks to Pablo Presedo for this. // // 2001-FEB-23 - Replace() had a bug which caused infinite loops if the // source string was empty. Fixed thanks to Eric Nitzsche. // // 2001-FEB-23 - Scott Hathaway was a huge help in providing me with the // ability to build CStdString on Sun Unix systems. He // sent me detailed build reports about what works and what // does not. If CStdString compiles on your Unix box, you // can thank Scott for it. // // 2000-DEC-29 - Joldakowski noticed one overload of Insert failed to do a // range check as CString's does. Now fixed -- thanks! // // 2000-NOV-07 - Aaron pointed out that I was calling static member // functions of char_traits via a temporary. This was not // technically wrong, but it was unnecessary and caused // problems for poor old buggy VC5. Thanks Aaron! // // 2000-JUL-11 - Joe Woodbury noted that the CString::Find docs don't match // what the CString::Find code really ends up doing. I was // trying to match the docs. Now I match the CString code // - Joe also caught me truncating strings for GetBuffer() calls // when the supplied length was less than the current length. // // 2000-MAY-25 - Better support for STLPORT's Standard library distribution // - Got rid of the NSP macro - it interfered with Koenig lookup // - Thanks to Joe Woodbury for catching a TrimLeft() bug that // I introduced in January. Empty strings were not getting // trimmed // // 2000-APR-17 - Thanks to Joe Vitaterna for pointing out that ReverseFind // is supposed to be a const function. // // 2000-MAR-07 - Thanks to Ullrich Poll?hne for catching a range bug in one // of the overloads of assign. // // 2000-FEB-01 - You can now use CStdString on the Mac with CodeWarrior! // Thanks to Todd Heckel for helping out with this. // // 2000-JAN-23 - Thanks to Jim Cline for pointing out how I could make the // Trim() function more efficient. // - Thanks to Jeff Kohn for prompting me to find and fix a typo // in one of the addition operators that takes _bstr_t. // - Got rid of the .CPP file - you only need StdString.h now! // // 1999-DEC-22 - Thanks to Greg Pickles for helping me identify a problem // with my implementation of CStdString::FormatV in which // resulting string might not be properly NULL terminated. // // 1999-DEC-06 - Chris Conti pointed yet another basic_string<> assignment // bug that MS has not fixed. CStdString did nothing to fix // it either but it does now! The bug was: create a string // longer than 31 characters, get a pointer to it (via c_str()) // and then assign that pointer to the original string object. // The resulting string would be empty. Not with CStdString! // // 1999-OCT-06 - BufferSet was erasing the string even when it was merely // supposed to shrink it. Fixed. Thanks to Chris Conti. // - Some of the Q172398 fixes were not checking for assignment- // to-self. Fixed. Thanks to Baptiste Lepilleur. // // 1999-AUG-20 - Improved Load() function to be more efficient by using // SizeOfResource(). Thanks to Rich Zuris for this. // - Corrected resource ID constructor, again thanks to Rich. // - Fixed a bug that occurred with UNICODE characters above // the first 255 ANSI ones. Thanks to Craig Watson. // - Added missing overloads of TrimLeft() and TrimRight(). // Thanks to Karim Ratib for pointing them out // // 1999-JUL-21 - Made all calls to GetBuf() with no args check length first. // // 1999-JUL-10 - Improved MFC/ATL independence of conversion macros // - Added SS_NO_REFCOUNT macro to allow you to disable any // reference-counting your basic_string<> impl. may do. // - Improved ReleaseBuffer() to be as forgiving as CString. // Thanks for Fan Xia for helping me find this and to // Matthew Williams for pointing it out directly. // // 1999-JUL-06 - Thanks to Nigel Nunn for catching a very sneaky bug in // ToLower/ToUpper. They should call GetBuf() instead of // data() in order to ensure the changed string buffer is not // reference-counted (in those implementations that refcount). // // 1999-JUL-01 - Added a true CString facade. Now you can use CStdString as // a drop-in replacement for CString. If you find this useful, // you can thank Chris Sells for finally convincing me to give // in and implement it. // - Changed operators << and >> (for MFC CArchive) to serialize // EXACTLY as CString's do. So now you can send a CString out // to a CArchive and later read it in as a CStdString. I have // no idea why you would want to do this but you can. // // 1999-JUN-21 - Changed the CStdString class into the CStdStr template. // - Fixed FormatV() to correctly decrement the loop counter. // This was harmless bug but a bug nevertheless. Thanks to // Chris (of Melbsys) for pointing it out // - Changed Format() to try a normal stack-based array before // using to _alloca(). // - Updated the text conversion macros to properly use code // pages and to fit in better in MFC/ATL builds. In other // words, I copied Microsoft's conversion stuff again. // - Added equivalents of CString::GetBuffer, GetBufferSetLength // - new sscpy() replacement of CStdString::CopyString() // - a Trim() function that combines TrimRight() and TrimLeft(). // // 1999-MAR-13 - Corrected the "NotSpace" functional object to use _istpace() // instead of _isspace() Thanks to Dave Plummer for this. // // 1999-FEB-26 - Removed errant line (left over from testing) that #defined // _MFC_VER. Thanks to John C Sipos for noticing this. // // 1999-FEB-03 - Fixed a bug in a rarely-used overload of operator+() that // caused infinite recursion and stack overflow // - Added member functions to simplify the process of // persisting CStdStrings to/from DCOM IStream interfaces // - Added functional objects (e.g. StdStringLessNoCase) that // allow CStdStrings to be used as keys STL map objects with // case-insensitive comparison // - Added array indexing operators (i.e. operator[]). I // originally assumed that these were unnecessary and would be // inherited from basic_string. However, without them, Visual // C++ complains about ambiguous overloads when you try to use // them. Thanks to Julian Selman to pointing this out. // // 1998-FEB-?? - Added overloads of assign() function to completely account // for Q172398 bug. Thanks to "Pete the Plumber" for this // // 1998-FEB-?? - Initial submission // // COPYRIGHT: // 2002 Joseph M. O'Leary. This code is 100% free. Use it anywhere you // want. Rewrite it, restructure it, whatever. If you can write software // that makes money off of it, good for you. I kinda like capitalism. // Please don't blame me if it causes your $30 billion dollar satellite // explode in orbit. If you redistribute it in any form, I'd appreciate it // if you would leave this notice here. // ============

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值