Q(Any|Utf8)StringView: move array size deduction feature to fromArray

The constructor taking an array literal will now stop at the first
null-terminator encountered.

And fromArray is introduced which only supports array literals.
Constructs a view of the full size. Explicit so it shouldn't be
surprising.

Change-Id: I1497c33a5c12453a95e87c990abe6335b2817081
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Mårten Nordheim 2020-09-16 12:04:31 +02:00
parent bbe7570ddc
commit 107ff4c1d6
10 changed files with 130 additions and 33 deletions

View File

@ -54,6 +54,6 @@
//! [0]
//! [2]
auto sv1 = QAnyStringView{std::begin(array), std::end(array)}; // using C++11 std::begin()/std::end()
auto sv2 = QAnyStringView(array, std::size(array)); // using C++17 std::size()
auto sv1 = QAnyStringView{std::begin(array), std::end(array) - 1}; // using C++11 std::begin()/std::end()
auto sv2 = QAnyStringView(array, std::size(array) - 1); // using C++17 std::size()
//! [2]

View File

@ -56,7 +56,3 @@
//! [1]
void fun(QChar ch) { fun(QStringView(&ch, 1)); }
//! [1]
//! [2]
auto sv = QStringView(array, std::size(array)); // using C++17 std::size()
//! [2]

View File

@ -52,8 +52,3 @@
void myfun1(QUtf8StringView sv); // preferred
void myfun2(const QUtf8StringView &sv); // compiles and works, but slower
//! [0]
//! [2]
auto sv1 = QUtf8StringView{std::begin(array), std::end(array)}; // using C++11 std::begin()/std::end()
auto sv2 = QUtf8StringView(array, std::size(array)); // using C++17 std::size()
//! [2]

View File

@ -109,9 +109,11 @@ private:
}
template <typename Char, size_t N>
static constexpr qsizetype lengthHelperContainer(const Char (&)[N]) noexcept
static constexpr qsizetype lengthHelperContainer(const Char (&str)[N]) noexcept
{
return qsizetype(N - 1);
const auto it = std::char_traits<Char>::find(str, N, Char(0));
const auto end = it ? it : std::next(str, N);
return qsizetype(std::distance(str, end));
}
static QChar toQChar(char ch) noexcept { return toQChar(QLatin1Char{ch}); } // we don't handle UTF-8 multibytes
@ -180,6 +182,10 @@ public:
constexpr QAnyStringView(QBasicUtf8StringView<UseChar8T> v) noexcept
: QAnyStringView(std::data(v), lengthHelperContainer(v)) {}
template <typename Char, size_t Size, if_compatible_char<Char> = true>
[[nodiscard]] constexpr static QAnyStringView fromArray(const Char (&string)[Size]) noexcept
{ return QAnyStringView(string, Size); }
// defined in qstring.h:
template <typename Visitor>
inline constexpr decltype(auto) visit(Visitor &&v) const;

View File

@ -197,11 +197,9 @@
\fn template <typename Char, size_t N> QAnyStringView::QAnyStringView(const Char (&string)[N])
Constructs a string view on the character string literal \a string.
The length is set to \c{N-1}, excluding the trailing \c{Char(0)}.
If you need the full array, use the constructor from pointer and
size instead:
\snippet code/src_corelib_text_qanystringview.cpp 2
The view covers the array until the first \c{Char(0)} is encountered,
or \c N, whichever comes first.
If you need the full array, use fromArray() instead.
\a string must remain valid for the lifetime of this string view
object.
@ -250,6 +248,27 @@
\sa isNull(), isEmpty(), {Compatible Character Types}
*/
/*!
\fn template <typename Char, size_t Size> static QAnyStringView fromArray(const Char (&string)[Size]) noexcept
Constructs a string view on the full character string literal \a string,
including any trailing \c{Char(0)}. If you don't want the
null-terminator included in the view then you can use the constructor
overload taking a pointer and a size:
\snippet code/src_corelib_text_qanystringview.cpp 2
Alternatively you can use the constructor overload taking an
array literal which will create a view up to, but not including,
the first null-terminator in the data.
\a string must remain valid for the lifetime of this string view
object.
This function will work with any array literal if \c Char is a
compatible character type.
*/
/*!
\fn QString QAnyStringView::toString() const

View File

@ -278,11 +278,9 @@ QT_BEGIN_NAMESPACE
\fn template <typename Char, size_t N> QStringView::QStringView(const Char (&string)[N])
Constructs a string view on the character string literal \a string.
The length is set to \c{N-1}, excluding the trailing \{Char(0)}.
If you need the full array, use the constructor from pointer and
size instead:
\snippet code/src_corelib_text_qstringview.cpp 2
The view covers the array until the first \c{Char(0)} is encountered,
or \c N, whichever comes first.
If you need the full array, use fromArray() instead.
\a string must remain valid for the lifetime of this string view
object.
@ -292,6 +290,8 @@ QT_BEGIN_NAMESPACE
type. The compatible character types are: \c QChar, \c ushort, \c
char16_t and (on platforms, such as Windows, where it is a 16-bit
type) \c wchar_t.
\sa fromArray
*/
/*!
@ -323,6 +323,25 @@ QT_BEGIN_NAMESPACE
\sa isNull(), isEmpty()
*/
/*!
\fn template <typename Char, size_t Size> static QStringView fromArray(const Char (&string)[Size]) noexcept
Constructs a string view on the full character string literal \a string,
including any trailing \c{Char(0)}. If you don't want the
null-terminator included in the view then you can chop() it off
when you are certain it is at the end. Alternatively you can use
the constructor overload taking an array literal which will create
a view up to, but not including, the first null-terminator in the data.
\a string must remain valid for the lifetime of this string view
object.
This function will work with any array literal if \c Char is a
compatible character type. The compatible character types are: \c QChar, \c ushort, \c
char16_t and (on platforms, such as Windows, where it is a 16-bit
type) \c wchar_t.
*/
/*!
\fn QString QStringView::toString() const

View File

@ -172,9 +172,11 @@ private:
}
template <typename Char, size_t N>
static constexpr qsizetype lengthHelperContainer(const Char (&)[N]) noexcept
static constexpr qsizetype lengthHelperContainer(const Char (&str)[N]) noexcept
{
return qsizetype(N - 1);
const auto it = std::char_traits<Char>::find(str, N, Char(0));
const auto end = it ? it : std::next(str, N);
return qsizetype(std::distance(str, end));
}
template <typename Char>
@ -223,6 +225,10 @@ public:
constexpr QStringView(const Container &c) noexcept
: QStringView(std::data(c), lengthHelperContainer(c)) {}
template <typename Char, size_t Size, if_compatible_char<Char> = true>
[[nodiscard]] constexpr static QStringView fromArray(const Char (&string)[Size]) noexcept
{ return QStringView(string, Size); }
Q_REQUIRED_RESULT inline QString toString() const; // defined in qstring.h
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
// defined in qcore_foundation.mm

View File

@ -160,9 +160,11 @@ private:
// Note: Do not replace with std::size(const Char (&)[N]), cause the result
// will be of by one.
template <typename Char, size_t N>
static constexpr qsizetype lengthHelperContainer(const Char (&)[N]) noexcept
static constexpr qsizetype lengthHelperContainer(const Char (&str)[N]) noexcept
{
return qsizetype(N - 1);
const auto it = std::char_traits<Char>::find(str, N, Char(0));
const auto end = it ? it : std::next(str, N);
return qsizetype(std::distance(str, end));
}
template <typename Char>
@ -216,6 +218,10 @@ public:
: QBasicUtf8StringView(other.data(), other.size()) {}
#endif
template <typename Char, size_t Size, if_compatible_char<Char> = true>
[[nodiscard]] constexpr static QBasicUtf8StringView fromArray(const Char (&string)[Size]) noexcept
{ return QBasicUtf8StringView(string, Size); }
[[nodiscard]] inline QString toString() const; // defined in qstring.h
[[nodiscard]] constexpr qsizetype size() const noexcept { return m_size; }

View File

@ -318,11 +318,9 @@
\fn template <typename Char, size_t N> QUtf8StringView::QUtf8StringView(const Char (&string)[N])
Constructs a string view on the character string literal \a string.
The length is set to \c{N-1}, excluding the trailing \c{Char(0)}.
If you need the full array, use the constructor from pointer and
size instead:
\snippet code/src_corelib_text_qutf8stringview.cpp 2
The view covers the array until the first \c{Char(0)} is encountered,
or \c N, whichever comes first.
If you need the full array, use fromArray() instead.
\a string must remain valid for the lifetime of this string view
object.
@ -331,6 +329,8 @@
is an actual array and if \c Char is a compatible character type. The
compatible character types are: \c char8_t, \c char, \c{signed char} and
\c{unsigned char}.
\sa fromArray
*/
/*!
@ -352,6 +352,24 @@
\sa isNull(), isEmpty()
*/
/*!
\fn template <typename Char, size_t Size> static QBasicUtf8StringView fromArray(const Char (&string)[Size])
Constructs a string view on the full character string literal \a string,
including any trailing \c{Char(0)}. If you don't want the
null-terminator included in the view then you can chop() it off
when you are certain it is at the end. Alternatively you can use
the constructor overload taking an array literal which will create
a view up to, but not including, the first null-terminator in the data.
\a string must remain valid for the lifetime of this string view
object.
This function will work with any array literal if \c Char is a
compatible character type. The compatible character types
are: \c char8_t, \c char, \c{signed char} and \c{unsigned char}.
*/
/*!
\fn QString QUtf8StringView::toString() const

View File

@ -157,6 +157,7 @@ private Q_SLOTS:
void constExpr() const;
void basics() const;
void literals() const;
void fromArray() const;
void at() const;
void arg() const;
@ -425,10 +426,41 @@ void tst_QStringView::literals() const
}
// these are different results
QCOMPARE(size_t(QStringView(withnull).size()), sizeof(withnull)/sizeof(withnull[0]) - 1);
QCOMPARE(size_t(QStringView(withnull).size()), 1);
QCOMPARE(size_t(QStringView::fromArray(withnull).size()), sizeof(withnull)/sizeof(withnull[0]));
QCOMPARE(QStringView(withnull + 0).size(), 1);
}
void tst_QStringView::fromArray() const
{
static constexpr char16_t hello[] = u"Hello\0abc\0\0.";
constexpr QStringView sv = QStringView::fromArray(hello);
QCOMPARE(sv.size(), 13);
QVERIFY(!sv.empty());
QVERIFY(!sv.isEmpty());
QVERIFY(!sv.isNull());
QCOMPARE(*sv.data(), 'H');
QCOMPARE(sv[0], 'H');
QCOMPARE(sv.at(0), 'H');
QCOMPARE(sv.front(), 'H');
QCOMPARE(sv.first(), 'H');
QCOMPARE(sv[4], 'o');
QCOMPARE(sv.at(4), 'o');
QCOMPARE(sv[5], '\0');
QCOMPARE(sv.at(5), '\0');
QCOMPARE(*(sv.data() + sv.size() - 2), '.');
QCOMPARE(sv.back(), '\0');
QCOMPARE(sv.last(), '\0');
const char16_t bytes[] = {u'a', u'b', u'c'};
QStringView sv2 = QStringView::fromArray(bytes);
QCOMPARE(sv2.data(), reinterpret_cast<const QChar *>(bytes + 0));
QCOMPARE(sv2.size(), 3);
QCOMPARE(sv2.first(), u'a');
QCOMPARE(sv2.last(), u'c');
}
void tst_QStringView::at() const
{
QString hello("Hello");