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.
 
 
 
 

1009 lignes
38 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/core/impl.h>
  24. #include <utl/meta/meta.h>
  25. namespace utl {
  26. /*!
  27. * \ingroup Devices
  28. * \brief Device iterator collection.
  29. */
  30. //!@{
  31. /*!
  32. * \brief Traits class for dev_iterators.
  33. *
  34. * This class does nothing but define nested typedefs. The general
  35. * version simply @a forwards the nested typedefs from the Iterator
  36. * argument.
  37. */
  38. template <typename _Cat, typename _Tp, typename _Diff =ptrdiff_t>
  39. struct dev_iterator_traits {
  40. using iterator_category = _Cat;
  41. using value_type = _Tp;
  42. using difference_type = _Diff;
  43. using pointer = _Tp*;
  44. using reference = _Tp&;
  45. };
  46. /*!
  47. * \brief Iterator tags [std.iterator.tags]
  48. * Extension: contiguous_iterator_tag for denoting contiguous iterators.
  49. */
  50. struct output_iterator_tag {};
  51. struct input_iterator_tag {};
  52. struct forward_iterator_tag : input_iterator_tag {};
  53. struct bidirectional_iterator_tag : forward_iterator_tag {};
  54. struct random_access_iterator_tag : bidirectional_iterator_tag {};
  55. struct contiguous_iterator_tag : random_access_iterator_tag {};
  56. /*
  57. * ================ Output device Iterator =================
  58. */
  59. template <typename cont_t, typename data_t>
  60. class ostreamdev_it {
  61. using iterator_t = ostreamdev_it <cont_t, data_t>; //! iterator type local name
  62. public:
  63. using type = iterator_t; //!< Export type as identity meta-function
  64. //! STL iterator traits "forwarding"
  65. //!@{
  66. public:
  67. using iterator_category = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::iterator_category;
  68. using value_type = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::value_type;
  69. using difference_type = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::difference_type;
  70. using pointer = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::pointer;
  71. using reference = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::reference;
  72. //!@}
  73. private:
  74. cont_t* owner_ {nullptr}; /*!<
  75. * Pointer to parent/owner device class. Usable iterator demands
  76. * owner container in order to access data. Considering the data
  77. * don't "live" in memory. A default constructed iterator will behave
  78. * like end() just like the input version does.
  79. */
  80. /*!
  81. * \name Constructor / Destructor
  82. */
  83. //!@{
  84. public:
  85. //! \brief Basic constructor
  86. ostreamdev_it (cont_t* owner =nullptr) noexcept
  87. : owner_ {owner} { }
  88. //! \brief Basic copy constructor
  89. ostreamdev_it (const iterator_t& it) noexcept
  90. : owner_ {const_cast<cont_t*>(it.owner_)} { }
  91. //! \brief Basic copy assignment operator
  92. iterator_t& operator= (const iterator_t& it) noexcept {
  93. owner_ = const_cast<cont_t*>(it.owner_);
  94. return *this;
  95. }
  96. //!@}
  97. //!@{ \name Public interface
  98. public:
  99. iterator_t& operator* () noexcept { return *this; }
  100. /*!
  101. * \brief
  102. * Value-assignment operation. Where the output method is invoked
  103. * \param value An instance of Cont_t::data_type
  104. * \return This %iterator, for chained operations.
  105. */
  106. iterator_t& operator= (const value_type& value) {
  107. if (owner_ != nullptr)
  108. owner_->put (value);
  109. return *this;
  110. }
  111. iterator_t& operator++ () noexcept { return *this; }
  112. iterator_t& operator++ (int) noexcept { return *this; }
  113. //!@}
  114. };
  115. template <typename cont_t, typename data_t>
  116. class istreamdev_it {
  117. using iterator_t = istreamdev_it <cont_t, data_t>; //! iterator type local name
  118. public:
  119. using type = iterator_t; //!< Export type as identity meta-function
  120. //! STL iterator traits "forwarding"
  121. //!@{
  122. public:
  123. using iterator_category = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::iterator_category;
  124. using value_type = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::value_type;
  125. using difference_type = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::difference_type;
  126. using pointer = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::pointer;
  127. using reference = typename dev_iterator_traits <std::output_iterator_tag, data_t, void>::reference;
  128. //!@}
  129. //! #define-like enumerator for Cursor-like behavior
  130. enum Cursor {
  131. init = 0,
  132. valid = 1,
  133. eos = 2
  134. };
  135. //!@{ \name Data members
  136. private:
  137. cont_t* owner_ {nullptr}; /*!<
  138. * Pointer to parent/owner device class. Usable iterator demands
  139. * owner container in order to access data. Considering the data
  140. * don't "live" in memory.
  141. */
  142. value_type value_ {};
  143. Cursor cursor_ {init};
  144. //!@}
  145. /*!
  146. * \name Constructor / Destructor
  147. */
  148. //!@{
  149. public:
  150. //! \brief Basic constructor
  151. istreamdev_it (cont_t* owner =nullptr, Cursor cursor =eos) noexcept :
  152. owner_ {owner},
  153. value_ {},
  154. cursor_{cursor} { }
  155. //! \brief Basic copy constructor
  156. istreamdev_it (const iterator_t& it) noexcept :
  157. owner_ {const_cast<cont_t*>(it.owner_)},
  158. value_ {it.value_},
  159. cursor_ {it.cursor_} { }
  160. //! \brief Basic copy assignment operator
  161. iterator_t& operator= (const iterator_t& it) noexcept {
  162. owner_ = const_cast<cont_t*>(it.owner_);
  163. value_ = it.value_;
  164. cursor_ = it.cursor_;
  165. return *this;
  166. }
  167. //!@}
  168. //!@{ \name Public interface
  169. public:
  170. value_type& operator* () noexcept {
  171. if (cursor_ == init)
  172. ++*this;
  173. return value_;
  174. }
  175. value_type* operator->() noexcept {
  176. if (cursor_ == init)
  177. ++*this;
  178. return &value_;
  179. }
  180. iterator_t& operator++ () noexcept {
  181. _get(value_);
  182. return *this;
  183. }
  184. iterator_t operator++ (int) noexcept {
  185. iterator_t r = *this;
  186. _get(value_);
  187. return r;
  188. }
  189. //! Export container for comparison
  190. const cont_t* owner () const noexcept { return owner_; }
  191. //! Export value for comparison
  192. const value_type& value () const noexcept { return value_; }
  193. //! Export cursor for comparison
  194. const Cursor cursor () const noexcept { return cursor_; }
  195. //!@}
  196. //!@{ \name private api
  197. private:
  198. void _get(value_type& v) {
  199. owner_->get(v);
  200. cursor_ = (v) ? valid : eos;
  201. }
  202. //!@}
  203. };
  204. /*!
  205. * \brief
  206. * Equality comparison template so that comparison between cv-qualified and
  207. * non-cv-qualified iterators be valid
  208. * \param lhs Left hand site iterator
  209. * \param rhs Right hand site iterator
  210. * \return True in equality
  211. */
  212. template<typename _C1, typename _D1, typename _C2, typename _D2>
  213. inline bool operator== (const istreamdev_it<_C1, _D1>& lhs,
  214. const istreamdev_it<_C2, _D2>& rhs) noexcept {
  215. return ((lhs.owner() == rhs.owner()) &&
  216. (lhs.value() == rhs.value()) &&
  217. (lhs.cursor() == rhs.cursor()));
  218. }
  219. template<typename _C1, typename _D1, typename _C2, typename _D2>
  220. inline bool operator!= (const istreamdev_it<_C1, _D1>& lhs,
  221. const istreamdev_it<_C2, _D2>& rhs) noexcept {
  222. return !operator==(lhs, rhs);
  223. }
  224. /*!
  225. * \brief
  226. * Output device iterator type. We "future call" interface methods
  227. * from owner class to provide iterator functionality.
  228. * \param cont_t Container/parent type
  229. * \param iter_t Iterator data type (pointer to container_t::value_type)
  230. * \param devsize Device's address space size
  231. */
  232. template<typename cont_t, typename iter_t, index_t _beg =0, index_t _end =static_cast<index_t>(-1)>
  233. class outdev_it {
  234. //! iterator type local name
  235. using iterator_t = outdev_it <cont_t, iter_t, _beg, _end>;
  236. public:
  237. using type = iterator_t; //!< Export type as identity meta-function
  238. //! STL iterator traits "forwarding"
  239. //!@{
  240. public:
  241. using iterator_category = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::iterator_category;
  242. using value_type = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::value_type;
  243. using difference_type = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::difference_type;
  244. using pointer = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::pointer;
  245. using reference = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::reference;
  246. //!@}
  247. //! #define-like enumerator for Cursor
  248. enum Cursor {
  249. beg = _beg, //!< Points the first item (relative address)
  250. eod = _end, //!< Points one place after last item (relative address)
  251. };
  252. private:
  253. cont_t* owner_ {nullptr}; /*!<
  254. * Pointer to parent/owner device class. Usable iterator demands
  255. * owner container in order to access data. Considering the data
  256. * don't "live" in memory. A default constructed iterator will behave
  257. * like end() just like the input version does.
  258. */
  259. index_t cursor_ {eod}; //!< virtual cursor for comparison operators
  260. /*!
  261. * \name Constructor / Destructor
  262. */
  263. //!@{
  264. public:
  265. //! \brief Default constructor results to end()
  266. explicit outdev_it() noexcept :
  267. owner_ {nullptr},
  268. cursor_{eod} { }
  269. //! \brief Basic constructor
  270. explicit outdev_it (cont_t* owner, index_t cursor =eod) noexcept :
  271. owner_ {owner},
  272. cursor_{cursor} { }
  273. //! \brief Basic copy constructor
  274. explicit outdev_it (const iterator_t& it) noexcept :
  275. owner_ {const_cast<cont_t*>(it.owner_)},
  276. cursor_{it.cursor_} { }
  277. //! \brief Basic copy assignment operator
  278. iterator_t& operator= (const iterator_t& it) noexcept {
  279. owner_ = const_cast<cont_t*>(it.owner_);
  280. cursor_ = it.cursor_;
  281. }
  282. //! \brief Iterator to const-iterator conversion (as STL requires)
  283. //! \param it Iterator reference
  284. // template<typename _It>
  285. // outdev_it (const outdev_it<
  286. // use_if_same_t <_It, typename container_t::pointer_type, container_t>,
  287. // _It,
  288. // streamsize
  289. // >& it) noexcept
  290. // : owner_ {const_cast<container_t*>(it.owner())},
  291. // cursor_ {it.cursor()} { }
  292. //!@}
  293. //!@{ \name Public interface
  294. public:
  295. iterator_t& operator* () noexcept { return *this; }
  296. /*!
  297. * \brief
  298. * Value-assignment operation. Where the output method is invoked
  299. * \param value An instance of Cont_t::data_type
  300. * \return This %iterator, for chained operations.
  301. */
  302. iterator_t& operator= (const value_type& value) {
  303. // end() and default constructible iterators are not dereferenceable
  304. if (cursor_ != eod)
  305. owner_->put (value, cursor_);
  306. return *this;
  307. }
  308. //!@{ \name ++ operators
  309. iterator_t& operator++ () noexcept {
  310. ++cursor_;
  311. return *this;
  312. }
  313. iterator_t operator++ (int) noexcept {
  314. iterator_t ret = *this;
  315. ++cursor_;
  316. return ret;
  317. }
  318. //!@}
  319. //! Export container for comparison
  320. const cont_t* owner () const noexcept { return owner_; }
  321. //! Export cursor for comparison
  322. const index_t cursor () const noexcept { return cursor_; }
  323. //!@}
  324. };
  325. /*!
  326. * \note
  327. * The following are not requirements for output iterator.
  328. * We provide them nevertheless.
  329. * \warn
  330. * Required: The rhs and lhs MUST belong to the same owner or
  331. * the result is undefined.
  332. */
  333. //!@{
  334. /*!
  335. * \brief
  336. * Equality comparison template so that comparison between cv-qualified and
  337. * non-cv-qualified iterators be valid
  338. * \param lhs Left hand site iterator
  339. * \param rhs Right hand site iterator
  340. * \return True in equality
  341. */
  342. template<typename _Cont1, typename _It1, index_t _beg1, index_t _end1,
  343. typename _Cont2, typename _It2, index_t _beg2, index_t _end2>
  344. inline bool operator== (const outdev_it<_Cont1, _It1, _beg1, _end1>& lhs,
  345. const outdev_it<_Cont2, _It2, _beg2, _end2>& rhs) noexcept {
  346. return ((lhs.cursor() == rhs.cursor()) &&
  347. (lhs.owner() == rhs.owner()));
  348. }
  349. /*!
  350. * \brief
  351. * Inequality comparison template so that comparison between cv-qualified and
  352. * non-cv-qualified iterators be valid
  353. * \param lhs Left hand site iterator
  354. * \param rhs Right hand site iterator
  355. * \return True in inequality
  356. */
  357. template<typename _Cont1, typename _It1, index_t _beg1, index_t _end1,
  358. typename _Cont2, typename _It2, index_t _beg2, index_t _end2>
  359. inline bool operator!= (const outdev_it<_Cont1, _It1, _beg1, _end1>& lhs,
  360. const outdev_it<_Cont2, _It2, _beg2, _end2>& rhs) noexcept {
  361. return !(lhs == rhs);
  362. }
  363. //!@}
  364. /*!
  365. * Output device iterator concept
  366. */
  367. //! @{
  368. #if defined _utl_have_concepts
  369. template <typename T>
  370. concept bool Outdev_it = requires (T t) {
  371. // STL compatibility
  372. typename T::value_type;
  373. typename T::difference_type;
  374. typename T::pointer;
  375. typename T::reference;
  376. requires same_<
  377. typename T::iterator_category,
  378. std::output_iterator_tag
  379. >::value;
  380. {*t} -> auto&&; // is dereferencable, and return non-void
  381. {++t} -> T&; // is incrementable
  382. {t++} -> T;
  383. // Extras
  384. {t.owner()} ->auto&&;
  385. {t.cursor()} -> size_t;
  386. };
  387. #else
  388. namespace outdev_it_details {
  389. using std::declval;
  390. //! Primary template to catch any non SPI interface types
  391. template <typename _Tp, typename =void>
  392. struct is_outdev_it_ : meta::false_ {};
  393. //! template to catch a proper SPI interface type
  394. template <typename _Tp>
  395. struct is_outdev_it_ <
  396. _Tp,
  397. meta::void_t <
  398. typename _Tp::value_type,
  399. typename _Tp::difference_type,
  400. typename _Tp::pointer,
  401. typename _Tp::reference,
  402. meta::use_if_same_t <
  403. typename _Tp::iterator_category,
  404. std::output_iterator_tag
  405. >
  406. >
  407. > : meta::true_ {};
  408. }
  409. /*!
  410. * Value meta-programming function for SPI interface checking
  411. * \param _Tp Type to check
  412. * \return True if _Tp is a spi interface
  413. */
  414. template <typename _Tp>
  415. constexpr bool Outdev_it = outdev_it_details::is_outdev_it_<_Tp>::value;
  416. #endif
  417. //! @}
  418. /*
  419. * ================ Input device Iterator =================
  420. */
  421. /*!
  422. * \brief
  423. * Input device iterator type. We "future call" interface methods
  424. * from owner class to provide iterator functionality.
  425. * \param cont_t Container/parent type
  426. * \param iter_t Iterator data type (pointer to container_t::value_type)
  427. * \param _beg Device starting address
  428. * \param _size Device's address space size
  429. */
  430. template<typename cont_t, typename iter_t, index_t _beg =0, size_t _size = static_cast<size_t>(-1)-_beg>
  431. class indev_it {
  432. //!< iterator type local name
  433. using iterator_t = indev_it <cont_t, iter_t, _beg, _size>;
  434. public:
  435. using type = iterator_t; //!< Export type as identity meta-function
  436. //! STL iterator traits "forwarding"
  437. //!@{
  438. public:
  439. using iterator_category = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::iterator_category;
  440. using value_type = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::value_type;
  441. using difference_type = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::difference_type;
  442. using pointer = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::pointer;
  443. using reference = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::reference;
  444. //!@}
  445. //! #define-like enumerator for Cursor
  446. enum Cursor {
  447. beg = _beg, //!< Points the first item
  448. eod = _beg + _size, //!< Points one place after last item
  449. };
  450. private:
  451. cont_t* owner_{nullptr}; /*!<
  452. * Pointer to parent/owner device class. Constructor demands
  453. * owner container in order to access data. Considering the data
  454. * don't "live" in memory.
  455. */
  456. index_t cursor_{eod}; //!< virtual cursor for comparison operators
  457. value_type value_ {}; //!< The current value, used as cache
  458. /*!
  459. * \name Constructor / Destructor
  460. * \note
  461. * We can not provide a default constructor as long as we depend
  462. * on container_t (the owner type).
  463. */
  464. //!@{
  465. public:
  466. //! \brief Default constructor
  467. indev_it () noexcept :
  468. owner_ {nullptr},
  469. cursor_{eod},
  470. value_ {} { }
  471. //! \brief Basic constructor
  472. explicit indev_it (cont_t* own, size_t cur =eod) noexcept :
  473. owner_ {own},
  474. cursor_{cur},
  475. value_ {} { }
  476. //! \brief Basic copy constructor
  477. explicit indev_it (const iterator_t& it) noexcept :
  478. owner_ {const_cast<cont_t*>(it.owner_)},
  479. cursor_{it.cursor_},
  480. value_ {it.value_} { }
  481. //! \brief Basic copy assignment operator
  482. iterator_t& operator= (const iterator_t& it) noexcept {
  483. owner_ = const_cast<cont_t*>(it.owner_);
  484. cursor_ = it.cursor_;
  485. value_ = it.value_;
  486. }
  487. //! \brief Iterator to const-iterator conversion (as STL requires)
  488. //! \param it Iterator reference
  489. // template<typename _It>
  490. // indev_it (const indev_it<
  491. // use_if_same_t <_It, typename container_t::pointer_type, container_t>,
  492. // _It,
  493. // streamsize
  494. // >& it) noexcept
  495. // : owner_ {const_cast<container_t*>(it.owner())},
  496. // cursor_{it.cursor()},
  497. // value_ {it.value()} { }
  498. //!@}
  499. //!@{ \name Public interface
  500. public:
  501. //! De-reference operator. No end() place dereference check is made.
  502. reference operator* () {
  503. owner_->get (value_, cursor_);
  504. return value_;
  505. }
  506. //! Arrow operator. No end() place dereference check is made.
  507. pointer operator-> () {
  508. owner_->get (value_, cursor_);
  509. return &value_;
  510. }
  511. //! Pre increment.
  512. iterator_t& operator++ () {
  513. ++cursor_;
  514. return *this;
  515. }
  516. //! Post increment.
  517. iterator_t operator++ (int) {
  518. iterator_t ret(*this);
  519. ++cursor_;
  520. return *this;
  521. }
  522. //! Pre decrement.
  523. iterator_t& operator-- () {
  524. --cursor_;
  525. return *this;
  526. }
  527. //! Post decrement.
  528. iterator_t operator-- (int) {
  529. iterator_t ret(*this);
  530. --cursor_;
  531. return *this;
  532. }
  533. //! [] operator. Is a combination of input method and dereference
  534. reference operator[] (difference_type n) {
  535. owner_->get (value_, cursor_ += n);
  536. return value_;
  537. }
  538. iterator_t& operator+= (difference_type n) {
  539. cursor_ += n;
  540. return *this;
  541. }
  542. iterator_t operator+ (difference_type n) {
  543. return iterator_t (owner_, cursor_ + n);
  544. }
  545. iterator_t& operator-= (difference_type n) {
  546. cursor_ -= n;
  547. return *this;
  548. }
  549. iterator_t operator- (difference_type n) {
  550. return iterator_t (owner_, cursor_ - n);
  551. }
  552. //! Export container for comparison
  553. const cont_t* owner () const noexcept { return owner_; }
  554. //! Export cursor for comparison
  555. const index_t cursor () const noexcept { return cursor_; }
  556. //! Export value for comparison
  557. //const reference value () const noexcept { return value_; }
  558. //!@}
  559. };
  560. /*!
  561. * \name indev_it EqualityComparable && LessThanComparable requirements
  562. * comparison template so that comparison between cv-qualified and
  563. * non-cv-qualified iterators be valid
  564. */
  565. //!@{
  566. //! Equality
  567. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  568. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  569. inline bool operator== (const indev_it<_Cont1, _It1, _beg1, _size1>& x,
  570. const indev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  571. return (x.owner() == y.owner() &&
  572. (x.cursor() == y.cursor()));
  573. }
  574. //! Less than
  575. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  576. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  577. inline bool operator< (const indev_it<_Cont1, _It1, _beg1, _size1>& x,
  578. const indev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  579. return (x.cursor() < y.cursor());
  580. }
  581. // relative ops
  582. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  583. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  584. inline bool operator!= (const indev_it<_Cont1, _It1, _beg1, _size1>& x,
  585. const indev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  586. return !(x == y);
  587. }
  588. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  589. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  590. inline bool operator<= (const indev_it<_Cont1, _It1, _beg1, _size1>& x,
  591. const indev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  592. return !(y < x);
  593. }
  594. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  595. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  596. inline bool operator> (const indev_it<_Cont1, _It1, _beg1, _size1>& x,
  597. const indev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  598. return (y < x);
  599. }
  600. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  601. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  602. inline bool operator>= (const indev_it<_Cont1, _It1, _beg1, _size1>& x,
  603. const indev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  604. return !(x < y);
  605. }
  606. //!@}
  607. //! @{ \name iterator arithmetic
  608. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  609. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  610. inline auto operator- (indev_it<_Cont1, _It1, _beg1, _size1>& x,
  611. indev_it<_Cont1, _It1, _beg1, _size1>& y) noexcept
  612. -> decltype (x.cursor() - y.cursor()) {
  613. return (x.cursor() - y.cursor());
  614. }
  615. template<typename _Cont, typename _It, index_t _beg, size_t _size>
  616. inline indev_it<_Cont, _It, _beg, _size>
  617. operator+ (typename _Cont::difference_type n,
  618. indev_it<_Cont, _It, _beg, _size>& it) noexcept {
  619. return indev_it<_Cont, _It, _beg, _size>(it.owner(), it.cursor() + n);
  620. }
  621. //! @}
  622. /*!
  623. * Input device iterator concept
  624. */
  625. //! @{
  626. #if defined _utl_have_concepts
  627. template <typename T>
  628. concept bool Indev_it = requires (T t, const T ct) {
  629. // STL compatibility
  630. typename T::value_type;
  631. typename T::difference_type;
  632. typename T::pointer;
  633. typename T::reference;
  634. requires same_ <
  635. typename T::iterator_category,
  636. std::input_iterator_tag
  637. >::value;
  638. {*t} -> typename T::value_type; // is dereferencable
  639. {++t} -> T&; // is incrementable
  640. {t++} -> T;
  641. // Extras
  642. {ct.owner()} ->auto&&;
  643. {ct.cursor()} -> const size_t;
  644. {ct.value()} -> auto&&;
  645. };
  646. #else
  647. namespace indev_it_details {
  648. using std::declval;
  649. //! Primary template to catch any non SPI interface types
  650. template <typename _Tp, typename =void>
  651. struct is_indev_it_ : meta::false_ {};
  652. //! template to catch a proper SPI interface type
  653. template <typename _Tp>
  654. struct is_indev_it_ <
  655. _Tp,
  656. meta::void_t <
  657. typename _Tp::value_type,
  658. typename _Tp::difference_type,
  659. typename _Tp::pointer,
  660. typename _Tp::reference,
  661. meta::use_if_same_t <
  662. typename _Tp::iterator_category,
  663. std::input_iterator_tag
  664. >
  665. >
  666. > : meta::true_ {};
  667. }
  668. /*!
  669. * Value meta-programming function for SPI interface checking
  670. * \param _Tp Type to check
  671. * \return True if _Tp is a spi interface
  672. */
  673. template <typename _Tp>
  674. constexpr bool Indev_it = indev_it_details::is_indev_it_<_Tp>::value;
  675. #endif
  676. //! @}
  677. /*
  678. * ================= Indexed device Iterator =================
  679. */
  680. /*!
  681. * \brief
  682. * Indexed device iterator type. We "future call" interface methods
  683. * from owner class to provide iterator functionality.
  684. * \note
  685. * This is a contiguous iterator
  686. * \param cont_t Container/parent type
  687. * \param iter_t Iterator data type (pointer to container_t::value_type)
  688. * \param _beg Starting address of the device
  689. * \param _size Device's address space size
  690. */
  691. template<typename cont_t, typename iter_t, index_t _beg =0, size_t _size = static_cast<size_t>(-1)-_beg>
  692. class iodev_it {
  693. //!< iterator type local name
  694. using iterator_t = iodev_it <cont_t, iter_t, _beg, _size>;
  695. public:
  696. using type = iterator_t; //!< Export type as identity meta-function
  697. //! STL iterator traits "forwarding"
  698. //!@{
  699. public:
  700. using iterator_category = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::iterator_category;
  701. using value_type = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::value_type;
  702. using difference_type = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::difference_type;
  703. using pointer = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::pointer;
  704. using reference = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::reference;
  705. //!@}
  706. //! #define-like enumerator for Cursor
  707. enum Cursor {
  708. beg = _beg, //!< Points the first item
  709. eod = _beg+_size, //!< Points one place after last item
  710. };
  711. private:
  712. cont_t* owner_{nullptr}; /*!<
  713. * Pointer to parent/owner device class. Constructor demands
  714. * owner container in order to access data. Considering the data
  715. * don't "live" in memory.
  716. */
  717. index_t cursor_{eod}; //!< virtual cursor for comparison operators
  718. /*!
  719. * Current value wrapper type, to used as put event catcher
  720. * owner_->get : Use v_ directly
  721. * owner_->put : Use operator= to a dereferenced iterator
  722. */
  723. struct value_type_t {
  724. value_type v_; //!< Current value buffer to access via get
  725. value_type_t(value_type v =value_type{}) :
  726. v_{v} { }
  727. operator value_type() { return v_; }
  728. operator reference() { return v_; }
  729. value_type& operator= (const value_type& v) {
  730. //!< Catch any attempt to write to value_ and sync the data back to device
  731. owner_->put (v_ =v, cursor_);
  732. }
  733. } value_ {};
  734. /*!
  735. * \name Constructor / Destructor
  736. */
  737. //!@{
  738. public:
  739. //! \brief Default constructor
  740. iodev_it () noexcept :
  741. owner_ {nullptr},
  742. cursor_{eod},
  743. value_ {} { }
  744. //! \brief Basic constructor
  745. explicit iodev_it (cont_t* owner, size_t cursor =eod) noexcept :
  746. owner_ {owner},
  747. cursor_{cursor},
  748. value_ {} { }
  749. //! \brief Basic copy constructor
  750. explicit iodev_it (const iterator_t& it) noexcept :
  751. owner_ {const_cast<cont_t*>(it.owner_)},
  752. cursor_{it.cursor_},
  753. value_ {it.value_} { }
  754. //! \brief Basic copy assignment operator
  755. iterator_t& operator= (const iterator_t& it) noexcept {
  756. owner_ = const_cast<cont_t*>(it.owner_);
  757. cursor_ = it.cursor_;
  758. value_ = it.value_;
  759. }
  760. //!@}
  761. //!@{ \name Public interface
  762. public:
  763. /*!
  764. * De-reference operator. This is where the input method is invoked
  765. * \note
  766. * No end() place dereference check is made.
  767. */
  768. reference operator* () noexcept {
  769. owner_->get (value_.v_, cursor_);
  770. return value_;
  771. }
  772. //! Arrow operator. This is where the input method is invoked
  773. pointer operator-> () noexcept {
  774. owner_->get (value_.v_, cursor_);
  775. return &value_;
  776. }
  777. //! Pre increment.
  778. iterator_t& operator++ () noexcept {
  779. ++cursor_;
  780. return *this;
  781. }
  782. //! Post increment.
  783. iterator_t operator++ (int) noexcept {
  784. iterator_t ret = *this;
  785. ++cursor_;
  786. return *this;
  787. }
  788. //! Pre decrement.
  789. iterator_t& operator-- () noexcept {
  790. --cursor_;
  791. return *this;
  792. }
  793. //! Post decrement.
  794. iterator_t operator-- (int) noexcept {
  795. iterator_t ret = *this;
  796. --cursor_;
  797. return *this;
  798. }
  799. //! Random access through iterator
  800. reference operator[] (difference_type n) noexcept {
  801. owner_->get (value_.v_, cursor_ = n);
  802. return value_;
  803. }
  804. //! Random cursor increment
  805. iterator_t& operator+= (difference_type n) noexcept {
  806. cursor_ += n;
  807. return *this;
  808. }
  809. //! Addition operation
  810. iterator_t operator+ (difference_type n) const noexcept {
  811. return iterator_t (owner_, cursor_ + n);
  812. }
  813. //! Random cursor decrement
  814. iterator_t& operator-= (difference_type n) noexcept {
  815. cursor_ -= n;
  816. return *this;
  817. }
  818. //! Subtraction operation
  819. iterator_t operator- (difference_type n) const noexcept {
  820. return iterator_t (owner_, cursor_ - n);
  821. }
  822. //! Export container for comparison
  823. const cont_t* owner () const noexcept { return owner_; }
  824. //! Export cursor for comparison
  825. const index_t& cursor () const noexcept { return cursor_; }
  826. //! Export value for comparison
  827. //const value_type_t& value () const noexcept { return value_; }
  828. //!@}
  829. };
  830. /*!
  831. * \name indev_it EqualityComparable && LessThanComparable requirements
  832. * comparison template so that comparison between cv-qualified and
  833. * non-cv-qualified iterators be valid
  834. */
  835. //!@{
  836. //! Equality
  837. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  838. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  839. inline bool operator== (const iodev_it<_Cont1, _It1, _beg1, _size1>& x,
  840. const iodev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  841. return (x.owner() == y.owner() &&
  842. (x.cursor() == y.cursor()));
  843. }
  844. //! Less than
  845. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  846. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  847. inline bool operator< (const iodev_it<_Cont1, _It1, _beg1, _size1>& x,
  848. const iodev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  849. return (x.cursor() < y.cursor());
  850. }
  851. // relative ops
  852. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  853. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  854. inline bool operator!= (const iodev_it<_Cont1, _It1, _beg1, _size1>& x,
  855. const iodev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  856. return !(x == y);
  857. }
  858. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  859. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  860. inline bool operator<= (const iodev_it<_Cont1, _It1, _beg1, _size1>& x,
  861. const iodev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  862. return !(y < x);
  863. }
  864. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  865. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  866. inline bool operator> (const iodev_it<_Cont1, _It1, _beg1, _size1>& x,
  867. const iodev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  868. return (y < x);
  869. }
  870. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  871. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  872. inline bool operator>= (const iodev_it<_Cont1, _It1, _beg1, _size1>& x,
  873. const iodev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  874. return !(x < y);
  875. }
  876. //!@}
  877. //! @{ \name iterator arithmetic
  878. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  879. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  880. inline auto operator- (iodev_it<_Cont1, _It1, _beg1, _size1>& x,
  881. iodev_it<_Cont1, _It1, _beg1, _size1>& y) noexcept
  882. -> decltype (x.cursor() - y.cursor()) {
  883. return (x.cursor() - y.cursor());
  884. }
  885. template<typename _Cont, typename _It, index_t _beg, size_t _size>
  886. inline iodev_it<_Cont, _It, _beg, _size>
  887. operator+ (typename _Cont::difference_type n,
  888. iodev_it<_Cont, _It, _beg, _size>& it) noexcept {
  889. return iodev_it<_Cont, _It, _beg, _size>(it.owner(), it.cursor() + n);
  890. }
  891. //! @}
  892. /*!
  893. * Index device iterator concept
  894. */
  895. //! @{
  896. #if defined _utl_have_concepts
  897. template <typename T>
  898. concept bool Idxdev_it = requires (T t, const T ct) {
  899. // STL compatibility
  900. typename T::value_type;
  901. typename T::difference_type;
  902. typename T::pointer;
  903. typename T::reference;
  904. requires same_<
  905. typename T::iterator_category,
  906. std::input_iterator_tag
  907. >::value;
  908. {*t} -> typename T::value_type; // is dereferencable
  909. {++t} -> T&; // is incrementable
  910. {t++} -> T;
  911. // Extras
  912. {ct.owner()} ->auto&&;
  913. {ct.cursor()} -> const size_t;
  914. {ct.value()} -> auto&&;
  915. };
  916. #else
  917. namespace idxdev_it_details {
  918. using std::declval;
  919. //! Primary template to catch any non SPI interface types
  920. template <typename _Tp, typename =void>
  921. struct is_idxdev_it_ : meta::false_ {};
  922. //! template to catch a proper SPI interface type
  923. template <typename _Tp>
  924. struct is_idxdev_it_ <
  925. _Tp,
  926. meta::void_t <
  927. typename _Tp::value_type,
  928. typename _Tp::difference_type,
  929. typename _Tp::pointer,
  930. typename _Tp::reference,
  931. meta::use_if_same_t <
  932. typename _Tp::iterator_category,
  933. std::input_iterator_tag
  934. >
  935. >
  936. > : meta::true_ {};
  937. }
  938. /*!
  939. * Value meta-programming function for SPI interface checking
  940. * \param _Tp Type to check
  941. * \return True if _Tp is a spi interface
  942. */
  943. template <typename _Tp>
  944. constexpr bool Idxdev_it = idxdev_it_details::is_idxdev_it_<_Tp>::value;
  945. #endif
  946. //! @}
  947. }
  948. //!@}
  949. #endif /* __utl_dev_dev_iterators_h__ */