/*!
* \file utl/dev/ostream_dev.h
* \brief Abstract base class interface for output devices of utl.
*
* Copyright (C) 2018 Christos Choutouridis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
*/
#ifndef __utl_dev_ostream_dev_h__
#define __utl_dev_ostream_dev_h__
#include
#include
#include
#include
namespace utl {
/*!
* \ingroup Device Interface
* \brief Abstract base classes for output stream devices
*/
//!@{
/*!
* \brief
* Template base class for output stream devices using CRTP
*
* This class force a common interface for output stream devices.
* By using this common interface the class implements
* - Stream-like inserting operator
* - Output iterator
* - Const output iterator
* to inherit to implementation.
*
* \param impl_t The CRTP type (the derived/implementation class typename).
* \param data_t The devices base type of data
*/
template
class ostream_dev {
_CRTP_IMPL(impl_t);
using ostream_dev_t = ostream_dev ; //!< class type syntactic sugar
//! Export types as output device concept demands
//! @{
public:
using data_type = data_t;
using pointer_type = data_t*;
//!@}
using type = ostream_dev_t; //!< Export type as identity meta-function
/*!
* \name Constructor / Destructor
*/
//!@{
protected:
~ostream_dev () = default; //!< \brief Allow destructor from derived only
ostream_dev () = default; //!< \brief A default constructor from derived only
ostream_dev(const ostream_dev_t&) = delete; //!< No copies
ostream_dev_t& operator= (const ostream_dev_t&) = delete; //!< No copy assignments
//!@}
//! \name Common output device interface requirements
//!@{
private:
size_t put_ (const data_t& data) { return impl().put_ (data); }
size_t put_ (const data_t* data, size_t n) {
return impl().put_ (data, n);
}
//!@}
/*!
* \name Common output device interface
*/
//!@{
public:
/*!
* \brief
* Put interface. This function should send a single
* data_t object to device.
* \param data The data to send
* \return The number of transmitted data items
* \note
* A successful call should return 1
*/
size_t put (const data_t& data) {
return put_ (data);
}
/*!
* \brief
* Put interface. This function should send a stream of
* data_t objects to device.
* \param data Pointer to buffer indenting write to device.
* \param n The number of data of type data_t to send
* \return The number of transmitted items.
*/
size_t put (const data_t* data, size_t n) {
return put_ (data, n);
}
//!@}
/*!
* \name Stream operator << interface
*/
//!@{
public:
/*!
* \brief
* Template operator<< implementation for for all by value/ref parameters
* \note
* In the case _Src_t size is not an exact multiple of data_t size
* the write data will be truncated and there may be data loss.
* \param src Reference to source data
* \return Reference to this device for chaining
*/
template
ostream_dev_t& operator<< (const _Src_t& src) {
static_assert ((sizeof (_Src_t)%sizeof(data_t) == 0),
"Source size must be an integer multiple of device's data size");
put_ (reinterpret_cast(&src), sizeof(_Src_t)/sizeof(data_t));
return *this;
}
//! Overload to disallow pointer types as source
template
ostream_dev_t& operator<< (_Src_t* src) = delete;
//! Overload for single data_t object
ostream_dev_t& operator<< (const data_t& src) {
put_ (src);
return *this;
}
//ToDo: Add support for c-string, utl::string, ...
//!@}
/*!
* \name STL-like Output iterator interface
*/
//!@{
using iterator = ostreamdev_it ; //!< Iterator
using const_iterator = ostreamdev_it ; //!< Const iterator
//!@{ .begin implementation
iterator begin () noexcept { return iterator(this); }
const_iterator begin () const noexcept { return const_iterator(this); }
const_iterator cbegin () const noexcept { return const_iterator(this); }
//!@}
//!@{ .end implementation
iterator end () noexcept { return iterator(); }
const_iterator end () const noexcept { return const_iterator(); }
const_iterator cend () const noexcept { return const_iterator(); }
//!@}
//!@}
};
template
class ostream_dev {
using ostream_dev_t = ostream_dev ; //!< class type syntactic sugar
//! Export types as output device concept demands
//! @{
public:
using data_type = data_t;
using pointer_type = data_t*;
//!@}
using type = ostream_dev_t; //!< Export type as identity meta-function
/*!
* \name Constructor / Destructor
*/
//!@{
public:
virtual ~ostream_dev () = default; //!< \brief Virtual destructor
protected:
ostream_dev () = default; //!< \brief A default constructor from derived only
ostream_dev(const ostream_dev_t&) = delete; //!< No copies
ostream_dev_t& operator= (const ostream_dev_t&) = delete; //!< No copy assignments
//!@}
//! \name Common output device interface requirements
//!@{
private:
virtual size_t put_ (const data_t& data) =0;
virtual size_t put_ (const data_t* data, size_t n) =0;
//!@}
/*!
* \name Common output device interface
*/
//!@{
public:
/*!
* \brief
* Put interface. This function should send a single
* data_t object to device.
* \param data The data to send
* \return The number of transmitted data items
* \note
* A successful call should return 1
*/
size_t put (const data_t& data) {
return put_ (data);
}
/*!
* \brief
* Put interface. This function should send a stream of
* data_t objects to device.
* \param data Pointer to buffer indenting write to device.
* \param n The number of data of type data_t to send
* \return The number of transmitted items.
*/
size_t put (const data_t* data, size_t n) {
return put_ (data, n);
}
//!@}
/*!
* \name Stream operator << interface
*/
//!@{
public:
/*!
* \brief
* Template operator<< implementation for for all by value/ref parameters
* \note
* In the case _Src_t size is not an exact multiple of data_t size
* the write data will be truncated and there may be data loss.
* \param src Reference to source data
* \return Reference to this device for chaining
*/
template
ostream_dev_t& operator<< (const _Src_t& src) {
static_assert ((sizeof (_Src_t)%sizeof(data_t) == 0),
"Source size must be an integer multiple of device's data size");
put_ (reinterpret_cast(&src), sizeof(_Src_t)/sizeof(data_t));
return *this;
}
//! Overload to disallow pointer types as source
template
ostream_dev_t& operator<< (_Src_t* src) = delete;
//! Overload for single data_t object
ostream_dev_t& operator<< (const data_t& src) {
put_ (src);
return *this;
}
//!@}
/*!
* \name STL-like Output iterator interface
*/
//!@{
using iterator = ostreamdev_it ; //!< Iterator
using const_iterator = ostreamdev_it ; //!< Const iterator
//!@{ .begin implementation
iterator begin () noexcept { return iterator(this); }
const_iterator begin () const noexcept { return const_iterator(this); }
const_iterator cbegin () const noexcept { return const_iterator(this); }
//!@}
//!@{ .end implementation
iterator end () noexcept { return iterator(); }
const_iterator end () const noexcept { return const_iterator(); }
const_iterator cend () const noexcept { return const_iterator(); }
//!@}
//!@}
};
//!@}
} //namespace utl
#endif /* #ifndef __utl_dev_out_dev_h__ */