From 64a044d5a64dd92473b4cc666a6877db78bd37d3 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 8 Aug 2008 02:59:32 +0000 Subject: [PATCH] added wxTLS_TYPE() macro git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@55019 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- configure | 67 ++++- configure.in | 20 +- include/wx/msw/tls.h | 73 ++++++ include/wx/string.h | 538 ++++++++++++++++++++++++++++++--------- include/wx/tls.h | 72 ++++++ include/wx/unix/tls.h | 70 +++++ interface/wx/tls.h | 27 ++ setup.h.in | 4 + src/common/string.cpp | 6 + tests/benchmarks/tls.cpp | 17 ++ 10 files changed, 773 insertions(+), 121 deletions(-) create mode 100644 include/wx/msw/tls.h create mode 100644 include/wx/tls.h create mode 100644 include/wx/unix/tls.h create mode 100644 interface/wx/tls.h diff --git a/configure b/configure index 4c5ff6e6b0..8019ade16f 100755 --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Id: configure.in 54853 2008-07-30 15:48:24Z SC . +# From configure.in Id: configure.in 54996 2008-08-06 17:50:06Z VZ . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.61 for wxWidgets 2.9.0. # @@ -40135,13 +40135,76 @@ _ACEOF { echo "$as_me:$LINENO: WARNING: wxMutex won't be recursive on this platform" >&5 echo "$as_me: WARNING: wxMutex won't be recursive on this platform" >&2;} fi + fi + + { echo "$as_me:$LINENO: checking for __thread keyword" >&5 +echo $ECHO_N "checking for __thread keyword... $ECHO_C" >&6; } +if test "${wx_cv_cc___thread+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ + + static __thread int n = 0; + static __thread int *p = 0; + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + wx_cv_cc___thread=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + wx_cv_cc___thread=no + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ echo "$as_me:$LINENO: result: $wx_cv_cc___thread" >&5 +echo "${ECHO_T}$wx_cv_cc___thread" >&6; } + + if test "$wx_cv_cc___thread" = "yes"; then + cat >>confdefs.h <<\_ACEOF +#define HAVE___THREAD_KEYWORD 1 +_ACEOF + fi fi else if test "$wxUSE_THREADS" = "yes" ; then case "${host}" in - x86_64-*-mingw32* ) + x86_64-*-mingw32* ) ;; *-*-mingw32* ) { echo "$as_me:$LINENO: checking if compiler supports -mthreads" >&5 diff --git a/configure.in b/configure.in index 06d887710a..7e7c11a4e3 100644 --- a/configure.in +++ b/configure.in @@ -4985,13 +4985,31 @@ if test "$TOOLKIT" != "MSW" -a "$USE_OS2" != 1; then AC_MSG_WARN([wxMutex won't be recursive on this platform]) fi fi + + dnl test for compiler thread-specific variables support + AC_CACHE_CHECK([for __thread keyword], + wx_cv_cc___thread, + [ + AC_TRY_COMPILE([#include ], + [ + static __thread int n = 0; + static __thread int *p = 0; + ], + wx_cv_cc___thread=yes, + wx_cv_cc___thread=no + ) + ]) + + if test "$wx_cv_cc___thread" = "yes"; then + AC_DEFINE(HAVE___THREAD_KEYWORD) + fi fi dnl from if !MSW else if test "$wxUSE_THREADS" = "yes" ; then case "${host}" in - x86_64-*-mingw32* ) + x86_64-*-mingw32* ) ;; *-*-mingw32* ) dnl check if the compiler accepts -mthreads diff --git a/include/wx/msw/tls.h b/include/wx/msw/tls.h new file mode 100644 index 0000000000..e7dc94023e --- /dev/null +++ b/include/wx/msw/tls.h @@ -0,0 +1,73 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/tls.h +// Purpose: Win32 implementation of wxTlsValue<> +// Author: Vadim Zeitlin +// Created: 2008-08-08 +// RCS-ID: $Id$ +// Copyright: (c) 2008 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_MSW_TLS_H_ +#define _WX_MSW_TLS_H_ + +#include "wx/log.h" + +#include "wx/msw/wrapwin.h" + +// ---------------------------------------------------------------------------- +// wxTlsKey is a helper class encapsulating a TLS slot +// ---------------------------------------------------------------------------- + +class wxTlsKey +{ +public: + // ctor allocates a new key + wxTlsKey() + { + m_slot = ::TlsAlloc(); + if ( m_slot == TLS_OUT_OF_INDEXES ) + wxLogError("Creating TLS key failed"); + } + + // return true if the key was successfully allocated + bool IsOk() const { return m_slot != TLS_OUT_OF_INDEXES; } + + // get the key value, there is no error return + void *Get() const + { + return ::TlsGetValue(m_slot); + } + + // change the key value, return true if ok + bool Set(void *value) + { + if ( !::TlsSetValue(m_slot, value) ) + { + wxLogSysError(_("Failed to set TLS value")); + return false; + } + + return true; + } + + // free the key + ~wxTlsKey() + { + if ( IsOk() ) + { + if ( !::TlsFree(m_slot) ) + { + wxLogDebug("TlsFree() failed: %08x", ::GetLastError()); + } + } + } + +private: + DWORD m_slot; + + DECLARE_NO_COPY_CLASS(wxTlsKey) +}; + +#endif // _WX_MSW_TLS_H_ + diff --git a/include/wx/string.h b/include/wx/string.h index 35491795df..b72a312f45 100644 --- a/include/wx/string.h +++ b/include/wx/string.h @@ -508,6 +508,11 @@ private: static size_t LenToImpl(size_t len) { return len; } static size_t PosFromImpl(size_t pos) { return pos; } + // we don't want to define this as an empty inline function as it could + // result in noticeable (and quite unnecessary in non-UTF-8 build) slowdown + // in debug build where the inline functions are not effectively inlined + #define wxSTRING_INVALIDATE_INDEX_CACHE() + #else // wxUSE_UNICODE_UTF8 static wxCharBuffer ImplStr(const char* str, @@ -522,14 +527,63 @@ private: static SubstrBufFromWC ImplStr(const wchar_t* str, size_t n) { return ConvertStr(str, n, wxMBConvUTF8()); } + // this is an extremely simple cache used by PosToImpl() + struct PosToImplCache + { + const wxString *str; + size_t pos, + impl; + }; + + static PosToImplCache ms_cache; + size_t PosToImpl(size_t pos) const { if ( pos == 0 || pos == npos ) return pos; - else - return (begin() + pos).impl() - m_impl.begin(); + + PosToImplCache& cache = ms_cache; + if ( this == cache.str ) + { + if ( pos == cache.pos ) + return cache.impl; + + // TODO: is it worth complicating this function even further by going + // backwards from the last position? it might be if we're just + // before it... + if ( cache.pos > pos ) + { + cache.pos = + cache.impl = 0; + } + } + else // data for this string not cached + { + cache.str = this; + cache.pos = + cache.impl = 0; + } + + wxStringImpl::const_iterator i(m_impl.begin() + cache.impl); + for ( size_t n = cache.pos; n < pos; n++ ) + wxStringOperations::IncIter(i); + + cache.pos = pos; + return cache.impl = i - m_impl.begin(); } + void InvalidatePosToImplCache() + { + PosToImplCache& cache = ms_cache; + if ( cache.str == this ) + { + cache.pos = + cache.impl = 0; + } + } + + #define wxSTRING_INVALIDATE_INDEX_CACHE() InvalidatePosToImplCache() + void PosLenToImpl(size_t pos, size_t len, size_t *implPos, size_t *implLen) const; size_t LenToImpl(size_t len) const @@ -737,6 +791,10 @@ public: size_t IterToImplPos(wxString::iterator i) const { return wxStringImpl::const_iterator(i.impl()) - m_impl.begin(); } + iterator GetNthIter(size_t n) + { return iterator(this, m_impl.begin() + PosToImpl(n)); } + const_iterator GetNthIter(size_t n) const + { return const_iterator(this, m_impl.begin() + PosToImpl(n)); } #else // !wxUSE_UNICODE_UTF8 class WXDLLIMPEXP_BASE iterator @@ -788,6 +846,9 @@ public: const_iterator(const wxString *WXUNUSED(str), underlying_iterator ptr) : m_cur(ptr) {} }; + + iterator GetNthIter(size_t n) { return begin() + n; } + const_iterator GetNthIter(size_t n) const { return begin() + n; } #endif // wxUSE_UNICODE_UTF8/!wxUSE_UNICODE_UTF8 #undef WX_STR_ITERATOR_TAG @@ -1071,6 +1132,8 @@ public: #if wxUSE_UNICODE_UTF8 if ( nSize < len ) { + wxSTRING_INVALIDATE_INDEX_CACHE(); + // we can't use wxStringImpl::resize() for truncating the string as it // counts in bytes, not characters erase(nSize); @@ -1110,11 +1173,7 @@ public: wxASSERT_MSG( empty(), _T("string not empty after call to Empty()?") ); } // empty the string and free memory - void Clear() - { - wxString tmp(wxEmptyString); - swap(tmp); - } + void Clear() { clear(); } // contents test // Is an ascii value @@ -1127,17 +1186,32 @@ public: // data access (all indexes are 0 based) // read access wxUniChar at(size_t n) const - { return *(begin() + n); } // FIXME-UTF8: optimize? + { return wxStringOperations::DecodeChar(m_impl.begin() + PosToImpl(n)); } wxUniChar GetChar(size_t n) const { return at(n); } // read/write access wxUniCharRef at(size_t n) - { return *(begin() + n); } // FIXME-UTF8: optimize? + { return *GetNthIter(n); } wxUniCharRef GetWritableChar(size_t n) { return at(n); } // write access - void SetChar(size_t n, wxUniChar ch) - { at(n) = ch; } + void SetChar(size_t n, wxUniChar ch) + { + wxUniCharRef ref(at(n)); + +#if wxUSE_UNICODE_UTF8 + // if the new character takes the same number of bytes as the old one, + // we can avoid invalidating the index cache and it's an important case + // as it is exercised by a simple for loop using indices + if ( wxStringOperations::GetUtf8CharLength(ref) + != wxStringOperations::GetUtf8CharLength(ch) ) + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + } +#endif // wxUSE_UNICODE_UTF8 + + ref = ch; + } // get last character wxUniChar Last() const @@ -1426,20 +1500,33 @@ public: // overloaded assignment // from another wxString wxString& operator=(const wxString& stringSrc) - { if (&stringSrc != this) m_impl = stringSrc.m_impl; return *this; } + { + if ( this != &stringSrc ) + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + m_impl = stringSrc.m_impl; + } + + return *this; + } + wxString& operator=(const wxCStrData& cstr) { return *this = cstr.AsString(); } // from a character wxString& operator=(wxUniChar ch) { + wxSTRING_INVALIDATE_INDEX_CACHE(); + #if wxUSE_UNICODE_UTF8 if ( !ch.IsAscii() ) m_impl = wxStringOperations::EncodeChar(ch); else -#endif +#endif // wxUSE_UNICODE_UTF8 m_impl = (wxStringCharType)ch; return *this; } + wxString& operator=(wxUniCharRef ch) { return operator=((wxUniChar)ch); } wxString& operator=(char ch) @@ -1452,15 +1539,48 @@ public: // so we need to compensate in that case #if wxUSE_STL_BASED_WXSTRING wxString& operator=(const char *psz) - { if (psz) m_impl = ImplStr(psz); else Clear(); return *this; } + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + if ( psz ) + m_impl = ImplStr(psz); + else + clear(); + + return *this; + } + wxString& operator=(const wchar_t *pwz) - { if (pwz) m_impl = ImplStr(pwz); else Clear(); return *this; } -#else + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + if ( pwz ) + m_impl = ImplStr(pwz); + else + clear(); + + return *this; + } +#else // !wxUSE_STL_BASED_WXSTRING wxString& operator=(const char *psz) - { m_impl = ImplStr(psz); return *this; } + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + m_impl = ImplStr(psz); + + return *this; + } + wxString& operator=(const wchar_t *pwz) - { m_impl = ImplStr(pwz); return *this; } -#endif + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + m_impl = ImplStr(pwz); + + return *this; + } +#endif // wxUSE_STL_BASED_WXSTRING/!wxUSE_STL_BASED_WXSTRING + wxString& operator=(const unsigned char *psz) { return operator=((const char*)psz); } @@ -1600,7 +1720,7 @@ public: const wxChar *fmt = _T("%") wxLongLongFmtSpec _T("u"); return (*this) << Format(fmt , ull); } -#endif +#endif // wxLongLong_t && !wxLongLongIsLong // insert a float into string wxString& operator<<(float f) { return (*this) << Format(_T("%f"), f); } @@ -1875,7 +1995,7 @@ public: #endif // wxNEEDS_WXSTRING_PRINTF_MIXIN // use Cmp() - inline int CompareTo(const wxChar* psz, caseCompare cmp = exact) const + int CompareTo(const wxChar* psz, caseCompare cmp = exact) const { return cmp == exact ? Cmp(psz) : CmpNoCase(psz); } // use length() @@ -2020,36 +2140,71 @@ public: // same as `this_string = str' wxString& assign(const wxString& str) - { m_impl = str.m_impl; return *this; } + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + m_impl = str.m_impl; + + return *this; + } + wxString& assign(const wxString& str, size_t len) { - m_impl.assign(str.m_impl, 0, str.LenToImpl(len)); - return *this; + wxSTRING_INVALIDATE_INDEX_CACHE(); + + m_impl.assign(str.m_impl, 0, str.LenToImpl(len)); + + return *this; } + // same as ` = str[pos..pos + n] wxString& assign(const wxString& str, size_t pos, size_t n) { - size_t from, len; - str.PosLenToImpl(pos, n, &from, &len); - m_impl.assign(str.m_impl, from, len); - return *this; + wxSTRING_INVALIDATE_INDEX_CACHE(); + + size_t from, len; + str.PosLenToImpl(pos, n, &from, &len); + m_impl.assign(str.m_impl, from, len); + return *this; } + // same as `= first n (or all if n == npos) characters of sz' wxString& assign(const char *sz) - { m_impl.assign(ImplStr(sz)); return *this; } + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + m_impl.assign(ImplStr(sz)); + + return *this; + } + wxString& assign(const wchar_t *sz) - { m_impl.assign(ImplStr(sz)); return *this; } + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + m_impl.assign(ImplStr(sz)); + + return *this; + } + wxString& assign(const char *sz, size_t n) { - SubstrBufFromMB str(ImplStr(sz, n)); - m_impl.assign(str.data, str.len); - return *this; + wxSTRING_INVALIDATE_INDEX_CACHE(); + + SubstrBufFromMB str(ImplStr(sz, n)); + m_impl.assign(str.data, str.len); + + return *this; } + wxString& assign(const wchar_t *sz, size_t n) { - SubstrBufFromWC str(ImplStr(sz, n)); - m_impl.assign(str.data, str.len); - return *this; + wxSTRING_INVALIDATE_INDEX_CACHE(); + + SubstrBufFromWC str(ImplStr(sz, n)); + m_impl.assign(str.data, str.len); + + return *this; } wxString& assign(const wxCStrData& str) @@ -2068,6 +2223,8 @@ public: // same as `= n copies of ch' wxString& assign(size_t n, wxUniChar ch) { + wxSTRING_INVALIDATE_INDEX_CACHE(); + #if wxUSE_UNICODE_UTF8 if ( !ch.IsAscii() ) m_impl.assign(wxStringOperations::EncodeNChars(n, ch)); @@ -2088,7 +2245,13 @@ public: // assign from first to last wxString& assign(const_iterator first, const_iterator last) - { m_impl.assign(first.impl(), last.impl()); return *this; } + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + m_impl.assign(first.impl(), last.impl()); + + return *this; + } #if WXWIN_COMPATIBILITY_STRING_PTR_AS_ITER wxString& assign(const char *first, const char *last) { return assign(first, last - first); } @@ -2121,35 +2284,61 @@ public: // insert another string wxString& insert(size_t nPos, const wxString& str) - { insert(begin() + nPos, str.begin(), str.end()); return *this; } + { insert(GetNthIter(nPos), str.begin(), str.end()); return *this; } // insert n chars of str starting at nStart (in str) wxString& insert(size_t nPos, const wxString& str, size_t nStart, size_t n) { - size_t from, len; - str.PosLenToImpl(nStart, n, &from, &len); - m_impl.insert(PosToImpl(nPos), str.m_impl, from, len); - return *this; + wxSTRING_INVALIDATE_INDEX_CACHE(); + + size_t from, len; + str.PosLenToImpl(nStart, n, &from, &len); + m_impl.insert(PosToImpl(nPos), str.m_impl, from, len); + + return *this; } + // insert first n (or all if n == npos) characters of sz wxString& insert(size_t nPos, const char *sz) - { m_impl.insert(PosToImpl(nPos), ImplStr(sz)); return *this; } + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + m_impl.insert(PosToImpl(nPos), ImplStr(sz)); + + return *this; + } + wxString& insert(size_t nPos, const wchar_t *sz) - { m_impl.insert(PosToImpl(nPos), ImplStr(sz)); return *this; } + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + m_impl.insert(PosToImpl(nPos), ImplStr(sz)); return *this; + } + wxString& insert(size_t nPos, const char *sz, size_t n) { - SubstrBufFromMB str(ImplStr(sz, n)); - m_impl.insert(PosToImpl(nPos), str.data, str.len); - return *this; + wxSTRING_INVALIDATE_INDEX_CACHE(); + + SubstrBufFromMB str(ImplStr(sz, n)); + m_impl.insert(PosToImpl(nPos), str.data, str.len); + + return *this; } + wxString& insert(size_t nPos, const wchar_t *sz, size_t n) { - SubstrBufFromWC str(ImplStr(sz, n)); - m_impl.insert(PosToImpl(nPos), str.data, str.len); - return *this; + wxSTRING_INVALIDATE_INDEX_CACHE(); + + SubstrBufFromWC str(ImplStr(sz, n)); + m_impl.insert(PosToImpl(nPos), str.data, str.len); + + return *this; } + // insert n copies of ch wxString& insert(size_t nPos, size_t n, wxUniChar ch) { + wxSTRING_INVALIDATE_INDEX_CACHE(); + #if wxUSE_UNICODE_UTF8 if ( !ch.IsAscii() ) m_impl.insert(PosToImpl(nPos), wxStringOperations::EncodeNChars(n, ch)); @@ -2158,8 +2347,11 @@ public: m_impl.insert(PosToImpl(nPos), n, (wxStringCharType)ch); return *this; } + iterator insert(iterator it, wxUniChar ch) { + wxSTRING_INVALIDATE_INDEX_CACHE(); + #if wxUSE_UNICODE_UTF8 if ( !ch.IsAscii() ) { @@ -2171,8 +2363,14 @@ public: #endif return iterator(this, m_impl.insert(it.impl(), (wxStringCharType)ch)); } + void insert(iterator it, const_iterator first, const_iterator last) - { m_impl.insert(it.impl(), first.impl(), last.impl()); } + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + m_impl.insert(it.impl(), first.impl(), last.impl()); + } + #if WXWIN_COMPATIBILITY_STRING_PTR_AS_ITER void insert(iterator it, const char *first, const char *last) { insert(it - begin(), first, last - first); } @@ -2184,6 +2382,8 @@ public: void insert(iterator it, size_type n, wxUniChar ch) { + wxSTRING_INVALIDATE_INDEX_CACHE(); + #if wxUSE_UNICODE_UTF8 if ( !ch.IsAscii() ) m_impl.insert(IterToImplPos(it), wxStringOperations::EncodeNChars(n, ch)); @@ -2195,139 +2395,225 @@ public: // delete characters from nStart to nStart + nLen wxString& erase(size_type pos = 0, size_type n = npos) { - size_t from, len; - PosLenToImpl(pos, n, &from, &len); - m_impl.erase(from, len); - return *this; + wxSTRING_INVALIDATE_INDEX_CACHE(); + + size_t from, len; + PosLenToImpl(pos, n, &from, &len); + m_impl.erase(from, len); + + return *this; } + // delete characters from first up to last iterator erase(iterator first, iterator last) - { return iterator(this, m_impl.erase(first.impl(), last.impl())); } + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + return iterator(this, m_impl.erase(first.impl(), last.impl())); + } + iterator erase(iterator first) - { return iterator(this, m_impl.erase(first.impl())); } + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + return iterator(this, m_impl.erase(first.impl())); + } #ifdef wxSTRING_BASE_HASNT_CLEAR void clear() { erase(); } #else - void clear() { m_impl.clear(); } + void clear() + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + m_impl.clear(); + } #endif // replaces the substring of length nLen starting at nStart wxString& replace(size_t nStart, size_t nLen, const char* sz) { - size_t from, len; - PosLenToImpl(nStart, nLen, &from, &len); - m_impl.replace(from, len, ImplStr(sz)); - return *this; + wxSTRING_INVALIDATE_INDEX_CACHE(); + + size_t from, len; + PosLenToImpl(nStart, nLen, &from, &len); + m_impl.replace(from, len, ImplStr(sz)); + + return *this; } + wxString& replace(size_t nStart, size_t nLen, const wchar_t* sz) { - size_t from, len; - PosLenToImpl(nStart, nLen, &from, &len); - m_impl.replace(from, len, ImplStr(sz)); - return *this; + wxSTRING_INVALIDATE_INDEX_CACHE(); + + size_t from, len; + PosLenToImpl(nStart, nLen, &from, &len); + m_impl.replace(from, len, ImplStr(sz)); + + return *this; } + // replaces the substring of length nLen starting at nStart wxString& replace(size_t nStart, size_t nLen, const wxString& str) { - size_t from, len; - PosLenToImpl(nStart, nLen, &from, &len); - m_impl.replace(from, len, str.m_impl); - return *this; + wxSTRING_INVALIDATE_INDEX_CACHE(); + + size_t from, len; + PosLenToImpl(nStart, nLen, &from, &len); + m_impl.replace(from, len, str.m_impl); + + return *this; } + // replaces the substring with nCount copies of ch wxString& replace(size_t nStart, size_t nLen, size_t nCount, wxUniChar ch) { - size_t from, len; - PosLenToImpl(nStart, nLen, &from, &len); + wxSTRING_INVALIDATE_INDEX_CACHE(); + + size_t from, len; + PosLenToImpl(nStart, nLen, &from, &len); #if wxUSE_UNICODE_UTF8 - if ( !ch.IsAscii() ) - m_impl.replace(from, len, wxStringOperations::EncodeNChars(nCount, ch)); - else + if ( !ch.IsAscii() ) + m_impl.replace(from, len, wxStringOperations::EncodeNChars(nCount, ch)); + else #endif - m_impl.replace(from, len, nCount, (wxStringCharType)ch); - return *this; + m_impl.replace(from, len, nCount, (wxStringCharType)ch); + + return *this; } + // replaces a substring with another substring wxString& replace(size_t nStart, size_t nLen, const wxString& str, size_t nStart2, size_t nLen2) { - size_t from, len; - PosLenToImpl(nStart, nLen, &from, &len); + wxSTRING_INVALIDATE_INDEX_CACHE(); - size_t from2, len2; - str.PosLenToImpl(nStart2, nLen2, &from2, &len2); + size_t from, len; + PosLenToImpl(nStart, nLen, &from, &len); - m_impl.replace(from, len, str.m_impl, from2, len2); - return *this; + size_t from2, len2; + str.PosLenToImpl(nStart2, nLen2, &from2, &len2); + + m_impl.replace(from, len, str.m_impl, from2, len2); + + return *this; } + // replaces the substring with first nCount chars of sz wxString& replace(size_t nStart, size_t nLen, const char* sz, size_t nCount) { - size_t from, len; - PosLenToImpl(nStart, nLen, &from, &len); + wxSTRING_INVALIDATE_INDEX_CACHE(); - SubstrBufFromMB str(ImplStr(sz, nCount)); + size_t from, len; + PosLenToImpl(nStart, nLen, &from, &len); - m_impl.replace(from, len, str.data, str.len); - return *this; + SubstrBufFromMB str(ImplStr(sz, nCount)); + + m_impl.replace(from, len, str.data, str.len); + + return *this; } + wxString& replace(size_t nStart, size_t nLen, const wchar_t* sz, size_t nCount) { - size_t from, len; - PosLenToImpl(nStart, nLen, &from, &len); + wxSTRING_INVALIDATE_INDEX_CACHE(); - SubstrBufFromWC str(ImplStr(sz, nCount)); + size_t from, len; + PosLenToImpl(nStart, nLen, &from, &len); - m_impl.replace(from, len, str.data, str.len); - return *this; + SubstrBufFromWC str(ImplStr(sz, nCount)); + + m_impl.replace(from, len, str.data, str.len); + + return *this; } + wxString& replace(size_t nStart, size_t nLen, const wxString& s, size_t nCount) { - size_t from, len; - PosLenToImpl(nStart, nLen, &from, &len); - m_impl.replace(from, len, s.m_impl.c_str(), s.LenToImpl(nCount)); - return *this; + wxSTRING_INVALIDATE_INDEX_CACHE(); + + size_t from, len; + PosLenToImpl(nStart, nLen, &from, &len); + m_impl.replace(from, len, s.m_impl.c_str(), s.LenToImpl(nCount)); + + return *this; } wxString& replace(iterator first, iterator last, const char* s) - { m_impl.replace(first.impl(), last.impl(), ImplStr(s)); return *this; } + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + m_impl.replace(first.impl(), last.impl(), ImplStr(s)); + + return *this; + } + wxString& replace(iterator first, iterator last, const wchar_t* s) - { m_impl.replace(first.impl(), last.impl(), ImplStr(s)); return *this; } + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + m_impl.replace(first.impl(), last.impl(), ImplStr(s)); + + return *this; + } + wxString& replace(iterator first, iterator last, const char* s, size_type n) { - SubstrBufFromMB str(ImplStr(s, n)); - m_impl.replace(first.impl(), last.impl(), str.data, str.len); - return *this; + wxSTRING_INVALIDATE_INDEX_CACHE(); + + SubstrBufFromMB str(ImplStr(s, n)); + m_impl.replace(first.impl(), last.impl(), str.data, str.len); + + return *this; } + wxString& replace(iterator first, iterator last, const wchar_t* s, size_type n) { - SubstrBufFromWC str(ImplStr(s, n)); - m_impl.replace(first.impl(), last.impl(), str.data, str.len); - return *this; + wxSTRING_INVALIDATE_INDEX_CACHE(); + + SubstrBufFromWC str(ImplStr(s, n)); + m_impl.replace(first.impl(), last.impl(), str.data, str.len); + + return *this; } + wxString& replace(iterator first, iterator last, const wxString& s) - { m_impl.replace(first.impl(), last.impl(), s.m_impl); return *this; } + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + m_impl.replace(first.impl(), last.impl(), s.m_impl); + + return *this; + } + wxString& replace(iterator first, iterator last, size_type n, wxUniChar ch) { + wxSTRING_INVALIDATE_INDEX_CACHE(); + #if wxUSE_UNICODE_UTF8 - if ( !ch.IsAscii() ) - m_impl.replace(first.impl(), last.impl(), - wxStringOperations::EncodeNChars(n, ch)); - else + if ( !ch.IsAscii() ) + m_impl.replace(first.impl(), last.impl(), + wxStringOperations::EncodeNChars(n, ch)); + else #endif - m_impl.replace(first.impl(), last.impl(), n, (wxStringCharType)ch); - return *this; + m_impl.replace(first.impl(), last.impl(), n, (wxStringCharType)ch); + + return *this; } + wxString& replace(iterator first, iterator last, const_iterator first1, const_iterator last1) { - m_impl.replace(first.impl(), last.impl(), first1.impl(), last1.impl()); - return *this; + wxSTRING_INVALIDATE_INDEX_CACHE(); + + m_impl.replace(first.impl(), last.impl(), first1.impl(), last1.impl()); + + return *this; } + wxString& replace(iterator first, iterator last, const char *first1, const char *last1) { replace(first, last, first1, last1 - first1); return *this; } @@ -2337,7 +2623,11 @@ public: // swap two strings void swap(wxString& str) - { m_impl.swap(str.m_impl); } + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + m_impl.swap(str.m_impl); + } // find a substring size_t find(const wxString& str, size_t nStart = 0) const @@ -2673,11 +2963,23 @@ private: #if !wxUSE_STL_BASED_WXSTRING // helpers for wxStringBuffer and wxStringBufferLength wxStringCharType *DoGetWriteBuf(size_t nLen) - { return m_impl.DoGetWriteBuf(nLen); } + { + return m_impl.DoGetWriteBuf(nLen); + } + void DoUngetWriteBuf() - { m_impl.DoUngetWriteBuf(); } + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + m_impl.DoUngetWriteBuf(); + } + void DoUngetWriteBuf(size_t nLen) - { m_impl.DoUngetWriteBuf(nLen); } + { + wxSTRING_INVALIDATE_INDEX_CACHE(); + + m_impl.DoUngetWriteBuf(nLen); + } #endif // !wxUSE_STL_BASED_WXSTRING #ifndef wxNEEDS_WXSTRING_PRINTF_MIXIN diff --git a/include/wx/tls.h b/include/wx/tls.h new file mode 100644 index 0000000000..9d1d6373b3 --- /dev/null +++ b/include/wx/tls.h @@ -0,0 +1,72 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/tls.h +// Purpose: Implementation of thread local storage +// Author: Vadim Zeitlin +// Created: 2008-08-08 +// RCS-ID: $Id$ +// Copyright: (c) 2008 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_TLS_H_ +#define _WX_TLS_H_ + +#include "wx/defs.h" + +// ---------------------------------------------------------------------------- +// check for compiler support of thread-specific variables +// ---------------------------------------------------------------------------- + +#ifdef HAVE___THREAD_KEYWORD + #define wxHAS_COMPILER_TLS + #define wxTHREAD_SPECIFIC_DECL __thread +#elif wxCHECK_VISUALC_VERSION(7) + #define wxHAS_COMPILER_TLS + #define wxTHREAD_SPECIFIC_DECL __declspec(thread) +#endif + +// ---------------------------------------------------------------------------- +// define wxTLS_TYPE() +// ---------------------------------------------------------------------------- + +#ifdef wxHAS_COMPILER_TLS + #define wxTLS_TYPE(T) wxTHREAD_SPECIFIC_DECL T +#else // !wxHAS_COMPILER_TLS + #ifdef __WXMSW__ + #include "wx/msw/tls.h" + #elif defined(__UNIX__) + #include "wx/unix/tls.h" + #else + // TODO: we could emulate TLS for such platforms... + #error Neither compiler nor OS support thread-specific variables. + #endif + + // wxTlsValue represents a thread-specific value of type T + template + class wxTlsValue + { + public: + typedef T ValueType; + + wxTlsValue() { *this = static_cast(0); } + + wxTlsValue& operator=(T value) + { + m_key.Set(wxUIntToPtr(value)); + + return *this; + } + + operator T() const { return wxPtrToUInt(m_key.Get()); } + + private: + wxTlsKey m_key; + + DECLARE_NO_COPY_TEMPLATE_CLASS(wxTlsValue, T) + }; + + #define wxTLS_TYPE(T) wxTlsValue +#endif // wxHAS_COMPILER_TLS/!wxHAS_COMPILER_TLS + +#endif // _WX_TLS_H_ + diff --git a/include/wx/unix/tls.h b/include/wx/unix/tls.h new file mode 100644 index 0000000000..776494d015 --- /dev/null +++ b/include/wx/unix/tls.h @@ -0,0 +1,70 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/unix/tls.h +// Purpose: Pthreads implementation of wxTlsValue<> +// Author: Vadim Zeitlin +// Created: 2008-08-08 +// RCS-ID: $Id$ +// Copyright: (c) 2008 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_UNIX_TLS_H_ +#define _WX_UNIX_TLS_H_ + +#include "wx/intl.h" +#include "wx/log.h" + +#include + +// ---------------------------------------------------------------------------- +// wxTlsKey is a helper class encapsulating the TLS value index +// ---------------------------------------------------------------------------- + +class wxTlsKey +{ +public: + // ctor allocates a new key + wxTlsKey() + { + int rc = pthread_key_create(&m_key, NULL); + if ( rc ) + wxLogSysError(_("Creating TLS key failed"), rc); + } + + // return true if the key was successfully allocated + bool IsOk() const { return m_key != 0; } + + // get the key value, there is no error return + void *Get() const + { + return pthread_getspecific(m_key); + } + + // change the key value, return true if ok + bool Set(void *value) + { + int rc = pthread_setspecific(m_key, value); + if ( rc ) + { + wxLogSysError(_("Failed to set TLS value")); + return false; + } + + return true; + } + + // free the key + ~wxTlsKey() + { + if ( IsOk() ) + pthread_key_delete(m_key); + } + +private: + pthread_key_t m_key; + + DECLARE_NO_COPY_CLASS(wxTlsKey) +}; + +#endif // _WX_UNIX_TLS_H_ + diff --git a/interface/wx/tls.h b/interface/wx/tls.h new file mode 100644 index 0000000000..6dcb387227 --- /dev/null +++ b/interface/wx/tls.h @@ -0,0 +1,27 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/tls.h +// Purpose: wxTLS_TYPE() +// Author: Vadim Zeitlin +// RCS-ID: $Id$ +// Licence: wxWindows license +///////////////////////////////////////////////////////////////////////////// + +/** + Macro to be used for thread-specific variables declarations. + + This macro can be used to define thread-specific variables of the specified + @a type. Such variables must be global or static. Example of use: + @code + struct PerThreadData + { + ... data which will be different for every thread ... + }; + + static wxTLS_TYPE(PerThreadData *) s_threadPtr; + @endcode + + Currently only types of size less than size of a pointer are supported. + This limitation will be lifted in the future. + */ +#define wxTLS_TYPE(type) + diff --git a/setup.h.in b/setup.h.in index ebec1d786a..498fd6f323 100644 --- a/setup.h.in +++ b/setup.h.in @@ -756,6 +756,10 @@ * Define if you have pthread_cleanup_push/pop() */ #undef wxHAVE_PTHREAD_CLEANUP +/* + * Define if compiler has __thread keyword. + */ +#undef HAVE___THREAD_KEYWORD /* compatibility */ /* diff --git a/src/common/string.cpp b/src/common/string.cpp index 16f764f44a..99f0f816a0 100644 --- a/src/common/string.cpp +++ b/src/common/string.cpp @@ -58,6 +58,10 @@ //According to STL _must_ be a -1 size_t const size_t wxString::npos = (size_t) -1; +#if wxUSE_UNICODE_UTF8 +wxString::PosToImplCache wxString::ms_cache; +#endif // wxUSE_UNICODE_UTF8 + // ---------------------------------------------------------------------------- // global functions // ---------------------------------------------------------------------------- @@ -1237,6 +1241,8 @@ size_t wxString::Replace(const wxString& strOld, wxCHECK_MSG( !strOld.empty(), 0, _T("wxString::Replace(): invalid parameter") ); + wxSTRING_INVALIDATE_INDEX_CACHE(); + size_t uiCount = 0; // count of replacements made // optimize the special common case: replacement of one character by diff --git a/tests/benchmarks/tls.cpp b/tests/benchmarks/tls.cpp index 213d3e87df..e9c780ed9a 100644 --- a/tests/benchmarks/tls.cpp +++ b/tests/benchmarks/tls.cpp @@ -10,6 +10,8 @@ #include "bench.h" +#include "wx/tls.h" + #if defined(__UNIX__) #define HAVE_PTHREAD #include @@ -171,3 +173,18 @@ BENCHMARK_FUNC(BoostTLS) } #endif // HAVE_BOOST_THREAD + +BENCHMARK_FUNC(wxTLS) +{ + static wxTLS_TYPE(int) s_global; + + for ( int n = 0; n < NUM_ITER; n++ ) + { + if ( n % 2 ) + s_global = 0; + else + s_global = n; + } + + return !s_global; +} -- 2.45.2