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