A QByteArray
is not a way to store QChar
s: QString
is. Given that, the implementation is not complicated. The switch-over point between using ws.contains
and std::binary_search
should be selected based on a benchmark.
The trimmedRef
, trimmedLeftRef
and trimmedRightRef
are optimizations that don't copy the source string. They can be used when the trimmed version of the string doesn't outlive the source string - this avoids a copy.
#include <QString>
#include <algorithm>
namespace detail { struct IsSpace final {
static QString sorted(QString s) {
std::sort(s.begin(), s.end());
return s;
}
QString const ws;
QString::const_iterator begin = ws.cBegin(), end = ws.cEnd();
bool (IsSpace::*test)(QChar) const =
ws.isEmpty() ? &IsSpace::test1 :
(ws.size() <= 8) ? &IsSpace::test2 :
&IsSpace::test3;
explicit IsSpace(const QString &whitespace) : ws(sorted(whitespace)) {}
bool test1(const QChar c) const { return c.isSpace(); }
bool test2(const QChar c) const { return ws.contains(c); }
bool test3(const QChar c) const { return std::binary_search(begin, end, c); }
inline bool operator()(QChar c) const { return (*this.*test)(c); }
}; }
enum TrimmedOption { TrimmedLeft = 1, TrimmedRight = 2 };
Q_DECLARE_FLAGS(TrimmedOptions, TrimmedOption)
Q_DECLARE_OPERATORS_FOR_FLAGS(TrimedOptions)
QStringRef trimmedRef(const QString &src, const QString &whitespace,
TrimmedOptions opt = TrimmedLeft | TrimmedRight) {
detail::IsSpace const isSpace{whitespace};
int l = 0;
if (options & TrimmedLeft)
while (l < src.length() && isSpace(src[l]))
l++;
int r = src.length();
if (options & TrimmedRight)
while (r > 0 && isSpace(src[r-1]))
r--;
return {&src, l, r-l};
}
QStringRef trimmedLeftRef(const QString &src, const QString &whitespace = {}) {
return trimmedRef(src, whitespace, TrimmedLeft);
}
QStringRef trimmedRightRef(const QString &src, const QString &whitespace = {}) {
return trimmed(src, whitespace, TrimmedRight);
}
QString trimmed(const QString &src, const QString &whitespace,
TrimmedOptions opt = TrimmedLeft | TrimmedRight) {
return trimmedRef(src, whitespace, opt);
}
QString trimmedLeft(const QString &src, const QString &whitespace = {}) {
return trimmedRef(src, whitespace, TrimmedLeft);
}
QString trimmedRight(const QString &src, const QString &whitespace = {}) {
return trimmedRef(src, whitespace, TrimmedRight);
}