summaryrefslogtreecommitdiffstats
path: root/app/perfstdin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'app/perfstdin.cpp')
-rw-r--r--app/perfstdin.cpp100
1 files changed, 89 insertions, 11 deletions
diff --git a/app/perfstdin.cpp b/app/perfstdin.cpp
index c5af9b4..af091eb 100644
--- a/app/perfstdin.cpp
+++ b/app/perfstdin.cpp
@@ -22,30 +22,59 @@
#include <QTimer>
+#include <cstring>
#include <cstdio>
#include <limits>
+PerfStdin::PerfStdin(QObject *parent) : QIODevice(parent)
+{
+ connect(&m_timer, &QTimer::timeout, this, &PerfStdin::receiveData);
+}
+
+PerfStdin::~PerfStdin()
+{
+ if (isOpen())
+ close();
+}
+
bool PerfStdin::open(QIODevice::OpenMode mode)
{
if (!(mode & QIODevice::ReadOnly) || (mode & QIODevice::WriteOnly))
return false;
- return QIODevice::open(mode);
+ if (QIODevice::open(mode)) {
+ m_buffer.resize(s_minBufferSize);
+ m_timer.start();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void PerfStdin::close()
+{
+ m_timer.stop();
+ QIODevice::close();
}
qint64 PerfStdin::readData(char *data, qint64 maxlen)
{
if (maxlen <= 0)
return 0;
- size_t read = fread(data, 1, static_cast<size_t>(maxlen), stdin);
- if (feof(stdin) || ferror(stdin))
- QTimer::singleShot(0, this, &QIODevice::close);
- if (read == 0) {
- return -1;
- } else {
- Q_ASSERT(read <= static_cast<size_t>(maxlen));
- return static_cast<qint64>(read);
- }
+
+ qint64 read = 0;
+ do {
+ Q_ASSERT(m_buffer.length() >= m_bufferPos);
+ Q_ASSERT(m_buffer.length() >= m_bufferUsed);
+ Q_ASSERT(m_bufferPos <= m_bufferUsed);
+ const size_t buffered = static_cast<size_t>(qMin(bufferedAvailable(), maxlen - read));
+ memcpy(data + read, m_buffer.constData() + m_bufferPos, buffered);
+ m_bufferPos += buffered;
+ read += buffered;
+ } while (read < maxlen && fillBuffer(maxlen) > 0);
+
+ Q_ASSERT(read > 0 || bufferedAvailable() == 0);
+ return (read == 0 && stdinAtEnd()) ? -1 : read;
}
qint64 PerfStdin::writeData(const char *data, qint64 len)
@@ -55,6 +84,55 @@ qint64 PerfStdin::writeData(const char *data, qint64 len)
return -1;
}
+void PerfStdin::receiveData()
+{
+ if (fillBuffer() > 0)
+ emit readyRead();
+ else if (stdinAtEnd())
+ close();
+}
+
+void PerfStdin::resizeBuffer(int newSize)
+{
+ QByteArray newBuffer(newSize, Qt::Uninitialized);
+ std::memcpy(newBuffer.data(), m_buffer.data() + m_bufferPos,
+ static_cast<size_t>(m_bufferUsed - m_bufferPos));
+ qSwap(m_buffer, newBuffer);
+ m_bufferUsed -= m_bufferPos;
+ Q_ASSERT(m_buffer.length() >= m_bufferUsed);
+ m_bufferPos = 0;
+}
+
+qint64 PerfStdin::fillBuffer(qint64 targetBufferSize)
+{
+ if (m_bufferUsed == m_bufferPos)
+ m_bufferPos = m_bufferUsed = 0;
+
+ targetBufferSize = qMin(targetBufferSize, static_cast<qint64>(s_maxBufferSize));
+ if (targetBufferSize > m_buffer.length())
+ resizeBuffer(static_cast<int>(targetBufferSize));
+
+ if (m_bufferUsed == m_buffer.length()) {
+ if (m_bufferPos == 0) {
+ resizeBuffer(m_bufferUsed <= s_maxBufferSize / 2 ? m_bufferUsed * 2
+ : s_maxBufferSize);
+ } else {
+ resizeBuffer(m_bufferUsed);
+ }
+ }
+
+ const size_t read = fread(m_buffer.data() + m_bufferUsed, 1,
+ static_cast<size_t>(m_buffer.length() - m_bufferUsed), stdin);
+ m_bufferUsed += read;
+ Q_ASSERT(m_buffer.length() >= m_bufferUsed);
+ return static_cast<qint64>(read);
+}
+
+bool PerfStdin::stdinAtEnd() const
+{
+ return feof(stdin) || ferror(stdin);
+}
+
bool PerfStdin::isSequential() const
{
return true;
@@ -62,5 +140,5 @@ bool PerfStdin::isSequential() const
qint64 PerfStdin::bytesAvailable() const
{
- return isOpen() ? std::numeric_limits<qint64>::max() : 0;
+ return bufferedAvailable() + QIODevice::bytesAvailable();
}