]> git.saurik.com Git - wxWidgets.git/blobdiff - include/wx/string.h
in release builds gcc on osx evaporates these inlines if not WXEXPORTed
[wxWidgets.git] / include / wx / string.h
index 62b362b1ed9849a22b875bbddd526bb22bbd22ff..b66afd79ae384fa28d8111b058d6510ef696d17f 100644 (file)
@@ -594,8 +594,41 @@ private:
       unsigned lastUsed;
   };
 
+#ifndef wxHAS_COMPILER_TLS
+  // we must use an accessor function and not a static variable when the TLS
+  // variables support is implemented in the library (and not by the compiler)
+  // because the global s_cache variable could be not yet initialized when a
+  // ctor of another global object is executed and if that ctor uses any
+  // wxString methods, bad things happen
+  //
+  // however notice that this approach does not work when compiler TLS is used,
+  // at least not with g++ 4.1.2 under amd64 as it apparently compiles code
+  // using this accessor incorrectly when optimizations are enabled (-O2 is
+  // 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
+  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
+  friend struct wxStrCacheInitializer;
+#else // wxHAS_COMPILER_TLS
   static wxTLS_TYPE(Cache) ms_cache;
+  static Cache& GetCache() { return wxTLS_VALUE(ms_cache); }
+#endif // !wxHAS_COMPILER_TLS/wxHAS_COMPILER_TLS
+
+  static Cache::Element *GetCacheBegin() { return GetCache().cached; }
+  static Cache::Element *GetCacheEnd() { return GetCacheBegin() + Cache::SIZE; }
+  static unsigned& LastUsedCacheElement() { return GetCache().lastUsed; }
 
+  // this is used in debug builds only to provide a convenient function,
+  // callable from a debugger, to show the cache contents
   friend struct wxStrCacheDumper;
 
   // uncomment this to have access to some profiling statistics on program
@@ -616,7 +649,7 @@ private:
                lenhits; // number of cache hits in length()
   } ms_cacheStats;
 
-  friend struct ShowCacheStats;
+  friend struct wxStrCacheStatsDumper;
 
   #define wxCACHE_PROFILE_FIELD_INC(field) ms_cacheStats.field++
   #define wxCACHE_PROFILE_FIELD_ADD(field, val) ms_cacheStats.field += (val)
@@ -638,9 +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 = ms_cache.cached;
-            c != ms_cache.cached + Cache::SIZE;
-            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;
@@ -654,9 +693,9 @@ private:
   // its corresponding index in the byte string or not
   Cache::Element *GetCacheElement() const
   {
-      Cache::Element * const cacheBegin = ms_cache.cached;
-      Cache::Element * const cacheEnd = ms_cache.cached + Cache::SIZE;
-      Cache::Element * const cacheStart = cacheBegin + ms_cache.lastUsed;
+      Cache::Element * const cacheBegin = GetCacheBegin();
+      Cache::Element * const cacheEnd = GetCacheEnd();
+      Cache::Element * const cacheStart = cacheBegin + LastUsedCacheElement();
 
       // check the last used first, this does no (measurable) harm for a miss
       // but does help for simple loops addressing the same string all the time
@@ -679,7 +718,7 @@ private:
           c->Reset();
 
           // and remember the last used element
-          ms_cache.lastUsed = c - cacheBegin;
+          LastUsedCacheElement() = c - cacheBegin;
       }
 
       return c;
@@ -702,7 +741,9 @@ private:
       // used for length caching only so far, i.e. it doesn't count as a hit
       // from our point of view
       if ( cache->pos )
+      {
           wxCACHE_PROFILE_FIELD_INC(poshits);
+      }
 
       if ( pos == cache->pos )
           return cache->impl;
@@ -817,22 +858,26 @@ public:
   typedef size_t size_type;
   typedef wxUniChar const_reference;
 
-#if wxUSE_STL
+#if wxUSE_STD_STRING
   #if wxUSE_UNICODE_UTF8
     // random access is not O(1), as required by Random Access Iterator
     #define WX_STR_ITERATOR_TAG std::bidirectional_iterator_tag
   #else
     #define WX_STR_ITERATOR_TAG std::random_access_iterator_tag
   #endif
+  #define WX_DEFINE_ITERATOR_CATEGORY(cat) typedef cat iterator_category;
 #else
-  #define WX_STR_ITERATOR_TAG void /* dummy type */
+  // not defining iterator_category at all in this case is better than defining
+  // it as some dummy type -- at least it results in more intelligible error
+  // messages
+  #define WX_DEFINE_ITERATOR_CATEGORY(cat)
 #endif
 
   #define WX_STR_ITERATOR_IMPL(iterator_name, pointer_type, reference_type) \
       private:                                                              \
           typedef wxStringImpl::iterator_name underlying_iterator;          \
       public:                                                               \
-          typedef WX_STR_ITERATOR_TAG iterator_category;                    \
+          WX_DEFINE_ITERATOR_CATEGORY(WX_STR_ITERATOR_TAG)                  \
           typedef wxUniChar value_type;                                     \
           typedef int difference_type;                                      \
           typedef reference_type reference;                                 \
@@ -1067,7 +1112,7 @@ public:
   public:
       typedef T iterator_type;
 
-      typedef typename T::iterator_category iterator_category;
+      WX_DEFINE_ITERATOR_CATEGORY(typename T::iterator_category)
       typedef typename T::value_type value_type;
       typedef typename T::difference_type difference_type;
       typedef typename T::reference reference;
@@ -1413,12 +1458,7 @@ public:
     // truncate the string to given length
   wxString& Truncate(size_t uiLen);
     // empty string contents
-  void Empty()
-  {
-    Truncate(0);
-
-    wxASSERT_MSG( empty(), _T("string not empty after call to Empty()?") );
-  }
+  void Empty() { clear(); }
     // empty the string and free memory
   void Clear() { clear(); }
 
@@ -2899,8 +2939,13 @@ public:
   // swap two strings
   void swap(wxString& str)
   {
-      wxSTRING_INVALIDATE_CACHE();
-      str.wxSTRING_INVALIDATE_CACHE();
+#if wxUSE_STRING_POS_CACHE
+      // we modify not only this string but also the other one directly so we
+      // need to invalidate cache for both of them (we could also try to
+      // exchange their cache entries but it seems unlikely to be worth it)
+      InvalidateCache();
+      str.InvalidateCache();
+#endif // wxUSE_STRING_POS_CACHE
 
       m_impl.swap(str.m_impl);
   }