Compare commits

..

2 Commits

Author SHA1 Message Date
Ralf W. Grosse-Kunstleve
e608036e99 Join ralf_grosse_kunstleve with HEAD
[SVN r9444]
2001-03-05 20:01:01 +00:00
nobody
91c135c0af This commit was manufactured by cvs2svn to create branch
'unlabeled-1.7.2'.

[SVN r9367]
2001-02-28 21:39:59 +00:00
3 changed files with 795 additions and 273 deletions

View File

@@ -1,273 +0,0 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Filter Iterator Adaptor Documentation</title>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)"
align="center" width="277" height="86">
<h1>Filter Iterator Adaptor</h1>
Defined in header
<a href="../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a>
<p>
The filter iterator adaptor creates a view of an iterator range in
which some elements of the range are skipped over. A <a
href="http://www.sgi.com/tech/stl/Predicate.html">Predicate</a>
function object controls which elements are skipped. When the
predicate is applied to an element, if it returns <tt>true</tt> then
the element is retained and if it returns <tt>false</tt> then the
element is skipped over.
<h2>Synopsis</h2>
<pre>
namespace boost {
template &lt;class Predicate, class BaseIterator, ...&gt;
class filter_iterator_generator;
template &lt;class Predicate, class BaseIterator&gt;
typename filter_iterator_generator&lt;Predicate, BaseIterator&gt;::type
make_filter_iterator(BaseIterator first, BaseIterator last, const Predicate& p = Predicate());
}
</pre>
<hr>
<h2><a name="filter_iterator_generator">The Filter Iterator Type
Generator</a></h2>
The class <tt>filter_iterator_generator</tt> is a helper class whose
purpose is to construct a filter iterator type. The template
parameters for this class are the <tt>Predicate</tt> function object
type and the <tt>BaseIterator</tt> type that is being wrapped. In
most cases the associated types for the wrapped iterator can be
deduced from <tt>std::iterator_traits</tt>, but in some situations the
user may want to override these types, so there are also template
parameters for each of the iterator's associated types.
<pre>
template &lt;class Predicate, class BaseIterator,
class Value, class Reference, class Pointer, class Category, class Distance>
class filter_iterator_generator
{
public:
typedef <tt><a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a>&lt...&gt;</tt> type; // the resulting filter iterator type
}
</pre>
<h3>Example</h3>
The following example uses filter iterator to print out all the
positive integers in an array.
<pre>
struct is_positive_number {
bool operator()(int x) { return 0 &lt; x; }
};
int main() {
int numbers[] = { 0, -1, 4, -3, 5, 8, -2 };
const int N = sizeof(numbers)/sizeof(int);
typedef boost::filter_iterator_generator&lt;is_positive_number, int*, int&gt;::type FilterIter;
is_positive_number predicate;
FilterIter::policies_type policies(predicate, numbers + N);
FilterIter filter_iter_first(numbers, policies);
FilterIter filter_iter_last(numbers + N, policies);
std::copy(filter_iter_first, filter_iter_last, std::ostream_iterator&lt;int&gt;(std::cout, " "));
std::cout &lt;&lt; std::endl;
return 0;
}
</pre>
The output is:
<pre>
4 5 8
</pre>
<h3>Template Parameters</h3>
<Table border>
<TR>
<TH>Parameter</TH><TH>Description</TH>
</TR>
<TR>
<TD><a href="http://www.sgi.com/tech/stl/Predicate.html"><tt>Predicate</tt></a></TD>
<TD>The function object that determines which elements are retained and which elements are skipped.
</TR>
<TR>
<TD><tt>BaseIterator</tt></TD>
<TD>The iterator type being wrapped. This type must at least be a model
of the <a href="http://www.sgi.com/tech/stl/InputIterator">InputIterator</a> concept.</TD>
</TR>
<TR>
<TD><tt>Value</tt></TD>
<TD>The <tt>value_type</tt> of the resulting iterator,
unless const. If const, a conforming compiler strips constness for the
<tt>value_type</tt>. Typically the default for this parameter is the
appropriate type<a href="#1">[1]</a>.<br> <b>Default:</b>
<tt>std::iterator_traits&lt;BaseIterator&gt;::value_type</TD>
</TR>
<TR>
<TD><tt>Reference</tt></TD>
<TD>The <tt>reference</tt> type of the resulting iterator, and in
particular, the result type of <tt>operator*()</tt>. Typically the default for
this parameter is the appropriate type.<br> <b>Default:</b> If
<tt>Value</tt> is supplied, <tt>Value&amp;</tt> is used. Otherwise
<tt>std::iterator_traits&lt;BaseIterator&gt;::reference</tt> is
used.</TD>
</TR>
<TR>
<TD><tt>Pointer</tt></TD>
<TD>The <tt>pointer</tt> type of the resulting iterator, and in
particular, the result type of <tt>operator->()</tt>.
Typically the default for
this parameter is the appropriate type.<br>
<b>Default:</b> If <tt>Value</tt> was supplied, then <tt>Value*</tt>,
otherwise <tt>std::iterator_traits&lt;BaseIterator&gt;::pointer</tt>.</TD>
</TR>
<TR>
<TD><tt>Category</tt></TD>
<TD>The <tt>iterator_category</tt> type for the resulting iterator.
Typically the
default for this parameter is the appropriate type. If you override
this parameter, do not use <tt>bidirectional_iterator_tag</tt>
because filter iterators can not go in reverse.<br>
<b>Default:</b> <tt>std::iterator_traits&lt;BaseIterator&gt;::iterator_category</tt></TD>
</TR>
<TR>
<TD><tt>Distance</tt></TD>
<TD>The <tt>difference_type</tt> for the resulting iterator. Typically the default for
this parameter is the appropriate type.<br>
<b>Default:</b> <tt>std::iterator_traits&lt;BaseIterator&gt;::difference_type</TD>
</TR>
</table>
<h3>Model of</h3>
The filter iterator adaptor (the type
<tt>filter_iterator_generator<...>::type</tt>) may be a model of <a
href="www.sgi.com/tech/stl/InputIterator.html">InputIterator</a> or <a
href="www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>
depending on the adapted iterator type.
<h3>Members</h3>
The filter iterator type implements all of the member functions and
operators required of the <a
href="http://www.sgi.com/tech/stl/ForwardIterator.html">ForwardIterator</a>
concept. In addition it has the following constructor:
<pre>filter_iterator_generator::type(const BaseIterator& it, const Policies& p = Policies())</pre>
<p>
The policies type has only one public function, which is its constructor:
<pre>filter_iterator_generator::policies_type(const Predicate& p, const BaseIterator& end)</pre>
<p>
<hr>
<p>
<h2><a name="make_filter_iterator">The Make Filter Iterator Function</a></h2>
<pre>
template &lt;class Predicate, class BaseIterator&gt;
typename detail::filter_generator&lt;Predicate, BaseIterator&gt;::type
make_filter_iterator(BaseIterator first, BaseIterator last, const Predicate& p = Predicate())
</pre>
This function provides a convenient way to create filter iterators.
<h3>Example</h3>
In this example we print out all numbers in the array that are
greater than negative two.
<pre>
int main()
{
int numbers[] = { 0, -1, 4, -3, 5, 8, -2 };
const int N = sizeof(numbers)/sizeof(int);
std::copy(boost::make_filter_iterator(numbers, numbers + N,
std::bind2nd(std::greater<int>(), -2)),
boost::make_filter_iterator(numbers + N, numbers + N,
std::bind2nd(std::greater<int>(), -2)),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
}
</pre>
The output is:
<pre>
0 -1 4 5 8
</pre>
<p>
In the next example we print the positive numbers using the
<tt>make_filter_iterator()</tt> function.
<pre>
struct is_positive_number {
bool operator()(int x) { return 0 &lt; x; }
};
int main()
{
int numbers[] = { 0, -1, 4, -3, 5, 8, -2 };
const int N = sizeof(numbers)/sizeof(int);
std::copy(boost::make_filter_iterator&lt;is_positive_number&gt;(numbers, numbers + N),
boost::make_filter_iterator&lt;is_positive_number&gt;(numbers + N, numbers + N),
std::ostream_iterator&lt;int&gt;(std::cout, " "));
std::cout &lt;&lt; std::endl;
return 0;
}
</pre>
The output is:
<pre>
4 5 8
</pre>
<h3>Notes</h3>
<a name="1">[1]</a> If the compiler does not support partial
specialization and the wrapped iterator type is a builtin pointer then
the <tt>Value</tt> type must be explicitly specified (don't use the
default).
<hr>
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->18 Feb 2001<!--webbot bot="Timestamp" endspan i-checksum="14389" --></p>
<p><EFBFBD> Copyright Jeremy Siek 2000. Permission to copy, use,
modify, sell and distribute this document is granted provided this copyright
notice appears in all copies. This document is provided &quot;as is&quot;
without express or implied warranty, and with no claim as to its suitability for
any purpose.</p>
</body>
</html>

464
iterator_adaptor_test.cpp Normal file
View File

@@ -0,0 +1,464 @@
// Demonstrate and test boost/operators.hpp on std::iterators -------------//
// (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify,
// sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
// See http://www.boost.org for most recent version including documentation.
// Revision History
// 04 Mar 01 Workaround for Borland (Dave Abrahams)
// 19 Feb 01 Take adavantage of improved iterator_traits to do more tests
// on MSVC. Hack around an MSVC-with-STLport internal compiler
// error. (David Abrahams)
// 11 Feb 01 Added test of operator-> for forward and input iterators.
// (Jeremy Siek)
// 11 Feb 01 Borland fixes (David Abrahams)
// 10 Feb 01 Use new adaptors interface. (David Abrahams)
// 10 Feb 01 Use new filter_ interface. (David Abrahams)
// 09 Feb 01 Use new reverse_ and indirect_ interfaces. Replace
// BOOST_NO_STD_ITERATOR_TRAITS with
// BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION to prove we've
// normalized to core compiler capabilities (David Abrahams)
// 08 Feb 01 Use Jeremy's new make_reverse_iterator form; add more
// comprehensive testing. Force-decay array function arguments to
// pointers.
// 07 Feb 01 Added tests for the make_xxx_iterator() helper functions.
// (Jeremy Siek)
// 07 Feb 01 Replaced use of xxx_pair_generator with xxx_generator where
// possible (which was all but the projection iterator).
// (Jeremy Siek)
// 06 Feb 01 Removed now-defaulted template arguments where possible
// Updated names to correspond to new generator naming convention.
// Added a trivial test for make_transform_iterator().
// Gave traits for const iterators a mutable value_type, per std.
// Resurrected my original tests for indirect iterators.
// (David Abrahams)
// 04 Feb 01 Fix for compilers without standard iterator_traits
// (David Abrahams)
// 13 Jun 00 Added const version of the iterator tests (Jeremy Siek)
// 12 Dec 99 Initial version with iterator operators (Jeremy Siek)
#include <boost/config.hpp>
#include <iostream>
#include <algorithm>
#include <functional>
#include <boost/iterator_adaptors.hpp>
#include <boost/pending/iterator_tests.hpp>
#include <boost/pending/integer_range.hpp>
#include <boost/concept_archetype.hpp>
#include <stdlib.h>
#include <vector>
#include <deque>
#include <set>
struct my_iterator_tag : public std::random_access_iterator_tag { };
using boost::dummyT;
struct my_iter_traits {
typedef dummyT value_type;
typedef dummyT* pointer;
typedef dummyT& reference;
typedef my_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
};
struct my_const_iter_traits {
typedef dummyT value_type;
typedef const dummyT* pointer;
typedef const dummyT& reference;
typedef my_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
};
typedef boost::iterator_adaptor<dummyT*,
boost::default_iterator_policies, dummyT> my_iterator;
typedef boost::iterator_adaptor<const dummyT*,
boost::default_iterator_policies, const dummyT> const_my_iterator;
struct mult_functor {
typedef int result_type;
typedef int argument_type;
// Functors used with transform_iterator must be
// DefaultConstructible, as the transform_iterator must be
// DefaultConstructible to satisfy the requirements for
// TrivialIterator.
mult_functor() { }
mult_functor(int aa) : a(aa) { }
int operator()(int b) const { return a * b; }
int a;
};
template <class Pair>
struct select1st_
: public std::unary_function<Pair, typename Pair::first_type>
{
const typename Pair::first_type& operator()(const Pair& x) const {
return x.first;
}
typename Pair::first_type& operator()(Pair& x) const {
return x.first;
}
};
struct one_or_four {
bool operator()(dummyT x) const {
return x.foo() == 1 || x.foo() == 4;
}
};
typedef std::deque<int> storage;
typedef std::deque<int*> pointer_deque;
typedef std::set<storage::iterator> iterator_set;
void more_indirect_iterator_tests()
{
// For some reason all heck breaks loose in the compiler under these conditions.
#if !defined(BOOST_MSVC) || !defined(__STL_DEBUG)
storage store(1000);
std::generate(store.begin(), store.end(), rand);
pointer_deque ptr_deque;
iterator_set iter_set;
for (storage::iterator p = store.begin(); p != store.end(); ++p)
{
ptr_deque.push_back(&*p);
iter_set.insert(p);
}
typedef boost::indirect_iterator_pair_generator<
pointer_deque::iterator
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
, int
#endif
> IndirectDeque;
IndirectDeque::iterator db(ptr_deque.begin());
IndirectDeque::iterator de(ptr_deque.end());
assert(static_cast<std::size_t>(de - db) == store.size());
assert(db + store.size() == de);
IndirectDeque::const_iterator dci(db);
assert(db == dci);
assert(dci == db);
assert(dci != de);
assert(dci < de);
assert(dci <= de);
assert(de >= dci);
assert(de > dci);
dci = de;
assert(dci == de);
boost::random_access_iterator_test(db + 1, store.size() - 1, boost::next(store.begin()));
*db = 999;
assert(store.front() == 999);
typedef boost::indirect_iterator_generator<
iterator_set::iterator
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
, int
#endif
>::type indirect_set_iterator;
typedef boost::indirect_iterator_generator<
iterator_set::iterator,
const int
>::type const_indirect_set_iterator;
indirect_set_iterator sb(iter_set.begin());
indirect_set_iterator se(iter_set.end());
const_indirect_set_iterator sci(iter_set.begin());
assert(sci == sb);
assert(sci != se);
sci = se;
assert(sci == se);
*boost::prior(se) = 888;
assert(store.back() == 888);
assert(std::equal(sb, se, store.begin()));
boost::bidirectional_iterator_test(boost::next(sb), store[1], store[2]);
assert(std::equal(db, de, store.begin()));
#endif
}
int
main()
{
dummyT array[] = { dummyT(0), dummyT(1), dummyT(2),
dummyT(3), dummyT(4), dummyT(5) };
const int N = sizeof(array)/sizeof(dummyT);
// sanity check, if this doesn't pass the test is buggy
boost::random_access_iterator_test(array,N,array);
// Check that the policy concept checks and the default policy
// implementation match up.
boost::function_requires<
boost::RandomAccessIteratorPoliciesConcept<
boost::default_iterator_policies, int*,
boost::iterator<std::random_access_iterator_tag, int, std::ptrdiff_t,
int*, int&>
> >();
// Test the iterator_adaptor
{
my_iterator i(array);
boost::random_access_iterator_test(i, N, array);
const_my_iterator j(array);
boost::random_access_iterator_test(j, N, array);
boost::const_nonconst_iterator_test(i, ++j);
}
// Test transform_iterator
{
int x[N], y[N];
for (int k = 0; k < N; ++k)
x[k] = k;
std::copy(x, x + N, y);
for (int k2 = 0; k2 < N; ++k2)
x[k2] = x[k2] * 2;
boost::transform_iterator_generator<mult_functor, int*>::type
i(y, mult_functor(2));
boost::input_iterator_test(i, x[0], x[1]);
boost::input_iterator_test(boost::make_transform_iterator(&y[0], mult_functor(2)), x[0], x[1]);
}
// Test indirect_iterator_generator
{
dummyT* ptr[N];
for (int k = 0; k < N; ++k)
ptr[k] = array + k;
typedef boost::indirect_iterator_generator<dummyT**
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
, dummyT
#endif
>::type indirect_iterator;
typedef boost::indirect_iterator_generator<dummyT**, const dummyT>::type const_indirect_iterator;
indirect_iterator i(ptr);
boost::random_access_iterator_test(i, N, array);
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
boost::random_access_iterator_test(boost::make_indirect_iterator(ptr), N, array);
#endif
// check operator->
assert((*i).m_x == i->foo());
const_indirect_iterator j(ptr);
boost::random_access_iterator_test(j, N, array);
dummyT*const* const_ptr = ptr;
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
boost::random_access_iterator_test(boost::make_indirect_iterator(const_ptr), N, array);
#endif
boost::const_nonconst_iterator_test(i, ++j);
more_indirect_iterator_tests();
}
// Test projection_iterator_pair_generator
{
typedef std::pair<dummyT,dummyT> Pair;
Pair pair_array[N];
for (int k = 0; k < N; ++k)
pair_array[k].first = array[k];
typedef boost::projection_iterator_pair_generator<select1st_<Pair>,
Pair*, const Pair*
> Projection;
Projection::iterator i(pair_array);
boost::random_access_iterator_test(i, N, array);
boost::random_access_iterator_test(boost::make_projection_iterator(pair_array, select1st_<Pair>()), N, array);
boost::random_access_iterator_test(boost::make_projection_iterator< select1st_<Pair> >(pair_array), N, array);
Projection::const_iterator j(pair_array);
boost::random_access_iterator_test(j, N, array);
boost::random_access_iterator_test(boost::make_const_projection_iterator(pair_array, select1st_<Pair>()), N, array);
boost::random_access_iterator_test(boost::make_const_projection_iterator<select1st_<Pair> >(pair_array), N, array);
boost::const_nonconst_iterator_test(i, ++j);
}
// Test reverse_iterator_generator
{
dummyT reversed[N];
std::copy(array, array + N, reversed);
std::reverse(reversed, reversed + N);
typedef boost::reverse_iterator_generator<dummyT*
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
, dummyT
#endif
>::type reverse_iterator;
reverse_iterator i(reversed + N);
boost::random_access_iterator_test(i, N, array);
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
boost::random_access_iterator_test(boost::make_reverse_iterator(reversed + N), N, array);
#endif
typedef boost::reverse_iterator_generator<const dummyT*
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
, const dummyT
#endif
>::type const_reverse_iterator;
const_reverse_iterator j(reversed + N);
boost::random_access_iterator_test(j, N, array);
const dummyT* const_reversed = reversed;
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
boost::random_access_iterator_test(boost::make_reverse_iterator(const_reversed + N), N, array);
#endif
boost::const_nonconst_iterator_test(i, ++j);
}
// Test reverse_iterator_generator again, with traits fully deducible on all platforms
{
std::deque<dummyT> reversed_container;
std::reverse_copy(array, array + N, std::back_inserter(reversed_container));
const std::deque<dummyT>::iterator reversed = reversed_container.begin();
typedef boost::reverse_iterator_generator<
std::deque<dummyT>::iterator>::type reverse_iterator;
typedef boost::reverse_iterator_generator<
std::deque<dummyT>::const_iterator, const dummyT>::type const_reverse_iterator;
// MSVC/STLport gives an INTERNAL COMPILER ERROR when any computation
// (e.g. "reversed + N") is used in the constructor below.
const std::deque<dummyT>::iterator finish = reversed_container.end();
reverse_iterator i(finish);
boost::random_access_iterator_test(i, N, array);
boost::random_access_iterator_test(boost::make_reverse_iterator(reversed + N), N, array);
const_reverse_iterator j = reverse_iterator(finish);
boost::random_access_iterator_test(j, N, array);
const std::deque<dummyT>::const_iterator const_reversed = reversed;
boost::random_access_iterator_test(boost::make_reverse_iterator(const_reversed + N), N, array);
// Many compilers' builtin deque iterators don't interoperate well, though
// STLport fixes that problem.
#if defined(__SGI_STL_PORT) || !defined(__GNUC__) && !defined(__BORLANDC__) && !defined(BOOST_MSVC)
boost::const_nonconst_iterator_test(i, ++j);
#endif
}
// Test integer_range's iterators
{
int int_array[] = { 0, 1, 2, 3, 4, 5 };
boost::integer_range<int> r(0, 5);
boost::random_access_iterator_test(r.begin(), r.size(), int_array);
}
// Test filter iterator
{
// Using typedefs for filter_gen::type and filter_gen::policies_type
// confused Borland terribly.
typedef boost::detail::non_bidirectional_category<dummyT*>::type category;
typedef ::boost::filter_iterator_generator<one_or_four, dummyT*
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
, dummyT
#endif
> filter_iter_gen;
#ifndef __BORLANDC__
typedef filter_iter_gen::type filter_iter;
#else
# define filter_iter filter_iter_gen::type // Borland has a problem with the above
#endif
filter_iter i(array, filter_iter::policies_type(one_or_four(), array + N));
boost::forward_iterator_test(i, dummyT(1), dummyT(4));
enum { is_forward = boost::is_same<
filter_iter::iterator_category,
std::forward_iterator_tag>::value };
BOOST_STATIC_ASSERT(is_forward);
// On compilers not supporting partial specialization, we can do more type
// deduction with deque iterators than with pointers... unless the library
// is broken ;-(
#if !defined(BOOST_MSVC) || defined(__SGI_STL_PORT)
std::deque<dummyT> array2;
std::copy(array+0, array+N, std::back_inserter(array2));
boost::forward_iterator_test(
boost::make_filter_iterator(array2.begin(), array2.end(), one_or_four()),
dummyT(1), dummyT(4));
boost::forward_iterator_test(
boost::make_filter_iterator<one_or_four>(array2.begin(), array2.end()),
dummyT(1), dummyT(4));
#endif
#if !defined(BOOST_MSVC) // This just freaks MSVC out completely
boost::forward_iterator_test(
boost::make_filter_iterator<one_or_four>(
boost::make_reverse_iterator(array2.end()),
boost::make_reverse_iterator(array2.begin())
),
dummyT(4), dummyT(1));
#endif
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
boost::forward_iterator_test(
boost::make_filter_iterator(array+0, array+N, one_or_four()),
dummyT(1), dummyT(4));
boost::forward_iterator_test(
boost::make_filter_iterator<one_or_four>(array, array + N),
dummyT(1), dummyT(4));
#endif
}
// check operator-> with a forward iterator
{
boost::forward_iterator_archetype<dummyT> forward_iter;
typedef boost::iterator_adaptor<boost::forward_iterator_archetype<dummyT>,
boost::default_iterator_policies,
dummyT, const dummyT&, const dummyT*,
std::forward_iterator_tag, std::ptrdiff_t> adaptor_type;
adaptor_type i(forward_iter);
if (0) // don't do this, just make sure it compiles
assert((*i).m_x == i->foo());
}
// check operator-> with an input iterator
{
boost::input_iterator_archetype<dummyT> input_iter;
typedef boost::iterator_adaptor<boost::input_iterator_archetype<dummyT>,
boost::default_iterator_policies,
dummyT, const dummyT&, const dummyT*,
std::input_iterator_tag, std::ptrdiff_t> adaptor_type;
adaptor_type i(input_iter);
if (0) // don't do this, just make sure it compiles
assert((*i).m_x == i->foo());
}
std::cout << "test successful " << std::endl;
return 0;
}

331
reverse_iterator.htm Normal file
View File

@@ -0,0 +1,331 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
<html>
<head>
<meta name="generator" content="HTML Tidy, see www.w3.org">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Reverse Iterator Adaptor Documentation</title>
</head>
<body bgcolor="#FFFFFF" text="#000000">
<img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)" align=
"center" width="277" height="86">
<h1>Reverse Iterator Adaptor</h1>
Defined in header <a href=
"../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a>
<p>The reverse iterator adaptor flips the direction of a base iterator's
motion. Invoking <tt>operator++()</tt> moves the base iterator backward and
invoking <tt>operator--()</tt> moves the base iterator forward. The Boost
reverse iterator adaptor is better to use than the
<tt>std::reverse_iterator</tt> class in situations where pairs of
mutable/constant iterators are needed (e.g., in containers) because
comparisons and conversions between the mutable and const versions are
implemented correctly.
<h2>Synopsis</h2>
<pre>
namespace boost {
template &lt;class <a href=
"http://www.sgi.com/tech/stl/BidirectionalIterator.html">BidirectionalIterator</a>,
class Value, class Reference, class Pointer, class Category, class Distance&gt;
struct reverse_iterator_generator;
template &lt;class <a href=
"http://www.sgi.com/tech/stl/BidirectionalIterator.html">BidirectionalIterator</a>&gt;
typename reverse_iterator_generator&lt;BidirectionalIterator&gt;::type
make_reverse_iterator(BidirectionalIterator base)
}
</pre>
<hr>
<h2><a name="reverse_iterator_generator">The Reverse Iterator Type
Generator</a></h2>
The <tt>reverse_iterator_generator</tt> template is a <a href=
"../../more/generic_programming.html#type_generator">generator</a> of
reverse iterator types. The main template parameter for this class is the
base <tt>BidirectionalIterator</tt> type that is being adapted. In most
cases the associated types of the base iterator can be deduced using
<tt>std::iterator_traits</tt>, but in some situations the user may want to
override these types, so there are also template parameters for the base
iterator's associated types.
<blockquote>
<pre>
template &lt;class <a href=
"http://www.sgi.com/tech/stl/BidirectionalIterator.html">BidirectionalIterator</a>,
class Value, class Reference, class Pointer, class Category, class Distance&gt;
class reverse_iterator_generator
{
public:
typedef <tt><a href=
"./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a>&lt;...&gt;</tt> type; // the resulting reverse iterator type
};
</pre>
</blockquote>
<h3>Example</h3>
In this example we sort a sequence of letters and then output the sequence
in descending order using reverse iterators.
<blockquote>
<pre>
#include &lt;boost/config.hpp&gt;
#include &lt;iostream&gt;
#include &lt;algorithm&gt;
#include &lt;boost/iterator_adaptors.hpp&gt;
int main(int, char*[])
{
char letters[] = "hello world!";
const int N = sizeof(letters)/sizeof(char) - 1;
std::cout &lt;&lt; "original sequence of letters:\t"
&lt;&lt; letters &lt;&lt; std::endl;
std::sort(letters, letters + N);
// Use reverse_iterator_generator to print a sequence
// of letters in reverse order.
boost::reverse_iterator_generator&lt;char*&gt;::type
reverse_letters_first(letters + N),
reverse_letters_last(letters);
std::cout &lt;&lt; "letters in descending order:\t";
std::copy(reverse_letters_first, reverse_letters_last,
std::ostream_iterator&lt;char&gt;(std::cout));
std::cout &lt;&lt; std::endl;
// to be continued...
</pre>
</blockquote>
The output is:
<blockquote>
<pre>
original sequence of letters: hello world!
letters in descending order: wroolllhed!
</pre>
</blockquote>
<h3>Template Parameters</h3>
<table border>
<tr>
<th>Parameter
<th>Description
<tr>
<td><tt><a href=
"http://www.sgi.com/tech/stl/BidirectionalIterator.html">BidirectionalIterator</a></tt>
<td>The iterator type being wrapped.
<tr>
<td><tt>Value</tt>
<td>The value-type of the base iterator and the resulting reverse
iterator.<br>
<b>Default:</b><tt>std::iterator_traits&lt;BidirectionalIterator&gt;::value_type</tt>
<tr>
<td><tt>Reference</tt>
<td>The <tt>reference</tt> type of the resulting iterator, and in
particular, the result type of <tt>operator*()</tt>.<br>
<b>Default:</b> If <tt>Value</tt> is supplied, <tt>Value&amp;</tt> is
used. Otherwise
<tt>std::iterator_traits&lt;BidirectionalIterator&gt;::reference</tt>
is used.
<tr>
<td><tt>Pointer</tt>
<td>The <tt>pointer</tt> type of the resulting iterator, and in
particular, the result type of <tt>operator-&gt;()</tt>.<br>
<b>Default:</b> If <tt>Value</tt> was supplied, then <tt>Value*</tt>,
otherwise
<tt>std::iterator_traits&lt;BidirectionalIterator&gt;::pointer</tt>.
<tr>
<td><tt>Category</tt>
<td>The <tt>iterator_category</tt> type for the resulting iterator.<br>
<b>Default:</b>
<tt>std::iterator_traits&lt;BidirectionalIterator&gt;::iterator_category</tt>
<tr>
<td><tt>Distance</tt>
<td>The <tt>difference_type</tt> for the resulting iterator.<br>
<b>Default:</b>
<tt>std::iterator_traits&lt;BidirectionalIterator&amp;gt::difference_type</tt>
</table>
<h3>Concept Model</h3>
The indirect iterator will model whichever <a href=
"http://www.sgi.com/tech/stl/Iterators.html">standard iterator concept
category</a> is modeled by the base iterator. Thus, if the base iterator is
a model of <a href=
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access
Iterator</a> then so is the resulting indirect iterator. If the base
iterator models a more restrictive concept, the resulting indirect iterator
will model the same concept. The base iterator must be at least a <a href=
"http://www.sgi.com/tech/stl/BidirectionalIterator.html">Bidirectional
Iterator</a>
<h3>Members</h3>
The reverse iterator type implements the member functions and operators
required of the <a href=
"http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random Access
Iterator</a> concept. In addition it has the following constructor:
<blockquote>
<pre>
reverse_iterator_generator::type(const BidirectionalIterator&amp; it)
</pre>
</blockquote>
<br>
<br>
<hr>
<p>
<h2><a name="make_reverse_iterator">The Reverse Iterator Object
Generator</a></h2>
The <tt>make_reverse_iterator()</tt> function provides a more convenient
way to create reverse iterator objects. The function saves the user the
trouble of explicitly writing out the iterator types.
<blockquote>
<pre>
template &lt;class BidirectionalIterator&gt;
typename reverse_iterator_generator&lt;BidirectionalIterator&gt;::type
make_reverse_iterator(BidirectionalIterator base);
</pre>
</blockquote>
<h3>Example</h3>
In this part of the example we use <tt>make_reverse_iterator()</tt> to
print the sequence of letters in reverse-reverse order, which is the
original order.
<blockquote>
<pre>
// continuing from the previous example...
std::cout &lt;&lt; "letters in ascending order:\t";
std::copy(boost::make_reverse_iterator(reverse_letters_last),
boost::make_reverse_iterator(reverse_letters_first),
std::ostream_iterator&lt;char&gt;(std::cout));
std::cout &lt;&lt; std::endl;
return 0;
}
</pre>
</blockquote>
The output is:
<blockquote>
<pre>
letters in ascending order: !dehllloorw
</pre>
</blockquote>
<hr>
<h2><a name="interactions">Constant/Mutable Iterator Interactions</a></h2>
<p>One failing of the standard <tt><a
href="http://www.sgi.com/tech/stl/ReverseIterator.html">reverse_iterator</a></tt>
adaptor is that it doesn't properly support interactions between adapted
<tt>const</tt> and non-<tt>const</tt> iterators. For example:
<blockquote>
<pre>
#include &lt;vector&gt;
template &lt;class T&gt; void convert(T x) {}
// Test interactions of a matched pair of random access iterators
template &lt;class Iterator, class ConstIterator&gt;
void test_interactions(Iterator i, ConstIterator ci)
{
bool eq = i == ci; // comparisons
bool ne = i != ci;
bool lt = i &lt; ci;
bool le = i &lt;= ci;
bool gt = i &gt; ci;
bool ge = i &gt;= ci;
std::size_t distance = i - ci; // difference
ci = i; // assignment
ConstIterator ci2(i); // construction
convert&lt;ConstIterator&gt;(i); // implicit conversion
}
void f()
{
typedef std::vector&lt;int&gt; vec;
vec v;
const vec&amp; cv;
test_interactions(v.begin(), cv.begin()); // <font color="#007F00">OK</font>
test_interactions(v.rbegin(), cv.rbegin()); // <font color="#FF0000">ERRORS ON EVERY TEST!!</font>
</pre>
</blockquote>
Reverse iterators created with <tt>boost::reverse_iterator_generator</tt> don't have this problem, though:
<blockquote>
<pre>
typedef boost::reverse_iterator_generator&lt;vec::iterator&gt;::type ri;
typedef boost::reverse_iterator_generator&lt;vec::const_iterator&gt;::type cri;
test_interactions(ri(v.begin()), cri(cv.begin())); // <font color="#007F00">OK!!</font>
</pre>
</blockquote>
Or, more simply,
<blockquote>
<pre>
test_interactions(
boost::make_reverse_iterator(v.begin()),
boost::make_reverse_iterator(cv.begin())); // <font color="#007F00">OK!!</font>
}
</pre>
</blockquote>
<p>If you are wondering why there is no
<tt>reverse_iterator_pair_generator</tt> in the manner of <tt><a
href="projection_iterator.htm#projection_iterator_pair_generator">projection_iterator_pair_generator</a></tt>,
the answer is simple: we tried it, but found that in practice it took
<i>more</i> typing to use <tt>reverse_iterator_pair_generator</tt> than to
simply use <tt>reverse_iterator_generator</tt> twice!<br><br>
<hr>
<p>Revised
<!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->26 Feb 2001<!--webbot bot="Timestamp" endspan i-checksum="14386" -->
<p>&copy; Copyright Jeremy Siek 2000. Permission to copy, use, modify, sell
and distribute this document is granted provided this copyright notice
appears in all copies. This document is provided "as is" without express or
implied warranty, and with no claim as to its suitability for any purpose.
<!-- LocalWords: html charset alt gif hpp BidirectionalIterator const namespace struct
-->
<!-- LocalWords: ConstPointer ConstReference typename iostream int abcdefg
-->
<!-- LocalWords: sizeof PairGen pre Siek wroolllhed dehllloorw
-->
</body>
</html>