KVIrc  4.9.2
DeveloperAPIs
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 {
61 public:
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 
495 private:
496  QList<QByteArray> buffers;
497  int head, tail;
498  int tailBuffer; // always buffers.size() - 1
501 };
502 
503 #endif // QRINGBUFFER_P_H
void chop(int bytes)
Definition: qringbuffer_p.h:214
void truncate(int pos)
Definition: qringbuffer_p.h:208
bool canReadLine() const
Definition: qringbuffer_p.h:490
int head
Definition: qringbuffer_p.h:497
int getChar()
Definition: qringbuffer_p.h:253
char s char s char s s s s s char char c s *s c s s s d c s *s d c d d d d c
Definition: KviIrcNumericCodes.h:391
void putChar(char c)
Definition: qringbuffer_p.h:262
int size() const
Definition: qringbuffer_p.h:282
bool isEmpty() const
Definition: qringbuffer_p.h:248
int tail
Definition: qringbuffer_p.h:497
int nextDataBlockSize() const
Definition: qringbuffer_p.h:68
QByteArray read()
Definition: qringbuffer_p.h:384
void clear()
Definition: qringbuffer_p.h:287
int skip(int length)
Definition: qringbuffer_p.h:462
void ungetChar(char c)
Definition: qringbuffer_p.h:268
#define i
Definition: detector.cpp:73
Definition: qringbuffer_p.h:59
void free(int bytes)
Definition: qringbuffer_p.h:131
int readLine(char *data, int maxLength)
Definition: qringbuffer_p.h:467
int indexOf(char c, int maxLength) const
Definition: qringbuffer_p.h:321
void append(const QByteArray &qba)
Definition: qringbuffer_p.h:429
int read(char *data, int maxLength)
Definition: qringbuffer_p.h:354
QByteArray peek(int maxLength) const
Definition: qringbuffer_p.h:438
const char * readPointerAtPosition(qint64 pos, qint64 &length) const
Definition: qringbuffer_p.h:81
#define j
Definition: detector.cpp:74
int tailBuffer
Definition: qringbuffer_p.h:498
int bufferSize
Definition: qringbuffer_p.h:500
QByteArray read(int maxLength)
Definition: qringbuffer_p.h:370
const char * readPointer() const
Definition: qringbuffer_p.h:73
QList< QByteArray > buffers
Definition: qringbuffer_p.h:496
int basicBlockSize
Definition: qringbuffer_p.h:499
QByteArray readAll()
Definition: qringbuffer_p.h:378
int indexOf(char c) const
Definition: qringbuffer_p.h:298
char * reserve(int bytes)
Definition: qringbuffer_p.h:167
QRingBuffer(int growth=4096)
Definition: qringbuffer_p.h:62