198 lines
5.6 KiB
C++
198 lines
5.6 KiB
C++
|
|
/****************************************************************************
|
|
** Copyright (c) 2006 - 2011, the LibQxt project.
|
|
** See the Qxt AUTHORS file for a list of authors and copyright holders.
|
|
** All rights reserved.
|
|
**
|
|
** Redistribution and use in source and binary forms, with or without
|
|
** modification, are permitted provided that the following conditions are met:
|
|
** * Redistributions of source code must retain the above copyright
|
|
** notice, this list of conditions and the following disclaimer.
|
|
** * Redistributions in binary form must reproduce the above copyright
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
** documentation and/or other materials provided with the distribution.
|
|
** * Neither the name of the LibQxt project nor the
|
|
** names of its contributors may be used to endorse or promote products
|
|
** derived from this software without specific prior written permission.
|
|
**
|
|
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
** DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
**
|
|
** <http://libqxt.org> <foundation@libqxt.org>
|
|
*****************************************************************************/
|
|
|
|
/*!
|
|
\class QxtFifo
|
|
|
|
\inmodule QxtCore
|
|
|
|
\brief The QxtFifo class provides a simple loopback QIODevice.
|
|
|
|
read and write to the same object
|
|
emits a readyRead Signal.
|
|
useful for loopback tests where QBuffer does not work.
|
|
|
|
\code
|
|
QxtFifo fifo;
|
|
QTextStream (&fifo)<<QString("foo");
|
|
QString a;
|
|
QTextStream(&fifo)>>a;
|
|
qDebug()<<a;
|
|
\endcode
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "qxtfifo.h"
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
#include <QDebug>
|
|
#include <QQueue>
|
|
|
|
#include <qatomic.h>
|
|
|
|
#if QT_VERSION >= 0x040400
|
|
# include <qbasicatomic.h>
|
|
# define QXT_EXCHANGE fetchAndStoreOrdered
|
|
# define QXT_ADD fetchAndAddOrdered
|
|
#else
|
|
typedef QBasicAtomic QBasicAtomicInt;
|
|
# define QXT_EXCHANGE exchange
|
|
# define QXT_ADD fetchAndAdd
|
|
#endif
|
|
|
|
struct QxtFifoNode {
|
|
QxtFifoNode(const char* data, int size) : content(data, size) {
|
|
next = NULL;
|
|
}
|
|
QxtFifoNode(const QByteArray &data) : content(data) {
|
|
next = NULL;
|
|
}
|
|
|
|
QByteArray content;
|
|
QBasicAtomicPointer<QxtFifoNode> next;
|
|
};
|
|
|
|
class QxtFifoPrivate : public QxtPrivate<QxtFifo> {
|
|
public:
|
|
QXT_DECLARE_PUBLIC(QxtFifo)
|
|
QxtFifoPrivate() {
|
|
head = tail = new QxtFifoNode(NULL, 0);
|
|
available = 0;
|
|
}
|
|
|
|
QBasicAtomicPointer<QxtFifoNode> head, tail;
|
|
QBasicAtomicInt available;
|
|
};
|
|
|
|
/*!
|
|
Constructs a new QxtFifo with \a parent.
|
|
*/
|
|
QxtFifo::QxtFifo(QObject *parent) : QIODevice(parent)
|
|
{
|
|
QXT_INIT_PRIVATE(QxtFifo);
|
|
setOpenMode(QIODevice::ReadWrite);
|
|
}
|
|
|
|
/*!
|
|
Constructs a new QxtFifo with \a parent and initial content from \a prime.
|
|
*/
|
|
QxtFifo::QxtFifo(const QByteArray &prime, QObject *parent) : QIODevice(parent)
|
|
{
|
|
QXT_INIT_PRIVATE(QxtFifo);
|
|
setOpenMode(QIODevice::ReadWrite);
|
|
// Since we're being constructed, access to the internals is safe
|
|
qxt_d().head->content = prime;
|
|
qxt_d().available = prime.size();
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
qint64 QxtFifo::readData ( char * data, qint64 maxSize )
|
|
{
|
|
int bytes = qxt_d().available, step;
|
|
if(!bytes) return 0;
|
|
if(bytes > maxSize) bytes = maxSize;
|
|
int written = bytes;
|
|
char* writePos = data;
|
|
QxtFifoNode* node;
|
|
while(bytes > 0) {
|
|
node = qxt_d().head;
|
|
step = node->content.size();
|
|
if(step >= bytes) {
|
|
int rem = step - bytes;
|
|
memcpy(writePos, node->content.constData(), bytes);
|
|
step = bytes;
|
|
node->content = node->content.right(rem);
|
|
} else {
|
|
memcpy(writePos, node->content.constData(), step);
|
|
qxt_d().head.QXT_EXCHANGE(node->next);
|
|
delete node;
|
|
node = qxt_d().head;
|
|
}
|
|
writePos += step;
|
|
bytes -= step;
|
|
}
|
|
qxt_d().available.QXT_ADD(-written);
|
|
return written;
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
qint64 QxtFifo::writeData ( const char * data, qint64 maxSize )
|
|
{
|
|
if(maxSize > 0) {
|
|
if(maxSize > INT_MAX) maxSize = INT_MAX; // qint64 could easily exceed QAtomicInt, so let's play it safe
|
|
QxtFifoNode* newData = new QxtFifoNode(data, maxSize);
|
|
qxt_d().tail->next.QXT_EXCHANGE(newData);
|
|
qxt_d().tail.QXT_EXCHANGE(newData);
|
|
qxt_d().available.QXT_ADD(maxSize);
|
|
QMetaObject::invokeMethod(this, "bytesWritten", Qt::QueuedConnection, Q_ARG(qint64, maxSize));
|
|
QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection);
|
|
}
|
|
return maxSize;
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
bool QxtFifo::isSequential () const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
qint64 QxtFifo::bytesAvailable () const
|
|
{
|
|
return qxt_d().available;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void QxtFifo::clear()
|
|
{
|
|
qxt_d().available.QXT_EXCHANGE(0);
|
|
qxt_d().tail.QXT_EXCHANGE(qxt_d().head);
|
|
QxtFifoNode* node = qxt_d().head->next.QXT_EXCHANGE(NULL);
|
|
while (node && node->next)
|
|
{
|
|
QxtFifoNode* next = node->next.QXT_EXCHANGE(NULL);
|
|
delete node;
|
|
node = next;
|
|
}
|
|
qxt_d().head->content = QByteArray();
|
|
}
|