Unify all mid() functions in QtBase.
Up to now, Qt had at least 3 different implementations of the mid(). Only QString::mid implementation was not crashing on edge cases and was protected against overflows, therefore I picked that one as the base implementation, even if it has weird semantics for an invalid input. As a side effect QVector::mid was slightly optimized to not detach in all cases (which follows current QList behavior). Documentation of QVector::mid and QList::mid was updated to not mention "copy of data" which could suggest that the mid() result is detached. QStringRef::mid was fixed and now it follows general Qt behavior, by returning a null value for a null input. Change-Id: Ie9ff5d98372bd193d66508e6dd92b6ed1180ad9b Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
8f3a393e41
commit
71fb3633e8
@ -130,4 +130,33 @@ void QArrayData::deallocate(QArrayData *data, size_t objectSize,
|
||||
::free(data);
|
||||
}
|
||||
|
||||
namespace QtPrivate {
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
QContainerImplHelper::CutResult QContainerImplHelper::mid(int originalLength, int *_position, int *_length)
|
||||
{
|
||||
int &position = *_position;
|
||||
int &length = *_length;
|
||||
if (position > originalLength)
|
||||
return Null;
|
||||
|
||||
if (position < 0) {
|
||||
if (length < 0 || length + position >= originalLength)
|
||||
return Full;
|
||||
if (length + position <= 0)
|
||||
return Null;
|
||||
length += position;
|
||||
position = 0;
|
||||
} else if (uint(length) > uint(originalLength - position)) {
|
||||
length = originalLength - position;
|
||||
}
|
||||
|
||||
if (position == 0 && length == originalLength)
|
||||
return Full;
|
||||
|
||||
return length > 0 ? Subset : Empty;
|
||||
}
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -361,6 +361,14 @@ namespace QtPrivate {
|
||||
QT_PREPEND_NAMESPACE(QtPrivate::qMakeArrayLiteral)<Type>( Array )
|
||||
#endif // !defined(Q_ARRAY_LITERAL)
|
||||
|
||||
namespace QtPrivate {
|
||||
struct Q_CORE_EXPORT QContainerImplHelper
|
||||
{
|
||||
enum CutResult { Null, Empty, Full, Subset };
|
||||
static CutResult mid(int originalLength, int *position, int *length);
|
||||
};
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // include guard
|
||||
|
@ -2677,19 +2677,22 @@ QByteArray QByteArray::right(int len) const
|
||||
|
||||
QByteArray QByteArray::mid(int pos, int len) const
|
||||
{
|
||||
if ((d->size == 0 && d->ref.isStatic()) || pos > d->size)
|
||||
using namespace QtPrivate;
|
||||
switch (QContainerImplHelper::mid(size(), &pos, &len)) {
|
||||
case QContainerImplHelper::Null:
|
||||
return QByteArray();
|
||||
if (len < 0)
|
||||
len = d->size - pos;
|
||||
if (pos < 0) {
|
||||
len += pos;
|
||||
pos = 0;
|
||||
case QContainerImplHelper::Empty:
|
||||
{
|
||||
QByteArrayDataPtr empty = { Data::allocate(0) };
|
||||
return QByteArray(empty);
|
||||
}
|
||||
if (len + pos > d->size)
|
||||
len = d->size - pos;
|
||||
if (pos == 0 && len == d->size)
|
||||
case QContainerImplHelper::Full:
|
||||
return *this;
|
||||
return QByteArray(d->data() + pos, len);
|
||||
case QContainerImplHelper::Subset:
|
||||
return QByteArray(d->data() + pos, len);
|
||||
}
|
||||
Q_UNREACHABLE();
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -491,11 +491,11 @@ void **QListData::erase(void **xi)
|
||||
/*!
|
||||
\fn QList<T> QList<T>::mid(int pos, int length) const
|
||||
|
||||
Returns a list whose elements are copied from this list,
|
||||
Returns a sub-list which includes elements from this list,
|
||||
starting at position \a pos. If \a length is -1 (the default), all
|
||||
elements from \a pos are copied; otherwise \a length elements (or
|
||||
elements from \a pos are included; otherwise \a length elements (or
|
||||
all remaining elements if there are less than \a length elements)
|
||||
are copied.
|
||||
are included.
|
||||
*/
|
||||
|
||||
/*! \fn QList::QList()
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include <QtCore/qalgorithms.h>
|
||||
#include <QtCore/qiterator.h>
|
||||
#include <QtCore/qrefcount.h>
|
||||
#include <QtCore/qarraydata.h>
|
||||
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
@ -646,10 +647,17 @@ inline void QList<T>::move(int from, int to)
|
||||
template<typename T>
|
||||
Q_OUTOFLINE_TEMPLATE QList<T> QList<T>::mid(int pos, int alength) const
|
||||
{
|
||||
if (alength < 0 || pos > size() - alength)
|
||||
alength = size() - pos;
|
||||
if (pos == 0 && alength == size())
|
||||
using namespace QtPrivate;
|
||||
switch (QContainerImplHelper::mid(size(), &pos, &alength)) {
|
||||
case QContainerImplHelper::Null:
|
||||
case QContainerImplHelper::Empty:
|
||||
return QList<T>();
|
||||
case QContainerImplHelper::Full:
|
||||
return *this;
|
||||
case QContainerImplHelper::Subset:
|
||||
break;
|
||||
}
|
||||
|
||||
QList<T> cpy;
|
||||
if (alength <= 0)
|
||||
return cpy;
|
||||
|
@ -4090,21 +4090,22 @@ QString QString::right(int n) const
|
||||
|
||||
QString QString::mid(int position, int n) const
|
||||
{
|
||||
if (position > d->size)
|
||||
using namespace QtPrivate;
|
||||
switch (QContainerImplHelper::mid(d->size, &position, &n)) {
|
||||
case QContainerImplHelper::Null:
|
||||
return QString();
|
||||
if (position < 0) {
|
||||
if (n < 0 || n + position >= d->size)
|
||||
return *this;
|
||||
if (n + position <= 0)
|
||||
return QString();
|
||||
|
||||
n += position;
|
||||
position = 0;
|
||||
} else if (uint(n) > uint(d->size - position))
|
||||
n = d->size - position;
|
||||
if (position == 0 && n == d->size)
|
||||
case QContainerImplHelper::Empty:
|
||||
{
|
||||
QStringDataPtr empty = { Data::allocate(0) };
|
||||
return QString(empty);
|
||||
}
|
||||
case QContainerImplHelper::Full:
|
||||
return *this;
|
||||
return QString((const QChar*) d->data() + position, n);
|
||||
case QContainerImplHelper::Subset:
|
||||
return QString((const QChar*)d->data() + position, n);
|
||||
}
|
||||
Q_UNREACHABLE();
|
||||
return QString();
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -8794,19 +8795,19 @@ QStringRef QString::rightRef(int n) const
|
||||
*/
|
||||
QStringRef QStringRef::mid(int pos, int n) const
|
||||
{
|
||||
if (pos > m_size)
|
||||
using namespace QtPrivate;
|
||||
switch (QContainerImplHelper::mid(m_size, &pos, &n)) {
|
||||
case QContainerImplHelper::Null:
|
||||
return QStringRef();
|
||||
if (pos < 0) {
|
||||
if (n < 0 || n + pos >= m_size)
|
||||
return QStringRef(m_string, m_position, m_size);
|
||||
if (n + pos <= 0)
|
||||
return QStringRef();
|
||||
n += pos;
|
||||
pos = 0;
|
||||
} else if (uint(n) > uint(m_size - pos)) {
|
||||
n = m_size - pos;
|
||||
case QContainerImplHelper::Empty:
|
||||
return QStringRef(m_string, 0, 0);
|
||||
case QContainerImplHelper::Full:
|
||||
return *this;
|
||||
case QContainerImplHelper::Subset:
|
||||
return QStringRef(m_string, pos + m_position, n);
|
||||
}
|
||||
return QStringRef(m_string, pos + m_position, n);
|
||||
Q_UNREACHABLE();
|
||||
return QStringRef();
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -8831,19 +8832,19 @@ QStringRef QStringRef::mid(int pos, int n) const
|
||||
*/
|
||||
QStringRef QString::midRef(int position, int n) const
|
||||
{
|
||||
if (position > d->size)
|
||||
using namespace QtPrivate;
|
||||
switch (QContainerImplHelper::mid(d->size, &position, &n)) {
|
||||
case QContainerImplHelper::Null:
|
||||
return QStringRef();
|
||||
if (position < 0) {
|
||||
if (n < 0 || n + position >= d->size)
|
||||
return QStringRef(this, 0, d->size);
|
||||
if (n + position <= 0)
|
||||
return QStringRef();
|
||||
|
||||
n += position;
|
||||
position = 0;
|
||||
} else if (uint(n) > uint(d->size - position))
|
||||
n = d->size - position;
|
||||
return QStringRef(this, position, n);
|
||||
case QContainerImplHelper::Empty:
|
||||
return QStringRef(this, 0, 0);
|
||||
case QContainerImplHelper::Full:
|
||||
return QStringRef(this, 0, d->size);
|
||||
case QContainerImplHelper::Subset:
|
||||
return QStringRef(this, position, n);
|
||||
}
|
||||
Q_UNREACHABLE();
|
||||
return QStringRef();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -180,11 +180,11 @@
|
||||
/*!
|
||||
\fn QVector<T> QVector::mid(int pos, int length = -1) const
|
||||
|
||||
Returns a vector whose elements are copied from this vector,
|
||||
Returns a sub-vector which contains elements from this vector,
|
||||
starting at position \a pos. If \a length is -1 (the default), all
|
||||
elements after \a pos are copied; otherwise \a length elements (or
|
||||
elements after \a pos are included; otherwise \a length elements (or
|
||||
all remaining elements if there are less than \a length elements)
|
||||
are copied.
|
||||
are included.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -822,12 +822,17 @@ int QVector<T>::count(const T &t) const
|
||||
template <typename T>
|
||||
Q_OUTOFLINE_TEMPLATE QVector<T> QVector<T>::mid(int pos, int len) const
|
||||
{
|
||||
if (len < 0)
|
||||
len = size() - pos;
|
||||
if (pos == 0 && len == size())
|
||||
using namespace QtPrivate;
|
||||
switch (QContainerImplHelper::mid(d->size, &pos, &len)) {
|
||||
case QContainerImplHelper::Null:
|
||||
case QContainerImplHelper::Empty:
|
||||
return QVector<T>();
|
||||
case QContainerImplHelper::Full:
|
||||
return *this;
|
||||
if (pos + len > size())
|
||||
len = size() - pos;
|
||||
case QContainerImplHelper::Subset:
|
||||
break;
|
||||
}
|
||||
|
||||
QVector<T> copy;
|
||||
copy.reserve(len);
|
||||
for (int i = pos; i < pos + len; ++i)
|
||||
|
Loading…
Reference in New Issue
Block a user