Boost.Rangeのirangeのstepに対してOvenのsteps


http://homepage1.nifty.com/herumi/diary/1105.html#13


Ovenは意図通りの挙動だった。
(というよりOvenには同様の機能が無いのでstepsを使った。)
boost1.46.1
Ovenはtrunk(たぶん現行のリリースの1.04.3でも問題ない)

#include <iostream>

#include <pstade/oven/algorithm.hpp>
#include <pstade/oven/counting.hpp>
#include <pstade/oven/io.hpp>
#include <pstade/oven/steps.hpp>

int main()
{
    namespace oven = pstade::oven;
    std::cout << oven::counting(0, 10) << std::endl;
    std::cout << (oven::counting(0, 10)|oven::steps(2)) << std::endl;
    std::cout << (oven::counting(0, 9)|oven::steps(2)) << std::endl;
}
{0,1,2,3,4,5,6,7,8,9}
{0,2,4,6,8}
{0,2,4,6,8}


boostのirangeの方でおかしくなってるのはこの部分だろうか
boost/range/irange.hpp

219         const std::ptrdiff_t last_step
220             = (static_cast<std::ptrdiff_t>(last) - static_cast<std::ptrdiff_t>(first))
221             / (static_cast<std::ptrdiff_t>(step_size));
222 
223         return strided_integer_range<Integer>(
224             iterator_t(first, 0, step_size),
225             iterator_t(first, last_step, step_size));

Ovenの方はstepsでIteratorを前進するときに毎回末尾を検査してます。
以下がBinaryPredになってsucceed_iteratorというものに渡されて、succeed_iterator::increment()の時に呼ばれます。

44         template< class Iterator >
45         Iterator aux(Iterator first, Iterator last, boost::random_access_traversal_tag) const
46         {
47             return first + (std::min)(last - first, m_stride);
48         }
49 
50         template< class Iterator >
51         Iterator aux(Iterator first, Iterator last, boost::single_pass_traversal_tag) const
52         {
53             Difference d = m_stride;
54             do {
55                 ++first;
56                 --d;
57             } while (d != 0 && first != last);
58 
59             return first;
60         }


見てないですが、おそらくboost/range/adaptor/strided.hppがBoost.Rangeにおける同様の実装だと思います。

irangeのstep、

219         const std::ptrdiff_t last_step
220             = (static_cast<std::ptrdiff_t>(last) - static_cast<std::ptrdiff_t>(first) - 1)
221             / (static_cast<std::ptrdiff_t>(step_size)) + 1;

とかなら期待通りかな。

議論
http://thread.gmane.org/gmane.comp.lib.boost.devel/211955

去年の12月に上げられていたstridedに関するticket
#5014 (stride doesn't end iteration properly) – Boost C++ Libraries

irangeの方のstepのticketって発行されてないっぽい。

追記:

 1 #include <iostream>
 2 
 3 #include <boost/range/irange.hpp>
 4 #include <boost/range/adaptor/strided.hpp>
 5 
 6 int main()
 7 {
 8     std::cout << boost::irange(0, 10, 2) << std::endl;
 9     std::cout << boost::irange(0, 9, 2) << std::endl;
10     std::cout << boost::irange(0, 8, 2) << std::endl;
11     std::cout << "--- --- --- --- " << std::endl;
12     std::cout << (boost::irange(0, 10)|boost::adaptors::strided(2)) << std::endl;
13     std::cout << (boost::irange(0, 9)|boost::adaptors::strided(2)) << std::endl;
14     std::cout << (boost::irange(0, 8)|boost::adaptors::strided(2)) << std::endl;
15 }
1 02468
2 0246
3 0246
4 --- --- --- ---
5 02468
6 02468
7 0246

やっぱりバグだと思う。

追記:
バグレポート投げたー!
#5544 (irange doesn't end iteration properly when step_size is 2 or more) – Boost C++ Libraries