diff options
author | orivej <orivej@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:49 +0300 |
commit | 718c552901d703c502ccbefdfc3c9028d608b947 (patch) | |
tree | 46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/libs/poco/Foundation/include/Poco/FIFOBuffer.h | |
parent | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff) | |
download | ydb-718c552901d703c502ccbefdfc3c9028d608b947.tar.gz |
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/libs/poco/Foundation/include/Poco/FIFOBuffer.h')
-rw-r--r-- | contrib/libs/poco/Foundation/include/Poco/FIFOBuffer.h | 1102 |
1 files changed, 551 insertions, 551 deletions
diff --git a/contrib/libs/poco/Foundation/include/Poco/FIFOBuffer.h b/contrib/libs/poco/Foundation/include/Poco/FIFOBuffer.h index 8382b753b5..95d27a827b 100644 --- a/contrib/libs/poco/Foundation/include/Poco/FIFOBuffer.h +++ b/contrib/libs/poco/Foundation/include/Poco/FIFOBuffer.h @@ -1,556 +1,556 @@ -// -// FIFOBuffer.h -// -// Library: Foundation -// Package: Core -// Module: FIFOBuffer -// -// Definition of the FIFOBuffer class. -// -// Copyright (c) 2006, Applied Informatics Software Engineering GmbH. -// and Contributors. -// -// SPDX-License-Identifier: BSL-1.0 -// - - -#ifndef Foundation_FIFOBuffer_INCLUDED -#define Foundation_FIFOBuffer_INCLUDED - - -#include "Poco/Foundation.h" -#include "Poco/Exception.h" -#include "Poco/Buffer.h" -#include "Poco/BasicEvent.h" -#include "Poco/Mutex.h" -#include "Poco/Format.h" - - -namespace Poco { - - -template <class T> -class BasicFIFOBuffer - /// A simple buffer class with support for re-entrant, - /// FIFO-style read/write operations, as well as (optional) - /// empty/non-empty/full (i.e. writable/readable) transition - /// notifications. Buffer can be flagged with end-of-file and - /// error flags, which renders it un-readable/writable. - /// - /// Critical portions of code are protected by a recursive mutex. - /// However, to achieve thread-safety in cases where multiple - /// member function calls are involved and have to be atomic, - /// the mutex must be locked externally. +// +// FIFOBuffer.h +// +// Library: Foundation +// Package: Core +// Module: FIFOBuffer +// +// Definition of the FIFOBuffer class. +// +// Copyright (c) 2006, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// SPDX-License-Identifier: BSL-1.0 +// + + +#ifndef Foundation_FIFOBuffer_INCLUDED +#define Foundation_FIFOBuffer_INCLUDED + + +#include "Poco/Foundation.h" +#include "Poco/Exception.h" +#include "Poco/Buffer.h" +#include "Poco/BasicEvent.h" +#include "Poco/Mutex.h" +#include "Poco/Format.h" + + +namespace Poco { + + +template <class T> +class BasicFIFOBuffer + /// A simple buffer class with support for re-entrant, + /// FIFO-style read/write operations, as well as (optional) + /// empty/non-empty/full (i.e. writable/readable) transition + /// notifications. Buffer can be flagged with end-of-file and + /// error flags, which renders it un-readable/writable. /// - /// 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. -{ -public: - typedef T Type; - - mutable Poco::BasicEvent<bool> writable; - /// Event indicating "writability" of the buffer, - /// triggered as follows: - /// - /// * when buffer transitions from non-full to full, - /// Writable event observers are notified, with - /// false value as the argument - /// - /// * when buffer transitions from full to non-full, - /// Writable event observers are notified, with - /// true value as the argument - - mutable Poco::BasicEvent<bool> readable; - /// Event indicating "readability" of the buffer, - /// triggered as follows: - /// - /// * when buffer transitions from non-empty to empty, - /// Readable event observers are notified, with false - /// value as the argument - /// - /// * when FIFOBuffer transitions from empty to non-empty, - /// Readable event observers are notified, with true value - /// as the argument - - BasicFIFOBuffer(std::size_t bufferSize, bool bufferNotify = false): - _buffer(bufferSize), - _begin(0), - _used(0), - _notify(bufferNotify), - _eof(false), - _error(false) - /// Creates the FIFOBuffer. - { - } - - BasicFIFOBuffer(T* pBuffer, std::size_t bufferSize, bool bufferNotify = false): - _buffer(pBuffer, bufferSize), - _begin(0), - _used(0), - _notify(bufferNotify), - _eof(false), - _error(false) - /// Creates the FIFOBuffer. - { - } - - BasicFIFOBuffer(const T* pBuffer, std::size_t bufferSize, bool bufferNotify = false): - _buffer(pBuffer, bufferSize), - _begin(0), - _used(bufferSize), - _notify(bufferNotify), - _eof(false), - _error(false) - /// Creates the FIFOBuffer. - { - } - - ~BasicFIFOBuffer() - /// Destroys the FIFOBuffer. - { - } - - void resize(std::size_t newSize, bool preserveContent = true) - /// Resizes the buffer. If preserveContent is true, - /// the content of the old buffer is preserved. - /// New size can be larger or smaller than - /// the current size, but it must not be 0. - /// Additionally, if the new length is smaller - /// than currently used length and preserveContent - /// is true, InvalidAccessException is thrown. - { - Mutex::ScopedLock lock(_mutex); - - if (preserveContent && (newSize < _used)) - throw InvalidAccessException("Can not resize FIFO without data loss."); - - std::size_t usedBefore = _used; - _buffer.resize(newSize, preserveContent); - if (!preserveContent) _used = 0; - if (_notify) notify(usedBefore); - } - - std::size_t peek(T* pBuffer, std::size_t length) const - /// Peeks into the data currently in the FIFO - /// without actually extracting it. - /// If length is zero, the return is immediate. - /// If length is greater than used length, - /// it is substituted with the the current FIFO - /// used length. - /// - /// Returns the number of elements copied in the - /// supplied buffer. - { - if (0 == length) return 0; - Mutex::ScopedLock lock(_mutex); - if (!isReadable()) return 0; - if (length > _used) length = _used; - std::memcpy(pBuffer, _buffer.begin() + _begin, length * sizeof(T)); - return length; - } - - std::size_t peek(Poco::Buffer<T>& rBuffer, std::size_t length = 0) const - /// Peeks into the data currently in the FIFO - /// without actually extracting it. - /// Resizes the supplied buffer to the size of - /// data written to it. If length is not - /// supplied by the caller or is greater than length - /// of currently used data, the current FIFO used - /// data length is substituted for it. - /// - /// Returns the number of elements copied in the - /// supplied buffer. - { - Mutex::ScopedLock lock(_mutex); - if (!isReadable()) return 0; - if (0 == length || length > _used) length = _used; - rBuffer.resize(length); - return peek(rBuffer.begin(), length); - } - - std::size_t read(T* pBuffer, std::size_t length) - /// Copies the data currently in the FIFO - /// into the supplied buffer, which must be - /// preallocated to at least the length size - /// before calling this function. - /// - /// Returns the size of the copied data. - { - if (0 == length) return 0; - Mutex::ScopedLock lock(_mutex); - if (!isReadable()) return 0; - std::size_t usedBefore = _used; - std::size_t readLen = peek(pBuffer, length); - poco_assert (_used >= readLen); - _used -= readLen; - if (0 == _used) _begin = 0; - else _begin += length; - - if (_notify) notify(usedBefore); - - return readLen; - } - - std::size_t read(Poco::Buffer<T>& rBuffer, std::size_t length = 0) - /// Copies the data currently in the FIFO - /// into the supplied buffer. - /// Resizes the supplied buffer to the size of - /// data written to it. - /// - /// Returns the size of the copied data. - { - Mutex::ScopedLock lock(_mutex); - if (!isReadable()) return 0; - std::size_t usedBefore = _used; - std::size_t readLen = peek(rBuffer, length); - poco_assert (_used >= readLen); - _used -= readLen; - if (0 == _used) _begin = 0; - else _begin += length; - - if (_notify) notify(usedBefore); - - return readLen; - } - - std::size_t write(const T* pBuffer, std::size_t length) - /// 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. Function does nothing and returns zero - /// if length argument is equal to zero. - /// - /// Returns the length of data written. - { - if (0 == length) return 0; - - Mutex::ScopedLock lock(_mutex); - - if (!isWritable()) return 0; - - if (_buffer.size() - (_begin + _used) < length) - { - std::memmove(_buffer.begin(), begin(), _used * sizeof(T)); - _begin = 0; - } - - std::size_t usedBefore = _used; - std::size_t availableBefore = _buffer.size() - _used - _begin; - std::size_t len = length > availableBefore ? availableBefore : length; - std::memcpy(begin() + _used, pBuffer, len * sizeof(T)); - _used += len; - poco_assert (_used <= _buffer.size()); - if (_notify) notify(usedBefore); - - return len; - } - - std::size_t write(const Buffer<T>& rBuffer, 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). + /// Critical portions of code are protected by a recursive mutex. + /// However, to achieve thread-safety in cases where multiple + /// member function calls are involved and have to be atomic, + /// the mutex must be locked externally. + /// + /// 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. +{ +public: + typedef T Type; + + mutable Poco::BasicEvent<bool> writable; + /// Event indicating "writability" of the buffer, + /// triggered as follows: /// - /// Returns the length of data written. - { - if (length == 0 || length > rBuffer.size()) - length = rBuffer.size(); - - return write(rBuffer.begin(), length); - } - - std::size_t size() const - /// Returns the size of the buffer. - { - return _buffer.size(); - } - - std::size_t used() const - /// Returns the size of the used portion of the buffer. - { - return _used; - } - - std::size_t available() const - /// Returns the size of the available portion of the buffer. - { - return 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. - { - Mutex::ScopedLock lock(_mutex); - - std::size_t usedBefore = _used; - - if (0 == length || length >= _used) - { - _begin = 0; - _used = 0; - } - else - { - _begin += length; - _used -= length; - } - - if (_notify) notify(usedBefore); - } - - void copy(const T* ptr, std::size_t length) - /// Copies the supplied data to the buffer and adjusts - /// the used buffer size. - { - poco_check_ptr(ptr); - if (0 == length) return; - - Mutex::ScopedLock lock(_mutex); - - if (length > available()) - throw Poco::InvalidAccessException("Cannot extend buffer."); - - if (!isWritable()) - throw Poco::InvalidAccessException("Buffer not writable."); - - std::memcpy(begin() + _used, ptr, length * sizeof(T)); - std::size_t usedBefore = _used; - _used += length; - if (_notify) notify(usedBefore); - } - - void advance(std::size_t length) - /// Advances buffer by length elements. - /// Should be called AFTER the data - /// was copied into the buffer. - { - Mutex::ScopedLock lock(_mutex); - - if (length > available()) - throw Poco::InvalidAccessException("Cannot extend buffer."); - - if (!isWritable()) - throw Poco::InvalidAccessException("Buffer not writable."); - - if (_buffer.size() - (_begin + _used) < length) - { - std::memmove(_buffer.begin(), begin(), _used * sizeof(T)); - _begin = 0; - } - - std::size_t usedBefore = _used; - _used += length; - if (_notify) notify(usedBefore); - } - - T* begin() - /// Returns the pointer to the beginning of the buffer. - { - Mutex::ScopedLock lock(_mutex); - if (_begin != 0) - { - // Move the data to the start of the buffer so begin() and next() - // always return consistent pointers with each other and allow writing - // to the end of the buffer. - std::memmove(_buffer.begin(), _buffer.begin() + _begin, _used * sizeof(T)); - _begin = 0; - } - return _buffer.begin(); - } - - T* next() - /// Returns the pointer to the next available position in the buffer. - { - Mutex::ScopedLock lock(_mutex); - return begin() + _used; - } - - T& operator [] (std::size_t index) - /// Returns value at index position. - /// Throws InvalidAccessException if index is larger than - /// the last valid (used) buffer position. - { - Mutex::ScopedLock lock(_mutex); - if (index >= _used) - throw InvalidAccessException(format("Index out of bounds: %z (max index allowed: %z)", index, _used - 1)); - - return _buffer[_begin + index]; - } - - const T& operator [] (std::size_t index) const - /// Returns value at index position. - /// Throws InvalidAccessException if index is larger than - /// the last valid (used) buffer position. - { - Mutex::ScopedLock lock(_mutex); - if (index >= _used) - throw InvalidAccessException(format("Index out of bounds: %z (max index allowed: %z)", index, _used - 1)); - - return _buffer[_begin + index]; - } - - const Buffer<T>& buffer() const - /// Returns const reference to the underlying buffer. - { - return _buffer; - } - - void setError(bool error = true) - /// Sets the error flag on the buffer and empties it. - /// If notifications are enabled, they will be triggered - /// if appropriate. + /// * when buffer transitions from non-full to full, + /// Writable event observers are notified, with + /// false value as the argument /// - /// Setting error flag to true prevents reading and writing - /// to the buffer; to re-enable FIFOBuffer for reading/writing, - /// the error flag must be set to false. - { - if (error) - { - bool f = false; - Mutex::ScopedLock lock(_mutex); - if (error && isReadable() && _notify) readable.notify(this, f); - if (error && isWritable() && _notify) writable.notify(this, f); - _error = error; - _used = 0; - } - else - { - bool t = true; - Mutex::ScopedLock lock(_mutex); - _error = false; - if (_notify && !_eof) writable.notify(this, t); - } - } - - bool isValid() const - /// Returns true if error flag is not set on the buffer, - /// otherwise returns false. - { - return !_error; - } - - void setEOF(bool eof = true) - /// Sets end-of-file flag on the buffer. + /// * when buffer transitions from full to non-full, + /// Writable event observers are notified, with + /// true value as the argument + + mutable Poco::BasicEvent<bool> readable; + /// Event indicating "readability" of the buffer, + /// triggered as follows: /// - /// Setting EOF flag to true prevents writing to the - /// buffer; reading from the buffer will still be - /// allowed until all data present in the buffer at the - /// EOF set time is drained. After that, to re-enable - /// FIFOBuffer for reading/writing, EOF must be - /// set to false. + /// * when buffer transitions from non-empty to empty, + /// Readable event observers are notified, with false + /// value as the argument /// - /// Setting EOF flag to false clears EOF state if it - /// was previously set. If EOF was not set, it has no - /// effect. - { - Mutex::ScopedLock lock(_mutex); - bool flag = !eof; - if (_notify) writable.notify(this, flag); - _eof = eof; - } - - bool hasEOF() const - /// Returns true if EOF flag has been set. - { - return _eof; - } - - bool isEOF() const - /// Returns true if EOF flag has been set and buffer is empty. - { - return isEmpty() && _eof; - } - - bool isEmpty() const - /// Returns true is buffer is empty, false otherwise. - { - return 0 == _used; - } - - bool isFull() const - /// Returns true is buffer is full, false otherwise. - { - return size() == _used; - } - - bool isReadable() const - /// Returns true if buffer contains data and is not - /// in error state. - { - return !isEmpty() && isValid(); - } - - bool isWritable() const - /// Returns true if buffer is not full and is not - /// in error state. - { - return !isFull() && isValid() && !_eof; - } - - void setNotify(bool bufferNotify = true) - /// Enables/disables notifications. - { - _notify = bufferNotify; - } - - bool getNotify() const - /// Returns true if notifications are enabled, false otherwise. - { - return _notify; - } - - Mutex& mutex() - /// Returns reference to mutex. - { - return _mutex; - } - -private: - void notify(std::size_t usedBefore) - { - bool t = true, f = false; - if (usedBefore == 0 && _used > 0) - readable.notify(this, t); - else if (usedBefore > 0 && 0 == _used) - readable.notify(this, f); - - if (usedBefore == _buffer.size() && _used < _buffer.size()) - writable.notify(this, t); - else if (usedBefore < _buffer.size() && _used == _buffer.size()) - writable.notify(this, f); - } - - BasicFIFOBuffer(); - BasicFIFOBuffer(const BasicFIFOBuffer&); - BasicFIFOBuffer& operator = (const BasicFIFOBuffer&); - - Buffer<T> _buffer; - std::size_t _begin; - std::size_t _used; - bool _notify; - mutable Mutex _mutex; - bool _eof; - bool _error; -}; - - -// -// We provide an instantiation for char -// -typedef BasicFIFOBuffer<char> FIFOBuffer; - - -} // namespace Poco - - -#endif // Foundation_FIFOBuffer_INCLUDED + /// * when FIFOBuffer transitions from empty to non-empty, + /// Readable event observers are notified, with true value + /// as the argument + + BasicFIFOBuffer(std::size_t bufferSize, bool bufferNotify = false): + _buffer(bufferSize), + _begin(0), + _used(0), + _notify(bufferNotify), + _eof(false), + _error(false) + /// Creates the FIFOBuffer. + { + } + + BasicFIFOBuffer(T* pBuffer, std::size_t bufferSize, bool bufferNotify = false): + _buffer(pBuffer, bufferSize), + _begin(0), + _used(0), + _notify(bufferNotify), + _eof(false), + _error(false) + /// Creates the FIFOBuffer. + { + } + + BasicFIFOBuffer(const T* pBuffer, std::size_t bufferSize, bool bufferNotify = false): + _buffer(pBuffer, bufferSize), + _begin(0), + _used(bufferSize), + _notify(bufferNotify), + _eof(false), + _error(false) + /// Creates the FIFOBuffer. + { + } + + ~BasicFIFOBuffer() + /// Destroys the FIFOBuffer. + { + } + + void resize(std::size_t newSize, bool preserveContent = true) + /// Resizes the buffer. If preserveContent is true, + /// the content of the old buffer is preserved. + /// New size can be larger or smaller than + /// the current size, but it must not be 0. + /// Additionally, if the new length is smaller + /// than currently used length and preserveContent + /// is true, InvalidAccessException is thrown. + { + Mutex::ScopedLock lock(_mutex); + + if (preserveContent && (newSize < _used)) + throw InvalidAccessException("Can not resize FIFO without data loss."); + + std::size_t usedBefore = _used; + _buffer.resize(newSize, preserveContent); + if (!preserveContent) _used = 0; + if (_notify) notify(usedBefore); + } + + std::size_t peek(T* pBuffer, std::size_t length) const + /// Peeks into the data currently in the FIFO + /// without actually extracting it. + /// If length is zero, the return is immediate. + /// If length is greater than used length, + /// it is substituted with the the current FIFO + /// used length. + /// + /// Returns the number of elements copied in the + /// supplied buffer. + { + if (0 == length) return 0; + Mutex::ScopedLock lock(_mutex); + if (!isReadable()) return 0; + if (length > _used) length = _used; + std::memcpy(pBuffer, _buffer.begin() + _begin, length * sizeof(T)); + return length; + } + + std::size_t peek(Poco::Buffer<T>& rBuffer, std::size_t length = 0) const + /// Peeks into the data currently in the FIFO + /// without actually extracting it. + /// Resizes the supplied buffer to the size of + /// data written to it. If length is not + /// supplied by the caller or is greater than length + /// of currently used data, the current FIFO used + /// data length is substituted for it. + /// + /// Returns the number of elements copied in the + /// supplied buffer. + { + Mutex::ScopedLock lock(_mutex); + if (!isReadable()) return 0; + if (0 == length || length > _used) length = _used; + rBuffer.resize(length); + return peek(rBuffer.begin(), length); + } + + std::size_t read(T* pBuffer, std::size_t length) + /// Copies the data currently in the FIFO + /// into the supplied buffer, which must be + /// preallocated to at least the length size + /// before calling this function. + /// + /// Returns the size of the copied data. + { + if (0 == length) return 0; + Mutex::ScopedLock lock(_mutex); + if (!isReadable()) return 0; + std::size_t usedBefore = _used; + std::size_t readLen = peek(pBuffer, length); + poco_assert (_used >= readLen); + _used -= readLen; + if (0 == _used) _begin = 0; + else _begin += length; + + if (_notify) notify(usedBefore); + + return readLen; + } + + std::size_t read(Poco::Buffer<T>& rBuffer, std::size_t length = 0) + /// Copies the data currently in the FIFO + /// into the supplied buffer. + /// Resizes the supplied buffer to the size of + /// data written to it. + /// + /// Returns the size of the copied data. + { + Mutex::ScopedLock lock(_mutex); + if (!isReadable()) return 0; + std::size_t usedBefore = _used; + std::size_t readLen = peek(rBuffer, length); + poco_assert (_used >= readLen); + _used -= readLen; + if (0 == _used) _begin = 0; + else _begin += length; + + if (_notify) notify(usedBefore); + + return readLen; + } + + std::size_t write(const T* pBuffer, std::size_t length) + /// 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. Function does nothing and returns zero + /// if length argument is equal to zero. + /// + /// Returns the length of data written. + { + if (0 == length) return 0; + + Mutex::ScopedLock lock(_mutex); + + if (!isWritable()) return 0; + + if (_buffer.size() - (_begin + _used) < length) + { + std::memmove(_buffer.begin(), begin(), _used * sizeof(T)); + _begin = 0; + } + + std::size_t usedBefore = _used; + std::size_t availableBefore = _buffer.size() - _used - _begin; + std::size_t len = length > availableBefore ? availableBefore : length; + std::memcpy(begin() + _used, pBuffer, len * sizeof(T)); + _used += len; + poco_assert (_used <= _buffer.size()); + if (_notify) notify(usedBefore); + + return len; + } + + std::size_t write(const Buffer<T>& rBuffer, 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. + { + if (length == 0 || length > rBuffer.size()) + length = rBuffer.size(); + + return write(rBuffer.begin(), length); + } + + std::size_t size() const + /// Returns the size of the buffer. + { + return _buffer.size(); + } + + std::size_t used() const + /// Returns the size of the used portion of the buffer. + { + return _used; + } + + std::size_t available() const + /// Returns the size of the available portion of the buffer. + { + return 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. + { + Mutex::ScopedLock lock(_mutex); + + std::size_t usedBefore = _used; + + if (0 == length || length >= _used) + { + _begin = 0; + _used = 0; + } + else + { + _begin += length; + _used -= length; + } + + if (_notify) notify(usedBefore); + } + + void copy(const T* ptr, std::size_t length) + /// Copies the supplied data to the buffer and adjusts + /// the used buffer size. + { + poco_check_ptr(ptr); + if (0 == length) return; + + Mutex::ScopedLock lock(_mutex); + + if (length > available()) + throw Poco::InvalidAccessException("Cannot extend buffer."); + + if (!isWritable()) + throw Poco::InvalidAccessException("Buffer not writable."); + + std::memcpy(begin() + _used, ptr, length * sizeof(T)); + std::size_t usedBefore = _used; + _used += length; + if (_notify) notify(usedBefore); + } + + void advance(std::size_t length) + /// Advances buffer by length elements. + /// Should be called AFTER the data + /// was copied into the buffer. + { + Mutex::ScopedLock lock(_mutex); + + if (length > available()) + throw Poco::InvalidAccessException("Cannot extend buffer."); + + if (!isWritable()) + throw Poco::InvalidAccessException("Buffer not writable."); + + if (_buffer.size() - (_begin + _used) < length) + { + std::memmove(_buffer.begin(), begin(), _used * sizeof(T)); + _begin = 0; + } + + std::size_t usedBefore = _used; + _used += length; + if (_notify) notify(usedBefore); + } + + T* begin() + /// Returns the pointer to the beginning of the buffer. + { + Mutex::ScopedLock lock(_mutex); + if (_begin != 0) + { + // Move the data to the start of the buffer so begin() and next() + // always return consistent pointers with each other and allow writing + // to the end of the buffer. + std::memmove(_buffer.begin(), _buffer.begin() + _begin, _used * sizeof(T)); + _begin = 0; + } + return _buffer.begin(); + } + + T* next() + /// Returns the pointer to the next available position in the buffer. + { + Mutex::ScopedLock lock(_mutex); + return begin() + _used; + } + + T& operator [] (std::size_t index) + /// Returns value at index position. + /// Throws InvalidAccessException if index is larger than + /// the last valid (used) buffer position. + { + Mutex::ScopedLock lock(_mutex); + if (index >= _used) + throw InvalidAccessException(format("Index out of bounds: %z (max index allowed: %z)", index, _used - 1)); + + return _buffer[_begin + index]; + } + + const T& operator [] (std::size_t index) const + /// Returns value at index position. + /// Throws InvalidAccessException if index is larger than + /// the last valid (used) buffer position. + { + Mutex::ScopedLock lock(_mutex); + if (index >= _used) + throw InvalidAccessException(format("Index out of bounds: %z (max index allowed: %z)", index, _used - 1)); + + return _buffer[_begin + index]; + } + + const Buffer<T>& buffer() const + /// Returns const reference to the underlying buffer. + { + return _buffer; + } + + void setError(bool error = true) + /// Sets the error flag on the buffer and empties it. + /// If notifications are enabled, they will be triggered + /// if appropriate. + /// + /// Setting error flag to true prevents reading and writing + /// to the buffer; to re-enable FIFOBuffer for reading/writing, + /// the error flag must be set to false. + { + if (error) + { + bool f = false; + Mutex::ScopedLock lock(_mutex); + if (error && isReadable() && _notify) readable.notify(this, f); + if (error && isWritable() && _notify) writable.notify(this, f); + _error = error; + _used = 0; + } + else + { + bool t = true; + Mutex::ScopedLock lock(_mutex); + _error = false; + if (_notify && !_eof) writable.notify(this, t); + } + } + + bool isValid() const + /// Returns true if error flag is not set on the buffer, + /// otherwise returns false. + { + return !_error; + } + + void setEOF(bool eof = true) + /// Sets end-of-file flag on the buffer. + /// + /// Setting EOF flag to true prevents writing to the + /// buffer; reading from the buffer will still be + /// allowed until all data present in the buffer at the + /// EOF set time is drained. After that, to re-enable + /// FIFOBuffer for reading/writing, EOF must be + /// set to false. + /// + /// Setting EOF flag to false clears EOF state if it + /// was previously set. If EOF was not set, it has no + /// effect. + { + Mutex::ScopedLock lock(_mutex); + bool flag = !eof; + if (_notify) writable.notify(this, flag); + _eof = eof; + } + + bool hasEOF() const + /// Returns true if EOF flag has been set. + { + return _eof; + } + + bool isEOF() const + /// Returns true if EOF flag has been set and buffer is empty. + { + return isEmpty() && _eof; + } + + bool isEmpty() const + /// Returns true is buffer is empty, false otherwise. + { + return 0 == _used; + } + + bool isFull() const + /// Returns true is buffer is full, false otherwise. + { + return size() == _used; + } + + bool isReadable() const + /// Returns true if buffer contains data and is not + /// in error state. + { + return !isEmpty() && isValid(); + } + + bool isWritable() const + /// Returns true if buffer is not full and is not + /// in error state. + { + return !isFull() && isValid() && !_eof; + } + + void setNotify(bool bufferNotify = true) + /// Enables/disables notifications. + { + _notify = bufferNotify; + } + + bool getNotify() const + /// Returns true if notifications are enabled, false otherwise. + { + return _notify; + } + + Mutex& mutex() + /// Returns reference to mutex. + { + return _mutex; + } + +private: + void notify(std::size_t usedBefore) + { + bool t = true, f = false; + if (usedBefore == 0 && _used > 0) + readable.notify(this, t); + else if (usedBefore > 0 && 0 == _used) + readable.notify(this, f); + + if (usedBefore == _buffer.size() && _used < _buffer.size()) + writable.notify(this, t); + else if (usedBefore < _buffer.size() && _used == _buffer.size()) + writable.notify(this, f); + } + + BasicFIFOBuffer(); + BasicFIFOBuffer(const BasicFIFOBuffer&); + BasicFIFOBuffer& operator = (const BasicFIFOBuffer&); + + Buffer<T> _buffer; + std::size_t _begin; + std::size_t _used; + bool _notify; + mutable Mutex _mutex; + bool _eof; + bool _error; +}; + + +// +// We provide an instantiation for char +// +typedef BasicFIFOBuffer<char> FIFOBuffer; + + +} // namespace Poco + + +#endif // Foundation_FIFOBuffer_INCLUDED |