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