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.
 
 
 
 

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