|
- /*!
- * \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/core/impl.h>
- #include <utl/core/crtp.h>
- #include <utl/dev/dev_iterators.h>
- #include <utl/meta/meta.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__ */
|