|
- /*!
- * \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__ */
|