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.
 
 
 
 

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