]> git.saurik.com Git - wxWidgets.git/commitdiff
added wxTLS_TYPE() macro
authorVadim Zeitlin <vadim@wxwidgets.org>
Fri, 8 Aug 2008 02:59:32 +0000 (02:59 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Fri, 8 Aug 2008 02:59:32 +0000 (02:59 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@55019 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

configure
configure.in
include/wx/msw/tls.h [new file with mode: 0644]
include/wx/string.h
include/wx/tls.h [new file with mode: 0644]
include/wx/unix/tls.h [new file with mode: 0644]
interface/wx/tls.h [new file with mode: 0644]
setup.h.in
src/common/string.cpp
tests/benchmarks/tls.cpp

index 4c5ff6e6b078ce714054a25cf077e8d689aaf8af..8019ade16f706facfae812b4d7723392cce524ef 100755 (executable)
--- 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 <pthread.h>
+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
index 06d887710a1270ce76fd5f3774ecdce8d7f2431b..7e7c11a4e36e5fd2560eeb7125cdb987ef7ef95b 100644 (file)
@@ -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 <pthread.h>],
+              [
+                  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 (file)
index 0000000..e7dc940
--- /dev/null
@@ -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 <vadim@wxwidgets.org>
+// 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_
+
index 35491795df1e0477311423a8784587d1271b9cd8..b72a312f45576726cbbeac7e8c1c24b99a3a3a27 100644 (file)
@@ -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 (file)
index 0000000..9d1d637
--- /dev/null
@@ -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 <vadim@wxwidgets.org>
+// 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<T> represents a thread-specific value of type T
+    template <typename T>
+    class wxTlsValue
+    {
+    public:
+        typedef T ValueType;
+
+        wxTlsValue() { *this = static_cast<T>(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<T>
+#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 (file)
index 0000000..776494d
--- /dev/null
@@ -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 <vadim@wxwidgets.org>
+// Licence:     wxWindows licence
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_UNIX_TLS_H_
+#define _WX_UNIX_TLS_H_
+
+#include "wx/intl.h"
+#include "wx/log.h"
+
+#include <pthread.h>
+
+// ----------------------------------------------------------------------------
+// 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 (file)
index 0000000..6dcb387
--- /dev/null
@@ -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)
+
index ebec1d786a8ace62f7890ea71ebafcff43941a0a..498fd6f323ba2453086858849616a4d25bcddf69 100644 (file)
  * Define if you have pthread_cleanup_push/pop()
  */
 #undef wxHAVE_PTHREAD_CLEANUP
+/*
+ * Define if compiler has __thread keyword.
+ */
+#undef HAVE___THREAD_KEYWORD
 
 /* compatibility */
 /*
index 16f764f44a1e50476759bc1abb308fda2ac9a3e9..99f0f816a0aec0de222384815eecdfbdde98ae61 100644 (file)
 //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
index 213d3e87df6301ced8169a8bab39e8e7e2549ae5..e9c780ed9a3e78bdc358382aa9fa37ed364a0e45 100644 (file)
@@ -10,6 +10,8 @@
 
 #include "bench.h"
 
+#include "wx/tls.h"
+
 #if defined(__UNIX__)
     #define HAVE_PTHREAD
     #include <pthread.h>
@@ -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;
+}