mirror of https://github.com/qt/qtbase.git
QRingBuffer: avoid allocation in c'tor
Reduces creation time and memory consumption when the buffer is unused. Robin's benchmark: QBENCHMARK { QFile file(filename); } reports the following results (run with -median 10 -iterations 524288): before: 0.00028 msecs per iteration (total: 149, iterations: 524288) after: 0.00017 msecs per iteration (total: 93, iterations: 524288). Change-Id: Ied4e7caeca794b94260b8fc59b3ba656f4719c30 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
This commit is contained in:
parent
61ad604ad4
commit
c3d8ab78b8
|
@ -65,6 +65,8 @@ const char *QRingBuffer::readPointerAtPosition(qint64 pos, qint64 &length) const
|
|||
|
||||
void QRingBuffer::free(qint64 bytes)
|
||||
{
|
||||
Q_ASSERT(bytes <= bufferSize);
|
||||
|
||||
while (bytes > 0) {
|
||||
const qint64 blockSize = buffers.first().size() - head;
|
||||
|
||||
|
@ -100,20 +102,25 @@ char *QRingBuffer::reserve(qint64 bytes)
|
|||
if (bytes <= 0 || bytes >= MaxByteArraySize)
|
||||
return 0;
|
||||
|
||||
const qint64 newSize = bytes + tail;
|
||||
// if need buffer reallocation
|
||||
if (newSize > buffers.last().size()) {
|
||||
if (newSize > buffers.last().capacity() && (tail >= basicBlockSize
|
||||
|| newSize >= MaxByteArraySize)) {
|
||||
// shrink this buffer to its current size
|
||||
buffers.last().resize(tail);
|
||||
if (buffers.isEmpty()) {
|
||||
buffers.append(QByteArray());
|
||||
buffers.first().resize(qMax(basicBlockSize, int(bytes)));
|
||||
} else {
|
||||
const qint64 newSize = bytes + tail;
|
||||
// if need buffer reallocation
|
||||
if (newSize > buffers.last().size()) {
|
||||
if (newSize > buffers.last().capacity() && (tail >= basicBlockSize
|
||||
|| newSize >= MaxByteArraySize)) {
|
||||
// shrink this buffer to its current size
|
||||
buffers.last().resize(tail);
|
||||
|
||||
// create a new QByteArray
|
||||
buffers.append(QByteArray());
|
||||
++tailBuffer;
|
||||
tail = 0;
|
||||
// create a new QByteArray
|
||||
buffers.append(QByteArray());
|
||||
++tailBuffer;
|
||||
tail = 0;
|
||||
}
|
||||
buffers.last().resize(qMax(basicBlockSize, tail + int(bytes)));
|
||||
}
|
||||
buffers.last().resize(qMax(basicBlockSize, tail + int(bytes)));
|
||||
}
|
||||
|
||||
char *writePtr = buffers.last().data() + tail;
|
||||
|
@ -134,9 +141,13 @@ char *QRingBuffer::reserveFront(qint64 bytes)
|
|||
return 0;
|
||||
|
||||
if (head < bytes) {
|
||||
buffers.first().remove(0, head);
|
||||
if (tailBuffer == 0)
|
||||
tail -= head;
|
||||
if (buffers.isEmpty()) {
|
||||
buffers.append(QByteArray());
|
||||
} else {
|
||||
buffers.first().remove(0, head);
|
||||
if (tailBuffer == 0)
|
||||
tail -= head;
|
||||
}
|
||||
|
||||
head = qMax(basicBlockSize, int(bytes));
|
||||
if (bufferSize == 0) {
|
||||
|
@ -155,6 +166,8 @@ char *QRingBuffer::reserveFront(qint64 bytes)
|
|||
|
||||
void QRingBuffer::chop(qint64 bytes)
|
||||
{
|
||||
Q_ASSERT(bytes <= bufferSize);
|
||||
|
||||
while (bytes > 0) {
|
||||
if (tailBuffer == 0 || tail > bytes) {
|
||||
// keep a single block around if it does not exceed
|
||||
|
@ -185,6 +198,9 @@ void QRingBuffer::chop(qint64 bytes)
|
|||
|
||||
void QRingBuffer::clear()
|
||||
{
|
||||
if (buffers.isEmpty())
|
||||
return;
|
||||
|
||||
buffers.erase(buffers.begin() + 1, buffers.end());
|
||||
buffers.first().clear();
|
||||
|
||||
|
@ -301,7 +317,10 @@ qint64 QRingBuffer::peek(char *data, qint64 maxLength, qint64 pos) const
|
|||
void QRingBuffer::append(const QByteArray &qba)
|
||||
{
|
||||
if (tail == 0) {
|
||||
buffers.last() = qba;
|
||||
if (buffers.isEmpty())
|
||||
buffers.append(qba);
|
||||
else
|
||||
buffers.last() = qba;
|
||||
} else {
|
||||
buffers.last().resize(tail);
|
||||
buffers.append(qba);
|
||||
|
|
|
@ -54,9 +54,7 @@ class QRingBuffer
|
|||
{
|
||||
public:
|
||||
explicit inline QRingBuffer(int growth = 4096) :
|
||||
head(0), tail(0), tailBuffer(0), basicBlockSize(growth), bufferSize(0) {
|
||||
buffers.append(QByteArray());
|
||||
}
|
||||
head(0), tail(0), tailBuffer(0), basicBlockSize(growth), bufferSize(0) { }
|
||||
|
||||
inline qint64 nextDataBlockSize() const {
|
||||
return (tailBuffer == 0 ? tail : buffers.first().size()) - head;
|
||||
|
|
|
@ -39,11 +39,11 @@ class tst_QRingBuffer : public QObject
|
|||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void constructing();
|
||||
void readPointerAtPositionWriteRead();
|
||||
void readPointerAtPositionEmptyRead();
|
||||
void readPointerAtPositionWithHead();
|
||||
void readPointerAtPositionReadTooMuch();
|
||||
void sizeWhenEmpty();
|
||||
void sizeWhenReservedAndChopped();
|
||||
void sizeWhenReserved();
|
||||
void free();
|
||||
|
@ -57,6 +57,23 @@ private slots:
|
|||
void readLine();
|
||||
};
|
||||
|
||||
void tst_QRingBuffer::constructing()
|
||||
{
|
||||
QRingBuffer ringBuffer;
|
||||
|
||||
QCOMPARE(ringBuffer.size(), Q_INT64_C(0));
|
||||
QVERIFY(ringBuffer.isEmpty());
|
||||
QCOMPARE(ringBuffer.nextDataBlockSize(), Q_INT64_C(0));
|
||||
QVERIFY(ringBuffer.readPointer() == Q_NULLPTR);
|
||||
QCOMPARE(ringBuffer.skip(5), Q_INT64_C(0));
|
||||
QCOMPARE(ringBuffer.read(), QByteArray());
|
||||
QCOMPARE(ringBuffer.getChar(), -1);
|
||||
QVERIFY(!ringBuffer.canReadLine());
|
||||
|
||||
char buf[5];
|
||||
QCOMPARE(ringBuffer.peek(buf, sizeof(buf)), Q_INT64_C(0));
|
||||
}
|
||||
|
||||
void tst_QRingBuffer::sizeWhenReserved()
|
||||
{
|
||||
QRingBuffer ringBuffer;
|
||||
|
@ -74,13 +91,6 @@ void tst_QRingBuffer::sizeWhenReservedAndChopped()
|
|||
QCOMPARE(ringBuffer.size(), Q_INT64_C(0));
|
||||
}
|
||||
|
||||
void tst_QRingBuffer::sizeWhenEmpty()
|
||||
{
|
||||
QRingBuffer ringBuffer;
|
||||
|
||||
QCOMPARE(ringBuffer.size(), Q_INT64_C(0));
|
||||
}
|
||||
|
||||
void tst_QRingBuffer::readPointerAtPositionReadTooMuch()
|
||||
{
|
||||
QRingBuffer ringBuffer;
|
||||
|
|
Loading…
Reference in New Issue