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.
 
 
 
 

1009 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. >
  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__ */