Micro template library A library for building device drivers
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

dev_iterators.h 38 KiB

il y a 4 ans
il y a 4 ans
il y a 4 ans
il y a 4 ans
il y a 4 ans
il y a 4 ans
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011
  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__ */