Micro template library A library for building device drivers
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

855 lines
32 KiB

  1. /*!
  2. * \file utl/dev/dev_iterators.h
  3. * \brief Iterator collection for devices.
  4. *
  5. * Copyright (C) 2018 Christos Choutouridis
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation, either version 3
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. */
  21. #ifndef __utl_dev_dev_iterators_h__
  22. #define __utl_dev_dev_iterators_h__
  23. #include <utl/impl/impl.h>
  24. #include <utl/meta/sfinae.h>
  25. namespace utl {
  26. /*!
  27. * \ingroup Devices
  28. * \brief Iterator collection.
  29. */
  30. //!@{
  31. /*!
  32. * Common template Iterator trait dispatcher for the STL requirement
  33. * type definitions.
  34. * Our iterators inherit from specializations of this type
  35. */
  36. template <typename _Cat, typename _Tp, typename _Diff =ptrdiff_t>
  37. struct dev_iterator_traits { };
  38. //! Partial specialization for pointer types.
  39. template<typename _Cat, typename _Tp, typename _Diff>
  40. struct dev_iterator_traits<_Cat, _Tp*, _Diff> {
  41. typedef _Cat iterator_category;
  42. typedef _Tp value_type;
  43. typedef _Diff difference_type;
  44. typedef _Tp* pointer;
  45. typedef _Tp& reference;
  46. };
  47. //! Partial specialization for const pointer types.
  48. template<typename _Cat, typename _Tp, typename _Diff>
  49. struct dev_iterator_traits<_Cat, const _Tp*, _Diff> {
  50. typedef _Cat iterator_category;
  51. typedef _Tp value_type;
  52. typedef _Diff difference_type;
  53. typedef const _Tp* pointer;
  54. typedef const _Tp& reference;
  55. };
  56. /*
  57. * ================ Output device Iterator =================
  58. */
  59. /*!
  60. * \brief
  61. * Output device iterator type. We "future call" interface methods
  62. * from owner class to provide iterator functionality.
  63. * \param container_t Container/parent type
  64. * \param iter_t Iterator data type (pointer to container_t::value_type)
  65. * \param streamsize Stream size
  66. */
  67. template<typename container_t, typename iter_t, size_t streamsize =0>
  68. class outdev_it {
  69. //! iterator type local name
  70. using iterator_t = outdev_it <container_t, iter_t, streamsize>;
  71. //! STL iterator traits "forwarding"
  72. //!@{
  73. public:
  74. using iterator_category = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::iterator_category;
  75. using value_type = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::value_type;
  76. using difference_type = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::difference_type;
  77. using pointer = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::pointer;
  78. using reference = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::reference;
  79. //!@}
  80. using type = iterator_t; //!< Export type as identity meta-function
  81. //! #define-like enumerator for Cursor
  82. enum Cursor {
  83. beg = 0, //!< Points the first item
  84. eos = streamsize, //!< Points one place after last item
  85. };
  86. private:
  87. container_t* owner_; /*!<
  88. * Pointer to parent/owner device class. Constructor demands
  89. * owner container in order to access data. Considering the data
  90. * don't "live" in memory.
  91. */
  92. size_t cursor_ {beg}; //!< virtual cursor for comparison operators
  93. /*!
  94. * \name Constructor / Destructor
  95. * \note
  96. * We can not provide a default constructor as long as we depend
  97. * on container_t (the owner type).
  98. */
  99. //!@{
  100. public:
  101. //! \brief Basic constructor
  102. explicit outdev_it (container_t* owner, size_t cursor =beg) noexcept
  103. : owner_{owner},
  104. cursor_{cursor} { }
  105. //! \brief Basic copy constructor
  106. explicit outdev_it (const iterator_t& it) noexcept
  107. : owner_ {const_cast<container_t*>(it.owner())},
  108. cursor_ {it.cursor()} { }
  109. //! \brief Iterator to const-iterator conversion (as STL requires)
  110. //! \param it Iterator reference
  111. template<typename _It>
  112. outdev_it (const outdev_it<
  113. use_if_same_t <_It, typename container_t::pointer_type, container_t>,
  114. _It,
  115. streamsize
  116. >& it) noexcept
  117. : owner_ {const_cast<container_t*>(it.owner())},
  118. cursor_ {it.cursor()} { }
  119. //! \brief Basic copy assignment operator
  120. iterator_t& operator= (const iterator_t& it) noexcept {
  121. owner_ = const_cast<container_t*>(it.owner());
  122. cursor_ = it.cursor();
  123. }
  124. //!@}
  125. //!@{ \name Public interface
  126. public:
  127. iterator_t& operator* () noexcept { return *this; }
  128. /*!
  129. * \brief
  130. * Assignment operation. Where the output method is invoked
  131. * \param value An instance of container_t basic type
  132. * \return This %iterator, for chained operations.
  133. */
  134. iterator_t& operator= (const value_type& value) {
  135. owner_->put (value);
  136. return *this;
  137. }
  138. //!@{ ++ operators
  139. //! STL compatibility. No cursor
  140. template <size_t S =streamsize>
  141. use_if_t <(S == 0), iterator_t&> operator++ () noexcept { *this; }
  142. template <size_t S =streamsize>
  143. use_if_t <(S == 0), iterator_t&> operator++ (int) noexcept { *this; }
  144. //!@}
  145. /*!
  146. * The following are not requirements for output iterator.
  147. * We provide them nevertheless.
  148. * This kind of %iterator doesn't usually have a @a cursor in the
  149. * container. Assigning a value to the %iterator will
  150. * always forward the value to the output device. If though we pass
  151. * a streamsize value !=0 then the iterator will work using the cursor.
  152. * The user has to be careful to keep sync between ++'s and ='s operator
  153. * calls in the code.
  154. */
  155. //!@{
  156. template <size_t S =streamsize>
  157. use_if_t <(S != 0), iterator_t&> operator++ () noexcept {
  158. ++cursor_;
  159. return *this;
  160. }
  161. template <size_t S =streamsize>
  162. use_if_t <(S != 0), iterator_t> operator++ (int) noexcept {
  163. iterator_t ret = *this;
  164. ++cursor_;
  165. return ret;
  166. }
  167. //!@}
  168. //! Export container for comparison
  169. const container_t* owner () const noexcept { return owner_; }
  170. //! Export cursor for comparison
  171. const size_t cursor () const noexcept { return cursor_; }
  172. //!@}
  173. };
  174. /*!
  175. * \brief
  176. * Equality comparison template so that comparison between cv-qualified and
  177. * non-cv-qualified iterators be valid
  178. * \param lhs Left hand site iterator
  179. * \param rhs Right hand site iterator
  180. * \return True in equality
  181. */
  182. template<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
  183. inline bool operator== (const outdev_it<_Cont, _It_L, _Size>& lhs,
  184. const outdev_it<_Cont, _It_R, _Size>& rhs) noexcept {
  185. return ((lhs.cursor() == rhs.cursor()) &&
  186. (lhs.owner() == rhs.owner()));
  187. }
  188. /*!
  189. * \brief
  190. * Inequality comparison template so that comparison between cv-qualified and
  191. * non-cv-qualified iterators be valid
  192. * \param lhs Left hand site iterator
  193. * \param rhs Right hand site iterator
  194. * \return True in inequality
  195. */
  196. template<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
  197. inline bool operator!= (const outdev_it<_Cont, _It_L, _Size>& lhs,
  198. const outdev_it<_Cont, _It_R, _Size>& rhs) noexcept {
  199. return !(lhs == rhs);
  200. }
  201. /*!
  202. * \note
  203. * The following are not requirements for output iterator.
  204. * We provide them nevertheless.
  205. * \warn
  206. * Required: The rhs and lhs MUST belong to the same owner or
  207. * the result is undefined.
  208. */
  209. //!@{
  210. template<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
  211. inline bool operator< (const outdev_it<_Cont, _It_L, _Size>& lhs,
  212. const outdev_it<_Cont, _It_R, _Size>& rhs) noexcept {
  213. return (lhs.cursor() < rhs.cursor());
  214. }
  215. template<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
  216. inline bool operator<= (const outdev_it<_Cont, _It_L, _Size>& lhs,
  217. const outdev_it<_Cont, _It_R, _Size>& rhs) noexcept {
  218. return (lhs.cursor() <= rhs.cursor());
  219. }
  220. template<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
  221. inline bool operator> (const outdev_it<_Cont, _It_L, _Size>& lhs,
  222. const outdev_it<_Cont, _It_R, _Size>& rhs) noexcept {
  223. return (lhs.cursor() > rhs.cursor());
  224. }
  225. template<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
  226. inline bool operator>= (const outdev_it<_Cont, _It_L, _Size>& lhs,
  227. const outdev_it<_Cont, _It_R, _Size>& rhs) noexcept {
  228. return (lhs.cursor() >= rhs.cursor());
  229. }
  230. //!@}
  231. /*!
  232. * Output device iterator concept
  233. */
  234. //! @{
  235. #if defined _utl_have_concepts
  236. template <typename T>
  237. concept bool Outdev_it = requires (T t) {
  238. // STL compatibility
  239. typename T::value_type;
  240. typename T::difference_type;
  241. typename T::pointer;
  242. typename T::reference;
  243. requires same_<
  244. typename T::iterator_category,
  245. std::output_iterator_tag
  246. >::value;
  247. {*t} -> auto&&; // is dereferencable, and return non-void
  248. {++t} -> T&; // is incrementable
  249. {t++} -> T;
  250. // Extras
  251. {t.owner()} ->auto&&;
  252. {t.cursor()} -> size_t;
  253. };
  254. #else
  255. namespace outdev_it_details {
  256. using std::declval;
  257. //! Primary template to catch any non SPI interface types
  258. template <typename _Tp, typename =void>
  259. struct is_outdev_it_ : false_ {};
  260. //! template to catch a proper SPI interface type
  261. template <typename _Tp>
  262. struct is_outdev_it_ <
  263. _Tp,
  264. void_t <
  265. typename T::value_type,
  266. typename T::difference_type,
  267. typename T::pointer,
  268. typename T::reference,
  269. use_if_same_t <
  270. typename T::iterator_category,
  271. std::output_iterator_tag
  272. >
  273. >
  274. > : true_ {};
  275. }
  276. /*!
  277. * Value meta-programming function for SPI interface checking
  278. * \param _Tp Type to check
  279. * \return True if _Tp is a spi interface
  280. */
  281. template <typename _Tp>
  282. constexpr bool Outdev_it = outdev_it_details::is_outdev_it_<_Tp>::value;
  283. #endif
  284. //! @}
  285. /*
  286. * ================ Input device Iterator =================
  287. */
  288. /*!
  289. * \brief
  290. * Input device iterator type. We "future call" interface methods
  291. * from owner class to provide iterator functionality.
  292. * \param container_t Container/parent type
  293. * \param iter_t Iterator data type (pointer to container_t::value_type)
  294. * \param streamsize Stream size
  295. */
  296. template<typename container_t, typename iter_t, size_t streamsize>
  297. class indev_it {
  298. using iterator_t = indev_it <container_t, iter_t, streamsize>; //!< iterator type local name
  299. //! STL iterator traits "forwarding"
  300. //!@{
  301. public:
  302. using iterator_category = typename dev_iterator_traits <std::input_iterator_tag, iter_t>::iterator_category;
  303. using value_type = typename dev_iterator_traits <std::input_iterator_tag, iter_t>::value_type;
  304. using difference_type = typename dev_iterator_traits <std::input_iterator_tag, iter_t>::difference_type;
  305. using pointer = typename dev_iterator_traits <std::input_iterator_tag, iter_t>::pointer;
  306. using reference = typename dev_iterator_traits <std::input_iterator_tag, iter_t>::reference;
  307. //!@}
  308. using type = iterator_t; //!< Export type as identity meta-function
  309. //! #define-like enumerator for Cursor
  310. enum Cursor {
  311. beg = 0, //!< Points the first item
  312. eos = streamsize, //!< Points one place after last item
  313. init= -1 //!< Used as flag so we have to fetch the first item
  314. };
  315. private:
  316. container_t* owner_; /*!<
  317. * Pointer to parent/owner device class. Constructor demands
  318. * owner container in order to access data. Considering the data
  319. * don't "live" in memory.
  320. */
  321. size_t cursor_ {init}; //!< virtual cursor for comparison operators
  322. value_type value_ {}; //!< The current value, used as a buffer
  323. /*!
  324. * \name Constructor / Destructor
  325. * \note
  326. * We can not provide a default constructor as long as we depend
  327. * on container_t (the owner type).
  328. */
  329. //!@{
  330. public:
  331. //! \brief Basic constructor
  332. explicit indev_it (container_t* own, size_t cur =init) noexcept
  333. : owner_{own},
  334. cursor_{cur},
  335. value_{} { }
  336. //! \brief Basic copy constructor
  337. explicit indev_it (const iterator_t& it) noexcept
  338. : owner_ {const_cast<container_t*>(it.owner())},
  339. cursor_{it.cursor()},
  340. value_ {it.value()} { }
  341. //! \brief Iterator to const-iterator conversion (as STL requires)
  342. //! \param it Iterator reference
  343. template<typename _It>
  344. indev_it (const indev_it<
  345. use_if_same_t <_It, typename container_t::pointer_type, container_t>,
  346. _It,
  347. streamsize
  348. >& it) noexcept
  349. : owner_ {const_cast<container_t*>(it.owner())},
  350. cursor_{it.cursor()},
  351. value_ {it.value()} { }
  352. //! \brief Basic copy assignment operator
  353. iterator_t& operator= (const iterator_t& it) noexcept {
  354. owner_ = const_cast<container_t*>(it.owner());
  355. cursor_ = it.cursor();
  356. value_ = it.value();
  357. }
  358. //!@}
  359. //!@{ \name Public interface
  360. public:
  361. /*!
  362. * De-reference operator. We just return the current value
  363. * \note
  364. * We have to make sure we retrieve the first item before the
  365. * first dereference.
  366. * \note
  367. * No end() place dereference check is made.
  368. */
  369. reference operator* () noexcept {
  370. if (cursor_ == init)
  371. ++*this;
  372. return value_;
  373. }
  374. //! Arrow operator
  375. pointer operator-> () noexcept {
  376. if (cursor_ == init)
  377. ++*this;
  378. return &value_;
  379. }
  380. //! Pre increment. This is where the input method is invoked
  381. iterator_t& operator++ () noexcept {
  382. owner_->get (value_);
  383. ++cursor_;
  384. return *this;
  385. }
  386. //! Post increment. This is where the input method is invoked
  387. iterator_t operator++ (int) noexcept {
  388. iterator_t ret = *this;
  389. owner_->get (value_);
  390. ++cursor_;
  391. return *this;
  392. }
  393. //! Export container for comparison
  394. const container_t* owner () const noexcept { return owner_; }
  395. //! Export cursor for comparison
  396. const size_t cursor () const noexcept { return cursor_; }
  397. //! Export value for comparison
  398. const value_type& value () const noexcept { return value_; }
  399. //!@}
  400. };
  401. /*!
  402. * \brief
  403. * Equality comparison template so that comparison between cv-qualified and
  404. * non-cv-qualified iterators be valid
  405. * \param lhs Left hand site iterator
  406. * \param rhs Right hand site iterator
  407. * \return True in equality
  408. */
  409. template<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
  410. inline bool operator== (const indev_it<_Cont, _It_L, _Size>& lhs,
  411. const indev_it<_Cont, _It_R, _Size>& rhs) noexcept {
  412. return ((lhs.cursor() == rhs.cursor()) &&
  413. (lhs.owner() == rhs.owner()) &&
  414. (lhs.value() == rhs.value()));
  415. }
  416. /*!
  417. * \brief
  418. * Inequality comparison template so that comparison between cv-qualified and
  419. * non-cv-qualified iterators be valid
  420. * \param lhs Left hand site iterator
  421. * \param rhs Right hand site iterator
  422. * \return True in inequality
  423. */
  424. template<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
  425. inline bool operator!= (const indev_it<_Cont, _It_L, _Size>& lhs,
  426. const indev_it<_Cont, _It_R, _Size>& rhs) noexcept {
  427. return ((lhs.cursor() != rhs.cursor()) ||
  428. (lhs.owner() != rhs.owner()) ||
  429. (lhs.value() != rhs.value()));
  430. }
  431. /*!
  432. * \note
  433. * The following are not requirements for input iterator.
  434. * We provide them nevertheless.
  435. * \warn
  436. * Required: The rhs and lhs MUST belong to the same owner or
  437. * the result is undefined.
  438. */
  439. //!@{
  440. template<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
  441. inline bool operator< (const indev_it<_Cont, _It_L, _Size>& lhs,
  442. const indev_it<_Cont, _It_R, _Size>& rhs) noexcept {
  443. return (lhs.cursor() < rhs.cursor());
  444. }
  445. template<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
  446. inline bool operator<= (const indev_it<_Cont, _It_L, _Size>& lhs,
  447. const indev_it<_Cont, _It_R, _Size>& rhs) noexcept {
  448. return (lhs.cursor() <= rhs.cursor());
  449. }
  450. template<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
  451. inline bool operator> (const indev_it<_Cont, _It_L, _Size>& lhs,
  452. const indev_it<_Cont, _It_R, _Size>& rhs) noexcept {
  453. return (lhs.cursor() > rhs.cursor());
  454. }
  455. template<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
  456. inline bool operator>= (const indev_it<_Cont, _It_L, _Size>& lhs,
  457. const indev_it<_Cont, _It_R, _Size>& rhs) noexcept {
  458. return (lhs.cursor() >= rhs.cursor());
  459. }
  460. //!@}
  461. /*!
  462. * Input device iterator concept
  463. */
  464. //! @{
  465. #if defined _utl_have_concepts
  466. template <typename T>
  467. concept bool Indev_it = requires (T t, const T ct) {
  468. // STL compatibility
  469. typename T::value_type;
  470. typename T::difference_type;
  471. typename T::pointer;
  472. typename T::reference;
  473. requires same_ <
  474. typename T::iterator_category,
  475. std::input_iterator_tag
  476. >::value;
  477. {*t} -> typename T::value_type; // is dereferencable
  478. {++t} -> T&; // is incrementable
  479. {t++} -> T;
  480. // Extras
  481. {ct.owner()} ->auto&&;
  482. {ct.cursor()} -> const size_t;
  483. {ct.value()} -> auto&&;
  484. };
  485. #else
  486. namespace indev_it_details {
  487. using std::declval;
  488. //! Primary template to catch any non SPI interface types
  489. template <typename _Tp, typename =void>
  490. struct is_indev_it_ : false_ {};
  491. //! template to catch a proper SPI interface type
  492. template <typename _Tp>
  493. struct is_indev_it_ <
  494. _Tp,
  495. void_t <
  496. typename T::value_type,
  497. typename T::difference_type,
  498. typename T::pointer,
  499. typename T::reference,
  500. use_if_same_t <
  501. typename T::iterator_category,
  502. std::input_iterator_tag
  503. >
  504. >
  505. > : true_ {};
  506. }
  507. /*!
  508. * Value meta-programming function for SPI interface checking
  509. * \param _Tp Type to check
  510. * \return True if _Tp is a spi interface
  511. */
  512. template <typename _Tp>
  513. constexpr bool Indev_it = indev_it_details::is_indev_it_<_Tp>::value;
  514. #endif
  515. //! @}
  516. /*
  517. * ================= Indexed device Iterator (input) =================
  518. */
  519. /*!
  520. * \brief
  521. * Indexed device iterator type. We "future call" interface methods
  522. * from owner class to provide iterator functionality.
  523. * \note
  524. * This is a Input type iterator
  525. * \param container_t Container/parent type
  526. * \param iter_t Iterator data type (pointer to container_t::value_type)
  527. * \param N Max indexed/addressed items of device
  528. * Usual the last address is N-1
  529. */
  530. template<typename container_t, typename iter_t, size_t N>
  531. class idxdev_it {
  532. using iterator_t = idxdev_it <container_t, iter_t, N>; //!< iterator type local name
  533. //!@{ STL iterator traits "forwarding"
  534. public:
  535. using iterator_category = typename dev_iterator_traits <std::input_iterator_tag, iter_t, size_t>::iterator_category;
  536. using value_type = typename dev_iterator_traits <std::input_iterator_tag, iter_t, size_t>::value_type;
  537. using difference_type = typename dev_iterator_traits <std::input_iterator_tag, iter_t, size_t>::difference_type;
  538. using pointer = typename dev_iterator_traits <std::input_iterator_tag, iter_t, size_t>::pointer;
  539. using reference = typename dev_iterator_traits <std::input_iterator_tag, iter_t, size_t>::reference;
  540. //!@}
  541. using type = iterator_t; //!< Export type as identity meta-function
  542. //! #define-like enumerator for cursor
  543. enum Cursor {
  544. beg = 0, //!< Points the first item
  545. eos = N, //!< Points one place after last item
  546. };
  547. private:
  548. container_t* owner_; /*!<
  549. * Pointer to parent/owner device class. Constructor demands
  550. * owner container in order to access data. Considering the data
  551. * don't "live" in memory.
  552. */
  553. size_t cursor_{beg}; //!< virtual cursor for comparison operators
  554. /*!
  555. * Current value wrapper type, to used as put event catcher
  556. * owner_->get : Use v_ directly
  557. * owner_->put : Use operator=
  558. */
  559. struct value_type_t {
  560. value_type v_; //!< Current value buffer to access via get
  561. value_type_t(value_type v =0) : v_{v} { }
  562. operator value_type() { return v_; }
  563. operator reference() { return v_; }
  564. value_type& operator= (const value_type& v) {
  565. v_ = v; //!< Catch any attempt to write to value_
  566. owner_->put (v_, cursor_); //!< Sync the data back to device
  567. }
  568. } value_ {};
  569. /*!
  570. * \name Constructor / Destructor
  571. * \note
  572. * We can not provide a default constructor as long as we depend
  573. * on container_t (the owner type).
  574. */
  575. //!@{
  576. public:
  577. //! \brief Basic constructor
  578. explicit idxdev_it (container_t* owner, size_t curor =beg) noexcept
  579. : owner_{owner},
  580. cursor_{curor},
  581. value_{} { }
  582. //! \brief Basic copy constructor
  583. explicit idxdev_it (const iterator_t& it) noexcept
  584. : owner_ {const_cast<container_t*> (it.owner())},
  585. cursor_{it.cursor()},
  586. value_ {it.value()} { }
  587. //! \brief Iterator to const iterator conversion (as STL requires)
  588. //! \param it Iterator reference
  589. template<typename _It>
  590. idxdev_it (const idxdev_it<
  591. use_if_same_t <_It, typename container_t::pointer_type, container_t>,
  592. _It,
  593. N
  594. >& it) noexcept
  595. : owner_ {const_cast<container_t*> (it.owner())},
  596. cursor_{it.cursor()},
  597. value_ {it.value()} {
  598. }
  599. //! \brief Basic copy assignment operator
  600. iterator_t& operator= (const iterator_t& it) noexcept {
  601. owner_ = const_cast<container_t*>(it.owner());
  602. cursor_ = it.cursor();
  603. value_ = it.value();
  604. }
  605. //!@}
  606. //!@{ \name Public interface
  607. public:
  608. /*!
  609. * De-reference operator. This is where the input method is invoked
  610. * \note
  611. * No end() place dereference check is made.
  612. */
  613. reference operator* () noexcept {
  614. owner_->get (value_.v_, cursor_);
  615. return value_;
  616. }
  617. //! Arrow operator. This is where the input method is invoked
  618. pointer operator-> () noexcept {
  619. owner_->get (value_.v_, cursor_);
  620. return &value_;
  621. }
  622. //! Pre increment.
  623. iterator_t& operator++ () noexcept {
  624. ++cursor_;
  625. return *this;
  626. }
  627. //! Post increment.
  628. iterator_t operator++ (int) noexcept {
  629. iterator_t ret = *this;
  630. ++cursor_;
  631. return *this;
  632. }
  633. /*!
  634. * \note
  635. * The following are not requirements for input iterator.
  636. * We provide them nevertheless.
  637. */
  638. //! Pre decrement.
  639. iterator_t& operator-- () noexcept {
  640. --cursor_;
  641. return *this;
  642. }
  643. //! Post decrement.
  644. iterator_t operator-- (int) noexcept {
  645. iterator_t ret = *this;
  646. --cursor_;
  647. return *this;
  648. }
  649. //! Random access through iterator
  650. reference operator[] (difference_type n) noexcept {
  651. owner_->get (value_.v_, cursor_ = n);
  652. return value_;
  653. }
  654. //! Random cursor increment
  655. iterator_t& operator+= (difference_type n) noexcept {
  656. cursor_ += n;
  657. return *this;
  658. }
  659. //! Addition operation
  660. iterator_t operator+ (difference_type n) const noexcept {
  661. return iterator_t (owner_, cursor_ + n);
  662. }
  663. //! Random cursor decrement
  664. iterator_t& operator-= (difference_type n) noexcept {
  665. cursor_ -= n;
  666. return *this;
  667. }
  668. //! Subtraction operation
  669. iterator_t operator- (difference_type n) const noexcept {
  670. return iterator_t (owner_, cursor_ - n);
  671. }
  672. //! Export container for comparison
  673. const container_t* owner () const noexcept { return owner_; }
  674. //! Export cursor for comparison
  675. const size_t& cursor () const noexcept { return cursor_; }
  676. //! Export value for comparison
  677. const value_type_t& value () const noexcept { return value_; }
  678. //!@}
  679. };
  680. /*!
  681. * \brief
  682. * Equality comparison template so that comparison between cv-qualified and
  683. * non-cv-qualified iterators be valid
  684. * \param lhs Left hand site iterator
  685. * \param rhs Right hand site iterator
  686. * \return True in equality
  687. */
  688. template<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
  689. inline bool operator== (const idxdev_it<_Cont, _It_L, _Size>& lhs,
  690. const idxdev_it<_Cont, _It_R, _Size>& rhs) noexcept {
  691. return ((lhs.cursor() == rhs.cursor()) &&
  692. (lhs.owner() == rhs.owner()));
  693. }
  694. /*!
  695. * \brief
  696. * Inequality comparison template so that comparison between cv-qualified and
  697. * non-cv-qualified iterators be valid
  698. * \param lhs Left hand site iterator
  699. * \param rhs Right hand site iterator
  700. * \return True in inequality
  701. */
  702. template<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
  703. inline bool operator!= (const idxdev_it<_Cont, _It_L, _Size>& lhs,
  704. const idxdev_it<_Cont, _It_R, _Size>& rhs) noexcept {
  705. return ((lhs.cursor() != rhs.cursor()) ||
  706. (lhs.owner() != rhs.owner()));
  707. }
  708. /*!
  709. * \note
  710. * The following are not requirements for input iterator.
  711. * Nevertheless we provide them.
  712. * \warn
  713. * Required: The rhs and lhs MUST be from the same owner or the
  714. * resuled is undefined.
  715. */
  716. //!@{
  717. template<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
  718. inline bool operator< (const idxdev_it<_Cont, _It_L, _Size>& lhs,
  719. const idxdev_it<_Cont, _It_R, _Size>& rhs) noexcept {
  720. return (lhs.cursor() < rhs.cursor());
  721. }
  722. template<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
  723. inline bool operator<= (const idxdev_it<_Cont, _It_L, _Size>& lhs,
  724. const idxdev_it<_Cont, _It_R, _Size>& rhs) noexcept {
  725. return (lhs.cursor() <= rhs.cursor());
  726. }
  727. template<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
  728. inline bool operator> (const idxdev_it<_Cont, _It_L, _Size>& lhs,
  729. const idxdev_it<_Cont, _It_R, _Size>& rhs) noexcept {
  730. return (lhs.cursor() > rhs.cursor());
  731. }
  732. template<typename _Cont, typename _It_L, typename _It_R, size_t _Size>
  733. inline bool operator>= (const idxdev_it<_Cont, _It_L, _Size>& lhs,
  734. const idxdev_it<_Cont, _It_R, _Size>& rhs) noexcept {
  735. return (lhs.cursor() >= rhs.cursor());
  736. }
  737. //!@}
  738. /*!
  739. * Index device iterator concept
  740. */
  741. //! @{
  742. #if defined _utl_have_concepts
  743. template <typename T>
  744. concept bool Idxdev_it = requires (T t, const T ct) {
  745. // STL compatibility
  746. typename T::value_type;
  747. typename T::difference_type;
  748. typename T::pointer;
  749. typename T::reference;
  750. requires same_<
  751. typename T::iterator_category,
  752. std::input_iterator_tag
  753. >::value;
  754. {*t} -> typename T::value_type; // is dereferencable
  755. {++t} -> T&; // is incrementable
  756. {t++} -> T;
  757. // Extras
  758. {ct.owner()} ->auto&&;
  759. {ct.cursor()} -> const size_t;
  760. {ct.value()} -> auto&&;
  761. };
  762. #else
  763. namespace idxdev_it_details {
  764. using std::declval;
  765. //! Primary template to catch any non SPI interface types
  766. template <typename _Tp, typename =void>
  767. struct is_idxdev_it_ : false_ {};
  768. //! template to catch a proper SPI interface type
  769. template <typename _Tp>
  770. struct is_idxdev_it_ <
  771. _Tp,
  772. void_t <
  773. typename T::value_type,
  774. typename T::difference_type,
  775. typename T::pointer,
  776. typename T::reference,
  777. use_if_same_t <
  778. typename T::iterator_category,
  779. std::input_iterator_tag
  780. >
  781. >
  782. > : true_ {};
  783. }
  784. /*!
  785. * Value meta-programming function for SPI interface checking
  786. * \param _Tp Type to check
  787. * \return True if _Tp is a spi interface
  788. */
  789. template <typename _Tp>
  790. constexpr bool Idxdev_it = idxdev_it_details::is_idxdev_it_<_Tp>::value;
  791. #endif
  792. //! @}
  793. }
  794. //!@}
  795. #endif /* __utl_dev_dev_iterators_h__ */