164 lines
4.4 KiB
C++
164 lines
4.4 KiB
C++
|
#ifndef SRK31_TRANSFORM_ITERATOR_HPP_
|
||
|
#define SRK31_TRANSFORM_ITERATOR_HPP_
|
||
|
|
||
|
#include <iterator>
|
||
|
#include <iostream>
|
||
|
#include <cassert>
|
||
|
#include <srk31/util.hpp>
|
||
|
|
||
|
/* Most of the time, you should use boost::transform_iterator instead.
|
||
|
* But this is factored as a a mixin, so that you can make iterators
|
||
|
* which inherit from whatever the base iterator type is.
|
||
|
*
|
||
|
* See notes in selective_iterator.hpp.
|
||
|
*/
|
||
|
|
||
|
namespace srk31
|
||
|
{
|
||
|
template <class Func, class Iter>
|
||
|
class transform_iterator;
|
||
|
|
||
|
template <class Func, class Iter, class MixerIn>
|
||
|
class transform_iterator_mixin
|
||
|
{
|
||
|
typedef transform_iterator_mixin<Func, Iter, MixerIn> self;
|
||
|
typedef MixerIn super;
|
||
|
public:
|
||
|
Func m_func;
|
||
|
|
||
|
const Iter& iter() const { return *static_cast<const MixerIn *>(this); }
|
||
|
Iter& iter() { return *static_cast< MixerIn *>(this); }
|
||
|
|
||
|
// fully specifying constructor
|
||
|
transform_iterator_mixin(Iter&& i, const Func& func = Func())
|
||
|
: m_func(func)
|
||
|
{}
|
||
|
|
||
|
// fully specifying constructor
|
||
|
transform_iterator_mixin(const Iter& i, const Func& func = Func())
|
||
|
: m_func(func)
|
||
|
{}
|
||
|
|
||
|
// default constructor
|
||
|
transform_iterator_mixin() {}
|
||
|
|
||
|
// copy constructor
|
||
|
transform_iterator_mixin(const self& arg)
|
||
|
: m_func(arg.m_func)
|
||
|
{}
|
||
|
|
||
|
// move constructor
|
||
|
transform_iterator_mixin(self&& arg)
|
||
|
: m_func(std::move(arg.m_func))
|
||
|
{}
|
||
|
|
||
|
// assignment
|
||
|
self& operator=(const self& arg)
|
||
|
{
|
||
|
this->m_func = arg.m_func;
|
||
|
return *this;
|
||
|
}
|
||
|
self& operator=(self&& arg) // move assignment
|
||
|
{
|
||
|
this->m_func = std::move(arg.m_func);
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
typedef typename Func::result_type reference;
|
||
|
typedef typename std::remove_reference<typename Func::result_type>::type value_type;
|
||
|
typedef value_type *pointer;
|
||
|
typedef typename Iter::difference_type difference_type;
|
||
|
typedef typename Iter::iterator_category iterator_category;
|
||
|
|
||
|
private:
|
||
|
void print_m_func() const
|
||
|
{
|
||
|
// typedef typename
|
||
|
// std::tuple_element<0, typename function_traits<Func>::argument_types>::type
|
||
|
// first_argument_type;
|
||
|
// std::cerr << "Derefing via function (with target? "
|
||
|
// << std::boolalpha << m_func.operator bool()
|
||
|
// << ") "
|
||
|
// << (void*) m_func.template target<reference(first_argument_type)>()
|
||
|
// << std::endl;
|
||
|
}
|
||
|
public:
|
||
|
reference operator*() const
|
||
|
{
|
||
|
this->print_m_func();
|
||
|
return m_func(*iter());
|
||
|
}
|
||
|
pointer operator->() const
|
||
|
{
|
||
|
this->print_m_func();
|
||
|
return &(m_func(*iter()));
|
||
|
}
|
||
|
self& operator++() // prefix
|
||
|
{
|
||
|
++iter();
|
||
|
return *this;
|
||
|
}
|
||
|
self operator++(int) // postfix ++, so copying
|
||
|
{
|
||
|
Iter tmp = iter();
|
||
|
++tmp;
|
||
|
return self(std::move(tmp), m_func);
|
||
|
}
|
||
|
self& operator--() // prefix --
|
||
|
{
|
||
|
--iter();
|
||
|
return *this;
|
||
|
}
|
||
|
self operator--(int) // postfix, so copying
|
||
|
{
|
||
|
Iter tmp = iter();
|
||
|
--tmp;
|
||
|
return self(std::move(tmp), m_func);
|
||
|
}
|
||
|
bool operator==(const self& arg) const { return iter() == arg.iter(); }
|
||
|
bool operator!=(const self& arg) const { return iter() != arg.iter(); }
|
||
|
};
|
||
|
|
||
|
template <class Func, class Iter>
|
||
|
class transform_iterator
|
||
|
: public Iter
|
||
|
, public transform_iterator_mixin<Func, Iter, transform_iterator<Func, Iter> >
|
||
|
{
|
||
|
typedef transform_iterator<Func, Iter> self;
|
||
|
typedef transform_iterator_mixin<Func, Iter, self> super;
|
||
|
public:
|
||
|
/* We don't just forward the mixin's constructors, because
|
||
|
* sometimes Iter will not have a default constructor -- rather,
|
||
|
* we have to pass our arguments to both bases. The mixin ignores
|
||
|
* any iterator argument, so it's up to Iter to initialize itself
|
||
|
* using this. FIXME: probably want to make selective_iterator
|
||
|
* consistent with this. */
|
||
|
transform_iterator(Iter&& i, const Func& func = Func())
|
||
|
: Iter(std::move(i)), super(i, func) {}
|
||
|
|
||
|
// fully specifying constructor
|
||
|
transform_iterator(const Iter& i, const Func& func = Func())
|
||
|
: Iter(i), super(i, func) {}
|
||
|
|
||
|
/* In cases where we can default-construct m_func,
|
||
|
* we can offer the Iter's constuctors too. */
|
||
|
using Iter::Iter;
|
||
|
|
||
|
typedef typename Func::result_type reference;
|
||
|
typedef typename std::remove_reference<typename Func::result_type>::type value_type;
|
||
|
typedef value_type *pointer;
|
||
|
typedef typename Iter::difference_type difference_type;
|
||
|
typedef typename Iter::iterator_category iterator_category;
|
||
|
|
||
|
using super::operator++;
|
||
|
using super::operator--;
|
||
|
using super::operator!=;
|
||
|
using super::operator==;
|
||
|
using super::operator*;
|
||
|
using super::operator->;
|
||
|
};
|
||
|
|
||
|
} // end namespace srk31
|
||
|
|
||
|
#endif
|