dev: A first non-working version of dev added
A first group of device interface base classes added.
This commit is contained in:
parent
5d1b3636f3
commit
03620c831f
854
include/utl/dev/dev_iterators.h
Normal file
854
include/utl/dev/dev_iterators.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef __utl_dev_dev_iterators_h__
|
||||||
|
#define __utl_dev_dev_iterators_h__
|
||||||
|
|
||||||
|
#include <utl/impl/impl.h>
|
||||||
|
#include <utl/meta/sfinae.h>
|
||||||
|
|
||||||
|
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 <typename _Cat, typename _Tp, typename _Diff =ptrdiff_t>
|
||||||
|
struct dev_iterator_traits { };
|
||||||
|
|
||||||
|
//! Partial specialization for pointer types.
|
||||||
|
template<typename _Cat, typename _Tp, typename _Diff>
|
||||||
|
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<typename _Cat, typename _Tp, typename _Diff>
|
||||||
|
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<typename container_t, typename iter_t, size_t streamsize =0>
|
||||||
|
class outdev_it {
|
||||||
|
//! iterator type local name
|
||||||
|
using iterator_t = outdev_it <container_t, iter_t, streamsize>;
|
||||||
|
|
||||||
|
//! STL iterator traits "forwarding"
|
||||||
|
//!@{
|
||||||
|
public:
|
||||||
|
using iterator_category = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::iterator_category;
|
||||||
|
using value_type = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::value_type;
|
||||||
|
using difference_type = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::difference_type;
|
||||||
|
using pointer = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::pointer;
|
||||||
|
using reference = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::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<container_t*>(it.owner())},
|
||||||
|
cursor_ {it.cursor()} { }
|
||||||
|
//! \brief Iterator to const-iterator conversion (as STL requires)
|
||||||
|
//! \param it Iterator reference
|
||||||
|
template<typename _It>
|
||||||
|
outdev_it (const outdev_it<
|
||||||
|
use_if_same_t <_It, typename container_t::pointer_type, container_t>,
|
||||||
|
_It,
|
||||||
|
streamsize
|
||||||
|
>& it) noexcept
|
||||||
|
: owner_ {const_cast<container_t*>(it.owner())},
|
||||||
|
cursor_ {it.cursor()} { }
|
||||||
|
//! \brief Basic copy assignment operator
|
||||||
|
iterator_t& operator= (const iterator_t& it) noexcept {
|
||||||
|
owner_ = const_cast<container_t*>(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 <size_t S =streamsize>
|
||||||
|
use_if_t <(S == 0), iterator_t&> operator++ () noexcept { *this; }
|
||||||
|
template <size_t S =streamsize>
|
||||||
|
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 <size_t S =streamsize>
|
||||||
|
use_if_t <(S != 0), iterator_t&> operator++ () noexcept {
|
||||||
|
++cursor_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
template <size_t S =streamsize>
|
||||||
|
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<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
|
||||||
|
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<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
|
||||||
|
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<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
|
||||||
|
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<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
|
||||||
|
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<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
|
||||||
|
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<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
|
||||||
|
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 <typename T>
|
||||||
|
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 <typename _Tp, typename =void>
|
||||||
|
struct is_outdev_it_ : false_ {};
|
||||||
|
|
||||||
|
//! template to catch a proper SPI interface type
|
||||||
|
template <typename _Tp>
|
||||||
|
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 <typename _Tp>
|
||||||
|
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<typename container_t, typename iter_t, size_t streamsize>
|
||||||
|
class indev_it {
|
||||||
|
using iterator_t = indev_it <container_t, iter_t, streamsize>; //!< iterator type local name
|
||||||
|
//! STL iterator traits "forwarding"
|
||||||
|
//!@{
|
||||||
|
public:
|
||||||
|
using iterator_category = typename dev_iterator_traits <std::input_iterator_tag, iter_t>::iterator_category;
|
||||||
|
using value_type = typename dev_iterator_traits <std::input_iterator_tag, iter_t>::value_type;
|
||||||
|
using difference_type = typename dev_iterator_traits <std::input_iterator_tag, iter_t>::difference_type;
|
||||||
|
using pointer = typename dev_iterator_traits <std::input_iterator_tag, iter_t>::pointer;
|
||||||
|
using reference = typename dev_iterator_traits <std::input_iterator_tag, iter_t>::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<container_t*>(it.owner())},
|
||||||
|
cursor_{it.cursor()},
|
||||||
|
value_ {it.value()} { }
|
||||||
|
//! \brief Iterator to const-iterator conversion (as STL requires)
|
||||||
|
//! \param it Iterator reference
|
||||||
|
template<typename _It>
|
||||||
|
indev_it (const indev_it<
|
||||||
|
use_if_same_t <_It, typename container_t::pointer_type, container_t>,
|
||||||
|
_It,
|
||||||
|
streamsize
|
||||||
|
>& it) noexcept
|
||||||
|
: owner_ {const_cast<container_t*>(it.owner())},
|
||||||
|
cursor_{it.cursor()},
|
||||||
|
value_ {it.value()} { }
|
||||||
|
//! \brief Basic copy assignment operator
|
||||||
|
iterator_t& operator= (const iterator_t& it) noexcept {
|
||||||
|
owner_ = const_cast<container_t*>(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<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
|
||||||
|
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<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
|
||||||
|
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<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
|
||||||
|
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<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
|
||||||
|
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<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
|
||||||
|
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<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
|
||||||
|
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 <typename T>
|
||||||
|
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 <typename _Tp, typename =void>
|
||||||
|
struct is_indev_it_ : false_ {};
|
||||||
|
|
||||||
|
//! template to catch a proper SPI interface type
|
||||||
|
template <typename _Tp>
|
||||||
|
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 <typename _Tp>
|
||||||
|
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<typename container_t, typename iter_t, size_t N>
|
||||||
|
class idxdev_it {
|
||||||
|
using iterator_t = idxdev_it <container_t, iter_t, N>; //!< iterator type local name
|
||||||
|
|
||||||
|
//!@{ STL iterator traits "forwarding"
|
||||||
|
public:
|
||||||
|
using iterator_category = typename dev_iterator_traits <std::input_iterator_tag, iter_t, size_t>::iterator_category;
|
||||||
|
using value_type = typename dev_iterator_traits <std::input_iterator_tag, iter_t, size_t>::value_type;
|
||||||
|
using difference_type = typename dev_iterator_traits <std::input_iterator_tag, iter_t, size_t>::difference_type;
|
||||||
|
using pointer = typename dev_iterator_traits <std::input_iterator_tag, iter_t, size_t>::pointer;
|
||||||
|
using reference = typename dev_iterator_traits <std::input_iterator_tag, iter_t, size_t>::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<container_t*> (it.owner())},
|
||||||
|
cursor_{it.cursor()},
|
||||||
|
value_ {it.value()} { }
|
||||||
|
//! \brief Iterator to const iterator conversion (as STL requires)
|
||||||
|
//! \param it Iterator reference
|
||||||
|
template<typename _It>
|
||||||
|
idxdev_it (const idxdev_it<
|
||||||
|
use_if_same_t <_It, typename container_t::pointer_type, container_t>,
|
||||||
|
_It,
|
||||||
|
N
|
||||||
|
>& it) noexcept
|
||||||
|
: owner_ {const_cast<container_t*> (it.owner())},
|
||||||
|
cursor_{it.cursor()},
|
||||||
|
value_ {it.value()} {
|
||||||
|
|
||||||
|
}
|
||||||
|
//! \brief Basic copy assignment operator
|
||||||
|
iterator_t& operator= (const iterator_t& it) noexcept {
|
||||||
|
owner_ = const_cast<container_t*>(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<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
|
||||||
|
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<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
|
||||||
|
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<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
|
||||||
|
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<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
|
||||||
|
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<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
|
||||||
|
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<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
|
||||||
|
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 <typename T>
|
||||||
|
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 <typename _Tp, typename =void>
|
||||||
|
struct is_idxdev_it_ : false_ {};
|
||||||
|
|
||||||
|
//! template to catch a proper SPI interface type
|
||||||
|
template <typename _Tp>
|
||||||
|
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 <typename _Tp>
|
||||||
|
constexpr bool Idxdev_it = idxdev_it_details::is_idxdev_it_<_Tp>::value;
|
||||||
|
#endif
|
||||||
|
//! @}
|
||||||
|
|
||||||
|
}
|
||||||
|
//!@}
|
||||||
|
#endif /* __utl_dev_dev_iterators_h__ */
|
530
include/utl/dev/idx_dev.h
Normal file
530
include/utl/dev/idx_dev.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef __utl_dev_idx_dev_h__
|
||||||
|
#define __utl_dev_idx_dev_h__
|
||||||
|
|
||||||
|
#include <utl/impl/impl.h>
|
||||||
|
#include <utl/helper/crtp.h>
|
||||||
|
#include <utl/meta/sfinae.h>
|
||||||
|
#include <utl/dev/dev_iterators.h>
|
||||||
|
|
||||||
|
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 <typename impl_t, typename data_t, typename idx_t, size_t N>
|
||||||
|
class idx_dev {
|
||||||
|
_CRTP_IMPL(impl_t);
|
||||||
|
using idx_dev_t = idx_dev <impl_t, data_t, idx_t, N>; //!< 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 <typename _Dst_t>
|
||||||
|
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<data_t*>(&dst), sizeof(_Dst_t)/sizeof(data_t), cursor_());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//! Specialization to disallow pointer types as destination
|
||||||
|
template <typename _Dst_t>
|
||||||
|
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 <typename _Src_t>
|
||||||
|
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<data_t*>(&src), sizeof (_Src_t)/sizeof(data_t), cursor_());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//! specialization to disallow pointer types as source
|
||||||
|
template <typename _Src_t>
|
||||||
|
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 <idx_dev_t, data_t*, N>; //!< Iterator
|
||||||
|
using const_iterator = idxdev_it <idx_dev_t, const data_t*, N>; //!< 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 <typename data_t, typename idx_t, size_t N>
|
||||||
|
class idx_dev <virtual_tag, data_t, idx_t, N> {
|
||||||
|
using idx_dev_t = idx_dev <virtual_tag, data_t, idx_t, N>; //!< 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 <typename _Dst_t>
|
||||||
|
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<data_t*>(&dst), sizeof(_Dst_t)/sizeof(data_t), cursor_());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//! specialization to disallow pointer types as destination
|
||||||
|
template <typename _Dst_t>
|
||||||
|
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 <typename _Src_t>
|
||||||
|
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<data_t*>(&src), sizeof (_Src_t)/sizeof(data_t), cursor_());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//! specialization to disallow pointer types as source
|
||||||
|
template <typename _Src_t>
|
||||||
|
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 <idx_dev_t, data_t*, N>; //!< Iterator
|
||||||
|
using const_iterator = idxdev_it <idx_dev_t, const data_t*, N>; //!< 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 <typename _Tp>
|
||||||
|
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::iterator>;
|
||||||
|
typename _Tp::const_iterator; //XXX: change to concept: is_idxdev_iterator<_Tp>
|
||||||
|
//requires idxdev_iterator_c<typename _Tp::const_iterator>;
|
||||||
|
{ 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 <class _Tp> using try_get1_t = decltype (declval<_Tp>().get (declval<typename _Tp::data_type&>()));
|
||||||
|
template <class _Tp> using try_get2_t = decltype (declval<_Tp>().get (declval<typename _Tp::data_type*>(), declval<size_t>()));
|
||||||
|
// operators
|
||||||
|
//template <class _Tp> using try_extract_t= decltype (declval<_Tp>() >> declval<typename _Tp::data_type&>());
|
||||||
|
// iterator members
|
||||||
|
template <class _Tp> using try_begin_t = decltype (declval<_Tp>().begin());
|
||||||
|
template <class _Tp> using tryc_begin_t = decltype (declval<const _Tp>().begin());
|
||||||
|
template <class _Tp> using try_cbegin_t = decltype (declval<const _Tp>().cbegin());
|
||||||
|
template <class _Tp> using try_end_t = decltype (declval<_Tp>().begin());
|
||||||
|
template <class _Tp> using tryc_end_t = decltype (declval<const _Tp>().begin());
|
||||||
|
template <class _Tp> using try_cend_t = decltype (declval<const _Tp>().cend());
|
||||||
|
|
||||||
|
//! Primary template to catch any non input device types
|
||||||
|
template <typename _Tp, typename =void>
|
||||||
|
struct is_idx_dev_ : false_ {};
|
||||||
|
|
||||||
|
//! template to catch a proper input device type
|
||||||
|
template <typename _Tp>
|
||||||
|
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 <try_get1_t <_Tp>, size_t>,
|
||||||
|
use_if_same_t <try_get2_t <_Tp>, size_t>,
|
||||||
|
//if_same_t <try_extract_t<_Tp>,typename _Tp&>,
|
||||||
|
use_if_same_t <try_begin_t<_Tp>, typename _Tp::iterator>,
|
||||||
|
use_if_same_t <tryc_begin_t<_Tp>, typename _Tp::const_iterator>,
|
||||||
|
use_if_same_t <try_cbegin_t<_Tp>, typename _Tp::const_iterator>,
|
||||||
|
use_if_same_t <try_end_t<_Tp>, typename _Tp::iterator>,
|
||||||
|
use_if_same_t <tryc_end_t<_Tp>, typename _Tp::const_iterator>,
|
||||||
|
use_if_same_t <try_cend_t<_Tp>, typename _Tp::const_iterator>
|
||||||
|
>
|
||||||
|
> : true_ {};
|
||||||
|
}
|
||||||
|
/*!
|
||||||
|
* Predicate for input device checking
|
||||||
|
* \param _Tp Type to check
|
||||||
|
* \return True if _Tp is a input device
|
||||||
|
*/
|
||||||
|
template <typename _Tp>
|
||||||
|
constexpr bool Idx_dev = idx_dev_details::is_idx_dev_ <_Tp>::value;
|
||||||
|
#endif
|
||||||
|
//!@}
|
||||||
|
|
||||||
|
}
|
||||||
|
//!@}
|
||||||
|
|
||||||
|
#endif /* #ifndef __utl_dev_idx_dev_h__ */
|
340
include/utl/dev/in_dev.h
Normal file
340
include/utl/dev/in_dev.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef __utl_dev_in_dev_h__
|
||||||
|
#define __utl_dev_in_dev_h__
|
||||||
|
|
||||||
|
#include <utl/impl/impl.h>
|
||||||
|
#include <utl/helper/crtp.h>
|
||||||
|
#include <utl/meta/sfinae.h>
|
||||||
|
#include <utl/dev/dev_iterators.h>
|
||||||
|
|
||||||
|
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 <typename impl_t, typename data_t, size_t streamsize =0>
|
||||||
|
class in_dev {
|
||||||
|
_CRTP_IMPL(impl_t);
|
||||||
|
using in_dev_t = in_dev <impl_t, data_t, streamsize>; //!< 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 <typename _Dst_t>
|
||||||
|
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<data_t*>(&dst), sizeof(_Dst_t)/sizeof(data_t));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//! Specialization to disallow pointer types as destination
|
||||||
|
template <typename _Dst_t>
|
||||||
|
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 <in_dev_t, data_t*, streamsize>; //!< Iterator
|
||||||
|
using const_iterator = indev_it <in_dev_t, const data_t*, streamsize>; //!< 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 <typename data_t, size_t streamsize>
|
||||||
|
class in_dev <virtual_tag, data_t, streamsize> {
|
||||||
|
//!< class type syntactic sugar
|
||||||
|
using in_dev_t = in_dev <virtual_tag, data_t, streamsize>;
|
||||||
|
|
||||||
|
//! 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 <typename _Dst_t>
|
||||||
|
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<data_t*>(&dst), sizeof(_Dst_t)/sizeof(data_t));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//! specialization to disallow pointer types as destination
|
||||||
|
template <typename _Dst_t>
|
||||||
|
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 <in_dev_t, data_t*, streamsize>; //!< Iterator
|
||||||
|
using const_iterator = indev_it <in_dev_t, const data_t*, streamsize>; //!< 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 <class _Tp> using try_get1_t = decltype (declval<_Tp>().get (declval<typename _Tp::data_type&>()));
|
||||||
|
template <class _Tp> using try_get2_t = decltype (declval<_Tp>().get (declval<typename _Tp::data_type*>(), declval<size_t>()));
|
||||||
|
// operators
|
||||||
|
//template <class _Tp> using try_extract_t= decltype (declval<_Tp>() >> declval<typename _Tp::data_type&>());
|
||||||
|
// iterator members
|
||||||
|
template <class _Tp> using try_begin_t = decltype (declval<_Tp>().begin());
|
||||||
|
template <class _Tp> using tryc_begin_t = decltype (declval<const _Tp>().begin());
|
||||||
|
template <class _Tp> using try_cbegin_t = decltype (declval<const _Tp>().cbegin());
|
||||||
|
template <class _Tp> using try_end_t = decltype (declval<_Tp>().begin());
|
||||||
|
template <class _Tp> using tryc_end_t = decltype (declval<const _Tp>().begin());
|
||||||
|
template <class _Tp> using try_cend_t = decltype (declval<const _Tp>().cend());
|
||||||
|
|
||||||
|
//! Primary template to catch any non input device types
|
||||||
|
template <typename _Tp, typename =void>
|
||||||
|
struct is_in_dev_ : false_ {};
|
||||||
|
|
||||||
|
//! template to catch a proper input device type
|
||||||
|
template <typename _Tp>
|
||||||
|
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 <try_get1_t <_Tp>, size_t>,
|
||||||
|
use_if_same_t <try_get2_t <_Tp>, size_t>,
|
||||||
|
//if_same_t <try_extract_t<_Tp>,typename _Tp&>,
|
||||||
|
use_if_same_t <try_begin_t<_Tp>, typename _Tp::iterator>,
|
||||||
|
use_if_same_t <tryc_begin_t<_Tp>, typename _Tp::const_iterator>,
|
||||||
|
use_if_same_t <try_cbegin_t<_Tp>, typename _Tp::const_iterator>,
|
||||||
|
use_if_same_t <try_end_t<_Tp>, typename _Tp::iterator>,
|
||||||
|
use_if_same_t <tryc_end_t<_Tp>, typename _Tp::const_iterator>,
|
||||||
|
use_if_same_t <try_cend_t<_Tp>, typename _Tp::const_iterator>
|
||||||
|
>
|
||||||
|
> : true_ {};
|
||||||
|
}
|
||||||
|
/*!
|
||||||
|
* Predicate for input device checking
|
||||||
|
* \param _Tp Type to check
|
||||||
|
* \return True if _Tp is a input device
|
||||||
|
*/
|
||||||
|
template <typename _Tp>
|
||||||
|
constexpr bool In_dev = in_dev_details::is_in_dev_ <_Tp>::value;
|
||||||
|
|
||||||
|
}
|
||||||
|
//!@}
|
||||||
|
|
||||||
|
#endif /* #ifndef __utl_dev_in_dev_h__ */
|
386
include/utl/dev/inbuf_dev.h
Normal file
386
include/utl/dev/inbuf_dev.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef __utl_dev_inbuf_dev_h__
|
||||||
|
#define __utl_dev_inbuf_dev_h__
|
||||||
|
|
||||||
|
#include <utl/impl/impl.h>
|
||||||
|
#include <utl/helper/crtp.h>
|
||||||
|
#include <utl/meta/sfinae.h>
|
||||||
|
#include <utl/dev/dev_iterators.h>
|
||||||
|
|
||||||
|
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 <typename impl_t, typename data_t, size_t streamsize =0>
|
||||||
|
class inbuf_dev {
|
||||||
|
_CRTP_IMPL(impl_t);
|
||||||
|
using inbuf_dev_t = inbuf_dev <impl_t, data_t, streamsize>; //!< 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 <typename _Dst_t>
|
||||||
|
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<data_t*>(&dst), sizeof(_Dst_t)/sizeof(data_t));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//! Specialization to disallow pointer types as destination
|
||||||
|
template <typename _Dst_t>
|
||||||
|
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 <inbuf_dev_t, data_t*, streamsize>; //!< Iterator
|
||||||
|
using const_iterator = indev_it <inbuf_dev_t, const data_t*, streamsize>; //!< 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 <typename data_t, size_t streamsize>
|
||||||
|
class inbuf_dev <virtual_tag, data_t, streamsize> {
|
||||||
|
//!< class type syntactic sugar
|
||||||
|
using inbuf_dev_t = inbuf_dev <virtual_tag, data_t, streamsize>;
|
||||||
|
|
||||||
|
//! 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 <typename _Dst_t>
|
||||||
|
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<data_t*>(&dst), sizeof(_Dst_t)/sizeof(data_t));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//! specialization to disallow pointer types as destination
|
||||||
|
template <typename _Dst_t>
|
||||||
|
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 <inbuf_dev_t, data_t*, streamsize>; //!< Iterator
|
||||||
|
using const_iterator = indev_it <inbuf_dev_t, const data_t*, streamsize>; //!< 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 <typename _Tp>
|
||||||
|
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<typename _Tp::iterator>;
|
||||||
|
//requires Indev_it<typename _Tp::const_iterator>;
|
||||||
|
{ 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 <class _Tp> using try_get1_t = decltype (declval<_Tp>().get (declval<typename _Tp::data_type&>()));
|
||||||
|
template <class _Tp> using try_get2_t = decltype (declval<_Tp>().get (declval<typename _Tp::data_type*>(), declval<size_t>()));
|
||||||
|
// operators
|
||||||
|
//template <class _Tp> using try_extract_t= decltype (declval<_Tp>() >> declval<typename _Tp::data_type&>());
|
||||||
|
// iterator members
|
||||||
|
template <class _Tp> using try_begin_t = decltype (declval<_Tp>().begin());
|
||||||
|
template <class _Tp> using tryc_begin_t = decltype (declval<const _Tp>().begin());
|
||||||
|
template <class _Tp> using try_cbegin_t = decltype (declval<const _Tp>().cbegin());
|
||||||
|
template <class _Tp> using try_end_t = decltype (declval<_Tp>().begin());
|
||||||
|
template <class _Tp> using tryc_end_t = decltype (declval<const _Tp>().begin());
|
||||||
|
template <class _Tp> using try_cend_t = decltype (declval<const _Tp>().cend());
|
||||||
|
|
||||||
|
//! Primary template to catch any non input device types
|
||||||
|
template <typename _Tp, typename =void>
|
||||||
|
struct is_inbuf_dev_ : false_ {};
|
||||||
|
|
||||||
|
//! template to catch a proper input device type
|
||||||
|
template <typename _Tp>
|
||||||
|
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 <try_get1_t <_Tp>, size_t>,
|
||||||
|
use_if_same_t <try_get2_t <_Tp>, size_t>,
|
||||||
|
//if_same_t <try_extract_t<_Tp>,typename _Tp&>,
|
||||||
|
use_if_same_t <try_begin_t<_Tp>, typename _Tp::iterator>,
|
||||||
|
use_if_same_t <tryc_begin_t<_Tp>, typename _Tp::const_iterator>,
|
||||||
|
use_if_same_t <try_cbegin_t<_Tp>, typename _Tp::const_iterator>,
|
||||||
|
use_if_same_t <try_end_t<_Tp>, typename _Tp::iterator>,
|
||||||
|
use_if_same_t <tryc_end_t<_Tp>, typename _Tp::const_iterator>,
|
||||||
|
use_if_same_t <try_cend_t<_Tp>, typename _Tp::const_iterator>
|
||||||
|
>
|
||||||
|
> : true_ {};
|
||||||
|
}
|
||||||
|
/*!
|
||||||
|
* Predicate for input device checking
|
||||||
|
* \param _Tp Type to check
|
||||||
|
* \return True if _Tp is a input device
|
||||||
|
*/
|
||||||
|
template <typename _Tp>
|
||||||
|
constexpr bool Inbuf_dev = inbuf_dev_details::is_inbuf_dev_ <_Tp>::value;
|
||||||
|
#endif
|
||||||
|
//!@}
|
||||||
|
}
|
||||||
|
|
||||||
|
//!@}
|
||||||
|
#endif /* #ifndef __utl_dev_inbuf_dev_h__ */
|
365
include/utl/dev/out_dev.h
Normal file
365
include/utl/dev/out_dev.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef __utl_dev_out_dev_h__
|
||||||
|
#define __utl_dev_out_dev_h__
|
||||||
|
|
||||||
|
#include <utl/impl/impl.h>
|
||||||
|
#include <utl/helper/crtp.h>
|
||||||
|
#include <utl/meta/sfinae.h>
|
||||||
|
#include <utl/dev/dev_iterators.h>
|
||||||
|
|
||||||
|
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 <typename impl_t, typename data_t, size_t streamsize =0>
|
||||||
|
class out_dev {
|
||||||
|
_CRTP_IMPL(impl_t);
|
||||||
|
using out_dev_t = out_dev <impl_t, data_t, streamsize>; //!< 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 <typename _Src_t>
|
||||||
|
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<data_t*>(&src), sizeof(_Src_t)/sizeof(data_t));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//! specialization to disallow pointer types as source
|
||||||
|
template <typename _Src_t>
|
||||||
|
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 <out_dev_t, data_t*, streamsize>; //!< Iterator
|
||||||
|
using const_iterator = outdev_it <out_dev_t, const data_t*, streamsize>; //!< 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 <typename data_t, size_t streamsize>
|
||||||
|
class out_dev <virtual_tag, data_t, streamsize> {
|
||||||
|
using out_dev_t = out_dev <virtual_tag, data_t, streamsize>; //!< 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 <typename _Src_t>
|
||||||
|
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<data_t*>(&src), sizeof(_Src_t)/sizeof(data_t));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//! specialization to disallow pointer types as source
|
||||||
|
template <typename _Src_t>
|
||||||
|
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 <out_dev_t, data_t*, streamsize>; //!< Iterator
|
||||||
|
using const_iterator = outdev_it <out_dev_t, const data_t*, streamsize>; //!< 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 <typename _Tp>
|
||||||
|
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<typename _Tp::iterator>;
|
||||||
|
// requires Outdev_it<typename _Tp::const_iterator>;
|
||||||
|
{ 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 <class _Tp> using try_put1_t = decltype (declval<_Tp>().put (declval<const typename _Tp::data_type&>()));
|
||||||
|
template <class _Tp> using try_put2_t = decltype (declval<_Tp>().put (declval<const typename _Tp::data_type*>(),
|
||||||
|
declval<size_t>()));
|
||||||
|
// operators
|
||||||
|
//template <class _Tp> using try_insert_t= decltype (declval<_Tp>() << declval<typename _Tp::data_type&>());
|
||||||
|
// iterator members
|
||||||
|
template <class _Tp> using try_begin_t = decltype (declval<_Tp>().begin());
|
||||||
|
template <class _Tp> using tryc_begin_t = decltype (declval<const _Tp>().begin());
|
||||||
|
template <class _Tp> using try_cbegin_t = decltype (declval<const _Tp>().cbegin());
|
||||||
|
template <class _Tp> using try_end_t = decltype (declval<_Tp>().begin());
|
||||||
|
template <class _Tp> using tryc_end_t = decltype (declval<const _Tp>().begin());
|
||||||
|
template <class _Tp> using try_cend_t = decltype (declval<const _Tp>().cend());
|
||||||
|
|
||||||
|
//! Primary template to catch any non output device types
|
||||||
|
template <typename _Tp, typename =void>
|
||||||
|
struct is_out_dev_ : false_ { };
|
||||||
|
|
||||||
|
//! template to catch a proper output device type
|
||||||
|
template <typename _Tp>
|
||||||
|
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 <try_put1_t <_Tp>, size_t>,
|
||||||
|
use_if_same_t <try_put2_t <_Tp>, size_t>,
|
||||||
|
//if_same_t <try_insert_t<_Tp>,_Tp&>,
|
||||||
|
use_if_same_t <try_begin_t<_Tp>, typename _Tp::iterator>,
|
||||||
|
use_if_same_t <tryc_begin_t<_Tp>, typename _Tp::const_iterator>,
|
||||||
|
use_if_same_t <try_cbegin_t<_Tp>, typename _Tp::const_iterator>,
|
||||||
|
use_if_same_t <try_end_t<_Tp>, typename _Tp::iterator>,
|
||||||
|
use_if_same_t <tryc_end_t<_Tp>, typename _Tp::const_iterator>,
|
||||||
|
use_if_same_t <try_cend_t<_Tp>, typename _Tp::const_iterator>
|
||||||
|
>
|
||||||
|
> : true_ { };
|
||||||
|
}
|
||||||
|
/*!
|
||||||
|
* Predicate for output device checking
|
||||||
|
* \param _Tp Type to check
|
||||||
|
* \return True if _Tp is a output device
|
||||||
|
*/
|
||||||
|
template <typename _Tp>
|
||||||
|
constexpr bool Out_dev = out_dev_details::is_out_dev_<_Tp>::value;
|
||||||
|
#endif
|
||||||
|
//!@}
|
||||||
|
|
||||||
|
//!@}
|
||||||
|
} //namespace utl
|
||||||
|
|
||||||
|
#endif /* #ifndef __utl_dev_out_dev_h__ */
|
Loading…
x
Reference in New Issue
Block a user