strided.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. // Boost.Range library
  2. //
  3. // Copyright Neil Groves 2007. Use, modification and
  4. // distribution is subject to the Boost Software License, Version
  5. // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. //
  9. // For more information, see http://www.boost.org/libs/range/
  10. //
  11. #ifndef BOOST_RANGE_ADAPTOR_STRIDED_HPP_INCLUDED
  12. #define BOOST_RANGE_ADAPTOR_STRIDED_HPP_INCLUDED
  13. #include <boost/range/adaptor/argument_fwd.hpp>
  14. #include <boost/range/iterator_range.hpp>
  15. #include <boost/iterator/iterator_facade.hpp>
  16. #include <iterator>
  17. namespace boost
  18. {
  19. namespace range_detail
  20. {
  21. // strided_iterator for wrapping a forward traversal iterator
  22. template<class BaseIterator, class Category>
  23. class strided_iterator
  24. : public iterator_facade<
  25. strided_iterator<BaseIterator, Category>
  26. , typename iterator_value<BaseIterator>::type
  27. , forward_traversal_tag
  28. , typename iterator_reference<BaseIterator>::type
  29. , typename iterator_difference<BaseIterator>::type
  30. >
  31. {
  32. friend class ::boost::iterator_core_access;
  33. typedef iterator_facade<
  34. strided_iterator<BaseIterator, Category>
  35. , typename iterator_value<BaseIterator>::type
  36. , forward_traversal_tag
  37. , typename iterator_reference<BaseIterator>::type
  38. , typename iterator_difference<BaseIterator>::type
  39. > super_t;
  40. public:
  41. typedef typename super_t::difference_type difference_type;
  42. typedef typename super_t::reference reference;
  43. typedef BaseIterator base_iterator;
  44. typedef std::forward_iterator_tag iterator_category;
  45. strided_iterator()
  46. : m_it()
  47. , m_last()
  48. , m_stride()
  49. {
  50. }
  51. strided_iterator(base_iterator it,
  52. base_iterator last,
  53. difference_type stride)
  54. : m_it(it)
  55. , m_last(last)
  56. , m_stride(stride)
  57. {
  58. }
  59. template<class OtherIterator>
  60. strided_iterator(
  61. const strided_iterator<OtherIterator, Category>& other,
  62. typename enable_if_convertible<
  63. OtherIterator,
  64. base_iterator
  65. >::type* = 0
  66. )
  67. : m_it(other.base())
  68. , m_last(other.base_end())
  69. , m_stride(other.get_stride())
  70. {
  71. }
  72. base_iterator base() const
  73. {
  74. return m_it;
  75. }
  76. base_iterator base_end() const
  77. {
  78. return m_last;
  79. }
  80. difference_type get_stride() const
  81. {
  82. return m_stride;
  83. }
  84. private:
  85. void increment()
  86. {
  87. for (difference_type i = 0;
  88. (m_it != m_last) && (i < m_stride); ++i)
  89. {
  90. ++m_it;
  91. }
  92. }
  93. reference dereference() const
  94. {
  95. return *m_it;
  96. }
  97. template<class OtherIterator>
  98. bool equal(
  99. const strided_iterator<OtherIterator, Category>& other,
  100. typename enable_if_convertible<
  101. OtherIterator,
  102. base_iterator
  103. >::type* = 0) const
  104. {
  105. return m_it == other.m_it;
  106. }
  107. base_iterator m_it;
  108. base_iterator m_last;
  109. difference_type m_stride;
  110. };
  111. // strided_iterator for wrapping a bidirectional iterator
  112. template<class BaseIterator>
  113. class strided_iterator<BaseIterator, bidirectional_traversal_tag>
  114. : public iterator_facade<
  115. strided_iterator<BaseIterator, bidirectional_traversal_tag>
  116. , typename iterator_value<BaseIterator>::type
  117. , bidirectional_traversal_tag
  118. , typename iterator_reference<BaseIterator>::type
  119. , typename iterator_difference<BaseIterator>::type
  120. >
  121. {
  122. friend class ::boost::iterator_core_access;
  123. typedef iterator_facade<
  124. strided_iterator<BaseIterator, bidirectional_traversal_tag>
  125. , typename iterator_value<BaseIterator>::type
  126. , bidirectional_traversal_tag
  127. , typename iterator_reference<BaseIterator>::type
  128. , typename iterator_difference<BaseIterator>::type
  129. > super_t;
  130. public:
  131. typedef typename super_t::difference_type difference_type;
  132. typedef typename super_t::reference reference;
  133. typedef BaseIterator base_iterator;
  134. typedef typename boost::make_unsigned<difference_type>::type
  135. size_type;
  136. typedef std::bidirectional_iterator_tag iterator_category;
  137. strided_iterator()
  138. : m_it()
  139. , m_offset()
  140. , m_index()
  141. , m_stride()
  142. {
  143. }
  144. strided_iterator(base_iterator it,
  145. size_type index,
  146. difference_type stride)
  147. : m_it(it)
  148. , m_offset()
  149. , m_index(index)
  150. , m_stride(stride)
  151. {
  152. if (stride && ((m_index % stride) != 0))
  153. m_index += (stride - (m_index % stride));
  154. }
  155. template<class OtherIterator>
  156. strided_iterator(
  157. const strided_iterator<
  158. OtherIterator,
  159. bidirectional_traversal_tag
  160. >& other,
  161. typename enable_if_convertible<
  162. OtherIterator,
  163. base_iterator
  164. >::type* = 0
  165. )
  166. : m_it(other.base())
  167. , m_offset(other.get_offset())
  168. , m_index(other.get_index())
  169. , m_stride(other.get_stride())
  170. {
  171. }
  172. base_iterator base() const
  173. {
  174. return m_it;
  175. }
  176. difference_type get_offset() const
  177. {
  178. return m_offset;
  179. }
  180. size_type get_index() const
  181. {
  182. return m_index;
  183. }
  184. difference_type get_stride() const
  185. {
  186. return m_stride;
  187. }
  188. private:
  189. void increment()
  190. {
  191. m_offset += m_stride;
  192. }
  193. void decrement()
  194. {
  195. m_offset -= m_stride;
  196. }
  197. reference dereference() const
  198. {
  199. update();
  200. return *m_it;
  201. }
  202. void update() const
  203. {
  204. std::advance(m_it, m_offset);
  205. m_index += m_offset;
  206. m_offset = 0;
  207. }
  208. template<class OtherIterator>
  209. bool equal(
  210. const strided_iterator<
  211. OtherIterator,
  212. bidirectional_traversal_tag
  213. >& other,
  214. typename enable_if_convertible<
  215. OtherIterator,
  216. base_iterator
  217. >::type* = 0) const
  218. {
  219. return (m_index + m_offset) ==
  220. (other.get_index() + other.get_offset());
  221. }
  222. mutable base_iterator m_it;
  223. mutable difference_type m_offset;
  224. mutable size_type m_index;
  225. difference_type m_stride;
  226. };
  227. // strided_iterator implementation for wrapping a random access iterator
  228. template<class BaseIterator>
  229. class strided_iterator<BaseIterator, random_access_traversal_tag>
  230. : public iterator_facade<
  231. strided_iterator<BaseIterator, random_access_traversal_tag>
  232. , typename iterator_value<BaseIterator>::type
  233. , random_access_traversal_tag
  234. , typename iterator_reference<BaseIterator>::type
  235. , typename iterator_difference<BaseIterator>::type
  236. >
  237. {
  238. friend class ::boost::iterator_core_access;
  239. typedef iterator_facade<
  240. strided_iterator<BaseIterator, random_access_traversal_tag>
  241. , typename iterator_value<BaseIterator>::type
  242. , random_access_traversal_tag
  243. , typename iterator_reference<BaseIterator>::type
  244. , typename iterator_difference<BaseIterator>::type
  245. > super_t;
  246. public:
  247. typedef typename super_t::difference_type difference_type;
  248. typedef typename super_t::reference reference;
  249. typedef BaseIterator base_iterator;
  250. typedef std::random_access_iterator_tag iterator_category;
  251. strided_iterator()
  252. : m_it()
  253. , m_first()
  254. , m_index(0)
  255. , m_stride()
  256. {
  257. }
  258. strided_iterator(
  259. base_iterator first,
  260. base_iterator it,
  261. difference_type stride
  262. )
  263. : m_it(it)
  264. , m_first(first)
  265. , m_index(stride ? (it - first) : difference_type())
  266. , m_stride(stride)
  267. {
  268. if (stride && ((m_index % stride) != 0))
  269. m_index += (stride - (m_index % stride));
  270. }
  271. template<class OtherIterator>
  272. strided_iterator(
  273. const strided_iterator<
  274. OtherIterator,
  275. random_access_traversal_tag
  276. >& other,
  277. typename enable_if_convertible<
  278. OtherIterator,
  279. base_iterator
  280. >::type* = 0
  281. )
  282. : m_it(other.base())
  283. , m_first(other.base_begin())
  284. , m_index(other.get_index())
  285. , m_stride(other.get_stride())
  286. {
  287. }
  288. base_iterator base_begin() const
  289. {
  290. return m_first;
  291. }
  292. base_iterator base() const
  293. {
  294. return m_it;
  295. }
  296. difference_type get_stride() const
  297. {
  298. return m_stride;
  299. }
  300. difference_type get_index() const
  301. {
  302. return m_index;
  303. }
  304. private:
  305. void increment()
  306. {
  307. m_index += m_stride;
  308. }
  309. void decrement()
  310. {
  311. m_index -= m_stride;
  312. }
  313. void advance(difference_type offset)
  314. {
  315. m_index += (m_stride * offset);
  316. }
  317. // Implementation detail: only update the actual underlying iterator
  318. // at the point of dereference. This is done so that the increment
  319. // and decrement can overshoot the valid sequence as is required
  320. // by striding. Since we can do all comparisons just with the index
  321. // simply, and all dereferences must be within the valid range.
  322. void update() const
  323. {
  324. m_it = m_first + m_index;
  325. }
  326. template<class OtherIterator>
  327. difference_type distance_to(
  328. const strided_iterator<
  329. OtherIterator,
  330. random_access_traversal_tag
  331. >& other,
  332. typename enable_if_convertible<
  333. OtherIterator, base_iterator>::type* = 0) const
  334. {
  335. BOOST_ASSERT((other.m_index - m_index) % m_stride == difference_type());
  336. return (other.m_index - m_index) / m_stride;
  337. }
  338. template<class OtherIterator>
  339. bool equal(
  340. const strided_iterator<
  341. OtherIterator,
  342. random_access_traversal_tag
  343. >& other,
  344. typename enable_if_convertible<
  345. OtherIterator, base_iterator>::type* = 0) const
  346. {
  347. return m_index == other.m_index;
  348. }
  349. reference dereference() const
  350. {
  351. update();
  352. return *m_it;
  353. }
  354. private:
  355. mutable base_iterator m_it;
  356. base_iterator m_first;
  357. difference_type m_index;
  358. difference_type m_stride;
  359. };
  360. template<class Rng, class Difference> inline
  361. strided_iterator<
  362. typename range_iterator<Rng>::type,
  363. forward_traversal_tag
  364. >
  365. make_begin_strided_iterator(
  366. Rng& rng,
  367. Difference stride,
  368. forward_traversal_tag)
  369. {
  370. return strided_iterator<
  371. typename range_iterator<Rng>::type,
  372. forward_traversal_tag
  373. >(boost::begin(rng), boost::end(rng), stride);
  374. }
  375. template<class Rng, class Difference> inline
  376. strided_iterator<
  377. typename range_iterator<const Rng>::type,
  378. forward_traversal_tag
  379. >
  380. make_begin_strided_iterator(
  381. const Rng& rng,
  382. Difference stride,
  383. forward_traversal_tag)
  384. {
  385. return strided_iterator<
  386. typename range_iterator<const Rng>::type,
  387. forward_traversal_tag
  388. >(boost::begin(rng), boost::end(rng), stride);
  389. }
  390. template<class Rng, class Difference> inline
  391. strided_iterator<
  392. typename range_iterator<Rng>::type,
  393. forward_traversal_tag
  394. >
  395. make_end_strided_iterator(
  396. Rng& rng,
  397. Difference stride,
  398. forward_traversal_tag)
  399. {
  400. return strided_iterator<
  401. typename range_iterator<Rng>::type,
  402. forward_traversal_tag
  403. >(boost::end(rng), boost::end(rng), stride);
  404. }
  405. template<class Rng, class Difference> inline
  406. strided_iterator<
  407. typename range_iterator<const Rng>::type,
  408. forward_traversal_tag
  409. >
  410. make_end_strided_iterator(
  411. const Rng& rng,
  412. Difference stride,
  413. forward_traversal_tag)
  414. {
  415. return strided_iterator<
  416. typename range_iterator<const Rng>::type,
  417. forward_traversal_tag
  418. >(boost::end(rng), boost::end(rng), stride);
  419. }
  420. template<class Rng, class Difference> inline
  421. strided_iterator<
  422. typename range_iterator<Rng>::type,
  423. bidirectional_traversal_tag
  424. >
  425. make_begin_strided_iterator(
  426. Rng& rng,
  427. Difference stride,
  428. bidirectional_traversal_tag)
  429. {
  430. typedef typename range_difference<Rng>::type difference_type;
  431. return strided_iterator<
  432. typename range_iterator<Rng>::type,
  433. bidirectional_traversal_tag
  434. >(boost::begin(rng), difference_type(), stride);
  435. }
  436. template<class Rng, class Difference> inline
  437. strided_iterator<
  438. typename range_iterator<const Rng>::type,
  439. bidirectional_traversal_tag
  440. >
  441. make_begin_strided_iterator(
  442. const Rng& rng,
  443. Difference stride,
  444. bidirectional_traversal_tag)
  445. {
  446. typedef typename range_difference<const Rng>::type difference_type;
  447. return strided_iterator<
  448. typename range_iterator<const Rng>::type,
  449. bidirectional_traversal_tag
  450. >(boost::begin(rng), difference_type(), stride);
  451. }
  452. template<class Rng, class Difference> inline
  453. strided_iterator<
  454. typename range_iterator<Rng>::type,
  455. bidirectional_traversal_tag
  456. >
  457. make_end_strided_iterator(
  458. Rng& rng,
  459. Difference stride,
  460. bidirectional_traversal_tag)
  461. {
  462. return strided_iterator<
  463. typename range_iterator<Rng>::type,
  464. bidirectional_traversal_tag
  465. >(boost::end(rng), boost::size(rng), stride);
  466. }
  467. template<class Rng, class Difference> inline
  468. strided_iterator<
  469. typename range_iterator<const Rng>::type,
  470. bidirectional_traversal_tag
  471. >
  472. make_end_strided_iterator(
  473. const Rng& rng,
  474. Difference stride,
  475. bidirectional_traversal_tag)
  476. {
  477. return strided_iterator<
  478. typename range_iterator<const Rng>::type,
  479. bidirectional_traversal_tag
  480. >(boost::end(rng), boost::size(rng), stride);
  481. }
  482. template<class Rng, class Difference> inline
  483. strided_iterator<
  484. typename range_iterator<Rng>::type,
  485. random_access_traversal_tag
  486. >
  487. make_begin_strided_iterator(
  488. Rng& rng,
  489. Difference stride,
  490. random_access_traversal_tag)
  491. {
  492. return strided_iterator<
  493. typename range_iterator<Rng>::type,
  494. random_access_traversal_tag
  495. >(boost::begin(rng), boost::begin(rng), stride);
  496. }
  497. template<class Rng, class Difference> inline
  498. strided_iterator<
  499. typename range_iterator<const Rng>::type,
  500. random_access_traversal_tag
  501. >
  502. make_begin_strided_iterator(
  503. const Rng& rng,
  504. Difference stride,
  505. random_access_traversal_tag)
  506. {
  507. return strided_iterator<
  508. typename range_iterator<const Rng>::type,
  509. random_access_traversal_tag
  510. >(boost::begin(rng), boost::begin(rng), stride);
  511. }
  512. template<class Rng, class Difference> inline
  513. strided_iterator<
  514. typename range_iterator<Rng>::type,
  515. random_access_traversal_tag
  516. >
  517. make_end_strided_iterator(
  518. Rng& rng,
  519. Difference stride,
  520. random_access_traversal_tag)
  521. {
  522. return strided_iterator<
  523. typename range_iterator<Rng>::type,
  524. random_access_traversal_tag
  525. >(boost::begin(rng), boost::end(rng), stride);
  526. }
  527. template<class Rng, class Difference> inline
  528. strided_iterator<
  529. typename range_iterator<const Rng>::type,
  530. random_access_traversal_tag
  531. >
  532. make_end_strided_iterator(
  533. const Rng& rng,
  534. Difference stride,
  535. random_access_traversal_tag)
  536. {
  537. return strided_iterator<
  538. typename range_iterator<const Rng>::type,
  539. random_access_traversal_tag
  540. >(boost::begin(rng), boost::end(rng), stride);
  541. }
  542. template<
  543. class Rng,
  544. class Category =
  545. typename iterators::pure_iterator_traversal<
  546. typename range_iterator<Rng>::type
  547. >::type
  548. >
  549. class strided_range
  550. : public iterator_range<
  551. range_detail::strided_iterator<
  552. typename range_iterator<Rng>::type,
  553. Category
  554. >
  555. >
  556. {
  557. typedef range_detail::strided_iterator<
  558. typename range_iterator<Rng>::type,
  559. Category
  560. > iter_type;
  561. typedef iterator_range<iter_type> super_t;
  562. public:
  563. template<class Difference>
  564. strided_range(Difference stride, Rng& rng)
  565. : super_t(
  566. range_detail::make_begin_strided_iterator(
  567. rng, stride,
  568. typename iterator_traversal<
  569. typename range_iterator<Rng>::type
  570. >::type()),
  571. range_detail::make_end_strided_iterator(
  572. rng, stride,
  573. typename iterator_traversal<
  574. typename range_iterator<Rng>::type
  575. >::type()))
  576. {
  577. BOOST_ASSERT( stride >= 0 );
  578. }
  579. };
  580. template<class Difference>
  581. class strided_holder : public holder<Difference>
  582. {
  583. public:
  584. explicit strided_holder(Difference value)
  585. : holder<Difference>(value)
  586. {
  587. }
  588. };
  589. template<class Rng, class Difference>
  590. inline strided_range<Rng>
  591. operator|(Rng& rng, const strided_holder<Difference>& stride)
  592. {
  593. return strided_range<Rng>(stride.val, rng);
  594. }
  595. template<class Rng, class Difference>
  596. inline strided_range<const Rng>
  597. operator|(const Rng& rng, const strided_holder<Difference>& stride)
  598. {
  599. return strided_range<const Rng>(stride.val, rng);
  600. }
  601. } // namespace range_detail
  602. using range_detail::strided_range;
  603. namespace adaptors
  604. {
  605. namespace
  606. {
  607. const range_detail::forwarder<range_detail::strided_holder>
  608. strided = range_detail::forwarder<
  609. range_detail::strided_holder>();
  610. }
  611. template<class Range, class Difference>
  612. inline strided_range<Range>
  613. stride(Range& rng, Difference step)
  614. {
  615. return strided_range<Range>(step, rng);
  616. }
  617. template<class Range, class Difference>
  618. inline strided_range<const Range>
  619. stride(const Range& rng, Difference step)
  620. {
  621. return strided_range<const Range>(step, rng);
  622. }
  623. } // namespace 'adaptors'
  624. } // namespace 'boost'
  625. #endif