]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/string.cpp
Revised #ifndef WX_PRECOMP headers, added missing #include wx/wxcrtvararg.h
[wxWidgets.git] / src / common / string.cpp
index e68c7f03c0de6d5be491592661e754f45c317c86..595caf71257daa6259c51b4c006b22304f15a879 100644 (file)
 //According to STL _must_ be a -1 size_t
 const size_t wxString::npos = (size_t) -1;
 
+#if wxUSE_STRING_POS_CACHE
+
+#ifdef wxHAS_COMPILER_TLS
+
+wxTLS_TYPE(wxString::Cache) wxString::ms_cache;
+
+#else // !wxHAS_COMPILER_TLS
+
+struct wxStrCacheInitializer
+{
+    wxStrCacheInitializer()
+    {
+        // calling this function triggers s_cache initialization in it, and
+        // from now on it becomes safe to call from multiple threads
+        wxString::GetCache();
+    }
+};
+
+/*
+wxString::Cache& wxString::GetCache()
+{
+    static wxTLS_TYPE(Cache) s_cache;
+
+    return wxTLS_VALUE(s_cache);
+}
+*/
+
+static wxStrCacheInitializer gs_stringCacheInit;
+
+#endif // wxHAS_COMPILER_TLS/!wxHAS_COMPILER_TLS
+
+// gdb seems to be unable to display thread-local variables correctly, at least
+// not my 6.4.98 version under amd64, so provide this debugging helper to do it
+#ifdef __WXDEBUG__
+
+struct wxStrCacheDumper
+{
+    static void ShowAll()
+    {
+        puts("*** wxString cache dump:");
+        for ( unsigned n = 0; n < wxString::Cache::SIZE; n++ )
+        {
+            const wxString::Cache::Element&
+                c = wxString::GetCacheBegin()[n];
+
+            printf("\t%u%s\t%p: pos=(%lu, %lu), len=%ld\n",
+                   n,
+                   n == wxString::LastUsedCacheElement() ? " [*]" : "",
+                   c.str,
+                   (unsigned long)c.pos,
+                   (unsigned long)c.impl,
+                   (long)c.len);
+        }
+    }
+};
+
+void wxDumpStrCache() { wxStrCacheDumper::ShowAll(); }
+
+#endif // __WXDEBUG__
+
+#ifdef wxPROFILE_STRING_CACHE
+
+wxString::CacheStats wxString::ms_cacheStats;
+
+struct wxStrCacheStatsDumper
+{
+    ~wxStrCacheStatsDumper()
+    {
+        const wxString::CacheStats& stats = wxString::ms_cacheStats;
+
+        if ( stats.postot )
+        {
+            puts("*** wxString cache statistics:");
+            printf("\tTotal non-trivial calls to PosToImpl(): %u\n",
+                   stats.postot);
+            printf("\tHits %u (of which %u not used) or %.2f%%\n",
+                   stats.poshits,
+                   stats.mishits,
+                   100.*float(stats.poshits - stats.mishits)/stats.postot);
+            printf("\tAverage position requested: %.2f\n",
+                   float(stats.sumpos) / stats.postot);
+            printf("\tAverage offset after cached hint: %.2f\n",
+                   float(stats.sumofs) / stats.postot);
+        }
+
+        if ( stats.lentot )
+        {
+            printf("\tNumber of calls to length(): %u, hits=%.2f%%\n",
+                   stats.lentot, 100.*float(stats.lenhits)/stats.lentot);
+        }
+    }
+};
+
+static wxStrCacheStatsDumper s_showCacheStats;
+
+#endif // wxPROFILE_STRING_CACHE
+
+#endif // wxUSE_STRING_POS_CACHE
+
 // ----------------------------------------------------------------------------
 // global functions
 // ----------------------------------------------------------------------------
@@ -123,22 +222,30 @@ void wxString::PosLenToImpl(size_t pos, size_t len,
                             size_t *implPos, size_t *implLen) const
 {
     if ( pos == npos )
+    {
         *implPos = npos;
-    else
+    }
+    else // have valid start position
     {
-        const_iterator i = begin() + pos;
-        *implPos = wxStringImpl::const_iterator(i.impl()) - m_impl.begin();
+        const const_iterator b = GetIterForNthChar(pos);
+        *implPos = wxStringImpl::const_iterator(b.impl()) - m_impl.begin();
         if ( len == npos )
+        {
             *implLen = npos;
-        else
+        }
+        else // have valid length too
         {
-            // too large length is interpreted as "to the end of the string"
-            // FIXME-UTF8: verify this is the case in std::string, assert
-            // otherwise
-            if ( pos + len > length() )
-                len = length() - pos;
-
-            *implLen = (i + len).impl() - i.impl();
+            // we need to handle the case of length specifying a substring
+            // going beyond the end of the string, just as std::string does
+            const const_iterator e(end());
+            const_iterator i(b);
+            while ( len && i <= e )
+            {
+                ++i;
+                --len;
+            }
+
+            *implLen = i.impl() - b.impl();
         }
     }
 }
@@ -1237,29 +1344,60 @@ size_t wxString::Replace(const wxString& strOld,
     wxCHECK_MSG( !strOld.empty(), 0,
                  _T("wxString::Replace(): invalid parameter") );
 
+    wxSTRING_INVALIDATE_CACHE();
+
     size_t uiCount = 0;   // count of replacements made
 
-    size_t uiOldLen = strOld.length();
-    size_t uiNewLen = strNew.length();
+    // optimize the special common case: replacement of one character by
+    // another one (in UTF-8 case we can only do this for ASCII characters)
+    //
+    // benchmarks show that this special version is around 3 times faster
+    // (depending on the proportion of matching characters and UTF-8/wchar_t
+    // build)
+    if ( strOld.m_impl.length() == 1 && strNew.m_impl.length() == 1 )
+    {
+        const wxStringCharType chOld = strOld.m_impl[0],
+                               chNew = strNew.m_impl[0];
+
+        // this loop is the simplified version of the one below
+        for ( size_t pos = 0; ; )
+        {
+            pos = m_impl.find(chOld, pos);
+            if ( pos == npos )
+                break;
+
+            m_impl[pos++] = chNew;
 
-    for ( size_t dwPos = 0; dwPos < length(); )
+            uiCount++;
+
+            if ( !bReplaceAll )
+                break;
+        }
+    }
+    else // general case
     {
-        dwPos = find(strOld, dwPos);
-        if ( dwPos == npos )
-            break;
+        const size_t uiOldLen = strOld.m_impl.length();
+        const size_t uiNewLen = strNew.m_impl.length();
+
+        for ( size_t pos = 0; ; )
+        {
+            pos = m_impl.find(strOld.m_impl, pos);
+            if ( pos == npos )
+                break;
 
-        // replace this occurance of the old string with the new one
-        replace(dwPos, uiOldLen, strNew, uiNewLen);
+            // replace this occurrence of the old string with the new one
+            m_impl.replace(pos, uiOldLen, strNew.m_impl);
 
-        // move up pos past the string that was replaced
-        dwPos += uiNewLen;
+            // move up pos past the string that was replaced
+            pos += uiNewLen;
 
-        // increase replace count
-        ++uiCount;
+            // increase replace count
+            uiCount++;
 
-        // stop after the first one?
-        if ( !bReplaceAll )
-            break;
+            // stop after the first one?
+            if ( !bReplaceAll )
+                break;
+        }
     }
 
     return uiCount;
@@ -1334,6 +1472,20 @@ wxString& wxString::MakeLower()
   return *this;
 }
 
+wxString& wxString::MakeCapitalized()
+{
+    const iterator en = end();
+    iterator it = begin();
+    if ( it != en )
+    {
+        *it = (wxChar)wxToupper(*it);
+        for ( ++it; it != en; ++it )
+            *it = (wxChar)wxTolower(*it);
+    }
+
+    return *this;
+}
+
 // ---------------------------------------------------------------------------
 // trimming and padding
 // ---------------------------------------------------------------------------
@@ -1938,13 +2090,6 @@ int wxString::Freq(wxUniChar ch) const
     return count;
 }
 
-// convert to upper case, return the copy of the string
-wxString wxString::Upper() const
-{ wxString s(*this); return s.MakeUpper(); }
-
-// convert to lower case, return the copy of the string
-wxString wxString::Lower() const { wxString s(*this); return s.MakeLower(); }
-
 // ----------------------------------------------------------------------------
 // wxUTF8StringBuffer
 // ----------------------------------------------------------------------------
@@ -1973,3 +2118,19 @@ wxUTF8StringBufferLength::~wxUTF8StringBufferLength()
     wbuf.SetLength(wlen);
 }
 #endif // wxUSE_UNICODE_WCHAR
+
+// ----------------------------------------------------------------------------
+// wxCharBufferType<T>
+// ----------------------------------------------------------------------------
+
+#ifndef __VMS_BROKEN_TEMPLATES
+template<>
+#endif
+wxCharTypeBuffer<char>::Data
+wxCharTypeBuffer<char>::NullData(NULL);
+
+#ifndef __VMS_BROKEN_TEMPLATES
+template<>
+#endif
+wxCharTypeBuffer<wchar_t>::Data
+wxCharTypeBuffer<wchar_t>::NullData(NULL);