X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/24f86c43c427160b7fb5a1b06c4c0861cc6cc72f..f1b63efe8993c6c0460354bc2da7331526d43efa:/include/wx/string.h diff --git a/include/wx/string.h b/include/wx/string.h index 1e8be0ca23..d1c3b6d783 100644 --- a/include/wx/string.h +++ b/include/wx/string.h @@ -607,13 +607,13 @@ private: // enough) -- luckily we don't need it then neither as static __thread // variables are initialized by 0 anyhow then and so we can use the variable // directly - static Cache& GetCache() + WXEXPORT static Cache& GetCache() { static wxTLS_TYPE(Cache) s_cache; return wxTLS_VALUE(s_cache); } - + // this helper struct is used to ensure that GetCache() is called during // static initialization time, i.e. before any threads creation, as otherwise // the static s_cache construction inside GetCache() wouldn't be MT-safe @@ -671,7 +671,15 @@ private: // profiling seems to show a small but consistent gain if we use this // simple loop instead of starting from the last used element (there are // a lot of misses in this function...) - for ( Cache::Element *c = GetCacheBegin(); c != GetCacheEnd(); c++ ) + Cache::Element * const cacheBegin = GetCacheBegin(); +#ifndef wxHAS_COMPILER_TLS + // during destruction tls calls may return NULL, in this case return NULL + // immediately without accessing anything else + if ( cacheBegin == NULL ) + return NULL; +#endif + Cache::Element * const cacheEnd = GetCacheEnd(); + for ( Cache::Element *c = cacheBegin; c != cacheEnd; c++ ) { if ( c->str == this ) return c; @@ -979,7 +987,7 @@ public: iterator(wxString *str, underlying_iterator ptr) : m_cur(ptr), m_node(str, &m_cur) {} - wxString* str() const { return wx_const_cast(wxString*, m_node.m_str); } + wxString* str() const { return const_cast(m_node.m_str); } wxStringIteratorNode m_node; @@ -1518,11 +1526,53 @@ public: { return at(n); } #endif // size_t != unsigned int - // explicit conversion to C string (use this with printf()!) + + /* + Overview of wxString conversions, implicit and explicit: + + - wxString has a std::[w]string-like c_str() method, however it does + not return a C-style string directly but instead returns wxCStrData + helper object which is convertible to either "char *" narrow string + or "wchar_t *" wide string. Usually the correct conversion will be + applied by the compiler automatically but if this doesn't happen you + need to explicitly choose one using wxCStrData::AsChar() or AsWChar() + methods or another wxString conversion function. + + - One of the places where the conversion does *NOT* happen correctly is + when c_str() is passed to a vararg function such as printf() so you + must *NOT* use c_str() with them. Either use wxPrintf() (all wx + functions do handle c_str() correctly, even if they appear to be + vararg (but they're not, really)) or add an explicit AsChar() or, if + compatibility with previous wxWidgets versions is important, add a + cast to "const char *". + + - In non-STL mode only, wxString is also implicitly convertible to + wxCStrData. The same warning as above applies. + + - c_str() is polymorphic as it can be converted to either narrow or + wide string. If you explicitly need one or the other, choose to use + mb_str() (for narrow) or wc_str() (for wide) instead. Notice that + these functions can return either the pointer to string directly (if + this is what the string uses internally) or a temporary buffer + containing the string and convertible to it. Again, conversion will + usually be done automatically by the compiler but beware of the + vararg functions: you need an explicit cast when using them. + + - There are also non-const versions of mb_str() and wc_str() called + char_str() and wchar_str(). They are only meant to be used with + non-const-correct functions and they always return buffers. + + - Finally wx_str() returns whatever string representation is used by + wxString internally. It may be either a narrow or wide string + depending on wxWidgets build mode but it will always be a raw pointer + (and not a buffer). + */ + + // explicit conversion to wxCStrData wxCStrData c_str() const { return wxCStrData(this); } wxCStrData data() const { return c_str(); } - // implicit conversion to C string + // implicit conversion to wxCStrData operator wxCStrData() const { return c_str(); } // the first two operators conflict with operators for conversion to @@ -2067,16 +2117,16 @@ public: wxString Left(size_t nCount) const; // get last nCount characters wxString Right(size_t nCount) const; - // get all characters before the first occurance of ch + // get all characters before the first occurrence of ch // (returns the whole string if ch not found) wxString BeforeFirst(wxUniChar ch) const; - // get all characters before the last occurence of ch + // get all characters before the last occurrence of ch // (returns empty string if ch not found) wxString BeforeLast(wxUniChar ch) const; - // get all characters after the first occurence of ch + // get all characters after the first occurrence of ch // (returns empty string if ch not found) wxString AfterFirst(wxUniChar ch) const; - // get all characters after the last occurence of ch + // get all characters after the last occurrence of ch // (returns the whole string if ch not found) wxString AfterLast(wxUniChar ch) const; @@ -2141,7 +2191,7 @@ public: int Find(const wxWCharBuffer& sub) const { return Find(sub.data()); } - // replace first (or all of bReplaceAll) occurences of substring with + // replace first (or all of bReplaceAll) occurrences of substring with // another string, returns the number of replacements made size_t Replace(const wxString& strOld, const wxString& strNew, @@ -2964,7 +3014,7 @@ public: size_t find(const wxCStrData& s, size_t nStart = 0, size_t n = npos) const { return find(s.AsWChar(), nStart, n); } - // find the first occurence of character ch after nStart + // find the first occurrence of character ch after nStart size_t find(wxUniChar ch, size_t nStart = 0) const { #if wxUSE_UNICODE_UTF8 @@ -3030,7 +3080,7 @@ public: size_t rfind(wchar_t ch, size_t nStart = npos) const { return rfind(wxUniChar(ch), nStart); } - // find first/last occurence of any character (not) in the set: + // find first/last occurrence of any character (not) in the set: #if wxUSE_STL_BASED_WXSTRING && !wxUSE_UNICODE_UTF8 // FIXME-UTF8: this is not entirely correct, because it doesn't work if // sizeof(wchar_t)==2 and surrogates are present in the string; @@ -3121,7 +3171,7 @@ public: size_t find_last_of(wxUniChar c, size_t nStart = npos) const { return rfind(c, nStart); } - // find first/last occurence of any character not in the set + // find first/last occurrence of any character not in the set // as strspn() (starting from nStart), returns npos on failure size_t find_first_not_of(const wxString& str, size_t nStart = 0) const @@ -3555,7 +3605,7 @@ private: #endif // !wxUSE_STL_BASED_WXSTRING template -class WXDLLIMPEXP_BASE wxStringTypeBufferBase +class wxStringTypeBufferBase { public: typedef T CharType; @@ -3595,8 +3645,7 @@ protected: }; template -class WXDLLIMPEXP_BASE wxStringTypeBufferLengthBase - : public wxStringTypeBufferBase +class wxStringTypeBufferLengthBase : public wxStringTypeBufferBase { public: wxStringTypeBufferLengthBase(wxString& str, size_t lenWanted = 1024) @@ -3700,25 +3749,57 @@ typedef wxStringInternalBufferLength wxUTF8StringBufferLength; WXDLLIMPEXP_TEMPLATE_INSTANCE_BASE( wxStringTypeBufferBase ) -class WXDLLIMPEXP_BASE wxUTF8StringBuffer : public wxStringTypeBufferBase +// Note about inlined dtors in the classes below: this is done not for +// performance reasons but just to avoid linking errors in the MSVC DLL build +// under Windows: if a class has non-inline methods it must be declared as +// being DLL-exported but, due to an extremely interesting feature of MSVC 7 +// and later, any template class which is used as a base of a DLL-exported +// class is implicitly made DLL-exported too, as explained at the bottom of +// http://msdn.microsoft.com/en-us/library/twa2aw10.aspx (just to confirm: yes, +// _inheriting_ from a class can change whether it is being exported from DLL) +// +// But this results in link errors because the base template class is not DLL- +// exported, whether it is declared with WXDLLIMPEXP_BASE or not, because it +// does have only inline functions. So the simplest fix is to just make all the +// functions of these classes inline too. + +class wxUTF8StringBuffer : public wxStringTypeBufferBase { public: wxUTF8StringBuffer(wxString& str, size_t lenWanted = 1024) : wxStringTypeBufferBase(str, lenWanted) {} - ~wxUTF8StringBuffer(); + ~wxUTF8StringBuffer() + { + wxMBConvStrictUTF8 conv; + size_t wlen = conv.ToWChar(NULL, 0, m_buf); + wxCHECK_RET( wlen != wxCONV_FAILED, "invalid UTF-8 data in string buffer?" ); + + wxStringInternalBuffer wbuf(m_str, wlen); + conv.ToWChar(wbuf, wlen, m_buf); + } DECLARE_NO_COPY_CLASS(wxUTF8StringBuffer) }; WXDLLIMPEXP_TEMPLATE_INSTANCE_BASE( wxStringTypeBufferLengthBase ) -class WXDLLIMPEXP_BASE wxUTF8StringBufferLength - : public wxStringTypeBufferLengthBase +class wxUTF8StringBufferLength : public wxStringTypeBufferLengthBase { public: wxUTF8StringBufferLength(wxString& str, size_t lenWanted = 1024) : wxStringTypeBufferLengthBase(str, lenWanted) {} - ~wxUTF8StringBufferLength(); + ~wxUTF8StringBufferLength() + { + wxCHECK_RET(m_lenSet, "length not set"); + + wxMBConvStrictUTF8 conv; + size_t wlen = conv.ToWChar(NULL, 0, m_buf, m_len); + wxCHECK_RET( wlen != wxCONV_FAILED, "invalid UTF-8 data in string buffer?" ); + + wxStringInternalBufferLength wbuf(m_str, wlen); + conv.ToWChar(wbuf, wlen, m_buf, m_len); + wbuf.SetLength(wlen); + } DECLARE_NO_COPY_CLASS(wxUTF8StringBufferLength) }; @@ -3874,7 +3955,7 @@ inline wxCStrData::wxCStrData(const wxCStrData& data) inline wxCStrData::~wxCStrData() { if ( m_owned ) - delete wx_const_cast(wxString*, m_str); // cast to silence warnings + delete const_cast(m_str); // cast to silence warnings } // simple cases for AsChar() and AsWChar(), the complicated ones are @@ -3997,7 +4078,7 @@ void wxStringIteratorNode::DoSet(const wxString *str, if ( str ) { m_next = str->m_iterators.ptr; - wx_const_cast(wxString*, m_str)->m_iterators.ptr = this; + const_cast(m_str)->m_iterators.ptr = this; if ( m_next ) m_next->m_prev = this; } @@ -4014,7 +4095,7 @@ void wxStringIteratorNode::clear() if ( m_prev ) m_prev->m_next = m_next; else if ( m_str ) // first in the list - wx_const_cast(wxString*, m_str)->m_iterators.ptr = m_next; + const_cast(m_str)->m_iterators.ptr = m_next; m_next = m_prev = NULL; m_citer = NULL;