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