Boost logo

Boost :

Subject: [boost] wrapper to add Boost.Iterator adaptors to Boost.Range
From: dstahlke (dstahlke_at_[hidden])
Date: 2010-02-07 02:33:10


I've worked up a subclass that adds Boost.Iterator functionality to a
Boost.Range object. The motivation was twofold: Range combines
begin() and
end() into one object, preventing the need to write iterator adapter
code
twice, and adding adaptors into the subclass avoids the need to
specify
namespaces and allows code structures similar to those of perl or
ruby. I
expect that this type of writing will become desirable when C++0x
lambda
functions are available. The C++0x 'auto' keyword will allow storing
the
generated iterators to local variables for further arithmetic; as it
stands now
the induced types are far to complex to be written out by hand.

The point of this message is just to share the idea in case anyone
wishes to do
something with it. I'm relatively new to C++ and lack the knowledge
needed to
make something like this the right way. For example, I have no idea
how to
make the transform_tuple function work with anything other than a two
element
tuple.

The '*' and '+' arithmetic operators have been defined to perform
pairwise arithmetic between elements, but it may also make sense to
define
operators like "magic_iter + scalar" and "magic_iter += magic_iter".
With the 'auto' keyword this would allow converting a bunch of STL
containers
into iterator objects which could then be manipulated mathematically
as
if they were Blitz++ arrays.

///////////////////////////////////////////////
// magic_iter_demo.cpp
///////////////////////////////////////////////

#include <magic_iter.h>

#include <vector>
#include <set>
#include <iostream>

#include <boost/foreach.hpp>
#include <boost/lambda/lambda.hpp>
using namespace boost::lambda;

int main() {
        std::cout << "--- odd multiples of 10, reverse sorted\n";

        std::vector<int> tmp;
        BOOST_FOREACH(
                int x,
                my::make_magic_counter(0, 10).
                        filter(_1 & 1).
                        transform<int>(_1 * 10).
                        assign_to(tmp). // needed to allow sort
                        sort(_1 > _2)
        ) {
                std::cout << x << std::endl;
        }

        std::cout << "--- unique elements of v*w, using zip\n";

        std::vector<int> v;
        std::vector<double> w;
        my::make_magic_counter(0, 11).
                transform<int>(_1 - 5).
                assign_to(v).
                transform<double>(_1 * 0.01).
                assign_to(w);

        std::set<double> tmp2;
        zip(my::make_magic_iter(v), my::make_magic_iter(w)).
                transform_tuple<double>(_1 * _2).
                insert_into(tmp2). // uniq
                for_each(std::cout << _1 << "\n");

        std::cout << "--- elements of v*w, using operator\n";

        (my::make_magic_iter(v) * my::make_magic_iter(w)).
                for_each(std::cout << _1 << "\n");
}

///////////////////////////////////////////////
// magic_iter.h
///////////////////////////////////////////////

#ifndef MAGIC_ITER_H
#define MAGIC_ITER_H

#include <iterator>
#include <algorithm>

#include <boost/range/iterator_range.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/iterator/filter_iterator.hpp>
#include <boost/iterator/zip_iterator.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/lambda/lambda.hpp>

namespace my {

// result_type_wrapper is from mailing list post by Maxim Yegorushkin
template <class R, class F>
struct result_type_wrapper : F {
    typedef R result_type;
    explicit result_type_wrapper(const F &f) : F(f) {}
};

template <class R, class F>
static inline result_type_wrapper<R, F> result_type(const F &f) {
    return result_type_wrapper<R, F>(f);
}

template <class R, class F>
struct tuple_lambda_wrapper {
    typedef R result_type;

    explicit tuple_lambda_wrapper(const F &_f) : f(_f) { }

    template <class T>
    R operator()(const T &tuple_val) const {
        return f(
            boost::tuples::get<0>(tuple_val),
            boost::tuples::get<1>(tuple_val)
        );
    }

    F f;
};

template <class R, class F>
static inline tuple_lambda_wrapper<R, F> tuple_lambda(const F &f) {
    return tuple_lambda_wrapper<R, F>(f);
}

template <class T>
class magic_iter : public boost::iterator_range<T>
{
public:
    typedef typename std::iterator_traits<T>::value_type value_type;

    magic_iter(const T &_begin, const T &_end) :
        boost::iterator_range<T>(_begin, _end)
    { }

    template <class F>
    magic_iter<boost::transform_iterator<F, T> > transform(const F &f)
{
        return magic_iter<boost::transform_iterator<F, T> >(
            boost::make_transform_iterator(this->begin(), f),
            boost::make_transform_iterator(this->end(), f)
        );
    }

    template <class R, class F>
    magic_iter<boost::transform_iterator<
    result_type_wrapper<R, F>, T> > transform(const F &f) {
        return transform(result_type<R>(f));
    }

    template <class R, class F>
    magic_iter<boost::transform_iterator<
    tuple_lambda_wrapper<R, F>, T> > transform_tuple(const F &f) {
        return transform(tuple_lambda<R>(f));
    }

    template <class C>
    magic_iter<typename C::iterator> assign_to(C &container) {
        container.assign(this->begin(), this->end());
        return make_magic_iter(container);
    }

    template <class C>
    magic_iter<typename C::iterator> insert_into(C &container) {
        container.insert(this->begin(), this->end());
        return make_magic_iter(container);
    }

    template <class F>
    magic_iter<T> &sort(const F &comparator) {
        std::sort(this->begin(), this->end(), comparator);
        return *this;
    }

    template <class F>
    magic_iter<boost::filter_iterator<F, T> > filter(const F &f) {
        return magic_iter<boost::filter_iterator<F, T> >(
            boost::make_filter_iterator(f, this->begin(), this-
>end()),
            boost::make_filter_iterator(f, this->end(), this->end())
        );
    }

    template <class F>
    void for_each(const F &f) {
        std::for_each(this->begin(), this->end(), f);
    }
};

template <class T>
magic_iter<typename T::iterator>
make_magic_iter(T &container) {
    return magic_iter<typename T::iterator>(container.begin(),
container.end());
}

template <class T>
magic_iter<typename T::iterator>
make_magic_iter(const T &begin, const T &end) {
    return magic_iter<typename T::iterator>(begin, end);
}

template <class T>
magic_iter<typename boost::counting_iterator<T> >
make_magic_counter(const T &begin, const T &end) {
    return magic_iter<typename boost::counting_iterator<T> >(
        boost::counting_iterator<T>(begin),
        boost::counting_iterator<T>(end)
    );
}

template <class A, class B>
magic_iter<boost::zip_iterator<boost::tuple<A, B> > >
zip(const magic_iter<A> &a, const magic_iter<B> &b) {
    //return make_magic_iter(
    return magic_iter<boost::zip_iterator<boost::tuple<A, B> > >(
        boost::make_zip_iterator(
            boost::tuple<A, B>(a.begin(), b.begin())
        ),
        boost::make_zip_iterator(
            boost::tuple<A, B>(a.end(), b.end())
        )
    );
}

template <class X, class Y>
struct tuple_multiply {
    typedef typename boost::lambda::return_type_2<
        boost::lambda::arithmetic_action<
            boost::lambda::multiply_action
>, X, Y>::type result_type;
    result_type operator()(const boost::tuple<X, Y> &t) const {
        const X &x = boost::tuples::get<0>(t);
        const Y &y = boost::tuples::get<1>(t);
        return x*y;
    }
};

template <class X, class Y>
magic_iter<boost::transform_iterator<
    tuple_multiply<typename X::value_type, typename Y::value_type>,
    boost::zip_iterator<boost::tuple<X, Y> >
> > operator*(magic_iter<X> x, magic_iter<Y> y) {
    //magic_iter<boost::zip_iterator<boost::tuple<X, Y> > > zi =
zip(x, y);
    //return zi.transform(tuple_multiply<typename X::value_type,
typename Y::value_type>());
    tuple_multiply<typename X::value_type, typename Y::value_type> op;
    return zip(x, y).transform(op);
}

template <class X, class Y>
struct tuple_plus {
    typedef typename boost::lambda::return_type_2<
        boost::lambda::arithmetic_action<
            boost::lambda::plus_action
>, X, Y>::type result_type;
    result_type operator()(const boost::tuple<X, Y> &t) const {
        const X &x = boost::tuples::get<0>(t);
        const Y &y = boost::tuples::get<1>(t);
        return x+y;
    }
};

template <class X, class Y>
magic_iter<boost::transform_iterator<
    tuple_plus<typename X::value_type, typename Y::value_type>,
    boost::zip_iterator<boost::tuple<X, Y> >
> > operator+(magic_iter<X> x, magic_iter<Y> y) {
    tuple_plus<typename X::value_type, typename Y::value_type> op;
    return zip(x, y).transform(op);
}

} // namespace my

#endif // MAGIC_ITER_H


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk