KVIrc 5.2.6
Developer APIs
qringbuffer_p.h
Go to the documentation of this file.
1/****************************************************************************
2**
3** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#ifndef QRINGBUFFER_P_H
43#define QRINGBUFFER_P_H
44
45//
46// W A R N I N G
47// -------------
48//
49// This file is not part of the Qt API. It exists for the convenience
50// of a number of Qt sources files. This header file may change from
51// version to version without notice, or even be removed.
52//
53// We mean it.
54//
55
56#include <QtCore/qbytearray.h>
57#include <QtCore/qlist.h>
58
60{
61public:
62 inline QRingBuffer(int growth = 4096) : basicBlockSize(growth)
63 {
64 buffers << QByteArray();
65 clear();
66 }
67
68 inline int nextDataBlockSize() const
69 {
70 return (tailBuffer == 0 ? tail : buffers.first().size()) - head;
71 }
72
73 inline const char * readPointer() const
74 {
75 return buffers.isEmpty() ? 0 : (buffers.first().constData() + head);
76 }
77
78 // access the bytes at a specified position
79 // the out-variable length will contain the amount of bytes readable
80 // from there, e.g. the amount still the same QByteArray
81 inline const char * readPointerAtPosition(qint64 pos, qint64 & length) const
82 {
83 if(buffers.isEmpty())
84 {
85 length = 0;
86 return 0;
87 }
88
89 if(pos >= bufferSize)
90 {
91 length = 0;
92 return 0;
93 }
94
95 // special case: it is in the first buffer
96 int nextDataBlockSizeValue = nextDataBlockSize();
97 if(pos - head < nextDataBlockSizeValue)
98 {
99 length = nextDataBlockSizeValue - pos;
100 return buffers.at(0).constData() + head + pos;
101 }
102
103 // special case: we only had one buffer and tried to read over it
104 if(buffers.length() == 1)
105 {
106 length = 0;
107 return 0;
108 }
109
110 // skip the first
111 pos -= nextDataBlockSizeValue;
112
113 // normal case: it is somewhere in the second to the-one-before-the-tailBuffer
114 for(int i = 1; i < tailBuffer; i++)
115 {
116 if(pos >= buffers[i].size())
117 {
118 pos -= buffers[i].size();
119 continue;
120 }
121
122 length = buffers[i].length() - pos;
123 return buffers[i].constData() + pos;
124 }
125
126 // it is in the tail buffer
127 length = tail - pos;
128 return buffers[tailBuffer].constData() + pos;
129 }
130
131 inline void free(int bytes)
132 {
133 bufferSize -= bytes;
134 if(bufferSize < 0)
135 bufferSize = 0;
136
137 for(;;)
138 {
139 int nextBlockSize = nextDataBlockSize();
140 if(bytes < nextBlockSize)
141 {
142 head += bytes;
143 if(head == tail && tailBuffer == 0)
144 head = tail = 0;
145 break;
146 }
147
148 bytes -= nextBlockSize;
149 if(buffers.count() == 1)
150 {
151 if(buffers.at(0).size() != basicBlockSize)
152 buffers[0].resize(basicBlockSize);
153 head = tail = 0;
154 tailBuffer = 0;
155 break;
156 }
157
158 buffers.removeAt(0);
159 --tailBuffer;
160 head = 0;
161 }
162
163 if(isEmpty())
164 clear(); // try to minify/squeeze us
165 }
166
167 inline char * reserve(int bytes)
168 {
169 // if this is a fresh empty QRingBuffer
170 if(bufferSize == 0)
171 {
172 buffers[0].resize(qMax(basicBlockSize, bytes));
173 bufferSize += bytes;
174 tail = bytes;
175 return buffers[tailBuffer].data();
176 }
177
178 bufferSize += bytes;
179
180 // if there is already enough space, simply return.
181 if(tail + bytes <= buffers.at(tailBuffer).size())
182 {
183 char * writePtr = buffers[tailBuffer].data() + tail;
184 tail += bytes;
185 return writePtr;
186 }
187
188 // if our buffer isn't half full yet, simply resize it.
189 if(tail < buffers.at(tailBuffer).size() / 2)
190 {
191 buffers[tailBuffer].resize(tail + bytes);
192 char * writePtr = buffers[tailBuffer].data() + tail;
193 tail += bytes;
194 return writePtr;
195 }
196
197 // shrink this buffer to its current size
198 buffers[tailBuffer].resize(tail);
199
200 // create a new QByteArray with the right size
201 buffers << QByteArray();
202 ++tailBuffer;
203 buffers[tailBuffer].resize(qMax(basicBlockSize, bytes));
204 tail = bytes;
205 return buffers[tailBuffer].data();
206 }
207
208 inline void truncate(int pos)
209 {
210 if(pos < size())
211 chop(size() - pos);
212 }
213
214 inline void chop(int bytes)
215 {
216 bufferSize -= bytes;
217 if(bufferSize < 0)
218 bufferSize = 0;
219
220 for(;;)
221 {
222 // special case: head and tail are in the same buffer
223 if(tailBuffer == 0)
224 {
225 tail -= bytes;
226 if(tail <= head)
227 tail = head = 0;
228 return;
229 }
230
231 if(bytes <= tail)
232 {
233 tail -= bytes;
234 return;
235 }
236
237 bytes -= tail;
238 buffers.removeAt(tailBuffer);
239
240 --tailBuffer;
241 tail = buffers.at(tailBuffer).size();
242 }
243
244 if(isEmpty())
245 clear(); // try to minify/squeeze us
246 }
247
248 inline bool isEmpty() const
249 {
250 return tailBuffer == 0 && tail == 0;
251 }
252
253 inline int getChar()
254 {
255 if(isEmpty())
256 return -1;
257 char c = *readPointer();
258 free(1);
259 return int(uchar(c));
260 }
261
262 inline void putChar(char c)
263 {
264 char * ptr = reserve(1);
265 *ptr = c;
266 }
267
268 inline void ungetChar(char c)
269 {
270 --head;
271 if(head < 0)
272 {
273 buffers.prepend(QByteArray());
274 buffers[0].resize(basicBlockSize);
275 head = basicBlockSize - 1;
276 ++tailBuffer;
277 }
278 buffers[0][head] = c;
279 ++bufferSize;
280 }
281
282 inline int size() const
283 {
284 return bufferSize;
285 }
286
287 inline void clear()
288 {
289 buffers.erase(buffers.begin() + 1, buffers.end());
290 buffers[0].resize(0);
291 buffers[0].squeeze();
292
293 head = tail = 0;
294 tailBuffer = 0;
295 bufferSize = 0;
296 }
297
298 inline int indexOf(char c) const
299 {
300 int index = 0;
301 for(int i = 0; i < buffers.size(); ++i)
302 {
303 int start = 0;
304 int end = buffers.at(i).size();
305
306 if(i == 0)
307 start = head;
308 if(i == tailBuffer)
309 end = tail;
310 const char * ptr = buffers.at(i).data() + start;
311 for(int j = start; j < end; ++j)
312 {
313 if(*ptr++ == c)
314 return index;
315 ++index;
316 }
317 }
318 return -1;
319 }
320
321 inline int indexOf(char c, int maxLength) const
322 {
323 int index = 0;
324 int remain = qMin(size(), maxLength);
325 for(int i = 0; remain && i < buffers.size(); ++i)
326 {
327 int start = 0;
328 int end = buffers.at(i).size();
329
330 if(i == 0)
331 start = head;
332 if(i == tailBuffer)
333 end = tail;
334 if(remain < end - start)
335 {
336 end = start + remain;
337 remain = 0;
338 }
339 else
340 {
341 remain -= end - start;
342 }
343 const char * ptr = buffers.at(i).data() + start;
344 for(int j = start; j < end; ++j)
345 {
346 if(*ptr++ == c)
347 return index;
348 ++index;
349 }
350 }
351 return -1;
352 }
353
354 inline int read(char * data, int maxLength)
355 {
356 int bytesToRead = qMin(size(), maxLength);
357 int readSoFar = 0;
358 while(readSoFar < bytesToRead)
359 {
360 const char * ptr = readPointer();
361 int bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar, nextDataBlockSize());
362 if(data)
363 memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock);
364 readSoFar += bytesToReadFromThisBlock;
365 free(bytesToReadFromThisBlock);
366 }
367 return readSoFar;
368 }
369
370 inline QByteArray read(int maxLength)
371 {
372 QByteArray tmp;
373 tmp.resize(qMin(maxLength, size()));
374 read(tmp.data(), tmp.size());
375 return tmp;
376 }
377
378 inline QByteArray readAll()
379 {
380 return read(size());
381 }
382
383 // read an unspecified amount (will read the first buffer)
384 inline QByteArray read()
385 {
386 if(bufferSize == 0)
387 return QByteArray();
388
389 // multiple buffers, just take the first one
390 if(head == 0 && tailBuffer != 0)
391 {
392 QByteArray qba = buffers.takeFirst();
393 --tailBuffer;
394 bufferSize -= qba.length();
395 return qba;
396 }
397
398 // one buffer with good value for head. Just take it.
399 if(head == 0 && tailBuffer == 0)
400 {
401 QByteArray qba = buffers.takeFirst();
402 qba.resize(tail);
403 buffers << QByteArray();
404 bufferSize = 0;
405 tail = 0;
406 return qba;
407 }
408
409 // Bad case: We have to memcpy.
410 // We can avoid by initializing the QRingBuffer with basicBlockSize of 0
411 // and only using this read() function.
412 QByteArray qba(readPointer(), nextDataBlockSize());
413 buffers.removeFirst();
414 head = 0;
415 if(tailBuffer == 0)
416 {
417 buffers << QByteArray();
418 tail = 0;
419 }
420 else
421 {
422 --tailBuffer;
423 }
424 bufferSize -= qba.length();
425 return qba;
426 }
427
428 // append a new buffer to the end
429 inline void append(const QByteArray & qba)
430 {
431 buffers[tailBuffer].resize(tail);
432 buffers << qba;
433 ++tailBuffer;
434 tail = qba.length();
435 bufferSize += qba.length();
436 }
437
438 inline QByteArray peek(int maxLength) const
439 {
440 int bytesToRead = qMin(size(), maxLength);
441 if(maxLength <= 0)
442 return QByteArray();
443 QByteArray ret;
444 ret.resize(bytesToRead);
445 int readSoFar = 0;
446 for(int i = 0; readSoFar < bytesToRead && i < buffers.size(); ++i)
447 {
448 int start = 0;
449 int end = buffers.at(i).size();
450 if(i == 0)
451 start = head;
452 if(i == tailBuffer)
453 end = tail;
454 const int len = qMin(ret.size() - readSoFar, end - start);
455 memcpy(ret.data() + readSoFar, buffers.at(i).constData() + start, len);
456 readSoFar += len;
457 }
458 Q_ASSERT(readSoFar == ret.size());
459 return ret;
460 }
461
462 inline int skip(int length)
463 {
464 return read(0, length);
465 }
466
467 inline int readLine(char * data, int maxLength)
468 {
469 int index = indexOf('\n');
470 if(index == -1)
471 return read(data, maxLength);
472 if(maxLength <= 0)
473 return -1;
474
475 int readSoFar = 0;
476 while(readSoFar < index + 1 && readSoFar < maxLength - 1)
477 {
478 int bytesToRead = qMin((index + 1) - readSoFar, nextDataBlockSize());
479 bytesToRead = qMin(bytesToRead, (maxLength - 1) - readSoFar);
480 memcpy(data + readSoFar, readPointer(), bytesToRead);
481 readSoFar += bytesToRead;
482 free(bytesToRead);
483 }
484
485 // Terminate it.
486 data[readSoFar] = '\0';
487 return readSoFar;
488 }
489
490 inline bool canReadLine() const
491 {
492 return indexOf('\n') != -1;
493 }
494
495private:
496 QList<QByteArray> buffers;
497 int head, tail;
498 int tailBuffer; // always buffers.size() - 1
501};
502
503#endif // QRINGBUFFER_P_H
KviPtrListIterator< T > end(KviPointerList< T > *ptrList)
Definition KviPtrListIterator.h:68
bool isEmpty() const
Definition qringbuffer_p.h:248
int nextDataBlockSize() const
Definition qringbuffer_p.h:68
QByteArray read()
Definition qringbuffer_p.h:384
char * reserve(int bytes)
Definition qringbuffer_p.h:167
void free(int bytes)
Definition qringbuffer_p.h:131
QList< QByteArray > buffers
Definition qringbuffer_p.h:496
int head
Definition qringbuffer_p.h:497
int bufferSize
Definition qringbuffer_p.h:500
const char * readPointer() const
Definition qringbuffer_p.h:73
int getChar()
Definition qringbuffer_p.h:253
void append(const QByteArray &qba)
Definition qringbuffer_p.h:429
QByteArray readAll()
Definition qringbuffer_p.h:378
const char * readPointerAtPosition(qint64 pos, qint64 &length) const
Definition qringbuffer_p.h:81
int size() const
Definition qringbuffer_p.h:282
int skip(int length)
Definition qringbuffer_p.h:462
void truncate(int pos)
Definition qringbuffer_p.h:208
bool canReadLine() const
Definition qringbuffer_p.h:490
QByteArray peek(int maxLength) const
Definition qringbuffer_p.h:438
int tailBuffer
Definition qringbuffer_p.h:498
void chop(int bytes)
Definition qringbuffer_p.h:214
int tail
Definition qringbuffer_p.h:497
int readLine(char *data, int maxLength)
Definition qringbuffer_p.h:467
QRingBuffer(int growth=4096)
Definition qringbuffer_p.h:62
QByteArray read(int maxLength)
Definition qringbuffer_p.h:370
void clear()
Definition qringbuffer_p.h:287
int basicBlockSize
Definition qringbuffer_p.h:499
int indexOf(char c) const
Definition qringbuffer_p.h:298
void ungetChar(char c)
Definition qringbuffer_p.h:268
int read(char *data, int maxLength)
Definition qringbuffer_p.h:354
void putChar(char c)
Definition qringbuffer_p.h:262
int indexOf(char c, int maxLength) const
Definition qringbuffer_p.h:321
#define i
Definition detector.cpp:74
#define j
Definition detector.cpp:75