Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-3682

Comparaison of strings should compare the shared data pointer first

    XMLWordPrintable

Details

    • Suggestion
    • Resolution: Done
    • P4: Low
    • 4.7.1
    • None
    • None
    • a97862318a6b3f72a05a3e66ebcf5f0e455bb42a

    Description

      String comparison is an expensive operation. The comparison operators of QString and QByteArray could check if the shared data are not the same before doing a comparison of the memory.

      For example:

      bool QString::operator==(const QString &other) const
      {
          return (size() == other.size()) &&
              (memcmp((char*)unicode(),(char*)other.unicode(), size()*sizeof(QChar))==0);
      }
      

      could be rewritten as

      bool QString::operator==(const QString &other) const
      {
          return (d == other.d) || ((size() == other.size()) &&
               (memcmp((char*)unicode(),(char*)other.unicode(), size()*sizeof(QChar))==0));
      }
      

      Moreover, if two string have the the same data but different shared pointer, the data could be shared between the strings. This would reduce the memory usage and speed up the following calls to any comparison operator (but can be slower due to the call to free):

      diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
      index cb6a6be..1cfff34 100644
      --- a/src/corelib/tools/qstring.cpp
      +++ b/src/corelib/tools/qstring.cpp
      @@ -1908,8 +1908,31 @@ QString &QString::replace(QChar c, const QLatin1String &after, Qt::CaseSensitivi
       */
       bool QString::operator==(const QString &other) const
       {
      -    return (size() == other.size()) &&
      -        (memcmp((char*)unicode(),(char*)other.unicode(), size()*sizeof(QChar))==0);
      +    if (d == other.d) {
      +        return true;
      +    } else if (size() == other.size()
      +              && (memcmp((char*)unicode(),(char*)other.unicode(), size()*sizeof(QChar))==0)) {
      +        const bool leftMajor = (d->ref) > (other.d->ref);
      +       QString *rhs = const_cast<QString*>(&other);
      +       QString *lhs = const_cast<QString*>(this);
      +
      +       QString * major;
      +       QString * minor;
      +       if (leftMajor) {
      +            major = lhs;
      +            minor = rhs;
      +       } else {
      +            major = rhs;
      +            minor = lhs;
      +       }
      +        major->d->ref.ref();
      +       Data *otherd = minor->d;
      +        minor->d = major->d;
      +       if (!otherd->ref.deref())
      +            free(otherd);
      +        return true;
      +    }
      +    return false;
       }
      
       /*!
      

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            poulain Benjamin Poulain (closed Nokia identity) (Inactive)
            poulain Benjamin Poulain (closed Nokia identity) (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes