1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QRINGBUFFER_P_H
5#define QRINGBUFFER_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists for the convenience
12// of a number of Qt sources files. This header file may change from
13// version to version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtCore/private/qglobal_p.h>
19#include <QtCore/qbytearray.h>
20#include <QtCore/qlist.h>
21
22QT_BEGIN_NAMESPACE
23
24#ifndef QRINGBUFFER_CHUNKSIZE
25#define QRINGBUFFER_CHUNKSIZE 4096
26#endif
27
28class QRingChunk
29{
30public:
31 // initialization and cleanup
32 QRingChunk() noexcept = default;
33 explicit inline QRingChunk(qsizetype alloc) :
34 chunk(alloc, Qt::Uninitialized), tailOffset(0)
35 {
36 }
37 explicit inline QRingChunk(const QByteArray &qba) noexcept :
38 chunk(qba), tailOffset(qba.size())
39 {
40 }
41 explicit QRingChunk(QByteArray &&qba) noexcept :
42 chunk(std::move(qba)), tailOffset(chunk.size())
43 {
44 }
45
46 inline void swap(QRingChunk &other) noexcept
47 {
48 chunk.swap(other&: other.chunk);
49 qSwap(value1&: headOffset, value2&: other.headOffset);
50 qSwap(value1&: tailOffset, value2&: other.tailOffset);
51 }
52
53 // allocating and sharing
54 void allocate(qsizetype alloc);
55 inline bool isShared() const
56 {
57 return !chunk.isDetached();
58 }
59 Q_CORE_EXPORT void detach();
60 QByteArray toByteArray() &&;
61
62 // getters
63 inline qsizetype head() const
64 {
65 return headOffset;
66 }
67 inline qsizetype size() const
68 {
69 return tailOffset - headOffset;
70 }
71 inline qsizetype capacity() const
72 {
73 return chunk.size();
74 }
75 inline qsizetype available() const
76 {
77 return chunk.size() - tailOffset;
78 }
79 inline const char *data() const
80 {
81 return chunk.constData() + headOffset;
82 }
83 inline char *data()
84 {
85 if (isShared())
86 detach();
87 return chunk.data() + headOffset;
88 }
89
90 // array management
91 inline void advance(qsizetype offset)
92 {
93 Q_ASSERT(headOffset + offset >= 0);
94 Q_ASSERT(size() - offset > 0);
95
96 headOffset += offset;
97 }
98 inline void grow(qsizetype offset)
99 {
100 Q_ASSERT(size() + offset > 0);
101 Q_ASSERT(head() + size() + offset <= capacity());
102
103 tailOffset += offset;
104 }
105 inline void assign(const QByteArray &qba)
106 {
107 chunk = qba;
108 headOffset = 0;
109 tailOffset = qba.size();
110 }
111 void assign(QByteArray &&qba)
112 {
113 chunk = std::move(qba);
114 headOffset = 0;
115 tailOffset = chunk.size();
116 }
117 inline void reset()
118 {
119 headOffset = tailOffset = 0;
120 }
121 inline void clear()
122 {
123 *this = {};
124 }
125
126private:
127 QByteArray chunk;
128 qsizetype headOffset = 0;
129 qsizetype tailOffset = 0;
130};
131Q_DECLARE_SHARED(QRingChunk)
132
133class QRingBuffer
134{
135 Q_DISABLE_COPY(QRingBuffer)
136public:
137 explicit inline QRingBuffer(int growth = QRINGBUFFER_CHUNKSIZE) :
138 bufferSize(0), basicBlockSize(growth) { }
139
140 QRingBuffer(QRingBuffer &&) noexcept = default;
141 QRingBuffer &operator=(QRingBuffer &&) noexcept = default;
142
143 inline void setChunkSize(int size) {
144 basicBlockSize = size;
145 }
146
147 inline int chunkSize() const {
148 return basicBlockSize;
149 }
150
151 inline qint64 nextDataBlockSize() const {
152 return bufferSize == 0 ? Q_INT64_C(0) : buffers.first().size();
153 }
154
155 inline const char *readPointer() const {
156 return bufferSize == 0 ? nullptr : buffers.first().data();
157 }
158
159 Q_CORE_EXPORT const char *readPointerAtPosition(qint64 pos, qint64 &length) const;
160 Q_CORE_EXPORT void free(qint64 bytes);
161 Q_CORE_EXPORT char *reserve(qint64 bytes);
162 Q_CORE_EXPORT char *reserveFront(qint64 bytes);
163
164 inline void truncate(qint64 pos) {
165 Q_ASSERT(pos >= 0 && pos <= size());
166
167 chop(bytes: size() - pos);
168 }
169
170 Q_CORE_EXPORT void chop(qint64 bytes);
171
172 inline bool isEmpty() const {
173 return bufferSize == 0;
174 }
175
176 inline int getChar() {
177 if (isEmpty())
178 return -1;
179 char c = *readPointer();
180 free(bytes: 1);
181 return int(uchar(c));
182 }
183
184 inline void putChar(char c) {
185 char *ptr = reserve(bytes: 1);
186 *ptr = c;
187 }
188
189 void ungetChar(char c)
190 {
191 char *ptr = reserveFront(bytes: 1);
192 *ptr = c;
193 }
194
195
196 inline qint64 size() const {
197 return bufferSize;
198 }
199
200 Q_CORE_EXPORT void clear();
201 inline qint64 indexOf(char c) const { return indexOf(c, maxLength: size()); }
202 Q_CORE_EXPORT qint64 indexOf(char c, qint64 maxLength, qint64 pos = 0) const;
203 Q_CORE_EXPORT qint64 read(char *data, qint64 maxLength);
204 Q_CORE_EXPORT QByteArray read();
205 Q_CORE_EXPORT qint64 peek(char *data, qint64 maxLength, qint64 pos = 0) const;
206 Q_CORE_EXPORT void append(const char *data, qint64 size);
207 Q_CORE_EXPORT void append(const QByteArray &qba);
208 Q_CORE_EXPORT void append(QByteArray &&qba);
209
210 inline qint64 skip(qint64 length) {
211 qint64 bytesToSkip = qMin(a: length, b: bufferSize);
212
213 free(bytes: bytesToSkip);
214 return bytesToSkip;
215 }
216
217 Q_CORE_EXPORT qint64 readLine(char *data, qint64 maxLength);
218
219 inline bool canReadLine() const {
220 return indexOf(c: '\n') >= 0;
221 }
222
223private:
224 QList<QRingChunk> buffers;
225 qint64 bufferSize;
226 int basicBlockSize;
227};
228
229Q_DECLARE_TYPEINFO(QRingBuffer, Q_RELOCATABLE_TYPE);
230
231QT_END_NAMESPACE
232
233#endif // QRINGBUFFER_P_H
234

source code of qtbase/src/corelib/tools/qringbuffer_p.h