From 92398565fcc3868fb80b6c7c839b2d60bd96a987 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sat, 19 Dec 2015 03:25:39 +0100 Subject: Remove a use of a QMap in QAccessibleTextWidget::attributes() The QMap was only used to hold key/value pairs until they were serialized into a QString at the end of the function. Serialize into QString directly instead, dropping the temporary QMap. The problem is that we'd like to keep the line formatting central while at the same time harnessing the power of QStringBuilder. This is possible with a templated function with an input/output parameter: format_attr(QString &result, const char *key, T &&value) format_attr(result, text-foo, str + str2 + str3); Or with return type deduction: formatted(const char *key, T &&value) -> decltype((expr)) { return expr; } result += formatted(text-foo, str + str2 + str3); I don't like out parameters, and we can't rely on auto return type deduction, yet, so I opted for a miniature expression template solution that can only match the expression attr[key] = value; where 'key' is a const char* and 'value' can be anything that QStringBuilder supports. This allows to keep the syntax of a map while at the same time serializing to QString immediately. The only behavioral difference to the old code is that the attributes are no longer sorted, but order doesn't matter. Saves more than 10KiB in text size on optimized GCC 4.9 Linux AMD64 builds. Change-Id: I7b3bec0466ef24156c693adaa95f0316007e0bfe Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/widgets/accessible/qaccessiblewidgets.cpp | 56 +++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 7 deletions(-) (limited to 'src/widgets/accessible/qaccessiblewidgets.cpp') diff --git a/src/widgets/accessible/qaccessiblewidgets.cpp b/src/widgets/accessible/qaccessiblewidgets.cpp index 9bbc01b5cc..1ecfb43309 100644 --- a/src/widgets/accessible/qaccessiblewidgets.cpp +++ b/src/widgets/accessible/qaccessiblewidgets.cpp @@ -707,6 +707,53 @@ int QAccessibleTextWidget::selectionCount() const return textCursor().hasSelection() ? 1 : 0; } +namespace { +/*! + \internal + \brief Helper class for AttributeFormatter + + This class is returned from AttributeFormatter's indexing operator to act + as a proxy for the following assignment. + + It uses perfect forwarding in its assignment operator to amend the RHS + with the formatting of the key, using QStringBuilder. Consequently, the + RHS can be anything that QStringBuilder supports. +*/ +class AttributeFormatterRef { + QString &string; + const char *key; + friend class AttributeFormatter; + AttributeFormatterRef(QString &string, const char *key) : string(string), key(key) {} +public: + template + void operator=(RHS &&rhs) + { string += QLatin1String(key) + QLatin1Char(':') + std::forward(rhs) + QLatin1Char(';'); } +}; + +/*! + \internal + \brief Small string-builder class that supports a map-like API to serialize key-value pairs. + \code + AttributeFormatter attrs; + attrs["foo"] = QLatinString("hello") + world + QLatin1Char('!'); + \endcode + The key type is always \c{const char*}, and the right-hand-side can + be any QStringBuilder expression. + + Breaking it down, this class provides the indexing operator, stores + the key in an instance of, and then returns, AttributeFormatterRef, + which is the class that provides the assignment part of the operation. +*/ +class AttributeFormatter { + QString string; +public: + AttributeFormatterRef operator[](const char *key) + { return AttributeFormatterRef(string, key); } + + QString toFormatted() const { return string; } +}; +} // unnamed namespace + QString QAccessibleTextWidget::attributes(int offset, int *startOffset, int *endOffset) const { /* The list of attributes can be found at: @@ -766,7 +813,7 @@ QString QAccessibleTextWidget::attributes(int offset, int *startOffset, int *end QTextBlockFormat blockFormat = cursor.blockFormat(); - QMap attrs; + AttributeFormatter attrs; QString family = charFormat.font().family(); if (!family.isEmpty()) { family = family.replace('\\',QStringLiteral("\\\\")); @@ -856,12 +903,7 @@ QString QAccessibleTextWidget::attributes(int offset, int *startOffset, int *end break; } - QString result; - foreach (const QByteArray &attributeName, attrs.keys()) { - result.append(QString::fromLatin1(attributeName)).append(':').append(attrs[attributeName]).append(';'); - } - - return result; + return attrs.toFormatted(); } int QAccessibleTextWidget::cursorPosition() const -- cgit v1.2.3