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

1012 lines
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. void
  407. >
  408. > : meta::true_ {};
  409. }
  410. /*!
  411. * Value meta-programming function for SPI interface checking
  412. * \param _Tp Type to check
  413. * \return True if _Tp is a spi interface
  414. */
  415. // template <typename _Tp>
  416. // constexpr bool Outdev_it = outdev_it_details::is_outdev_it_<_Tp>::value;
  417. #endif
  418. //! @}
  419. /*
  420. * ================ Input device Iterator =================
  421. */
  422. /*!
  423. * \brief
  424. * Input device iterator type. We "future call" interface methods
  425. * from owner class to provide iterator functionality.
  426. * \param cont_t Container/parent type
  427. * \param iter_t Iterator data type (pointer to container_t::value_type)
  428. * \param _beg Device starting address
  429. * \param _size Device's address space size
  430. */
  431. template<typename cont_t, typename iter_t, index_t _beg =0, size_t _size = static_cast<size_t>(-1)-_beg>
  432. class indev_it {
  433. //!< iterator type local name
  434. using iterator_t = indev_it <cont_t, iter_t, _beg, _size>;
  435. public:
  436. using type = iterator_t; //!< Export type as identity meta-function
  437. //! STL iterator traits "forwarding"
  438. //!@{
  439. public:
  440. using iterator_category = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::iterator_category;
  441. using value_type = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::value_type;
  442. using difference_type = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::difference_type;
  443. using pointer = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::pointer;
  444. using reference = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::reference;
  445. //!@}
  446. //! #define-like enumerator for Cursor
  447. enum Cursor {
  448. beg = _beg, //!< Points the first item
  449. eod = _beg + _size, //!< Points one place after last item
  450. };
  451. private:
  452. cont_t* owner_{nullptr}; /*!<
  453. * Pointer to parent/owner device class. Constructor demands
  454. * owner container in order to access data. Considering the data
  455. * don't "live" in memory.
  456. */
  457. index_t cursor_{eod}; //!< virtual cursor for comparison operators
  458. value_type value_ {}; //!< The current value, used as cache
  459. /*!
  460. * \name Constructor / Destructor
  461. * \note
  462. * We can not provide a default constructor as long as we depend
  463. * on container_t (the owner type).
  464. */
  465. //!@{
  466. public:
  467. //! \brief Default constructor
  468. indev_it () noexcept :
  469. owner_ {nullptr},
  470. cursor_{eod},
  471. value_ {} { }
  472. //! \brief Basic constructor
  473. explicit indev_it (cont_t* own, size_t cur =eod) noexcept :
  474. owner_ {own},
  475. cursor_{cur},
  476. value_ {} { }
  477. //! \brief Basic copy constructor
  478. explicit indev_it (const iterator_t& it) noexcept :
  479. owner_ {const_cast<cont_t*>(it.owner_)},
  480. cursor_{it.cursor_},
  481. value_ {it.value_} { }
  482. //! \brief Basic copy assignment operator
  483. iterator_t& operator= (const iterator_t& it) noexcept {
  484. owner_ = const_cast<cont_t*>(it.owner_);
  485. cursor_ = it.cursor_;
  486. value_ = it.value_;
  487. }
  488. //! \brief Iterator to const-iterator conversion (as STL requires)
  489. //! \param it Iterator reference
  490. // template<typename _It>
  491. // indev_it (const indev_it<
  492. // use_if_same_t <_It, typename container_t::pointer_type, container_t>,
  493. // _It,
  494. // streamsize
  495. // >& it) noexcept
  496. // : owner_ {const_cast<container_t*>(it.owner())},
  497. // cursor_{it.cursor()},
  498. // value_ {it.value()} { }
  499. //!@}
  500. //!@{ \name Public interface
  501. public:
  502. //! De-reference operator. No end() place dereference check is made.
  503. reference operator* () {
  504. owner_->get (value_, cursor_);
  505. return value_;
  506. }
  507. //! Arrow operator. No end() place dereference check is made.
  508. pointer operator-> () {
  509. owner_->get (value_, cursor_);
  510. return &value_;
  511. }
  512. //! Pre increment.
  513. iterator_t& operator++ () {
  514. ++cursor_;
  515. return *this;
  516. }
  517. //! Post increment.
  518. iterator_t operator++ (int) {
  519. iterator_t ret(*this);
  520. ++cursor_;
  521. return *this;
  522. }
  523. //! Pre decrement.
  524. iterator_t& operator-- () {
  525. --cursor_;
  526. return *this;
  527. }
  528. //! Post decrement.
  529. iterator_t operator-- (int) {
  530. iterator_t ret(*this);
  531. --cursor_;
  532. return *this;
  533. }
  534. //! [] operator. Is a combination of input method and dereference
  535. reference operator[] (difference_type n) {
  536. owner_->get (value_, cursor_ += n);
  537. return value_;
  538. }
  539. iterator_t& operator+= (difference_type n) {
  540. cursor_ += n;
  541. return *this;
  542. }
  543. iterator_t operator+ (difference_type n) {
  544. return iterator_t (owner_, cursor_ + n);
  545. }
  546. iterator_t& operator-= (difference_type n) {
  547. cursor_ -= n;
  548. return *this;
  549. }
  550. iterator_t operator- (difference_type n) {
  551. return iterator_t (owner_, cursor_ - n);
  552. }
  553. //! Export container for comparison
  554. const cont_t* owner () const noexcept { return owner_; }
  555. //! Export cursor for comparison
  556. const index_t cursor () const noexcept { return cursor_; }
  557. //! Export value for comparison
  558. //const reference value () const noexcept { return value_; }
  559. //!@}
  560. };
  561. /*!
  562. * \name indev_it EqualityComparable && LessThanComparable requirements
  563. * comparison template so that comparison between cv-qualified and
  564. * non-cv-qualified iterators be valid
  565. */
  566. //!@{
  567. //! Equality
  568. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  569. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  570. inline bool operator== (const indev_it<_Cont1, _It1, _beg1, _size1>& x,
  571. const indev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  572. return (x.owner() == y.owner() &&
  573. (x.cursor() == y.cursor()));
  574. }
  575. //! Less than
  576. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  577. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  578. inline bool operator< (const indev_it<_Cont1, _It1, _beg1, _size1>& x,
  579. const indev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  580. return (x.cursor() < y.cursor());
  581. }
  582. // relative ops
  583. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  584. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  585. inline bool operator!= (const indev_it<_Cont1, _It1, _beg1, _size1>& x,
  586. const indev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  587. return !(x == y);
  588. }
  589. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  590. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  591. inline bool operator<= (const indev_it<_Cont1, _It1, _beg1, _size1>& x,
  592. const indev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  593. return !(y < x);
  594. }
  595. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  596. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  597. inline bool operator> (const indev_it<_Cont1, _It1, _beg1, _size1>& x,
  598. const indev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  599. return (y < x);
  600. }
  601. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  602. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  603. inline bool operator>= (const indev_it<_Cont1, _It1, _beg1, _size1>& x,
  604. const indev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  605. return !(x < y);
  606. }
  607. //!@}
  608. //! @{ \name iterator arithmetic
  609. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  610. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  611. inline auto operator- (indev_it<_Cont1, _It1, _beg1, _size1>& x,
  612. indev_it<_Cont1, _It1, _beg1, _size1>& y) noexcept
  613. -> decltype (x.cursor() - y.cursor()) {
  614. return (x.cursor() - y.cursor());
  615. }
  616. template<typename _Cont, typename _It, index_t _beg, size_t _size>
  617. inline indev_it<_Cont, _It, _beg, _size>
  618. operator+ (typename _Cont::difference_type n,
  619. indev_it<_Cont, _It, _beg, _size>& it) noexcept {
  620. return indev_it<_Cont, _It, _beg, _size>(it.owner(), it.cursor() + n);
  621. }
  622. //! @}
  623. /*!
  624. * Input device iterator concept
  625. */
  626. //! @{
  627. #if defined _utl_have_concepts
  628. template <typename T>
  629. concept bool Indev_it = requires (T t, const T ct) {
  630. // STL compatibility
  631. typename T::value_type;
  632. typename T::difference_type;
  633. typename T::pointer;
  634. typename T::reference;
  635. requires same_ <
  636. typename T::iterator_category,
  637. std::input_iterator_tag
  638. >::value;
  639. {*t} -> typename T::value_type; // is dereferencable
  640. {++t} -> T&; // is incrementable
  641. {t++} -> T;
  642. // Extras
  643. {ct.owner()} ->auto&&;
  644. {ct.cursor()} -> const size_t;
  645. {ct.value()} -> auto&&;
  646. };
  647. #else
  648. namespace indev_it_details {
  649. using std::declval;
  650. //! Primary template to catch any non SPI interface types
  651. template <typename _Tp, typename =void>
  652. struct is_indev_it_ : meta::false_ {};
  653. //! template to catch a proper SPI interface type
  654. template <typename _Tp>
  655. struct is_indev_it_ <
  656. _Tp,
  657. meta::void_t <
  658. typename _Tp::value_type,
  659. typename _Tp::difference_type,
  660. typename _Tp::pointer,
  661. typename _Tp::reference,
  662. // meta::use_if_same_t <
  663. // typename _Tp::iterator_category,
  664. // std::input_iterator_tag
  665. // >
  666. void
  667. >
  668. > : meta::true_ {};
  669. }
  670. /*!
  671. * Value meta-programming function for SPI interface checking
  672. * \param _Tp Type to check
  673. * \return True if _Tp is a spi interface
  674. */
  675. // template <typename _Tp>
  676. // constexpr bool Indev_it = indev_it_details::is_indev_it_<_Tp>::value;
  677. #endif
  678. //! @}
  679. /*
  680. * ================= Indexed device Iterator =================
  681. */
  682. /*!
  683. * \brief
  684. * Indexed device iterator type. We "future call" interface methods
  685. * from owner class to provide iterator functionality.
  686. * \note
  687. * This is a contiguous iterator
  688. * \param cont_t Container/parent type
  689. * \param iter_t Iterator data type (pointer to container_t::value_type)
  690. * \param _beg Starting address of the device
  691. * \param _size Device's address space size
  692. */
  693. template<typename cont_t, typename iter_t, index_t _beg =0, size_t _size = static_cast<size_t>(-1)-_beg>
  694. class iodev_it {
  695. //!< iterator type local name
  696. using iterator_t = iodev_it <cont_t, iter_t, _beg, _size>;
  697. public:
  698. using type = iterator_t; //!< Export type as identity meta-function
  699. //! STL iterator traits "forwarding"
  700. //!@{
  701. public:
  702. using iterator_category = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::iterator_category;
  703. using value_type = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::value_type;
  704. using difference_type = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::difference_type;
  705. using pointer = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::pointer;
  706. using reference = typename dev_iterator_traits <std::output_iterator_tag, iter_t>::reference;
  707. //!@}
  708. //! #define-like enumerator for Cursor
  709. enum Cursor {
  710. beg = _beg, //!< Points the first item
  711. eod = _beg+_size, //!< Points one place after last item
  712. };
  713. private:
  714. cont_t* owner_{nullptr}; /*!<
  715. * Pointer to parent/owner device class. Constructor demands
  716. * owner container in order to access data. Considering the data
  717. * don't "live" in memory.
  718. */
  719. index_t cursor_{eod}; //!< virtual cursor for comparison operators
  720. /*!
  721. * Current value wrapper type, to used as put event catcher
  722. * owner_->get : Use v_ directly
  723. * owner_->put : Use operator= to a dereferenced iterator
  724. */
  725. struct value_type_t {
  726. value_type v_; //!< Current value buffer to access via get
  727. value_type_t(value_type v =value_type{}) :
  728. v_{v} { }
  729. operator value_type() { return v_; }
  730. operator reference() { return v_; }
  731. value_type& operator= (const value_type& v) {
  732. //!< Catch any attempt to write to value_ and sync the data back to device
  733. owner_->put (v_ =v, cursor_);
  734. }
  735. } value_ {};
  736. /*!
  737. * \name Constructor / Destructor
  738. */
  739. //!@{
  740. public:
  741. //! \brief Default constructor
  742. iodev_it () noexcept :
  743. owner_ {nullptr},
  744. cursor_{eod},
  745. value_ {} { }
  746. //! \brief Basic constructor
  747. explicit iodev_it (cont_t* owner, size_t cursor =eod) noexcept :
  748. owner_ {owner},
  749. cursor_{cursor},
  750. value_ {} { }
  751. //! \brief Basic copy constructor
  752. explicit iodev_it (const iterator_t& it) noexcept :
  753. owner_ {const_cast<cont_t*>(it.owner_)},
  754. cursor_{it.cursor_},
  755. value_ {it.value_} { }
  756. //! \brief Basic copy assignment operator
  757. iterator_t& operator= (const iterator_t& it) noexcept {
  758. owner_ = const_cast<cont_t*>(it.owner_);
  759. cursor_ = it.cursor_;
  760. value_ = it.value_;
  761. }
  762. //!@}
  763. //!@{ \name Public interface
  764. public:
  765. /*!
  766. * De-reference operator. This is where the input method is invoked
  767. * \note
  768. * No end() place dereference check is made.
  769. */
  770. reference operator* () noexcept {
  771. owner_->get (value_.v_, cursor_);
  772. return value_;
  773. }
  774. //! Arrow operator. This is where the input method is invoked
  775. pointer operator-> () noexcept {
  776. owner_->get (value_.v_, cursor_);
  777. return &value_;
  778. }
  779. //! Pre increment.
  780. iterator_t& operator++ () noexcept {
  781. ++cursor_;
  782. return *this;
  783. }
  784. //! Post increment.
  785. iterator_t operator++ (int) noexcept {
  786. iterator_t ret = *this;
  787. ++cursor_;
  788. return *this;
  789. }
  790. //! Pre decrement.
  791. iterator_t& operator-- () noexcept {
  792. --cursor_;
  793. return *this;
  794. }
  795. //! Post decrement.
  796. iterator_t operator-- (int) noexcept {
  797. iterator_t ret = *this;
  798. --cursor_;
  799. return *this;
  800. }
  801. //! Random access through iterator
  802. reference operator[] (difference_type n) noexcept {
  803. owner_->get (value_.v_, cursor_ = n);
  804. return value_;
  805. }
  806. //! Random cursor increment
  807. iterator_t& operator+= (difference_type n) noexcept {
  808. cursor_ += n;
  809. return *this;
  810. }
  811. //! Addition operation
  812. iterator_t operator+ (difference_type n) const noexcept {
  813. return iterator_t (owner_, cursor_ + n);
  814. }
  815. //! Random cursor decrement
  816. iterator_t& operator-= (difference_type n) noexcept {
  817. cursor_ -= n;
  818. return *this;
  819. }
  820. //! Subtraction operation
  821. iterator_t operator- (difference_type n) const noexcept {
  822. return iterator_t (owner_, cursor_ - n);
  823. }
  824. //! Export container for comparison
  825. const cont_t* owner () const noexcept { return owner_; }
  826. //! Export cursor for comparison
  827. const index_t& cursor () const noexcept { return cursor_; }
  828. //! Export value for comparison
  829. //const value_type_t& value () const noexcept { return value_; }
  830. //!@}
  831. };
  832. /*!
  833. * \name indev_it EqualityComparable && LessThanComparable requirements
  834. * comparison template so that comparison between cv-qualified and
  835. * non-cv-qualified iterators be valid
  836. */
  837. //!@{
  838. //! Equality
  839. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  840. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  841. inline bool operator== (const iodev_it<_Cont1, _It1, _beg1, _size1>& x,
  842. const iodev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  843. return (x.owner() == y.owner() &&
  844. (x.cursor() == y.cursor()));
  845. }
  846. //! Less than
  847. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  848. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  849. inline bool operator< (const iodev_it<_Cont1, _It1, _beg1, _size1>& x,
  850. const iodev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  851. return (x.cursor() < y.cursor());
  852. }
  853. // relative ops
  854. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  855. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  856. inline bool operator!= (const iodev_it<_Cont1, _It1, _beg1, _size1>& x,
  857. const iodev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  858. return !(x == y);
  859. }
  860. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  861. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  862. inline bool operator<= (const iodev_it<_Cont1, _It1, _beg1, _size1>& x,
  863. const iodev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  864. return !(y < x);
  865. }
  866. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  867. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  868. inline bool operator> (const iodev_it<_Cont1, _It1, _beg1, _size1>& x,
  869. const iodev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  870. return (y < x);
  871. }
  872. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  873. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  874. inline bool operator>= (const iodev_it<_Cont1, _It1, _beg1, _size1>& x,
  875. const iodev_it<_Cont2, _It2, _beg2, _size2>& y) noexcept {
  876. return !(x < y);
  877. }
  878. //!@}
  879. //! @{ \name iterator arithmetic
  880. template<typename _Cont1, typename _It1, index_t _beg1, size_t _size1,
  881. typename _Cont2, typename _It2, index_t _beg2, size_t _size2>
  882. inline auto operator- (iodev_it<_Cont1, _It1, _beg1, _size1>& x,
  883. iodev_it<_Cont1, _It1, _beg1, _size1>& y) noexcept
  884. -> decltype (x.cursor() - y.cursor()) {
  885. return (x.cursor() - y.cursor());
  886. }
  887. template<typename _Cont, typename _It, index_t _beg, size_t _size>
  888. inline iodev_it<_Cont, _It, _beg, _size>
  889. operator+ (typename _Cont::difference_type n,
  890. iodev_it<_Cont, _It, _beg, _size>& it) noexcept {
  891. return iodev_it<_Cont, _It, _beg, _size>(it.owner(), it.cursor() + n);
  892. }
  893. //! @}
  894. /*!
  895. * Index device iterator concept
  896. */
  897. //! @{
  898. #if defined _utl_have_concepts
  899. template <typename T>
  900. concept bool Idxdev_it = requires (T t, const T ct) {
  901. // STL compatibility
  902. typename T::value_type;
  903. typename T::difference_type;
  904. typename T::pointer;
  905. typename T::reference;
  906. requires same_<
  907. typename T::iterator_category,
  908. std::input_iterator_tag
  909. >::value;
  910. {*t} -> typename T::value_type; // is dereferencable
  911. {++t} -> T&; // is incrementable
  912. {t++} -> T;
  913. // Extras
  914. {ct.owner()} ->auto&&;
  915. {ct.cursor()} -> const size_t;
  916. {ct.value()} -> auto&&;
  917. };
  918. #else
  919. namespace idxdev_it_details {
  920. using std::declval;
  921. //! Primary template to catch any non SPI interface types
  922. template <typename _Tp, typename =void>
  923. struct is_idxdev_it_ : meta::false_ {};
  924. //! template to catch a proper SPI interface type
  925. template <typename _Tp>
  926. struct is_idxdev_it_ <
  927. _Tp,
  928. meta::void_t <
  929. typename _Tp::value_type,
  930. typename _Tp::difference_type,
  931. typename _Tp::pointer,
  932. typename _Tp::reference,
  933. // meta::use_if_same_t <
  934. // typename _Tp::iterator_category,
  935. // std::input_iterator_tag
  936. // >
  937. void
  938. >
  939. > : meta::true_ {};
  940. }
  941. /*!
  942. * Value meta-programming function for SPI interface checking
  943. * \param _Tp Type to check
  944. * \return True if _Tp is a spi interface
  945. */
  946. // template <typename _Tp>
  947. // constexpr bool Idxdev_it = idxdev_it_details::is_idxdev_it_<_Tp>::value;
  948. #endif
  949. //! @}
  950. }
  951. //!@}
  952. #endif /* __utl_dev_dev_iterators_h__ */