forked from boostorg/range
Merge branch 'develop' - improved indexed adaptor
This commit is contained in:
@ -1,172 +1,370 @@
|
||||
// Boost.Range library
|
||||
// Copyright 2014 Neil Groves
|
||||
//
|
||||
// Copyright Thorsten Ottosen, Neil Groves 2006 - 2008. Use, modification and
|
||||
// distribution is subject to the Boost Software License, Version
|
||||
// 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// Copyright (c) 2010 Ilya Murav'jov
|
||||
//
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// For more information, see http://www.boost.org/libs/range/
|
||||
// Credits:
|
||||
// My (Neil's) first indexed adaptor was hindered by having the underlying
|
||||
// iterator return the same reference as the wrapped iterator. This meant that
|
||||
// to obtain the index one had to get to the index_iterator and call the
|
||||
// index() function on it. Ilya politely pointed out that this was useless in
|
||||
// a number of scenarios since one naturally hides the use of iterators in
|
||||
// good range-based code. Ilya provided a new interface (which has remained)
|
||||
// and a first implementation. Much of this original implementation has
|
||||
// been simplified and now supports more compilers and platforms.
|
||||
//
|
||||
#ifndef BOOST_RANGE_ADAPTOR_INDEXED_HPP_INCLUDED
|
||||
#define BOOST_RANGE_ADAPTOR_INDEXED_HPP_INCLUDED
|
||||
|
||||
#ifndef BOOST_RANGE_ADAPTOR_INDEXED_IMPL_HPP
|
||||
#define BOOST_RANGE_ADAPTOR_INDEXED_IMPL_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable : 4355 )
|
||||
#endif
|
||||
|
||||
#include <boost/range/config.hpp>
|
||||
#include <boost/range/adaptor/argument_fwd.hpp>
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <boost/range/traversal.hpp>
|
||||
#include <boost/range/size.hpp>
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
#include <boost/range/concepts.hpp>
|
||||
#include <boost/iterator/iterator_adaptor.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
|
||||
#include <boost/iterator/iterator_traits.hpp>
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace adaptors
|
||||
{
|
||||
// This structure exists to carry the parameters from the '|' operator
|
||||
// to the index adapter. The expression rng | indexed(1) instantiates
|
||||
// this structure and passes it as the right-hand operand to the
|
||||
// '|' operator.
|
||||
struct indexed
|
||||
{
|
||||
explicit indexed(std::size_t x) : val(x) {}
|
||||
std::size_t val;
|
||||
};
|
||||
|
||||
struct indexed
|
||||
{
|
||||
explicit indexed(std::ptrdiff_t x = 0)
|
||||
: val(x)
|
||||
{
|
||||
}
|
||||
std::ptrdiff_t val;
|
||||
};
|
||||
|
||||
} // namespace adaptors
|
||||
|
||||
namespace range
|
||||
{
|
||||
|
||||
// Why yet another "pair" class:
|
||||
// - std::pair can't store references
|
||||
// - no need for typing for index type (default to "std::ptrdiff_t"); this is
|
||||
// useful in BOOST_FOREACH() expressions that have pitfalls with commas
|
||||
// ( see http://www.boost.org/doc/libs/1_44_0/doc/html/foreach/pitfalls.html )
|
||||
// - meaningful access functions index(), value()
|
||||
template<class T, class Indexable = std::ptrdiff_t>
|
||||
class index_value
|
||||
: public tuple<Indexable, T>
|
||||
{
|
||||
typedef tuple<Indexable, T> base_t;
|
||||
|
||||
template<int N>
|
||||
struct iv_types
|
||||
{
|
||||
typedef typename tuples::element<N, base_t>::type n_type;
|
||||
|
||||
typedef typename tuples::access_traits<n_type>::non_const_type non_const_type;
|
||||
typedef typename tuples::access_traits<n_type>::const_type const_type;
|
||||
};
|
||||
|
||||
public:
|
||||
typedef typename iv_types<0>::non_const_type index_type;
|
||||
typedef typename iv_types<0>::const_type const_index_type;
|
||||
typedef typename iv_types<1>::non_const_type value_type;
|
||||
typedef typename iv_types<1>::const_type const_value_type;
|
||||
|
||||
index_value()
|
||||
{
|
||||
}
|
||||
|
||||
namespace range_detail
|
||||
index_value(typename tuples::access_traits<Indexable>::parameter_type t0,
|
||||
typename tuples::access_traits<T>::parameter_type t1)
|
||||
: base_t(t0, t1)
|
||||
{
|
||||
template< class Iter >
|
||||
class indexed_iterator
|
||||
: public boost::iterator_adaptor< indexed_iterator<Iter>, Iter >
|
||||
{
|
||||
private:
|
||||
typedef boost::iterator_adaptor< indexed_iterator<Iter>, Iter >
|
||||
base;
|
||||
}
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME base::difference_type index_type;
|
||||
// member functions index(), value() (non-const and const)
|
||||
index_type index()
|
||||
{
|
||||
return boost::tuples::get<0>(*this);
|
||||
}
|
||||
|
||||
index_type m_index;
|
||||
const_index_type index() const
|
||||
{
|
||||
return boost::tuples::get<0>(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
indexed_iterator()
|
||||
: m_index(index_type()) {}
|
||||
|
||||
explicit indexed_iterator( Iter i, index_type index )
|
||||
: base(i), m_index(index)
|
||||
{
|
||||
BOOST_ASSERT( m_index >= 0 && "Indexed Iterator out of bounds" );
|
||||
}
|
||||
value_type value()
|
||||
{
|
||||
return boost::tuples::get<1>(*this);
|
||||
}
|
||||
|
||||
index_type index() const
|
||||
{
|
||||
return m_index;
|
||||
}
|
||||
const_value_type value() const
|
||||
{
|
||||
return boost::tuples::get<1>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
} // namespace range
|
||||
|
||||
void increment()
|
||||
{
|
||||
++m_index;
|
||||
++(this->base_reference());
|
||||
}
|
||||
namespace range_detail
|
||||
{
|
||||
|
||||
template<typename Iter>
|
||||
struct indexed_iterator_value_type
|
||||
{
|
||||
typedef ::boost::range::index_value<
|
||||
typename iterator_reference<Iter>::type,
|
||||
typename iterator_difference<Iter>::type
|
||||
> type;
|
||||
};
|
||||
|
||||
void decrement()
|
||||
{
|
||||
BOOST_ASSERT( m_index > 0 && "Indexed Iterator out of bounds" );
|
||||
--m_index;
|
||||
--(this->base_reference());
|
||||
}
|
||||
// Meta-function to get the traversal for the range and therefore iterator
|
||||
// returned by the indexed adaptor for a specified iterator type.
|
||||
//
|
||||
// Random access -> Random access
|
||||
// Bidirectional -> Forward
|
||||
// Forward -> Forward
|
||||
// SinglePass -> SinglePass
|
||||
//
|
||||
// The rationale for demoting a Bidirectional input to Forward is that the end
|
||||
// iterator cannot cheaply have an index computed for it. Therefore I chose to
|
||||
// demote to forward traversal. I can maintain the ability to traverse randomly
|
||||
// when the input is Random Access since the index for the end iterator is cheap
|
||||
// to compute.
|
||||
template<typename Iter>
|
||||
struct indexed_traversal
|
||||
{
|
||||
private:
|
||||
typedef typename iterator_traversal<Iter>::type wrapped_traversal;
|
||||
|
||||
void advance( index_type n )
|
||||
{
|
||||
m_index += n;
|
||||
BOOST_ASSERT( m_index >= 0 && "Indexed Iterator out of bounds" );
|
||||
this->base_reference() += n;
|
||||
}
|
||||
};
|
||||
public:
|
||||
|
||||
template< class Rng >
|
||||
struct indexed_range :
|
||||
iterator_range< indexed_iterator<BOOST_DEDUCED_TYPENAME range_iterator<Rng>::type> >
|
||||
{
|
||||
private:
|
||||
typedef indexed_iterator<BOOST_DEDUCED_TYPENAME range_iterator<Rng>::type>
|
||||
iter_type;
|
||||
typedef iterator_range<iter_type>
|
||||
base;
|
||||
public:
|
||||
template< class Index >
|
||||
indexed_range( Index i, Rng& r )
|
||||
: base( iter_type(boost::begin(r), i), iter_type(boost::end(r),i) )
|
||||
{ }
|
||||
};
|
||||
typedef typename mpl::if_<
|
||||
is_convertible<wrapped_traversal, random_access_traversal_tag>,
|
||||
random_access_traversal_tag,
|
||||
typename mpl::if_<
|
||||
is_convertible<wrapped_traversal, bidirectional_traversal_tag>,
|
||||
forward_traversal_tag,
|
||||
wrapped_traversal
|
||||
>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
} // 'range_detail'
|
||||
template<typename Iter>
|
||||
class indexed_iterator
|
||||
: public iterator_facade<
|
||||
indexed_iterator<Iter>,
|
||||
typename indexed_iterator_value_type<Iter>::type,
|
||||
typename indexed_traversal<Iter>::type,
|
||||
typename indexed_iterator_value_type<Iter>::type,
|
||||
typename iterator_difference<Iter>::type
|
||||
>
|
||||
{
|
||||
public:
|
||||
typedef Iter wrapped;
|
||||
|
||||
private:
|
||||
typedef iterator_facade<
|
||||
indexed_iterator<wrapped>,
|
||||
typename indexed_iterator_value_type<wrapped>::type,
|
||||
typename indexed_traversal<wrapped>::type,
|
||||
typename indexed_iterator_value_type<wrapped>::type,
|
||||
typename iterator_difference<wrapped>::type
|
||||
> base_t;
|
||||
|
||||
public:
|
||||
typedef typename base_t::difference_type difference_type;
|
||||
typedef typename base_t::reference reference;
|
||||
typedef typename base_t::difference_type index_type;
|
||||
|
||||
indexed_iterator()
|
||||
: m_it()
|
||||
, m_index()
|
||||
{
|
||||
}
|
||||
|
||||
template<typename OtherWrapped>
|
||||
indexed_iterator(
|
||||
const indexed_iterator<OtherWrapped>& other,
|
||||
typename enable_if<is_convertible<OtherWrapped, wrapped> >::type* = 0
|
||||
)
|
||||
: m_it(other.get())
|
||||
, m_index(other.get_index())
|
||||
{
|
||||
}
|
||||
|
||||
explicit indexed_iterator(wrapped it, index_type index)
|
||||
: m_it(it)
|
||||
, m_index(index)
|
||||
{
|
||||
}
|
||||
|
||||
wrapped get() const
|
||||
{
|
||||
return m_it;
|
||||
}
|
||||
|
||||
index_type get_index() const
|
||||
{
|
||||
return m_index;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
reference dereference() const
|
||||
{
|
||||
return reference(m_index, *m_it);
|
||||
}
|
||||
|
||||
bool equal(const indexed_iterator& other) const
|
||||
{
|
||||
return m_it == other.m_it;
|
||||
}
|
||||
|
||||
void increment()
|
||||
{
|
||||
++m_index;
|
||||
++m_it;
|
||||
}
|
||||
|
||||
void decrement()
|
||||
{
|
||||
BOOST_ASSERT_MSG(m_index > 0, "indexed Iterator out of bounds");
|
||||
--m_index;
|
||||
--m_it;
|
||||
}
|
||||
|
||||
void advance(index_type n)
|
||||
{
|
||||
m_index += n;
|
||||
BOOST_ASSERT_MSG(m_index >= 0, "indexed Iterator out of bounds");
|
||||
m_it += n;
|
||||
}
|
||||
|
||||
difference_type distance_to(const indexed_iterator& other) const
|
||||
{
|
||||
return other.m_it - m_it;
|
||||
}
|
||||
|
||||
wrapped m_it;
|
||||
index_type m_index;
|
||||
};
|
||||
|
||||
template<typename SinglePassRange>
|
||||
struct indexed_range
|
||||
: iterator_range<
|
||||
indexed_iterator<
|
||||
typename range_iterator<SinglePassRange>::type
|
||||
>
|
||||
>
|
||||
{
|
||||
typedef iterator_range<
|
||||
indexed_iterator<
|
||||
typename range_iterator<SinglePassRange>::type
|
||||
>
|
||||
> base_t;
|
||||
|
||||
BOOST_RANGE_CONCEPT_ASSERT((
|
||||
boost::SinglePassRangeConcept<SinglePassRange>));
|
||||
public:
|
||||
typedef indexed_iterator<
|
||||
typename range_iterator<SinglePassRange>::type
|
||||
> iterator;
|
||||
|
||||
// Constructor for non-random access iterators.
|
||||
// This sets the end iterator index to i despite this being incorrect it
|
||||
// is never observable since bidirectional iterators are demoted to
|
||||
// forward iterators.
|
||||
indexed_range(
|
||||
typename base_t::difference_type i,
|
||||
SinglePassRange& r,
|
||||
single_pass_traversal_tag
|
||||
)
|
||||
: base_t(iterator(boost::begin(r), i),
|
||||
iterator(boost::end(r), i))
|
||||
{
|
||||
}
|
||||
|
||||
indexed_range(
|
||||
typename base_t::difference_type i,
|
||||
SinglePassRange& r,
|
||||
random_access_traversal_tag
|
||||
)
|
||||
: base_t(iterator(boost::begin(r), i),
|
||||
iterator(boost::end(r), i + boost::size(r)))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace range_detail
|
||||
|
||||
// Make this available to users of this library. It will sometimes be
|
||||
// required since it is the return type of operator '|' and
|
||||
// index().
|
||||
using range_detail::indexed_range;
|
||||
|
||||
namespace adaptors
|
||||
{
|
||||
template< class SinglePassRange >
|
||||
inline indexed_range<SinglePassRange>
|
||||
operator|( SinglePassRange& r,
|
||||
const indexed& f )
|
||||
{
|
||||
BOOST_RANGE_CONCEPT_ASSERT((
|
||||
SinglePassRangeConcept<SinglePassRange>));
|
||||
|
||||
return indexed_range<SinglePassRange>( f.val, r );
|
||||
}
|
||||
|
||||
template< class SinglePassRange >
|
||||
inline indexed_range<const SinglePassRange>
|
||||
operator|( const SinglePassRange& r,
|
||||
const indexed& f )
|
||||
{
|
||||
BOOST_RANGE_CONCEPT_ASSERT((
|
||||
SinglePassRangeConcept<const SinglePassRange>));
|
||||
|
||||
return indexed_range<const SinglePassRange>( f.val, r );
|
||||
}
|
||||
|
||||
template<class SinglePassRange, class Index>
|
||||
inline indexed_range<SinglePassRange>
|
||||
index(SinglePassRange& rng, Index index_value)
|
||||
{
|
||||
BOOST_RANGE_CONCEPT_ASSERT((
|
||||
SinglePassRangeConcept<SinglePassRange>));
|
||||
|
||||
return indexed_range<SinglePassRange>(index_value, rng);
|
||||
}
|
||||
|
||||
template<class SinglePassRange, class Index>
|
||||
inline indexed_range<const SinglePassRange>
|
||||
index(const SinglePassRange& rng, Index index_value)
|
||||
{
|
||||
BOOST_RANGE_CONCEPT_ASSERT((
|
||||
SinglePassRangeConcept<const SinglePassRange>));
|
||||
|
||||
return indexed_range<const SinglePassRange>(index_value, rng);
|
||||
}
|
||||
} // 'adaptors'
|
||||
|
||||
template<class SinglePassRange>
|
||||
inline indexed_range<SinglePassRange>
|
||||
operator|(SinglePassRange& r, indexed e)
|
||||
{
|
||||
BOOST_RANGE_CONCEPT_ASSERT((
|
||||
boost::SinglePassRangeConcept<SinglePassRange>
|
||||
));
|
||||
return indexed_range<SinglePassRange>(
|
||||
e.val, r,
|
||||
typename range_traversal<SinglePassRange>::type());
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning( pop )
|
||||
#endif
|
||||
template<class SinglePassRange>
|
||||
inline indexed_range<const SinglePassRange>
|
||||
operator|(const SinglePassRange& r, indexed e)
|
||||
{
|
||||
BOOST_RANGE_CONCEPT_ASSERT((
|
||||
boost::SinglePassRangeConcept<const SinglePassRange>
|
||||
));
|
||||
return indexed_range<const SinglePassRange>(
|
||||
e.val, r,
|
||||
typename range_traversal<const SinglePassRange>::type());
|
||||
}
|
||||
|
||||
#endif
|
||||
template<class SinglePassRange>
|
||||
inline indexed_range<SinglePassRange>
|
||||
index(
|
||||
SinglePassRange& rng,
|
||||
typename range_difference<SinglePassRange>::type index_value = 0)
|
||||
{
|
||||
BOOST_RANGE_CONCEPT_ASSERT((
|
||||
boost::SinglePassRangeConcept<SinglePassRange>
|
||||
));
|
||||
return indexed_range<SinglePassRange>(
|
||||
index_value, rng,
|
||||
typename range_traversal<SinglePassRange>::type());
|
||||
}
|
||||
|
||||
template<class SinglePassRange>
|
||||
inline indexed_range<const SinglePassRange>
|
||||
index(
|
||||
const SinglePassRange& rng,
|
||||
typename range_difference<const SinglePassRange>::type index_value = 0)
|
||||
{
|
||||
BOOST_RANGE_CONCEPT_ASSERT((
|
||||
boost::SinglePassRangeConcept<SinglePassRange>
|
||||
));
|
||||
return indexed_range<const SinglePassRange>(
|
||||
index_value, rng,
|
||||
typename range_traversal<const SinglePassRange>::type());
|
||||
}
|
||||
|
||||
} // namespace adaptors
|
||||
} // namespace boost
|
||||
|
||||
#endif // include guard
|
||||
|
31
include/boost/range/traversal.hpp
Normal file
31
include/boost/range/traversal.hpp
Normal file
@ -0,0 +1,31 @@
|
||||
// Boost.Range library
|
||||
//
|
||||
// Copyright Neil Groves 2014. Use, modification and
|
||||
// distribution is subject to the Boost Software License, Version
|
||||
// 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// For more information, see http://www.boost.org/libs/range/
|
||||
//
|
||||
|
||||
#ifndef BOOST_RANGE_TRAVERSAL_HPP
|
||||
#define BOOST_RANGE_TRAVERSAL_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/range/config.hpp>
|
||||
#include <boost/range/iterator.hpp>
|
||||
#include <boost/iterator/iterator_traits.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template<typename SinglePassRange>
|
||||
struct range_traversal
|
||||
: iterator_traversal<typename range_iterator<SinglePassRange>::type>
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user