QByteArrayView: move array size deduction feature to fromArray
1. Make the ctor unable to construct a QByteArrayView from
array literals other than 'char'.
With the new behavior it would either be (very likely) unintended to
pass e.g. a std::byte array to the ctor. And it would be confusing
because you would get different sizes based on signed-ness.
2. Introduce fromArray
Only supports array literals. Constructs a view of the full size.
Explicit so it shouldn't be surprising.
Change-Id: Ifdb55eb21057dfe7053b2561bd81e2c9825e9bc6
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
bb10
parent
7a5e0c5712
commit
bbe7570ddc
|
|
@ -58,10 +58,3 @@
|
|||
void fun(QByteArrayView bv);
|
||||
void fun(char ch) { fun(QByteArrayView(&ch, 1)); }
|
||||
//! [1]
|
||||
|
||||
void wrapper() {
|
||||
const char array[1] = { 0 };
|
||||
//! [2]
|
||||
auto bv = QByteArrayView(array, std::size(array)); // using C++17 std::size()
|
||||
//! [2]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,6 +94,9 @@ struct IsContainerCompatibleWithQByteArrayView<T, std::enable_if_t<
|
|||
// This needs to be treated specially due to the empty vs null distinction
|
||||
std::negation<std::is_same<std::decay_t<T>, QByteArray>>,
|
||||
|
||||
// We handle array literals specially for source compat reasons
|
||||
std::negation<std::is_array<T>>,
|
||||
|
||||
// Don't make an accidental copy constructor
|
||||
std::negation<std::is_same<std::decay_t<T>, QByteArrayView>>>>> : std::true_type {};
|
||||
|
||||
|
|
@ -147,10 +150,11 @@ private:
|
|||
return qsizetype(std::size(c));
|
||||
}
|
||||
|
||||
template <typename Char, size_t N>
|
||||
static constexpr qsizetype lengthHelperContainer(const Char (&)[N]) noexcept
|
||||
static constexpr qsizetype lengthHelperCharArray(const char *data, size_t size) noexcept
|
||||
{
|
||||
return qsizetype(N - 1);
|
||||
const auto it = std::char_traits<char>::find(data, size, '\0');
|
||||
const auto end = it ? it : std::next(data, size);
|
||||
return qsizetype(std::distance(data, end));
|
||||
}
|
||||
|
||||
template <typename Byte>
|
||||
|
|
@ -175,9 +179,6 @@ public:
|
|||
: QByteArrayView(first, last - first) {}
|
||||
|
||||
#ifdef Q_QDOC
|
||||
template <typename Byte, size_t N>
|
||||
constexpr QByteArrayView(const Byte (&array)[N]) noexcept;
|
||||
|
||||
template <typename Byte>
|
||||
constexpr QByteArrayView(const Byte *data) noexcept;
|
||||
#else
|
||||
|
|
@ -198,6 +199,13 @@ public:
|
|||
template <typename Container, if_compatible_container<Container> = true>
|
||||
constexpr QByteArrayView(const Container &c) noexcept
|
||||
: QByteArrayView(std::data(c), lengthHelperContainer(c)) {}
|
||||
template <size_t Size>
|
||||
constexpr QByteArrayView(const char (&data)[Size]) noexcept
|
||||
: QByteArrayView(data, lengthHelperCharArray(data, Size)) {}
|
||||
|
||||
template <typename Byte, size_t Size, if_compatible_byte<Byte> = true>
|
||||
[[nodiscard]] constexpr static QByteArrayView fromArray(const Byte (&data)[Size]) noexcept
|
||||
{ return QByteArrayView(data, Size); }
|
||||
|
||||
[[nodiscard]] inline QByteArray toByteArray() const; // defined in qbytearray.h
|
||||
|
||||
|
|
|
|||
|
|
@ -256,23 +256,25 @@
|
|||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename Byte, size_t N> QByteArrayView::QByteArrayView(const Byte (&data)[N])
|
||||
\fn template <size_t Size> QByteArrayView(const char (&data)[Size])
|
||||
|
||||
Constructs a byte array view on the array of bytes \a data.
|
||||
The length is set to \c{N-1}, excluding the trailing \{Byte(0)}.
|
||||
If you need the full array, use the constructor from pointer and
|
||||
size instead:
|
||||
|
||||
\snippet code/src_corelib_text_qbytearrayview.cpp 2
|
||||
Constructs a byte array view on the char array \a data.
|
||||
The view covers the array until the first \c{'\0'} is encountered,
|
||||
or \c Size, whichever comes first.
|
||||
If you need the full array, use fromArray() instead.
|
||||
|
||||
\a data must remain valid for the lifetime of this byte array view
|
||||
object.
|
||||
|
||||
This constructor only participates in overload resolution if \a
|
||||
data is an actual array and \c Byte is a compatible byte
|
||||
type.
|
||||
\note This constructor is only available for char array literals.
|
||||
The reasoning behind that is for compatibility with C-libraries
|
||||
which predefine "large-enough" arrays, but only use some of the
|
||||
preallocated space. To support this in an intuitive way in an
|
||||
implicit constructor overload, we need to stop at the first
|
||||
\c{char(0)}. This is logical for a char array, but not
|
||||
for a \c{std::byte} array.
|
||||
|
||||
\sa {Compatible Byte Types}
|
||||
\sa fromArray
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
|
@ -299,6 +301,21 @@
|
|||
\sa {Compatible Byte Types}
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn template <typename Byte, size_t Size> static QByteArrayView QByteArrayView::fromArray(Byte (&data)[Size])
|
||||
|
||||
Constructs a byte array view on the array literal \a data. The view covers the full
|
||||
array. That includes the trailing null-terminator of \c{char} array literals.
|
||||
If you don't want the null-terminator included in the view, you can chop() it off
|
||||
when you are certain it is at the end. Alternatively you can use the constructor
|
||||
overload taking a char array literal which will create a view up to, but not including,
|
||||
the first null-terminator in the data.
|
||||
|
||||
This function will work with any array literal of a compatible byte type.
|
||||
|
||||
\sa {Compatible Byte Types}, QByteArrayView
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn QByteArray QByteArrayView::toByteArray() const
|
||||
|
||||
|
|
|
|||
|
|
@ -48,20 +48,20 @@ static_assert(CanConvert<char*>);
|
|||
static_assert(CanConvert<const char*>);
|
||||
|
||||
static_assert(!CanConvert<uchar>);
|
||||
static_assert(CanConvert<uchar[1]>);
|
||||
static_assert(CanConvert<const uchar[1]>);
|
||||
static_assert(!CanConvert<uchar[1]>);
|
||||
static_assert(!CanConvert<const uchar[1]>);
|
||||
static_assert(CanConvert<uchar*>);
|
||||
static_assert(CanConvert<const uchar*>);
|
||||
|
||||
static_assert(!CanConvert<signed char>);
|
||||
static_assert(CanConvert<signed char[1]>);
|
||||
static_assert(CanConvert<const signed char[1]>);
|
||||
static_assert(!CanConvert<signed char[1]>);
|
||||
static_assert(!CanConvert<const signed char[1]>);
|
||||
static_assert(CanConvert<signed char*>);
|
||||
static_assert(CanConvert<const signed char*>);
|
||||
|
||||
static_assert(!CanConvert<std::byte>);
|
||||
static_assert(CanConvert<std::byte[1]>);
|
||||
static_assert(CanConvert<const std::byte[1]>);
|
||||
static_assert(!CanConvert<std::byte[1]>);
|
||||
static_assert(!CanConvert<const std::byte[1]>);
|
||||
static_assert(CanConvert<std::byte*>);
|
||||
static_assert(CanConvert<const std::byte*>);
|
||||
|
||||
|
|
@ -110,6 +110,7 @@ private slots:
|
|||
void constExpr() const;
|
||||
void basics() const;
|
||||
void literals() const;
|
||||
void fromArray() const;
|
||||
void literalsWithInternalNulls() const;
|
||||
void at() const;
|
||||
|
||||
|
|
@ -324,9 +325,11 @@ void tst_QByteArrayView::basics() const
|
|||
QVERIFY(!(bv2 != bv1));
|
||||
}
|
||||
|
||||
// Note: initially the size would be deduced from the array literal,
|
||||
// but it caused source compatibility issues so this is currently not the case.
|
||||
void tst_QByteArrayView::literals() const
|
||||
{
|
||||
const char hello[] = "Hello";
|
||||
const char hello[] = "Hello\0This shouldn't be found";
|
||||
|
||||
QCOMPARE(QByteArrayView(hello).size(), 5);
|
||||
QCOMPARE(QByteArrayView(hello + 0).size(), 5); // forces decay to pointer
|
||||
|
|
@ -349,6 +352,44 @@ void tst_QByteArrayView::literals() const
|
|||
QVERIFY(!bv2.isNull());
|
||||
QVERIFY(!bv2.empty());
|
||||
QCOMPARE(bv2.size(), 5);
|
||||
|
||||
const char abc[] = "abc";
|
||||
bv = abc;
|
||||
QCOMPARE(bv.size(), 3);
|
||||
|
||||
const char def[3] = {'d', 'e', 'f'};
|
||||
bv = def;
|
||||
QCOMPARE(bv.size(), 3);
|
||||
}
|
||||
|
||||
void tst_QByteArrayView::fromArray() const
|
||||
{
|
||||
static constexpr char hello[] = "Hello\0abc\0\0.";
|
||||
|
||||
constexpr QByteArrayView bv = QByteArrayView::fromArray(hello);
|
||||
QCOMPARE(bv.size(), 13);
|
||||
QVERIFY(!bv.empty());
|
||||
QVERIFY(!bv.isEmpty());
|
||||
QVERIFY(!bv.isNull());
|
||||
QCOMPARE(*bv.data(), 'H');
|
||||
QCOMPARE(bv[0], 'H');
|
||||
QCOMPARE(bv.at(0), 'H');
|
||||
QCOMPARE(bv.front(), 'H');
|
||||
QCOMPARE(bv.first(), 'H');
|
||||
QCOMPARE(bv[4], 'o');
|
||||
QCOMPARE(bv.at(4), 'o');
|
||||
QCOMPARE(bv[5], '\0');
|
||||
QCOMPARE(bv.at(5), '\0');
|
||||
QCOMPARE(*(bv.data() + bv.size() - 2), '.');
|
||||
QCOMPARE(bv.back(), '\0');
|
||||
QCOMPARE(bv.last(), '\0');
|
||||
|
||||
const std::byte bytes[] = {std::byte(0x0), std::byte(0x1), std::byte(0x2)};
|
||||
QByteArrayView bbv = QByteArrayView::fromArray(bytes);
|
||||
QCOMPARE(bbv.data(), reinterpret_cast<const char *>(bytes + 0));
|
||||
QCOMPARE(bbv.size(), 3);
|
||||
QCOMPARE(bbv.first(), 0x0);
|
||||
QCOMPARE(bbv.last(), 0x2);
|
||||
}
|
||||
|
||||
void tst_QByteArrayView::literalsWithInternalNulls() const
|
||||
|
|
@ -356,36 +397,39 @@ void tst_QByteArrayView::literalsWithInternalNulls() const
|
|||
const char withnull[] = "a\0zzz";
|
||||
|
||||
// these are different results
|
||||
QCOMPARE(size_t(QByteArrayView(withnull).size()), sizeof(withnull)/sizeof(withnull[0]) - 1);
|
||||
QCOMPARE(size_t(QByteArrayView::fromArray(withnull).size()), std::size(withnull));
|
||||
QCOMPARE(QByteArrayView(withnull + 0).size(), 1);
|
||||
|
||||
QByteArrayView nulled(withnull);
|
||||
QByteArrayView nulled = QByteArrayView::fromArray(withnull);
|
||||
QCOMPARE(nulled.last(), '\0');
|
||||
nulled.chop(1); // cut off trailing \0
|
||||
QCOMPARE(nulled[1], '\0');
|
||||
QCOMPARE(nulled.indexOf('\0'), 1);
|
||||
QCOMPARE(nulled.indexOf('z'), 2);
|
||||
QCOMPARE(nulled.lastIndexOf('z'), 4);
|
||||
QCOMPARE(nulled.lastIndexOf('a'), 0);
|
||||
QVERIFY(nulled.startsWith("a\0z"));
|
||||
QVERIFY(!nulled.startsWith("a\0y"));
|
||||
QVERIFY(nulled.startsWith("a\0y"));
|
||||
QVERIFY(!nulled.startsWith(QByteArrayView("a\0y", 3)));
|
||||
QVERIFY(nulled.endsWith("zz"));
|
||||
QVERIFY(nulled.contains("z"));
|
||||
QVERIFY(nulled.contains("\0z"));
|
||||
QVERIFY(!nulled.contains("\0y"));
|
||||
QCOMPARE(nulled.first(5), withnull);
|
||||
QCOMPARE(nulled.last(5), withnull);
|
||||
QCOMPARE(nulled.sliced(0), withnull);
|
||||
QVERIFY(nulled.contains(QByteArrayView("\0z", 2)));
|
||||
QVERIFY(!nulled.contains(QByteArrayView("\0y", 2)));
|
||||
QCOMPARE(nulled.first(5), QByteArrayView(withnull, 5));
|
||||
QCOMPARE(nulled.last(5), QByteArrayView(withnull, 5));
|
||||
QCOMPARE(nulled.sliced(0), QByteArrayView(withnull, 5));
|
||||
QCOMPARE(nulled.sliced(2, 2), "zz");
|
||||
QCOMPARE(nulled.chopped(2), "a\0z");
|
||||
QVERIFY(nulled.chopped(2) != "a\0y");
|
||||
QCOMPARE(nulled.chopped(2), QByteArrayView("a\0z", 3));
|
||||
QVERIFY(nulled.chopped(2) != QByteArrayView("a\0y", 3));
|
||||
QCOMPARE(nulled.count('z'), 3);
|
||||
|
||||
const char nullfirst[] = "\0buzz";
|
||||
QByteArrayView fromnull(nullfirst);
|
||||
QByteArrayView fromnull = QByteArrayView::fromArray(nullfirst);
|
||||
QVERIFY(!fromnull.isEmpty());
|
||||
|
||||
const char nullNotEnd[] = { 'b', 'o', 'w', '\0', 'a', 'f', 't', 'z' };
|
||||
QByteArrayView midNull(nullNotEnd);
|
||||
QCOMPARE(midNull.back(), 't');
|
||||
QByteArrayView midNull = QByteArrayView::fromArray(nullNotEnd);
|
||||
QCOMPARE(midNull.back(), 'z');
|
||||
}
|
||||
|
||||
void tst_QByteArrayView::at() const
|
||||
|
|
@ -522,14 +566,14 @@ void tst_QByteArrayView::fromEmptyLiteral() const
|
|||
|
||||
QCOMPARE(QByteArrayView(null).size(), 0);
|
||||
QCOMPARE(QByteArrayView(null).data(), nullptr);
|
||||
QCOMPARE(QByteArrayView(empty).size(), 0);
|
||||
QCOMPARE(static_cast<const void*>(QByteArrayView(empty).data()),
|
||||
QCOMPARE(QByteArrayView::fromArray(empty).size(), 1);
|
||||
QCOMPARE(static_cast<const void*>(QByteArrayView::fromArray(empty).data()),
|
||||
static_cast<const void*>(empty));
|
||||
|
||||
QVERIFY(QByteArrayView(null).isNull());
|
||||
QVERIFY(QByteArrayView(null).isEmpty());
|
||||
QVERIFY(QByteArrayView(empty).isEmpty());
|
||||
QVERIFY(!QByteArrayView(empty).isNull());
|
||||
QVERIFY(!QByteArrayView::fromArray(empty).isEmpty());
|
||||
QVERIFY(!QByteArrayView::fromArray(empty).isNull());
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
|
|
|
|||
Loading…
Reference in New Issue