Make QRingBuffer a move-only type

There's no sense in copying a ring buffer. Moving is enough. This
marks an important step on the way to preventing accidental copies of
ring buffer content, because the 'QList buffers' member can now no
longer be implicitly shared. While the compiler will still emit the
code for detach()ing, it will now never be executed.

Pick-to: 6.3
Change-Id: I968bfe3e50c46720ed4baca55c99c1f9c518f653
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Marc Mutz 2021-12-12 17:04:26 +01:00
parent 758a830f7e
commit 81bf3e68b9
3 changed files with 26 additions and 7 deletions

View File

@ -703,15 +703,18 @@ void QIODevice::setCurrentReadChannel(int channel)
void QIODevicePrivate::setReadChannelCount(int count)
{
if (count > readBuffers.size()) {
readBuffers.reserve(count);
// If readBufferChunkSize is zero, we should bypass QIODevice's
// read buffers, even if the QIODeviceBase::Unbuffered flag is not
// set when opened. However, if a read transaction is started or
// ungetChar() is called, we still have to use the internal buffer.
// To support these cases, pass a default value to the QRingBuffer
// constructor.
readBuffers.insert(readBuffers.end(), count - readBuffers.size(),
QRingBuffer(readBufferChunkSize != 0 ? readBufferChunkSize
: QIODEVICE_BUFFERSIZE));
while (readBuffers.size() < count)
readBuffers.emplace_back(readBufferChunkSize != 0 ? readBufferChunkSize
: QIODEVICE_BUFFERSIZE);
} else {
readBuffers.resize(count);
}
@ -762,8 +765,9 @@ void QIODevicePrivate::setWriteChannelCount(int count)
// If writeBufferChunkSize is zero (default value), we don't use
// QIODevice's write buffers.
if (writeBufferChunkSize != 0) {
writeBuffers.insert(writeBuffers.end(), count - writeBuffers.size(),
QRingBuffer(writeBufferChunkSize));
writeBuffers.reserve(count);
while (writeBuffers.size() < count)
writeBuffers.emplace_back(writeBufferChunkSize);
}
} else {
writeBuffers.resize(count);

View File

@ -189,10 +189,14 @@ Q_DECLARE_SHARED(QRingChunk)
class QRingBuffer
{
Q_DISABLE_COPY(QRingBuffer)
public:
explicit inline QRingBuffer(int growth = QRINGBUFFER_CHUNKSIZE) :
bufferSize(0), basicBlockSize(growth) { }
QRingBuffer(QRingBuffer &&) noexcept = default;
QRingBuffer &operator=(QRingBuffer &&) noexcept = default;
inline void setChunkSize(int size) {
basicBlockSize = size;
}

View File

@ -38,6 +38,7 @@ class tst_QRingBuffer : public QObject
private slots:
void constructing();
void usingInVector();
void usingInVarLengthArray();
void readPointerAtPositionWriteRead();
void readPointerAtPositionEmptyRead();
void readPointerAtPositionWithHead();
@ -83,10 +84,20 @@ void tst_QRingBuffer::constructing()
void tst_QRingBuffer::usingInVector()
{
QRingBuffer ringBuffer;
QList<QRingBuffer> buffers;
std::vector<QRingBuffer> buffers;
ringBuffer.reserve(5);
buffers.append(ringBuffer);
buffers.push_back(std::move(ringBuffer));
QCOMPARE(buffers[0].size(), Q_INT64_C(5));
}
void tst_QRingBuffer::usingInVarLengthArray()
{
QRingBuffer ringBuffer;
QVarLengthArray<QRingBuffer, 42> buffers;
ringBuffer.reserve(5);
buffers.push_back(std::move(ringBuffer));
QCOMPARE(buffers[0].size(), Q_INT64_C(5));
}