QtBase  v6.3.1
qringbuffer.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2021 The Qt Company Ltd.
4 ** Copyright (C) 2015 Alex Trotsenko <alex1973tr@gmail.com>
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the QtCore module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 
41 #include "private/qringbuffer_p.h"
42 #include "private/qbytearray_p.h"
43 
44 #include <type_traits>
45 
46 #include <string.h>
47 
49 
50 static_assert(std::is_nothrow_default_constructible_v<QRingChunk>);
51 static_assert(std::is_nothrow_move_constructible_v<QRingChunk>);
52 static_assert(std::is_nothrow_move_assignable_v<QRingChunk>);
53 
55 {
56  Q_ASSERT(alloc > 0 && size() == 0);
57 
58  if (chunk.size() < alloc || isShared())
59  chunk = QByteArray(alloc, Qt::Uninitialized);
60 }
61 
63 {
64  Q_ASSERT(isShared());
65 
66  const qsizetype chunkSize = size();
67  chunk = QByteArray(std::as_const(*this).data(), chunkSize);
68  headOffset = 0;
69  tailOffset = chunkSize;
70 }
71 
73 {
74  if (headOffset != 0 || tailOffset != chunk.size()) {
75  if (isShared())
76  return chunk.mid(headOffset, size());
77 
78  if (headOffset != 0) {
79  char *ptr = chunk.data();
80  ::memmove(ptr, ptr + headOffset, size());
81  tailOffset -= headOffset;
82  headOffset = 0;
83  }
84 
85  chunk.reserve(0); // avoid that resizing needlessly reallocates
86  chunk.resize(tailOffset);
87  }
88 
89  return chunk;
90 }
91 
100 {
101  Q_ASSERT(pos >= 0);
102 
103  for (const QRingChunk &chunk : buffers) {
104  length = chunk.size();
105  if (length > pos) {
106  length -= pos;
107  return chunk.data() + pos;
108  }
109  pos -= length;
110  }
111 
112  length = 0;
113  return nullptr;
114 }
115 
117 {
118  Q_ASSERT(bytes <= bufferSize);
119 
120  while (bytes > 0) {
121  const qint64 chunkSize = buffers.constFirst().size();
122 
123  if (buffers.size() == 1 || chunkSize > bytes) {
124  QRingChunk &chunk = buffers.first();
125  // keep a single block around if it does not exceed
126  // the basic block size, to avoid repeated allocations
127  // between uses of the buffer
128  if (bufferSize == bytes) {
129  if (chunk.capacity() <= basicBlockSize && !chunk.isShared()) {
130  chunk.reset();
131  bufferSize = 0;
132  } else {
133  clear(); // try to minify/squeeze us
134  }
135  } else {
136  Q_ASSERT(bytes < MaxByteArraySize);
137  chunk.advance(bytes);
138  bufferSize -= bytes;
139  }
140  return;
141  }
142 
143  bufferSize -= chunkSize;
144  bytes -= chunkSize;
145  buffers.removeFirst();
146  }
147 }
148 
150 {
151  Q_ASSERT(bytes > 0 && bytes < MaxByteArraySize);
152 
153  const qsizetype chunkSize = qMax(qint64(basicBlockSize), bytes);
154  qsizetype tail = 0;
155  if (bufferSize == 0) {
156  if (buffers.isEmpty())
157  buffers.append(QRingChunk(chunkSize));
158  else
159  buffers.first().allocate(chunkSize);
160  } else {
161  const QRingChunk &chunk = buffers.constLast();
162  // if need a new buffer
163  if (basicBlockSize == 0 || chunk.isShared() || bytes > chunk.available())
164  buffers.append(QRingChunk(chunkSize));
165  else
166  tail = chunk.size();
167  }
168 
169  buffers.last().grow(bytes);
170  bufferSize += bytes;
171  return buffers.last().data() + tail;
172 }
173 
180 {
181  Q_ASSERT(bytes > 0 && bytes < MaxByteArraySize);
182 
183  const qsizetype chunkSize = qMax(qint64(basicBlockSize), bytes);
184  if (bufferSize == 0) {
185  if (buffers.isEmpty())
186  buffers.prepend(QRingChunk(chunkSize));
187  else
188  buffers.first().allocate(chunkSize);
189  buffers.first().grow(chunkSize);
190  buffers.first().advance(chunkSize - bytes);
191  } else {
192  const QRingChunk &chunk = buffers.constFirst();
193  // if need a new buffer
194  if (basicBlockSize == 0 || chunk.isShared() || bytes > chunk.head()) {
195  buffers.prepend(QRingChunk(chunkSize));
196  buffers.first().grow(chunkSize);
197  buffers.first().advance(chunkSize - bytes);
198  } else {
199  buffers.first().advance(-bytes);
200  }
201  }
202 
203  bufferSize += bytes;
204  return buffers.first().data();
205 }
206 
208 {
209  Q_ASSERT(bytes <= bufferSize);
210 
211  while (bytes > 0) {
212  const qsizetype chunkSize = buffers.constLast().size();
213 
214  if (buffers.size() == 1 || chunkSize > bytes) {
215  QRingChunk &chunk = buffers.last();
216  // keep a single block around if it does not exceed
217  // the basic block size, to avoid repeated allocations
218  // between uses of the buffer
219  if (bufferSize == bytes) {
220  if (chunk.capacity() <= basicBlockSize && !chunk.isShared()) {
221  chunk.reset();
222  bufferSize = 0;
223  } else {
224  clear(); // try to minify/squeeze us
225  }
226  } else {
227  Q_ASSERT(bytes < MaxByteArraySize);
228  chunk.grow(-bytes);
229  bufferSize -= bytes;
230  }
231  return;
232  }
233 
234  bufferSize -= chunkSize;
235  bytes -= chunkSize;
236  buffers.removeLast();
237  }
238 }
239 
241 {
242  if (buffers.isEmpty())
243  return;
244 
245  buffers.erase(buffers.begin() + 1, buffers.end());
246  buffers.first().clear();
247  bufferSize = 0;
248 }
249 
251 {
252  Q_ASSERT(maxLength >= 0 && pos >= 0);
253 
254  if (maxLength == 0)
255  return -1;
256 
257  qint64 index = -pos;
258  for (const QRingChunk &chunk : buffers) {
259  const qint64 nextBlockIndex = qMin(index + chunk.size(), maxLength);
260 
261  if (nextBlockIndex > 0) {
262  const char *ptr = chunk.data();
263  if (index < 0) {
264  ptr -= index;
265  index = 0;
266  }
267 
268  const char *findPtr = reinterpret_cast<const char *>(memchr(ptr, c,
269  nextBlockIndex - index));
270  if (findPtr)
271  return qint64(findPtr - ptr) + index + pos;
272 
273  if (nextBlockIndex == maxLength)
274  return -1;
275  }
276  index = nextBlockIndex;
277  }
278  return -1;
279 }
280 
282 {
283  const qint64 bytesToRead = qMin(size(), maxLength);
284  qint64 readSoFar = 0;
285  while (readSoFar < bytesToRead) {
286  const qint64 bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar,
288  if (data)
289  memcpy(data + readSoFar, readPointer(), bytesToReadFromThisBlock);
290  readSoFar += bytesToReadFromThisBlock;
291  free(bytesToReadFromThisBlock);
292  }
293  return readSoFar;
294 }
295 
302 {
303  if (bufferSize == 0)
304  return QByteArray();
305 
306  bufferSize -= buffers.constFirst().size();
307  return buffers.takeFirst().toByteArray();
308 }
309 
316 {
317  Q_ASSERT(maxLength >= 0 && pos >= 0);
318 
319  qint64 readSoFar = 0;
320  for (const QRingChunk &chunk : buffers) {
321  if (readSoFar == maxLength)
322  break;
323 
324  qint64 blockLength = chunk.size();
325  if (pos < blockLength) {
326  blockLength = qMin(blockLength - pos, maxLength - readSoFar);
327  memcpy(data + readSoFar, chunk.data() + pos, blockLength);
328  readSoFar += blockLength;
329  pos = 0;
330  } else {
331  pos -= blockLength;
332  }
333  }
334 
335  return readSoFar;
336 }
337 
344 {
345  Q_ASSERT(size >= 0);
346 
347  if (size == 0)
348  return;
349 
350  char *writePointer = reserve(size);
351  if (size == 1)
352  *writePointer = *data;
353  else
354  ::memcpy(writePointer, data, size);
355 }
356 
363 {
364  if (bufferSize != 0 || buffers.isEmpty())
365  buffers.append(QRingChunk(qba));
366  else
367  buffers.last().assign(qba);
368  bufferSize += qba.size();
369 }
370 
377 {
378  const auto qbaSize = qba.size();
379  if (bufferSize != 0 || buffers.isEmpty())
380  buffers.emplace_back(std::move(qba));
381  else
382  buffers.last().assign(std::move(qba));
383  bufferSize += qbaSize;
384 }
385 
387 {
388  Q_ASSERT(data != nullptr && maxLength > 1);
389 
390  --maxLength;
391  qint64 i = indexOf('\n', maxLength);
392  i = read(data, i >= 0 ? (i + 1) : maxLength);
393 
394  // Terminate it.
395  data[i] = '\0';
396  return i;
397 }
398 
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
char * data()
Definition: qbytearray.h:516
qsizetype size() const noexcept
Definition: qbytearray.h:470
void reserve(qsizetype size)
Definition: qbytearray.h:539
void resize(qsizetype size)
QByteArray mid(qsizetype index, qsizetype len=-1) const
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)
Q_CORE_EXPORT const char * readPointerAtPosition(qint64 pos, qint64 &length) const
Definition: qringbuffer.cpp:99
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
const char * readPointer() const
Q_CORE_EXPORT void clear()
qint64 nextDataBlockSize() const
int chunkSize() const
void allocate(qsizetype alloc)
Definition: qringbuffer.cpp:54
bool isShared() const
Definition: qringbuffer_p.h:91
qsizetype size() const
Q_CORE_EXPORT void detach()
Definition: qringbuffer.cpp:62
QByteArray toByteArray()
Definition: qringbuffer.cpp:72
GeneratorWrapper< std::vector< T > > chunk(size_t size, GeneratorWrapper< T > &&generator)
Definition: catch_p_p.h:4333
constexpr Initialization Uninitialized
Definition: qnamespace.h:1613
void *PRIV() memmove(void *d, const void *s, size_t n)
constexpr QT_BEGIN_NAMESPACE qsizetype MaxByteArraySize
Definition: qbytearray_p.h:60
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
ptrdiff_t qsizetype
Definition: qglobal.h:308
long long qint64
Definition: qglobal.h:298
GLenum GLuint GLenum GLsizei length
Definition: qopengl.h:270
GLuint const GLuint * buffers
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
const GLubyte * c
Definition: qopenglext.h:12701
GLsizei maxLength
Definition: qopenglext.h:4189
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84