What you want can be implemented using Boost.Variant .
The idea is to define a new type of iterator that stores a variant (think of it as a C-connection on steroids) containing either a direct or reverse iterator:
template<class InputRange> struct any_dir_iterator : std::iterator_traits<typename boost::range_iterator<InputRange>::type> { typedef typename boost::range_iterator<InputRange>::type forward_iterator; typedef typename boost::range_reverse_iterator<InputRange>::type reverse_iterator; typedef boost::variant<forward_iterator, reverse_iterator> iterator_type; iterator_type current_it, end_it; any_dir_iterator(InputRange & input_range, bool fwd = true, bool end = false) { end_it = fwd ? iterator_type(boost::end(input_range)) : iterator_type(boost::rend(input_range)); if(end) current_it = end_it; else current_it = fwd ? iterator_type(boost::begin(input_range)) : iterator_type(boost::rbegin(input_range)); } reference operator*() const { return boost::apply_visitor(dereference_visitor<any_dir_iterator>(), current_it); } any_dir_iterator & operator++() { boost::apply_visitor(increment_visitor<any_dir_iterator>(), current_it); return *this; } bool operator==(any_dir_iterator const & rhs) { return boost::apply_visitor(equals_visitor<any_dir_iterator>(), current_it, rhs.current_it); } };
This is similar to Adobe any iterator , but much less general, which means that it will have virtually no overhead compared to a regular iterator.
As you can see in the above code, all logic is delegated to static visitors, which we define as follows:
template<class AnyDirIterator> struct dereference_visitor : boost::static_visitor<typename AnyDirIterator::iterator_type> { typedef typename AnyDirIterator::reference result_type; template<class FwdOrRevIterator> result_type operator()(FwdOrRevIterator const & it) const { return *it; } }; template<class AnyDirIterator> struct increment_visitor : boost::static_visitor<typename AnyDirIterator::iterator_type> { typedef void result_type; template<class FwdOrRevIterator> result_type operator()(FwdOrRevIterator & it) const { ++it; } }; template<class AnyDirIterator> struct equals_visitor : boost::static_visitor<typename AnyDirIterator::iterator_type> { typedef bool result_type; template <typename FwdOrRevIterator> bool operator()(FwdOrRevIterator const & lhs, FwdOrRevIterator const & rhs) const { return lhs == rhs; } template <typename T, typename U> bool operator()( const T &, const U & ) const { return false;
That was the hard part. But we still need to make it more convenient for use, for which we define a helper function that relies on the functionality provided by the Boost.Range library:
template<class InputRange> boost::iterator_range<any_dir_iterator<InputRange> > make_any_dir_range(InputRange & range, bool forward=true) { typedef any_dir_iterator<InputRange> iterator; return boost::make_iterator_range(iterator(range, forward), iterator(range, forward, true)); }
And it's all. Now you can write:
int main() { int items[] = { 1, 2 }; typedef std::vector<int> container_type; container_type container(items, items + sizeof(items)/sizeof(items[0])); BOOST_FOREACH(int i, make_any_dir_range(container, true)) std::cout << i << " "; std::cout << "\n"; BOOST_FOREACH(int i, make_any_dir_range(container, false)) std::cout << i << " "; return 0; }
What prints:
1 2 2 1
This also works with constant containers, although I have not shown this feature in the main function.
Another nice thing that results from using Boost.Range is that it works with arrays out of the box. So you can do this:
int items[] = { 1, 2 }; BOOST_FOREACH(int i, make_any_dir_range(items, true))
The answer to this question is too short. I left a few unrealized things (but they are all templates that do not require new visitors):
- Postfix increment operator
- Operator! = Operator
- Operator β
Here is all the code in the encoder . Due to the "warn about warnings as errors" policy, Codepad will not swallow it, but both VS2008 and GCC 4.4 will compile it in my local machine.
UPDATE
I did some tests, and apparently boost::variant introduces some overhead at runtime: a BOOST_FOREACH , based on a loop like the one in the main function, runs about 4 times slower (when compiled in release mode ) than the equivalent version using a simple iterator. It would be interesting to check if this is better or worse than the overhead paid by Adobe any_iterator .