QStringView: add an array ctor

With sufficient enable_if magic, the array ctor can overload the
pointer ctor and statically determine the size of the array passed.
Consequently, remove the sizeof in QStringViewLiteral again.

Change-Id: I486baa3cafefde60ccc5f2b47eb94ee53cefe63c
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Marc Mutz 2017-03-31 19:52:21 +02:00
parent d40dcee642
commit 8b5aa7b6c4
3 changed files with 115 additions and 9 deletions

View File

@ -260,9 +260,33 @@ QT_BEGIN_NAMESPACE
Passing \c nullptr as \a str is safe and results in a null string view.
This constructor only participates in overload resolution 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.
This constructor only participates in overload resolution if \a
str is not an array and 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 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:
\code
auto sv = QStringView(array, std::size(array)); // using C++17 std::size()
\endcode
\a string must remain valid for the lifetime of this string view
object.
This constructor only participates in overload resolution if \a
string is an actual array and \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.
*/
/*!

View File

@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE
# ifndef QT_UNICODE_LITERAL
# error "If you change QStringLiteral, please change QStringViewLiteral, too"
# endif
# define QStringViewLiteral(str) QStringView(QT_UNICODE_LITERAL(str), sizeof(str) - 1)
# define QStringViewLiteral(str) QStringView(QT_UNICODE_LITERAL(str))
#endif
namespace QtPrivate {
@ -69,6 +69,24 @@ template <typename Char>
struct IsCompatibleCharType
: IsCompatibleCharTypeHelper<typename std::remove_cv<typename std::remove_reference<Char>::type>::type> {};
template <typename Array>
struct IsCompatibleArrayHelper : std::false_type {};
template <typename Char, size_t N>
struct IsCompatibleArrayHelper<Char[N]>
: IsCompatibleCharType<Char> {};
template <typename Array>
struct IsCompatibleArray
: IsCompatibleArrayHelper<typename std::remove_cv<typename std::remove_reference<Array>::type>::type> {};
template <typename Pointer>
struct IsCompatiblePointerHelper : std::false_type {};
template <typename Char>
struct IsCompatiblePointerHelper<Char*>
: IsCompatibleCharType<Char> {};
template <typename Pointer>
struct IsCompatiblePointer
: IsCompatiblePointerHelper<typename std::remove_cv<typename std::remove_reference<Pointer>::type>::type> {};
template <typename T>
struct IsCompatibleStdBasicStringHelper : std::false_type {};
template <typename Char, typename...Args>
@ -108,21 +126,32 @@ private:
template <typename Char>
using if_compatible_char = typename std::enable_if<QtPrivate::IsCompatibleCharType<Char>::value, bool>::type;
template <typename Array>
using if_compatible_array = typename std::enable_if<QtPrivate::IsCompatibleArray<Array>::value, bool>::type;
template <typename Pointer>
using if_compatible_pointer = typename std::enable_if<QtPrivate::IsCompatiblePointer<Pointer>::value, bool>::type;
template <typename T>
using if_compatible_string = typename std::enable_if<QtPrivate::IsCompatibleStdBasicString<T>::value, bool>::type;
template <typename T>
using if_compatible_qstring_like = typename std::enable_if<std::is_same<T, QString>::value || std::is_same<T, QStringRef>::value, bool>::type;
template <typename Char, size_t N>
static Q_DECL_CONSTEXPR size_type lengthHelperArray(const Char (&)[N]) Q_DECL_NOTHROW
{
return size_type(N - 1);
}
template <typename Char>
static Q_DECL_RELAXED_CONSTEXPR size_type lengthHelper(const Char *str) Q_DECL_NOTHROW
static Q_DECL_RELAXED_CONSTEXPR size_type lengthHelperPointer(const Char *str) Q_DECL_NOTHROW
{
size_type result = 0;
while (*str++)
++result;
return result;
}
static Q_DECL_RELAXED_CONSTEXPR size_type lengthHelper(const QChar *str) Q_DECL_NOTHROW
static Q_DECL_RELAXED_CONSTEXPR size_type lengthHelperPointer(const QChar *str) Q_DECL_NOTHROW
{
size_type result = 0;
while (!str++->isNull())
@ -151,9 +180,21 @@ public:
: m_size((Q_ASSERT(len >= 0), Q_ASSERT(str || !len), len)),
m_data(castHelper(str)) {}
template <typename Char, if_compatible_char<Char> = true>
Q_DECL_CONSTEXPR QStringView(const Char *str)
: QStringView(str, str ? lengthHelper(str) : 0) {}
#ifdef Q_QDOC
template <typename Char, size_t N>
Q_DECL_CONSTEXPR QStringView(const Char (&array)[N]) Q_DECL_NOTHROW;
template <typename Char>
Q_DECL_CONSTEXPR QStringView(const Char *str) Q_DECL_NOTHROW;
#else
template <typename Array, if_compatible_array<Array> = true>
Q_DECL_CONSTEXPR QStringView(const Array &str) Q_DECL_NOTHROW
: QStringView(str, lengthHelperArray(str)) {}
template <typename Pointer, if_compatible_pointer<Pointer> = true>
Q_DECL_CONSTEXPR QStringView(const Pointer &str) Q_DECL_NOTHROW
: QStringView(str, str ? lengthHelperPointer(str) : 0) {}
#endif
#ifdef Q_QDOC
QStringView(const QString &str) Q_DECL_NOTHROW;

View File

@ -58,6 +58,8 @@ Q_STATIC_ASSERT(!CanConvert<QByteArray>::value);
Q_STATIC_ASSERT(!CanConvert<QChar>::value);
Q_STATIC_ASSERT(CanConvert<QChar[123]>::value);
Q_STATIC_ASSERT(CanConvert< QString >::value);
Q_STATIC_ASSERT(CanConvert<const QString >::value);
Q_STATIC_ASSERT(CanConvert< QString&>::value);
@ -75,6 +77,8 @@ Q_STATIC_ASSERT(CanConvert<const QStringRef&>::value);
Q_STATIC_ASSERT(!CanConvert<ushort>::value);
Q_STATIC_ASSERT(CanConvert<ushort[123]>::value);
Q_STATIC_ASSERT(CanConvert< ushort*>::value);
Q_STATIC_ASSERT(CanConvert<const ushort*>::value);
@ -232,6 +236,43 @@ void tst_QStringView::constExpr() const
Q_STATIC_ASSERT(sv.back() == QLatin1Char('o'));
Q_STATIC_ASSERT(sv.last() == QLatin1Char('o'));
}
#if !defined(Q_OS_WIN) || defined(Q_COMPILER_UNICODE_STRINGS)
{
Q_STATIC_ASSERT(QStringView(u"Hello").size() == 5);
constexpr QStringView sv = u"Hello";
Q_STATIC_ASSERT(sv.size() == 5);
Q_STATIC_ASSERT(!sv.empty());
Q_STATIC_ASSERT(!sv.isEmpty());
Q_STATIC_ASSERT(!sv.isNull());
Q_STATIC_ASSERT(*sv.utf16() == 'H');
Q_STATIC_ASSERT(sv[0] == QLatin1Char('H'));
Q_STATIC_ASSERT(sv.at(0) == QLatin1Char('H'));
Q_STATIC_ASSERT(sv.front() == QLatin1Char('H'));
Q_STATIC_ASSERT(sv.first() == QLatin1Char('H'));
Q_STATIC_ASSERT(sv[4] == QLatin1Char('o'));
Q_STATIC_ASSERT(sv.at(4) == QLatin1Char('o'));
Q_STATIC_ASSERT(sv.back() == QLatin1Char('o'));
Q_STATIC_ASSERT(sv.last() == QLatin1Char('o'));
}
#else // storage_type is wchar_t
{
Q_STATIC_ASSERT(QStringView(L"Hello").size() == 5);
constexpr QStringView sv = L"Hello";
Q_STATIC_ASSERT(sv.size() == 5);
Q_STATIC_ASSERT(!sv.empty());
Q_STATIC_ASSERT(!sv.isEmpty());
Q_STATIC_ASSERT(!sv.isNull());
Q_STATIC_ASSERT(*sv.utf16() == 'H');
Q_STATIC_ASSERT(sv[0] == QLatin1Char('H'));
Q_STATIC_ASSERT(sv.at(0) == QLatin1Char('H'));
Q_STATIC_ASSERT(sv.front() == QLatin1Char('H'));
Q_STATIC_ASSERT(sv.first() == QLatin1Char('H'));
Q_STATIC_ASSERT(sv[4] == QLatin1Char('o'));
Q_STATIC_ASSERT(sv.at(4) == QLatin1Char('o'));
Q_STATIC_ASSERT(sv.back() == QLatin1Char('o'));
Q_STATIC_ASSERT(sv.last() == QLatin1Char('o'));
}
#endif
#endif
}