rangeをより小さな部分に分割するadaptor
rangeを一定サイズの部分rangeに分割するadaptorを書いてみました。こんな感じに使えます。
#include <iostream> #include <boost/lambda/lambda.hpp> #include <boost/range/algorithm/for_each.hpp> #include <boost/range/as_literal.hpp> #include "chunked.hpp" int main() { boost::for_each( // 文字列を4文字ごとに分割する boost::as_literal("Hello, world!") | iorate::adaptors::chunked(4), std::cout << boost::lambda::_1 << "\n"); }
出力
Hell o, w orld !
iterator_rangeのforward rangeを返しているので、単体では使えません。pstade::oven::delimitedなどと組み合わせて使うことを想定しています。
実装は以下から。
chunked.hpp
#ifndef IORATE_ADAPTOR_CHUNKED_HPP #define IORATE_ADAPTOR_CHUNKED_HPP #include <iterator> #include <boost/iterator/iterator_categories.hpp> #include <boost/iterator/iterator_facade.hpp> #include <boost/range/adaptor/define_adaptor.hpp> #include <boost/range/begin.hpp> #include <boost/range/end.hpp> #include <boost/range/iterator_range.hpp> namespace iorate { namespace detail { template <class Iterator, class Distance> inline Iterator next_impl(Iterator it, Iterator last, Distance n, boost::random_access_traversal_tag) { return last - it < n ? last : it + n; } template <class Iterator, class Distance> inline Iterator next_impl(Iterator it, Iterator last, Distance n, ...) { if (n >= 0) while (n-- && it != last) ++it; else while (n++) --it; return it; } template <class Iterator, class Distance> inline Iterator next(Iterator it, Iterator last, Distance n) { return next_impl(it, last, n, typename boost::iterator_traversal<Iterator>::type()); } template <class Iterator> class chunk_iterator : public boost::iterator_facade< chunk_iterator<Iterator>, boost::iterator_range<Iterator>, boost::forward_traversal_tag, boost::iterator_range<Iterator> const & > { public: typedef boost::iterator_range<Iterator> chunk_type; chunk_iterator(Iterator first, Iterator last, std::size_t size) : chunk_(first, next(first, last, size)), last_(last), size_(size) {} private: friend class boost::iterator_core_access; void increment() { chunk_ = chunk_type(chunk_.end(), next(chunk_.end(), last_, size_)); } bool equal(chunk_iterator const &other) const { return chunk_ == other.chunk_; } chunk_type const &dereference() const { return chunk_; } chunk_type chunk_; Iterator last_; std::size_t size_; }; template <class Range> struct chunk_range : boost::iterator_range< chunk_iterator<typename boost::range_iterator<Range>::type> > { typedef boost::iterator_range< chunk_iterator<typename boost::range_iterator<Range>::type> > base; typedef typename base::iterator iterator; chunk_range(Range &range, std::size_t size) : base(iterator(boost::begin(range), boost::end(range), size), iterator(boost::end(range), boost::end(range), size)) {} }; } // namespace detail namespace adaptors { BOOST_DEFINE_RANGE_ADAPTOR_1(chunked, detail::chunk_range, std::size_t) } } // namespace iorate #endif
Boost1.45.0ではマクロが多重定義されている旨の警告が出ます。ヘッダ