Skip to content

Channels input output interface

incoder edited this page Mar 15, 2018 · 3 revisions

(in development)

Most of programs processing some data, i.e. reading and writing files, network sockets, named and unnamed pipes etc.

C++ standard library have next options for the input and output:

  • Use standard streams like std::cin, std::cout for console or std::fstream for files, this is useful for textual data but not for binary. Unfortunately standard library not providing streams for network sockets or named pipes yet (In 2018 network support from boost::asio is under C++ comity discussion state). Moreover streams design is not very nice, as well as streams are well known performance bottleneck;
  • Use C library functions like std::read and std::write or std::printf. This is not object oriented approach at all, as well as C library file descriptors e.g. FILE or SOCKET is heavy about 128 bytes depending on C library implementation;
  • Use operating system calls directly, i.e. functions from Windows.h or unistd.h. This is most performed approach, very good for the binary data, and in the same time requires a lot of custom coding.

Another paint-full thing streams and C library functions depends on locale. Locale behavior is implementation defined, off cause you can tune it but this is not so trivial. Another locale problem - it bring to some unexpected result for sort of applications with the strong data format restrictions or expected to work with many languages at time, this is classic for the sort of internet web or ftp servers accessed from world wide.

IO using C++ object oriented approach to unify input and output on top of operating system calls and in fact generally any data-source/data-destination. For this propose introduces input/output channels abstraction.

There are for types of channels: read_channel, write_channel, read_write_channel and random_access_channel defined in channels.hpp as following pure-virtual classes (interfaces) derived from channel virtual base, in order to use pointer on reference and intrusive smart pointer.

/// \brief General input/output channel interface
/// \details Adds ability for put implementor into boost::instrusive_ptr
class channel:public object {
public:
	channel(const channel&) = delete;
	channel& operator=(const channel&) = delete;
protected:
	constexpr channel() noexcept:
		object()
	{}
	virtual ~channel() override = default;
};

/**
  General interface to input operations on an resource like a: file, socket, std in device, named pipe, shared memory blocks etc.
 **/
class read_channel:public virtual channel {
protected:
	read_channel() noexcept;
public:
	/// Reads certain number of bytes from underlying resource
	/// \param ec
	///		operation error code
	/// \param buff
	///		memory buffer to store read data, must be continues and at least size bytes length
	/// \param bytes
	///		requested bytes to read
	/// \return number of bytes read or 0 if nothing read or EOF riched
	/// \throw never throws
	virtual std::size_t read(std::error_code& ec,uint8_t* const buff, std::size_t bytes) const noexcept = 0;
};

/**
 * General interface to output operations on an resource
 * like a: file, socket, std out device, named pipe, shared memory blocks etc.
 **/
class write_channel:public virtual channel {
protected:
	write_channel() noexcept;
public:
	/// Writes certain number of bytes to underlying resource
	/// \param ec
	///		operation error code
	/// \param buff
	///		memory buffer to storing data to write, must be continues and at least size bytes length
	/// \param size
	///		requested bytes to write
	/// \return number of bytes written or 0 if nothing written
	/// \throw never throws
	virtual std::size_t write(std::error_code& ec, const uint8_t* buff,std::size_t size) const noexcept = 0;
};

/**
 * General interface to output operations on an resource
 * like a: file, socket, std out device, named pipe, shared memory blocks etc.
 **/
class write_channel:public virtual channel {
protected:
	write_channel() noexcept;
public:
	/// Writes certain number of bytes to underlying resource
	/// \param ec
	///		operation error code
	/// \param buff
	///		memory buffer to storing data to write, must be continues and at least size bytes length
	/// \param size
	///		requested bytes to write
	/// \return number of bytes written or 0 if nothing written
	/// \throw never throws
	virtual std::size_t write(std::error_code& ec, const uint8_t* buff,std::size_t size) const noexcept = 0;
};

/**
* General interface to input and output operations on an resource
* like a: file, socket, std in/out device, named pipe, shared memory blocks etc.
**/
class read_write_channel:public virtual channel, public read_channel, public write_channel {
protected:
	read_write_channel() noexcept;
public:
	virtual ~read_write_channel() noexcept = 0;
	virtual std::size_t read(std::error_code& ec,uint8_t* const buff, std::size_t bytes) const noexcept override = 0;
	virtual std::size_t write(std::error_code& ec, const uint8_t* buff,std::size_t size) const noexcept override = 0;
};

/**
 * General interface to input, output and position moving operations on an resource
 * like a: file, socket, shared memory blocks etc.
 **/
class random_access_channel:public read_write_channel {
protected:
	random_access_channel() noexcept;
public:
	virtual ~random_access_channel() noexcept = 0;
	/// Moving forward current device position
	/// \param ec
	///		operation error code
	/// \param size
	///			moving offset
	virtual std::size_t forward(std::error_code& err,std::size_t size) noexcept = 0;
	/// Moving backward current device position
	/// \param ec
	///		operation error code
	/// \param size
	///			moving offset
	virtual std::size_t backward(std::error_code& err, std::size_t size) noexcept = 0;
	/// Moving current device position forward from the device starting position
	/// \param ec
	///		operation error code
	/// \param size
	///			moving offset
	virtual std::size_t from_begin(std::error_code& err, std::size_t size) noexcept = 0;
	/// Moving current device position backward from the device ending position
	/// \param ec
	///		operation error code
	/// \param size
	///			moving offset
	virtual std::size_t from_end(std::error_code& err, std::size_t size) noexcept = 0;
	/// Gets current device position as an offset from the starting device position
	/// \param ec
	///		operation error code
	virtual std::size_t position(std::error_code& err) noexcept = 0;
};
Clone this wiki locally