From 03620c831f9e9856cf25aa3509c81c5f7623c003 Mon Sep 17 00:00:00 2001 From: Christos Houtouridis Date: Sun, 28 Oct 2018 22:26:35 +0200 Subject: [PATCH] dev: A first non-working version of dev added A first group of device interface base classes added. --- include/utl/dev/dev_iterators.h | 854 ++++++++++++++++++++++++++++++++ include/utl/dev/idx_dev.h | 530 ++++++++++++++++++++ include/utl/dev/in_dev.h | 340 +++++++++++++ include/utl/dev/inbuf_dev.h | 386 +++++++++++++++ include/utl/dev/out_dev.h | 365 ++++++++++++++ 5 files changed, 2475 insertions(+) create mode 100644 include/utl/dev/dev_iterators.h create mode 100644 include/utl/dev/idx_dev.h create mode 100644 include/utl/dev/in_dev.h create mode 100644 include/utl/dev/inbuf_dev.h create mode 100644 include/utl/dev/out_dev.h diff --git a/include/utl/dev/dev_iterators.h b/include/utl/dev/dev_iterators.h new file mode 100644 index 0000000..bda07b3 --- /dev/null +++ b/include/utl/dev/dev_iterators.h @@ -0,0 +1,854 @@ +/*! + * \file utl/dev/dev_iterators.h + * \brief Iterator collection for devices. + * + * 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_dev_iterators_h__ +#define __utl_dev_dev_iterators_h__ + +#include +#include + +namespace utl { + +/*! + * \ingroup Devices + * \brief Iterator collection. + */ +//!@{ + + /*! + * Common template Iterator trait dispatcher for the STL requirement + * type definitions. + * Our iterators inherit from specializations of this type + */ + template + struct dev_iterator_traits { }; + + //! Partial specialization for pointer types. + template + struct dev_iterator_traits<_Cat, _Tp*, _Diff> { + typedef _Cat iterator_category; + typedef _Tp value_type; + typedef _Diff difference_type; + typedef _Tp* pointer; + typedef _Tp& reference; + }; + + //! Partial specialization for const pointer types. + template + struct dev_iterator_traits<_Cat, const _Tp*, _Diff> { + typedef _Cat iterator_category; + typedef _Tp value_type; + typedef _Diff difference_type; + typedef const _Tp* pointer; + typedef const _Tp& reference; + }; + + /* + * ================ Output device Iterator ================= + */ + + /*! + * \brief + * Output device iterator type. We "future call" interface methods + * from owner class to provide iterator functionality. + * \param container_t Container/parent type + * \param iter_t Iterator data type (pointer to container_t::value_type) + * \param streamsize Stream size + */ + template + class outdev_it { + //! iterator type local name + using iterator_t = outdev_it ; + + //! STL iterator traits "forwarding" + //!@{ + public: + using iterator_category = typename dev_iterator_traits ::iterator_category; + using value_type = typename dev_iterator_traits ::value_type; + using difference_type = typename dev_iterator_traits ::difference_type; + using pointer = typename dev_iterator_traits ::pointer; + using reference = typename dev_iterator_traits ::reference; + //!@} + using type = iterator_t; //!< Export type as identity meta-function + + //! #define-like enumerator for Cursor + enum Cursor { + beg = 0, //!< Points the first item + eos = streamsize, //!< Points one place after last item + }; + private: + container_t* owner_; /*!< + * Pointer to parent/owner device class. Constructor demands + * owner container in order to access data. Considering the data + * don't "live" in memory. + */ + size_t cursor_ {beg}; //!< virtual cursor for comparison operators + /*! + * \name Constructor / Destructor + * \note + * We can not provide a default constructor as long as we depend + * on container_t (the owner type). + */ + //!@{ + public: + //! \brief Basic constructor + explicit outdev_it (container_t* owner, size_t cursor =beg) noexcept + : owner_{owner}, + cursor_{cursor} { } + //! \brief Basic copy constructor + explicit outdev_it (const iterator_t& it) noexcept + : owner_ {const_cast(it.owner())}, + cursor_ {it.cursor()} { } + //! \brief Iterator to const-iterator conversion (as STL requires) + //! \param it Iterator reference + template + outdev_it (const outdev_it< + use_if_same_t <_It, typename container_t::pointer_type, container_t>, + _It, + streamsize + >& it) noexcept + : owner_ {const_cast(it.owner())}, + cursor_ {it.cursor()} { } + //! \brief Basic copy assignment operator + iterator_t& operator= (const iterator_t& it) noexcept { + owner_ = const_cast(it.owner()); + cursor_ = it.cursor(); + } + //!@} + + + //!@{ \name Public interface + public: + iterator_t& operator* () noexcept { return *this; } + /*! + * \brief + * Assignment operation. Where the output method is invoked + * \param value An instance of container_t basic type + * \return This %iterator, for chained operations. + */ + iterator_t& operator= (const value_type& value) { + owner_->put (value); + return *this; + } + + //!@{ ++ operators + //! STL compatibility. No cursor + template + use_if_t <(S == 0), iterator_t&> operator++ () noexcept { *this; } + template + use_if_t <(S == 0), iterator_t&> operator++ (int) noexcept { *this; } + //!@} + /*! + * The following are not requirements for output iterator. + * We provide them nevertheless. + * This kind of %iterator doesn't usually have a @a cursor in the + * container. Assigning a value to the %iterator will + * always forward the value to the output device. If though we pass + * a streamsize value !=0 then the iterator will work using the cursor. + * The user has to be careful to keep sync between ++'s and ='s operator + * calls in the code. + */ + //!@{ + template + use_if_t <(S != 0), iterator_t&> operator++ () noexcept { + ++cursor_; + return *this; + } + template + use_if_t <(S != 0), iterator_t> operator++ (int) noexcept { + iterator_t ret = *this; + ++cursor_; + return ret; + } + //!@} + + //! Export container for comparison + const container_t* owner () const noexcept { return owner_; } + //! Export cursor for comparison + const size_t cursor () const noexcept { return cursor_; } + //!@} + }; + + /*! + * \brief + * Equality comparison template so that comparison between cv-qualified and + * non-cv-qualified iterators be valid + * \param lhs Left hand site iterator + * \param rhs Right hand site iterator + * \return True in equality + */ + template + inline bool operator== (const outdev_it<_Cont, _It_L, _Size>& lhs, + const outdev_it<_Cont, _It_R, _Size>& rhs) noexcept { + return ((lhs.cursor() == rhs.cursor()) && + (lhs.owner() == rhs.owner())); + } + + /*! + * \brief + * Inequality comparison template so that comparison between cv-qualified and + * non-cv-qualified iterators be valid + * \param lhs Left hand site iterator + * \param rhs Right hand site iterator + * \return True in inequality + */ + template + inline bool operator!= (const outdev_it<_Cont, _It_L, _Size>& lhs, + const outdev_it<_Cont, _It_R, _Size>& rhs) noexcept { + return !(lhs == rhs); + } + + /*! + * \note + * The following are not requirements for output iterator. + * We provide them nevertheless. + * \warn + * Required: The rhs and lhs MUST belong to the same owner or + * the result is undefined. + */ + //!@{ + template + inline bool operator< (const outdev_it<_Cont, _It_L, _Size>& lhs, + const outdev_it<_Cont, _It_R, _Size>& rhs) noexcept { + return (lhs.cursor() < rhs.cursor()); + } + + template + inline bool operator<= (const outdev_it<_Cont, _It_L, _Size>& lhs, + const outdev_it<_Cont, _It_R, _Size>& rhs) noexcept { + return (lhs.cursor() <= rhs.cursor()); + } + + template + inline bool operator> (const outdev_it<_Cont, _It_L, _Size>& lhs, + const outdev_it<_Cont, _It_R, _Size>& rhs) noexcept { + return (lhs.cursor() > rhs.cursor()); + } + + template + inline bool operator>= (const outdev_it<_Cont, _It_L, _Size>& lhs, + const outdev_it<_Cont, _It_R, _Size>& rhs) noexcept { + return (lhs.cursor() >= rhs.cursor()); + } + //!@} + + /*! + * Output device iterator concept + */ + //! @{ + #if defined _utl_have_concepts + template + concept bool Outdev_it = requires (T t) { + // STL compatibility + typename T::value_type; + typename T::difference_type; + typename T::pointer; + typename T::reference; + requires same_< + typename T::iterator_category, + std::output_iterator_tag + >::value; + {*t} -> auto&&; // is dereferencable, and return non-void + {++t} -> T&; // is incrementable + {t++} -> T; + // Extras + {t.owner()} ->auto&&; + {t.cursor()} -> size_t; + }; + #else + namespace outdev_it_details { + using std::declval; + + //! Primary template to catch any non SPI interface types + template + struct is_outdev_it_ : false_ {}; + + //! template to catch a proper SPI interface type + template + struct is_outdev_it_ < + _Tp, + void_t < + typename T::value_type, + typename T::difference_type, + typename T::pointer, + typename T::reference, + use_if_same_t < + typename T::iterator_category, + std::output_iterator_tag + > + > + > : true_ {}; + } + /*! + * Value meta-programming function for SPI interface checking + * \param _Tp Type to check + * \return True if _Tp is a spi interface + */ + template + constexpr bool Outdev_it = outdev_it_details::is_outdev_it_<_Tp>::value; + #endif + //! @} + + + /* + * ================ Input device Iterator ================= + */ + + /*! + * \brief + * Input device iterator type. We "future call" interface methods + * from owner class to provide iterator functionality. + * \param container_t Container/parent type + * \param iter_t Iterator data type (pointer to container_t::value_type) + * \param streamsize Stream size + */ + template + class indev_it { + using iterator_t = indev_it ; //!< iterator type local name + //! STL iterator traits "forwarding" + //!@{ + public: + using iterator_category = typename dev_iterator_traits ::iterator_category; + using value_type = typename dev_iterator_traits ::value_type; + using difference_type = typename dev_iterator_traits ::difference_type; + using pointer = typename dev_iterator_traits ::pointer; + using reference = typename dev_iterator_traits ::reference; + //!@} + using type = iterator_t; //!< Export type as identity meta-function + + //! #define-like enumerator for Cursor + enum Cursor { + beg = 0, //!< Points the first item + eos = streamsize, //!< Points one place after last item + init= -1 //!< Used as flag so we have to fetch the first item + }; + + private: + container_t* owner_; /*!< + * Pointer to parent/owner device class. Constructor demands + * owner container in order to access data. Considering the data + * don't "live" in memory. + */ + size_t cursor_ {init}; //!< virtual cursor for comparison operators + value_type value_ {}; //!< The current value, used as a buffer + + /*! + * \name Constructor / Destructor + * \note + * We can not provide a default constructor as long as we depend + * on container_t (the owner type). + */ + //!@{ + public: + //! \brief Basic constructor + explicit indev_it (container_t* own, size_t cur =init) noexcept + : owner_{own}, + cursor_{cur}, + value_{} { } + //! \brief Basic copy constructor + explicit indev_it (const iterator_t& it) noexcept + : owner_ {const_cast(it.owner())}, + cursor_{it.cursor()}, + value_ {it.value()} { } + //! \brief Iterator to const-iterator conversion (as STL requires) + //! \param it Iterator reference + template + indev_it (const indev_it< + use_if_same_t <_It, typename container_t::pointer_type, container_t>, + _It, + streamsize + >& it) noexcept + : owner_ {const_cast(it.owner())}, + cursor_{it.cursor()}, + value_ {it.value()} { } + //! \brief Basic copy assignment operator + iterator_t& operator= (const iterator_t& it) noexcept { + owner_ = const_cast(it.owner()); + cursor_ = it.cursor(); + value_ = it.value(); + } + //!@} + + //!@{ \name Public interface + public: + /*! + * De-reference operator. We just return the current value + * \note + * We have to make sure we retrieve the first item before the + * first dereference. + * \note + * No end() place dereference check is made. + */ + reference operator* () noexcept { + if (cursor_ == init) + ++*this; + return value_; + } + //! Arrow operator + pointer operator-> () noexcept { + if (cursor_ == init) + ++*this; + return &value_; + } + //! Pre increment. This is where the input method is invoked + iterator_t& operator++ () noexcept { + owner_->get (value_); + ++cursor_; + return *this; + } + //! Post increment. This is where the input method is invoked + iterator_t operator++ (int) noexcept { + iterator_t ret = *this; + owner_->get (value_); + ++cursor_; + return *this; + } + //! Export container for comparison + const container_t* owner () const noexcept { return owner_; } + //! Export cursor for comparison + const size_t cursor () const noexcept { return cursor_; } + //! Export value for comparison + const value_type& value () const noexcept { return value_; } + //!@} + }; + + /*! + * \brief + * Equality comparison template so that comparison between cv-qualified and + * non-cv-qualified iterators be valid + * \param lhs Left hand site iterator + * \param rhs Right hand site iterator + * \return True in equality + */ + template + inline bool operator== (const indev_it<_Cont, _It_L, _Size>& lhs, + const indev_it<_Cont, _It_R, _Size>& rhs) noexcept { + return ((lhs.cursor() == rhs.cursor()) && + (lhs.owner() == rhs.owner()) && + (lhs.value() == rhs.value())); + } + + /*! + * \brief + * Inequality comparison template so that comparison between cv-qualified and + * non-cv-qualified iterators be valid + * \param lhs Left hand site iterator + * \param rhs Right hand site iterator + * \return True in inequality + */ + template + inline bool operator!= (const indev_it<_Cont, _It_L, _Size>& lhs, + const indev_it<_Cont, _It_R, _Size>& rhs) noexcept { + return ((lhs.cursor() != rhs.cursor()) || + (lhs.owner() != rhs.owner()) || + (lhs.value() != rhs.value())); + } + + /*! + * \note + * The following are not requirements for input iterator. + * We provide them nevertheless. + * \warn + * Required: The rhs and lhs MUST belong to the same owner or + * the result is undefined. + */ + //!@{ + template + inline bool operator< (const indev_it<_Cont, _It_L, _Size>& lhs, + const indev_it<_Cont, _It_R, _Size>& rhs) noexcept { + return (lhs.cursor() < rhs.cursor()); + } + + template + inline bool operator<= (const indev_it<_Cont, _It_L, _Size>& lhs, + const indev_it<_Cont, _It_R, _Size>& rhs) noexcept { + return (lhs.cursor() <= rhs.cursor()); + } + + template + inline bool operator> (const indev_it<_Cont, _It_L, _Size>& lhs, + const indev_it<_Cont, _It_R, _Size>& rhs) noexcept { + return (lhs.cursor() > rhs.cursor()); + } + + template + inline bool operator>= (const indev_it<_Cont, _It_L, _Size>& lhs, + const indev_it<_Cont, _It_R, _Size>& rhs) noexcept { + return (lhs.cursor() >= rhs.cursor()); + } + //!@} + + /*! + * Input device iterator concept + */ + //! @{ + #if defined _utl_have_concepts + template + concept bool Indev_it = requires (T t, const T ct) { + // STL compatibility + typename T::value_type; + typename T::difference_type; + typename T::pointer; + typename T::reference; + requires same_ < + typename T::iterator_category, + std::input_iterator_tag + >::value; + {*t} -> typename T::value_type; // is dereferencable + {++t} -> T&; // is incrementable + {t++} -> T; + // Extras + {ct.owner()} ->auto&&; + {ct.cursor()} -> const size_t; + {ct.value()} -> auto&&; + }; + #else + namespace indev_it_details { + using std::declval; + + //! Primary template to catch any non SPI interface types + template + struct is_indev_it_ : false_ {}; + + //! template to catch a proper SPI interface type + template + struct is_indev_it_ < + _Tp, + void_t < + typename T::value_type, + typename T::difference_type, + typename T::pointer, + typename T::reference, + use_if_same_t < + typename T::iterator_category, + std::input_iterator_tag + > + > + > : true_ {}; + } + /*! + * Value meta-programming function for SPI interface checking + * \param _Tp Type to check + * \return True if _Tp is a spi interface + */ + template + constexpr bool Indev_it = indev_it_details::is_indev_it_<_Tp>::value; + #endif + //! @} + + /* + * ================= Indexed device Iterator (input) ================= + */ + + /*! + * \brief + * Indexed device iterator type. We "future call" interface methods + * from owner class to provide iterator functionality. + * \note + * This is a Input type iterator + * \param container_t Container/parent type + * \param iter_t Iterator data type (pointer to container_t::value_type) + * \param N Max indexed/addressed items of device + * Usual the last address is N-1 + */ + template + class idxdev_it { + using iterator_t = idxdev_it ; //!< iterator type local name + + //!@{ STL iterator traits "forwarding" + public: + using iterator_category = typename dev_iterator_traits ::iterator_category; + using value_type = typename dev_iterator_traits ::value_type; + using difference_type = typename dev_iterator_traits ::difference_type; + using pointer = typename dev_iterator_traits ::pointer; + using reference = typename dev_iterator_traits ::reference; + //!@} + using type = iterator_t; //!< Export type as identity meta-function + + //! #define-like enumerator for cursor + enum Cursor { + beg = 0, //!< Points the first item + eos = N, //!< Points one place after last item + }; + + private: + container_t* owner_; /*!< + * Pointer to parent/owner device class. Constructor demands + * owner container in order to access data. Considering the data + * don't "live" in memory. + */ + size_t cursor_{beg}; //!< virtual cursor for comparison operators + /*! + * Current value wrapper type, to used as put event catcher + * owner_->get : Use v_ directly + * owner_->put : Use operator= + */ + struct value_type_t { + value_type v_; //!< Current value buffer to access via get + value_type_t(value_type v =0) : v_{v} { } + operator value_type() { return v_; } + operator reference() { return v_; } + value_type& operator= (const value_type& v) { + v_ = v; //!< Catch any attempt to write to value_ + owner_->put (v_, cursor_); //!< Sync the data back to device + } + } value_ {}; + /*! + * \name Constructor / Destructor + * \note + * We can not provide a default constructor as long as we depend + * on container_t (the owner type). + */ + //!@{ + public: + //! \brief Basic constructor + explicit idxdev_it (container_t* owner, size_t curor =beg) noexcept + : owner_{owner}, + cursor_{curor}, + value_{} { } + //! \brief Basic copy constructor + explicit idxdev_it (const iterator_t& it) noexcept + : owner_ {const_cast (it.owner())}, + cursor_{it.cursor()}, + value_ {it.value()} { } + //! \brief Iterator to const iterator conversion (as STL requires) + //! \param it Iterator reference + template + idxdev_it (const idxdev_it< + use_if_same_t <_It, typename container_t::pointer_type, container_t>, + _It, + N + >& it) noexcept + : owner_ {const_cast (it.owner())}, + cursor_{it.cursor()}, + value_ {it.value()} { + + } + //! \brief Basic copy assignment operator + iterator_t& operator= (const iterator_t& it) noexcept { + owner_ = const_cast(it.owner()); + cursor_ = it.cursor(); + value_ = it.value(); + } + //!@} + + //!@{ \name Public interface + public: + /*! + * De-reference operator. This is where the input method is invoked + * \note + * No end() place dereference check is made. + */ + reference operator* () noexcept { + owner_->get (value_.v_, cursor_); + return value_; + } + //! Arrow operator. This is where the input method is invoked + pointer operator-> () noexcept { + owner_->get (value_.v_, cursor_); + return &value_; + } + + //! Pre increment. + iterator_t& operator++ () noexcept { + ++cursor_; + return *this; + } + //! Post increment. + iterator_t operator++ (int) noexcept { + iterator_t ret = *this; + ++cursor_; + return *this; + } + + /*! + * \note + * The following are not requirements for input iterator. + * We provide them nevertheless. + */ + //! Pre decrement. + iterator_t& operator-- () noexcept { + --cursor_; + return *this; + } + //! Post decrement. + iterator_t operator-- (int) noexcept { + iterator_t ret = *this; + --cursor_; + return *this; + } + //! Random access through iterator + reference operator[] (difference_type n) noexcept { + owner_->get (value_.v_, cursor_ = n); + return value_; + } + //! Random cursor increment + iterator_t& operator+= (difference_type n) noexcept { + cursor_ += n; + return *this; + } + //! Addition operation + iterator_t operator+ (difference_type n) const noexcept { + return iterator_t (owner_, cursor_ + n); + } + //! Random cursor decrement + iterator_t& operator-= (difference_type n) noexcept { + cursor_ -= n; + return *this; + } + //! Subtraction operation + iterator_t operator- (difference_type n) const noexcept { + return iterator_t (owner_, cursor_ - n); + } + + //! Export container for comparison + const container_t* owner () const noexcept { return owner_; } + //! Export cursor for comparison + const size_t& cursor () const noexcept { return cursor_; } + //! Export value for comparison + const value_type_t& value () const noexcept { return value_; } + //!@} + }; + + /*! + * \brief + * Equality comparison template so that comparison between cv-qualified and + * non-cv-qualified iterators be valid + * \param lhs Left hand site iterator + * \param rhs Right hand site iterator + * \return True in equality + */ + template + inline bool operator== (const idxdev_it<_Cont, _It_L, _Size>& lhs, + const idxdev_it<_Cont, _It_R, _Size>& rhs) noexcept { + return ((lhs.cursor() == rhs.cursor()) && + (lhs.owner() == rhs.owner())); + } + + /*! + * \brief + * Inequality comparison template so that comparison between cv-qualified and + * non-cv-qualified iterators be valid + * \param lhs Left hand site iterator + * \param rhs Right hand site iterator + * \return True in inequality + */ + template + inline bool operator!= (const idxdev_it<_Cont, _It_L, _Size>& lhs, + const idxdev_it<_Cont, _It_R, _Size>& rhs) noexcept { + return ((lhs.cursor() != rhs.cursor()) || + (lhs.owner() != rhs.owner())); + } + + /*! + * \note + * The following are not requirements for input iterator. + * Nevertheless we provide them. + * \warn + * Required: The rhs and lhs MUST be from the same owner or the + * resuled is undefined. + */ + //!@{ + template + inline bool operator< (const idxdev_it<_Cont, _It_L, _Size>& lhs, + const idxdev_it<_Cont, _It_R, _Size>& rhs) noexcept { + return (lhs.cursor() < rhs.cursor()); + } + + template + inline bool operator<= (const idxdev_it<_Cont, _It_L, _Size>& lhs, + const idxdev_it<_Cont, _It_R, _Size>& rhs) noexcept { + return (lhs.cursor() <= rhs.cursor()); + } + + template + inline bool operator> (const idxdev_it<_Cont, _It_L, _Size>& lhs, + const idxdev_it<_Cont, _It_R, _Size>& rhs) noexcept { + return (lhs.cursor() > rhs.cursor()); + } + + template + inline bool operator>= (const idxdev_it<_Cont, _It_L, _Size>& lhs, + const idxdev_it<_Cont, _It_R, _Size>& rhs) noexcept { + return (lhs.cursor() >= rhs.cursor()); + } + //!@} + + /*! + * Index device iterator concept + */ + //! @{ + #if defined _utl_have_concepts + template + concept bool Idxdev_it = requires (T t, const T ct) { + // STL compatibility + typename T::value_type; + typename T::difference_type; + typename T::pointer; + typename T::reference; + requires same_< + typename T::iterator_category, + std::input_iterator_tag + >::value; + {*t} -> typename T::value_type; // is dereferencable + {++t} -> T&; // is incrementable + {t++} -> T; + // Extras + {ct.owner()} ->auto&&; + {ct.cursor()} -> const size_t; + {ct.value()} -> auto&&; + }; + #else + namespace idxdev_it_details { + using std::declval; + + //! Primary template to catch any non SPI interface types + template + struct is_idxdev_it_ : false_ {}; + + //! template to catch a proper SPI interface type + template + struct is_idxdev_it_ < + _Tp, + void_t < + typename T::value_type, + typename T::difference_type, + typename T::pointer, + typename T::reference, + use_if_same_t < + typename T::iterator_category, + std::input_iterator_tag + > + > + > : true_ {}; + } + /*! + * Value meta-programming function for SPI interface checking + * \param _Tp Type to check + * \return True if _Tp is a spi interface + */ + template + constexpr bool Idxdev_it = idxdev_it_details::is_idxdev_it_<_Tp>::value; + #endif + //! @} + +} +//!@} +#endif /* __utl_dev_dev_iterators_h__ */ diff --git a/include/utl/dev/idx_dev.h b/include/utl/dev/idx_dev.h new file mode 100644 index 0000000..4e719e1 --- /dev/null +++ b/include/utl/dev/idx_dev.h @@ -0,0 +1,530 @@ +/*! + * \file utl/dev/idx_dev.h + * \brief Abstract base class implementations for indexed + * devices interface 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_idx_dev_h__ +#define __utl_dev_idx_dev_h__ + +#include +#include +#include +#include + +namespace utl { + +/*! + * \ingroup Device Interface + * \brief Abstract base class for indexed devices + */ +//!@{ + + /*! + * \brief + * Template base class for indexed (I/O) devices. using CRTP + * + * This class force a common interface for input, indexed (I/O) devices. + * By using this common interface the class implements + * - Stream-like extracting and insertion operator + * - Helper operators + * - Input iterator + * - Const input 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 + * \param idx_t The type to use for indexing + * \param streamsize The number of elements to indicate eos. + */ + template + class idx_dev { + _CRTP_IMPL(impl_t); + using idx_dev_t = idx_dev ; //!< class type syntactic sugar + + //!@{ Export types as index device concept demands + public: + using data_type = data_t; + using pointer_type= data_t*; + using idx_type = idx_t; + //!@} + using type = idx_dev_t; //!< Export type as identity meta-function + + /*! + * \name Constructor / Destructor + */ + //!@{ + protected: + ~idx_dev () = default; //!< \brief Allow destructor from derived only + idx_dev () = default; //!< \brief A default constructor from derived only + idx_dev(const idx_dev_t&) = delete; //!< No copies + idx_dev_t& operator= (const idx_dev_t&) = delete; //!< No copy assignments + //!@} + + //! \name Common index device interface requirements + //!@{ + private: + size_t get_ (data_t& data, idx_t idx) { return impl().get_(data, idx); } + size_t get_ (data_t* data, size_t n, idx_t idx) { return impl().get_(data, n, idx); } + size_t put_ (const data_t& data, idx_t idx) { return impl().put_(data, idx); } + size_t put_ (const data_t* data, size_t n, idx_t idx) { return impl().put_ (data, n, idx); } + idx_t cursor_ () const { return impl().cursor_(); } + void cursor_ (idx_t idx) { impl().cursor_(idx); } + //!@} + + /*! + * \name Public index device interface + */ + //!@{ + public: + /*! + * \brief + * Get interface. This function should read + * a single data_t object from device in blocking mode. + * \param data Reference to data output from device. + * \return Number of data read from device + * \note + * A successful call should return 1 + */ + size_t get (data_t& data, idx_t cursor) { + return get_ (data, cursor); + } + + /*! + * \brief + * Old stile get functionality using free standing data_t*. + * This function should return a stream of data from device + * \param data Pointer to buffer to write the data from device. + * \param n The number of data of type data_t to read + * \return The read data items. + */ + size_t get (data_t* data, size_t n, idx_t cursor) { + return get_ (data, n, cursor); + } + + /*! + * \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, idx_t cursor) { + return put_ (data, cursor); + } + + /*! + * \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, idx_t cursor) { + return put_ (data, n, cursor); + } + + /*! + * \brief + * Return the current cursor position + */ + idx_t cursor () const { return cursor_(); } + /*! + * \brief + * Set the cursor position + * \param idx Cursor address to set + * \return The current cursor + */ + idx_t cursor (idx_t idx) { return cursor_(idx); } + //!@} + + /*! + * \name Stream operator >> interface + */ + //!@{ + /*! + * \brief + * Template operator>> implementation for for all by value/ref parameters + * \param dst Reference to destination + * \return Reference to this device for chaining + */ + template + idx_dev_t& operator>> (_Dst_t& dst) { + static_assert ((sizeof (_Dst_t)%sizeof(data_t) == 0), + "Target size must be a integer multiple of device's data size"); + get_ (reinterpret_cast(&dst), sizeof(_Dst_t)/sizeof(data_t), cursor_()); + return *this; + } + //! Specialization to disallow pointer types as destination + template + idx_dev_t& operator>> (_Dst_t* dst) = delete; + + //! Overload for single data_t object + idx_dev_t& operator>> (data_t& dst) { + get_ (dst, cursor_()); + return *this; + } + //!@} + + /*! + * \name Stream operator<< interface + */ + //!@{ + /*! + * \brief + * Template operator<< implementation for for all by value/ref parameters + * \param src Reference to source data + * \return Reference to this device for chaining + */ + template + idx_dev_t& operator<< (_Src_t& src) { + static_assert ((sizeof (_Src_t)%sizeof(data_t) == 0), + "Source size must be a integer multiple of device's data size"); + put_ (reinterpret_cast(&src), sizeof (_Src_t)/sizeof(data_t), cursor_()); + return *this; + } + //! specialization to disallow pointer types as source + template + idx_dev_t& operator<< (_Src_t* src) = delete; + + //! Overload for single data_t object + idx_dev_t& operator<< (const data_t& src) { + put_ (src, cursor_()); + return *this; + } + //!@} + + /*! + * \name Helper operators + */ + //!@{ + data_t& operator[] (const idx_t idx) { + iterator it(this, idx); + return *it; + } + //!@} + + /*! + * \name STL-like Input iterator interface + */ + //!@{ + public: + using iterator = idxdev_it ; //!< Iterator + using const_iterator = idxdev_it ; //!< Const iterator + + //!@{ .begin implementation + iterator begin () noexcept { return iterator(this, iterator::beg); } + const_iterator begin () const noexcept { return const_iterator(this, iterator::beg); } + const_iterator cbegin () const noexcept { return const_iterator(this, iterator::beg); } + //!@} + //!@{ .end implementation + iterator end () noexcept { return iterator(this, iterator::eos); } + const_iterator end () const noexcept { return const_iterator(this, iterator::eos); } + const_iterator cend () const noexcept { return const_iterator(this, iterator::eos); } + //!@} + //!@} + }; + + + /*! + * \brief + * A virtual base class specialization + * \param impl_t = virtual_tag + * \param data_t The devices base type of data + * \param idx_t The type to use for indexing + * \param streamsize The number of elements to indicate eos. + */ + template + class idx_dev { + using idx_dev_t = idx_dev ; //!< class type syntactic sugar + + //!@{ Export types as index device concept demands + public: + using data_type = data_t; + using pointer_type= data_t*; + using idx_type = idx_t; + //!@} + using type = idx_dev_t; //!< Export type as identity meta-function + + /*! + * \name Constructor / Destructor + */ + //!@{ + public: + virtual ~idx_dev () = default; //!< \brief Virtual destructor + protected: + idx_dev () = default; //!< \brief A default constructor from derived only + idx_dev(const idx_dev_t&) = delete; //!< No copies + idx_dev_t& operator= (const idx_dev_t&) = delete; //!< No copy assignments + //!@} + + //!@{ \name Common index device interface requirements + private: + virtual size_t get_ (data_t&, idx_t) =0; + virtual size_t get_ (data_t*, size_t n, idx_t) =0; + virtual size_t put_ (const data_t&, idx_t) =0; + virtual size_t put_ (const data_t*, size_t n, idx_t) =0; + virtual idx_t cursor_ () const =0; + virtual void cursor_ (idx_t) =0; + //!@} + + /*! + * \name Public index device interface + */ + //!@{ + public: + /*! + * \brief + * Get interface. This function should read + * a single data_t object from device in blocking mode. + * \param data Reference to data output from device. + * \return Number of data read from device + * \note + * A successful call should return 1 + */ + size_t get (data_t& data, idx_t cursor) { + return get_ (data, cursor); + } + + /*! + * \brief + * Old stile get functionality using free standing data_t*. + * This function should return a stream of data from device + * \param data Pointer to buffer to write the data from device. + * \param n The number of data of type data_t to read + * \return The read data items. + */ + size_t get (data_t* data, size_t n, idx_t cursor) { + return get_ (data, n, cursor); + } + + /*! + * \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, idx_t cursor) { + return put_ (data, cursor); + } + + /*! + * \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, idx_t cursor) { + return put_ (data, n, cursor); + } + + /*! + * \brief + * Return the current cursor position + */ + idx_t cursor () const { return cursor_(); } + /*! + * \brief + * Set the cursor position + * \param idx Cursor address to set + * \return The current cursor + */ + idx_t cursor (idx_t idx) { return cursor_(idx); } + //!@} + + /*! + * \name Stream operator>> interface + */ + //!@{ + /*! + * \brief + * Template operator>> implementation for for all by value/ref parameters + * \param dst Reference to destination + * \return Reference to this device for chaining + */ + template + idx_dev_t& operator>> (_Dst_t& dst) { + static_assert ((sizeof (_Dst_t)%sizeof(data_t) == 0), + "Target size must be an integer multiple of device's data size"); + get_ (reinterpret_cast(&dst), sizeof(_Dst_t)/sizeof(data_t), cursor_()); + return *this; + } + //! specialization to disallow pointer types as destination + template + idx_dev_t& operator>> (_Dst_t* dst) = delete; + + //! Overload for single data_t object + idx_dev_t& operator>> (data_t& dst) { + get_ (dst, cursor_()); + return *this; + } + //!@} + + /*! + * \name Stream operator<< interface + */ + //!@{ + /*! + * \brief + * Template operator<< implementation for for all by value/ref parameters + * \param src Reference to source data + * \return Reference to this device for chaining + */ + template + idx_dev_t& operator<< (_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), cursor_()); + return *this; + } + //! specialization to disallow pointer types as source + template + idx_dev_t& operator<< (_Src_t* src) = delete; + + //! Overload for single data_t object + idx_dev_t& operator<< (const data_t& src) { + put_ (src, cursor_()); + return *this; + } + //!@} + + /*! + * \name Helper operators + */ + //!@{ + data_t& operator[] (const idx_t idx) { + iterator it(this, idx); + return *it; + } + //!@} + + /*! + * \name STL-like Input iterator interface + */ + //!@{ + public: + using iterator = idxdev_it ; //!< Iterator + using const_iterator = idxdev_it ; //!< Const iterator + + //!@{ .begin implementation + iterator begin () noexcept { return iterator(this, iterator::beg); } + const_iterator begin () const noexcept { return const_iterator(this, iterator::beg); } + const_iterator cbegin () const noexcept { return const_iterator(this, iterator::beg); } + //!@} + //!@{ .end implementation + iterator end () noexcept { return iterator(this, iterator::eos); } + const_iterator end () const noexcept { return const_iterator(this, iterator::eos); } + const_iterator cend () const noexcept { return const_iterator(this, iterator::eos); } + //!@} + //!@} + }; + + /*! + * indexed device concept + */ + //! @{ + #if defined _utl_have_concepts + template + concept bool Idx_dev = requires (_Tp t, const _Tp ct, typename _Tp::data_type v) { + // Object type + // requires std::is_default_constructible<_Tp>::value; + requires !std::is_copy_constructible<_Tp>::value; + requires !std::is_copy_assignable<_Tp>::value; + // Methods + {t.get(v, 0)} -> size_t; + {t.get(&v, 1, 0)} -> size_t; + {t.put(v, 0)} -> size_t; + {t.put(&v, 1, 0)} -> size_t; + // Operators + t >> v; + t << v; + {t[typename _Tp::idx_type{}]} -> typename _Tp::data_type&; + // Iterators + requires idxdev_iterator_c; + typename _Tp::const_iterator; //XXX: change to concept: is_idxdev_iterator<_Tp> + //requires idxdev_iterator_c; + { t.begin()} -> typename _Tp::iterator; + // {ct.begin()} -> typename _Tp::const_iterator; + // { t.cbegin()} -> typename _Tp::const_iterator; + { t.end()} -> typename _Tp::iterator; + // {ct.end()} -> typename _Tp::const_iterator; + // { t.cend()} -> typename _Tp::const_iterator; + }; + #else + namespace idx_dev_details { + using std::declval; + + // main api members + template using try_get1_t = decltype (declval<_Tp>().get (declval())); + template using try_get2_t = decltype (declval<_Tp>().get (declval(), declval())); + // operators + //template using try_extract_t= decltype (declval<_Tp>() >> declval()); + // iterator members + template using try_begin_t = decltype (declval<_Tp>().begin()); + template using tryc_begin_t = decltype (declval().begin()); + template using try_cbegin_t = decltype (declval().cbegin()); + template using try_end_t = decltype (declval<_Tp>().begin()); + template using tryc_end_t = decltype (declval().begin()); + template using try_cend_t = decltype (declval().cend()); + + //! Primary template to catch any non input device types + template + struct is_idx_dev_ : false_ {}; + + //! template to catch a proper input device type + template + struct is_idx_dev_ <_Tp, + void_t < + typename _Tp::data_type, + typename _Tp::pointer_type, + typename _Tp::iterator, + typename _Tp::const_iterator, + use_if_same_t , size_t>, + use_if_same_t , size_t>, + //if_same_t ,typename _Tp&>, + use_if_same_t , typename _Tp::iterator>, + use_if_same_t , typename _Tp::const_iterator>, + use_if_same_t , typename _Tp::const_iterator>, + use_if_same_t , typename _Tp::iterator>, + use_if_same_t , typename _Tp::const_iterator>, + use_if_same_t , typename _Tp::const_iterator> + > + > : true_ {}; + } + /*! + * Predicate for input device checking + * \param _Tp Type to check + * \return True if _Tp is a input device + */ + template + constexpr bool Idx_dev = idx_dev_details::is_idx_dev_ <_Tp>::value; + #endif + //!@} + +} +//!@} + +#endif /* #ifndef __utl_dev_idx_dev_h__ */ diff --git a/include/utl/dev/in_dev.h b/include/utl/dev/in_dev.h new file mode 100644 index 0000000..4cd7a47 --- /dev/null +++ b/include/utl/dev/in_dev.h @@ -0,0 +1,340 @@ +/*! + * \file utl/dev/in_dev.h + * \brief Abstract base class interface for input 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_in_dev_h__ +#define __utl_dev_in_dev_h__ + +#include +#include +#include +#include + +namespace utl { + +/*! + * \ingroup Device Interface + * \brief Abstract base class for input devices + */ +//!@{ + + /*! + * \brief + * Template base class for un-buffered input devices. using CRTP + * + * This class force a common interface for input, non-buffered devices. + * By using this common interface the class implements + * - Stream-like extracting operator + * - Input iterator + * - Const input 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 + * \param streamsize The number of elements to indicate eos. + * \arg None or 0 Stream only. No iterator as begin() now equals end(). + */ + template + class in_dev { + _CRTP_IMPL(impl_t); + using in_dev_t = in_dev ; //!< class type syntactic sugar + + //! Export types as input device concept demands + //! @{ + public: + using data_type = data_t; + using pointer_type = data_t*; + //! @} + using type = in_dev_t; //!< Export type as identity meta-function + /*! + * \name Constructor / Destructor + */ + //!@{ + protected: + ~in_dev () = default; //!< \brief Allow destructor from derived only + in_dev () = default; //!< \brief A default constructor from derived only + in_dev(const in_dev_t&) = delete; //!< No copies + in_dev_t& operator= (const in_dev_t&) = delete; //!< No copy assignments + //!@} + + //! \name Common input device interface requirements + //! @{ + private: + size_t get_ (data_t& data) { return impl().get_ (data); } + size_t get_ (data_t* data, size_t n) { return impl().get (data, n); } + //! @} + + /*! + * \name Public Get interface + */ + //!@{ + public: + /*! + * \brief + * Get interface. This function should read + * a single data_t object from device in blocking mode. + * \param data Reference to data output from device. + * \return Number of data read from device + * \note + * A successful call should return 1 + */ + size_t get (data_t& data) { + return get_ (data); + } + + /*! + * \brief + * Old stile get functionality using free standing data_t*. + * This function should return a stream of data from device + * \param data Pointer to buffer to write the data from device. + * \param n The number of data of type data_t to read + * \return The read data items. + */ + size_t get (data_t* data, size_t n) { + return get_ (data, n); + } + //!@} + + /*! + * \name Stream operator >> interface + */ + //!@{ + public: + /*! + * \brief + * Template operator >> implementation for for all by value/ref parameters + * \note + * In the case _Dst_t size is not a integer multiple of device's data size + * this will fail by static assertion + * \param dst Reference to destination + * \return Reference to this device for chaining + */ + template + in_dev_t& operator>> (_Dst_t& dst) { + static_assert ((sizeof (_Dst_t)%sizeof(data_t) == 0), + "Target size must be an integer multiple of device's data size"); + get_ (reinterpret_cast(&dst), sizeof(_Dst_t)/sizeof(data_t)); + return *this; + } + //! Specialization to disallow pointer types as destination + template + in_dev_t& operator>> (_Dst_t* dst) = delete; + + //! Overload for single data_t object + in_dev_t& operator>> (data_t& dst) { + get_ (dst); + return *this; + } + //!@} + + /*! + * \name STL-like Input iterator interface + */ + //!@{ + using iterator = indev_it ; //!< Iterator + using const_iterator = indev_it ; //!< Const iterator + + //!@{ .begin implementation + iterator begin () noexcept { return iterator(this, iterator::init); } + const_iterator begin () const noexcept { return const_iterator(this, iterator::init); } + const_iterator cbegin () const noexcept { return const_iterator(this, iterator::init); } + //!@} + //!@{ .end implementation + iterator end () noexcept { return iterator(this, iterator::eos); } + const_iterator end () const noexcept { return const_iterator(this, iterator::eos); } + const_iterator cend () const noexcept { return const_iterator(this, iterator::eos); } + //!@} + //!@} + }; + + /*! + * \brief + * A virtual base class specialization + * \param impl_t = virtual_tag + * \param data_t The devices base type of data + * \param streamsize_t Type to hold the number of read bytes + */ + template + class in_dev { + //!< class type syntactic sugar + using in_dev_t = in_dev ; + + //! Export types as input device concept demands + //!@{ + public: + using data_type = data_t; + using pointer_type = data_t*; + //!@} + using type = in_dev_t; //!< Export type as identity meta-function + + /*! + * \name Constructor / Destructor + */ + //!@{ + public: + virtual ~in_dev () = default; //!< \brief Virtual destructor + protected: + in_dev () = default; //!< \brief A default constructor from derived only + in_dev(const in_dev_t&) = delete; //!< No copies + in_dev_t& operator= (const in_dev_t&) = delete; //!< No copy assignments + //!@} + + /*! + * \name Common input device interface requirements + */ + //!@{ + private: + /*! + * \brief + * Get interface. This function should read + * a single data_t object from device in blocking mode. + * \param data Reference to data output from device. + * \return Number of data read from device + * \note + * A successful call should return 1 + */ + virtual size_t get_ (data_t& data) = 0; + + /*! + * \brief + * Old stile get functionality using free standing data_t*. + * This function should return a stream of data from device + * \param data Pointer to buffer to write the data from device. + * \param n The number of data of type data_t to read + * \return The read data items. + */ + virtual size_t get_ (data_t* data, size_t n) = 0; + //!@} + + /*! + * \name Public Get interface + */ + //!@{ + public: + size_t get (data_t& data) { return get_ (data); } + size_t get (data_t* data, size_t n) { return get_ (data, n); } + //!@} + + /*! + * \name Stream operator >> interface + */ + //!@{ + public: + /*! + * \brief + * Template operator >> implementation for for all by value/ref parameters + * \note + * In the case _Dst_t size is not a integer multiple of device's data size + * this will fail by static assertion + * \param dst Reference to destination + * \return Reference to this device for chaining + */ + template + in_dev_t& operator>> (_Dst_t& dst) { + static_assert ((sizeof (_Dst_t)%sizeof(data_t) == 0), + "Target size must be an integer multiple of device's data size"); + get_ (reinterpret_cast(&dst), sizeof(_Dst_t)/sizeof(data_t)); + return *this; + } + //! specialization to disallow pointer types as destination + template + in_dev_t& operator>> (_Dst_t* dst) = delete; + + //! Overload for single data_t object + in_dev_t& operator>> (data_t& dst) { + get_ (dst); + return *this; + } + //!@} + + /*! + * \name STL-like Input iterator interface + */ + //!@{ + using iterator = indev_it ; //!< Iterator + using const_iterator = indev_it ; //!< Const iterator + + //!@{ .begin implementation + iterator begin () noexcept { return iterator(this, iterator::init); } + const_iterator begin () const noexcept { return const_iterator(this, iterator::init); } + const_iterator cbegin () const noexcept { return const_iterator(this, iterator::init); } + //!@} + //!@{ .end implementation + iterator end () noexcept { return iterator(this, iterator::eos); } + const_iterator end () const noexcept { return const_iterator(this, iterator::eos); } + const_iterator cend () const noexcept { return const_iterator(this, iterator::eos); } + //!@} + //!@} + }; + + /* + * Input device predicate (concept) + */ + namespace in_dev_details { + using std::declval; + + // main api members + template using try_get1_t = decltype (declval<_Tp>().get (declval())); + template using try_get2_t = decltype (declval<_Tp>().get (declval(), declval())); + // operators + //template using try_extract_t= decltype (declval<_Tp>() >> declval()); + // iterator members + template using try_begin_t = decltype (declval<_Tp>().begin()); + template using tryc_begin_t = decltype (declval().begin()); + template using try_cbegin_t = decltype (declval().cbegin()); + template using try_end_t = decltype (declval<_Tp>().begin()); + template using tryc_end_t = decltype (declval().begin()); + template using try_cend_t = decltype (declval().cend()); + + //! Primary template to catch any non input device types + template + struct is_in_dev_ : false_ {}; + + //! template to catch a proper input device type + template + struct is_in_dev_ <_Tp, + void_t < + typename _Tp::data_type, + typename _Tp::pointer_type, + typename _Tp::iterator, + typename _Tp::const_iterator, + use_if_same_t , size_t>, + use_if_same_t , size_t>, + //if_same_t ,typename _Tp&>, + use_if_same_t , typename _Tp::iterator>, + use_if_same_t , typename _Tp::const_iterator>, + use_if_same_t , typename _Tp::const_iterator>, + use_if_same_t , typename _Tp::iterator>, + use_if_same_t , typename _Tp::const_iterator>, + use_if_same_t , typename _Tp::const_iterator> + > + > : true_ {}; + } + /*! + * Predicate for input device checking + * \param _Tp Type to check + * \return True if _Tp is a input device + */ + template + constexpr bool In_dev = in_dev_details::is_in_dev_ <_Tp>::value; + +} +//!@} + +#endif /* #ifndef __utl_dev_in_dev_h__ */ diff --git a/include/utl/dev/inbuf_dev.h b/include/utl/dev/inbuf_dev.h new file mode 100644 index 0000000..db4f36a --- /dev/null +++ b/include/utl/dev/inbuf_dev.h @@ -0,0 +1,386 @@ +/*! + * \file utl/dev/inbuf_dev.h + * \brief Abstract base class interface for input buffered + * 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_inbuf_dev_h__ +#define __utl_dev_inbuf_dev_h__ + +#include +#include +#include +#include + +namespace utl { + +/*! + * \ingroup Device Interface + * \brief Abstract base class for input buffered devices + */ +//!@{ + + /*! + * \brief + * Template base class for buffered input buffered devices. using CRTP + * + * This class force a common interface for input, buffered devices. + * By using this common interface the class implements + * - Stream-like extracting operator + * - Input iterator + * - Const input 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 + * \param streamsize The number of elements to indicate eos. + * \arg None or 0 Stream only. No iterator as begin() now equals end(). + */ + template + class inbuf_dev { + _CRTP_IMPL(impl_t); + using inbuf_dev_t = inbuf_dev ; //!< class type syntactic sugar + + //! Export types as input device concept demands + //!@{ + public: + using data_type = data_t; + using pointer_type = data_t*; + //!@} + using type = inbuf_dev_t; //!< Export type as identity meta-function + + /*! + * \name Constructor / Destructor + */ + //!@{ + protected: + ~inbuf_dev () = default; //!< \brief Allow destructor from derived only + inbuf_dev () = default; //!< \brief A default constructor from derived only + inbuf_dev(const inbuf_dev_t&) = delete; //!< No copies + inbuf_dev_t& operator= (const inbuf_dev_t&) = delete; //!< No copy assignments + //!@} + + //! \name Common input device interface requirements + //!@{ + private: + size_t in_avail_ () { return impl().in_avail_(); } + size_t get_ (data_t& data) { return impl().get_(data); } + size_t get_ (data_t* data, size_t n) { return impl().get_ (data, n); } + //!@} + + /*! + * \name Public Get interface + */ + //!@{ + public: + /*! + * \return + * The available @a data_t typed items in input buffer. + */ + size_t in_avail () { + return in_avail_ (); + } + + /*! + * \brief + * The base get interface. This function should read + * a single data_t object from device usually in non-blocking mode. + * \param data Reference to data output from device. + * \return Number of data read from device + * \note + * A successful call should return 1 + */ + size_t get (data_t& data) { + return get_ (data); + } + + /*! + * \brief + * Old stile get functionality using free standing data_t*. + * This function should return a stream of data from device + * \param data Pointer to buffer to write the data from device. + * \param n The number of data of type data_t to read + * \return The read data items. + */ + size_t get (data_t* data, size_t n) { + return get_ (data, n); + } + //!@} + + /*! + * \name Stream operator >> interface + */ + //!@{ + public: + /*! + * \brief + * Template operator >> implementation for for all by value/ref parameters + * \note + * In the case _Dst_t size is not a integer multiple of device's data size + * this will fail by static assertion + * \param dst Reference to destination + * \return Reference to this device for chaining + */ + template + inbuf_dev_t& operator>> (_Dst_t& dst) { + static_assert ((sizeof (_Dst_t)%sizeof(data_t) == 0), + "Target size must be an integer multiple of device's data size"); + get_ (reinterpret_cast(&dst), sizeof(_Dst_t)/sizeof(data_t)); + return *this; + } + //! Specialization to disallow pointer types as destination + template + inbuf_dev_t& operator>> (_Dst_t* dst) = delete; + + //! Overload for single data_t object + inbuf_dev_t& operator>> (data_t& dst) { + get_ (dst); + return *this; + } + //!@} + + /*! + * \name STL-like Input iterator interface + */ + //!@{ + using iterator = indev_it ; //!< Iterator + using const_iterator = indev_it ; //!< Const iterator + + //!@{ .begin implementation + iterator begin () noexcept { return iterator(this, iterator::init); } + const_iterator begin () const noexcept { return const_iterator(this, iterator::init); } + const_iterator cbegin () const noexcept { return const_iterator(this, iterator::init); } + //!@} + //!@{ .end implementation + iterator end () noexcept { return iterator(this, iterator::eos); } + const_iterator end () const noexcept { return const_iterator(this, iterator::eos); } + const_iterator cend () const noexcept { return const_iterator(this, iterator::eos); } + //!@} + //!@} + }; + + + + /*! + * \brief + * A virtual base class specialization + * \param impl_t = virtual_tag + * \param data_t The devices base type of data + * \param streamsize The number of elements to indicate eos. + * \arg None or 0 Stream only. No iterator as begin() now equals end(). + */ + template + class inbuf_dev { + //!< class type syntactic sugar + using inbuf_dev_t = inbuf_dev ; + + //! Export types as input device concept demands + //!@{ + public: + using data_type = data_t; + using pointer_type = data_t*; + //!@} + using type = inbuf_dev_t; //!< Export type as identity meta-function + + /*! + * \name Constructor / Destructor + */ + //!@{ + public: + virtual ~inbuf_dev () = default; //!< \brief Virtual destructor + protected: + inbuf_dev () = default; //!< \brief A default constructor from derived only + inbuf_dev(const inbuf_dev_t&) = delete; //!< No copies + inbuf_dev_t& operator= (const inbuf_dev_t&) = delete; //!< No copy assignments + //!@} + + /*! + * \name Common input device interface requirements + */ + //!@{ + private: + /*! + * \return + * The available @a data_t typed items in input buffer. + */ + virtual size_t in_avail_ () = 0; + + /*! + * \brief + * The base get interface. This function should read + * a single data_t object from device usually in non-blocking mode. + * \param data Reference to data output from device. + * \return Number of data read from device + * \note + * A successful call should return 1 + */ + virtual size_t get_ (data_t& data) = 0; + + /*! + * \brief + * Old stile get functionality using free standing data_t*. + * This function should return a stream of data from device + * \param data Pointer to buffer to write the data from device. + * \param n The number of data of type data_t to read + * \return The read data items. + */ + virtual size_t get_ (data_t* data, size_t n) = 0; + //!@} + + /*! + * \name Public Get interface + */ + //!@{ + public: + size_t in_avail() { return in_avail_(); } + size_t get (data_t& data) { return get_ (data); } + size_t get (data_t* data, size_t n) { return get_ (data, n); } + //!@} + + /*! + * \name Stream operator >> interface + */ + //!@{ + /*! + * \brief + * Template operator >> implementation for for all by value/ref parameters + * \note + * In the case _Dst_t size is not a integer multiple of device's data size + * this will fail by static assertion + * \param dst Reference to destination + * \return Reference to this device for chaining + */ + template + inbuf_dev_t& operator>> (_Dst_t& dst) { + static_assert ((sizeof (_Dst_t)%sizeof(data_t) == 0), + "Target size must be an integer multiple of device's data size"); + get_ (reinterpret_cast(&dst), sizeof(_Dst_t)/sizeof(data_t)); + return *this; + } + //! specialization to disallow pointer types as destination + template + inbuf_dev_t& operator>> (_Dst_t* dst) = delete; + + //! Overload for single data_t object + inbuf_dev_t& operator>> (data_t& dst) { + get_ (dst); + return *this; + } + //!@} + + /*! + * \name STL-like Input iterator interface + */ + //!@{ + using iterator = indev_it ; //!< Iterator + using const_iterator = indev_it ; //!< Const iterator + + //!@{ .begin implementation + iterator begin () noexcept { return iterator(this, iterator::init); } + const_iterator begin () const noexcept { return const_iterator(this, iterator::init); } + const_iterator cbegin () const noexcept { return const_iterator(this, iterator::init); } + //!@} + //!@{ .end implementation + iterator end () noexcept { return iterator(this, iterator::eos); } + const_iterator end () const noexcept { return const_iterator(this, iterator::eos); } + const_iterator cend () const noexcept { return const_iterator(this, iterator::eos); } + //!@} + //!@} + }; + +/*! + * Input buffer device concept + */ +//! @{ +#if defined _utl_have_concepts + template + concept bool Inbuf_dev = requires (_Tp t, const _Tp ct, typename _Tp::data_type v) { + // Object type +// requires std::is_default_constructible<_Tp>::value; + requires !std::is_copy_constructible<_Tp>::value; + requires !std::is_copy_assignable<_Tp>::value; + // Methods + {t.get(v, 0)} -> size_t; + {t.get(&v, 1, 0)} -> size_t; + // Operators + t >> v; + // Iterators + typename _Tp::const_iterator; //XXX: change to concept: is_idxdev_iterator<_Tp> + requires Indev_it; + //requires Indev_it; + { t.begin() } -> typename _Tp::iterator; +// {ct.begin()} -> typename _Tp::const_iterator; +// { t.cbegin()} -> typename _Tp::const_iterator; + { t.end() } -> typename _Tp::iterator; +// {ct.end()} -> typename _Tp::const_iterator; +// { t.cend()} -> typename _Tp::const_iterator; + }; +#else + namespace inbuf_dev_details { + using std::declval; + + // main api members + template using try_get1_t = decltype (declval<_Tp>().get (declval())); + template using try_get2_t = decltype (declval<_Tp>().get (declval(), declval())); + // operators + //template using try_extract_t= decltype (declval<_Tp>() >> declval()); + // iterator members + template using try_begin_t = decltype (declval<_Tp>().begin()); + template using tryc_begin_t = decltype (declval().begin()); + template using try_cbegin_t = decltype (declval().cbegin()); + template using try_end_t = decltype (declval<_Tp>().begin()); + template using tryc_end_t = decltype (declval().begin()); + template using try_cend_t = decltype (declval().cend()); + + //! Primary template to catch any non input device types + template + struct is_inbuf_dev_ : false_ {}; + + //! template to catch a proper input device type + template + struct is_inbuf_dev_ <_Tp, + void_t < + typename _Tp::data_type, + typename _Tp::pointer_type, + typename _Tp::iterator, + typename _Tp::const_iterator, + use_if_same_t , size_t>, + use_if_same_t , size_t>, + //if_same_t ,typename _Tp&>, + use_if_same_t , typename _Tp::iterator>, + use_if_same_t , typename _Tp::const_iterator>, + use_if_same_t , typename _Tp::const_iterator>, + use_if_same_t , typename _Tp::iterator>, + use_if_same_t , typename _Tp::const_iterator>, + use_if_same_t , typename _Tp::const_iterator> + > + > : true_ {}; + } + /*! + * Predicate for input device checking + * \param _Tp Type to check + * \return True if _Tp is a input device + */ + template + constexpr bool Inbuf_dev = inbuf_dev_details::is_inbuf_dev_ <_Tp>::value; +#endif +//!@} +} + +//!@} +#endif /* #ifndef __utl_dev_inbuf_dev_h__ */ diff --git a/include/utl/dev/out_dev.h b/include/utl/dev/out_dev.h new file mode 100644 index 0000000..a86a493 --- /dev/null +++ b/include/utl/dev/out_dev.h @@ -0,0 +1,365 @@ +/*! + * \file utl/dev/out_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_out_dev_h__ +#define __utl_dev_out_dev_h__ + +#include +#include +#include +#include + +namespace utl { + +/*! + * \ingroup Device Interface + * \brief Abstract base class for output devices + */ +//!@{ + + /*! + * \brief + * Template base class for output devices. using CRTP + * + * This class force a common interface for output 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 + * \param streamsize The number of elements to indicate eos. + * \arg None or 0 Stream only. No iterator as begin() now equals end(). + */ + template + class out_dev { + _CRTP_IMPL(impl_t); + using out_dev_t = out_dev ; //!< class type syntactic sugar + + //! Export types as input device concept demands + //! @{ + public: + using data_type = data_t; + using pointer_type = data_t*; + //!@} + using type = out_dev_t; //!< Export type as identity meta-function + + /*! + * \name Constructor / Destructor + */ + //!@{ + protected: + ~out_dev () = default; //!< \brief Allow destructor from derived only + out_dev () = default; //!< \brief A default constructor from derived only + out_dev(const out_dev_t&) = delete; //!< No copies + out_dev_t& operator= (const out_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 + out_dev_t& operator<< (_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; + } + //! specialization to disallow pointer types as source + template + out_dev_t& operator<< (_Src_t* src) = delete; + + //! Overload for single data_t object + out_dev_t& operator<< (const data_t& src) { + put_ (src); + return *this; + } + //!@} + + /*! + * \name STL-like Output iterator interface + */ + //!@{ + using iterator = outdev_it ; //!< Iterator + using const_iterator = outdev_it ; //!< Const iterator + + //!@{ .begin implementation + iterator begin () noexcept { return iterator(this, iterator::beg); } + const_iterator begin () const noexcept { return const_iterator(this, iterator::beg); } + const_iterator cbegin () const noexcept { return const_iterator(this, iterator::beg); } + //!@} + //!@{ .end implementation + iterator end () noexcept { return iterator(this, iterator::eos); } + const_iterator end () const noexcept { return const_iterator(this, iterator::eos); } + const_iterator cend () const noexcept { return const_iterator(this, iterator::eos); } + //!@} + //!@} + }; + + /*! + * \brief + * A virtual base class specialization + * \param impl_t = virtual_tag + * \param data_t The devices base type of data + * \param streamsize The number of elements to indicate eos. + * \arg None or 0 Stream only. No iterator as begin() now equals end(). + */ + template + class out_dev { + using out_dev_t = out_dev ; //!< class type syntactic sugar + + //! Export types as input device concept demands + //! @{ + public: + using data_type = data_t; + using pointer_type = data_t*; + //! @} + using type = out_dev_t; //!< Export type as identity meta-function + + /*! + * \name Constructor / Destructor + */ + //!@{ + public: + virtual ~out_dev () = default; //!< \brief Virtual destructor + protected: + out_dev () = default; //!< \brief A default constructor from derived only + out_dev(const out_dev&) = delete; //!< No copies + out_dev_t& operator= (const out_dev_t&) = delete; //!< No copy assignments + //!@} + + /*! + * \name Common output device interface requirements + */ + //!@{ + private: + /*! + * \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 + */ + virtual size_t put_ (const data_t& data) = 0; + + /*! + * \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. + */ + virtual size_t put_ (const data_t* data, size_t n) = 0; + //!@} + /*! + * \name Public Put interface + */ + //!@{ + public: + size_t put (const data_t& data) { return put_ (data); } + 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 + * \param src Reference to source data + * \return Reference to this device for chaining + */ + template + out_dev_t& operator<< (_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; + } + //! specialization to disallow pointer types as source + template + out_dev_t& operator<< (_Src_t* src) = delete; + + //! Overload for single data_t object + out_dev_t& operator<< (const data_t& src) { + put_ (src); + return *this; + } + //!@} + + /*! + * \name STL-like Output iterator interface + */ + //!@{ + using iterator = outdev_it ; //!< Iterator + using const_iterator = outdev_it ; //!< Const iterator + + //!@{ .begin implementation + iterator begin () noexcept { return iterator(this, iterator::beg); } + const_iterator begin () const noexcept { return const_iterator(this, iterator::beg); } + const_iterator cbegin () const noexcept { return const_iterator(this, iterator::beg); } + //!@} + //!@{ .end implementation + iterator end () noexcept { return iterator(this, iterator::eos); } + const_iterator end () const noexcept { return const_iterator(this, iterator::eos); } + const_iterator cend () const noexcept { return const_iterator(this, iterator::eos); } + //!@} + //!@} + }; + + + /*! + * Output device concept + */ + //! @{ + #if defined _utl_have_concepts + template + concept bool Out_dev = requires (_Tp t, const _Tp ct, typename _Tp::data_type v) { + // Object type + // requires std::is_default_constructible<_Tp>::value; + requires !std::is_copy_constructible<_Tp>::value; + requires !std::is_copy_assignable<_Tp>::value; + // Methods + {t.put(v)} -> size_t; + {t.put(&v, sizeof(v))} -> size_t; + // Operators + t << v; + // Iterators + typename _Tp::const_iterator; //XXX: change to concept: is_idxdev_iterator<_Tp> + requires Outdev_it; +// requires Outdev_it; + { t.begin() } -> typename _Tp::iterator; + {ct.begin()} -> typename _Tp::const_iterator; + // { t.cbegin()} -> typename _Tp::const_iterator; + { t.end() } -> typename _Tp::iterator; +// {ct.end()} -> typename _Tp::const_iterator; + // { t.cend()} -> typename _Tp::const_iterator; + }; + #else + namespace out_dev_details { + using std::declval; + + template using try_put1_t = decltype (declval<_Tp>().put (declval())); + template using try_put2_t = decltype (declval<_Tp>().put (declval(), + declval())); + // operators + //template using try_insert_t= decltype (declval<_Tp>() << declval()); + // iterator members + template using try_begin_t = decltype (declval<_Tp>().begin()); + template using tryc_begin_t = decltype (declval().begin()); + template using try_cbegin_t = decltype (declval().cbegin()); + template using try_end_t = decltype (declval<_Tp>().begin()); + template using tryc_end_t = decltype (declval().begin()); + template using try_cend_t = decltype (declval().cend()); + + //! Primary template to catch any non output device types + template + struct is_out_dev_ : false_ { }; + + //! template to catch a proper output device type + template + struct is_out_dev_ <_Tp, + void_t < + typename _Tp::data_type, + typename _Tp::pointer_type, + typename _Tp::iterator, + typename _Tp::const_iterator, + use_if_same_t , size_t>, + use_if_same_t , size_t>, + //if_same_t ,_Tp&>, + use_if_same_t , typename _Tp::iterator>, + use_if_same_t , typename _Tp::const_iterator>, + use_if_same_t , typename _Tp::const_iterator>, + use_if_same_t , typename _Tp::iterator>, + use_if_same_t , typename _Tp::const_iterator>, + use_if_same_t , typename _Tp::const_iterator> + > + > : true_ { }; + } + /*! + * Predicate for output device checking + * \param _Tp Type to check + * \return True if _Tp is a output device + */ + template + constexpr bool Out_dev = out_dev_details::is_out_dev_<_Tp>::value; + #endif + //!@} + +//!@} +} //namespace utl + +#endif /* #ifndef __utl_dev_out_dev_h__ */