strided.hpp 22 KB

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