|
- /*!
- * \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/core/impl.h>
- #include <utl/meta/meta.h>
-
- namespace utl {
-
- /*!
- * \ingroup Devices
- * \brief Device iterator collection.
- */
- //!@{
-
- /*!
- * \brief Traits class for dev_iterators.
- *
- * This class does nothing but define nested typedefs. The general
- * version simply @a forwards the nested typedefs from the Iterator
- * argument.
- */
- template <typename _Cat, typename _Tp, typename _Diff =ptrdiff_t>
- struct dev_iterator_traits {
- using iterator_category = _Cat;
- using value_type = _Tp;
- using difference_type = _Diff;
- using pointer = _Tp*;
- using reference = _Tp&;
- };
-
- /*!
- * \brief Iterator tags [std.iterator.tags]
- * Extension: contiguous_iterator_tag for denoting contiguous iterators.
- */
- struct output_iterator_tag {};
- struct input_iterator_tag {};
- struct forward_iterator_tag : input_iterator_tag {};
- struct bidirectional_iterator_tag : forward_iterator_tag {};
- struct random_access_iterator_tag : bidirectional_iterator_tag {};
- struct contiguous_iterator_tag : random_access_iterator_tag {};
-
-
-
- /*
- * ================ Output device Iterator =================
- */
-
- template <typename cont_t, typename data_t>
- class ostreamdev_it {
- using iterator_t = ostreamdev_it <cont_t, data_t>; //! iterator type local name
- public:
- using type = iterator_t; //!< Export type as identity meta-function
- //! STL iterator traits "forwarding"
- //!@{
- public:
- using iterator_category = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::iterator_category;
- using value_type = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::value_type;
- using difference_type = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::difference_type;
- using pointer = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::pointer;
- using reference = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::reference;
- //!@}
-
- private:
- cont_t* owner_ {nullptr}; /*!<
- * Pointer to parent/owner device class. Usable iterator demands
- * owner container in order to access data. Considering the data
- * don't "live" in memory. A default constructed iterator will behave
- * like end() just like the input version does.
- */
- /*!
- * \name Constructor / Destructor
- */
- //!@{
- public:
- //! \brief Basic constructor
- ostreamdev_it (cont_t* owner =nullptr) noexcept
- : owner_ {owner} { }
- //! \brief Basic copy constructor
- ostreamdev_it (const iterator_t& it) noexcept
- : owner_ {const_cast<cont_t*>(it.owner_)} { }
- //! \brief Basic copy assignment operator
- iterator_t& operator= (const iterator_t& it) noexcept {
- owner_ = const_cast<cont_t*>(it.owner_);
- return *this;
- }
- //!@}
-
- //!@{ \name Public interface
- public:
- iterator_t& operator* () noexcept { return *this; }
- /*!
- * \brief
- * Value-assignment operation. Where the output method is invoked
- * \param value An instance of Cont_t::data_type
- * \return This %iterator, for chained operations.
- */
- iterator_t& operator= (const value_type& value) {
- if (owner_ != nullptr)
- owner_->put (value);
- return *this;
- }
- iterator_t& operator++ () noexcept { return *this; }
- iterator_t& operator++ (int) noexcept { return *this; }
- //!@}
- };
-
- template <typename cont_t, typename data_t>
- class istreamdev_it {
- using iterator_t = istreamdev_it <cont_t, data_t>; //! iterator type local name
- public:
- using type = iterator_t; //!< Export type as identity meta-function
- //! STL iterator traits "forwarding"
- //!@{
- public:
- using iterator_category = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::iterator_category;
- using value_type = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::value_type;
- using difference_type = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::difference_type;
- using pointer = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::pointer;
- using reference = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::reference;
- //!@}
- //! #define-like enumerator for Cursor-like behavior
- enum Cursor {
- init = 0,
- valid = 1,
- eos = 2
- };
- //!@{ \name Data members
- private:
- cont_t* owner_ {nullptr}; /*!<
- * Pointer to parent/owner device class. Usable iterator demands
- * owner container in order to access data. Considering the data
- * don't "live" in memory.
- */
- value_type value_ {};
- Cursor cursor_ {init};
- //!@}
- /*!
- * \name Constructor / Destructor
- */
- //!@{
- public:
- //! \brief Basic constructor
- istreamdev_it (cont_t* owner =nullptr, Cursor cursor =eos) noexcept :
- owner_ {owner},
- value_ {},
- cursor_{cursor} { }
- //! \brief Basic copy constructor
- istreamdev_it (const iterator_t& it) noexcept :
- owner_ {const_cast<cont_t*>(it.owner_)},
- value_ {it.value_},
- cursor_ {it.cursor_} { }
- //! \brief Basic copy assignment operator
- iterator_t& operator= (const iterator_t& it) noexcept {
- owner_ = const_cast<cont_t*>(it.owner_);
- value_ = it.value_;
- cursor_ = it.cursor_;
- return *this;
- }
- //!@}
-
- //!@{ \name Public interface
- public:
- value_type& operator* () noexcept {
- if (cursor_ == init)
- ++*this;
- return value_;
- }
- value_type* operator->() noexcept {
- if (cursor_ == init)
- ++*this;
- return &value_;
- }
- iterator_t& operator++ () noexcept {
- _get(value_);
- return *this;
- }
- iterator_t operator++ (int) noexcept {
- iterator_t r = *this;
- _get(value_);
- return r;
- }
-
- //! Export container for comparison
- const cont_t* owner () const noexcept { return owner_; }
- //! Export value for comparison
- const value_type& value () const noexcept { return value_; }
- //! Export cursor for comparison
- const Cursor cursor () const noexcept { return cursor_; }
- //!@}
-
- //!@{ \name private api
- private:
- void _get(value_type& v) {
- owner_->get(v);
- cursor_ = (v) ? valid : eos;
- }
- //!@}
- };
-
- /*!
- * \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 _C1, typename _D1, typename _C2, typename _D2>
- inline bool operator== (const istreamdev_it<_C1, _D1>& lhs,
- const istreamdev_it<_C2, _D2>& rhs) noexcept {
- return ((lhs.owner() == rhs.owner()) &&
- (lhs.value() == rhs.value()) &&
- (lhs.cursor() == rhs.cursor()));
- }
- template<typename _C1, typename _D1, typename _C2, typename _D2>
- inline bool operator!= (const istreamdev_it<_C1, _D1>& lhs,
- const istreamdev_it<_C2, _D2>& rhs) noexcept {
- return !operator==(lhs, rhs);
- }
-
- /*!
- * \brief
- * Output device iterator type. We "future call" interface methods
- * from owner class to provide iterator functionality.
- * \param cont_t Container/parent type
- * \param iter_t Iterator data type (pointer to container_t::value_type)
- * \param devsize Device's address space size
- */
- template<typename cont_t, typename iter_t, index_t _beg =0, index_t _end =static_cast<index_t>(-1)>
- class outdev_it {
- //! iterator type local name
- using iterator_t = outdev_it <cont_t, iter_t, _beg, _end>;
- public:
- using type = iterator_t; //!< Export type as identity meta-function
- //! 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;
- //!@}
- //! #define-like enumerator for Cursor
- enum Cursor {
- beg = _beg, //!< Points the first item (relative address)
- eod = _end, //!< Points one place after last item (relative address)
- };
- private:
- cont_t* owner_ {nullptr}; /*!<
- * Pointer to parent/owner device class. Usable iterator demands
- * owner container in order to access data. Considering the data
- * don't "live" in memory. A default constructed iterator will behave
- * like end() just like the input version does.
- */
- index_t cursor_ {eod}; //!< virtual cursor for comparison operators
- /*!
- * \name Constructor / Destructor
- */
- //!@{
- public:
- //! \brief Default constructor results to end()
- explicit outdev_it() noexcept :
- owner_ {nullptr},
- cursor_{eod} { }
- //! \brief Basic constructor
- explicit outdev_it (cont_t* owner, index_t cursor =eod) noexcept :
- owner_ {owner},
- cursor_{cursor} { }
- //! \brief Basic copy constructor
- explicit outdev_it (const iterator_t& it) noexcept :
- owner_ {const_cast<cont_t*>(it.owner_)},
- cursor_{it.cursor_} { }
- //! \brief Basic copy assignment operator
- iterator_t& operator= (const iterator_t& it) noexcept {
- owner_ = const_cast<cont_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()} { }
- //!@}
-
-
- //!@{ \name Public interface
- public:
- iterator_t& operator* () noexcept { return *this; }
- /*!
- * \brief
- * Value-assignment operation. Where the output method is invoked
- * \param value An instance of Cont_t::data_type
- * \return This %iterator, for chained operations.
- */
- iterator_t& operator= (const value_type& value) {
- // end() and default constructible iterators are not dereferenceable
- if (cursor_ != eod)
- owner_->put (value, cursor_);
- return *this;
- }
-
- //!@{ \name ++ operators
- iterator_t& operator++ () noexcept {
- ++cursor_;
- return *this;
- }
- iterator_t operator++ (int) noexcept {
- iterator_t ret = *this;
- ++cursor_;
- return ret;
- }
- //!@}
-
- //! Export container for comparison
- const cont_t* owner () const noexcept { return owner_; }
- //! Export cursor for comparison
- const index_t cursor () const noexcept { return cursor_; }
- //!@}
- };
-
- /*!
- * \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.
- */
- //!@{
- /*!
- * \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 _Cont1, typename _It1, index_t _beg1, index_t _end1,
- typename _Cont2, typename _It2, index_t _beg2, index_t _end2>
- inline bool operator== (const outdev_it<_Cont1, _It1, _beg1, _end1>& lhs,
- const outdev_it<_Cont2, _It2, _beg2, _end2>& 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 _Cont1, typename _It1, index_t _beg1, index_t _end1,
- typename _Cont2, typename _It2, index_t _beg2, index_t _end2>
- inline bool operator!= (const outdev_it<_Cont1, _It1, _beg1, _end1>& lhs,
- const outdev_it<_Cont2, _It2, _beg2, _end2>& rhs) noexcept {
- return !(lhs == rhs);
- }
- //!@}
-
- /*!
- * 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_ : meta::false_ {};
-
- //! template to catch a proper SPI interface type
- template <typename _Tp>
- struct is_outdev_it_ <
- _Tp,
- meta::void_t <
- typename _Tp::value_type,
- typename _Tp::difference_type,
- typename _Tp::pointer,
- typename _Tp::reference,
- // meta::use_if_same_t <
- // typename _Tp::iterator_category,
- // std::output_iterator_tag
- // >
- void
- >
- > : meta::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 cont_t Container/parent type
- * \param iter_t Iterator data type (pointer to container_t::value_type)
- * \param _beg Device starting address
- * \param _size Device's address space size
- */
- template<typename cont_t, typename iter_t, index_t _beg =0, size_t _size = static_cast<size_t>(-1)-_beg>
- class indev_it {
- //!< iterator type local name
- using iterator_t = indev_it <cont_t, iter_t, _beg, _size>;
- public:
- using type = iterator_t; //!< Export type as identity meta-function
- //! 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;
- //!@}
-
- //! #define-like enumerator for Cursor
- enum Cursor {
- beg = _beg, //!< Points the first item
- eod = _beg + _size, //!< Points one place after last item
- };
-
- private:
- cont_t* owner_{nullptr}; /*!<
- * Pointer to parent/owner device class. Constructor demands
- * owner container in order to access data. Considering the data
- * don't "live" in memory.
- */
- index_t cursor_{eod}; //!< virtual cursor for comparison operators
- value_type value_ {}; //!< The current value, used as cache
-
- /*!
- * \name Constructor / Destructor
- * \note
- * We can not provide a default constructor as long as we depend
- * on container_t (the owner type).
- */
- //!@{
- public:
- //! \brief Default constructor
- indev_it () noexcept :
- owner_ {nullptr},
- cursor_{eod},
- value_ {} { }
- //! \brief Basic constructor
- explicit indev_it (cont_t* own, size_t cur =eod) noexcept :
- owner_ {own},
- cursor_{cur},
- value_ {} { }
- //! \brief Basic copy constructor
- explicit indev_it (const iterator_t& it) noexcept :
- owner_ {const_cast<cont_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<cont_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()} { }
-
- //!@}
-
- //!@{ \name Public interface
- public:
- //! De-reference operator. No end() place dereference check is made.
- reference operator* () {
- owner_->get (value_, cursor_);
- return value_;
- }
- //! Arrow operator. No end() place dereference check is made.
- pointer operator-> () {
- owner_->get (value_, cursor_);
- return &value_;
- }
-
- //! Pre increment.
- iterator_t& operator++ () {
- ++cursor_;
- return *this;
- }
- //! Post increment.
- iterator_t operator++ (int) {
- iterator_t ret(*this);
- ++cursor_;
- return *this;
- }
-
- //! Pre decrement.
- iterator_t& operator-- () {
- --cursor_;
- return *this;
- }
- //! Post decrement.
- iterator_t operator-- (int) {
- iterator_t ret(*this);
- --cursor_;
- return *this;
- }
- //! [] operator. Is a combination of input method and dereference
- reference operator[] (difference_type n) {
- owner_->get (value_, cursor_ += n);
- return value_;
- }
-
- iterator_t& operator+= (difference_type n) {
- cursor_ += n;
- return *this;
- }
- iterator_t operator+ (difference_type n) {
- return iterator_t (owner_, cursor_ + n);
- }
- iterator_t& operator-= (difference_type n) {
- cursor_ -= n;
- return *this;
- }
- iterator_t operator- (difference_type n) {
- return iterator_t (owner_, cursor_ - n);
- }
- //! Export container for comparison
- const cont_t* owner () const noexcept { return owner_; }
- //! Export cursor for comparison
- const index_t cursor () const noexcept { return cursor_; }
- //! Export value for comparison
- //const reference value () const noexcept { return value_; }
- //!@}
- };
-
- /*!
- * \name indev_it EqualityComparable && LessThanComparable requirements
- * comparison template so that comparison between cv-qualified and
- * non-cv-qualified iterators be valid
- */
- //!@{
- //! Equality
- template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
- typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
- inline bool operator== (const indev_it<_Cont1, _It1, _beg1, _size1>& x,
- const indev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
- return (x.owner() == y.owner() &&
- (x.cursor() == y.cursor()));
- }
- //! Less than
- template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
- typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
- inline bool operator< (const indev_it<_Cont1, _It1, _beg1, _size1>& x,
- const indev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
- return (x.cursor() < y.cursor());
- }
-
- // relative ops
- template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
- typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
- inline bool operator!= (const indev_it<_Cont1, _It1, _beg1, _size1>& x,
- const indev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
- return !(x == y);
- }
- template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
- typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
- inline bool operator<= (const indev_it<_Cont1, _It1, _beg1, _size1>& x,
- const indev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
- return !(y < x);
- }
- template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
- typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
- inline bool operator> (const indev_it<_Cont1, _It1, _beg1, _size1>& x,
- const indev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
- return (y < x);
- }
- template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
- typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
- inline bool operator>= (const indev_it<_Cont1, _It1, _beg1, _size1>& x,
- const indev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
- return !(x < y);
- }
- //!@}
-
- //! @{ \name iterator arithmetic
- template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
- typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
- inline auto operator- (indev_it<_Cont1, _It1, _beg1, _size1>& x,
- indev_it<_Cont1, _It1, _beg1, _size1>& y) noexcept
- -> decltype (x.cursor() - y.cursor()) {
- return (x.cursor() - y.cursor());
- }
-
- template<typename _Cont, typename _It, index_t _beg, size_t _size>
- inline indev_it<_Cont, _It, _beg, _size>
- operator+ (typename _Cont::difference_type n,
- indev_it<_Cont, _It, _beg, _size>& it) noexcept {
- return indev_it<_Cont, _It, _beg, _size>(it.owner(), it.cursor() + n);
- }
- //! @}
-
- /*!
- * 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_ : meta::false_ {};
-
- //! template to catch a proper SPI interface type
- template <typename _Tp>
- struct is_indev_it_ <
- _Tp,
- meta::void_t <
- typename _Tp::value_type,
- typename _Tp::difference_type,
- typename _Tp::pointer,
- typename _Tp::reference,
- // meta::use_if_same_t <
- // typename _Tp::iterator_category,
- // std::input_iterator_tag
- // >
- void
- >
- > : meta::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 =================
- */
-
- /*!
- * \brief
- * Indexed device iterator type. We "future call" interface methods
- * from owner class to provide iterator functionality.
- * \note
- * This is a contiguous iterator
- * \param cont_t Container/parent type
- * \param iter_t Iterator data type (pointer to container_t::value_type)
- * \param _beg Starting address of the device
- * \param _size Device's address space size
- */
- template<typename cont_t, typename iter_t, index_t _beg =0, size_t _size = static_cast<size_t>(-1)-_beg>
- class iodev_it {
- //!< iterator type local name
- using iterator_t = iodev_it <cont_t, iter_t, _beg, _size>;
- public:
- using type = iterator_t; //!< Export type as identity meta-function
- //! 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;
- //!@}
-
- //! #define-like enumerator for Cursor
- enum Cursor {
- beg = _beg, //!< Points the first item
- eod = _beg+_size, //!< Points one place after last item
- };
-
- private:
- cont_t* owner_{nullptr}; /*!<
- * Pointer to parent/owner device class. Constructor demands
- * owner container in order to access data. Considering the data
- * don't "live" in memory.
- */
- index_t cursor_{eod}; //!< virtual cursor for comparison operators
- /*!
- * Current value wrapper type, to used as put event catcher
- * owner_->get : Use v_ directly
- * owner_->put : Use operator= to a dereferenced iterator
- */
- struct value_type_t {
- value_type v_; //!< Current value buffer to access via get
- value_type_t(value_type v =value_type{}) :
- v_{v} { }
- operator value_type() { return v_; }
- operator reference() { return v_; }
- value_type& operator= (const value_type& v) {
- //!< Catch any attempt to write to value_ and sync the data back to device
- owner_->put (v_ =v, cursor_);
- }
- } value_ {};
- /*!
- * \name Constructor / Destructor
- */
- //!@{
- public:
- //! \brief Default constructor
- iodev_it () noexcept :
- owner_ {nullptr},
- cursor_{eod},
- value_ {} { }
- //! \brief Basic constructor
- explicit iodev_it (cont_t* owner, size_t cursor =eod) noexcept :
- owner_ {owner},
- cursor_{cursor},
- value_ {} { }
- //! \brief Basic copy constructor
- explicit iodev_it (const iterator_t& it) noexcept :
- owner_ {const_cast<cont_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<cont_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;
- }
- //! 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 cont_t* owner () const noexcept { return owner_; }
- //! Export cursor for comparison
- const index_t& cursor () const noexcept { return cursor_; }
- //! Export value for comparison
- //const value_type_t& value () const noexcept { return value_; }
- //!@}
- };
-
- /*!
- * \name indev_it EqualityComparable && LessThanComparable requirements
- * comparison template so that comparison between cv-qualified and
- * non-cv-qualified iterators be valid
- */
- //!@{
- //! Equality
- template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
- typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
- inline bool operator== (const iodev_it<_Cont1, _It1, _beg1, _size1>& x,
- const iodev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
- return (x.owner() == y.owner() &&
- (x.cursor() == y.cursor()));
- }
- //! Less than
- template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
- typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
- inline bool operator< (const iodev_it<_Cont1, _It1, _beg1, _size1>& x,
- const iodev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
- return (x.cursor() < y.cursor());
- }
-
- // relative ops
- template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
- typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
- inline bool operator!= (const iodev_it<_Cont1, _It1, _beg1, _size1>& x,
- const iodev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
- return !(x == y);
- }
- template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
- typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
- inline bool operator<= (const iodev_it<_Cont1, _It1, _beg1, _size1>& x,
- const iodev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
- return !(y < x);
- }
- template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
- typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
- inline bool operator> (const iodev_it<_Cont1, _It1, _beg1, _size1>& x,
- const iodev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
- return (y < x);
- }
- template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
- typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
- inline bool operator>= (const iodev_it<_Cont1, _It1, _beg1, _size1>& x,
- const iodev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
- return !(x < y);
- }
- //!@}
-
- //! @{ \name iterator arithmetic
- template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
- typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
- inline auto operator- (iodev_it<_Cont1, _It1, _beg1, _size1>& x,
- iodev_it<_Cont1, _It1, _beg1, _size1>& y) noexcept
- -> decltype (x.cursor() - y.cursor()) {
- return (x.cursor() - y.cursor());
- }
-
- template<typename _Cont, typename _It, index_t _beg, size_t _size>
- inline iodev_it<_Cont, _It, _beg, _size>
- operator+ (typename _Cont::difference_type n,
- iodev_it<_Cont, _It, _beg, _size>& it) noexcept {
- return iodev_it<_Cont, _It, _beg, _size>(it.owner(), it.cursor() + n);
- }
- //! @}
-
- /*!
- * 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_ : meta::false_ {};
-
- //! template to catch a proper SPI interface type
- template <typename _Tp>
- struct is_idxdev_it_ <
- _Tp,
- meta::void_t <
- typename _Tp::value_type,
- typename _Tp::difference_type,
- typename _Tp::pointer,
- typename _Tp::reference,
- // meta::use_if_same_t <
- // typename _Tp::iterator_category,
- // std::input_iterator_tag
- // >
- void
- >
- > : meta::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__ */
|