FIFOBuffer::drain() and partial write

This commit is contained in:
Aleksandar Fabijanic
2012-04-29 18:09:43 +00:00
parent c33bf13bdc
commit 056cbeb744
3 changed files with 121 additions and 15 deletions

View File

@@ -58,10 +58,10 @@ class Buffer
/// is needed.
{
public:
Buffer(std::size_t size):
_capacity(size),
_used(size),
_ptr(new T[size])
Buffer(std::size_t capacity):
_capacity(capacity),
_used(capacity),
_ptr(new T[capacity])
/// Creates and allocates the Buffer.
{
}
@@ -75,8 +75,8 @@ public:
void resize(std::size_t newCapacity, bool preserveContent = true)
/// Resizes the buffer. If preserveContent is true,
/// the content of the old buffer is copied over to the
/// new buffer. NewSize can be larger or smaller than
/// the current size, but it must not be 0.
/// new buffer. The new capacity can be larger or smaller than
/// the current one, but it must not be 0.
{
poco_assert(newCapacity);

View File

@@ -54,10 +54,10 @@ namespace Poco {
template <class T>
class BasicFIFOBuffer
/// A simple buffer class with support for re-entrant,
/// FIFO-style read/write operations. as well as
/// empty/full transition notifications. Buffer size
/// introspection as well as amount of unread data and
/// available space are supported as well.
/// FIFO-style read/write operations, as well as (optional)
/// empty/non-empty/full (i.e. writable/readable) transition
/// notifications. Buffer size, as well as amount of unread data
/// and available space introspections are supported as well.
///
/// This class is useful anywhere where a FIFO functionality
/// is needed.
@@ -167,17 +167,22 @@ public:
return readLen;
}
std::size_t write(const Buffer<T>& buffer)
/// Writes data.size() to the FIFO buffer.
std::size_t write(const Buffer<T>& buffer, std::size_t length = 0)
/// Writes data from supplied buffer to the FIFO buffer.
/// If there is no sufficient space for the whole
/// buffer to be written, data up to available
/// length is written.
/// The length of data to be written is determined from the
/// length argument or buffer size (when length argument is
/// default zero or greater than buffer size).
///
/// Returns the length of data written.
{
Mutex::ScopedLock lock(_mutex);
if (_buffer.size() - (_begin + _used) < buffer.size())
if (0 == length || length > buffer.size()) length = buffer.size();
if (_buffer.size() - (_begin + _used) < length)
{
std::memmove(_buffer.begin(), _buffer.begin() + _begin, _used);
_begin = 0;
@@ -185,7 +190,7 @@ public:
std::size_t usedBefore = _used;
std::size_t available = _buffer.size() - _used - _begin;
std::size_t len = buffer.size() > available ? available : buffer.size();
std::size_t len = length > available ? available : length;
std::memcpy(_buffer.begin() + _begin + _used, buffer.begin(), len * sizeof(T));
_used += len;
poco_assert (_used <= _buffer.size());
@@ -212,6 +217,24 @@ public:
return _buffer.size() - _used;
}
void drain(std::size_t length = 0)
/// Drains length number of elements from the buffer.
/// If length is zero or greater than buffer current
/// content length, buffer is emptied.
{
std::size_t usedBefore = _used;
if (0 == length || length >= _used)
{
_begin = 0;
_used = 0;
}
else
_used -= length;
if (_notify) notify(usedBefore);
}
T& operator [] (std::size_t index)
/// Returns value at index position.
/// Throws InvalidAccessException if index is larger than
@@ -234,6 +257,12 @@ public:
return _buffer[_begin + index];
}
const Buffer<T>& buffer() const
/// Returns const reference to the underlying buffer.
{
return _buffer;
}
bool isEmpty() const
/// Returns true is buffer is empty, flase otherwise.
{

View File

@@ -406,6 +406,83 @@ void CoreTest::testFIFOBufferChar()
assert(1 == _writableToNot);
assert (f.isEmpty());
f.resize(10);
assert (10 == f.size());
assert (0 == f.used());
assert (10 == f.available());
assert (f.isEmpty());
assert(3 == _notToReadable);
assert(3 == _readableToNot);
assert(1 == _notToWritable);
assert(1 == _writableToNot);
f.write(b);
assert(4 == _notToReadable);
assert(3 == _readableToNot);
assert(1 == _notToWritable);
assert(1 == _writableToNot);
assert (10 == f.size());
assert (3 == f.used());
assert (7 == f.available());
assert (!f.isEmpty());
f.drain(1);
assert(4 == _notToReadable);
assert(3 == _readableToNot);
assert(1 == _notToWritable);
assert(1 == _writableToNot);
assert (10 == f.size());
assert (2 == f.used());
assert (8 == f.available());
assert (!f.isEmpty());
f.drain(2);
assert(4 == _notToReadable);
assert(4 == _readableToNot);
assert(1 == _notToWritable);
assert(1 == _writableToNot);
assert (10 == f.size());
assert (0 == f.used());
assert (10 == f.available());
assert (f.isEmpty());
f.write(b);
assert(5 == _notToReadable);
assert(4 == _readableToNot);
assert(1 == _notToWritable);
assert(1 == _writableToNot);
assert (10 == f.size());
assert (3 == f.used());
assert (7 == f.available());
assert (!f.isEmpty());
f.drain();
assert(5 == _notToReadable);
assert(5 == _readableToNot);
assert(1 == _notToWritable);
assert(1 == _writableToNot);
assert (10 == f.size());
assert (0 == f.used());
assert (10 == f.available());
assert (f.isEmpty());
f.write(b, 2);
assert (10 == f.size());
assert (2 == f.used());
assert (8 == f.available());
assert (!f.isEmpty());
f.drain();
assert (3 == f.write(b, 10));
assert (10 == f.size());
assert (3 == f.used());
assert (7 == f.available());
assert (!f.isEmpty());
f.Readable -= delegate(this, &CoreTest::onReadable);
f.Writable -= delegate(this, &CoreTest::onReadable);
}