// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QPRIVATELINEARBUFFER_P_H #define QPRIVATELINEARBUFFER_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // // This is QIODevice's read buffer, optimised for read(), isEmpty() and getChar() class QPrivateLinearBuffer { public: QPrivateLinearBuffer() : len(0), first(0), buf(0), capacity(0) { } ~QPrivateLinearBuffer() { delete [] buf; } void clear() { first = buf; len = 0; } qsizetype size() const { return len; } bool isEmpty() const { return len == 0; } void skip(qsizetype n) { if (n >= len) { clear(); } else { len -= n; first += n; } } int getChar() { if (len == 0) return -1; int ch = uchar(*first); len--; first++; return ch; } qsizetype read(char* target, qsizetype size) { qsizetype r = (std::min)(size, len); memcpy(target, first, r); len -= r; first += r; return r; } char* reserve(qsizetype size) { makeSpace(size + len, freeSpaceAtEnd); char* writePtr = first + len; len += size; return writePtr; } void chop(qsizetype size) { if (size >= len) { clear(); } else { len -= size; } } QByteArray readAll() { char* f = first; qsizetype l = len; clear(); return QByteArray(f, l); } qsizetype readLine(char* target, qsizetype size) { qsizetype r = (std::min)(size, len); char* eol = static_cast(memchr(first, '\n', r)); if (eol) r = 1+(eol-first); memcpy(target, first, r); len -= r; first += r; return r; } bool canReadLine() const { return memchr(first, '\n', len); } void ungetChar(char c) { if (first == buf) { // underflow, the existing valid data needs to move to the end of the (potentially bigger) buffer makeSpace(len+1, freeSpaceAtStart); } first--; len++; *first = c; } void ungetBlock(const char* block, qsizetype size) { if ((first - buf) < size) { // underflow, the existing valid data needs to move to the end of the (potentially bigger) buffer makeSpace(len + size, freeSpaceAtStart); } first -= size; len += size; memcpy(first, block, size); } private: enum FreeSpacePos {freeSpaceAtStart, freeSpaceAtEnd}; void makeSpace(size_t required, FreeSpacePos where) { size_t newCapacity = (std::max)(capacity, size_t(QPRIVATELINEARBUFFER_BUFFERSIZE)); while (newCapacity < required) newCapacity *= 2; const qsizetype moveOffset = (where == freeSpaceAtEnd) ? 0 : qsizetype(newCapacity) - len; if (newCapacity > capacity) { // allocate more space char* newBuf = new char[newCapacity]; memmove(newBuf + moveOffset, first, len); delete [] buf; buf = newBuf; capacity = newCapacity; } else { // shift any existing data to make space memmove(buf + moveOffset, first, len); } first = buf + moveOffset; } private: // length of the unread data qsizetype len; // start of the unread data char* first; // the allocated buffer char* buf; // allocated buffer size size_t capacity; }; #endif // QPRIVATELINEARBUFFER_P_H