📄 basicstr.h
字号:
/*******************************************************************************
*
* (C) COPYRIGHT MICROSOFT CORPORATION, 1998
*
* Copyright (c) 2003 Microsoft Corporation. All Rights Reserved.
*
* DESCRIPTION: Simple string classes
*
*******************************************************************************/
#ifndef _SIMSTR_H_INCLUDED
#define _SIMSTR_H_INCLUDED
/*
* Simple string class.
*
* Template class:
* CBasicStringBase<CharType>
* Implementations:
* CBasicStringBase<wchar_t> CBasicStringWide
* CBasicStringBase<char> CBasicStringAnsi
* CBasicString = CBasicString[Ansi|Wide] depending on UNICODE macro
* Inline functions:
* CBasicStringAnsi CBasicStringConvert::AnsiString(CharType n)
* CBasicStringWide CBasicStringConvert::WideString(CharType n)
* Macros:
* IS_CHAR(CharType)
* IS_WCHAR(CharType)
*/
#include <windows.h>
#include <stdarg.h>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>
//
// Disable the "conditional expression is constant" warning that is caused by
// the IS_CHAR and IS_WCHAR macros
//
#pragma warning( push )
#pragma warning( disable : 4127 )
#define IS_CHAR(x) (sizeof(x) & sizeof(char))
#define IS_WCHAR(x) (sizeof(x) & sizeof(wchar_t))
#ifndef ARRAYSIZE
#define ARRAYSIZE(x) (sizeof(x) / sizeof(x[0]))
#endif
template <class CharType>
class CBasicStringBase
{
private:
enum
{
c_nDefaultGranularity = 16, // Default number of extra characters to allocate when we have to grow
c_nInitialLoadStringBuffer = 1024, // Initial length of .RC string
c_nMaxAutoDataLength = 128 // Length of non-dynamically allocated string
};
private:
//
// If the string is less than c_nMaxAutoDataLength characters, it will be
// stored here, instead of in a dynamically allocated buffer
//
CharType m_pstrAutoData[c_nMaxAutoDataLength];
//
// If we have to allocate data, it will be stored here
//
CharType *m_pstrData;
//
// Current maximum buffer size
//
size_t m_nMaxSize;
//
// Amount of extra space we allocate when we have to grow the buffer
//
size_t m_nGranularity;
//
// Error flag. This is set if an allocation fails.
//
bool m_bError;
private:
//
// Min, in case it isn't already defined
//
template <class NumberType>
static NumberType Min( const NumberType &a, const NumberType &b )
{
return (a < b) ? a : b;
}
private:
//
// Replacements (in some cases just wrappers) for strlen, strcpy, ...
//
static inline CharType *GenericCopyLength( CharType *pstrTarget, const CharType *pstrSource, size_t nSize );
static inline size_t GenericLength( const CharType *pstrStr );
static inline CharType *GenericConcatenate( CharType *pstrTarget, const CharType *pstrSource );
static inline int GenericCompare( const CharType *pstrTarget, const CharType *pstrSource );
static inline int GenericCompareNoCase( const CharType *pstrStrA, const CharType *pstrStrB );
static inline int GenericCompareLength( const CharType *pstrTarget, const CharType *pstrSource, size_t cchLength );
static inline LPSTR GenericCharNext( LPCSTR );
static inline LPWSTR GenericCharNext( LPCWSTR );
private:
//
// Internal only helpers
//
bool EnsureLength( size_t nMaxSize );
void DeleteStorage();
CharType *CreateStorage( size_t nCount, size_t &nAllocated );
void Destroy();
public:
//
// Constructors and destructor
//
CBasicStringBase();
CBasicStringBase( const CBasicStringBase & );
CBasicStringBase( const CharType *szStr );
CBasicStringBase( CharType ch );
CBasicStringBase( UINT nResId, HMODULE hModule );
virtual ~CBasicStringBase();
//
// String state
//
bool OK() const
{
return (!Error() && String());
}
bool IsValid() const
{
return (String() != NULL);
}
bool Error() const
{
return m_bError;
}
HRESULT Status() const
{
return OK() ? S_OK : E_OUTOFMEMORY;
}
void ClearError()
{
m_bError = false;
}
private:
void PropagateError( const CBasicStringBase &other )
{
if (!Error() && other.Error())
{
m_bError = true;
}
}
public:
#if defined(SIMSTR_UNIT_TEST)
bool m_bForceError;
void ForceError( bool bForceError ) { m_bForceError = bForceError; }
#endif
//
// Various helpers
//
size_t Length() const;
void Concat( const CBasicStringBase &other );
bool Assign( const CharType *szStr );
bool Assign( const CBasicStringBase & );
void SetAt( size_t nIndex, CharType chValue );
CharType GetAt( size_t nIndex ) const;
CharType &operator[](int index);
const CharType &operator[](int index) const;
//
// Handy Win32 wrappers
//
CBasicStringBase &Format( const CharType *strFmt, ... );
CBasicStringBase &Format( int nResId, HINSTANCE hInst, ... );
bool LoadString( UINT nResId, HMODULE hModule );
//
// Operators
//
CBasicStringBase &operator=( const CBasicStringBase &other );
CBasicStringBase &operator=( const CharType *other );
CBasicStringBase &operator+=( const CBasicStringBase &other );
//
// Convert this string and return the converted string
//
CBasicStringBase ToUpper() const;
CBasicStringBase ToLower() const;
//
// Convert in place
//
CBasicStringBase &MakeUpper();
CBasicStringBase &MakeLower();
//
// Remove leading and trailing spaces
//
CBasicStringBase &TrimRight();
CBasicStringBase &TrimLeft();
CBasicStringBase &Trim();
//
// Searching
//
int Find( CharType cChar ) const;
int Find( const CBasicStringBase &other, size_t nStart=0 ) const;
int ReverseFind( CharType cChar ) const;
int ReverseFind( const CBasicStringBase &other ) const;
//
// Substring copies
//
CBasicStringBase SubStr( size_t nStart, size_t nCount ) const;
CBasicStringBase SubStr( size_t nStart ) const;
CBasicStringBase Left( size_t nCount ) const
{
return SubStr( 0, (int)nCount );
}
CBasicStringBase Right( size_t nCount ) const
{
return SubStr( Length()-nCount );
}
//
// Comparison functions
//
int CompareNoCase( const CBasicStringBase &other, int cchLength=-1 ) const;
int Compare( const CBasicStringBase &other, int cchLength=-1 ) const;
//
// Direct manipulation
//
CharType *GetBuffer( size_t cchLength )
{
//
// If we are able to allocate a string of the
// requested length, return a pointer to the actual data.
//
return EnsureLength(cchLength+1) ? m_pstrData : NULL;
}
//
// Useful inlines
//
const CharType *String() const
{
return m_pstrData;
}
size_t MaxSize() const
{
return m_nMaxSize;
}
size_t Granularity( size_t nGranularity )
{
if (nGranularity>0)
{
m_nGranularity = nGranularity;
}
return m_nGranularity;
}
size_t Granularity() const
{
return m_nGranularity;
}
//
// Implicit cast operator
//
operator const CharType *() const
{
return String();
}
friend class CBasicStringBase;
};
template <>
inline LPSTR CBasicStringBase<CHAR>::GenericCharNext( LPCSTR pszStr )
{
if (!pszStr)
{
return NULL;
}
return CharNextA(pszStr);
}
template <>
inline LPWSTR CBasicStringBase<WCHAR>::GenericCharNext( LPCWSTR pszStr )
{
if (!pszStr)
{
return NULL;
}
return CharNextW(pszStr);
}
template <class CharType>
inline CharType *CBasicStringBase<CharType>::GenericCopyLength( CharType *pszTarget, const CharType *pszSource, size_t nCount )
{
if (!pszTarget || !pszSource)
{
return NULL;
}
size_t nCopyLen = min( nCount, GenericLength(pszSource) + 1 );
if (0 == nCopyLen)
{
return pszTarget;
}
CopyMemory( pszTarget, pszSource, nCopyLen * sizeof(CharType) );
pszTarget[nCopyLen-1] = 0;
return pszTarget;
}
template <>
inline size_t CBasicStringBase<CHAR>::GenericLength( LPCSTR pszString )
{
if (!pszString)
{
return 0;
}
size_t nSize = 0;
if (S_OK != StringCchLengthA( pszString, STRSAFE_MAX_CCH, &nSize ))
{
return 0;
}
return nSize;
}
template <>
inline size_t CBasicStringBase<WCHAR>::GenericLength( LPCWSTR pszString )
{
if (!pszString)
{
return 0;
}
size_t nSize = 0;
if (S_OK != StringCchLengthW( pszString, STRSAFE_MAX_CCH, &nSize ))
{
return 0;
}
return nSize;
}
template <class CharType>
inline CharType*CBasicStringBase<CharType>::GenericConcatenate( CharType *pszTarget, const CharType *pszSource )
{
if (!pszTarget || !pszSource)
{
return NULL;
}
CharType *pszCurr = pszTarget;
while (*pszCurr)
{
pszCurr++;
}
CopyMemory( pszCurr, pszSource, sizeof(CharType) * (GenericLength(pszSource) + 1) );
return pszTarget;
}
template <class CharType>
inline int CBasicStringBase<CharType>::GenericCompare( const CharType *pszSource, const CharType *pszTarget )
{
#if defined(DBG) && !defined(UNICODE) && !defined(_UNICODE)
if (sizeof(CharType) == sizeof(wchar_t))
{
OutputDebugString(TEXT("CompareStringW is not supported under win9x, so this call is going to fail!"));
}
#endif
int nRes = IS_CHAR(*pszSource) ?
CompareStringA( LOCALE_USER_DEFAULT, 0, (LPCSTR)pszSource, -1, (LPCSTR)pszTarget, -1 ) :
CompareStringW( LOCALE_USER_DEFAULT, 0, (LPCWSTR)pszSource, -1, (LPCWSTR)pszTarget, -1 );
switch (nRes)
{
case CSTR_LESS_THAN:
return -1;
case CSTR_GREATER_THAN:
return 1;
default:
return 0;
}
}
template <class CharType>
inline int CBasicStringBase<CharType>::GenericCompareNoCase( const CharType *pszSource, const CharType *pszTarget )
{
#if defined(DBG) && !defined(UNICODE) && !defined(_UNICODE)
if (sizeof(CharType) == sizeof(wchar_t))
{
OutputDebugString(TEXT("CompareStringW is not supported under win9x, so this call is going to fail!"));
}
#endif
int nRes = IS_CHAR(*pszSource) ?
CompareStringA( LOCALE_USER_DEFAULT, NORM_IGNORECASE, (LPCSTR)pszSource, -1, (LPCSTR)pszTarget, -1 ) :
CompareStringW( LOCALE_USER_DEFAULT, NORM_IGNORECASE, (LPCWSTR)pszSource, -1, (LPCWSTR)pszTarget, -1 );
switch (nRes)
{
case CSTR_LESS_THAN:
return -1;
case CSTR_GREATER_THAN:
return 1;
default:
return 0;
}
}
template <class CharType>
inline int CBasicStringBase<CharType>::GenericCompareLength( const CharType *pszStringA, const CharType *pszStringB, size_t cchLength )
{
#if defined(DBG) && !defined(UNICODE) && !defined(_UNICODE)
if (sizeof(CharType) == sizeof(wchar_t))
{
OutputDebugString(TEXT("CompareStringW is not supported under win9x, so this call is going to fail!"));
}
#endif
if (!cchLength)
return(0);
int nRes = IS_CHAR(*pszStringA) ?
CompareStringA( LOCALE_USER_DEFAULT, 0, (LPCSTR)pszStringA, (int)Min(cchLength,CBasicStringBase<CHAR>::GenericLength((LPCSTR)pszStringA)), (LPCSTR)pszStringB, (int)Min(cchLength,CBasicStringBase<CHAR>::GenericLength((LPCSTR)pszStringB)) ) :
CompareStringW( LOCALE_USER_DEFAULT, 0, (LPWSTR)pszStringA, (int)Min(cchLength,CBasicStringBase<WCHAR>::GenericLength((LPCWSTR)pszStringA)), (LPCWSTR)pszStringB, (int)Min(cchLength,CBasicStringBase<WCHAR>::GenericLength((LPCWSTR)pszStringB)) );
switch (nRes)
{
case CSTR_LESS_THAN:
return -1;
case CSTR_GREATER_THAN:
return 1;
default:
return 0;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -