xentara-utils v2.0.4
The Xentara Utility Library
|
Base class for all output devices. More...
#include <xentara/utils/io/OutputDevice.hpp>
Public Member Functions | |
virtual | ~OutputDevice () noexcept(false)=0 |
Virtual, throwing destructor. | |
Write Functions | |
template<std::ranges::contiguous_range Data> requires std::same_as<std::remove_cv_t<std::ranges::range_value_t<Data>>, std::byte> | |
auto | write (const Data &data) -> void |
Writes a block of data. | |
auto | writeByte (std::byte byte) -> void |
Write a single byte. | |
template<std::ranges::contiguous_range Data> requires std::same_as<std::remove_cv_t<std::ranges::range_value_t<Data>>, std::byte> | |
auto | writeChunk (const Data &data) -> std::ranges::range_size_t< Data > |
Writes a single chunk of data contained in an iterator range. | |
template<std::ranges::contiguous_range Data> requires std::same_as<std::remove_cv_t<std::ranges::range_value_t<Data>>, std::byte> | |
auto | tryWrite (const Data &data) -> std::ranges::range_size_t< Data > |
Write as much of a data block as is possible without blocking. | |
auto | tryWriteByte (std::byte byte) -> bool |
Write a single byte, if this can be done without blocking. | |
Iterator Based Write Functions | |
template<std::contiguous_iterator Iterator, std::sized_sentinel_for< Iterator > Sentinel> requires std::same_as<std::remove_cv_t<std::iter_value_t<Iterator>>, std::byte> | |
auto | write (Iterator first, Sentinel last) -> void |
Writes the data contained in an iterator range. | |
template<std::contiguous_iterator Iterator, std::sized_sentinel_for< Iterator > Sentinel> requires std::same_as<std::remove_cv_t<std::iter_value_t<Iterator>>, std::byte> | |
auto | writeChunk (Iterator first, Sentinel last) -> Iterator |
Writes a single chunk of data from an an iterator range. | |
template<std::contiguous_iterator Iterator, std::sized_sentinel_for< Iterator > Sentinel> requires std::same_as<std::iter_value_t<Iterator>, std::byte> | |
auto | tryWrite (Iterator first, Sentinel last) -> Iterator |
Write as much of the data contained in an iterator range as is possible without blocking. | |
Low Level Write Functions | |
auto | write (const std::byte *data, std::size_t size) -> void |
Write a block of data. | |
auto | writeChunk (const std::byte *data, std::size_t size) -> std::size_t |
Writes a single chunk of data. | |
auto | tryWrite (const std::byte *data, std::size_t size) -> std::size_t |
Write as much of a data block as is possible without blocking. | |
Accessing the Write Position | |
auto | writePosition () const -> std::optional< std::size_t > |
Gets the current write position within the device. | |
auto | setWritePosition (std::size_t position) -> std::optional< std::size_t > |
Sets the current write position within the device. | |
auto | moveWritePosition (std::ptrdiff_t offset, std::ios_base::seekdir origin=std::ios_base::cur) -> std::optional< std::size_t > |
Advances or retreats the current write position within the device. | |
Waiting to Write Data | |
auto | waitUntilWritable (std::chrono::nanoseconds timeout) -> bool |
Waits for the device to be able to accept more write data within a certain time. | |
auto | writeTimeout () const noexcept -> std::chrono::nanoseconds |
Returns the write timeout for communication devices. | |
Public Member Functions inherited from xentara::utils::io::DeviceBase | |
virtual | ~DeviceBase () noexcept(false)=0 |
Virtual, throwing destructor. | |
auto | deviceDescription () const -> std::string |
Get a description of the device. | |
Protected Member Functions | |
virtual auto | doWrite (const std::byte *data, std::size_t size) -> std::size_t=0 |
Called by the framework to write data up to a maximum size. | |
virtual auto | doWaitUntilWritable (std::optional< std::chrono::nanoseconds > timeout) -> bool |
Called by the framework to wait for the device to be able to accept more write data with an optional timeout. | |
virtual auto | doWaitUntilWritableAndWrite (const std::byte *data, std::size_t size, std::chrono::nanoseconds timeout) -> std::size_t |
Called by the framework to wait for the device to be able to accept more write data, and then write to it. | |
virtual auto | doGetWriteTimeout () const noexcept -> std::chrono::nanoseconds |
Called by the framework to get the write timeout. | |
virtual auto | doGetWritePosition () const -> std::optional< std::size_t > |
Called by the framework to get the current write position within the device. | |
virtual auto | doSetWritePosition (std::size_t position) -> std::optional< std::size_t > |
Called by the framework to set the current write position within the device. | |
virtual auto | doMoveWritePosition (std::ptrdiff_t offset, std::ios_base::seekdir origin=std::ios_base::cur) -> std::optional< std::size_t > |
Called by the framework to advance or retreat the current write position within the device. | |
Protected Member Functions inherited from xentara::utils::io::DeviceBase | |
virtual auto | doGetDeviceDescription () const -> std::string=0 |
Called by the framework to get a description of the device. | |
Base class for all output devices.
|
pure virtual |
Virtual, throwing destructor.
|
protectedvirtual |
Called by the framework to get the current write position within the device.
The default implementation returns std::nullopt
std::runtime_error | The functionality is supported in principal, but an error occurred |
|
protectedvirtualnoexcept |
Called by the framework to get the write timeout.
The write timeout is the maximum time allowed between chunks of data before write() or writeByte() throw an exception of type WriteTimeoutError.
|
protectedvirtual |
Called by the framework to advance or retreat the current write position within the device.
The default implementation returns std::nullopt
offset | The desired offset for write position. This offset may put the position past the end of the device, or before the beginning of the device, in which case the position must be set to the end or beginning of the device, respectively. |
origin | The origin for the move. |
std::nullopt
if the device does not support the functionality. std::runtime_error | The functionality is supported in principal, but an error occurred |
|
protectedvirtual |
Called by the framework to set the current write position within the device.
The default implementation calls doMoveWritePosition() with origin std::ios_base::cur
position | The desired new write position. This may lie past the end of the device, in which case the position must be set to the end of the device. |
std::nullopt
if the device does not support the functionality. std::runtime_error | The functionality is supported in principal, but an error occurred |
|
protectedvirtual |
Called by the framework to wait for the device to be able to accept more write data with an optional timeout.
This function must wait for the device to enter a state where the next call to doWrite() will not return std::nullopt, but either return an actual size, or throw an exception.
This function is usually only overridden for communication devices, which will wait for the device to go into a writable state or into an error state.
timeout | The number of nanoseconds to wait, or std::nullopt to wait indefinitely. If a timeout of 0 is passed, the function should not wait, but simply return whether the device can be written without blocking or not. The framework will never pass a negative value. |
StopRequested | Implementations that use a stop source should throw this exception if the stop source was triggered. |
std::runtime_error | This exception, or an appropriate subclass, must be thrown if an error occurs waiting for the data. Throwing an exception on error is optional if a subsequent call to doWrite() will itself throw a suitable exception. Throwing an error is only required if doWaitUntilWritable() failed, but a subsequent call to doWrite() might still succeed. If this function uses the Linux poll(2) command, for example, and poll(2) sets the POLLERR flag in revents, you can just return true instead of throwing an exception, because a subsequent call to send(2) is guaranteed to fail. If poll(2) return -1, however, you must throw an exception, because a subsequent call to send(2) might still be successful. |
|
protectedvirtual |
Called by the framework to wait for the device to be able to accept more write data, and then write to it.
This function enables subclasses to optimize the case where the framework wants to wait for the device to become writable with a certain timeout, and then immediately write some data.
On most platforms, waiting for writability is accomplished by first attempting to do a non-blocking write to write any data that can be written immediately. If the write returns a special status to indicate that the operation would need to block, a wait function is called, and the write is repeated. On Posix platforms, for example, send() can be used to write data to a socket. If send() returns -1 with errno set to EAGAIN or EWOULDBLOCK, then poll() or select() is called to wait for the device to become writable, and the call to send() is repeated. The default implementation of doWaitUntilWritableAndWrite() uses exactly this strategy, calling doWrite() and doWaitUntilWritable() to do the writing and waiting, respectively.
On some platforms, however, different strategies are used. On Windows, for example, writing with a timeout is accomplished using overlapped I/O. Here, the write function returns FALSE with the last error set to ERROR_IO_PENDING if no buffer space is immediately available. In that case, WaitForSingleObject() is called to wait for the device to become writable, and GetOverlappedResult() to complete the write. Unlike Posix, the write function itself is never called a second time. In order to efficiently use overlapped I/O, doWaitUntilWritableAndWrite() must be overwritten to implement this strategy.
If you reimplement this function, it must be functionally equivalent to the following:
data | A pointer to the data that needs to be written |
size | The size of the data. The framework will never pass 0 for this parameter. Please note that this value may be greater than the maximum written size of the operating system (SSIZE_MAX on Posix, maximum DWORD value on Windows). Care must be taken to account for this in the implementation. |
timeout | The number of nanoseconds to wait. The framework will never always pass a positive value for the timeout. timeout will never be 0 or negative. |
std::runtime_error | This exception or an appropriate subclass must be thrown if an error occurs. If the error is caused by the connection being closed on a communication device, the exception thrown should also be derived from ConnectionClosed, e.g. by using throwWithConnectionClosed(). |
|
protectedpure virtual |
Called by the framework to write data up to a maximum size.
This function must write as much of the data as is possible without waiting, up to the size specified.
data | A pointer to the data that needs to be written |
size | The size of the data. The framework will never pass 0 for this parameter. Please note that this value may be greater than the maximum written size of the operating system (SSIZE_MAX on Posix, maximum DWORD value on Windows). Care must be taken to account for this in the implementation. |
std::runtime_error | This exception or an appropriate subclass must be thrown if an error occurs. If the error is caused by the connection being closed on a communication device, the exception thrown should also be derived from ConnectionClosed, e.g. by using throwWithConnectionClosed(). |
auto xentara::utils::io::OutputDevice::moveWritePosition | ( | std::ptrdiff_t | offset, |
std::ios_base::seekdir | origin = std::ios_base::cur |
||
) | -> std::optional< std::size_t > |
Advances or retreats the current write position within the device.
This function will not move the write position beyond the boundaries of the device's data.
offset | The desired offset for the write position |
origin | The origin for the move |
std::runtime_error | Moving the write position as indicated is supported in principal, but an error occurred |
auto xentara::utils::io::OutputDevice::setWritePosition | ( | std::size_t | position | ) | -> std::optional< std::size_t > |
Sets the current write position within the device.
This function will adjust the write position if it lies outside the device's data.
std::runtime_error | Setting the write position is supported in principal, but an error occurred |
auto xentara::utils::io::OutputDevice::tryWrite | ( | const Data & | data | ) | -> std::ranges::range_size_t<Data> |
Write as much of a data block as is possible without blocking.
Writes as much data from a data block to the device as possible without blocking. The function will not block to wait until the device becomes writable. To wait until data can be written, use waitUntilWritable().
data | The data to write |
std::runtime_error | An error occurred writing the data. |
ConnectionClosed | On communication devices, errors thrown because the connection was closed are derived from ConnectionClosed in addition to std::runtime_error. This allows you to handle closed connections during read and write operations in the same catch block by catching exceptions of type ConnectionClosed. |
auto xentara::utils::io::OutputDevice::tryWrite | ( | const std::byte * | data, |
std::size_t | size | ||
) | -> std::size_t |
Write as much of a data block as is possible without blocking.
Writes as much data from a data block to the device as possible without blocking. The function will not block to wait until the device becomes writable. To wait until data can be written, use waitUntilWritable().
data | The address of the data block |
size | The size of the data block |
std::runtime_error | An error occurred writing the data. |
ConnectionClosed | On communication devices, errors thrown because the connection was closed are derived from ConnectionClosed in addition to std::runtime_error. This allows you to handle closed connections during read and write operations in the same catch block by catching exceptions of type ConnectionClosed. |
auto xentara::utils::io::OutputDevice::tryWrite | ( | Iterator | first, |
Sentinel | last | ||
) | -> Iterator |
Write as much of the data contained in an iterator range as is possible without blocking.
Writes as much data from an iterator range to the device as possible without blocking. The function will not block to wait until the device becomes writable. To wait until data can be written, use waitUntilWritable().
first | The beginning of the range |
last | The postion after the end of the range |
std::runtime_error | An error occurred writing the data. |
ConnectionClosed | On communication devices, errors thrown because the connection was closed are derived from ConnectionClosed in addition to std::runtime_error. This allows you to handle closed connections during read and write operations in the same catch block by catching exceptions of type ConnectionClosed. |
auto xentara::utils::io::OutputDevice::tryWriteByte | ( | std::byte | byte | ) | -> bool |
Write a single byte, if this can be done without blocking.
Tries to writes a single byte to the device. The function will not block to wait until the device becomes writable. To wait until data can be written, use waitUntilWritable().
byte | The byte to write. |
std::runtime_error | An error occurred writing the data. |
ConnectionClosed | On communication devices, errors thrown because the connection was closed are derived from ConnectionClosed in addition to std::runtime_error. This allows you to handle closed connections during read and write operations in the same catch block by catching exceptions of type ConnectionClosed. |
auto xentara::utils::io::OutputDevice::waitUntilWritable | ( | std::chrono::nanoseconds | timeout | ) | -> bool |
Waits for the device to be able to accept more write data within a certain time.
On communication devices, this function waits until the device is in a state where the next write operation will not block, and return true if that state was reached before the timeout elapsed.
On non-communication devices, this function always returns true immediately.
timeout | The number of nanoseconds to wait. If you pass 0 or a negative value to this function, it will not wait, but simply return whether the device can be written without blocking or not. |
StopRequested | The device is a communication device that uses a stop source, and that stop source was triggered. |
std::runtime_error | An error occurred accessing the device. |
auto xentara::utils::io::OutputDevice::write | ( | const Data & | data | ) | -> void |
Writes a block of data.
On communication devices, this function will allow short delays (of up to the time returned by writeTimeout()) when sending the data. This ensures that data will still be sent correctly, even if network packets get delayed, or if the receiver is slow. The function will not block for long periods of time, however.
data | The data to write |
WriteTimeoutError | This exception is thrown on communication devices if the send buffer is full and the data takes too long to be sent. This can mean that there is a network congestion, that the receiver is too slow, or that the receiver is not reading the data at all. |
StopRequested | This exception is thrown on communication devices that use a stop source if the stop source was triggered while waiting for the device to become writable. |
std::runtime_error | An error occurred writing the data. |
ConnectionClosed | On communication devices, errors thrown because the connection was closed are derived from ConnectionClosed in addition to std::runtime_error. This allows you to handle closed connections during read and write operations in the same catch block by catching exceptions of type ConnectionClosed. |
auto xentara::utils::io::OutputDevice::write | ( | const std::byte * | data, |
std::size_t | size | ||
) | -> void |
Write a block of data.
On communication devices, this function will allow short delays (of up to the time returned by writeTimeout()) when sending the data. This ensures that data will still be sent correctly, even if network packets get delayed, or if the receiver is slow. The function will not block for long periods of time, however.
data | The address of the data block |
size | The size of the data block long to send all the data |
WriteTimeoutError | This exception is thrown on communication devices if the send buffer is full and the data takes too long to be sent. This can mean that there is a network congestion, that the receiver is too slow, or that the receiver is not reading the data at all. |
StopRequested | This exception is thrown on communication devices that use a stop source if the stop source was triggered while waiting for the device to become writable. |
std::runtime_error | An error occurred writing the data. |
ConnectionClosed | On communication devices, errors thrown because the connection was closed are derived from ConnectionClosed in addition to std::runtime_error. This allows you to handle closed connections during read and write operations in the same catch block by catching exceptions of type ConnectionClosed. |
auto xentara::utils::io::OutputDevice::write | ( | Iterator | first, |
Sentinel | last | ||
) | -> void |
Writes the data contained in an iterator range.
On communication devices, this function will allow short delays (of up to the time returned by writeTimeout()) when sending the data. This ensures that data will still be sent correctly, even if network packets get delayed, or if the receiver is slow. The function will not block for long periods of time, however.
first | The beginning of the range |
last | The postion after the end of the range |
WriteTimeoutError | This exception is thrown on communication devices if the send buffer is full and the data takes too long to be sent. This can mean that there is a network congestion, that the receiver is too slow, or that the receiver is not reading the data at all. |
StopRequested | This exception is thrown on communication devices that use a stop source if the stop source was triggered while waiting for the device to become writable. |
std::runtime_error | An error occurred writing the data. |
ConnectionClosed | On communication devices, errors thrown because the connection was closed are derived from ConnectionClosed in addition to std::runtime_error. This allows you to handle closed connections during read and write operations in the same catch block by catching exceptions of type ConnectionClosed. |
auto xentara::utils::io::OutputDevice::writeByte | ( | std::byte | byte | ) | -> void |
Write a single byte.
On communication devices, this function will allow a short delay (of up to the time returned by writeTimeout()) when sending the byte. This ensures that the byte will still be sent correctly, even if network packets get delayed, or if the receiver is slow. The function will not block for long periods of time, however.
byte | The byte to write. |
WriteTimeoutError | This exception is thrown on communication devices if the send buffer is full and the data takes too long to be sent. This can mean that there is a network congestion, that the receiver is too slow, or that the receiver is not reading the data at all. |
StopRequested | This exception is thrown on communication devices that use a stop source if the stop source was triggered while waiting for the device to become writable. |
std::runtime_error | An error occurred writing the data. |
ConnectionClosed | On communication devices, errors thrown because the connection was closed are derived from ConnectionClosed in addition to std::runtime_error. This allows you to handle closed connections during read and write operations in the same catch block by catching exceptions of type ConnectionClosed. |
auto xentara::utils::io::OutputDevice::writeChunk | ( | const Data & | data | ) | -> std::ranges::range_size_t<Data> |
Writes a single chunk of data contained in an iterator range.
This function is intended to be called in a loop to write data to a device. It will write a chunk of data on each call.
On non-communication devices, this function is equivalant to tryWrite(). It will write some or all of the data in the block, at the discression of the operating system.
On communication devices, this function will try to wait for the device to become writable if no data can be written immediately. If the device cannot accept data after a certain time (the time returned by writeTimeout()), an exception is thrown.
data | The data to write |
WriteTimeoutError | No data could be written before the write timeout on a communication device. On non-communication devices, this exception is never thrown. |
std::runtime_error | An error occurred writing the data. |
StopRequested | This exception is thrown on communication devices that use a stop source if the stop source was triggered while waiting for the device to become writable. |
ConnectionClosed | On communication devices, errors thrown because the connection was closed are derived from ConnectionClosed in addition to std::runtime_error. This allows you to handle closed connections during read and write operations in the same catch block by catching exceptions of type ConnectionClosed. |
auto xentara::utils::io::OutputDevice::writeChunk | ( | const std::byte * | data, |
std::size_t | size | ||
) | -> std::size_t |
Writes a single chunk of data.
This function is intended to be called in a loop to write data to a device. It will write a chunk of data on each call.
On non-communication devices, this function is equivalant to tryWrite(). It will write some or all of the data in the block, at the discression of the operating system.
On communication devices, this function will try to wait for the device to become writable if no data can be written immediately. If the device cannot accept data after a certain time (the time returned by writeTimeout()), an exception is thrown.
data | The address of the data block |
size | The size of the data block |
WriteTimeoutError | No data could be written before the write timeout on a communication device. On non-communication devices, this exception is never thrown. |
StopRequested | This exception is thrown on communication devices that use a stop source if the stop source was triggered while waiting for the device to become writable. |
std::runtime_error | An error occurred writing the data. |
ConnectionClosed | On communication devices, errors thrown because the connection was closed are derived from ConnectionClosed in addition to std::runtime_error. This allows you to handle closed connections during read and write operations in the same catch block by catching exceptions of type ConnectionClosed. |
auto xentara::utils::io::OutputDevice::writeChunk | ( | Iterator | first, |
Sentinel | last | ||
) | -> Iterator |
Writes a single chunk of data from an an iterator range.
This function is intended to be called in a loop to write data to a device. It will write a chunk of data on each call.
On non-communication devices, this function is equivalant to tryWrite(). It will write some or all of the data in the block, at the discression of the operating system.
On communication devices, this function will try to wait for the device to become writable if no data can be written immediately. If the device cannot accept data after a certain time (the time returned by writeTimeout()), an exception is thrown.
first | The beginning of the range |
last | The postion after the end of the range |
WriteTimeoutError | No data could be written before the write timeout on a communication device. On non-communication devices, this exception is never thrown. |
StopRequested | This exception is thrown on communication devices that use a stop source if the stop source was triggered while waiting for the device to become writable. |
std::runtime_error | An error occurred writing the data. |
ConnectionClosed | On communication devices, errors thrown because the connection was closed are derived from ConnectionClosed in addition to std::runtime_error. This allows you to handle closed connections during read and write operations in the same catch block by catching exceptions of type ConnectionClosed. |
auto xentara::utils::io::OutputDevice::writePosition | ( | ) | const -> std::optional< std::size_t > |
Gets the current write position within the device.
std::runtime_error | The device tracks a write position, but an error occurred retreiving it |
|
noexcept |
Returns the write timeout for communication devices.
The write timeout is the maximum time allowed between chunks of data before write() or writeByte() throw an exception of type WriteTimeoutError.