Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qringbuffer.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// Copyright (C) 2015 Alex Trotsenko <alex1973tr@gmail.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "private/qringbuffer_p.h"
6
7#include <type_traits>
8
9#include <string.h>
10
12
13static_assert(std::is_nothrow_default_constructible_v<QRingChunk>);
14static_assert(std::is_nothrow_move_constructible_v<QRingChunk>);
15static_assert(std::is_nothrow_move_assignable_v<QRingChunk>);
16
18{
19 Q_ASSERT(alloc > 0 && size() == 0);
20
21 if (chunk.size() < alloc || isShared())
22 chunk = QByteArray(alloc, Qt::Uninitialized);
23}
24
26{
28
29 const qsizetype chunkSize = size();
30 chunk = QByteArray(std::as_const(*this).data(), chunkSize);
31 headOffset = 0;
32 tailOffset = chunkSize;
33}
34
36{
37 // ### Replace with std::move(chunk).sliced(head(), size()) once sliced()&& is available
38 if (headOffset != 0 || tailOffset != chunk.size()) {
39 if (isShared())
40 return chunk.sliced(head(), size());
41
42 chunk.resize(tailOffset);
43 chunk.remove(0, headOffset);
44 }
45
46 return std::move(chunk);
47}
48
57{
58 Q_ASSERT(pos >= 0);
59
60 for (const QRingChunk &chunk : buffers) {
61 length = chunk.size();
62 if (length > pos) {
63 length -= pos;
64 return chunk.data() + pos;
65 }
66 pos -= length;
67 }
68
69 length = 0;
70 return nullptr;
71}
72
74{
75 Q_ASSERT(bytes <= bufferSize);
76
77 while (bytes > 0) {
78 const qint64 chunkSize = buffers.constFirst().size();
79
80 if (buffers.size() == 1 || chunkSize > bytes) {
81 QRingChunk &chunk = buffers.first();
82 // keep a single block around if it does not exceed
83 // the basic block size, to avoid repeated allocations
84 // between uses of the buffer
85 if (bufferSize == bytes) {
86 if (chunk.capacity() <= basicBlockSize && !chunk.isShared()) {
87 chunk.reset();
88 bufferSize = 0;
89 } else {
90 clear(); // try to minify/squeeze us
91 }
92 } else {
94 chunk.advance(bytes);
95 bufferSize -= bytes;
96 }
97 return;
98 }
99
100 bufferSize -= chunkSize;
101 bytes -= chunkSize;
102 buffers.removeFirst();
103 }
104}
105
107{
108 Q_ASSERT(bytes > 0 && bytes < QByteArray::max_size());
109
110 const qsizetype chunkSize = qMax(qint64(basicBlockSize), bytes);
111 qsizetype tail = 0;
112 if (bufferSize == 0) {
113 if (buffers.isEmpty())
115 else
116 buffers.first().allocate(chunkSize);
117 } else {
118 const QRingChunk &chunk = buffers.constLast();
119 // if need a new buffer
120 if (basicBlockSize == 0 || chunk.isShared() || bytes > chunk.available())
122 else
123 tail = chunk.size();
124 }
125
126 buffers.last().grow(bytes);
127 bufferSize += bytes;
128 return buffers.last().data() + tail;
129}
130
137{
138 Q_ASSERT(bytes > 0 && bytes < QByteArray::max_size());
139
140 const qsizetype chunkSize = qMax(qint64(basicBlockSize), bytes);
141 if (bufferSize == 0) {
142 if (buffers.isEmpty())
143 buffers.prepend(QRingChunk(chunkSize));
144 else
145 buffers.first().allocate(chunkSize);
146 buffers.first().grow(chunkSize);
147 buffers.first().advance(chunkSize - bytes);
148 } else {
149 const QRingChunk &chunk = buffers.constFirst();
150 // if need a new buffer
151 if (basicBlockSize == 0 || chunk.isShared() || bytes > chunk.head()) {
152 buffers.prepend(QRingChunk(chunkSize));
153 buffers.first().grow(chunkSize);
154 buffers.first().advance(chunkSize - bytes);
155 } else {
156 buffers.first().advance(-bytes);
157 }
158 }
159
160 bufferSize += bytes;
161 return buffers.first().data();
162}
163
165{
166 Q_ASSERT(bytes <= bufferSize);
167
168 while (bytes > 0) {
169 const qsizetype chunkSize = buffers.constLast().size();
170
171 if (buffers.size() == 1 || chunkSize > bytes) {
172 QRingChunk &chunk = buffers.last();
173 // keep a single block around if it does not exceed
174 // the basic block size, to avoid repeated allocations
175 // between uses of the buffer
176 if (bufferSize == bytes) {
177 if (chunk.capacity() <= basicBlockSize && !chunk.isShared()) {
178 chunk.reset();
179 bufferSize = 0;
180 } else {
181 clear(); // try to minify/squeeze us
182 }
183 } else {
185 chunk.grow(-bytes);
186 bufferSize -= bytes;
187 }
188 return;
189 }
190
191 bufferSize -= chunkSize;
192 bytes -= chunkSize;
193 buffers.removeLast();
194 }
195}
196
198{
199 if (buffers.isEmpty())
200 return;
201
202 buffers.erase(buffers.begin() + 1, buffers.end());
203 buffers.first().clear();
204 bufferSize = 0;
205}
206
208{
209 Q_ASSERT(maxLength >= 0 && pos >= 0);
210
211 if (maxLength == 0)
212 return -1;
213
214 qint64 index = -pos;
215 for (const QRingChunk &chunk : buffers) {
216 const qint64 nextBlockIndex = qMin(index + chunk.size(), maxLength);
217
218 if (nextBlockIndex > 0) {
219 const char *ptr = chunk.data();
220 if (index < 0) {
221 ptr -= index;
222 index = 0;
223 }
224
225 const char *findPtr = reinterpret_cast<const char *>(memchr(ptr, c,
226 nextBlockIndex - index));
227 if (findPtr)
228 return qint64(findPtr - ptr) + index + pos;
229
230 if (nextBlockIndex == maxLength)
231 return -1;
232 }
233 index = nextBlockIndex;
234 }
235 return -1;
236}
237
239{
240 const qint64 bytesToRead = qMin(size(), maxLength);
241 qint64 readSoFar = 0;
242 while (readSoFar < bytesToRead) {
243 const qint64 bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar,
245 if (data)
246 memcpy(data + readSoFar, readPointer(), bytesToReadFromThisBlock);
247 readSoFar += bytesToReadFromThisBlock;
248 free(bytesToReadFromThisBlock);
249 }
250 return readSoFar;
251}
252
259{
260 if (bufferSize == 0)
261 return QByteArray();
262
263 bufferSize -= buffers.constFirst().size();
264 return buffers.takeFirst().toByteArray();
265}
266
273{
274 Q_ASSERT(maxLength >= 0 && pos >= 0);
275
276 qint64 readSoFar = 0;
277 for (const QRingChunk &chunk : buffers) {
278 if (readSoFar == maxLength)
279 break;
280
281 qint64 blockLength = chunk.size();
282 if (pos < blockLength) {
283 blockLength = qMin(blockLength - pos, maxLength - readSoFar);
284 memcpy(data + readSoFar, chunk.data() + pos, blockLength);
285 readSoFar += blockLength;
286 pos = 0;
287 } else {
288 pos -= blockLength;
289 }
290 }
291
292 return readSoFar;
293}
294
301{
302 Q_ASSERT(size >= 0);
303
304 if (size == 0)
305 return;
306
307 char *writePointer = reserve(size);
308 if (size == 1)
309 *writePointer = *data;
310 else
311 ::memcpy(writePointer, data, size);
312}
313
320{
321 if (bufferSize != 0 || buffers.isEmpty())
322 buffers.append(QRingChunk(qba));
323 else
324 buffers.last().assign(qba);
325 bufferSize += qba.size();
326}
327
334{
335 const auto qbaSize = qba.size();
336 if (bufferSize != 0 || buffers.isEmpty())
337 buffers.emplace_back(std::move(qba));
338 else
339 buffers.last().assign(std::move(qba));
340 bufferSize += qbaSize;
341}
342
344{
345 Q_ASSERT(data != nullptr && maxLength > 1);
346
347 --maxLength;
348 qint64 i = indexOf('\n', maxLength);
349 i = read(data, i >= 0 ? (i + 1) : maxLength);
350
351 // Terminate it.
352 data[i] = '\0';
353 return i;
354}
355
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
static constexpr qsizetype max_size() noexcept
Definition qbytearray.h:485
QByteArray sliced(qsizetype pos) const &
Definition qbytearray.h:200
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
Q_CORE_EXPORT void free(qint64 bytes)
Q_CORE_EXPORT QByteArray read()
qint64 size() const
Q_CORE_EXPORT qint64 peek(char *data, qint64 maxLength, qint64 pos=0) const
Q_CORE_EXPORT qint64 readLine(char *data, qint64 maxLength)
const char * readPointer() const
Q_CORE_EXPORT const char * readPointerAtPosition(qint64 pos, qint64 &length) const
Q_CORE_EXPORT void chop(qint64 bytes)
Q_CORE_EXPORT char * reserve(qint64 bytes)
Q_CORE_EXPORT void append(const char *data, qint64 size)
Q_CORE_EXPORT char * reserveFront(qint64 bytes)
qint64 indexOf(char c) const
Q_CORE_EXPORT void clear()
qint64 nextDataBlockSize() const
int chunkSize() const
void advance(qsizetype offset)
void allocate(qsizetype alloc)
void grow(qsizetype offset)
bool isShared() const
qsizetype available() const
qsizetype size() const
qsizetype capacity() const
Q_CORE_EXPORT void detach()
QByteArray toByteArray() &&
qsizetype head() const
Combined button and popup list for selecting options.
constexpr Initialization Uninitialized
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
static ControlElement< T > * ptr(QWidget *widget)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLuint const GLuint * buffers
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
const GLubyte * c
GLsizei maxLength
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
ptrdiff_t qsizetype
Definition qtypes.h:165
long long qint64
Definition qtypes.h:60
manager head(request, this, [this](QRestReply &reply) { if(reply.isSuccess()) })
[6]