forked from boostorg/range
change the return type from the indexed adaptor so that the index is available from the range element.
This commit is contained in:
@ -7,14 +7,60 @@
|
|||||||
|
|
||||||
[table
|
[table
|
||||||
[[Syntax] [Code]]
|
[[Syntax] [Code]]
|
||||||
|
[[Pipe] [`rng | boost::adaptors::indexed()`]]
|
||||||
[[Pipe] [`rng | boost::adaptors::indexed(start_index)`]]
|
[[Pipe] [`rng | boost::adaptors::indexed(start_index)`]]
|
||||||
|
[[Function] [`boost::adaptors::index(rng)`]]
|
||||||
[[Function] [`boost::adaptors::index(rng, start_index)`]]
|
[[Function] [`boost::adaptors::index(rng, start_index)`]]
|
||||||
]
|
]
|
||||||
|
|
||||||
* [*Returns:] A range adapted to return both the element and the associated index. The returned range consists of iterators that have in addition to the usual iterator member functions an `index()` member function that returns the appropriate index for the element in the sequence corresponding with the iterator.
|
[heading Description]
|
||||||
|
The index within each returned `boost::range::index_value` is equal to
|
||||||
|
`start_index` + the offset of the element from the beginning of the range. In
|
||||||
|
the versions of the functions that omit `start_index` the starting index is
|
||||||
|
taken to be `0`.
|
||||||
|
|
||||||
|
* [*Purpose:] Adapt `rng` to return elements that have the corresponding value
|
||||||
|
from `rng` and a numeric index.
|
||||||
|
* [*Returns:] A range adapted to return both the element and the associated
|
||||||
|
index. The returned range has elements of type:
|
||||||
|
|
||||||
|
``
|
||||||
|
boost::range::index_value<
|
||||||
|
typename boost::range_reference<decltype(rng)>::type,
|
||||||
|
typename boost::range_difference<decltype(rng)>::type
|
||||||
|
>
|
||||||
|
``
|
||||||
|
|
||||||
|
The synopsis of index_value is as follows:
|
||||||
|
``
|
||||||
|
template<class T, class Indexable=std::ptrdiff_t>
|
||||||
|
class index_value : public boost::tuple<Indexable, T>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef ...unspecified... index_type;
|
||||||
|
typedef ...unspecified... const_index_type;
|
||||||
|
|
||||||
|
typedef ...unspecified... value_type;
|
||||||
|
typedef ...unspecified... const_value_type;
|
||||||
|
|
||||||
|
// ...unspecified... constructors
|
||||||
|
|
||||||
|
index_type index();
|
||||||
|
const_index_type index() const;
|
||||||
|
|
||||||
|
value_type value();
|
||||||
|
const_value_type value() const;
|
||||||
|
};
|
||||||
|
``
|
||||||
|
|
||||||
* [*Range Category:] __single_pass_range__
|
* [*Range Category:] __single_pass_range__
|
||||||
* [*Range Return Type:] `boost::indexed_range<decltype(rng)>`
|
* [*Range Return Type:] `boost::indexed_range<decltype(rng)>`
|
||||||
* [*Returned Range Category:] The range category of `rng`
|
* [*Returned Range Category:] The range category of `rng` if and only if `rng`
|
||||||
|
is not a __bidirectional_range__. If `rng` is a __bidirectional_range__ then the
|
||||||
|
returned range category is __forward_range__. The rationale for the demotion of
|
||||||
|
__bidirectional_range__ inputs to __forward_range__ is to avoid slow calculation
|
||||||
|
of indices for `boost::end(rng)`.
|
||||||
|
|
||||||
[section:indexed_example indexed example]
|
[section:indexed_example indexed example]
|
||||||
[import ../../../test/adaptor_test/indexed_example.cpp]
|
[import ../../../test/adaptor_test/indexed_example.cpp]
|
||||||
|
@ -1,172 +1,370 @@
|
|||||||
// Boost.Range library
|
// Copyright 2014 Neil Groves
|
||||||
//
|
//
|
||||||
// Copyright Thorsten Ottosen, Neil Groves 2006 - 2008. Use, modification and
|
// Copyright (c) 2010 Ilya Murav'jov
|
||||||
// distribution is subject to the Boost Software License, Version
|
//
|
||||||
// 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
// 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)
|
// 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
|
#include <boost/range/config.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/adaptor/argument_fwd.hpp>
|
#include <boost/range/adaptor/argument_fwd.hpp>
|
||||||
#include <boost/range/iterator_range.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/begin.hpp>
|
||||||
#include <boost/range/end.hpp>
|
#include <boost/range/end.hpp>
|
||||||
#include <boost/range/concepts.hpp>
|
#include <boost/mpl/if.hpp>
|
||||||
#include <boost/iterator/iterator_adaptor.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 boost
|
||||||
{
|
{
|
||||||
namespace adaptors
|
namespace adaptors
|
||||||
{
|
{
|
||||||
// This structure exists to carry the parameters from the '|' operator
|
|
||||||
// to the index adapter. The expression rng | indexed(1) instantiates
|
struct indexed
|
||||||
// this structure and passes it as the right-hand operand to the
|
{
|
||||||
// '|' operator.
|
explicit indexed(std::ptrdiff_t x = 0)
|
||||||
struct indexed
|
: val(x)
|
||||||
{
|
{
|
||||||
explicit indexed(std::size_t x) : val(x) {}
|
}
|
||||||
std::size_t val;
|
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:
|
value_type value()
|
||||||
indexed_iterator()
|
{
|
||||||
: m_index(index_type()) {}
|
return boost::tuples::get<1>(*this);
|
||||||
|
}
|
||||||
explicit indexed_iterator( Iter i, index_type index )
|
|
||||||
: base(i), m_index(index)
|
|
||||||
{
|
|
||||||
BOOST_ASSERT( m_index >= 0 && "Indexed Iterator out of bounds" );
|
|
||||||
}
|
|
||||||
|
|
||||||
index_type index() const
|
const_value_type value() const
|
||||||
{
|
{
|
||||||
return m_index;
|
return boost::tuples::get<1>(*this);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
} // namespace range
|
||||||
friend class boost::iterator_core_access;
|
|
||||||
|
|
||||||
void increment()
|
namespace range_detail
|
||||||
{
|
{
|
||||||
++m_index;
|
|
||||||
++(this->base_reference());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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()
|
// Meta-function to get the traversal for the range and therefore iterator
|
||||||
{
|
// returned by the indexed adaptor for a specified iterator type.
|
||||||
BOOST_ASSERT( m_index > 0 && "Indexed Iterator out of bounds" );
|
//
|
||||||
--m_index;
|
// Random access -> Random access
|
||||||
--(this->base_reference());
|
// 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 )
|
public:
|
||||||
{
|
|
||||||
m_index += n;
|
|
||||||
BOOST_ASSERT( m_index >= 0 && "Indexed Iterator out of bounds" );
|
|
||||||
this->base_reference() += n;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template< class Rng >
|
typedef typename mpl::if_<
|
||||||
struct indexed_range :
|
is_convertible<wrapped_traversal, random_access_traversal_tag>,
|
||||||
iterator_range< indexed_iterator<BOOST_DEDUCED_TYPENAME range_iterator<Rng>::type> >
|
random_access_traversal_tag,
|
||||||
{
|
typename mpl::if_<
|
||||||
private:
|
is_convertible<wrapped_traversal, bidirectional_traversal_tag>,
|
||||||
typedef indexed_iterator<BOOST_DEDUCED_TYPENAME range_iterator<Rng>::type>
|
forward_traversal_tag,
|
||||||
iter_type;
|
wrapped_traversal
|
||||||
typedef iterator_range<iter_type>
|
>::type
|
||||||
base;
|
>::type type;
|
||||||
public:
|
};
|
||||||
template< class Index >
|
|
||||||
indexed_range( Index i, Rng& r )
|
|
||||||
: base( iter_type(boost::begin(r), i), iter_type(boost::end(r),i) )
|
|
||||||
{ }
|
|
||||||
};
|
|
||||||
|
|
||||||
} // '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;
|
using range_detail::indexed_range;
|
||||||
|
|
||||||
namespace adaptors
|
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
|
template<class SinglePassRange>
|
||||||
#pragma warning( pop )
|
inline indexed_range<const SinglePassRange>
|
||||||
#endif
|
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
|
@ -1,6 +1,6 @@
|
|||||||
// Boost.Range library
|
// Boost.Range library
|
||||||
//
|
//
|
||||||
// Copyright Neil Groves 2009. Use, modification and
|
// Copyright Neil Groves 2014. Use, modification and
|
||||||
// distribution is subject to the Boost Software License, Version
|
// distribution is subject to the Boost Software License, Version
|
||||||
// 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
// 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
// http://www.boost.org/LICENSE_1_0.txt)
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@ -14,6 +14,7 @@
|
|||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
#include <boost/assign.hpp>
|
#include <boost/assign.hpp>
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
#include <boost/range/algorithm_ext.hpp>
|
#include <boost/range/algorithm_ext.hpp>
|
||||||
#include <boost/range/concepts.hpp>
|
#include <boost/range/concepts.hpp>
|
||||||
|
|
||||||
@ -23,83 +24,129 @@
|
|||||||
|
|
||||||
#include "../test_utils.hpp"
|
#include "../test_utils.hpp"
|
||||||
|
|
||||||
namespace boost
|
namespace boost_range_test
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
template< class Container >
|
|
||||||
void indexed_test_impl( Container& c )
|
|
||||||
{
|
|
||||||
using namespace boost::adaptors;
|
|
||||||
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME Container::value_type value_t;
|
template<typename Container, typename AdaptedRange>
|
||||||
|
void check_result(
|
||||||
|
const Container& reference_range,
|
||||||
|
const AdaptedRange& adapted_range,
|
||||||
|
std::ptrdiff_t start_index
|
||||||
|
)
|
||||||
|
{
|
||||||
|
typedef typename boost::range_iterator<const Container>::type
|
||||||
|
reference_iterator;
|
||||||
|
|
||||||
// This is my preferred syntax using the | operator.
|
typedef typename boost::range_iterator<const AdaptedRange>::type
|
||||||
std::vector< value_t > test_result1;
|
adapted_iterator;
|
||||||
boost::push_back(test_result1, c | indexed(0));
|
|
||||||
|
|
||||||
// This is an alternative syntax preferred by some.
|
BOOST_REQUIRE_EQUAL(boost::size(reference_range),
|
||||||
std::vector< value_t > test_result2;
|
boost::size(adapted_range));
|
||||||
boost::push_back(test_result2, adaptors::index(c, 0));
|
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL_COLLECTIONS( c.begin(), c.end(),
|
reference_iterator reference_it = boost::begin(reference_range);
|
||||||
test_result1.begin(), test_result1.end() );
|
adapted_iterator adapted_it = boost::begin(adapted_range);
|
||||||
|
for (std::ptrdiff_t i = start_index;
|
||||||
BOOST_CHECK_EQUAL_COLLECTIONS( c.begin(), c.end(),
|
reference_it != boost::end(reference_range);
|
||||||
test_result2.begin(), test_result2.end() );
|
++reference_it, ++adapted_it, ++i)
|
||||||
|
{
|
||||||
boost::indexed_range< Container > test_result3
|
BOOST_CHECK_EQUAL(i, adapted_it->index());
|
||||||
= c | indexed(0);
|
BOOST_CHECK_EQUAL(*reference_it, adapted_it->value());
|
||||||
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME boost::range_const_iterator<
|
|
||||||
boost::indexed_range< Container > >::type iter_t;
|
|
||||||
|
|
||||||
iter_t it = test_result3.begin();
|
|
||||||
for (std::size_t i = 0, count = c.size(); i < count; ++i)
|
|
||||||
{
|
|
||||||
BOOST_CHECK_EQUAL( i, static_cast<std::size_t>(it.index()) );
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template< class Container >
|
|
||||||
void indexed_test_impl()
|
|
||||||
{
|
|
||||||
using namespace boost::assign;
|
|
||||||
|
|
||||||
Container c;
|
|
||||||
|
|
||||||
// test empty container
|
|
||||||
indexed_test_impl(c);
|
|
||||||
|
|
||||||
// test one element
|
|
||||||
c += 1;
|
|
||||||
indexed_test_impl(c);
|
|
||||||
|
|
||||||
// test many elements
|
|
||||||
c += 1,2,2,2,3,4,4,4,4,5,6,7,8,9,9;
|
|
||||||
indexed_test_impl(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void indexed_test()
|
|
||||||
{
|
|
||||||
indexed_test_impl< std::vector< int > >();
|
|
||||||
indexed_test_impl< std::list< int > >();
|
|
||||||
|
|
||||||
check_random_access_range_concept(std::vector<int>() | boost::adaptors::indexed(0));
|
|
||||||
check_bidirectional_range_concept(std::list<int>() | boost::adaptors::indexed(0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Container>
|
||||||
|
void indexed_test_impl(Container& c, std::ptrdiff_t start_index)
|
||||||
|
{
|
||||||
|
// This is my preferred syntax using the | operator.
|
||||||
|
check_result(c, c | boost::adaptors::indexed(), 0);
|
||||||
|
check_result(c, c | boost::adaptors::indexed(start_index), start_index);
|
||||||
|
|
||||||
|
// This is the function syntax
|
||||||
|
check_result(c, boost::adaptors::index(c), 0);
|
||||||
|
check_result(c, boost::adaptors::index(c, start_index), start_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Container>
|
||||||
|
void indexed_test_impl(Container& c)
|
||||||
|
{
|
||||||
|
indexed_test_impl(c, 0);
|
||||||
|
indexed_test_impl(c, -1);
|
||||||
|
indexed_test_impl(c, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Container>
|
||||||
|
void indexed_test_impl()
|
||||||
|
{
|
||||||
|
using namespace boost::assign;
|
||||||
|
|
||||||
|
Container c;
|
||||||
|
|
||||||
|
// test empty container
|
||||||
|
indexed_test_impl(c);
|
||||||
|
|
||||||
|
// test one element
|
||||||
|
c += 1;
|
||||||
|
indexed_test_impl(c);
|
||||||
|
|
||||||
|
// test many elements
|
||||||
|
c += 1,2,2,2,3,4,4,4,4,5,6,7,8,9,9;
|
||||||
|
indexed_test_impl(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Traversal, typename Range>
|
||||||
|
void check_traversal(const Range& rng)
|
||||||
|
{
|
||||||
|
BOOST_STATIC_ASSERT(
|
||||||
|
boost::is_convertible<
|
||||||
|
typename boost::range_traversal<const Range>::type,
|
||||||
|
Traversal
|
||||||
|
>::value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Traversal, typename Range>
|
||||||
|
void check_not_traversal(const Range& rng)
|
||||||
|
{
|
||||||
|
BOOST_STATIC_ASSERT(
|
||||||
|
!boost::is_convertible<
|
||||||
|
typename boost::range_traversal<const Range>::type,
|
||||||
|
Traversal
|
||||||
|
>::value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void indexed_test()
|
||||||
|
{
|
||||||
|
indexed_test_impl< std::vector< int > >();
|
||||||
|
indexed_test_impl< std::list< int > >();
|
||||||
|
|
||||||
|
std::vector<int> vi;
|
||||||
|
|
||||||
|
check_traversal<boost::random_access_traversal_tag>(
|
||||||
|
vi | boost::adaptors::indexed());
|
||||||
|
|
||||||
|
std::list<int> li;
|
||||||
|
|
||||||
|
check_traversal<boost::forward_traversal_tag>(
|
||||||
|
li | boost::adaptors::indexed());
|
||||||
|
|
||||||
|
check_not_traversal<boost::bidirectional_traversal_tag>(
|
||||||
|
li | boost::adaptors::indexed());
|
||||||
|
|
||||||
|
check_not_traversal<boost::random_access_traversal_tag>(
|
||||||
|
li | boost::adaptors::indexed());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namesapce
|
||||||
|
} // namespace boost_range_test
|
||||||
|
|
||||||
boost::unit_test::test_suite*
|
boost::unit_test::test_suite*
|
||||||
init_unit_test_suite(int argc, char* argv[])
|
init_unit_test_suite(int, char*[])
|
||||||
{
|
{
|
||||||
boost::unit_test::test_suite* test
|
boost::unit_test::test_suite* test
|
||||||
= BOOST_TEST_SUITE( "RangeTestSuite.adaptor.indexed" );
|
= BOOST_TEST_SUITE( "Boost.Range indexed adaptor test suite" );
|
||||||
|
|
||||||
test->add( BOOST_TEST_CASE( &boost::indexed_test ) );
|
test->add(BOOST_TEST_CASE(&boost_range_test::indexed_test));
|
||||||
|
|
||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,12 @@
|
|||||||
// For more information, see http://www.boost.org/libs/range/
|
// For more information, see http://www.boost.org/libs/range/
|
||||||
//
|
//
|
||||||
//[indexed_example
|
//[indexed_example
|
||||||
|
|
||||||
|
//<-
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
//->
|
||||||
|
|
||||||
#include <boost/range/adaptor/indexed.hpp>
|
#include <boost/range/adaptor/indexed.hpp>
|
||||||
#include <boost/range/algorithm/copy.hpp>
|
|
||||||
#include <boost/assign.hpp>
|
#include <boost/assign.hpp>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -20,8 +24,6 @@
|
|||||||
#include <boost/test/test_tools.hpp>
|
#include <boost/test/test_tools.hpp>
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
#include <boost/range/algorithm_ext/push_back.hpp>
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -35,14 +37,14 @@ void check_element_and_index(
|
|||||||
BOOST_CHECK_EQUAL( std::distance(test_first, test_last),
|
BOOST_CHECK_EQUAL( std::distance(test_first, test_last),
|
||||||
std::distance(reference_first, reference_last) );
|
std::distance(reference_first, reference_last) );
|
||||||
|
|
||||||
int reference_index = 0;
|
std::ptrdiff_t reference_index = 0;
|
||||||
|
|
||||||
Iterator1 test_it = test_first;
|
Iterator1 test_it = test_first;
|
||||||
Iterator2 reference_it = reference_first;
|
Iterator2 reference_it = reference_first;
|
||||||
for (; test_it != test_last; ++test_it, ++reference_it, ++reference_index)
|
for (; test_it != test_last; ++test_it, ++reference_it, ++reference_index)
|
||||||
{
|
{
|
||||||
BOOST_CHECK_EQUAL( *test_it, *reference_it );
|
BOOST_CHECK_EQUAL(test_it->value(), *reference_it);
|
||||||
BOOST_CHECK_EQUAL( test_it.index(), reference_index );
|
BOOST_CHECK_EQUAL(test_it->index(), reference_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,24 +53,11 @@ void check_element_and_index(
|
|||||||
const SinglePassRange1& test_rng,
|
const SinglePassRange1& test_rng,
|
||||||
const SinglePassRange2& reference_rng)
|
const SinglePassRange2& reference_rng)
|
||||||
{
|
{
|
||||||
check_element_and_index(boost::begin(test_rng), boost::end(test_rng),
|
check_element_and_index(
|
||||||
|
boost::begin(test_rng), boost::end(test_rng),
|
||||||
boost::begin(reference_rng), boost::end(reference_rng));
|
boost::begin(reference_rng), boost::end(reference_rng));
|
||||||
}
|
}
|
||||||
//->
|
//->
|
||||||
template<class Iterator>
|
|
||||||
void display_element_and_index(Iterator first, Iterator last)
|
|
||||||
{
|
|
||||||
for (Iterator it = first; it != last; ++it)
|
|
||||||
{
|
|
||||||
std::cout << "Element = " << *it << " Index = " << it.index() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class SinglePassRange>
|
|
||||||
void display_element_and_index(const SinglePassRange& rng)
|
|
||||||
{
|
|
||||||
display_element_and_index(boost::begin(rng), boost::end(rng));
|
|
||||||
}
|
|
||||||
|
|
||||||
//<-
|
//<-
|
||||||
void indexed_example_test()
|
void indexed_example_test()
|
||||||
@ -81,8 +70,19 @@ void indexed_example_test()
|
|||||||
std::vector<int> input;
|
std::vector<int> input;
|
||||||
input += 10,20,30,40,50,60,70,80,90;
|
input += 10,20,30,40,50,60,70,80,90;
|
||||||
|
|
||||||
display_element_and_index( input | indexed(0) );
|
//<-
|
||||||
|
#ifndef BOOST_NO_CXX11_RANGE_BASED_FOR
|
||||||
|
//->
|
||||||
|
for (const auto& element : input | indexed(0))
|
||||||
|
{
|
||||||
|
std::cout << "Element = " << element.value()
|
||||||
|
<< " Index = " << element.index()
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
//<-
|
||||||
|
#endif // C++11 has range for loop
|
||||||
|
//->
|
||||||
|
|
||||||
//= return 0;
|
//= return 0;
|
||||||
//=}
|
//=}
|
||||||
//]
|
//]
|
||||||
|
Reference in New Issue
Block a user