Micro template library A library for building device drivers
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

855 lignes
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__ */