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

View File

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

View File

@@ -406,6 +406,83 @@ void CoreTest::testFIFOBufferChar()
assert(1 == _writableToNot); assert(1 == _writableToNot);
assert (f.isEmpty()); 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.Readable -= delegate(this, &CoreTest::onReadable);
f.Writable -= delegate(this, &CoreTest::onReadable); f.Writable -= delegate(this, &CoreTest::onReadable);
} }