diff options
author | Marc Mutz <marc.mutz@kdab.com> | 2015-12-19 03:25:39 +0100 |
---|---|---|
committer | Marc Mutz <marc.mutz@kdab.com> | 2015-12-21 09:30:57 +0000 |
commit | 92398565fcc3868fb80b6c7c839b2d60bd96a987 (patch) | |
tree | afe5c93dd0bd50cb97befb9920f9ca8bd41a2877 /src/widgets | |
parent | 6066af7f09460bbf72d7aaca12836ca002dcea2a (diff) |
Remove a use of a QMap in QAccessibleTextWidget::attributes()
The QMap<QByteArray, QString> 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) <ogoffart@woboq.com>
Diffstat (limited to 'src/widgets')
-rw-r--r-- | src/widgets/accessible/qaccessiblewidgets.cpp | 56 |
1 files changed, 49 insertions, 7 deletions
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 <typename RHS> + void operator=(RHS &&rhs) + { string += QLatin1String(key) + QLatin1Char(':') + std::forward<RHS>(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<QByteArray, QString> 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 |