[SCM] WebKit Debian packaging branch, debian/unstable, updated. debian/1.1.15-1-40151-g37bb677

rjw rjw at 268f45cc-cd09-0410-ab3c-d52691b4dbfc
Sat Sep 26 06:32:52 UTC 2009


The following commit has been merged in the debian/unstable branch:
commit 5a0174d5c8e5d5fa8db7b16d186fa3719df0f0d7
Author: rjw <rjw at 268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Tue Aug 20 02:11:13 2002 +0000

            QString rewrite.  Much faster now.
            QString has an inline rep, QStringData, which
            has an inline character buffer.  reps are
            referenced indirectly via a handle.  inline
            reps are detached when necessary.  Typical
            stack based usage requires no allocations
            for small string.  Attempts are made to avoid
            costly conversions between ascii and unicode.
            Extensive diagnostics can be enable by
            defining QSTRING_DEBUG_ALLOCATIONS and calling
            _printQStringAllocationStatistics().
    
            There appear to be a few small lingering leaks
            that I need to track down.
    
            * WebCore-tests.exp:
    
            Added symbols for qstring-test.cpp.
    
            * khtml/css/cssstyleselector.cpp:
    
            Removed old string optimization hack.
    
            * kwq/KWQString.mm:
    
            Rewrite.
            (_isOnStack):
            (countInstance):
            (allocatedBuffers):
            (ALLOC_CHAR):
            (REALLOC_CHAR):
            (DELETE_CHAR):
            (ALLOC_QCHAR):
            (REALLOC_QCHAR):
            (DELETE_QCHAR):
            (_printQStringAllocationStatistics):
            (ucstrcmp):
            (ucstrncmp):
            (ucstrnicmp):
            (ok_in_base):
            (QStringData::QStringData):
            (QStringData::initialize):
            (QStringData::operator new):
            (QStringData::operator delete):
            (QString::makeSharedNullHandle):
            (QString::makeSharedNull):
            (QStringData::~QStringData):
            (QStringData::ascii):
            (QStringData::increaseAsciiSize):
            (QStringData::unicode):
            (QStringData::increaseUnicodeSize):
            (QStringData::makeAscii):
            (QStringData::makeUnicode):
            (QString::setBufferFromCFString):
            (QString::fromStringWithEncoding):
            (QString::fromCFMutableString):
            (QString::fromCFString):
            (QString::fromNSString):
            (QString::getCFMutableString):
            (QString::getNSString):
            (QString::~QString):
            (QString::QString):
            (QString::operator=):
            (QString::at):
            (QString::unicode):
            (QString::compare):
            (QString::startsWith):
            (QString::endsWith):
            (QString::latin1):
            (QString::isNull):
            (QString::find):
            (QString::findRev):
            (QString::contains):
            (QString::toShort):
            (QString::toUShort):
            (QString::toInt):
            (QString::toUInt):
            (QString::toLong):
            (QString::toULong):
            (QString::toDouble):
            (QString::findArg):
            (QString::arg):
            (QString::left):
            (QString::right):
            (QString::mid):
            (QString::copy):
            (QString::lower):
            (QString::stripWhiteSpace):
            (QString::simplifyWhiteSpace):
            (QString::deref):
            (QString::setUnicode):
            (QString::setLatin1):
            (QString::sprintf):
            (QString::append):
            (QString::insert):
            (QString::detachInternal):
            (QString::detach):
            (QString::remove):
            (QString::replace):
            (QString::forceUnicode):
            (QString::setLength):
            (QString::truncate):
            (QString::fill):
            (QString::operator+=):
            (QString::convertToQCString):
            (operator==):
            (QConstString::QConstString):
            (QConstString::~QConstString):
            (_initializeHandleNodeBlock):
            (_allocatePageNode):
            (_initializeHandleNodes):
            (_allocateNode):
            (allocateHandle):
            (freeHandle):
    
            * kwq/qt/qstring.h:
            Rewrite
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@1874 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog-2002-12-03 b/WebCore/ChangeLog-2002-12-03
index ce3b7b0..ece8e2f 100644
--- a/WebCore/ChangeLog-2002-12-03
+++ b/WebCore/ChangeLog-2002-12-03
@@ -1,3 +1,123 @@
+2002-08-19  Richard Williamson (Local)  <rjw at apple.com>
+
+        QString rewrite.  Much faster now.
+        QString has an inline rep, QStringData, which
+        has an inline character buffer.  reps are
+        referenced indirectly via a handle.  inline
+        reps are detached when necessary.  Typical
+        stack based usage requires no allocations
+        for small string.  Attempts are made to avoid
+        costly conversions between ascii and unicode.
+        Extensive diagnostics can be enable by
+        defining QSTRING_DEBUG_ALLOCATIONS and calling
+        _printQStringAllocationStatistics().
+        
+        There appear to be a few small lingering leaks
+        that I need to track down.
+        
+        * WebCore-tests.exp:
+        
+        Added symbols for qstring-test.cpp.
+        
+        * khtml/css/cssstyleselector.cpp:
+        
+        Removed old string optimization hack.
+        
+        * kwq/KWQString.mm:
+        
+        Rewrite.
+        (_isOnStack):
+        (countInstance):
+        (allocatedBuffers):
+        (ALLOC_CHAR):
+        (REALLOC_CHAR):
+        (DELETE_CHAR):
+        (ALLOC_QCHAR):
+        (REALLOC_QCHAR):
+        (DELETE_QCHAR):
+        (_printQStringAllocationStatistics):
+        (ucstrcmp):
+        (ucstrncmp):
+        (ucstrnicmp):
+        (ok_in_base):
+        (QStringData::QStringData):
+        (QStringData::initialize):
+        (QStringData::operator new):
+        (QStringData::operator delete):
+        (QString::makeSharedNullHandle):
+        (QString::makeSharedNull):
+        (QStringData::~QStringData):
+        (QStringData::ascii):
+        (QStringData::increaseAsciiSize):
+        (QStringData::unicode):
+        (QStringData::increaseUnicodeSize):
+        (QStringData::makeAscii):
+        (QStringData::makeUnicode):
+        (QString::setBufferFromCFString):
+        (QString::fromStringWithEncoding):
+        (QString::fromCFMutableString):
+        (QString::fromCFString):
+        (QString::fromNSString):
+        (QString::getCFMutableString):
+        (QString::getNSString):
+        (QString::~QString):
+        (QString::QString):
+        (QString::operator=):
+        (QString::at):
+        (QString::unicode):
+        (QString::compare):
+        (QString::startsWith):
+        (QString::endsWith):
+        (QString::latin1):
+        (QString::isNull):
+        (QString::find):
+        (QString::findRev):
+        (QString::contains):
+        (QString::toShort):
+        (QString::toUShort):
+        (QString::toInt):
+        (QString::toUInt):
+        (QString::toLong):
+        (QString::toULong):
+        (QString::toDouble):
+        (QString::findArg):
+        (QString::arg):
+        (QString::left):
+        (QString::right):
+        (QString::mid):
+        (QString::copy):
+        (QString::lower):
+        (QString::stripWhiteSpace):
+        (QString::simplifyWhiteSpace):
+        (QString::deref):
+        (QString::setUnicode):
+        (QString::setLatin1):
+        (QString::sprintf):
+        (QString::append):
+        (QString::insert):
+        (QString::detachInternal):
+        (QString::detach):
+        (QString::remove):
+        (QString::replace):
+        (QString::forceUnicode):
+        (QString::setLength):
+        (QString::truncate):
+        (QString::fill):
+        (QString::operator+=):
+        (QString::convertToQCString):
+        (operator==):
+        (QConstString::QConstString):
+        (QConstString::~QConstString):
+        (_initializeHandleNodeBlock):
+        (_allocatePageNode):
+        (_initializeHandleNodes):
+        (_allocateNode):
+        (allocateHandle):
+        (freeHandle):
+        
+        * kwq/qt/qstring.h:
+        Rewrite
+        
 2002-08-19  Maciej Stachowiak  <mjs at apple.com>
 
         * Makefile.am: Added new mechanism to clean only the objects that
diff --git a/WebCore/ChangeLog-2003-10-25 b/WebCore/ChangeLog-2003-10-25
index ce3b7b0..ece8e2f 100644
--- a/WebCore/ChangeLog-2003-10-25
+++ b/WebCore/ChangeLog-2003-10-25
@@ -1,3 +1,123 @@
+2002-08-19  Richard Williamson (Local)  <rjw at apple.com>
+
+        QString rewrite.  Much faster now.
+        QString has an inline rep, QStringData, which
+        has an inline character buffer.  reps are
+        referenced indirectly via a handle.  inline
+        reps are detached when necessary.  Typical
+        stack based usage requires no allocations
+        for small string.  Attempts are made to avoid
+        costly conversions between ascii and unicode.
+        Extensive diagnostics can be enable by
+        defining QSTRING_DEBUG_ALLOCATIONS and calling
+        _printQStringAllocationStatistics().
+        
+        There appear to be a few small lingering leaks
+        that I need to track down.
+        
+        * WebCore-tests.exp:
+        
+        Added symbols for qstring-test.cpp.
+        
+        * khtml/css/cssstyleselector.cpp:
+        
+        Removed old string optimization hack.
+        
+        * kwq/KWQString.mm:
+        
+        Rewrite.
+        (_isOnStack):
+        (countInstance):
+        (allocatedBuffers):
+        (ALLOC_CHAR):
+        (REALLOC_CHAR):
+        (DELETE_CHAR):
+        (ALLOC_QCHAR):
+        (REALLOC_QCHAR):
+        (DELETE_QCHAR):
+        (_printQStringAllocationStatistics):
+        (ucstrcmp):
+        (ucstrncmp):
+        (ucstrnicmp):
+        (ok_in_base):
+        (QStringData::QStringData):
+        (QStringData::initialize):
+        (QStringData::operator new):
+        (QStringData::operator delete):
+        (QString::makeSharedNullHandle):
+        (QString::makeSharedNull):
+        (QStringData::~QStringData):
+        (QStringData::ascii):
+        (QStringData::increaseAsciiSize):
+        (QStringData::unicode):
+        (QStringData::increaseUnicodeSize):
+        (QStringData::makeAscii):
+        (QStringData::makeUnicode):
+        (QString::setBufferFromCFString):
+        (QString::fromStringWithEncoding):
+        (QString::fromCFMutableString):
+        (QString::fromCFString):
+        (QString::fromNSString):
+        (QString::getCFMutableString):
+        (QString::getNSString):
+        (QString::~QString):
+        (QString::QString):
+        (QString::operator=):
+        (QString::at):
+        (QString::unicode):
+        (QString::compare):
+        (QString::startsWith):
+        (QString::endsWith):
+        (QString::latin1):
+        (QString::isNull):
+        (QString::find):
+        (QString::findRev):
+        (QString::contains):
+        (QString::toShort):
+        (QString::toUShort):
+        (QString::toInt):
+        (QString::toUInt):
+        (QString::toLong):
+        (QString::toULong):
+        (QString::toDouble):
+        (QString::findArg):
+        (QString::arg):
+        (QString::left):
+        (QString::right):
+        (QString::mid):
+        (QString::copy):
+        (QString::lower):
+        (QString::stripWhiteSpace):
+        (QString::simplifyWhiteSpace):
+        (QString::deref):
+        (QString::setUnicode):
+        (QString::setLatin1):
+        (QString::sprintf):
+        (QString::append):
+        (QString::insert):
+        (QString::detachInternal):
+        (QString::detach):
+        (QString::remove):
+        (QString::replace):
+        (QString::forceUnicode):
+        (QString::setLength):
+        (QString::truncate):
+        (QString::fill):
+        (QString::operator+=):
+        (QString::convertToQCString):
+        (operator==):
+        (QConstString::QConstString):
+        (QConstString::~QConstString):
+        (_initializeHandleNodeBlock):
+        (_allocatePageNode):
+        (_initializeHandleNodes):
+        (_allocateNode):
+        (allocateHandle):
+        (freeHandle):
+        
+        * kwq/qt/qstring.h:
+        Rewrite
+        
 2002-08-19  Maciej Stachowiak  <mjs at apple.com>
 
         * Makefile.am: Added new mechanism to clean only the objects that
diff --git a/WebCore/ChangeLog-2005-08-23 b/WebCore/ChangeLog-2005-08-23
index ce3b7b0..ece8e2f 100644
--- a/WebCore/ChangeLog-2005-08-23
+++ b/WebCore/ChangeLog-2005-08-23
@@ -1,3 +1,123 @@
+2002-08-19  Richard Williamson (Local)  <rjw at apple.com>
+
+        QString rewrite.  Much faster now.
+        QString has an inline rep, QStringData, which
+        has an inline character buffer.  reps are
+        referenced indirectly via a handle.  inline
+        reps are detached when necessary.  Typical
+        stack based usage requires no allocations
+        for small string.  Attempts are made to avoid
+        costly conversions between ascii and unicode.
+        Extensive diagnostics can be enable by
+        defining QSTRING_DEBUG_ALLOCATIONS and calling
+        _printQStringAllocationStatistics().
+        
+        There appear to be a few small lingering leaks
+        that I need to track down.
+        
+        * WebCore-tests.exp:
+        
+        Added symbols for qstring-test.cpp.
+        
+        * khtml/css/cssstyleselector.cpp:
+        
+        Removed old string optimization hack.
+        
+        * kwq/KWQString.mm:
+        
+        Rewrite.
+        (_isOnStack):
+        (countInstance):
+        (allocatedBuffers):
+        (ALLOC_CHAR):
+        (REALLOC_CHAR):
+        (DELETE_CHAR):
+        (ALLOC_QCHAR):
+        (REALLOC_QCHAR):
+        (DELETE_QCHAR):
+        (_printQStringAllocationStatistics):
+        (ucstrcmp):
+        (ucstrncmp):
+        (ucstrnicmp):
+        (ok_in_base):
+        (QStringData::QStringData):
+        (QStringData::initialize):
+        (QStringData::operator new):
+        (QStringData::operator delete):
+        (QString::makeSharedNullHandle):
+        (QString::makeSharedNull):
+        (QStringData::~QStringData):
+        (QStringData::ascii):
+        (QStringData::increaseAsciiSize):
+        (QStringData::unicode):
+        (QStringData::increaseUnicodeSize):
+        (QStringData::makeAscii):
+        (QStringData::makeUnicode):
+        (QString::setBufferFromCFString):
+        (QString::fromStringWithEncoding):
+        (QString::fromCFMutableString):
+        (QString::fromCFString):
+        (QString::fromNSString):
+        (QString::getCFMutableString):
+        (QString::getNSString):
+        (QString::~QString):
+        (QString::QString):
+        (QString::operator=):
+        (QString::at):
+        (QString::unicode):
+        (QString::compare):
+        (QString::startsWith):
+        (QString::endsWith):
+        (QString::latin1):
+        (QString::isNull):
+        (QString::find):
+        (QString::findRev):
+        (QString::contains):
+        (QString::toShort):
+        (QString::toUShort):
+        (QString::toInt):
+        (QString::toUInt):
+        (QString::toLong):
+        (QString::toULong):
+        (QString::toDouble):
+        (QString::findArg):
+        (QString::arg):
+        (QString::left):
+        (QString::right):
+        (QString::mid):
+        (QString::copy):
+        (QString::lower):
+        (QString::stripWhiteSpace):
+        (QString::simplifyWhiteSpace):
+        (QString::deref):
+        (QString::setUnicode):
+        (QString::setLatin1):
+        (QString::sprintf):
+        (QString::append):
+        (QString::insert):
+        (QString::detachInternal):
+        (QString::detach):
+        (QString::remove):
+        (QString::replace):
+        (QString::forceUnicode):
+        (QString::setLength):
+        (QString::truncate):
+        (QString::fill):
+        (QString::operator+=):
+        (QString::convertToQCString):
+        (operator==):
+        (QConstString::QConstString):
+        (QConstString::~QConstString):
+        (_initializeHandleNodeBlock):
+        (_allocatePageNode):
+        (_initializeHandleNodes):
+        (_allocateNode):
+        (allocateHandle):
+        (freeHandle):
+        
+        * kwq/qt/qstring.h:
+        Rewrite
+        
 2002-08-19  Maciej Stachowiak  <mjs at apple.com>
 
         * Makefile.am: Added new mechanism to clean only the objects that
diff --git a/WebCore/WebCore-tests.exp b/WebCore/WebCore-tests.exp
index 3f1241b..56492ad 100644
--- a/WebCore/WebCore-tests.exp
+++ b/WebCore/WebCore-tests.exp
@@ -299,3 +299,5 @@ __ZplPKcRK7QString
 __ZplRK5QSizeS1_
 __ZplRK6QPointS1_
 __ZplcRK7QString
+__ZNK7QString7compareERKS_
+__ZNK7QString10startsWithERKS_
diff --git a/WebCore/khtml/css/cssstyleselector.cpp b/WebCore/khtml/css/cssstyleselector.cpp
index 05728f4..51c0eae 100644
--- a/WebCore/khtml/css/cssstyleselector.cpp
+++ b/WebCore/khtml/css/cssstyleselector.cpp
@@ -78,13 +78,6 @@ enum PseudoState { PseudoUnknown, PseudoNone, PseudoLink, PseudoVisited};
 static PseudoState pseudoState;
 
 
-#ifdef APPLE_CHANGES
-#define OPTIMIZE_STRING_USAGE
-#ifdef OPTIMIZE_STRING_USAGE
-static CFMutableStringRef reuseableString = 0;
-#endif
-#endif
-
 CSSStyleSelector::CSSStyleSelector( DocumentImpl* doc, QString userStyleSheet, StyleSheetListImpl *styleSheets,
                                     const KURL &url, bool _strictParsing )
 {
@@ -642,11 +635,7 @@ static void checkPseudoState( DOM::ElementImpl *e )
 	pseudoState = PseudoNone;
 	return;
     }
-#if (defined(APPLE_CHANGES) && defined(OPTIMIZE_STRING_USAGE))
-    QString u = QString::gstring_toQString(&reuseableString, (UniChar *)(attr.unicode()), attr.length());
-#else
     QString u = attr.string();
-#endif
     if ( !u.contains("://") ) {
 	if ( u[0] == '/' )
 	    u = encodedurl->host + u;
@@ -754,13 +743,9 @@ bool CSSStyleSelector::checkOneSelector(DOM::CSSSelector *sel, DOM::ElementImpl
     }
     if(sel->match == CSSSelector::Pseudo)
     {
-#if (defined(APPLE_CHANGES) && defined(OPTIMIZE_STRING_USAGE))
-	const QString value = QString::gstring_toQString(&reuseableString, (UniChar *)(sel->value.unicode()), sel->value.length());
-#else
         // Pseudo elements. We need to check first child here. No dynamic pseudo
         // elements for the moment
 	const QString& value = sel->value.string();
-#endif
 //	kdDebug() << "CSSOrderedRule::pseudo " << value << endl;
 	if(value == "first-child") {
 	    // first-child matches the first child that is an element!
diff --git a/WebCore/kwq/KWQString.h b/WebCore/kwq/KWQString.h
index 8478e6e..a971e5b 100644
--- a/WebCore/kwq/KWQString.h
+++ b/WebCore/kwq/KWQString.h
@@ -264,6 +264,64 @@ inline bool operator<(char ch, QChar qc)
     return (uchar) ch < qc.c;
 }
 
+// Keep this struct to <= 46 bytes, that's what the system will allocate.
+// Will be rounded up even multiple of for, so we're stuck at 44.
+
+#define QS_INTERNAL_BUFFER_SIZE 20
+#define QS_INTERNAL_BUFFER_CHARS QS_INTERNAL_BUFFER_SIZE-1
+#define QS_INTERNAL_BUFFER_UCHARS QS_INTERNAL_BUFFER_SIZE/2
+
+struct QStringData {
+    // Uses shared null data.
+    QStringData();
+    void initialize();
+    
+    // No copy.
+    QStringData(QChar *u, uint l, uint m);
+    void initialize(QChar *u, uint l, uint m);
+    
+    // Copy bytes;
+    QStringData(const QChar *u, uint l);
+    void initialize(const QChar *u, uint l);
+
+    // Copy bytes;
+    QStringData(const char *u, uint l);
+    void initialize(const char *u, uint l);
+
+    ~QStringData();
+
+#ifdef QSTRING_DEBUG_ALLOCATIONS
+    void* operator new(size_t s);
+    void operator delete(void*p);
+#endif
+
+
+    inline void ref() { refCount++; }
+    inline void deref() { if (--refCount == 0 && _isHeapAllocated) delete this; }
+        
+    char *ascii();
+    char *makeAscii();
+    void increaseAsciiSize(uint size);
+
+    QChar *unicode();
+    QChar *makeUnicode();    
+    void increaseUnicodeSize(uint size);
+        
+    uint refCount;
+    uint _length;
+    mutable QChar *_unicode;
+    mutable char *_ascii;
+    uint _maxUnicode:29;
+    uint _isUnicodeInternal:1;
+    uint _isUnicodeValid:1;
+    uint _isHeapAllocated:1;	// Fragile, but the only way we can be sure the instance was
+                                // created with 'new'.
+    uint _maxAscii:30;
+    uint _isAsciiInternal:1;
+    uint _isAsciiValid:1;
+    char _internalBuffer[QS_INTERNAL_BUFFER_SIZE]; // Pad out to a (((size + 1) & ~15) + 14) size
+};
+
 class QString {
 public:
     static const QString null;
@@ -318,11 +376,13 @@ public:
     int find(const QRegExp &, int index=0) const;
 
     int findRev(char, int index=-1) const;
+    int findRev(const QString& str, int index, bool cs=true ) const;
     int findRev(const char *, int index=-1) const;
 
     int contains(char) const;
     int contains(const char *, bool cs=true) const;
     int contains(const QString &, bool cs=true) const;
+    int contains( QChar c, bool cs=true ) const;
 
     bool endsWith(const QString &) const;
 
@@ -346,6 +406,8 @@ public:
     static QString number(ulong);
     static QString number(double);
 
+    bool findArg(int& pos, int& len) const;
+    
     QString arg(const QString &, int width=0) const;
     QString arg(short, int width=0) const;
     QString arg(ushort, int width=0) const;
@@ -366,7 +428,7 @@ public:
     QString simplifyWhiteSpace() const;
 
     QString &setUnicode(const QChar *, uint);
-    QString &setLatin1(const char *);
+    QString &setLatin1(const char *, int len=-1);
 
     QString &setNum(short);
     QString &setNum(ushort);
@@ -384,6 +446,8 @@ public:
     QString &insert(uint, QChar);
     QString &insert(uint, char);
     QString &remove(uint, uint);
+    QString &replace( uint index, uint len, const QString &s );
+    //QString &replace( uint index, uint len, const QChar* s, uint slen );
     QString &replace(const QRegExp &, const QString &);
 
     void truncate(uint);
@@ -403,17 +467,31 @@ public:
     QString &operator+=(QChar);
     QString &operator+=(char);
 
+    void setBufferFromCFString(CFStringRef cfs);
+    
 private:
+    // Used by QConstString.
+    QString(QStringData *constData, bool /*dummy*/);
+    void detach();
+    void detachInternal();
+    void deref();
+    void forceUnicode();
+    void setLength( uint pos );
+
+    struct QStringData *data() const;
+    
     enum CacheType { CacheInvalid, CacheUnicode, CacheLatin1 };
 
-    void flushCache() const;
     QCString convertToQCString(CFStringEncoding) const;
-    ulong convertToNumber(bool *ok, int base, bool *neg) const;
-    QString leftRight(uint width, bool left) const;
     int compareToLatin1(const char *chs) const;
 
-    CFMutableStringRef s;
-    mutable void *cache;
+    struct QStringData **dataHandle;
+    struct QStringData internalData;
+    
+    static QStringData* shared_null;
+    static QStringData* makeSharedNull();
+    static QStringData**shared_null_handle;
+    static QStringData**makeSharedNullHandle();
 
     friend bool operator==(const QString &, const QString &);
     friend bool operator==(const QString &, const char *);
@@ -441,9 +519,7 @@ private:
 
     friend class QConstString;
     friend class QGDict;
-
-    void _copyIfNeededInternalString();
-
+    friend struct QStringData;
 };
 
 QString operator+(const QString &, const QString &);
@@ -454,9 +530,11 @@ QString operator+(const char *, const QString &);
 QString operator+(QChar, const QString &);
 QString operator+(char, const QString &);
 
+inline struct QStringData *QString::data() const { return *dataHandle; }
+
 inline uint QString::length() const
 {
-    return CFStringGetLength(s);
+    return data()->_length;
 }
 
 inline bool QString::isEmpty() const
@@ -464,21 +542,6 @@ inline bool QString::isEmpty() const
     return length() == 0;
 }
 
-inline int QString::compare(const QString &qs) const
-{
-    return CFStringCompare(s, qs.s, 0);
-}
-
-inline bool QString::startsWith(const QString &qs) const
-{
-    return CFStringHasPrefix(s, qs.s);
-}
-
-inline bool QString::endsWith(const QString &qs) const
-{
-    return CFStringHasSuffix(s, qs.s);
-}
-
 inline QString QString::fromLatin1(const char *chs)
 {
     return chs;
@@ -504,16 +567,6 @@ inline const QChar QString::operator[](int index) const
     return at(index);
 }
 
-inline CFMutableStringRef QString::getCFMutableString() const
-{
-    return s;
-}
-
-inline NSString *QString::getNSString() const
-{
-    return (NSString *)s;
-}
-
 inline bool operator==(const char *chs, const QString &qs)
 {
     return qs == chs;
@@ -597,6 +650,7 @@ inline bool operator>=(const char *chs, const QString &qs)
 class QConstString : private QString {
 public:
     QConstString(const QChar *, uint);
+    ~QConstString();
     const QString &string() const { return *this; }
 };
 
diff --git a/WebCore/kwq/KWQString.mm b/WebCore/kwq/KWQString.mm
index 6e53063..bd7417a 100644
--- a/WebCore/kwq/KWQString.mm
+++ b/WebCore/kwq/KWQString.mm
@@ -23,37 +23,665 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  */
 
-/*
-    This implementation uses CFMutableStringRefs as a rep for the actual
-    string data.  Reps may be shared between QString instances, and follow
-    a copy-on-write sematic.  If you change the implementation be sure to
-    copy the rep before calling any of the CF functions that might mutate
-    the string.
-*/
-
 #import <Foundation/Foundation.h>
 #import <kwqdebug.h>
 #import <qstring.h>
 #import <qregexp.h>
 #import <stdio.h>
 
-const QString QString::null;
+// Why can't I find this in a header anywhere?  It's too bad we have
+// to wire knowledge of allocation sizes, but it makes a huge diffence.
+extern "C" {
+int malloc_good_size(int size);
+}
+
+#define ALLOC_QCHAR_GOOD_SIZE(X) (malloc_good_size(X*sizeof(QChar))/sizeof(QChar))
+#define ALLOC_CHAR_GOOD_SIZE(X) (malloc_good_size(X))
+
+#ifdef QSTRING_DEBUG_ALLOCATIONS
+#import <pthread.h>
+#import <mach/mach_types.h>
+
+static CFMutableDictionaryRef _allocatedBuffers = 0;
+#define ALLOCATION_HISTOGRAM_SIZE 128
+static uint _allocationHistogram[ALLOCATION_HISTOGRAM_SIZE];
+
+static uint stackInstances = 0;
+static uint heapInstances = 0;
+static uint stringDataInstances = 0;
+static uint stringDataHeapInstances = 0;
+static uint stringDataDetachments = 0;
+static uint handleInstances = 0;
+
+static bool _isOnStack(void *ptr){
+    void *address;
+    size_t size;
+    pthread_t thisThread = pthread_self();
+    
+    size = pthread_get_stacksize_np(thisThread);
+    address = pthread_get_stackaddr_np(thisThread);
+    if (ptr >= (void *)(((char *)address) - size) &&
+        ptr <= address)
+        return true;
+    return false;
+}
+
+
+static void countInstance(void *ptr)
+{
+    if (_isOnStack(ptr))
+        stackInstances++;
+    else
+        heapInstances++;
+}
+
+static CFMutableDictionaryRef allocatedBuffers()
+{
+    if (_allocatedBuffers == 0){
+        for (int i = 0; i < ALLOCATION_HISTOGRAM_SIZE; i++)
+            _allocationHistogram[i] = 0;
+        _allocatedBuffers = CFDictionaryCreateMutable (kCFAllocatorDefault, 1024*8, NULL, NULL);
+    }
+    return _allocatedBuffers;
+}
+
+static char *ALLOC_CHAR(int n){
+    char *ptr = (char *)malloc(n);
+
+    CFDictionarySetValue (allocatedBuffers(), ptr, (void *)n);
+    
+    if (n >= ALLOCATION_HISTOGRAM_SIZE)
+        _allocationHistogram[ALLOCATION_HISTOGRAM_SIZE-1]++;
+    else
+        _allocationHistogram[n]++;
+    return ptr;
+}
+
+static char *REALLOC_CHAR(void *p, int n){
+    char *ptr = (char *)realloc(p, n);
+
+    CFDictionaryRemoveValue (allocatedBuffers(), p);
+    CFDictionarySetValue (allocatedBuffers(), ptr, (const void *)(n));
+    if (n >= ALLOCATION_HISTOGRAM_SIZE)
+        _allocationHistogram[ALLOCATION_HISTOGRAM_SIZE-1]++;
+    else
+        _allocationHistogram[n]++;
+    return ptr;
+}
+
+static void DELETE_CHAR(void *p)
+{
+    CFDictionaryRemoveValue (allocatedBuffers(), p);
+    free (p);
+}
+
+static QChar *ALLOC_QCHAR(int n){
+    size_t size = (sizeof(QChar)*( n ));
+    QChar *ptr = (QChar *)malloc(size);
+
+    CFDictionarySetValue (allocatedBuffers(), ptr, (const void *)size);
+    if (size >= ALLOCATION_HISTOGRAM_SIZE)
+        _allocationHistogram[ALLOCATION_HISTOGRAM_SIZE-1]++;
+    else
+        _allocationHistogram[size]++;
+    return ptr;
+}
+
+static QChar *REALLOC_QCHAR(void *p, int n){
+    size_t size = (sizeof(QChar)*( n ));
+    QChar *ptr = (QChar *)realloc(p, size);
+
+    CFDictionaryRemoveValue (allocatedBuffers(), p);
+    CFDictionarySetValue (allocatedBuffers(), ptr, (const void *)size);
+    if (size >= ALLOCATION_HISTOGRAM_SIZE)
+        _allocationHistogram[ALLOCATION_HISTOGRAM_SIZE-1]++;
+    else
+        _allocationHistogram[size]++;
+        
+    return ptr;
+}
+
+static void DELETE_QCHAR(void *p)
+{
+    CFDictionaryRemoveValue (allocatedBuffers(), p);
+    free (p);
+}
+
+void _printQStringAllocationStatistics()
+{
+    const void **values;
+    const void **keys;
+    int j, i, count;
+    int totalSize = 0;
+    int totalAllocations = 0;
+    
+    count = (int)CFDictionaryGetCount (allocatedBuffers());
+    values = (const void **)malloc (count*sizeof(void *));
+    keys = (const void **)malloc (count*sizeof(void *));
+
+    CFDictionaryGetKeysAndValues (allocatedBuffers(), keys, values);
+    printf ("Leaked strings:\n");
+    for (i = 0; i < count; i++){
+        char *cp = (char *)keys[i];
+        printf ("%04d:  0x%08x size %d \"", i, (unsigned int)keys[i], (unsigned int)values[i]);
+        for (j = 0; j < MIN ((int)values[i], 64); j++){
+            if (isprint(*cp))
+                putchar (*cp);
+            cp++;
+        }
+        printf ("\"\n");
+        totalSize += (int)values[i];
+    }
+    printf ("Total leak %d\n", totalSize);
+    
+    printf ("\nString size histogram:\n");
+    for (i = 0; i < ALLOCATION_HISTOGRAM_SIZE; i++){
+        if (_allocationHistogram[i])
+            printf ("[%d] = %d\n", i, _allocationHistogram[i]);
+        totalAllocations += _allocationHistogram[i];
+    }
+    printf ("Total allocations %d\n", totalAllocations);
+    
+    printf ("\nQString instance counts:\n");
+    printf ("QString stack allocated instances %d\n", stackInstances);
+    printf ("QString heap allocated instances %d\n", heapInstances);
+    printf ("QStringData instances %d\n", stringDataInstances);
+    printf ("QStringData heap allocated instances %d\n", stringDataHeapInstances);
+    printf ("QStringData detachments (copies) %d\n", stringDataDetachments);
+    printf ("QStringData handles %d\n", handleInstances);
+    
+    free(keys);
+    free(values);
+}
+#else
+
+#define ALLOC_CHAR( N ) (char*) malloc(N)
+#define REALLOC_CHAR( P, N ) realloc(P,N)
+#define DELETE_CHAR( P ) free(P)
+
+#define ALLOC_QCHAR( N ) (QChar*) malloc(sizeof(QChar)*( N ))
+#define REALLOC_QCHAR( P, N ) realloc(P,sizeof(QChar)*( N ))
+#define DELETE_QCHAR( P ) free( P )
+#endif // QSTRING_DEBUG_ALLOCATIONS
+
+#import <mach/vm_map.h>
+#import <mach/mach_init.h>
+
+static void *allocateHandle();
+static void freeHandle(void *free);
+
+#define IS_ASCII_QCHAR(C) (C > (QChar)0 && C < (QChar)0xff)
+
+static const int caseDelta = ('a' - 'A');
+#define ASCII_TO_LOWER (p)  ((p >= 'A' && p <= 'Z') ? (p + caseDelta) : p)
+
+#ifdef NDEBUG
+#define QSTRING_FAILURE(str_expr) {}
+#else
+#define QSTRING_FAILURE(str_expr) \
+    do { \
+        struct rlimit _rlimit = {RLIM_INFINITY, RLIM_INFINITY}; \
+        setrlimit(RLIMIT_CORE, &_rlimit); \
+            fprintf(stderr, "QSTRING FAILURE: (%s:%d %s) %s \n", __FILE__, __LINE__, __PRETTY_FUNCTION__, str_expr); \
+        raise(SIGQUIT); \
+    } while (0)
+#endif //NDEBUG
+
+
+// -------------------------------------------------------------------------
+// Utility functions
+// -------------------------------------------------------------------------
+
+static int ucstrcmp( const QString &as, const QString &bs )
+{
+    const QChar *a = as.unicode();
+    const QChar *b = bs.unicode();
+    if ( a == b )
+	return 0;
+    if ( a == 0 )
+	return 1;
+    if ( b == 0 )
+	return -1;
+    int l = QMIN(as.length(), bs.length());
+    while ( l-- && *a == *b )
+	a++,b++;
+    if ( l == -1 )
+	return ( as.length() - bs.length() );
+    return a->unicode() - b->unicode();
+}
+
+
+static int ucstrncmp( const QChar *a, const QChar *b, int l )
+{
+    while ( l-- && *a == *b )
+	a++,b++;
+    if ( l == -1 )
+	return 0;
+    return a->unicode() - b->unicode();
+}
+
+
+static int ucstrnicmp( const QChar *a, const QChar *b, int l )
+{
+    while ( l-- && a->lower() == b->lower() )
+	a++,b++;
+    if ( l == -1 )
+	return 0;
+    QChar al = a->lower();
+    QChar bl = b->lower();
+    return al.unicode() - bl.unicode();
+}
+
+
+static bool ok_in_base( QChar c, int base )
+{
+    if ( base <= 10 )
+	return c.isDigit() && c.digitValue() < base;
+    else
+	return c.isDigit() || (c >= 'a' && c < char('a' + base - 10))
+			   || (c >= 'A' && c < char('A' + base - 10));
+}
+
+
+
+// -------------------------------------------------------------------------
+// QStringData
+// -------------------------------------------------------------------------
+
+// FIXME, make constructor explicity take a 'copy' flag.
+// This can be used to hand off ownership of allocated data when detaching and
+// deleting QStrings.
+
+QStringData::QStringData() :
+	refCount(1), _length(0), _unicode(0), _ascii(0), _maxUnicode(QS_INTERNAL_BUFFER_UCHARS), _isUnicodeInternal(0), _isUnicodeValid(0), _isHeapAllocated(0), _maxAscii(QS_INTERNAL_BUFFER_CHARS), _isAsciiInternal(1), _isAsciiValid(1) 
+{ 
+#ifdef QSTRING_DEBUG_ALLOCATIONS
+    stringDataInstances++;
+#endif
+    _ascii = &_internalBuffer[0];
+    _internalBuffer[0] = 0;
+}
+
+void QStringData::initialize()
+{
+    refCount = 1;
+    _length = 0;
+    _unicode = 0;
+    _ascii = &_internalBuffer[0];
+    _maxUnicode = QS_INTERNAL_BUFFER_UCHARS;
+    _isUnicodeInternal = 0;
+    _isUnicodeValid = 0;
+    _maxAscii = QS_INTERNAL_BUFFER_CHARS;
+    _isAsciiInternal = 1;
+    _isAsciiValid = 1;
+    _internalBuffer[0] = 0;
+    _isHeapAllocated = 0;
+}
+
+// Dont' copy data.
+QStringData::QStringData(QChar *u, uint l, uint m) :
+	refCount(1), _length(l), _unicode(u), _ascii(0), _maxUnicode(m), _isUnicodeInternal(0), _isUnicodeValid(1), _isHeapAllocated(0), _maxAscii(QS_INTERNAL_BUFFER_CHARS), _isAsciiInternal(0), _isAsciiValid(0)
+{
+#ifdef QSTRING_DEBUG_ALLOCATIONS
+    stringDataInstances++;
+#endif
+}
+
+// Don't copy data.
+void QStringData::initialize(QChar *u, uint l, uint m)
+{
+    refCount = 1;
+    _length = l;
+    _unicode = u;
+    _ascii = 0;
+    _maxUnicode = m;
+    _isUnicodeInternal = 0;
+    _isUnicodeValid = 1;
+    _maxAscii = 0;
+    _isAsciiInternal = 0;
+    _isAsciiValid = 0;
+    _isHeapAllocated = 0;
+}
+
+// Copy data
+QStringData::QStringData(const QChar *u, uint l)
+{
+#ifdef QSTRING_DEBUG_ALLOCATIONS
+    stringDataInstances++;
+#endif
+    initialize (u, l);
+}
+
+#ifdef QSTRING_DEBUG_ALLOCATIONS
+void* QStringData::operator new(size_t s)
+{
+    stringDataHeapInstances++;
+    return malloc(s);
+}
+void QStringData::operator delete(void*p)
+{
+    return free(p);
+}
+
+#endif
+
+// Copy data
+void QStringData::initialize(const QChar *u, uint l)
+{
+    refCount = 1;
+    _length = l;
+    _ascii = 0;
+    _isUnicodeInternal = 0;
+    _isUnicodeValid = 1;
+    _maxAscii = 0;
+    _isAsciiInternal = 0;
+    _isAsciiValid = 0;
+    _isHeapAllocated = 0;
+
+    if (l > QS_INTERNAL_BUFFER_UCHARS){
+        _maxUnicode = ALLOC_QCHAR_GOOD_SIZE(l);
+        _unicode = ALLOC_QCHAR(_maxUnicode);
+        if (u)
+            memcpy(_unicode, u, l*sizeof(QChar));
+    }
+    else {
+        _unicode = (QChar *)&_internalBuffer[0];
+        _maxUnicode = QS_INTERNAL_BUFFER_UCHARS;
+        _isUnicodeInternal = 1;
+        if (u)
+            memcpy(_internalBuffer, u, l*sizeof(QChar));
+    }
+}
+
+
+// Copy data
+QStringData::QStringData(const char *a, uint l)
+{
+#ifdef QSTRING_DEBUG_ALLOCATIONS
+    stringDataInstances++;
+#endif
+    initialize(a, l);
+}
+
+
+// Copy data
+void QStringData::initialize(const char *a, uint l)
+{
+    refCount = 1;
+    _length = l;
+    _unicode = 0;
+    _isUnicodeInternal = 0;
+    _isUnicodeValid = 0;
+    _maxUnicode = 0;
+    _isAsciiInternal = 0;
+    _isAsciiValid = 1;
+    _isHeapAllocated = 0;
+
+    if (l > QS_INTERNAL_BUFFER_CHARS){
+        _maxAscii = ALLOC_CHAR_GOOD_SIZE(l+1);
+        _ascii = ALLOC_CHAR(_maxAscii);
+        if (a)
+            memcpy(_ascii, a, l*sizeof(char));
+        _ascii[l] = 0;
+    }
+    else {
+        _ascii = &_internalBuffer[0];
+        _maxAscii = QS_INTERNAL_BUFFER_CHARS;
+        _isAsciiInternal = 1;
+        if (a)
+            memcpy(_internalBuffer, a, l*sizeof(char));
+        _internalBuffer[l] = 0;
+    }
+}
+
+
+QStringData *QString::shared_null = 0;
+QStringData **QString::shared_null_handle = 0;
+QStringData **QString::makeSharedNullHandle()
+{
+    if (!shared_null_handle){
+        shared_null_handle = (QStringData **)allocateHandle();
+        *shared_null_handle = makeSharedNull();
+    }
+    return shared_null_handle;
+}
+
+QStringData* QString::makeSharedNull()
+{
+    if (!shared_null){
+        shared_null = new QStringData();
+        shared_null->ref();
+        shared_null->_length = 0;
+        shared_null->_maxAscii = 0;
+        shared_null->_maxUnicode = 0;
+        shared_null->_unicode = (QChar *)&shared_null->_internalBuffer[0]; 
+        shared_null->_isUnicodeValid = 1;   
+        shared_null->_isUnicodeInternal = 1;   
+    }
+    return shared_null;
+}
+
+QStringData::~QStringData()
+{
+    if (refCount != 0)
+        QSTRING_FAILURE ("deleting when refCount != 0\n");
+        
+    // Ack!  The destcructor will be called when the QString is deleted.
+    if ( _unicode && !_isUnicodeInternal )
+        DELETE_QCHAR (_unicode);
+    if ( _ascii && !_isAsciiInternal )
+        DELETE_CHAR (_ascii); 
+}
+
+
+inline char *QStringData::ascii()
+{
+    if (_isAsciiValid){
+        if (_isAsciiInternal)
+            return &_internalBuffer[0];
+        else
+            return _ascii;
+    }
+    else
+        return makeAscii();
+}
+
+
+void QStringData::increaseAsciiSize(uint size)
+{
+    if (this == QString::shared_null)
+        fprintf (stderr, "increaseAsciiSize!\n");
+        
+    uint newSize = (uint)ALLOC_CHAR_GOOD_SIZE(size);
+    char *prev = 0;
+    
+    if (!_isAsciiValid && _isUnicodeValid)
+        makeAscii();
+        
+    if (_ascii && !_isAsciiInternal)
+        prev = _ascii;
+        
+    if (_isAsciiValid){
+        if (_isAsciiInternal){
+            if (_length){
+                char *newAscii = ALLOC_CHAR(newSize);
+                memcpy (newAscii, _ascii, _length);
+                _ascii = newAscii;
+            }
+            else
+                _ascii = ALLOC_CHAR(newSize);
+        }
+        else {
+            _ascii = (char *)REALLOC_CHAR (_ascii, newSize);
+            prev = 0;
+        }
+    }
+    else
+        QSTRING_FAILURE ("invalid character cache\n");
+    
+    if (prev)
+        DELETE_CHAR(prev);
+        
+    _maxAscii = newSize;
+    _isAsciiValid = 1;
+    _isAsciiInternal = 0;
+    _isUnicodeValid = 0;
+}
+
+
+inline QChar *QStringData::unicode()
+{
+    if (_isUnicodeValid){
+        if (_isUnicodeInternal)
+            return (QChar *)_internalBuffer;
+        else
+            return _unicode;
+    }
+    else
+        return makeUnicode();
+}
+
+
+void QStringData::increaseUnicodeSize(uint size)
+{
+    if (this == QString::shared_null)
+        fprintf (stderr, "increaseUnicodeSize!\n");
+        
+    uint newSize = (uint)ALLOC_QCHAR_GOOD_SIZE(size);
+    QChar *prev = 0;
+    
+    if (!_isUnicodeValid && _isAsciiValid)
+        makeUnicode();
+
+    if (_unicode && !_isUnicodeInternal)
+        prev = _unicode;
+        
+    if (_isUnicodeValid){
+        if (_isUnicodeInternal){
+            QChar *newUni = ALLOC_QCHAR(newSize);
+            if (_length)
+                memcpy (newUni, _unicode, _length*sizeof(QChar));
+            _unicode = newUni;
+        }
+        else {
+            _unicode = (QChar *)REALLOC_QCHAR (_unicode, newSize);
+            prev = 0;
+        }
+    }
+    else
+        QSTRING_FAILURE ("invalid character cache\n");
+    
+    if (prev)
+        DELETE_QCHAR(prev);
+        
+    _maxUnicode = newSize;
+    _isUnicodeValid = 1;
+    _isUnicodeInternal = 0;
+    _isAsciiValid = 0;
+}
+
 
-static CFMutableStringRef
-getNullCFString()
+char *QStringData::makeAscii()
 {
-    static CFStringRef ref = CFSTR("");
-    CFRetain(ref);
-    return (CFMutableStringRef)ref;
+    if (this == QString::shared_null)
+        fprintf (stderr, "makeAscii!\n");
+        
+    uint newSize = ALLOC_CHAR_GOOD_SIZE(_length+1);
+
+    if (_isUnicodeValid){
+        QChar copyBuf[QS_INTERNAL_BUFFER_CHARS];
+        QChar *str;
+        
+        if (_ascii && !_isAsciiInternal)
+            DELETE_QCHAR(_ascii);
+            
+        if (_length < QS_INTERNAL_BUFFER_CHARS){
+            if (_isUnicodeInternal){
+                uint i = _length;
+                QChar *tp = &copyBuf[0], *fp = _unicode;
+                while (i--)
+                    *tp++ = *fp++;
+                str = &copyBuf[0];
+            }
+            else
+                str = _unicode;
+            _ascii = (char *)&_internalBuffer[0];
+            _isAsciiInternal = 1;
+        }
+        else {
+            _ascii = ALLOC_CHAR(newSize);
+            str = _unicode;
+            _isAsciiInternal = 0;
+        }
+
+        uint i = _length;
+        char *cp = _ascii;
+        while ( i-- )
+            *cp++ = *str++;
+        *cp = 0;
+    }
+    else if (!_isAsciiValid)
+        QSTRING_FAILURE("unicode character cache not valid\n");
+        
+    _maxAscii = newSize;
+    _isAsciiValid = 1;
+    _isUnicodeValid = 0;
+    return _ascii;
 }
 
-static const QChar *
-getNullQCharString()
+
+QChar *QStringData::makeUnicode()
 {
-    static QChar nullCharacter;
-    return &nullCharacter;
+    if (this == QString::shared_null)
+        fprintf (stderr, "makeUnicode!\n");
+        
+    uint newSize = ALLOC_QCHAR_GOOD_SIZE(_length);
+    
+    if (_isAsciiValid){
+        char copyBuf[QS_INTERNAL_BUFFER_CHARS];
+        char *str;
+        
+        if (_unicode && !_isUnicodeInternal)
+            DELETE_QCHAR(_unicode);
+            
+        if (_length <= QS_INTERNAL_BUFFER_UCHARS){
+            if (_isAsciiInternal){
+                uint i = _length;
+                char *tp = &copyBuf[0], *fp = _ascii;
+                while (i--)
+                    *tp++ = *fp++;
+                str = &copyBuf[0];
+            }
+            else
+                str = _ascii;
+            _unicode = (QChar *)&_internalBuffer[0];
+            _isUnicodeInternal = 1;
+        }
+        else {
+            _unicode = ALLOC_QCHAR(newSize);
+            str = _ascii;
+            _isUnicodeInternal = 0;
+        }
+        uint i = _length;
+        QChar *cp = _unicode;
+        while ( i-- )
+            *cp++ = *str++;
+    }
+    else if (!_isUnicodeValid)
+        QSTRING_FAILURE("invalid character cache\n");
+
+    _maxUnicode = newSize;
+    _isUnicodeValid = 1;
+    _isAsciiValid = 0;
+    return _unicode;
 }
 
+
+// -------------------------------------------------------------------------
+// QString
+// -------------------------------------------------------------------------
+
+
 QString QString::number(int n)
 {
     QString qs;
@@ -89,23 +717,35 @@ QString QString::number(double n)
     return qs;
 }
 
+void QString::setBufferFromCFString(CFStringRef cfs)
+{
+    CFIndex size = CFStringGetLength(cfs);
+    UniChar *buffer;
+    
+    buffer = (UniChar *)malloc (size * sizeof(UniChar));
+    CFStringGetCharacters (cfs, CFRangeMake (0, size), buffer);
+    setUnicode ((const QChar *)buffer, (uint)size);
+    free (buffer);
+}
+
 QString QString::fromStringWithEncoding(const char *chs, int len,
                                         CFStringEncoding encoding)
 {
     QString qs;
     if (chs && *chs) {
-        qs.s = CFStringCreateMutable(kCFAllocatorDefault, 0);
-        if (qs.s) {
+        CFMutableStringRef s = CFStringCreateMutable(kCFAllocatorDefault, 0);
+        if (s) {
             if (len < 0) {
                 // append null-terminated string
-                CFStringAppendCString(qs.s, chs, encoding);
+                CFStringAppendCString(s, chs, encoding);
             } else {
                 // append length-specified string
                 // FIXME: can we find some way of not using this temporary?
                 char *buf = (char *)CFAllocatorAllocate(kCFAllocatorDefault, len + 1, 0);
                 strncpy(buf, chs, len);
                 *(buf + len) = '\0';
-                CFStringAppendCString(qs.s, buf, encoding);
+                CFStringAppendCString(s, buf, encoding);
+                qs.setBufferFromCFString(s);
                 CFAllocatorDeallocate(kCFAllocatorDefault, buf);
             }
         }
@@ -116,140 +756,215 @@ QString QString::fromStringWithEncoding(const char *chs, int len,
 QString QString::fromCFMutableString(CFMutableStringRef cfs)
 {
     QString qs;
-    // shared copy
-    if (cfs) {
-        CFRetain(cfs);
-        qs.s = cfs;
-    }
+    qs.setBufferFromCFString(cfs);
     return qs;
 }
 
 QString QString::fromCFString(CFStringRef cfs)
 {
     QString qs;
-
-    qs.s = CFStringCreateMutableCopy(NULL, 0, cfs);
+    qs.setBufferFromCFString((CFStringRef)cfs);
     return qs;
 }
 
 QString QString::fromNSString(NSString *nss)
 {
     QString qs;
-
-    qs.s = CFStringCreateMutableCopy(NULL, 0, (CFStringRef)nss);
+    qs.setBufferFromCFString((CFStringRef)nss);
     return qs;
 }
 
-QString QString::gstring_toQString(CFMutableStringRef *ref, UniChar *uchars, int len)
+CFMutableStringRef QString::getCFMutableString() const
 {
-    if (*ref == 0)
-        *ref = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault, uchars, len, len, kCFAllocatorDefault);
+    CFMutableStringRef s = CFStringCreateMutable(kCFAllocatorDefault, 0);
+    if ((*dataHandle)->_isUnicodeValid)
+        CFStringAppendCharacters (s, (UniChar *)unicode(), (*dataHandle)->_length);
+    else if ((*dataHandle)->_isAsciiValid)
+        CFStringAppendCString (s, (const char *)ascii(), kCFStringEncodingISOLatin1);
     else
-        CFStringSetExternalCharactersNoCopy(*ref, uchars, len, len);
-    return QString::fromCFMutableString(*ref);
+        QSTRING_FAILURE ("invalid character cache\n");
+    return (CFMutableStringRef)[(NSString *)s autorelease];
 }
 
-CFMutableStringRef QString::gstring_toCFString(CFMutableStringRef *ref, UniChar *uchars, int len)
+NSString *QString::getNSString() const
 {
-    if (*ref == 0)
-        *ref = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault, uchars, len, len, kCFAllocatorDefault);
-    else
-        CFStringSetExternalCharactersNoCopy(*ref, uchars, len, len);
-    return *ref;
+    return (NSString *)getCFMutableString();
 }
 
+const QString QString::null;
+
+QString::~QString()
+{
+    bool needToFreeHandle = false;
+    struct QStringData *oldData = (*dataHandle);
+    struct QStringData **oldHandle = dataHandle;
+    
+    if (!oldHandle)
+        QSTRING_FAILURE ("QStringData == nil\n");
+        
+    if (oldData->refCount == 0)
+        QSTRING_FAILURE ("QStringData refCount == 0\n");
+
+    // Only free the handle if no other string has a reference to the
+    // data.  The handle will be freed by the string that has the
+    // last reference to data.
+    if (dataHandle != makeSharedNullHandle() && oldData->refCount == 1)
+        needToFreeHandle = true;
+
+    // Copy our internal data if necessary, other strings still need it.
+    detachInternal();
+    
+    // Remove our reference.  This should always be the last reference
+    // if *dataHandle points to our internal QStringData.
+    oldData->deref();
+
+    if (oldData == &internalData && oldData->refCount != 0)
+        QSTRING_FAILURE ("QStringData refCount != 0\n");
+    
+    if (needToFreeHandle)
+        freeHandle (oldHandle);
+
+    dataHandle = 0;
+}
+
+
 QString::QString()
 {
-    s = getNullCFString();
-    cache = NULL;
+#ifdef QSTRING_DEBUG_ALLOCATIONS
+    countInstance (&dataHandle);
+#endif
+    internalData.deref();
+    dataHandle = makeSharedNullHandle();
+    (*dataHandle)->ref();
 }
 
-QString::~QString()
+
+// Careful, just used by QConstString
+QString::QString(QStringData *constData, bool /*dummy*/) 
 {
-    CFRelease(s);
-    if (cache)
-        CFAllocatorDeallocate(kCFAllocatorDefault, cache);
+    internalData.deref();
+    dataHandle = (struct QStringData **)allocateHandle();
+    *dataHandle = constData;
+    
+    // The QConstString constructor allocated the QStringData.
+    constData->_isHeapAllocated = 1;
 }
 
+
 QString::QString(QChar qc)
 {
-    s = CFStringCreateMutable(kCFAllocatorDefault, 0);
-    CFStringAppendCharacters(s, &qc.c, 1);
-    cache = NULL;
+#ifdef QSTRING_DEBUG_ALLOCATIONS
+    countInstance (&dataHandle);
+#endif
+    dataHandle = (struct QStringData **)allocateHandle();
+
+    // Copy the QChar.
+    if (IS_ASCII_QCHAR(qc)){
+        char c = (char)qc; 
+        *dataHandle = &internalData;
+        internalData.initialize( &c, 1 );
+    }
+    else {
+        *dataHandle = &internalData;
+        internalData.initialize( &qc, 1 );
+    }
 }
 
 QString::QString(const QByteArray &qba)
 {
-    if (qba.size() && *qba.data()) {
-        CFStringRef tmp = CFStringCreateWithBytes
-            (kCFAllocatorDefault, (const UInt8 *) qba.data(), qba.size(),
-             kCFStringEncodingISOLatin1, false);
-        s = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, tmp);
-        CFRelease(tmp);
-    } else
-        s = getNullCFString();
-    cache = NULL;
+#ifdef QSTRING_DEBUG_ALLOCATIONS
+    countInstance (&dataHandle);
+#endif
+    dataHandle = (struct QStringData **)allocateHandle();
+
+    // Copy data
+    *dataHandle = &internalData;
+    internalData.initialize(qba.data(),qba.size());
 }
 
-QString::QString(const QChar *qcs, uint len)
+QString::QString(const QChar *unicode, uint length)
 {
-    if (qcs || len) {
-        s = CFStringCreateMutable(kCFAllocatorDefault, 0);
-        CFStringAppendCharacters(s, &qcs->c, len);
-    } else
-        s = getNullCFString();
-    cache = NULL;
+#ifdef QSTRING_DEBUG_ALLOCATIONS
+    countInstance (&dataHandle);
+#endif
+    if ( !unicode && !length ) {
+        internalData.deref();
+        dataHandle = makeSharedNullHandle();
+	(*dataHandle)->ref();
+    } else {
+        dataHandle = (struct QStringData **)allocateHandle();
+
+        // Copy the QChar *
+        *dataHandle = &internalData;
+	internalData.initialize(unicode, length);
+    }
 }
 
 QString::QString(const char *chs)
 {
-    if (chs && *chs) {
-        s = CFStringCreateMutable(kCFAllocatorDefault, 0);
-        CFStringAppendCString(s, chs, kCFStringEncodingISOLatin1);
-    } else
-        s = getNullCFString();
-    cache = NULL;
+#ifdef QSTRING_DEBUG_ALLOCATIONS
+    countInstance (&dataHandle);
+#endif
+    dataHandle = (struct QStringData **)allocateHandle();
+    *dataHandle = &internalData;
+
+    if (chs)
+        internalData.initialize(chs,strlen(chs));
+    else
+        internalData.initialize();
 }
 
 QString::QString(const char *chs, int len)
 {
-    if (len > 0) {
-        CFStringRef tmp = CFStringCreateWithBytes
-             (kCFAllocatorDefault, (const UInt8 *)chs, len,
-              kCFStringEncodingISOLatin1, false);
-        s = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, tmp);
-        CFRelease(tmp);
-    } else
-        s = getNullCFString();
-    cache = NULL;
+#ifdef QSTRING_DEBUG_ALLOCATIONS
+    countInstance (&dataHandle);
+#endif
+    dataHandle = (struct QStringData **)allocateHandle();
+    *dataHandle = &internalData;
+    internalData.initialize(chs,len);
 }
 
-QString::QString(const QString &qs)
+QString::QString(const QString &qs) : dataHandle(qs.dataHandle)
 {
-    // shared copy
-    CFRetain(qs.s);
-    s = qs.s;
-    cache = NULL;
+#ifdef QSTRING_DEBUG_ALLOCATIONS
+    countInstance (&dataHandle);
+#endif
+    internalData.deref();
+    (*dataHandle)->ref();
 }
 
 QString &QString::operator=(const QString &qs)
 {
-    // shared copy
-    CFRetain(qs.s);
-    CFRelease(s);
-    s = qs.s;
-    flushCache();
+    bool needToFreeHandle = false;
+    
+    if (this == &qs)
+        return *this;
+
+    // free our handle if it isn't the shared
+    // null handle, and if no-one else is using
+    // it.
+    if (dataHandle != makeSharedNullHandle() && (*dataHandle)->refCount == 1)
+        needToFreeHandle = true;
+    
+    qs.data()->ref();
+    deref();
+    
+    if (needToFreeHandle)
+        freeHandle (dataHandle);
+        
+    dataHandle = qs.dataHandle;
+
     return *this;
 }
 
 QString &QString::operator=(const QCString &qcs)
 {
-    return *this = QString(qcs);
+    return setLatin1(qcs);
 }
 
 QString &QString::operator=(const char *chs)
 {
-    return *this = QString(chs);
+    return setLatin1(chs);
 }
 
 QString &QString::operator=(QChar qc)
@@ -262,55 +977,82 @@ QString &QString::operator=(char ch)
     return *this = QString(QChar(ch));
 }
 
-QChar QString::at(uint index) const
+inline QChar QString::at(uint i) const
 {
-    CFIndex signedIndex = index;
-    CFIndex len = CFStringGetLength(s);
-    if (signedIndex < len)
-        return CFStringGetCharacterAtIndex(s, signedIndex);
-    return 0;
+    QStringData *thisData = (*dataHandle);
+    
+    if (i >= thisData->_length)
+        return QChar::null;
+        
+    if (thisData->_isAsciiValid){
+        if (thisData->_isAsciiInternal)
+            return QChar(thisData->_internalBuffer[i]);
+        else
+            return QChar(thisData->_ascii[i]);
+    }
+    else if (thisData->_isUnicodeValid){
+        if (thisData->_isUnicodeInternal)
+            return ((QChar *)thisData->_internalBuffer)[i];
+        else
+            return thisData->_unicode[i];
+    }
+    else
+        QSTRING_FAILURE ("invalid character cache\n");
+        
+    return (QChar)0;
 }
 
 const QChar *QString::unicode() const
 {
-    const UniChar *ucs = CFStringGetCharactersPtr(s);
-    if (ucs)
-        return (QChar *) ucs;
+    return (*dataHandle)->unicode();
+}
 
-    uint len = length();
-    if (len == 0)
-        return getNullQCharString();
+int QString::compare( const QString& s ) const
+{
+    return ucstrcmp(*this,s);
+}
 
-    if (cache == NULL || * (int *) cache != CacheUnicode) {
-        flushCache();
-        cache = CFAllocatorAllocate(kCFAllocatorDefault, sizeof(int) + len * sizeof (UniChar), 0);
-        * (int *) cache = CacheUnicode;
-        CFStringGetCharacters(s, CFRangeMake(0, len), (UniChar *) ((int *) cache + 1));
+bool QString::startsWith( const QString& s ) const
+{
+    if ((*dataHandle)->_isAsciiValid){
+        const char *asc = ascii();
+        
+        for ( int i =0; i < (int) s.data()->_length; i++ ) {
+            if ( i >= (int) (*dataHandle)->_length || asc[i] != s[i] )
+                return FALSE;
+        }
     }
-
-    return (QChar *) ((int *) cache + 1); 
+    else if ((*dataHandle)->_isUnicodeValid){
+        const QChar *uni = unicode();
+        
+        for ( int i =0; i < (int) s.data()->_length; i++ ) {
+            if ( i >= (int) (*dataHandle)->_length || uni[i] != s[i] )
+                return FALSE;
+        }
+    }
+    else
+        QSTRING_FAILURE ("invalid character cache\n");
+        
+    return TRUE;
 }
 
-const char *QString::latin1() const
+bool QString::endsWith( const QString& s ) const
 {
-    const char *chs = CFStringGetCStringPtr(s, kCFStringEncodingISOLatin1);
-    if (chs)
-        return chs;
+    const QChar *uni = unicode();
 
-    uint len = length();
-    if (len == 0)
-        return "";
+    if ((*dataHandle)->_length < s.data()->_length)
+        return FALSE;
         
-    if (cache == NULL || * (int *) cache != CacheLatin1) {
-        flushCache();
-        cache = CFAllocatorAllocate(kCFAllocatorDefault, sizeof(int) + len + 1, 0);
-        * (int *) cache = CacheLatin1;
-        if (!CFStringGetCString(s, (char *) ((int *) cache + 1), len + 1, kCFStringEncodingISOLatin1)) {
-            * (char *) ((int *) cache + 1) = '\0';
-        }
+    for ( int i = (*dataHandle)->_length - s.data()->_length; i < (int) s.data()->_length; i++ ) {
+	if ( uni[i] != s[i] )
+	    return FALSE;
     }
+    return TRUE;
+}
 
-    return (char *) ((int *) cache + 1);
+const char *QString::latin1() const
+{
+    return (*dataHandle)->ascii();
 }
 
 QCString QString::utf8() const
@@ -325,50 +1067,108 @@ QCString QString::local8Bit() const
 
 bool QString::isNull() const
 {
-    return s == getNullCFString();
+    return (*dataHandle)->_length == 0;
 }
 
 int QString::find(QChar qc, int index) const
 {
-    CFIndex len = CFStringGetLength(s);
-    if (index < 0)
-        index += len;
-    if (len && (index >= 0) && (index < len)) {
-        CFStringInlineBuffer buf;
-        CFStringInitInlineBuffer(s, &buf, CFRangeMake(0, len));
-        for (CFIndex i = index; i < len; i++)
-            if (qc.c == CFStringGetCharacterFromInlineBuffer(&buf, i))
-                return i;
-    }
+    if (IS_ASCII_QCHAR(qc) && (*dataHandle)->_isAsciiValid)
+        return find((char)qc, index);
+    else if ((*dataHandle)->_isUnicodeValid)
+        return find(QString(qc), index, TRUE);
+    else
+        QSTRING_FAILURE ("invalid character cache\n");
+
+    // Should never get here.  Needed for compiler.
     return -1;
 }
 
 int QString::find(char ch, int index) const
 {
-    return find(QChar(ch), index);
+    if ((*dataHandle)->_isAsciiValid){
+        const char *cp = ascii();
+        
+        if ( index < 0 )
+            index += (*dataHandle)->_length;
+        
+        if (index >= (int)(*dataHandle)->_length)
+            return -1;
+            
+        for (int i = index; i < (int)(*dataHandle)->_length; i++)
+            if (cp[i] == ch)
+                return i;
+    }
+    else if ((*dataHandle)->_isUnicodeValid)
+        return find(QChar(ch), index, TRUE);
+    else
+        QSTRING_FAILURE ("invalid character cache\n");
+
+    return -1;
 }
 
-int QString::find(const QString &qs, int index, bool caseSensitive) const
-{
-    CFIndex len = CFStringGetLength(s);
-    if (index < 0)
-        index += len;
-    if (len && (index >= 0) && (index < len)) {
-        CFRange r;
-        CFRange start = CFRangeMake(index, len - index); 
-        if (CFStringFindWithOptions(s, qs.s, start, caseSensitive ? 0 : kCFCompareCaseInsensitive, &r))
-            return r.location;
+int QString::find(const QString &str, int index, bool caseSensitive) const
+{
+    // FIXME, use the first character algorithm
+    /*
+      We use some weird hashing for efficiency's sake.  Instead of
+      comparing strings, we compare the hash value of str with that of
+      a part of this QString.  Only if that matches, we call ucstrncmp
+      or ucstrnicmp.
+
+      The hash value of a string is the sum of the cells of its
+      QChars.
+    */
+    if ( index < 0 )
+	index += (*dataHandle)->_length;
+    int lstr = str.data()->_length;
+    int lthis = (*dataHandle)->_length - index;
+    if ( (uint)lthis > (*dataHandle)->_length )
+	return -1;
+    int delta = lthis - lstr;
+    if ( delta < 0 )
+	return -1;
+
+    const QChar *uthis = unicode() + index;
+    const QChar *ustr = str.unicode();
+    uint hthis = 0;
+    uint hstr = 0;
+    int i;
+    if ( caseSensitive ) {
+	for ( i = 0; i < lstr; i++ ) {
+	    hthis += uthis[i].cell();
+	    hstr += ustr[i].cell();
+	}
+	i = 0;
+	while ( TRUE ) {
+	    if ( hthis == hstr && ucstrncmp(uthis + i, ustr, lstr) == 0 )
+		return index + i;
+	    if ( i == delta )
+		return -1;
+	    hthis += uthis[i + lstr].cell();
+	    hthis -= uthis[i].cell();
+	    i++;
+	}
+    } else {
+	for ( i = 0; i < lstr; i++ ) {
+	    hthis += uthis[i].lower().cell();
+	    hstr += ustr[i].lower().cell();
+	}
+	i = 0;
+	while ( TRUE ) {
+	    if ( hthis == hstr && ucstrnicmp(uthis + i, ustr, lstr) == 0 )
+		return index + i;
+	    if ( i == delta )
+		return -1;
+	    hthis += uthis[i + lstr].lower().cell();
+	    hthis -= uthis[i].lower().cell();
+	    i++;
+	}
     }
+    
+    // Should never get here.
     return -1;
 }
 
-#ifdef DEBUG_FIND_COUNTER
-static int findCount = 0;
-static int findExpensiveCount = 0;
-static int findCheapCount = 0;
-#endif
-
-const int caseDelta = ('a' - 'A');
 
 static inline bool compareToLatinCharacter (UniChar c1, UniChar c2, bool caseSensitive)
 {
@@ -389,55 +1189,67 @@ static inline bool compareToLatinCharacter (UniChar c1, UniChar c2, bool caseSen
     return false;
 }
 
+
+// This function should be as fast as possible, every little bit helps.
+// Our usage patterns are typically small strings.  In time trials
+// this simplistic algorithm is much faster than Boyer-Moore or hash
+// based alrogithms.
 int QString::find(const char *chs, int index, bool caseSensitive) const
 {
-    int pos = -1;
-    if (chs) {
-#ifdef DEBUG_FIND_COUNTER
-        findCount++;
-#endif
-        const UniChar *internalBuffer = CFStringGetCharactersPtr(s);
-        CFIndex len = CFStringGetLength(s);
-        if (index < 0)
-            index += len;
-        if (internalBuffer == 0){
-#ifdef DEBUG_FIND_COUNTER
-            findExpensiveCount++;
-            if (findCount % 500 == 0)
-                fprintf (stdout, "findCount = %d, expensive = %d, cheap = %d\n", findCount, findExpensiveCount, findCheapCount);
-#endif
+    if ((*dataHandle)->_isAsciiValid){
+        char *ptr = (*dataHandle)->ascii();
+        
+        if (chs) {
+            int len = (*dataHandle)->_length;
+            
+            ptr += index;
+            
             if (len && (index >= 0) && (index < len)) {
-                CFStringRef tmp = CFStringCreateWithCStringNoCopy(
-                        kCFAllocatorDefault, chs, kCFStringEncodingISOLatin1,
-                        kCFAllocatorNull);
-                CFRange r;
-                if (CFStringFindWithOptions(s, tmp,
-                        CFRangeMake(index, len - index),
-                        caseSensitive ? 0 : kCFCompareCaseInsensitive, &r)) {
-                    pos = r.location;
+                QChar firstC, c1, c2;
+                const char *_chs;
+                int remaining = len - index, found = -1;
+                int compareToLength = strlen(chs);
+                            
+                _chs = chs + 1;
+                firstC = (QChar)(*chs);
+                while (remaining >= compareToLength){
+                    if (compareToLatinCharacter((UniChar)*ptr++,firstC,caseSensitive)){
+                        char *compareTo = ptr;
+                        
+                        found = len - remaining;
+                        while ( (c2 = (UniChar)(*_chs++)) ){
+                            c1 = (UniChar)(*compareTo++);
+                            if (compareToLatinCharacter(c1, c2,caseSensitive))
+                                continue;
+                            break;
+                        }
+                        if (c2 == (QChar)0)
+                            return found;
+                        _chs = chs + 1;
+                    }
+                    remaining--;
                 }
-                CFRelease(tmp);
             }
         }
-        else {
-#ifdef DEBUG_FIND_COUNTER
-            findCheapCount++;
-            if (findCount % 500 == 0)
-                fprintf (stdout, "findCount = %d, expensive = %d, cheap = %d\n", findCount, findExpensiveCount, findCheapCount);
-#endif
+    }
+    else if ((*dataHandle)->_isUnicodeValid){
+        QChar *ptr = (QChar *)(*dataHandle)->unicode();
+
+        if (chs) {
+            int len = (*dataHandle)->_length;
+
+            ptr += index;
             if (len && (index >= 0) && (index < len)) {
-                UniChar firstC, c1, c2;
+                QChar firstC, c1, c2;
                 const char *_chs;
                 int remaining = len - index, found = -1;
                 int compareToLength = strlen(chs);
-                
-                internalBuffer = &internalBuffer[index];
-                
+                            
                 _chs = chs + 1;
-                firstC = (UniChar)(*chs);
+                firstC = (QChar)(*chs);
                 while (remaining >= compareToLength){
-                    if (compareToLatinCharacter(*internalBuffer++,firstC,caseSensitive)){
-                        const UniChar *compareTo = internalBuffer;
+                    if (compareToLatinCharacter((UniChar)*ptr++,firstC,caseSensitive)){
+                        QChar *compareTo = ptr;
                         
                         found = len - remaining;
                         while ( (c2 = (UniChar)(*_chs++)) ){
@@ -446,7 +1258,7 @@ int QString::find(const char *chs, int index, bool caseSensitive) const
                                 continue;
                             break;
                         }
-                        if (c2 == 0)
+                        if (c2 == (QChar)0)
                             return found;
                         _chs = chs + 1;
                     }
@@ -455,242 +1267,404 @@ int QString::find(const char *chs, int index, bool caseSensitive) const
             }
         }
     }
-    return pos;
+    return -1;
 }
 
 int QString::find(const QRegExp &qre, int index) const
 {
-    CFIndex len = CFStringGetLength(s);
-    if (index < 0)
-        index += len;
-    if (len && (index >= 0) && (index < len))
-        return qre.match(*this, index);
-    return -1;
+    if ( index < 0 )
+	index += (*dataHandle)->_length;
+    return qre.match( *this, index );
 }
 
 int QString::findRev(char ch, int index) const
 {
-    CFIndex len = CFStringGetLength(s);
-    if (index < 0)
-        index += len;
-    if (len && (index <= len)) {
-        CFStringInlineBuffer buf;
-        CFStringInitInlineBuffer(s, &buf, CFRangeMake(0, index));
-        for (CFIndex i = index; i >= 0; i--) {
-            if (ch == CFStringGetCharacterFromInlineBuffer(&buf, i))
+    if ((*dataHandle)->_isAsciiValid){
+        const char *cp = ascii();
+        
+        if (index < 0)
+            index += (*dataHandle)->_length;
+        if (index > (int)(*dataHandle)->_length)
+            return -1;
+            
+        for (int i = index; i >= 0; i--) {
+            if (cp[i] == ch)
                 return i;
         }
     }
+    else if ((*dataHandle)->_isUnicodeValid)
+        return findRev(QString(QChar(ch)), index);
+    else
+        QSTRING_FAILURE ("invalid character cache\n");
+
     return -1;
 }
 
 int QString::findRev(const char *chs, int index) const
 {
-    int pos = -1;
-    if (chs) {
-        CFIndex len = CFStringGetLength(s);
-        if (index < 0)
-            index += len;
-        if (len && (index <= len)) {
-            CFStringRef tmp = CFStringCreateWithCStringNoCopy(
-                    kCFAllocatorDefault, chs, kCFStringEncodingISOLatin1,
-                    kCFAllocatorNull);
-            CFRange r;
-            if (CFStringFindWithOptions(s, tmp, CFRangeMake(0, index),
-                                        kCFCompareBackwards, &r)) {
-                pos = r.location;
-            }
-            CFRelease(tmp);
-        }
+    return findRev(QString(chs), index);
+}
+
+int QString::findRev( const QString& str, int index, bool cs ) const
+{
+    // FIXME, use the first character algorithm
+    /*
+      See QString::find() for explanations.
+    */
+    int lthis = (*dataHandle)->_length;
+    if ( index < 0 )
+	index += lthis;
+
+    int lstr = str.data()->_length;
+    int delta = lthis - lstr;
+    if ( index < 0 || index > lthis || delta < 0 )
+	return -1;
+    if ( index > delta )
+	index = delta;
+
+    const QChar *uthis = unicode();
+    const QChar *ustr = str.unicode();
+    uint hthis = 0;
+    uint hstr = 0;
+    int i;
+    if ( cs ) {
+	for ( i = 0; i < lstr; i++ ) {
+	    hthis += uthis[index + i].cell();
+	    hstr += ustr[i].cell();
+	}
+	i = index;
+	while ( TRUE ) {
+	    if ( hthis == hstr && ucstrncmp(uthis + i, ustr, lstr) == 0 )
+		return i;
+	    if ( i == 0 )
+		return -1;
+	    i--;
+	    hthis -= uthis[i + lstr].cell();
+	    hthis += uthis[i].cell();
+	}
+    } else {
+	for ( i = 0; i < lstr; i++ ) {
+	    hthis += uthis[index + i].lower().cell();
+	    hstr += ustr[i].lower().cell();
+	}
+	i = index;
+	while ( TRUE ) {
+	    if ( hthis == hstr && ucstrnicmp(uthis + i, ustr, lstr) == 0 )
+		return i;
+	    if ( i == 0 )
+		return -1;
+	    i--;
+	    hthis -= uthis[i + lstr].lower().cell();
+	    hthis += uthis[i].lower().cell();
+	}
     }
-    return pos;
+
+    // Should never get here.
+    return -1;
 }
 
+
 #ifdef DEBUG_CONTAINS_COUNTER
 static int containsCount = 0;
 #endif
 
+int QString::contains( QChar c, bool cs ) const
+{
+    int count = 0;
+    
+    if ((*dataHandle)->_isAsciiValid){
+        if (!IS_ASCII_QCHAR(c))
+            return 0;
+            
+        char tc, ac = (char)c;
+        const char *cPtr = ascii();
+        if ( !cPtr )
+            return 0;
+        int n = (*dataHandle)->_length;
+        if ( cs ) {					// case sensitive
+            while ( n-- )
+                if ( *cPtr++ == ac )
+                    count++;
+        } else {					// case insensitive
+            ac = (ac >= 'A' && ac <= 'Z') ? ac + caseDelta : ac;
+            while ( n-- ) {
+                tc = *cPtr++;
+                tc =  (tc >= 'A' && tc <= 'Z') ? tc + caseDelta : tc;
+                if ( tc == ac )
+                    count++;
+            }
+        }
+    }
+    else if ((*dataHandle)->_isUnicodeValid){
+        const QChar *uc = unicode();
+        if ( !uc )
+            return 0;
+        int n = (*dataHandle)->_length;
+        if ( cs ) {					// case sensitive
+            while ( n-- )
+                if ( *uc++ == c )
+                    count++;
+        } else {					// case insensitive
+            c = c.lower();
+            while ( n-- ) {
+                if ( uc->lower() == c )
+                    count++;
+                uc++;
+            }
+        }
+    } 
+    else
+        QSTRING_FAILURE ("invalid character cache\n");
+    return count;
+}
+
 int QString::contains(char ch) const
 {
-    int c = 0;
-    CFIndex len = CFStringGetLength(s);
-    CFStringInlineBuffer buf;
-    CFStringInitInlineBuffer(s, &buf, CFRangeMake(0, len));
-    for (CFIndex i = 0; i < len; i++)
-        if (ch == CFStringGetCharacterFromInlineBuffer(&buf, i))
-            c++;
-    return c;
+    return contains (QChar(ch),true);
 }
 
-int QString::contains(const char *chs, bool cs) const
+int QString::contains(const char *str, bool caseSensitive) const
 {
-    int c = 0;
-    if (chs) {
-#ifdef DEBUG_CONTAINS_COUNTER
-        containsCount++;
-        if (containsCount % 500 == 0)
-            fprintf (stdout, "containsCount = %d\n", containsCount);
-#endif
-        CFStringRef tmp = CFStringCreateWithCStringNoCopy(
-                kCFAllocatorDefault, chs, kCFStringEncodingISOLatin1,
-                kCFAllocatorNull);
-        CFIndex pos = 0;
-        CFIndex len = CFStringGetLength(s);
-        while (pos < len) {
-            CFRange r;
-            if (!CFStringFindWithOptions(s, tmp,
-                    CFRangeMake(pos, len - pos),
-                    cs ? 0 : kCFCompareCaseInsensitive, &r)) {
-                break;
+    if ( !str )
+        return 0;
+
+    if ((*dataHandle)->_isAsciiValid){
+        int count = 0;
+        const char *uc = ascii();
+        int n = (*dataHandle)->_length;
+        int toLen = strlen(str);
+        
+        while ( n-- ) {
+            if ( caseSensitive ) {
+                if ( strncmp( uc, str, toLen ) == 0 )
+                    count++;
+            } else {
+                if ( strncasecmp(uc, str, toLen) == 0 )
+                    count++;
             }
-            c++;
-            // move to next possible overlapping match
-            pos += r.location + 1;
+            uc++;
         }
-        CFRelease(tmp);
+        return count;
     }
-    return c;
+    else if ((*dataHandle)->_isUnicodeValid)
+        return contains(QString(str),caseSensitive);
+    else
+        QSTRING_FAILURE ("invalid character cache\n");
+
+    return 0;
 }
 
-int QString::contains(const QString &cfs, bool cs) const
-{
-    int c = 0;
-    CFIndex pos = 0;
-    CFIndex len = CFStringGetLength(s);
-    while (pos < len) {
-        CFRange r;
-        if (!CFStringFindWithOptions(s, cfs.s,
-                CFRangeMake(pos, len - pos),
-                cs ? 0 : kCFCompareCaseInsensitive, &r)) {
-            break;
-        }
-        c++;
-        // move to next possible overlapping match
-        pos += r.location + 1;
+int QString::contains(const QString &str, bool caseSensitive) const
+{
+    int count = 0;
+    const QChar *uc = unicode();
+    if ( !str )
+	return 0;
+    int len = str.data()->_length;
+    int n = (*dataHandle)->_length;
+    while ( n-- ) {				// counts overlapping strings
+	// ### Doesn't account for length of this - searches over "end"
+	if ( caseSensitive ) {
+	    if ( ucstrncmp( uc, str.unicode(), len ) == 0 )
+		count++;
+	} else {
+	    if ( ucstrnicmp(uc, str.unicode(), len) == 0 )
+		count++;
+	}
+	uc++;
     }
-    return c;
+    return count;
 }
 
 short QString::toShort(bool *ok, int base) const
 {
-    bool neg;
-    short n = convertToNumber(ok, base, &neg);
-    return neg ? -n : n;
+    long v = toLong( ok, base );
+    if ( ok && *ok && (v < -32768 || v > 32767) ) {
+	*ok = FALSE;
+	v = 0;
+    }
+    return (short)v;
 }
 
 ushort QString::toUShort(bool *ok, int base) const
 {
-    return convertToNumber(ok, base, NULL);
+    ulong v = toULong( ok, base );
+    if ( ok && *ok && (v > 65535) ) {
+	*ok = FALSE;
+	v = 0;
+    }
+    return (ushort)v;
 }
 
 int QString::toInt(bool *ok, int base) const
 {
-    bool neg;
-    int n = convertToNumber(ok, base, &neg);
-    return neg ? -n : n;
+    return (int)toLong( ok, base );
 }
 
 uint QString::toUInt(bool *ok, int base) const
 {
-    return convertToNumber(ok, base, NULL);
+    return (uint)toULong( ok, base );
 }
 
 long QString::toLong(bool *ok, int base) const
 {
-    bool neg;
-    long n = convertToNumber(ok, base, &neg);
-    return neg ? -n : n;
+    const QChar *p = unicode();
+    long val=0;
+    int l = (*dataHandle)->_length;
+    const long max_mult = INT_MAX / base;
+    bool is_ok = FALSE;
+    int neg = 0;
+    if ( !p )
+	goto bye;
+    while ( l && p->isSpace() )			// skip leading space
+	l--,p++;
+    if ( l && *p == '-' ) {
+	l--;
+	p++;
+	neg = 1;
+    } else if ( *p == '+' ) {
+	l--;
+	p++;
+    }
+
+    // NOTE: toULong() code is similar
+    if ( !l || !ok_in_base(*p,base) )
+	goto bye;
+    while ( l && ok_in_base(*p,base) ) {
+	l--;
+	int dv;
+	if ( p->isDigit() ) {
+	    dv = p->digitValue();
+	} else {
+	    if ( *p >= 'a' && *p <= 'z' )
+		dv = *p - 'a' + 10;
+	    else
+		dv = *p - 'A' + 10;
+	}
+	if ( val > max_mult || (val == max_mult && dv > (INT_MAX%base)+neg) )
+	    goto bye;
+	val = base*val + dv;
+	p++;
+    }
+    if ( neg )
+	val = -val;
+    while ( l && p->isSpace() )			// skip trailing space
+	l--,p++;
+    if ( !l )
+	is_ok = TRUE;
+bye:
+    if ( ok )
+	*ok = is_ok;
+    return is_ok ? val : 0;
 }
 
 ulong QString::toULong(bool *ok, int base) const
 {
-    return convertToNumber(ok, base, NULL);
+    const QChar *p = unicode();
+    ulong val=0;
+    int l = (*dataHandle)->_length;
+    const ulong max_mult = UINT_MAX / base;
+    bool is_ok = FALSE;
+    if ( !p )
+	goto bye;
+    while ( l && p->isSpace() )			// skip leading space
+	l--,p++;
+    if ( *p == '+' )
+	l--,p++;
+
+    // NOTE: toLong() code is similar
+    if ( !l || !ok_in_base(*p,base) )
+	goto bye;
+    while ( l && ok_in_base(*p,base) ) {
+	l--;
+	uint dv;
+	if ( p->isDigit() ) {
+	    dv = p->digitValue();
+	} else {
+	    if ( *p >= 'a' && *p <= 'z' )
+		dv = *p - 'a' + 10;
+	    else
+		dv = *p - 'A' + 10;
+	}
+	if ( val > max_mult || (val == max_mult && dv > (UINT_MAX%base)) )
+	    goto bye;
+	val = base*val + dv;
+	p++;
+    }
+
+    while ( l && p->isSpace() )			// skip trailing space
+	l--,p++;
+    if ( !l )
+	is_ok = TRUE;
+bye:
+    if ( ok )
+	*ok = is_ok;
+    return is_ok ? val : 0;
 }
 
 double QString::toDouble(bool *ok) const
 {
-    double n;
-    n = CFStringGetDoubleValue(s);
-    if (ok) {
-        // NOTE: since CFStringGetDoubleValue returns 0.0 on error there is no
-        // way to know if "n" is valid in that case
-        //
-        // EXTRA NOTE: We can't assume 0.0 is bad, since it totally breaks
-        // html like border="0". So, only trigger breakage if the char 
-        // at index 0 is neither a '0' nor a '.' nor a '-'.
-        *ok = true;
-        if (n == 0.0) {
-            UniChar uc = CFStringGetLength(s) == 0 ? 0 : CFStringGetCharacterAtIndex(s, 0);
-            if (uc != '0' && uc != '.' && uc != '-') {
-                *ok = false;
-            }
-        }
+    char *end;
+
+    QCString a = latin1();
+
+    double val = strtod( a.data() ? a.data() : "", &end );
+    if ( ok )
+	*ok = ( a && *a && ( end == 0 || *end == '\0' ) );
+    return val;
+}
+
+
+bool QString::findArg(int& pos, int& len) const
+{
+    char lowest=0;
+    for (uint i = 0; i< (*dataHandle)->_length; i++) {
+	if ( at(i) == '%' && i + 1 < (*dataHandle)->_length ) {
+	    char dig = at(i+1);
+	    if ( dig >= '0' && dig <= '9' ) {
+		if ( !lowest || dig < lowest ) {
+		    lowest = dig;
+		    pos = i;
+		    len = 2;
+		}
+	    }
+	}
     }
-    return n;
+    return lowest != 0;
 }
 
-QString QString::arg(const QString &replacement, int width) const
+QString QString::arg(const QString &a, int fieldwidth) const
 {
-    QString qs;
-    if (CFStringGetLength(s)) {
-        qs.s = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, s);
-    }
-    if (qs.s) {
-        CFIndex pos = 0;
-        UniChar found = 0;
-        CFIndex len = CFStringGetLength(qs.s);
-        if (len) {
-            CFStringInlineBuffer buf;
-            CFStringInitInlineBuffer(qs.s, &buf, CFRangeMake(0, len));
-            // find position of lowest numerical position marker
-            for (CFIndex i = 0; i < len; i++) {
-                UniChar uc = CFStringGetCharacterFromInlineBuffer(&buf, i);
-                if ((uc == '%') && ((i + 1) < len)) {
-                    UniChar uc2 = CFStringGetCharacterFromInlineBuffer(&buf,
-                            i + 1);
-                    if ((uc2 >= '0') && (uc2 <= '9')) {
-                        if (!found || (uc2 < found)) {
-                            found = uc2;
-                            pos = i;
-                        }
-                    }
-                }
-            }
-        }
-        CFIndex mlen;
-        if (found) {
-            mlen = 2;
-        } else {
-            // append space and then replacement text at end of string
-            CFStringAppend(qs.s, CFSTR(" "));
-            pos = len + 1;
-            mlen = 0;
-        }
-        if (replacement.s) {
-            CFStringReplace(qs.s, CFRangeMake(pos, mlen), replacement.s);
-            if (width) {
-                CFIndex rlen = CFStringGetLength(replacement.s);
-                CFIndex padding;
-                if (width < 0) {
-                    padding = -width;
-                    pos += rlen;
-                } else {
-                    padding = width;
-                }
-                padding -= rlen;
-                if (padding > 0) {
-                    CFMutableStringRef tmp =
-                        CFStringCreateMutable(kCFAllocatorDefault, 0);
-                    if (tmp) {
-                        CFStringPad(tmp, CFSTR(" "), padding, 0);
-                        CFStringInsert(qs.s, pos, tmp);
-                        CFRelease(tmp);
-                    }
-                }
-            }
-        }
+    int pos, len;
+    QString r = *this;
+
+    if ( !findArg( pos, len ) ) {
+	qWarning( "QString::arg(): Argument missing: %s, %s",
+		  latin1(), a.latin1() );
+	// Make sure the text at least appears SOMEWHERE
+	r += ' ';
+	pos = r.data()->_length;
+	len = 0;
     }
-    return qs;
+
+    r.replace( pos, len, a );
+    if ( fieldwidth < 0 ) {
+	QString s;
+	while ( (uint)-fieldwidth > a.data()->_length ) {
+	    s += ' ';
+	    fieldwidth++;
+	}
+	r.insert( pos + a.data()->_length, s );
+    } else if ( fieldwidth ) {
+	QString s;
+	while ( (uint)fieldwidth > a.data()->_length ) {
+	    s += ' ';
+	    fieldwidth--;
+	}
+	r.insert( pos, s );
+    }
+
+    return r;
 }
 
 QString QString::arg(short replacement, int width) const
@@ -728,133 +1702,261 @@ QString QString::arg(double replacement, int width) const
     return arg(number(replacement), width);
 }
 
-QString QString::left(uint width) const
+QString QString::left(uint len) const
 {
-    return leftRight(width, true);
+    if ( isEmpty() ) {
+	return QString();
+    } else if ( len == 0 ) {			// ## just for 1.x compat:
+	return QString::fromLatin1("");
+    } else if ( len > (*dataHandle)->_length ) {
+	return *this;
+    } else {
+	QString s( unicode(), len );
+	return s;
+    }
 }
 
-QString QString::right(uint width) const
+QString QString::right(uint len) const
 {
-    return leftRight(width, false);
+    if ( isEmpty() ) {
+	return QString();
+    } else if ( len == 0 ) {			// ## just for 1.x compat:
+	return QString::fromLatin1("");
+    } else {
+	uint l = (*dataHandle)->_length;
+	if ( len > l )
+	    len = l;
+	QString s( unicode()+(l-len), len );
+	return s;
+    }
 }
 
-QString QString::mid(uint index, uint width) const
+QString QString::mid(uint index, uint len) const
 {
-    QString qs;
-    CFIndex len = CFStringGetLength(s);
-    if (len && (index < (uint)len) && width) {
-        if (!((index == 0) && (width >= (uint)len))) {
-            if (width > (len - index)) {
-                width = len - index;
-            }
-            CFStringRef tmp = CFStringCreateWithSubstring(
-                    kCFAllocatorDefault, s, CFRangeMake(index, width));
-            if (tmp) {
-                qs.s = CFStringCreateMutableCopy(kCFAllocatorDefault, 0,
-                        tmp);
-                CFRelease(tmp);
-            }
-        } else {
-            CFRetain(s);
-            qs.s = s;
-        }
+    uint slen = (*dataHandle)->_length;
+    if ( isEmpty() || index >= slen ) {
+	return QString();
+    } else if ( len == 0 ) {			// ## just for 1.x compat:
+	return QString::fromLatin1("");
+    } else {
+	if ( len > slen-index )
+	    len = slen - index;
+	if ( index == 0 && len == (*dataHandle)->_length )
+	    return *this;
+	register const QChar *p = unicode()+index;
+	QString s( p, len );
+	return s;
     }
-    return qs;
 }
 
 QString QString::copy() const
 {
     // does not need to be a deep copy
-    return *this;
+    return QString(*this);
 }
 
 QString QString::lower() const
 {
-    QString qs;
-    if (CFStringGetLength(s)) {
-        qs.s = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, s);
-        CFStringLowercase(qs.s, NULL);
+    QString s(*this);
+    int l = (*dataHandle)->_length;
+    if ( l ) {
+	s.detach();
+        if (s.data()->_isAsciiValid){
+            char *p= (char *)s.ascii();
+            if ( p ) {
+                while ( l-- ) {
+                    *p = (*p >= 'A' && *p <= 'Z') ? (*p + caseDelta) : *p;
+                    p++;
+                }
+            }
+        }
+        else if (s.data()->_isUnicodeValid){
+            QChar *p= (QChar *)s.unicode();
+            if ( p ) {
+                while ( l-- ) {
+                    if (IS_ASCII_QCHAR(*p)){
+                        *p = (*p >= (QChar)'A' && *p <= (QChar)'Z') ? (QChar)(*p + caseDelta) : *p;
+                    }
+                    else
+                        *p = p->lower();
+                    p++;
+                }
+            }
+        }
+        else
+            QSTRING_FAILURE ("invalid character cache\n");
     }
-    return qs;
+    return s;
 }
 
 QString QString::stripWhiteSpace() const
 {
-    QString qs;
-    CFIndex len = CFStringGetLength(s);
-    if (len) {
-        static CFCharacterSetRef wscs = CFCharacterSetGetPredefined(
-                kCFCharacterSetWhitespaceAndNewline);
-        if (CFCharacterSetIsCharacterMember(wscs,
-                CFStringGetCharacterAtIndex(s, 0))
-                || CFCharacterSetIsCharacterMember(wscs,
-                CFStringGetCharacterAtIndex(s, len - 1))) {
-            qs.s = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, s);
-            CFStringTrimWhitespace(qs.s);
-        } else {
-            CFRetain(s);
-            qs.s = s;
-        }
+    if ( isEmpty() )				// nothing to do
+	return *this;
+    if ( !at(0).isSpace() && !at((*dataHandle)->_length-1).isSpace() )
+	return *this;
+
+    int start = 0;
+    int end = (*dataHandle)->_length - 1;
+
+    QString result = fromLatin1("");
+    while ( start<=end && at(start).isSpace() )	// skip white space from start
+        start++;
+    if ( start > end ) {			// only white space
+        return result;
     }
-    return qs;
+    while ( end && at(end).isSpace() )		// skip white space from end
+        end--;
+    int l = end - start + 1;
+    
+    if ((*dataHandle)->_isAsciiValid){
+        result.setLength( l );
+        if ( l )
+            memcpy( (char *)result.data()->ascii(), &ascii()[start], l );
+    }
+    else if ((*dataHandle)->_isUnicodeValid){
+        result.forceUnicode();
+        result.setLength( l );
+        if ( l )
+            memcpy( (QChar *)result.data()->unicode(), &unicode()[start], sizeof(QChar)*l );
+    }
+    else
+        QSTRING_FAILURE ("invalid character cache\n");
+    return result;
 }
 
 QString QString::simplifyWhiteSpace() const
 {
-    QString qs;
-    CFIndex len = CFStringGetLength(s);
-    if (len) {
-        qs.s = CFStringCreateMutable(kCFAllocatorDefault, 0);
-        static CFCharacterSetRef wscs = CFCharacterSetGetPredefined(
-                kCFCharacterSetWhitespaceAndNewline);
-        CFStringInlineBuffer buf;
-        CFStringInitInlineBuffer(s, &buf, CFRangeMake(0, len));
-        bool chars = false;
-        bool space = false;
-        for (CFIndex i = 0; i < len; i++) {
-            UniChar uc = CFStringGetCharacterFromInlineBuffer(&buf, i);
-            if (CFCharacterSetIsCharacterMember(wscs, uc)) {
-                if (chars)
-                    space = true;
-            } else {
-                if (space) {
-                    UniChar spc = ' ';
-                    CFStringAppendCharacters(qs.s, &spc, 1);
-                    space = false;
-                }
-                CFStringAppendCharacters(qs.s, &uc, 1);
-                chars = true;
-            }
+    if ( isEmpty() )				// nothing to do
+	return *this;
+    
+    QString result;
+
+    if ((*dataHandle)->_isAsciiValid){
+        result.setLength( (*dataHandle)->_length );
+        const char *from = ascii();
+        const char *fromend = from + (*dataHandle)->_length;
+        int outc=0;
+        
+        char *to = (char *)result.ascii();
+        while ( TRUE ) {
+            while ( from!=fromend && QChar(*from).isSpace() )
+                from++;
+            while ( from!=fromend && !QChar(*from).isSpace() )
+                to[outc++] = *from++;
+            if ( from!=fromend )
+                to[outc++] = ' ';
+            else
+                break;
         }
-    } else {
-        CFRetain(s);
-        qs.s = s;
+        if ( outc > 0 && to[outc-1] == ' ' )
+            outc--;
+        result.truncate( outc );
     }
-    return qs;
+    else if ((*dataHandle)->_isUnicodeValid){
+        result.forceUnicode();
+        result.setLength( (*dataHandle)->_length );
+        const QChar *from = unicode();
+        const QChar *fromend = from + (*dataHandle)->_length;
+        int outc=0;
+        
+        QChar *to = (QChar *)result.unicode();
+        while ( TRUE ) {
+            while ( from!=fromend && from->isSpace() )
+                from++;
+            while ( from!=fromend && !from->isSpace() )
+                to[outc++] = *from++;
+            if ( from!=fromend )
+                to[outc++] = ' ';
+            else
+                break;
+        }
+        if ( outc > 0 && to[outc-1] == ' ' )
+            outc--;
+        result.truncate( outc );
+    }
+    else
+        QSTRING_FAILURE ("invalid character cache\n");
+    
+    return result;
 }
 
-QString &QString::setUnicode(const QChar *qcs, uint len)
+void QString::deref()
 {
-    flushCache();
-    CFRelease(s);
-    if (qcs && len) {
-        s = CFStringCreateMutable(kCFAllocatorDefault, 0);
-        CFStringAppendCharacters(s, &qcs->c, len);
+    (*dataHandle)->deref();
+}
+
+
+QString &QString::setUnicode(const QChar *uni, uint len)
+{
+    detach();
+    
+    bool needToFreeHandle = false;
+    
+    // free our handle if it isn't the shared
+    // null handle, and if no-one else is using
+    // it.
+    if (dataHandle != makeSharedNullHandle() && (*dataHandle)->refCount == 1)
+        needToFreeHandle = true;
+        
+    if ( len == 0 ) {
+        deref();
+        if (needToFreeHandle)
+            freeHandle (dataHandle);
+        dataHandle = makeSharedNullHandle();
+        (*dataHandle)->ref();
+    } else if (len > (*dataHandle)->_maxUnicode || (*dataHandle)->refCount != 1 || !(*dataHandle)->_isUnicodeValid) {
+        deref();
+        if (needToFreeHandle)
+            freeHandle (dataHandle);
+        dataHandle = (struct QStringData **)allocateHandle();
+	*dataHandle = new QStringData( uni, len );
+        (*dataHandle)->_isHeapAllocated = 1;
     } else {
-        s = getNullCFString();
+	if ( uni )
+	    memcpy( (void *)unicode(), uni, sizeof(QChar)*len );
+        (*dataHandle)->_length = len;
+        (*dataHandle)->_isAsciiValid = 0;
     }
+    
     return *this;
 }
 
-QString &QString::setLatin1(const char *chs)
+
+QString &QString::setLatin1(const char *str, int len)
 {
-    flushCache();
-    CFRelease(s);
-    if (chs && *chs) {
-        s = CFStringCreateMutable(kCFAllocatorDefault, 0);
-        CFStringAppendCString(s, chs, kCFStringEncodingISOLatin1);
+    if ( str == 0 )
+	return setUnicode(0,0);
+    if ( len < 0 )
+	len = strlen(str);
+
+    detach();
+    
+    bool needToFreeHandle = false;
+    
+    // free our handle if it isn't the shared
+    // null handle, and if no-one else is using
+    // it.
+    if (dataHandle != makeSharedNullHandle() && (*dataHandle)->refCount == 1)
+        needToFreeHandle = true;
+        
+    if ( len == 0 ) {
+        deref();
+        if (needToFreeHandle)
+            freeHandle (dataHandle);
+        dataHandle = makeSharedNullHandle();
+        (*dataHandle)->ref();
+    } else if (len+1 > (int)(*dataHandle)->_maxAscii || (*dataHandle)->refCount != 1 || !(*dataHandle)->_isAsciiValid) {
+        deref();
+        if (needToFreeHandle)
+            freeHandle (dataHandle);
+        dataHandle = (struct QStringData **)allocateHandle();
+        *dataHandle = new QStringData(str,len);
+        (*dataHandle)->_isHeapAllocated = 1;
     } else {
-        s = getNullCFString();
+        strcpy( (char *)ascii(), str );
+        (*dataHandle)->_length = len;
+        (*dataHandle)->_isUnicodeValid = 0;
     }
     return *this;
 }
@@ -913,23 +2015,18 @@ QString &QString::sprintf(const char *format, ...)
 {
     va_list args;
     va_start(args, format);
-    flushCache();
-    CFRelease(s);
     if (format && *format) {
-        s = CFStringCreateMutable(kCFAllocatorDefault, 0);
-        CFStringRef f = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault,
+        CFStringRef tmp, f = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault,
                 format, kCFStringEncodingISOLatin1, kCFAllocatorNull);
         if (f) {
-            CFStringRef tmp = CFStringCreateWithFormatAndArguments(
+            tmp = CFStringCreateWithFormatAndArguments(
                     kCFAllocatorDefault, NULL, f, args);
-            if (tmp) {
-                CFStringReplaceAll(s, tmp);
-                CFRelease(tmp);
-            }
             CFRelease(f);
+            setBufferFromCFString(tmp);
+            CFRelease (tmp);
         }
     } else {
-        s = getNullCFString();
+        setLength(0);
     }
     va_end(args);
     return *this;
@@ -942,119 +2039,360 @@ QString &QString::prepend(const QString &qs)
 
 QString &QString::append(const QString &qs)
 {
-    return insert(length(), qs);
+    return insert((*dataHandle)->_length, qs);
 }
 
-void QString::_copyIfNeededInternalString()
-{
-    if (CFGetRetainCount(s) != 1) {
-        CFMutableStringRef tmp = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, s);
-        CFRelease(s);
-        s = tmp;
-    }
-}
 
 QString &QString::insert(uint index, const QString &qs)
 {
-    flushCache();
-    _copyIfNeededInternalString();
-    if (index < (uint) CFStringGetLength(s))
-        CFStringInsert(s, index, qs.s);
-    else
-        CFStringAppend(s, qs.s);
+    detach();
+    
+    if (qs.data()->_length == 0)
+        return *this;
+        
+#ifdef QSTRING_DEBUG_UNICODE
+    forceUnicode();
+#endif
+    if ((*dataHandle)->_isAsciiValid && qs.data()->_isAsciiValid){
+        uint insertLength = qs.data()->_length;
+        uint originalLength = (*dataHandle)->_length;
+        char *insertChars = (char *)qs.ascii();
+        char *targetChars;
+        
+        // Ensure that we have enough space.
+        setLength (originalLength + insertLength);
+        targetChars = (char *)ascii();
+        
+        // Move tail to make space for inserted characters.
+        memmove (targetChars+index+insertLength, targetChars+index, originalLength-index);
+        
+        // Insert characters.
+        memcpy (targetChars+index, insertChars, insertLength);
+    }
+    else {
+        uint insertLength = qs.data()->_length;
+        uint originalLength = (*dataHandle)->_length;
+        QChar *targetChars;
+        
+        // Ensure that we have enough space.
+        setLength (originalLength + insertLength);
+        forceUnicode();
+        targetChars = (QChar *)unicode();
+        
+        // Move tail to make space for inserted characters.
+        memmove (targetChars+(index+insertLength), targetChars+index, (originalLength-index)*sizeof(QChar));
+
+        // Insert characters.
+        if (qs.data()->_isAsciiValid){
+            uint i = insertLength;
+            QChar *target = targetChars+index;
+            char *a = (char *)qs.ascii();
+            
+            while (i--)
+                *target++ = *a++;
+        }
+        else {
+            QChar *insertChars = (QChar *)qs.unicode();
+            memcpy (targetChars+index, insertChars, insertLength*sizeof(QChar));
+        }
+        
+    }
+    
     return *this;
 }
 
+
 QString &QString::insert(uint index, QChar qc)
 {
-    flushCache();
-    _copyIfNeededInternalString();
-    UniChar uch = qc.unicode();
-    if (index < (uint) CFStringGetLength(s)) {
-        CFStringRef chs = CFStringCreateWithCharactersNoCopy(NULL, &uch, 1, kCFAllocatorNull);
-        CFStringInsert(s, index, chs);
-        CFRelease(chs);
-    } else {
-        CFStringAppendCharacters(s, &uch, 1);
+    detach();
+    
+    if ((*dataHandle)->_isAsciiValid && IS_ASCII_QCHAR(qc)){
+        uint originalLength = (*dataHandle)->_length;
+        char insertChar = (char)qc;
+        char *targetChars;
+        
+        // Ensure that we have enough space.
+        setLength (originalLength + 1);
+        targetChars = (char *)ascii();
+        
+        // Move tail to make space for inserted character.
+        memmove (targetChars+index+1, targetChars+index, originalLength-index);
+        
+        // Insert character.
+        targetChars[index] = insertChar;
+        targetChars[(*dataHandle)->_length] = 0;
+    }
+    else {
+        uint originalLength = (*dataHandle)->_length;
+        QChar *targetChars;
+        
+        // Ensure that we have enough space.
+        setLength (originalLength + 1);
+        forceUnicode();
+        targetChars = (QChar *)unicode();
+        
+        // Move tail to make space for inserted character.
+        memmove (targetChars+(index+1), targetChars+index, (originalLength-index)*sizeof(QChar));
+
+        targetChars[index] = qc;
     }
+    
     return *this;
 }
 
+
 QString &QString::insert(uint index, char ch)
 {
-    flushCache();
-    _copyIfNeededInternalString();
-    UniChar uch = (uchar) ch;
-    if (index < (uint) CFStringGetLength(s)) {
-        CFStringRef chs = CFStringCreateWithCharactersNoCopy(NULL, &uch, 1, kCFAllocatorNull);
-        CFStringInsert(s, index, chs);
-        CFRelease(chs);
-    } else {
-        CFStringAppendCharacters(s, &uch, 1);
+    detach();
+    
+    if ((*dataHandle)->_isAsciiValid){
+        uint originalLength = (*dataHandle)->_length;
+        char *targetChars;
+        
+        // Ensure that we have enough space.
+        setLength (originalLength + 1);
+        targetChars = (char *)ascii();
+        
+        // Move tail to make space for inserted character.
+        memmove (targetChars+index+1, targetChars+index, originalLength-index);
+        
+        // Insert character.
+        targetChars[index] = ch;
+        targetChars[(*dataHandle)->_length] = 0;
     }
+    else if ((*dataHandle)->_isUnicodeValid){
+        uint originalLength = (*dataHandle)->_length;
+        QChar *targetChars;
+        
+        // Ensure that we have enough space.
+        setLength (originalLength + 1);
+        targetChars = (QChar *)unicode();
+        
+        // Move tail to make space for inserted character.
+        memmove (targetChars+(index+1), targetChars+index, (originalLength-index)*sizeof(QChar));
+
+        targetChars[index] = (QChar)ch;
+    }
+    else
+        QSTRING_FAILURE ("invalid character cache\n");
+    
     return *this;
 }
 
-QString &QString::remove(uint index, uint width)
+
+void QString::detachInternal()
 {
-    flushCache();
-    CFIndex len = CFStringGetLength(s);
-    if (len && (index < (uint)len) && width) {
-        if (width > (len - index)) {
-            width = len - index;
+    struct QStringData *oldData = (*dataHandle), *newData = 0;
+    
+    if (oldData->refCount > 1 && oldData == &internalData){
+        if (oldData->_isAsciiValid)
+            newData = new QStringData (oldData->ascii(), oldData->_length);
+        else if (oldData->_isUnicodeValid){
+            // No need to copy the allocated unicode bytes.
+            if (!oldData->_isUnicodeInternal){
+                newData = new QStringData (oldData->unicode(), oldData->_length, oldData->_maxUnicode);
+                oldData->_unicode = 0;
+                oldData->_isUnicodeValid = 0;
+            }
+            else
+                newData = new QStringData (oldData->unicode(), oldData->_length);
         }
-        _copyIfNeededInternalString();
-        CFStringDelete(s, CFRangeMake(index, width));
+        else
+            QSTRING_FAILURE ("invalid character cache");
+        newData->_isHeapAllocated = 1;
+        newData->refCount = oldData->refCount - 1;
+        *dataHandle = newData;
+        
+        oldData->refCount -= (oldData->refCount - 1);
     }
-    return *this;
 }
 
-QString &QString::replace(const QRegExp &qre, const QString &qs)
+// Copy QStringData if necessary.  Must be called before
+// the string data is mutated.
+void QString::detach()
 {
-    int len = qs.length();
-    for (int i = 0; i < CFStringGetLength(s); i += len) {
-        int width = 0;
-        i = qre.match(*this, i, &width, false);
-        flushCache();
-        if ((i < 0) || !width) {
-            break;
+    if ((*dataHandle)->refCount == 1 && dataHandle != shared_null_handle)
+        return;
+
+#ifdef QSTRING_DEBUG_ALLOCATIONS
+    stringDataDetachments++;
+#endif
+    struct QStringData *oldData = (*dataHandle), *newData = 0;
+    
+    // Copy data for this string so we can safely mutate it,
+    // and put it in a new handle.
+    if (oldData->_isAsciiValid)
+        newData = new QStringData (oldData->ascii(), oldData->_length);
+    else if (oldData->_isUnicodeValid)
+        newData = new QStringData (oldData->unicode(), oldData->_length);
+    else if (oldData == shared_null){
+        newData = new QStringData ();
+    }
+    else
+        QSTRING_FAILURE ("invalid character cache");
+
+    // We must copy our internal data so other strings
+    // can still safely reference it.
+    detachInternal();
+    
+    newData->_isHeapAllocated = 1;
+    dataHandle = (struct QStringData **)allocateHandle();
+    *dataHandle = newData;
+    
+    // Release the old data.
+    oldData->deref();
+}
+
+QString &QString::remove(uint index, uint len)
+{
+    uint olen = (*dataHandle)->_length;
+    if ( index >= olen  ) {
+        // range problems
+    } else if ( index + len >= olen ) {  // index ok
+        setLength( index );
+    } else if ( len != 0 ) {
+	detach();
+        
+#ifdef QSTRING_DEBUG_UNICODE
+    forceUnicode();
+#endif
+        if ((*dataHandle)->_isAsciiValid){
+            memmove( (*dataHandle)->ascii()+index, (*dataHandle)->ascii()+index+len,
+                    sizeof(char)*(olen-index-len) );
+            setLength( olen-len );
         }
-        CFRange r = CFRangeMake(i, width);
-        _copyIfNeededInternalString();
-        if (len) {
-            CFStringReplace(s, r, qs.s);
-        } else {
-            CFStringDelete(s, r);
+        else if ((*dataHandle)->_isUnicodeValid){
+            memmove( (*dataHandle)->unicode()+index, (*dataHandle)->unicode()+index+len,
+                    sizeof(QChar)*(olen-index-len) );
+            setLength( olen-len );
         }
+        else
+            QSTRING_FAILURE ("invalid character cache\n");
     }
     return *this;
 }
 
-void QString::truncate(uint newLen)
+QString &QString::replace( uint index, uint len, const QString &str )
 {
-    flushCache();
-    _copyIfNeededInternalString();
-    CFIndex len = CFStringGetLength(s);
-    if (len && (newLen < (uint)len)) {
-        CFStringDelete(s, CFRangeMake(newLen, len - newLen));
+    // No need to detach here, detach will happen if necessary
+    // in remove() or insert().
+    
+    if (str.data()->_length == 0)
+        return *this;
+        
+    remove( index, len );
+    insert( index, str );
+
+    return *this;
+}
+
+QString &QString::replace(const QRegExp &qre, const QString &str)
+{
+    if ( isEmpty() )
+	return *this;
+    int index = 0;
+    int slen  = str.data()->_length;
+    int len;
+    while ( index < (int)(*dataHandle)->_length ) {
+	index = qre.match( *this, index, &len, FALSE );
+	if ( index >= 0 ) {
+	    replace( index, len, str );
+	    index += slen;
+	    if ( !len )
+		break;	// Avoid infinite loop on 0-length matches, e.g. [a-z]*
+	}
+	else
+	    break;
     }
+    return *this;
+}
+
+
+
+void QString::forceUnicode()
+{
+    detach();
+    
+    unicode();
+
+    (*dataHandle)->_isAsciiValid = 0;
+}
+
+
+// Increase buffer size if necessary.  Newly allocated
+// bytes will contain garbage.
+void QString::setLength( uint newLen )
+{
+    detach();
+    
+    // If we going to change the length, we'll need our 
+    // own data.
+    if (dataHandle == makeSharedNullHandle()){
+        deref();
+        dataHandle = (struct QStringData **)allocateHandle();
+        *dataHandle = new QStringData();
+        (*dataHandle)->_isHeapAllocated = 1;
+    }
+    
+#ifdef QSTRING_DEBUG_UNICODE
+    forceUnicode();
+#endif
+    if ((*dataHandle)->_isAsciiValid){
+        if (newLen+1 > (*dataHandle)->_maxAscii) {
+            (*dataHandle)->increaseAsciiSize(newLen+1);
+        }
+        
+        // Ensure null termination, although newly allocated
+        // bytes contain garbage.
+        (*dataHandle)->_ascii[newLen] = 0;
+    }
+    else if ((*dataHandle)->_isUnicodeValid){
+        if (newLen > (*dataHandle)->_maxUnicode) {
+            (*dataHandle)->increaseUnicodeSize(newLen);
+        }
+    }
+    else
+        QSTRING_FAILURE ("invalid character cache\n");
+
+    (*dataHandle)->_length = newLen;
+}
+
+
+void QString::truncate(uint newLen)
+{
+    if ( newLen < (*dataHandle)->_length )
+	setLength( newLen );
 }
 
 void QString::fill(QChar qc, int len)
 {
-    flushCache();
-    if (len < 0)
-        len = CFStringGetLength(s);
-    CFRelease(s);
-    if (len <= 0)
-        s = getNullCFString();
-    else {
-        UniChar *ucs = (UniChar *)CFAllocatorAllocate(kCFAllocatorDefault, len * sizeof (UniChar), 0);
-        for (int i = 0; i < len; i++)
-            ucs[i] = qc.c;
-        s = CFStringCreateMutable(kCFAllocatorDefault, 0);
-        CFStringAppendCharacters(s, ucs, len);
-        CFAllocatorDeallocate(kCFAllocatorDefault, ucs);
+    detach();
+    
+#ifdef QSTRING_DEBUG_UNICODE
+    forceUnicode();
+#endif
+    // len == -1 means fill to string length.
+    if ( len < 0 )
+	len = (*dataHandle)->_length;
+        
+    if ( len == 0 ) {
+        deref();
+        dataHandle = makeSharedNullHandle();
+        (*dataHandle)->ref();
+    } else {
+        if ((*dataHandle)->_isAsciiValid && IS_ASCII_QCHAR(qc)){
+            setLength(len);
+            char *nd = (char *)ascii();
+            while (len--) 
+                *nd++ = (char)qc;
+        }
+        else {
+            forceUnicode();
+            setLength(len);
+            QChar *nd = (QChar *)unicode();
+            while (len--) 
+                *nd++ = qc;
+        }
     }
 }
 
@@ -1073,33 +2411,88 @@ QString QString::visual()
 
 QString &QString::operator+=(const QString &qs)
 {
-    return insert(length(), qs);
+    detach();
+
+    if ((*dataHandle)->_isUnicodeValid && (*dataHandle)->_length + qs.data()->_length < (*dataHandle)->_maxUnicode){
+        uint i = qs.data()->_length;
+        QChar *tp = &(*dataHandle)->_unicode[(*dataHandle)->_length];
+        if (qs.data()->_isAsciiValid){
+            char *fp = (char *)qs.ascii();
+            while (i--)
+                *tp++ = *fp++;
+        }
+        else if(qs.data()->_isUnicodeValid){
+            QChar *fp = (QChar *)qs.unicode();
+            while (i--)
+                *tp++ = *fp++;
+        }
+        else 
+            QSTRING_FAILURE ("invalid character cache\n");
+        (*dataHandle)->_length += qs.data()->_length;
+        return *this;
+    }
+    else if ((*dataHandle)->_isAsciiValid && qs.data()->_isAsciiValid && (*dataHandle)->_length + qs.data()->_length < (*dataHandle)->_maxAscii){
+        uint i = qs.data()->_length;
+        char *tp = &(*dataHandle)->_ascii[(*dataHandle)->_length];
+        char *fp = (char *)qs.ascii();
+        while (i--)
+            *tp++ = *fp++;
+        *tp = 0;
+        (*dataHandle)->_length += qs.data()->_length;
+        return *this;
+    }
+    return insert((*dataHandle)->_length, qs);
 }
 
 QString &QString::operator+=(QChar qc)
 {
-    return insert(length(), qc);
+    detach();
+    
+    QStringData *thisData = *dataHandle;
+    if (thisData->_isUnicodeValid && thisData->_length + 1 < thisData->_maxUnicode){
+        thisData->_unicode[data()->_length] = qc;
+        thisData->_length++;
+        thisData->_isAsciiValid = 0;
+        return *this;
+    }
+    else if (thisData->_isAsciiValid && IS_ASCII_QCHAR(qc) && thisData->_length + 2 < thisData->_maxAscii){
+        thisData->_ascii[data()->_length] = (char)qc;
+        thisData->_length++;
+        thisData->_ascii[data()->_length] = 0;
+        thisData->_isUnicodeValid = 0;
+        return *this;
+    }
+    return insert(thisData->_length, qc);
 }
 
 QString &QString::operator+=(char ch)
 {
-    return insert(length(), ch);
-}
-
-void QString::flushCache() const
-{
-    if (cache) {
-        CFAllocatorDeallocate(kCFAllocatorDefault, cache);
-        cache = NULL;
+    detach();
+    
+    QStringData *thisData = *dataHandle;
+    if (thisData->_isUnicodeValid && thisData->_length + 1 < thisData->_maxUnicode){
+        thisData->_unicode[thisData->_length] = (QChar)ch;
+        thisData->_length++;
+        thisData->_isAsciiValid = 0;
+        return *this;
     }
+    else if (thisData->_isAsciiValid && thisData->_length + 2 < thisData->_maxAscii){
+        thisData->_ascii[thisData->_length] = ch;
+        thisData->_length++;
+        thisData->_ascii[thisData->_length] = 0;
+        thisData->_isUnicodeValid = 0;
+        return *this;
+    }
+    return insert(thisData->_length, ch);
 }
 
 QCString QString::convertToQCString(CFStringEncoding enc) const
 {
-    uint len = length();
+    uint len = (*dataHandle)->_length;
     if (len) {
         char *chs = (char *)CFAllocatorAllocate(kCFAllocatorDefault, len + 1, 0);
         if (chs) {
+            CFStringRef s = getCFMutableString(); // autoreleased
             if (!CFStringGetCString(s, chs, len + 1, enc)) {
                 *reinterpret_cast<char *>(chs) = '\0';
             }
@@ -1111,166 +2504,22 @@ QCString QString::convertToQCString(CFStringEncoding enc) const
     return QCString();
 }
 
-ulong QString::convertToNumber(bool *ok, int base, bool *neg) const
-{
-    ulong n = 0;
-    bool valid = false;
-    bool negative = false;
-    if (s) {
-        CFIndex len = CFStringGetLength(s);
-        if (len) {
-            CFStringInlineBuffer buf;
-            UniChar uc;
-            static CFCharacterSetRef wscs =
-                CFCharacterSetGetPredefined(
-                        kCFCharacterSetWhitespaceAndNewline);
-            CFStringInitInlineBuffer(s, &buf, CFRangeMake(0, len));
-            CFIndex i;
-            // ignore any leading whitespace
-            for (i = 0; i < len; i++) {
-                uc = CFStringGetCharacterFromInlineBuffer(&buf, i);
-                if (!CFCharacterSetIsCharacterMember(wscs, uc)) {
-                    break;
-                }
-            }
-            if (neg) {
-                // is there a sign?
-                if (i < len) {
-                    uc = CFStringGetCharacterFromInlineBuffer(&buf, i);
-                    if (uc == '-') {
-                        i++;
-                        negative = true;
-                    } else if (uc == '+') {
-                        i++;
-                    }
-                }
-            }
-            ulong max = negative ? LONG_MAX : ULONG_MAX;
-            // is there a number?
-            while (i < len) {
-                uc = CFStringGetCharacterFromInlineBuffer(&buf, i);
-                // NOTE: ignore anything other than base 10 and base 16
-                if ((uc >= '0') && (uc <= '9')) {
-                    if (n > (max / base)) {
-                        valid = false;
-                        break;
-                    }
-                    n = (n * base) + (uc - '0');
-                } else if (base == 16) {
-                    if ((uc >= 'A') && (uc <= 'F')) {
-                        if (n > (max / base)) {
-                            valid = false;
-                            break;
-                        }
-                        n = (n * base) + (10 + (uc - 'A'));
-                    } else if ((uc >= 'a') && (uc <= 'f')) {
-                        if (n > (max / base)) {
-                            valid = false;
-                            break;
-                        }
-                        n = (n * base) + (10 + (uc - 'a'));
-                    } else {
-                        break;
-                    }
-                } else {
-                    break;
-                }
-                valid = true;
-                i++;
-            }
-            // ignore any trailing whitespace
-            while (i < len) {
-                uc = CFStringGetCharacterFromInlineBuffer(&buf, i);
-                if (!CFCharacterSetIsCharacterMember(wscs, uc)) {
-                    valid = false;
-                    break;
-                }
-                i++;
-            }
-        }
-    }
-    if (ok) {
-        *ok = valid;
-    }
-    if (neg) {
-        *neg = negative;
-    }
-    return valid ? n : 0;
-}
 
-QString QString::leftRight(uint width, bool left) const
+bool operator==(const QString &s1, const QString &s2)
 {
-    QString qs;
-    if (s) {
-        CFIndex len = CFStringGetLength(s);
-        if (len && width) {
-            if ((uint)len > width) {
-                CFStringRef tmp = CFStringCreateWithSubstring(
-                        kCFAllocatorDefault, s, left ? CFRangeMake(0, width)
-                        : CFRangeMake(len - width, width));
-                qs.s = CFStringCreateMutableCopy(kCFAllocatorDefault, 0,
-                        tmp);
-                CFRelease(tmp);
-            } else {
-                CFRetain(s);
-                qs.s = s;
-            }
-        }
-    }
-    return qs;
-}
-
-int QString::compareToLatin1(const char *chs) const
-{
-    if (!chs || !*chs) {
-        if (length() == 0)
-            return kCFCompareEqualTo;
-        return kCFCompareGreaterThan;
-    }
-
-    CFIndex len = CFStringGetLength(s);
-    CFStringInlineBuffer buf;
-    CFStringInitInlineBuffer(s, &buf, CFRangeMake(0, len));
-    for (CFIndex i = 0; i < len; i++) {
-        UniChar c1 = CFStringGetCharacterFromInlineBuffer(&buf, i);
-        UniChar c2 = (uchar) chs[i];
-        if (c1 < c2)
-            return kCFCompareLessThan;
-        if (c1 > c2)
-            return kCFCompareGreaterThan;
+    if (s1.data()->_isAsciiValid && s2.data()->_isAsciiValid){
+        return ((s1.data()->_length == s2.data()->_length) && (strcmp (s1.ascii(), s2.ascii()) == 0));
     }
-    if (chs[len] == 0)
-        return kCFCompareEqualTo;
-    return kCFCompareGreaterThan;
+    return (s1.data()->_length == s2.data()->_length) && s1.isNull() == s2.isNull() &&
+	   (memcmp((char*)s1.unicode(),(char*)s2.unicode(),
+		   s1.data()->_length*sizeof(QChar)) ==0);
 }
 
-bool operator==(const QString &qs1, const QString &qs2)
+bool operator==(const QString &s1, const char *chs)
 {
-    return CFEqual(qs1.s, qs2.s);
-}
-
-bool operator==(const QString &qs, const char *chs)
-{
-    if (!chs || !*chs) {
-        if (qs.length() == 0)
-            return kCFCompareEqualTo;
-        return kCFCompareGreaterThan;
-    }
-
-    CFIndex len = CFStringGetLength(qs.s);
-    CFIndex chsLen = strlen(chs);
-    if (len != chsLen)
-        return false;
-    
-    CFStringInlineBuffer buf;
-    CFStringInitInlineBuffer(qs.s, &buf, CFRangeMake(0, len));
-    for (CFIndex i = 0; i < len; i++) {
-        UniChar c1 = CFStringGetCharacterFromInlineBuffer(&buf, i);
-        UniChar c2 = (uchar) chs[i];
-        if (c1 != c2)
-            return false;
-    }
-    return true;
+    if (s1.data()->_isAsciiValid)
+        return (strcmp(s1.ascii(), chs) == 0);
+    return s1==QString(chs);
 }
 
 QString operator+(const QString &qs1, const QString &qs2)
@@ -1322,17 +2571,191 @@ QString operator+(char ch, const QString &qs)
     return tmp;
 }
 
-QConstString::QConstString(const QChar *qcs, uint len)
+QConstString::QConstString(const QChar* unicode, uint length ) :
+    QString(new QStringData((QChar *)unicode, length, length),TRUE)
+{
+}
+
+
+QConstString::~QConstString()
 {
-    if (qcs || len) {
-        // NOTE: use instead of CFStringCreateWithCharactersNoCopy function to
-        // guarantee backing store is not copied even though string is mutable
-        //s = CFStringCreateMutableWithExternalCharactersNoCopy(
-        //        kCFAllocatorDefault, &qcs->c, len, len, kCFAllocatorNull);
-        s = CFStringCreateMutable(kCFAllocatorDefault, 0);
-        CFStringAppendCharacters(s, &qcs->c, len);
+    if ( (*dataHandle)->refCount > 1 ) {
+        QChar *tp, *fp = (QChar *)unicode();
+        if ((*dataHandle)->_length <= QS_INTERNAL_BUFFER_UCHARS){
+            (*dataHandle)->_maxUnicode = QS_INTERNAL_BUFFER_UCHARS;
+            tp = (QChar *)&(*dataHandle)->_internalBuffer[0];
+            (*dataHandle)->_isUnicodeInternal = 1;
+        }
+        else {
+            (*dataHandle)->_maxUnicode = ALLOC_QCHAR_GOOD_SIZE((*dataHandle)->_length);
+            tp = ALLOC_QCHAR( (*dataHandle)->_maxUnicode );
+            (*dataHandle)->_isUnicodeInternal = 0;
+        }
+        memcpy( tp, fp, (*dataHandle)->_length*sizeof(QChar) );
+        (*dataHandle)->_unicode = tp;
+	(*dataHandle)->_isUnicodeValid = 1;
+        (*dataHandle)->_isAsciiValid = 0;
     } else {
-        s = getNullCFString();
+	(*dataHandle)->_unicode = 0;
+    }
+}
+
+#define NODE_BLOCK_SIZE ((vm_page_size)/sizeof(HandleNode))
+
+#define TO_NODE_OFFSET(ptr)   ((uint)(((uint)ptr - (uint)base)/sizeof(HandleNode)))
+#define TO_NODE_ADDRESS(offset,base) ((HandleNode *)(offset*sizeof(HandleNode) + (uint)base))
+
+typedef struct _HandlePageNode
+{
+    struct _HandlePageNode *next;
+    struct _HandlePageNode *previous;
+    void *nodes;
+} HandlePageNode;
+
+typedef struct _HandleNode {
+    union {
+        struct {
+            uint next:16;
+            uint previous:16;
+        } internalNode;
+        
+        struct _HandleNode *freeNodes;  // Always at block[0] in page.
+        
+        HandlePageNode *pageNode;	// Always at block[1] in page
+        
+        void *handle;
+    } type;
+} HandleNode;
+
+
+HandleNode *firstBlock;
+HandlePageNode *usedNodeAllocationPages = 0;
+HandlePageNode *freeNodeAllocationPages = 0;
+
+static HandleNode *_initializeHandleNodeBlock(HandlePageNode *pageNode)
+{
+    uint i;
+    HandleNode *block, *aNode;
+    
+    vm_allocate(mach_task_self(), (vm_address_t *)&block, vm_page_size, 1);
+    //printf ("allocated block at 0%08x, page boundary 0x%08x\n", (unsigned int)block, (unsigned int)trunc_page((uint)block));
+    
+    for (i = 2; i < NODE_BLOCK_SIZE; i++){
+        aNode = &block[i];
+        if (i > 2) {
+            aNode->type.internalNode.previous = i-1;
+        }
+        else {
+            aNode->type.internalNode.previous = 0;
+        }
+        if (i != NODE_BLOCK_SIZE-1)
+            aNode->type.internalNode.next = i+1;
+        else
+            aNode->type.internalNode.next = 0;
+    }
+    block[0].type.freeNodes = &block[NODE_BLOCK_SIZE-1];
+    block[1].type.pageNode = pageNode;
+
+    return block;
+}
+
+HandlePageNode *_allocatePageNode()
+{
+    HandlePageNode *node = (HandlePageNode *)malloc(sizeof(HandlePageNode));
+    node->next = node->previous = 0;
+    node->nodes = _initializeHandleNodeBlock(node);
+    return node;
+}
+
+
+void _initializeHandleNodes()
+{
+    if (freeNodeAllocationPages == 0)
+        freeNodeAllocationPages = _allocatePageNode();    
+}
+
+HandleNode *_allocateNode(HandlePageNode *pageNode)
+{
+    HandleNode *block = (HandleNode *)pageNode->nodes;
+    HandleNode *freeNodes = block[0].type.freeNodes;
+    HandleNode *allocated;
+    
+    // Check to see if we're out of nodes.
+    if (freeNodes == 0) {
+        printf ("error!\n");
+        return 0;
+    }
+    
+    // Remove node from end of free list 
+    allocated = freeNodes;
+    if (allocated->type.internalNode.previous >= 2) {
+        block[0].type.freeNodes = TO_NODE_ADDRESS(allocated->type.internalNode.previous, block);
+        block[0].type.freeNodes->type.internalNode.next = 0;
+    }
+    else {
+        // Used last noded on this page.
+        block[0].type.freeNodes = 0;
+        
+        freeNodeAllocationPages = freeNodeAllocationPages->previous;
+
+        pageNode->previous = usedNodeAllocationPages;
+        pageNode->next = 0;
+        if (usedNodeAllocationPages)
+            usedNodeAllocationPages->next = pageNode;
+        usedNodeAllocationPages = pageNode;        
     }
-    cache = NULL;
+        
+    return allocated;
+}
+
+
+void *allocateHandle()
+{
+    _initializeHandleNodes();
+    
+#ifdef QSTRING_DEBUG_ALLOCATIONS
+    handleInstances++;
+#endif
+
+    return _allocateNode (freeNodeAllocationPages);
+}
+
+
+void freeHandle(void *_free)
+{
+    HandleNode *free = (HandleNode *)_free;
+    HandleNode *base = (HandleNode *)trunc_page((uint)free);
+    HandleNode *freeNodes = base[0].type.freeNodes;
+    HandlePageNode *pageNode = base[1].type.pageNode;
+    
+    if (freeNodes == 0){
+        free->type.internalNode.previous = 0;
+    }
+    else {
+        // Insert at head of free list.
+        free->type.internalNode.previous = TO_NODE_OFFSET(freeNodes);
+        freeNodes->type.internalNode.next = TO_NODE_OFFSET(free);
+    }
+    free->type.internalNode.next = 0;
+    base[0].type.freeNodes = free;
+    
+    // Remove page from used/free list and place on free list
+    if (usedNodeAllocationPages == pageNode)
+        usedNodeAllocationPages = usedNodeAllocationPages->previous;
+    else if (freeNodeAllocationPages != pageNode){
+        if (pageNode->previous)
+            pageNode->previous->next = pageNode->next;
+        if (pageNode->next)
+            pageNode->next->previous = pageNode->previous;
+    
+        pageNode->previous = freeNodeAllocationPages;
+        pageNode->next = 0;
+        if (freeNodeAllocationPages)
+            freeNodeAllocationPages->next = pageNode;
+        freeNodeAllocationPages = pageNode;
+    }
+    
+#ifdef QSTRING_DEBUG_ALLOCATIONS
+    handleInstances--;
+#endif
 }
diff --git a/WebCore/kwq/qt/qstring.h b/WebCore/kwq/qt/qstring.h
index 8478e6e..a971e5b 100644
--- a/WebCore/kwq/qt/qstring.h
+++ b/WebCore/kwq/qt/qstring.h
@@ -264,6 +264,64 @@ inline bool operator<(char ch, QChar qc)
     return (uchar) ch < qc.c;
 }
 
+// Keep this struct to <= 46 bytes, that's what the system will allocate.
+// Will be rounded up even multiple of for, so we're stuck at 44.
+
+#define QS_INTERNAL_BUFFER_SIZE 20
+#define QS_INTERNAL_BUFFER_CHARS QS_INTERNAL_BUFFER_SIZE-1
+#define QS_INTERNAL_BUFFER_UCHARS QS_INTERNAL_BUFFER_SIZE/2
+
+struct QStringData {
+    // Uses shared null data.
+    QStringData();
+    void initialize();
+    
+    // No copy.
+    QStringData(QChar *u, uint l, uint m);
+    void initialize(QChar *u, uint l, uint m);
+    
+    // Copy bytes;
+    QStringData(const QChar *u, uint l);
+    void initialize(const QChar *u, uint l);
+
+    // Copy bytes;
+    QStringData(const char *u, uint l);
+    void initialize(const char *u, uint l);
+
+    ~QStringData();
+
+#ifdef QSTRING_DEBUG_ALLOCATIONS
+    void* operator new(size_t s);
+    void operator delete(void*p);
+#endif
+
+
+    inline void ref() { refCount++; }
+    inline void deref() { if (--refCount == 0 && _isHeapAllocated) delete this; }
+        
+    char *ascii();
+    char *makeAscii();
+    void increaseAsciiSize(uint size);
+
+    QChar *unicode();
+    QChar *makeUnicode();    
+    void increaseUnicodeSize(uint size);
+        
+    uint refCount;
+    uint _length;
+    mutable QChar *_unicode;
+    mutable char *_ascii;
+    uint _maxUnicode:29;
+    uint _isUnicodeInternal:1;
+    uint _isUnicodeValid:1;
+    uint _isHeapAllocated:1;	// Fragile, but the only way we can be sure the instance was
+                                // created with 'new'.
+    uint _maxAscii:30;
+    uint _isAsciiInternal:1;
+    uint _isAsciiValid:1;
+    char _internalBuffer[QS_INTERNAL_BUFFER_SIZE]; // Pad out to a (((size + 1) & ~15) + 14) size
+};
+
 class QString {
 public:
     static const QString null;
@@ -318,11 +376,13 @@ public:
     int find(const QRegExp &, int index=0) const;
 
     int findRev(char, int index=-1) const;
+    int findRev(const QString& str, int index, bool cs=true ) const;
     int findRev(const char *, int index=-1) const;
 
     int contains(char) const;
     int contains(const char *, bool cs=true) const;
     int contains(const QString &, bool cs=true) const;
+    int contains( QChar c, bool cs=true ) const;
 
     bool endsWith(const QString &) const;
 
@@ -346,6 +406,8 @@ public:
     static QString number(ulong);
     static QString number(double);
 
+    bool findArg(int& pos, int& len) const;
+    
     QString arg(const QString &, int width=0) const;
     QString arg(short, int width=0) const;
     QString arg(ushort, int width=0) const;
@@ -366,7 +428,7 @@ public:
     QString simplifyWhiteSpace() const;
 
     QString &setUnicode(const QChar *, uint);
-    QString &setLatin1(const char *);
+    QString &setLatin1(const char *, int len=-1);
 
     QString &setNum(short);
     QString &setNum(ushort);
@@ -384,6 +446,8 @@ public:
     QString &insert(uint, QChar);
     QString &insert(uint, char);
     QString &remove(uint, uint);
+    QString &replace( uint index, uint len, const QString &s );
+    //QString &replace( uint index, uint len, const QChar* s, uint slen );
     QString &replace(const QRegExp &, const QString &);
 
     void truncate(uint);
@@ -403,17 +467,31 @@ public:
     QString &operator+=(QChar);
     QString &operator+=(char);
 
+    void setBufferFromCFString(CFStringRef cfs);
+    
 private:
+    // Used by QConstString.
+    QString(QStringData *constData, bool /*dummy*/);
+    void detach();
+    void detachInternal();
+    void deref();
+    void forceUnicode();
+    void setLength( uint pos );
+
+    struct QStringData *data() const;
+    
     enum CacheType { CacheInvalid, CacheUnicode, CacheLatin1 };
 
-    void flushCache() const;
     QCString convertToQCString(CFStringEncoding) const;
-    ulong convertToNumber(bool *ok, int base, bool *neg) const;
-    QString leftRight(uint width, bool left) const;
     int compareToLatin1(const char *chs) const;
 
-    CFMutableStringRef s;
-    mutable void *cache;
+    struct QStringData **dataHandle;
+    struct QStringData internalData;
+    
+    static QStringData* shared_null;
+    static QStringData* makeSharedNull();
+    static QStringData**shared_null_handle;
+    static QStringData**makeSharedNullHandle();
 
     friend bool operator==(const QString &, const QString &);
     friend bool operator==(const QString &, const char *);
@@ -441,9 +519,7 @@ private:
 
     friend class QConstString;
     friend class QGDict;
-
-    void _copyIfNeededInternalString();
-
+    friend struct QStringData;
 };
 
 QString operator+(const QString &, const QString &);
@@ -454,9 +530,11 @@ QString operator+(const char *, const QString &);
 QString operator+(QChar, const QString &);
 QString operator+(char, const QString &);
 
+inline struct QStringData *QString::data() const { return *dataHandle; }
+
 inline uint QString::length() const
 {
-    return CFStringGetLength(s);
+    return data()->_length;
 }
 
 inline bool QString::isEmpty() const
@@ -464,21 +542,6 @@ inline bool QString::isEmpty() const
     return length() == 0;
 }
 
-inline int QString::compare(const QString &qs) const
-{
-    return CFStringCompare(s, qs.s, 0);
-}
-
-inline bool QString::startsWith(const QString &qs) const
-{
-    return CFStringHasPrefix(s, qs.s);
-}
-
-inline bool QString::endsWith(const QString &qs) const
-{
-    return CFStringHasSuffix(s, qs.s);
-}
-
 inline QString QString::fromLatin1(const char *chs)
 {
     return chs;
@@ -504,16 +567,6 @@ inline const QChar QString::operator[](int index) const
     return at(index);
 }
 
-inline CFMutableStringRef QString::getCFMutableString() const
-{
-    return s;
-}
-
-inline NSString *QString::getNSString() const
-{
-    return (NSString *)s;
-}
-
 inline bool operator==(const char *chs, const QString &qs)
 {
     return qs == chs;
@@ -597,6 +650,7 @@ inline bool operator>=(const char *chs, const QString &qs)
 class QConstString : private QString {
 public:
     QConstString(const QChar *, uint);
+    ~QConstString();
     const QString &string() const { return *this; }
 };
 

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list