X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c801d85f158c4cba50b588807daabdcbd0ed3853..246037e22990a4719c672c2e2a8b62b99cc4d49c:/include/wx/string.h diff --git a/include/wx/string.h b/include/wx/string.h index 55b4812624..7aa6819b92 100644 --- a/include/wx/string.h +++ b/include/wx/string.h @@ -6,14 +6,14 @@ // Created: 29/01/98 // RCS-ID: $Id$ // Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows license +// Licence: wxWindows license ///////////////////////////////////////////////////////////////////////////// #ifndef __WXSTRINGH__ #define __WXSTRINGH__ #ifdef __GNUG__ -#pragma interface +#pragma interface "string.h" #endif /* Dependencies (should be included before this header): @@ -26,14 +26,20 @@ #include #include #include +#include + +#ifndef WX_PRECOMP + #include "wx/defs.h" // Robert Roebling + #ifdef WXSTRING_IS_WXOBJECT + #include "wx/object.h" + #endif +#endif -#include "wx/defs.h" // Robert Roebling -#include "wx/object.h" #include "wx/debug.h" /** @name wxString library @memo Efficient wxString class [more or less] compatible with MFC CString, - wxWindows wxString and std::string and some handy functions + wxWindows wxString and std::string and some handy functions missing from string.h. */ //@{ @@ -42,7 +48,7 @@ // macros // --------------------------------------------------------------------------- -/** @name Macros +/** @name Macros @memo You can switch off wxString/std::string compatibility if desired */ /// compile the std::string compatibility functions @@ -62,7 +68,7 @@ #define ASSERT_VALID_INDEX(i) wxASSERT( (unsigned)(i) < Len() ) // --------------------------------------------------------------------------- -/** @name Global functions complementing standard C string library +/** @name Global functions complementing standard C string library @memo replacements for strlen() and portable strcasecmp() */ // --------------------------------------------------------------------------- @@ -75,32 +81,69 @@ inline size_t WXDLLEXPORT Strlen(const char *psz) { return psz ? strlen(psz) : 0; } /// 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 pointer to empty string +extern const char *g_szNul; + +// return an empty wxString +class wxString; // not yet defined +inline const wxString& wxGetEmptyString() { return *(wxString *)&g_szNul; } // --------------------------------------------------------------------------- -// string data prepended with some housekeeping info (used by String class), +// string data prepended with some housekeeping info (used by wxString class), // is never used directly (but had to be put here to allow inlining) // --------------------------------------------------------------------------- struct WXDLLEXPORT wxStringData { int nRefs; // reference count - size_t nDataLength, // actual string length + uint nDataLength, // actual string length nAllocLength; // allocated memory size // mimics declaration 'char data[nAllocLength]' - char* data() const { return (char*)(this + 1); } + char* data() const { return (char*)(this + 1); } // empty string has a special ref count so it's never deleted bool IsEmpty() const { return nRefs == -1; } bool IsShared() const { return nRefs > 1; } - bool IsValid() const { return nRefs != 0; } // lock/unlock - void Lock() { if ( !IsEmpty() ) nRefs++; } - void Unlock() { if ( !IsEmpty() && --nRefs == 0) delete (char *)this; } -}; + void Lock() { if ( !IsEmpty() ) nRefs++; } + void Unlock() { if ( !IsEmpty() && --nRefs == 0) free(this); } -extern const char *g_szNul; // global pointer to empty string + // if we had taken control over string memory (GetWriteBuf), it's + // intentionally put in invalid state + void Validate(bool b) { nRefs = b ? 1 : 0; } + bool IsValid() const { return nRefs != 0; } +}; // --------------------------------------------------------------------------- /** @@ -113,9 +156,9 @@ extern const char *g_szNul; // global pointer to empty string This class aims to be as compatible as possible with the new standard std::string class, but adds some additional functions and should be at least as efficient than the standard implementation. - - Performance note: it's more efficient to write functions which take - "const String&" arguments than "const char *" if you assign the argument + + Performance note: it's more efficient to write functions which take + "const String&" arguments than "const char *" if you assign the argument to another string. It was compiled and tested under Win32, Linux (libc 5 & 6), Solaris 5.5. @@ -124,7 +167,7 @@ extern const char *g_szNul; // global pointer to empty string - ressource support (string tables in ressources) - more wide character (UNICODE) support - regular expressions support - + @memo A non-template portable wxString class implementing copy-on-write. @author VZ @version 1.3 @@ -141,33 +184,89 @@ extern const char *g_szNul; // global pointer to empty string friend class wxArrayString; + // NB: special care was taken in arrangin the member functions in such order + // that all inline functions can be effectively inlined +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 + // initializes the string to the empty value (must be called only from + // ctors, use Reinit() otherwise) + void Init() { m_pchData = (char *)g_szNul; } + // initializaes the string with (a part of) C-string + void InitWith(const char *psz, size_t nPos = 0, size_t nLen = STRING_MAXLEN); + // as Init, but also frees old data + void Reinit() { GetStringData()->Unlock(); Init(); } + + // memory allocation + // allocates memory for string of lenght nLen + void AllocBuffer(size_t nLen); + // copies data to another string + void AllocCopy(wxString&, int, int) const; + // effectively copies data to string + void AssignCopy(size_t, const char *); + + // append a (sub)string + void ConcatSelf(int nLen, const char *src); + + // functions called before writing to the string: they copy it if there + // are other references to our data (should be the only owner when writing) + void CopyBeforeWrite(); + void AllocBeforeWrite(size_t); + public: /** @name constructors & dtor */ //@{ /// ctor for an empty string - wxString(); + wxString() { Init(); } /// copy ctor - wxString(const wxString& stringSrc); + wxString(const wxString& stringSrc) + { + wxASSERT( stringSrc.GetStringData()->IsValid() ); + + if ( stringSrc.IsEmpty() ) { + // nothing to do for an empty string + Init(); + } + else { + m_pchData = stringSrc.m_pchData; // share same data + GetStringData()->Lock(); // => one more copy + } + } /// string containing nRepeat copies of ch - wxString(char ch, size_t nRepeat = 1); + wxString(char ch, size_t nRepeat = 1); /// ctor takes first nLength characters from C string - wxString(const char *psz, size_t nLength = STRING_MAXLEN); + // (default value of STRING_MAXLEN means take all the string) + wxString(const char *psz, size_t nLength = STRING_MAXLEN) + { InitWith(psz, 0, nLength); } /// from C string (for compilers using unsigned char) wxString(const unsigned char* psz, size_t nLength = STRING_MAXLEN); /// from wide (UNICODE) string wxString(const wchar_t *pwz); /// dtor is not virtual, this class must not be inherited from! - ~wxString(); + ~wxString() { GetStringData()->Unlock(); } //@} /** @name generic attributes & operations */ //@{ /// as standard strlen() - size_t Len() const { return GetStringData()->nDataLength; } + uint Len() const { return GetStringData()->nDataLength; } /// string contains any characters? - bool IsEmpty() const; + bool IsEmpty() const { return Len() == 0; } /// 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 bool IsAscii() const; /// Is a number @@ -180,10 +279,10 @@ public: //@{ /// read access 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 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 void SetChar(size_t n, char ch) { ASSERT_VALID_INDEX( n ); CopyBeforeWrite(); m_pchData[n] = ch; } @@ -192,7 +291,7 @@ public: char Last() const { wxASSERT( !IsEmpty() ); return m_pchData[Len() - 1]; } /// get writable last character - char& Last() + char& Last() { wxASSERT( !IsEmpty() ); CopyBeforeWrite(); return m_pchData[Len()-1]; } /// operator version of GetChar @@ -206,7 +305,7 @@ public: { ASSERT_VALID_INDEX( n ); CopyBeforeWrite(); return m_pchData[n]; } /// implicit conversion to C string - operator const char*() const { return m_pchData; } + operator const char*() const { return m_pchData; } /// explicit conversion to C string (use this with printf()!) const char* c_str() const { return m_pchData; } /// @@ -226,30 +325,38 @@ public: /// wxString& operator=(const wchar_t *pwz); //@} - + /** @name string concatenation */ //@{ /** @name in place concatenation */ - //@{ - /// string += string - void operator+=(const wxString& string); - /// string += C string - void operator+=(const char *psz); - /// string += char - void operator+=(char ch); - //@} /** @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 << ..." */ //@{ /// as += - wxString& operator<<(const wxString& string); + wxString& operator<<(const wxString& s) + { + wxASSERT( s.GetStringData()->IsValid() ); + + ConcatSelf(s.Len(), s); + return *this; + } /// as += - wxString& operator<<(char ch); + wxString& operator<<(const char *psz) + { ConcatSelf(Strlen(psz), psz); return *this; } /// as += - wxString& operator<<(const char *psz); + wxString& operator<<(char ch) { ConcatSelf(1, &ch); return *this; } + //@} + + //@{ + /// string += string + void operator+=(const wxString& s) { (void)operator<<(s); } + /// string += C string + void operator+=(const char *psz) { (void)operator<<(psz); } + /// string += char + void operator+=(char ch) { (void)operator<<(ch); } //@} - + /** @name return resulting string */ //@{ /// @@ -264,10 +371,10 @@ public: friend wxString operator+(const char *psz, const wxString& string); //@} //@} - + /** @name string comparison */ //@{ - /** + /** case-sensitive comparaison @return 0 if equal, +1 if greater or -1 if less @see CmpNoCase, IsSameAs @@ -284,20 +391,20 @@ public: @return TRUE if strings are equal, FALSE otherwise @see Cmp, CmpNoCase */ - bool IsSameAs(const char *psz, bool bCase = TRUE) const + bool IsSameAs(const char *psz, bool bCase = TRUE) const { return !(bCase ? Cmp(psz) : CmpNoCase(psz)); } //@} - + /** @name other standard string operations */ //@{ /** @name simple sub-string extraction */ //@{ - /** - return substring starting at nFirst of length + /** + return substring starting at nFirst of length nCount (or till the end if nCount = default value) */ - wxString Mid(size_t nFirst, size_t nCount = STRING_MAXLEN) const; + wxString Mid(size_t nFirst, size_t nCount = STRING_MAXLEN) const; /// get first nCount characters wxString Left(size_t nCount) const; /// get all characters before the first occurence of ch @@ -315,9 +422,9 @@ public: /// (returns the whole string if ch not found) wxString Right(char ch) const; //@} - + /** @name case conversion */ - //@{ + //@{ /// wxString& MakeUpper(); /// @@ -333,7 +440,7 @@ public: /// truncate string to given length wxString& Truncate(size_t uiLen); //@} - + /** @name searching and replacing */ //@{ /// searching (return starting index, or -1 if not found) @@ -347,18 +454,36 @@ public: */ uint Replace(const char *szOld, const char *szNew, bool bReplaceAll = TRUE); //@} + + /// check if the string contents matches a mask containing '*' and '?' + bool Matches(const char *szMask) const; //@} - /** @name formated output */ + /** @name formated input/output */ //@{ /// as sprintf(), returns the number of characters written or < 0 on error int Printf(const char *pszFormat, ...); /// as vprintf(), returns the number of characters written or < 0 on error int PrintfV(const char* pszFormat, va_list argptr); //@} - - // get writable buffer of at least nLen characters - char *GetWriteBuf(size_t nLen); + + /** @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. + Unget() *must* be called a.s.a.p. to put string back in a reasonable + state! + */ + char *GetWriteBuf(uint nLen); + /// call this immediately after GetWriteBuf() has been used + void UngetWriteBuf(); + //@} /** @name wxWindows compatibility functions */ //@{ @@ -378,17 +503,20 @@ public: /// same as Cmp inline int CompareTo(const char* psz, caseCompare cmp = exact) const - { return cmp == exact ? Cmp(psz) : CmpNoCase(psz); } + { return cmp == exact ? Cmp(psz) : CmpNoCase(psz); } /// same as Mid (substring extraction) - inline wxString operator()(size_t start, size_t len) const { return Mid(start, len); } + inline wxString operator()(size_t start, size_t len) const + { return Mid(start, len); } /// same as += or << inline wxString& Append(const char* psz) { return *this << psz; } - inline wxString& Append(char ch, int count = 1) { wxString str(ch, count); (*this) += str; return *this; } + inline wxString& Append(char ch, int count = 1) + { wxString str(ch, count); (*this) += str; return *this; } /// - wxString& Prepend(const wxString& str) { *this = str + *this; return *this; } + wxString& Prepend(const wxString& str) + { *this = str + *this; return *this; } /// same as Len size_t Length() const { return Len(); } /// same as MakeLower @@ -406,9 +534,9 @@ public: wxString& RemoveLast() { return Truncate(Len() - 1); } // Robert Roebling - - wxString& Remove(size_t nStart, size_t nLen) { return erase( nStart, nLen ); } - + wxString& Remove(size_t nStart, size_t nLen) + { return erase( nStart, nLen ); } + size_t First( const char ch ) const { return find(ch); } size_t First( const char* psz ) const { return find(psz); } size_t First( const wxString &str ) const { return find(str); } @@ -423,15 +551,19 @@ public: #ifdef STD_STRING_COMPATIBILITY /** @name std::string compatibility functions */ - + /// an 'invalid' value for string index static const size_t npos; - + //@{ /** @name constructors */ //@{ /// take nLen chars starting at nPos - wxString(const wxString& s, size_t nPos, size_t nLen = npos); + wxString(const wxString& str, size_t nPos, size_t nLen = npos) + { + wxASSERT( str.GetStringData()->IsValid() ); + InitWith(str.c_str(), nPos, nLen == npos ? 0 : nLen); + } /// take all characters from pStart to pEnd wxString(const void *pStart, const void *pEnd); //@} @@ -442,7 +574,7 @@ public: /// return the length of the string size_t length() const { return Len(); } /// return the maximum size of the string - size_t max_size() const { return STRING_MAXLEN; } + size_t max_size() const { return STRING_MAXLEN; } /// resize the string, filling the space with c if c != 0 void resize(size_t nSize, char ch = '\0'); /// delete the contents of the string @@ -462,58 +594,58 @@ public: /** @name append something to the end of this one */ //@{ /// append a string - wxString& append(const wxString& str) + wxString& append(const wxString& str) { *this += str; return *this; } /// append elements str[pos], ..., str[pos+n] - wxString& append(const wxString& str, size_t pos, size_t n) + wxString& append(const wxString& str, size_t pos, size_t n) { ConcatSelf(n, str.c_str() + pos); return *this; } /// append first n (or all if n == npos) characters of sz - wxString& append(const char *sz, size_t n = npos) + wxString& append(const char *sz, size_t n = npos) { ConcatSelf(n == npos ? Strlen(sz) : n, sz); return *this; } /// append n copies of ch wxString& append(size_t n, char ch) { return Pad(n, ch); } //@} - + /** @name replaces the contents of this string with another one */ //@{ /// same as `this_string = str' wxString& assign(const wxString& str) { return (*this) = str; } /// same as ` = str[pos..pos + n] - wxString& assign(const wxString& str, size_t pos, size_t n) + wxString& assign(const wxString& str, size_t pos, size_t n) { return *this = wxString((const char *)str + pos, n); } /// same as `= first n (or all if n == npos) characters of sz' - wxString& assign(const char *sz, size_t n = npos) + wxString& assign(const char *sz, size_t n = npos) { return *this = wxString(sz, n); } /// same as `= n copies of ch' - wxString& assign(size_t n, char ch) + wxString& assign(size_t n, char ch) { return *this = wxString(ch, n); } //@} - - /** @name inserts something at position nPos into this one */ + + /** @name inserts something at position nPos into this one */ //@{ /// insert another string wxString& insert(size_t nPos, const wxString& 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) - { 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 wxString& insert(size_t nPos, const char *sz, size_t n = npos) { return insert(nPos, wxString(sz, n)); } /// insert n copies of ch - wxString& insert(size_t nPos, size_t n, char ch) + wxString& insert(size_t nPos, size_t n, char ch) { return insert(nPos, wxString(ch, n)); } //@} - + /** @name deletes a part of the string */ //@{ /// delete characters from nStart to nStart + nLen wxString& erase(size_t nStart = 0, size_t nLen = npos); //@} - + /** @name replaces a substring of this string with another one */ //@{ /// replaces the substring of length nLen starting at nStart @@ -521,14 +653,14 @@ public: /// replaces the substring with nCount copies of ch wxString& replace(size_t nStart, size_t nLen, size_t nCount, char ch); /// replaces a substring with another substring - wxString& replace(size_t nStart, size_t nLen, + wxString& replace(size_t nStart, size_t nLen, const wxString& str, size_t nStart2, size_t nLen2); /// replaces the substring with first nCount chars of sz - wxString& replace(size_t nStart, size_t nLen, + wxString& replace(size_t nStart, size_t nLen, const char* sz, size_t nCount); //@} //@} - + /// swap two strings void swap(wxString& str); @@ -536,41 +668,48 @@ public: //@{ /** All find() functions take the nStart argument which specifies the position to start the search on, the default value is 0. - + All functions return npos if there were no match. - - @name string search + + @name string search */ //@{ /** - @name find a match for the string/character in this string + @name find a match for the string/character in this string */ //@{ /// find a substring size_t find(const wxString& str, size_t nStart = 0) const; + + // VC++ 1.5 can't cope with this syntax. +#if ! (defined(_MSC_VER) && !defined(__WIN32__)) /// find first n characters of sz size_t find(const char* sz, size_t nStart = 0, size_t n = npos) const; +#endif /// find the first occurence of character ch after nStart size_t find(char ch, size_t nStart = 0) const; - // wxWin compatibility - inline bool Contains(const wxString& str) { return (Find(str) != -1); } + // wxWin compatibility + inline bool Contains(const wxString& str) { return Find(str) != -1; } //@} - - /** + + /** @name rfind() family is exactly like find() but works right to left */ //@{ /// as find, but from the end size_t rfind(const wxString& str, size_t nStart = npos) const; /// as find, but from the end - size_t rfind(const char* sz, size_t nStart = npos, + // VC++ 1.5 can't cope with this syntax. +#if ! (defined(_MSC_VER) && !defined(__WIN32__)) + size_t rfind(const char* sz, size_t nStart = npos, size_t n = npos) const; /// as find, but from the end size_t rfind(char ch, size_t nStart = npos) const; +#endif //@} - + /** @name find first/last occurence of any character in the set */ @@ -581,7 +720,7 @@ public: size_t find_first_of(const char* sz, size_t nStart = 0) const; /// same as find(char, size_t) size_t find_first_of(char c, size_t nStart = 0) const; - + /// size_t find_last_of (const wxString& str, size_t nStart = npos) const; /// @@ -589,7 +728,7 @@ public: /// same as rfind(char, size_t) size_t find_last_of (char c, size_t nStart = npos) const; //@} - + /** @name find first/last occurence of any character not in the set */ @@ -600,7 +739,7 @@ public: size_t find_first_not_of(const char* s, size_t nStart = 0) const; /// size_t find_first_not_of(char ch, size_t nStart = 0) const; - + /// size_t find_last_not_of(const wxString& str, size_t nStart=npos) const; /// @@ -609,11 +748,11 @@ public: size_t find_last_not_of(char ch, size_t nStart = npos) const; //@} //@} - - /** - All compare functions return -1, 0 or 1 if the [sub]string + + /** + All compare functions return -1, 0 or 1 if the [sub]string is less, equal or greater than the compare() argument. - + @name comparison */ //@{ @@ -633,39 +772,6 @@ public: wxString substr(size_t nStart = 0, size_t nLen = npos) const; //@} #endif - -protected: - // 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 - // initializes the string to the empty value (must be called only from - // ctors, use Reinit() otherwise) - void Init() { m_pchData = (char *)g_szNul; } - // initializaes the string with (a part of) C-string - void InitWith(const char *psz, size_t nPos = 0, size_t nLen = STRING_MAXLEN); - // as Init, but also frees old data - inline void Reinit(); - - // memory allocation - // allocates memory for string of lenght nLen - void AllocBuffer(size_t nLen); - // copies data to another string - void AllocCopy(wxString&, int, int) const; - // effectively copies data to string - void AssignCopy(size_t, const char *); - - // append a (sub)string - void ConcatCopy(int nLen1, const char *src1, int nLen2, const char *src2); - void ConcatSelf(int nLen, const char *src); - - // functions called before writing to the string: they copy it if there - // other references (should be the only owner when writing) - void CopyBeforeWrite(); - void AllocBeforeWrite(size_t); }; // ---------------------------------------------------------------------------- @@ -675,7 +781,7 @@ protected: sizeof(char *)) we store these pointers instead. The cast to "String *" is really all we need to turn such pointer into a string! - Of course, it can be called a dirty hack, but we use twice less memory + Of course, it can be called a dirty hack, but we use twice less memory and this approach is also more speed efficient, so it's probably worth it. Usage notes: when a string is added/inserted, a new copy of it is created, @@ -709,6 +815,8 @@ public: void Clear(); /// preallocates memory for given number of items void Alloc(size_t nCount); + /// minimzes the memory usage (by freeing all extra memory) + void Shrink(); //@} /** @name simple accessors */ @@ -764,13 +872,7 @@ private: }; // --------------------------------------------------------------------------- -// implementation of inline functions -// --------------------------------------------------------------------------- - -// Put back into class, since BC++ can't create precompiled header otherwise - -// --------------------------------------------------------------------------- -/** @name wxString comparaison functions +/** @name wxString comparaison functions @memo Comparaisons are case sensitive */ // --------------------------------------------------------------------------- @@ -811,9 +913,9 @@ inline bool operator>=(const wxString& s1, const char * s2) { return s1.Cmp(s2) /// inline bool operator>=(const char * s1, const wxString& s2) { return s2.Cmp(s1) <= 0; } //@} - + // --------------------------------------------------------------------------- -/** @name Global functions complementing standard C string library +/** @name Global functions complementing standard C string library @memo replacements for strlen() and portable strcasecmp() */ // ---------------------------------------------------------------------------