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
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)
// 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;
// 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
c->Reset();
// and remember the last used element
- ms_cache.lastUsed = c - cacheBegin;
+ LastUsedCacheElement() = c - cacheBegin;
}
return c;
// 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;
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; \
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;
// 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(); }
// 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);
}