/*! * \file utl/dev/inbuf_dev.h * \brief Abstract base class interface for input buffered * devices of utl. * * Copyright (C) 2018 Christos Choutouridis * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef __utl_dev_inbuf_dev_h__ #define __utl_dev_inbuf_dev_h__ #include #include #include #include namespace utl { /*! * \ingroup Device Interface * \brief Abstract base class for input buffered devices */ //!@{ /*! * \brief * Template base class for buffered input buffered devices. using CRTP * * This class force a common interface for input, buffered devices. * By using this common interface the class implements * - Stream-like extracting operator * - Input iterator * - Const input iterator * to inherit to implementation. * * \param impl_t The CRTP type (the derived/implementation class typename). * \param data_t The devices base type of data * \param streamsize The number of elements to indicate eos. * \arg None or 0 Stream only. No iterator as begin() now equals end(). */ template class inbuf_dev { _CRTP_IMPL(impl_t); using inbuf_dev_t = inbuf_dev ; //!< class type syntactic sugar //! Export types as input device concept demands //!@{ public: using data_type = data_t; using pointer_type = data_t*; //!@} using type = inbuf_dev_t; //!< Export type as identity meta-function /*! * \name Constructor / Destructor */ //!@{ protected: ~inbuf_dev () = default; //!< \brief Allow destructor from derived only inbuf_dev () = default; //!< \brief A default constructor from derived only inbuf_dev(const inbuf_dev_t&) = delete; //!< No copies inbuf_dev_t& operator= (const inbuf_dev_t&) = delete; //!< No copy assignments //!@} //! \name Common input device interface requirements //!@{ private: size_t in_avail_ () { return impl().in_avail_(); } size_t get_ (data_t& data) { return impl().get_(data); } size_t get_ (data_t* data, size_t n) { return impl().get_ (data, n); } //!@} /*! * \name Public Get interface */ //!@{ public: /*! * \return * The available @a data_t typed items in input buffer. */ size_t in_avail () { return in_avail_ (); } /*! * \brief * The base get interface. This function should read * a single data_t object from device usually in non-blocking mode. * \param data Reference to data output from device. * \return Number of data read from device * \note * A successful call should return 1 */ size_t get (data_t& data) { return get_ (data); } /*! * \brief * Old stile get functionality using free standing data_t*. * This function should return a stream of data from device * \param data Pointer to buffer to write the data from device. * \param n The number of data of type data_t to read * \return The read data items. */ size_t get (data_t* data, size_t n) { return get_ (data, n); } //!@} /*! * \name Stream operator >> interface */ //!@{ public: /*! * \brief * Template operator >> implementation for for all by value/ref parameters * \note * In the case _Dst_t size is not a integer multiple of device's data size * this will fail by static assertion * \param dst Reference to destination * \return Reference to this device for chaining */ template inbuf_dev_t& operator>> (_Dst_t& dst) { static_assert ((sizeof (_Dst_t)%sizeof(data_t) == 0), "Target size must be an integer multiple of device's data size"); get_ (reinterpret_cast(&dst), sizeof(_Dst_t)/sizeof(data_t)); return *this; } //! Specialization to disallow pointer types as destination template inbuf_dev_t& operator>> (_Dst_t* dst) = delete; //! Overload for single data_t object inbuf_dev_t& operator>> (data_t& dst) { get_ (dst); return *this; } //!@} /*! * \name STL-like Input iterator interface */ //!@{ using iterator = indev_it ; //!< Iterator using const_iterator = indev_it ; //!< Const iterator //!@{ .begin implementation iterator begin () noexcept { return iterator(this, iterator::init); } const_iterator begin () const noexcept { return const_iterator(this, iterator::init); } const_iterator cbegin () const noexcept { return const_iterator(this, iterator::init); } //!@} //!@{ .end implementation iterator end () noexcept { return iterator(this, iterator::eos); } const_iterator end () const noexcept { return const_iterator(this, iterator::eos); } const_iterator cend () const noexcept { return const_iterator(this, iterator::eos); } //!@} //!@} }; /*! * \brief * A virtual base class specialization * \param impl_t = virtual_tag * \param data_t The devices base type of data * \param streamsize The number of elements to indicate eos. * \arg None or 0 Stream only. No iterator as begin() now equals end(). */ template class inbuf_dev { //!< class type syntactic sugar using inbuf_dev_t = inbuf_dev ; //! Export types as input device concept demands //!@{ public: using data_type = data_t; using pointer_type = data_t*; //!@} using type = inbuf_dev_t; //!< Export type as identity meta-function /*! * \name Constructor / Destructor */ //!@{ public: virtual ~inbuf_dev () = default; //!< \brief Virtual destructor protected: inbuf_dev () = default; //!< \brief A default constructor from derived only inbuf_dev(const inbuf_dev_t&) = delete; //!< No copies inbuf_dev_t& operator= (const inbuf_dev_t&) = delete; //!< No copy assignments //!@} /*! * \name Common input device interface requirements */ //!@{ private: /*! * \return * The available @a data_t typed items in input buffer. */ virtual size_t in_avail_ () = 0; /*! * \brief * The base get interface. This function should read * a single data_t object from device usually in non-blocking mode. * \param data Reference to data output from device. * \return Number of data read from device * \note * A successful call should return 1 */ virtual size_t get_ (data_t& data) = 0; /*! * \brief * Old stile get functionality using free standing data_t*. * This function should return a stream of data from device * \param data Pointer to buffer to write the data from device. * \param n The number of data of type data_t to read * \return The read data items. */ virtual size_t get_ (data_t* data, size_t n) = 0; //!@} /*! * \name Public Get interface */ //!@{ public: size_t in_avail() { return in_avail_(); } size_t get (data_t& data) { return get_ (data); } size_t get (data_t* data, size_t n) { return get_ (data, n); } //!@} /*! * \name Stream operator >> interface */ //!@{ /*! * \brief * Template operator >> implementation for for all by value/ref parameters * \note * In the case _Dst_t size is not a integer multiple of device's data size * this will fail by static assertion * \param dst Reference to destination * \return Reference to this device for chaining */ template inbuf_dev_t& operator>> (_Dst_t& dst) { static_assert ((sizeof (_Dst_t)%sizeof(data_t) == 0), "Target size must be an integer multiple of device's data size"); get_ (reinterpret_cast(&dst), sizeof(_Dst_t)/sizeof(data_t)); return *this; } //! specialization to disallow pointer types as destination template inbuf_dev_t& operator>> (_Dst_t* dst) = delete; //! Overload for single data_t object inbuf_dev_t& operator>> (data_t& dst) { get_ (dst); return *this; } //!@} /*! * \name STL-like Input iterator interface */ //!@{ using iterator = indev_it ; //!< Iterator using const_iterator = indev_it ; //!< Const iterator //!@{ .begin implementation iterator begin () noexcept { return iterator(this, iterator::init); } const_iterator begin () const noexcept { return const_iterator(this, iterator::init); } const_iterator cbegin () const noexcept { return const_iterator(this, iterator::init); } //!@} //!@{ .end implementation iterator end () noexcept { return iterator(this, iterator::eos); } const_iterator end () const noexcept { return const_iterator(this, iterator::eos); } const_iterator cend () const noexcept { return const_iterator(this, iterator::eos); } //!@} //!@} }; /*! * Input buffer device concept */ //! @{ #if defined _utl_have_concepts template concept bool Inbuf_dev = requires (_Tp t, const _Tp ct, typename _Tp::data_type v) { // Object type // requires std::is_default_constructible<_Tp>::value; requires !std::is_copy_constructible<_Tp>::value; requires !std::is_copy_assignable<_Tp>::value; // Methods {t.get(v, 0)} -> size_t; {t.get(&v, 1, 0)} -> size_t; // Operators t >> v; // Iterators typename _Tp::const_iterator; //XXX: change to concept: is_idxdev_iterator<_Tp> requires Indev_it; //requires Indev_it; { t.begin() } -> typename _Tp::iterator; // {ct.begin()} -> typename _Tp::const_iterator; // { t.cbegin()} -> typename _Tp::const_iterator; { t.end() } -> typename _Tp::iterator; // {ct.end()} -> typename _Tp::const_iterator; // { t.cend()} -> typename _Tp::const_iterator; }; #else namespace inbuf_dev_details { using std::declval; // main api members template using try_get1_t = decltype (declval<_Tp>().get (declval())); template using try_get2_t = decltype (declval<_Tp>().get (declval(), declval())); // operators //template using try_extract_t= decltype (declval<_Tp>() >> declval()); // iterator members template using try_begin_t = decltype (declval<_Tp>().begin()); template using tryc_begin_t = decltype (declval().begin()); template using try_cbegin_t = decltype (declval().cbegin()); template using try_end_t = decltype (declval<_Tp>().begin()); template using tryc_end_t = decltype (declval().begin()); template using try_cend_t = decltype (declval().cend()); //! Primary template to catch any non input device types template struct is_inbuf_dev_ : false_ {}; //! template to catch a proper input device type template struct is_inbuf_dev_ <_Tp, void_t < typename _Tp::data_type, typename _Tp::pointer_type, typename _Tp::iterator, typename _Tp::const_iterator, use_if_same_t , size_t>, use_if_same_t , size_t>, //if_same_t ,typename _Tp&>, use_if_same_t , typename _Tp::iterator>, use_if_same_t , typename _Tp::const_iterator>, use_if_same_t , typename _Tp::const_iterator>, use_if_same_t , typename _Tp::iterator>, use_if_same_t , typename _Tp::const_iterator>, use_if_same_t , typename _Tp::const_iterator> > > : true_ {}; } /*! * Predicate for input device checking * \param _Tp Type to check * \return True if _Tp is a input device */ template constexpr bool Inbuf_dev = inbuf_dev_details::is_inbuf_dev_ <_Tp>::value; #endif //!@} } //!@} #endif /* #ifndef __utl_dev_inbuf_dev_h__ */