File indexing completed on 2024-05-19 04:52:26
0001 /* 0002 SPDX-FileCopyrightText: 2009 Nokia Corporation and /or its subsidiary(-ies). 0003 Contact: Qt Software Information (qt-info@nokia.com) 0004 0005 This file is part of the QtCore module of the Qt Toolkit. 0006 0007 $QT_BEGIN_LICENSE:LGPL$ 0008 Commercial Usage 0009 Licensees holding valid Qt Commercial licenses may use this file in 0010 accordance with the Qt Commercial License Agreement provided with the 0011 Software or, alternatively, in accordance with the terms contained in 0012 a written agreement between you and Nokia. 0013 0014 GNU Lesser General Public License Usage 0015 Alternatively, this file may be used under the terms of the GNU Lesser 0016 General Public License version 2.1 as published by the Free Software 0017 Foundation and appearing in the file LICENSE.LGPL included in the 0018 packaging of this file. Please review the following information to 0019 ensure the GNU Lesser General Public License version 2.1 requirements 0020 will be met: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 0021 0022 In addition, as a special exception, Nokia gives you certain 0023 additional rights. These rights are described in the Nokia Qt LGPL 0024 Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 0025 package. 0026 0027 GNU General Public License Usage 0028 Alternatively, this file may be used under the terms of the GNU 0029 General Public License version 3.0 as published by the Free Software 0030 Foundation and appearing in the file LICENSE.GPL included in the 0031 packaging of this file. Please review the following information to 0032 ensure the GNU General Public License version 3.0 requirements will be 0033 met: https://www.gnu.org/licenses/gpl-3.0.html. 0034 0035 If you are unsure which license is appropriate for your use, please 0036 contact the sales department at qt-sales@nokia.com. 0037 $QT_END_LICENSE$ 0038 0039 */ 0040 0041 #ifndef QRINGBUFFER_P_H 0042 #define QRINGBUFFER_P_H 0043 0044 // 0045 // W A R N I N G 0046 // ------------- 0047 // 0048 // This file is not part of the Qt API. It exists for the convenience 0049 // of a number of Qt sources files. This header file may change from 0050 // version to version without notice, or even be removed. 0051 // 0052 // We mean it. 0053 // 0054 0055 #include <QByteArray> 0056 #include <QList> 0057 0058 QT_BEGIN_NAMESPACE 0059 0060 class QRingBuffer 0061 { 0062 public: 0063 inline QRingBuffer(int growth = 4096) : basicBlockSize(growth) { 0064 buffers << QByteArray(); 0065 clear(); 0066 } 0067 0068 inline int nextDataBlockSize() const { 0069 return (tailBuffer == 0 ? tail : buffers.first().size()) - head; 0070 } 0071 0072 inline const char *readPointer() const { 0073 return buffers.isEmpty() ? 0 : (buffers.first().constData() + head); 0074 } 0075 0076 inline void free(int bytes) { 0077 bufferSize -= bytes; 0078 if (bufferSize < 0) 0079 bufferSize = 0; 0080 0081 for (;;) { 0082 int nextBlockSize = nextDataBlockSize(); 0083 if (bytes < nextBlockSize) { 0084 head += bytes; 0085 if (head == tail && tailBuffer == 0) 0086 head = tail = 0; 0087 break; 0088 } 0089 0090 bytes -= nextBlockSize; 0091 if (buffers.count() == 1) { 0092 if (buffers.at(0).size() != basicBlockSize) 0093 buffers[0].resize(basicBlockSize); 0094 head = tail = 0; 0095 tailBuffer = 0; 0096 break; 0097 } 0098 0099 buffers.removeAt(0); 0100 --tailBuffer; 0101 head = 0; 0102 } 0103 } 0104 0105 inline char *reserve(int bytes) { 0106 bufferSize += bytes; 0107 0108 // if there is already enough space, simply return. 0109 if (tail + bytes <= buffers.at(tailBuffer).size()) { 0110 char *writePtr = buffers[tailBuffer].data() + tail; 0111 tail += bytes; 0112 return writePtr; 0113 } 0114 0115 // if our buffer isn't half full yet, simply resize it. 0116 if (tail < buffers.at(tailBuffer).size() / 2) { 0117 buffers[tailBuffer].resize(tail + bytes); 0118 char *writePtr = buffers[tailBuffer].data() + tail; 0119 tail += bytes; 0120 return writePtr; 0121 } 0122 0123 // shrink this buffer to its current size 0124 buffers[tailBuffer].resize(tail); 0125 0126 // create a new QByteArray with the right size 0127 buffers << QByteArray(); 0128 ++tailBuffer; 0129 buffers[tailBuffer].resize(qMax(basicBlockSize, bytes)); 0130 tail = bytes; 0131 return buffers[tailBuffer].data(); 0132 } 0133 0134 inline void truncate(int pos) { 0135 if (pos < size()) 0136 chop(size() - pos); 0137 } 0138 0139 inline void chop(int bytes) { 0140 bufferSize -= bytes; 0141 if (bufferSize < 0) 0142 bufferSize = 0; 0143 0144 for (;;) { 0145 // special case: head and tail are in the same buffer 0146 if (tailBuffer == 0) { 0147 tail -= bytes; 0148 if (tail <= head) 0149 tail = head = 0; 0150 return; 0151 } 0152 0153 if (bytes <= tail) { 0154 tail -= bytes; 0155 return; 0156 } 0157 0158 bytes -= tail; 0159 buffers.removeAt(tailBuffer); 0160 0161 --tailBuffer; 0162 tail = buffers.at(tailBuffer).size(); 0163 } 0164 } 0165 0166 inline bool isEmpty() const { 0167 return tailBuffer == 0 && tail == 0; 0168 } 0169 0170 inline int getChar() { 0171 if (isEmpty()) 0172 return -1; 0173 char c = *readPointer(); 0174 free(1); 0175 return int(uchar(c)); 0176 } 0177 0178 inline void putChar(char c) { 0179 char *ptr = reserve(1); 0180 *ptr = c; 0181 } 0182 0183 inline void ungetChar(char c) { 0184 --head; 0185 if (head < 0) { 0186 buffers.prepend(QByteArray()); 0187 buffers[0].resize(basicBlockSize); 0188 head = basicBlockSize - 1; 0189 ++tailBuffer; 0190 } 0191 buffers[0][head] = c; 0192 ++bufferSize; 0193 } 0194 0195 inline int size() const { 0196 return bufferSize; 0197 } 0198 0199 inline void clear() { 0200 if(!buffers.isEmpty()) { 0201 QByteArray tmp = buffers[0]; 0202 buffers.clear(); 0203 buffers << tmp; 0204 if (buffers.at(0).size() != basicBlockSize) 0205 buffers[0].resize(basicBlockSize); 0206 } 0207 head = tail = 0; 0208 tailBuffer = 0; 0209 bufferSize = 0; 0210 } 0211 0212 inline int indexOf(char c) const { 0213 int index = 0; 0214 for (int i = 0; i < buffers.size(); ++i) { 0215 int start = 0; 0216 int end = buffers.at(i).size(); 0217 0218 if (i == 0) 0219 start = head; 0220 if (i == tailBuffer) 0221 end = tail; 0222 const char *ptr = buffers.at(i).data() + start; 0223 for (int j = start; j < end; ++j) { 0224 if (*ptr++ == c) 0225 return index; 0226 ++index; 0227 } 0228 } 0229 return -1; 0230 } 0231 0232 inline int read(char *data, int maxLength) { 0233 int bytesToRead = qMin(size(), maxLength); 0234 int readSoFar = 0; 0235 while (readSoFar < bytesToRead) { 0236 const char *ptr = readPointer(); 0237 int bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar, nextDataBlockSize()); 0238 if (data) 0239 memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock); 0240 readSoFar += bytesToReadFromThisBlock; 0241 free(bytesToReadFromThisBlock); 0242 } 0243 return readSoFar; 0244 } 0245 0246 inline QByteArray read(int maxLength) { 0247 QByteArray tmp; 0248 tmp.resize(qMin(maxLength, size())); 0249 read(tmp.data(), tmp.size()); 0250 return tmp; 0251 } 0252 0253 inline QByteArray readAll() { 0254 return read(size()); 0255 } 0256 0257 inline QByteArray peek(int maxLength) const { 0258 int bytesToRead = qMin(size(), maxLength); 0259 if(maxLength <= 0) 0260 return QByteArray(); 0261 QByteArray ret; 0262 ret.resize(bytesToRead); 0263 int readSoFar = 0; 0264 for (int i = 0; readSoFar < bytesToRead && i < buffers.size(); ++i) { 0265 int start = 0; 0266 int end = buffers.at(i).size(); 0267 if (i == 0) 0268 start = head; 0269 if (i == tailBuffer) 0270 end = tail; 0271 const int len = qMin(ret.size()-readSoFar, end-start); 0272 memcpy(ret.data()+readSoFar, buffers.at(i).constData()+start, len); 0273 readSoFar += len; 0274 } 0275 Q_ASSERT(readSoFar == ret.size()); 0276 return ret; 0277 } 0278 0279 inline int skip(int length) { 0280 return read(0, length); 0281 } 0282 0283 inline int readLine(char *data, int maxLength) { 0284 int index = indexOf('\n'); 0285 if (index == -1) 0286 return read(data, maxLength); 0287 if (maxLength <= 0) 0288 return -1; 0289 0290 int readSoFar = 0; 0291 while (readSoFar < index + 1 && readSoFar < maxLength - 1) { 0292 int bytesToRead = qMin((index + 1) - readSoFar, nextDataBlockSize()); 0293 bytesToRead = qMin(bytesToRead, (maxLength - 1) - readSoFar); 0294 memcpy(data + readSoFar, readPointer(), bytesToRead); 0295 readSoFar += bytesToRead; 0296 free(bytesToRead); 0297 } 0298 0299 // Terminate it. 0300 data[readSoFar] = '\0'; 0301 return readSoFar; 0302 } 0303 0304 inline bool canReadLine() const { 0305 return indexOf('\n') != -1; 0306 } 0307 0308 private: 0309 QList<QByteArray> buffers; 0310 int head, tail; 0311 int tailBuffer; 0312 int basicBlockSize; 0313 int bufferSize; 0314 }; 0315 0316 QT_END_NAMESPACE 0317 0318 #endif // QRINGBUFFER_P_H