diff options
Diffstat (limited to 'src/corelib/tools/qringbuffer.cpp')
-rw-r--r-- | src/corelib/tools/qringbuffer.cpp | 194 |
1 files changed, 101 insertions, 93 deletions
diff --git a/src/corelib/tools/qringbuffer.cpp b/src/corelib/tools/qringbuffer.cpp index 4dd58b4291..c9ef3bc69a 100644 --- a/src/corelib/tools/qringbuffer.cpp +++ b/src/corelib/tools/qringbuffer.cpp @@ -44,6 +44,46 @@ QT_BEGIN_NAMESPACE +void QRingChunk::allocate(int alloc) +{ + Q_ASSERT(alloc > 0 && size() == 0); + + if (chunk.size() < alloc || isShared()) + chunk = QByteArray(alloc, Qt::Uninitialized); +} + +void QRingChunk::detach() +{ + Q_ASSERT(isShared()); + + const int chunkSize = size(); + QByteArray x(chunkSize, Qt::Uninitialized); + ::memcpy(x.data(), chunk.constData() + headOffset, chunkSize); + chunk = qMove(x); + headOffset = 0; + tailOffset = chunkSize; +} + +QByteArray QRingChunk::toByteArray() +{ + if (headOffset != 0 || tailOffset != chunk.size()) { + if (isShared()) + return chunk.mid(headOffset, size()); + + if (headOffset != 0) { + char *ptr = chunk.data(); + ::memmove(ptr, ptr + headOffset, size()); + tailOffset -= headOffset; + headOffset = 0; + } + + chunk.reserve(0); // avoid that resizing needlessly reallocates + chunk.resize(tailOffset); + } + + return chunk; +} + /*! \internal @@ -54,12 +94,11 @@ QT_BEGIN_NAMESPACE const char *QRingBuffer::readPointerAtPosition(qint64 pos, qint64 &length) const { if (pos >= 0) { - pos += head; - for (int i = 0; i < buffers.size(); ++i) { - length = (i == tailBuffer ? tail : buffers[i].size()); + for (const QRingChunk &chunk : buffers) { + length = chunk.size(); if (length > pos) { length -= pos; - return buffers[i].constData() + pos; + return chunk.data() + pos; } pos -= length; } @@ -74,32 +113,31 @@ void QRingBuffer::free(qint64 bytes) Q_ASSERT(bytes <= bufferSize); while (bytes > 0) { - const qint64 blockSize = buffers.constFirst().size() - head; + const qint64 chunkSize = buffers.constFirst().size(); - if (tailBuffer == 0 || blockSize > bytes) { + if (buffers.size() == 1 || chunkSize > bytes) { + QRingChunk &chunk = buffers.first(); // keep a single block around if it does not exceed // the basic block size, to avoid repeated allocations // between uses of the buffer if (bufferSize <= bytes) { - if (buffers.constFirst().size() <= basicBlockSize) { + if (chunk.capacity() <= basicBlockSize && !chunk.isShared()) { + chunk.reset(); bufferSize = 0; - head = tail = 0; } else { clear(); // try to minify/squeeze us } } else { Q_ASSERT(bytes < MaxByteArraySize); - head += int(bytes); + chunk.advance(bytes); bufferSize -= bytes; } return; } - bufferSize -= blockSize; - bytes -= blockSize; + bufferSize -= chunkSize; + bytes -= chunkSize; buffers.removeFirst(); - --tailBuffer; - head = 0; } } @@ -108,32 +146,25 @@ char *QRingBuffer::reserve(qint64 bytes) if (bytes <= 0 || bytes >= MaxByteArraySize) return 0; + const int chunkSize = qMax(basicBlockSize, int(bytes)); + int tail = 0; if (bufferSize == 0) { if (buffers.isEmpty()) - buffers.append(QByteArray(qMax(basicBlockSize, int(bytes)), Qt::Uninitialized)); + buffers.append(QRingChunk(chunkSize)); else - buffers.first().resize(qMax(basicBlockSize, int(bytes))); + buffers.first().allocate(chunkSize); } else { - const qint64 newSize = bytes + tail; + const QRingChunk &chunk = buffers.constLast(); // if need a new buffer - if (basicBlockSize == 0 || (newSize > buffers.constLast().capacity() - && (tail >= basicBlockSize || newSize >= MaxByteArraySize))) { - // shrink this buffer to its current size - buffers.last().resize(tail); - - // create a new QByteArray - buffers.append(QByteArray(qMax(basicBlockSize, int(bytes)), Qt::Uninitialized)); - ++tailBuffer; - tail = 0; - } else if (newSize > buffers.constLast().size()) { - buffers.last().resize(qMax(basicBlockSize, int(newSize))); - } + if (basicBlockSize == 0 || chunk.isShared() || bytes > chunk.available()) + buffers.append(QRingChunk(chunkSize)); + else + tail = chunk.size(); } - char *writePtr = buffers.last().data() + tail; + buffers.last().grow(bytes); bufferSize += bytes; - tail += int(bytes); - return writePtr; + return buffers.last().data() + tail; } /*! @@ -146,29 +177,28 @@ char *QRingBuffer::reserveFront(qint64 bytes) if (bytes <= 0 || bytes >= MaxByteArraySize) return 0; - if (head < bytes || basicBlockSize == 0) { - if (head > 0) { - buffers.first().remove(0, head); - if (tailBuffer == 0) - tail -= head; - } - - head = qMax(basicBlockSize, int(bytes)); - if (bufferSize == 0) { - if (buffers.isEmpty()) - buffers.prepend(QByteArray(head, Qt::Uninitialized)); - else - buffers.first().resize(head); - tail = head; + const int chunkSize = qMax(basicBlockSize, int(bytes)); + if (bufferSize == 0) { + if (buffers.isEmpty()) + buffers.prepend(QRingChunk(chunkSize)); + else + buffers.first().allocate(chunkSize); + buffers.first().grow(chunkSize); + buffers.first().advance(chunkSize - bytes); + } else { + const QRingChunk &chunk = buffers.constFirst(); + // if need a new buffer + if (basicBlockSize == 0 || chunk.isShared() || bytes > chunk.head()) { + buffers.prepend(QRingChunk(chunkSize)); + buffers.first().grow(chunkSize); + buffers.first().advance(chunkSize - bytes); } else { - buffers.prepend(QByteArray(head, Qt::Uninitialized)); - ++tailBuffer; + buffers.first().advance(-bytes); } } - head -= int(bytes); bufferSize += bytes; - return buffers.first().data() + head; + return buffers.first().data(); } void QRingBuffer::chop(qint64 bytes) @@ -176,30 +206,31 @@ void QRingBuffer::chop(qint64 bytes) Q_ASSERT(bytes <= bufferSize); while (bytes > 0) { - if (tailBuffer == 0 || tail > bytes) { + const qint64 chunkSize = buffers.constLast().size(); + + if (buffers.size() == 1 || chunkSize > bytes) { + QRingChunk &chunk = buffers.last(); // keep a single block around if it does not exceed // the basic block size, to avoid repeated allocations // between uses of the buffer if (bufferSize == bytes) { - if (buffers.constFirst().size() <= basicBlockSize) { + if (chunk.capacity() <= basicBlockSize && !chunk.isShared()) { + chunk.reset(); bufferSize = 0; - head = tail = 0; } else { clear(); // try to minify/squeeze us } } else { Q_ASSERT(bytes < MaxByteArraySize); - tail -= int(bytes); + chunk.grow(-bytes); bufferSize -= bytes; } return; } - bufferSize -= tail; - bytes -= tail; + bufferSize -= chunkSize; + bytes -= chunkSize; buffers.removeLast(); - --tailBuffer; - tail = buffers.constLast().size(); } } @@ -210,9 +241,6 @@ void QRingBuffer::clear() buffers.erase(buffers.begin() + 1, buffers.end()); buffers.first().clear(); - - head = tail = 0; - tailBuffer = 0; bufferSize = 0; } @@ -221,13 +249,12 @@ qint64 QRingBuffer::indexOf(char c, qint64 maxLength, qint64 pos) const if (maxLength <= 0 || pos < 0) return -1; - qint64 index = -(pos + head); - for (int i = 0; i < buffers.size(); ++i) { - const qint64 nextBlockIndex = qMin(index + (i == tailBuffer ? tail : buffers[i].size()), - maxLength); + qint64 index = -pos; + for (const QRingChunk &chunk : buffers) { + const qint64 nextBlockIndex = qMin(index + chunk.size(), maxLength); if (nextBlockIndex > 0) { - const char *ptr = buffers[i].constData(); + const char *ptr = chunk.data(); if (index < 0) { ptr -= index; index = 0; @@ -271,19 +298,8 @@ QByteArray QRingBuffer::read() if (bufferSize == 0) return QByteArray(); - QByteArray qba(buffers.takeFirst()); - - qba.reserve(0); // avoid that resizing needlessly reallocates - if (tailBuffer == 0) { - qba.resize(tail); - tail = 0; - } else { - --tailBuffer; - } - qba.remove(0, head); // does nothing if head is 0 - head = 0; - bufferSize -= qba.size(); - return qba; + bufferSize -= buffers.constFirst().size(); + return buffers.takeFirst().toByteArray(); } /*! @@ -296,13 +312,12 @@ qint64 QRingBuffer::peek(char *data, qint64 maxLength, qint64 pos) const qint64 readSoFar = 0; if (pos >= 0) { - pos += head; for (int i = 0; readSoFar < maxLength && i < buffers.size(); ++i) { - qint64 blockLength = (i == tailBuffer ? tail : buffers[i].size()); + qint64 blockLength = buffers[i].size(); if (pos < blockLength) { blockLength = qMin(blockLength - pos, maxLength - readSoFar); - memcpy(data + readSoFar, buffers[i].constData() + pos, blockLength); + memcpy(data + readSoFar, buffers[i].data() + pos, blockLength); readSoFar += blockLength; pos = 0; } else { @@ -335,18 +350,11 @@ void QRingBuffer::append(const char *data, qint64 size) */ void QRingBuffer::append(const QByteArray &qba) { - if (tail == 0) { - if (buffers.isEmpty()) - buffers.append(qba); - else - buffers.last() = qba; - } else { - buffers.last().resize(tail); - buffers.append(qba); - ++tailBuffer; - } - tail = qba.size(); - bufferSize += tail; + if (bufferSize != 0 || buffers.isEmpty()) + buffers.append(QRingChunk(qba)); + else + buffers.last().assign(qba); + bufferSize += qba.size(); } qint64 QRingBuffer::readLine(char *data, qint64 maxLength) |