optimizations: more functions made inline, added Alloc()/Shrink() function for

more precise control over string's memory


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@275 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
1998-07-15 17:10:23 +00:00
parent 2ab889ff7b
commit dd1eaa89dd
2 changed files with 218 additions and 220 deletions

View File

@@ -6,7 +6,7 @@
// Created: 29/01/98 // Created: 29/01/98
// RCS-ID: $Id$ // RCS-ID: $Id$
// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
// Licence: wxWindows license // Licence: wxWindows license
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#ifndef __WXSTRINGH__ #ifndef __WXSTRINGH__
@@ -26,10 +26,13 @@
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <limits.h> #include <limits.h>
#include <stdlib.h>
#ifndef WX_PRECOMP #ifndef WX_PRECOMP
#include "wx/defs.h" // Robert Roebling #include "wx/defs.h" // Robert Roebling
#include "wx/object.h" #ifdef WXSTRING_IS_WXOBJECT
#include "wx/object.h"
#endif
#endif #endif
#include "wx/debug.h" #include "wx/debug.h"
@@ -78,7 +81,31 @@ inline size_t WXDLLEXPORT Strlen(const char *psz)
{ return psz ? strlen(psz) : 0; } { return psz ? strlen(psz) : 0; }
/// portable strcasecmp/_stricmp /// portable strcasecmp/_stricmp
int WXDLLEXPORT Stricmp(const char *, const char *); inline int WXDLLEXPORT Stricmp(const char *psz1, const char *psz2)
{
#if defined(_MSC_VER)
return _stricmp(psz1, psz2);
#elif defined(__BORLANDC__)
return stricmp(psz1, psz2);
#elif defined(__UNIX__) || defined(__GNUWIN32__)
return strcasecmp(psz1, psz2);
#else
// almost all compilers/libraries provide this function (unfortunately under
// different names), that's why we don't implement our own which will surely
// be more efficient than this code (uncomment to use):
/*
register char c1, c2;
do {
c1 = tolower(*psz1++);
c2 = tolower(*psz2++);
} while ( c1 && (c1 == c2) );
return c1 - c2;
*/
#error "Please define string case-insensitive compare for your OS/compiler"
#endif // OS/compiler
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// global data // global data
@@ -109,8 +136,8 @@ struct WXDLLEXPORT wxStringData
bool IsShared() const { return nRefs > 1; } bool IsShared() const { return nRefs > 1; }
// lock/unlock // lock/unlock
void Lock() { if ( !IsEmpty() ) nRefs++; } void Lock() { if ( !IsEmpty() ) nRefs++; }
void Unlock() { if ( !IsEmpty() && --nRefs == 0) delete (char *)this; } void Unlock() { if ( !IsEmpty() && --nRefs == 0) free(this); }
// if we had taken control over string memory (GetWriteBuf), it's // if we had taken control over string memory (GetWriteBuf), it's
// intentionally put in invalid state // intentionally put in invalid state
@@ -157,6 +184,15 @@ struct WXDLLEXPORT wxStringData
friend class wxArrayString; friend class wxArrayString;
// NB: this data must be here (before all other functions) to be sure that all
// inline functions are really inlined by all compilers
private:
// points to data preceded by wxStringData structure with ref count info
char *m_pchData;
// accessor to string data
wxStringData* GetStringData() const { return (wxStringData*)m_pchData - 1; }
public: public:
/** @name constructors & dtor */ /** @name constructors & dtor */
//@{ //@{
@@ -179,11 +215,19 @@ public:
/** @name generic attributes & operations */ /** @name generic attributes & operations */
//@{ //@{
/// as standard strlen() /// as standard strlen()
size_t Len() const { return GetStringData()->nDataLength; } uint Len() const { return GetStringData()->nDataLength; }
/// string contains any characters? /// string contains any characters?
bool IsEmpty() const; bool IsEmpty() const { return Len() == 0; }
/// reinitialize string (and free data!) /// reinitialize string (and free data!)
void Empty(); void Empty()
{
if ( GetStringData()->nDataLength != 0 )
Reinit();
wxASSERT( GetStringData()->nDataLength == 0 );
wxASSERT( GetStringData()->nAllocLength == 0 );
}
/// Is an ascii value /// Is an ascii value
bool IsAscii() const; bool IsAscii() const;
/// Is a number /// Is a number
@@ -196,10 +240,10 @@ public:
//@{ //@{
/// read access /// read access
char GetChar(size_t n) const char GetChar(size_t n) const
{ ASSERT_VALID_INDEX( n ); return m_pchData[n]; } { ASSERT_VALID_INDEX( n ); return m_pchData[n]; }
/// read/write access /// read/write access
char& GetWritableChar(size_t n) char& GetWritableChar(size_t n)
{ ASSERT_VALID_INDEX( n ); CopyBeforeWrite(); return m_pchData[n]; } { ASSERT_VALID_INDEX( n ); CopyBeforeWrite(); return m_pchData[n]; }
/// write access /// write access
void SetChar(size_t n, char ch) void SetChar(size_t n, char ch)
{ ASSERT_VALID_INDEX( n ); CopyBeforeWrite(); m_pchData[n] = ch; } { ASSERT_VALID_INDEX( n ); CopyBeforeWrite(); m_pchData[n] = ch; }
@@ -248,22 +292,29 @@ public:
/** @name in place concatenation */ /** @name in place concatenation */
//@{ //@{
/// string += string /// string += string
void operator+=(const wxString& string); void operator+=(const wxString& s) { (void)operator<<(s); }
/// string += C string /// string += C string
void operator+=(const char *psz); void operator+=(const char *psz) { (void)operator<<(psz); }
/// string += char /// string += char
void operator+=(char ch); void operator+=(char ch) { (void)operator<<(ch); }
//@} //@}
/** @name concatenate and return the result /** @name concatenate and return the result
left to right associativity of << allows to write left to right associativity of << allows to write
things like "str << str1 << str2 << ..." */ things like "str << str1 << str2 << ..." */
//@{ //@{
/// as += /// as +=
wxString& operator<<(const wxString& string); wxString& operator<<(const wxString& s)
{
wxASSERT( s.GetStringData()->IsValid() );
ConcatSelf(s.Len(), s);
return *this;
}
/// as += /// as +=
wxString& operator<<(char ch); wxString& operator<<(const char *psz)
{ ConcatSelf(Strlen(psz), psz); return *this; }
/// as += /// as +=
wxString& operator<<(const char *psz); wxString& operator<<(char ch) { ConcatSelf(1, &ch); return *this; }
//@} //@}
/** @name return resulting string */ /** @name return resulting string */
@@ -378,12 +429,18 @@ public:
/** @name raw access to string memory */ /** @name raw access to string memory */
//@{ //@{
/// ensure that string has space for at least nLen characters
// only works if the data of this string is not shared
void Alloc(uint nLen);
/// minimize the string's memory
// only works if the data of this string is not shared
void Shrink();
/** /**
get writable buffer of at least nLen bytes. get writable buffer of at least nLen bytes.
Unget() *must* be called a.s.a.p. to put string back in a reasonable Unget() *must* be called a.s.a.p. to put string back in a reasonable
state! state!
*/ */
char *GetWriteBuf(int nLen); char *GetWriteBuf(uint nLen);
/// call this immediately after GetWriteBuf() has been used /// call this immediately after GetWriteBuf() has been used
void UngetWriteBuf(); void UngetWriteBuf();
//@} //@}
@@ -525,7 +582,7 @@ public:
wxString& insert(size_t nPos, const wxString& str); wxString& insert(size_t nPos, const wxString& str);
/// insert n chars of str starting at nStart (in str) /// insert n chars of str starting at nStart (in str)
wxString& insert(size_t nPos, const wxString& str, size_t nStart, size_t n) wxString& insert(size_t nPos, const wxString& str, size_t nStart, size_t n)
{ return insert(nPos, wxString((const char *)str + nStart, n)); } { return insert(nPos, wxString((const char *)str + nStart, n)); }
/// insert first n (or all if n == npos) characters of sz /// insert first n (or all if n == npos) characters of sz
wxString& insert(size_t nPos, const char *sz, size_t n = npos) wxString& insert(size_t nPos, const char *sz, size_t n = npos)
@@ -585,8 +642,8 @@ public:
/// find the first occurence of character ch after nStart /// find the first occurence of character ch after nStart
size_t find(char ch, size_t nStart = 0) const; size_t find(char ch, size_t nStart = 0) const;
// wxWin compatibility // wxWin compatibility
inline bool Contains(const wxString& str) { return (Find(str) != -1); } inline bool Contains(const wxString& str) { return Find(str) != -1; }
//@} //@}
@@ -669,12 +726,8 @@ public:
//@} //@}
#endif #endif
protected: private:
// points to data preceded by wxStringData structure with ref count info
char *m_pchData;
// accessor to string data
wxStringData* GetStringData() const { return (wxStringData*)m_pchData - 1; }
// string (re)initialization functions // string (re)initialization functions
// initializes the string to the empty value (must be called only from // initializes the string to the empty value (must be called only from
@@ -683,7 +736,7 @@ protected:
// initializaes the string with (a part of) C-string // initializaes the string with (a part of) C-string
void InitWith(const char *psz, size_t nPos = 0, size_t nLen = STRING_MAXLEN); void InitWith(const char *psz, size_t nPos = 0, size_t nLen = STRING_MAXLEN);
// as Init, but also frees old data // as Init, but also frees old data
inline void Reinit(); void Reinit() { GetStringData()->Unlock(); Init(); }
// memory allocation // memory allocation
// allocates memory for string of lenght nLen // allocates memory for string of lenght nLen
@@ -744,6 +797,8 @@ public:
void Clear(); void Clear();
/// preallocates memory for given number of items /// preallocates memory for given number of items
void Alloc(size_t nCount); void Alloc(size_t nCount);
/// minimzes the memory usage (by freeing all extra memory)
void Shrink();
//@} //@}
/** @name simple accessors */ /** @name simple accessors */

View File

@@ -6,7 +6,7 @@
// Created: 29/01/98 // Created: 29/01/98
// RCS-ID: $Id$ // RCS-ID: $Id$
// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
// Licence: wxWindows license // Licence: wxWindows license
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#ifdef __GNUG__ #ifdef __GNUG__
@@ -236,8 +236,8 @@ void wxString::AllocBuffer(size_t nLen)
// allocate memory: // allocate memory:
// 1) one extra character for '\0' termination // 1) one extra character for '\0' termination
// 2) sizeof(wxStringData) for housekeeping info // 2) sizeof(wxStringData) for housekeeping info
wxStringData* pData = (wxStringData*)new char[sizeof(wxStringData) + wxStringData* pData = (wxStringData*)malloc(sizeof(wxStringData) +
(nLen + 1)*sizeof(char)]; (nLen + 1)*sizeof(char));
pData->nRefs = 1; pData->nRefs = 1;
pData->data()[nLen] = '\0'; pData->data()[nLen] = '\0';
pData->nDataLength = nLen; pData->nDataLength = nLen;
@@ -245,23 +245,6 @@ void wxString::AllocBuffer(size_t nLen)
m_pchData = pData->data(); // data starts after wxStringData m_pchData = pData->data(); // data starts after wxStringData
} }
// releases the string memory and reinits it
void wxString::Reinit()
{
GetStringData()->Unlock();
Init();
}
// wrapper around wxString::Reinit
void wxString::Empty()
{
if ( GetStringData()->nDataLength != 0 )
Reinit();
wxASSERT( GetStringData()->nDataLength == 0 );
wxASSERT( GetStringData()->nAllocLength == 0 );
}
// must be called before changing this string // must be called before changing this string
void wxString::CopyBeforeWrite() void wxString::CopyBeforeWrite()
{ {
@@ -292,8 +275,44 @@ void wxString::AllocBeforeWrite(size_t nLen)
wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner
} }
// allocate enough memory for nLen characters
void wxString::Alloc(uint nLen)
{
wxStringData *pData = GetStringData();
if ( pData->nAllocLength <= nLen ) {
if ( pData->IsEmpty() )
AllocBuffer(nLen);
else {
wxStringData *p = (wxStringData *)
realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(char));
if ( p != NULL && p != pData ) {
// the call succeeded but the pointer changed
pData->Unlock();
free(pData);
p->nRefs = 1;
p->nAllocLength = nLen;
m_pchData = p->data();
}
//else: do nothing: either the call failed or the pointer is unchanged
}
}
//else: we've already got enough
}
// shrink to minimal size (releasing extra memory)
void wxString::Shrink()
{
wxStringData *pData = GetStringData();
void *p = realloc(pData, sizeof(wxStringData) +
(pData->nDataLength + 1)*sizeof(char));
if ( p == NULL ) // huh? can't unallocate memory? unlikely but possible.
return;
wxASSERT( p == pData ); // we're decrementing the size - block shouldn't move!
}
// get the pointer to writable buffer of (at least) nLen bytes // get the pointer to writable buffer of (at least) nLen bytes
char *wxString::GetWriteBuf(int nLen) char *wxString::GetWriteBuf(uint nLen)
{ {
AllocBeforeWrite(nLen); AllocBeforeWrite(nLen);
@@ -396,7 +415,7 @@ wxString& wxString::operator=(const wchar_t *pwz)
// concatenate two sources // concatenate two sources
// NB: assume that 'this' is a new wxString object // NB: assume that 'this' is a new wxString object
void wxString::ConcatCopy(int nSrc1Len, const char *pszSrc1Data, void wxString::ConcatCopy(int nSrc1Len, const char *pszSrc1Data,
int nSrc2Len, const char *pszSrc2Data) int nSrc2Len, const char *pszSrc2Data)
{ {
int nNewLen = nSrc1Len + nSrc2Len; int nNewLen = nSrc1Len + nSrc2Len;
if ( nNewLen != 0 ) if ( nNewLen != 0 )
@@ -436,51 +455,6 @@ void wxString::ConcatSelf(int nSrcLen, const char *pszSrcData)
} }
} }
/*
* string may be concatenated with other string, C string or a character
*/
void wxString::operator+=(const wxString& string)
{
wxASSERT( string.GetStringData()->IsValid() );
ConcatSelf(string.Len(), string);
}
void wxString::operator+=(const char *psz)
{
ConcatSelf(Strlen(psz), psz);
}
void wxString::operator+=(char ch)
{
ConcatSelf(1, &ch);
}
/*
* Same as above but return the result
*/
wxString& wxString::operator<<(const wxString& string)
{
wxASSERT( string.GetStringData()->IsValid() );
ConcatSelf(string.Len(), string);
return *this;
}
wxString& wxString::operator<<(const char *psz)
{
ConcatSelf(Strlen(psz), psz);
return *this;
}
wxString& wxString::operator<<(char ch)
{
ConcatSelf(1, &ch);
return *this;
}
/* /*
* concatenation functions come in 5 flavours: * concatenation functions come in 5 flavours:
* string + string * string + string
@@ -720,10 +694,6 @@ bool wxString::IsNumber() const
return(TRUE); return(TRUE);
} }
// kludge: we don't have declaraton of wxStringData here, so we add offsets
// manually to get to the "length" field of wxStringData structure
bool wxString::IsEmpty() const { return Len() == 0; }
wxString wxString::Strip(stripType w) const wxString wxString::Strip(stripType w) const
{ {
wxString s = *this; wxString s = *this;
@@ -732,33 +702,6 @@ wxString wxString::Strip(stripType w) const
return s; return s;
} }
/// case-insensitive strcmp() (platform independent)
int Stricmp(const char *psz1, const char *psz2)
{
#if defined(_MSC_VER)
return _stricmp(psz1, psz2);
#elif defined(__BORLANDC__)
return stricmp(psz1, psz2);
#elif defined(__UNIX__) || defined(__GNUWIN32__)
return strcasecmp(psz1, psz2);
#else
// almost all compilers/libraries provide this function (unfortunately under
// different names), that's why we don't implement our own which will surely
// be more efficient than this code (uncomment to use):
/*
register char c1, c2;
do {
c1 = tolower(*psz1++);
c2 = tolower(*psz2++);
} while ( c1 && (c1 == c2) );
return c1 - c2;
*/
#error "Please define string case-insensitive compare for your OS/compiler"
#endif // OS/compiler
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// case conversion // case conversion
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -1158,7 +1101,7 @@ wxArrayString& wxArrayString::operator=(const wxArrayString& src)
m_nCount = src.m_nCount; m_nCount = src.m_nCount;
if ( m_nSize != 0 ) if ( m_nSize != 0 )
m_pItems = new char *[m_nSize]; m_pItems = new char *[m_nCount];
else else
m_pItems = NULL; m_pItems = NULL;