compilation-bundle/dwarf-compilation.base/contrib/libsrk31cxx/include/srk31/transform_iterator.hpp

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