forked from boostorg/iterator
This commit was manufactured by cvs2svn to create branch 'RC_1_31_0'.
[SVN r21650]
This commit is contained in:
40
doc/counting_iterator_eg.rst
Normal file
40
doc/counting_iterator_eg.rst
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
Example
|
||||||
|
.......
|
||||||
|
|
||||||
|
This example fills an array with numbers and a second array with
|
||||||
|
pointers into the first array, using ``counting_iterator`` for both
|
||||||
|
tasks. Finally ``indirect_iterator`` is used to print out the numbers
|
||||||
|
into the first array via indirection through the second array.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
int N = 7;
|
||||||
|
std::vector<int> numbers;
|
||||||
|
typedef std::vector<int>::iterator n_iter;
|
||||||
|
std::copy(boost::counting_iterator<int>(0),
|
||||||
|
boost::counting_iterator<int>(N),
|
||||||
|
std::back_inserter(numbers));
|
||||||
|
|
||||||
|
std::vector<std::vector<int>::iterator> pointers;
|
||||||
|
std::copy(boost::make_counting_iterator(numbers.begin()),
|
||||||
|
boost::make_counting_iterator(numbers.end()),
|
||||||
|
std::back_inserter(pointers));
|
||||||
|
|
||||||
|
std::cout << "indirectly printing out the numbers from 0 to "
|
||||||
|
<< N << std::endl;
|
||||||
|
std::copy(boost::make_indirect_iterator(pointers.begin()),
|
||||||
|
boost::make_indirect_iterator(pointers.end()),
|
||||||
|
std::ostream_iterator<int>(std::cout, " "));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
The output is::
|
||||||
|
|
||||||
|
indirectly printing out the numbers from 0 to 7
|
||||||
|
0 1 2 3 4 5 6
|
||||||
|
|
||||||
|
The source code for this example can be found `here`__.
|
||||||
|
|
||||||
|
__ ../example/counting_iterator_example.cpp
|
||||||
|
|
69
doc/filter_iterator_eg.rst
Normal file
69
doc/filter_iterator_eg.rst
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
|
||||||
|
Example
|
||||||
|
.......
|
||||||
|
|
||||||
|
This example uses ``filter_iterator`` and then
|
||||||
|
``make_filter_iterator`` to output only the positive integers from an
|
||||||
|
array of integers. Then ``make_filter_iterator`` is is used to output
|
||||||
|
the integers greater than ``-2``.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
struct is_positive_number {
|
||||||
|
bool operator()(int x) { return 0 < x; }
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int numbers_[] = { 0, -1, 4, -3, 5, 8, -2 };
|
||||||
|
const int N = sizeof(numbers_)/sizeof(int);
|
||||||
|
|
||||||
|
typedef int* base_iterator;
|
||||||
|
base_iterator numbers(numbers_);
|
||||||
|
|
||||||
|
// Example using filter_iterator
|
||||||
|
typedef boost::filter_iterator<is_positive_number, base_iterator>
|
||||||
|
FilterIter;
|
||||||
|
|
||||||
|
is_positive_number predicate;
|
||||||
|
FilterIter filter_iter_first(predicate, numbers, numbers + N);
|
||||||
|
FilterIter filter_iter_last(predicate, numbers + N, numbers + N);
|
||||||
|
|
||||||
|
std::copy(filter_iter_first, filter_iter_last, std::ostream_iterator<int>(std::cout, " "));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
// Example using make_filter_iterator()
|
||||||
|
std::copy(boost::make_filter_iterator<is_positive_number>(numbers, numbers + N),
|
||||||
|
boost::make_filter_iterator<is_positive_number>(numbers + N, numbers + N),
|
||||||
|
std::ostream_iterator<int>(std::cout, " "));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
// Another example using make_filter_iterator()
|
||||||
|
std::copy(
|
||||||
|
boost::make_filter_iterator(
|
||||||
|
std::bind2nd(std::greater<int>(), -2)
|
||||||
|
, numbers, numbers + N)
|
||||||
|
|
||||||
|
, boost::make_filter_iterator(
|
||||||
|
std::bind2nd(std::greater<int>(), -2)
|
||||||
|
, numbers + N, numbers + N)
|
||||||
|
|
||||||
|
, std::ostream_iterator<int>(std::cout, " ")
|
||||||
|
);
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
return boost::exit_success;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
The output is::
|
||||||
|
|
||||||
|
4 5 8
|
||||||
|
4 5 8
|
||||||
|
0 -1 4 5 8
|
||||||
|
|
||||||
|
|
||||||
|
The source code for this example can be found `here`__.
|
||||||
|
|
||||||
|
__ ../example/filter_iterator_example.cpp
|
35
doc/function_output_iterator_eg.rst
Normal file
35
doc/function_output_iterator_eg.rst
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
Example
|
||||||
|
.......
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
struct string_appender
|
||||||
|
{
|
||||||
|
string_appender(std::string& s)
|
||||||
|
: m_str(&s)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void operator()(const std::string& x) const
|
||||||
|
{
|
||||||
|
*m_str += x;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string* m_str;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int, char*[])
|
||||||
|
{
|
||||||
|
std::vector<std::string> x;
|
||||||
|
x.push_back("hello");
|
||||||
|
x.push_back(" ");
|
||||||
|
x.push_back("world");
|
||||||
|
x.push_back("!");
|
||||||
|
|
||||||
|
std::string s = "";
|
||||||
|
std::copy(x.begin(), x.end(),
|
||||||
|
boost::make_function_output_iterator(string_appender(s)));
|
||||||
|
|
||||||
|
std::cout << s << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
69
doc/indirect_iterator_eg.rst
Normal file
69
doc/indirect_iterator_eg.rst
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
Example
|
||||||
|
.......
|
||||||
|
|
||||||
|
This example prints an array of characters, using
|
||||||
|
``indirect_iterator`` to access the array of characters through an
|
||||||
|
array of pointers. Next ``indirect_iterator`` is used with the
|
||||||
|
``transform`` algorithm to copy the characters (incremented by one) to
|
||||||
|
another array. A constant indirect iterator is used for the source and
|
||||||
|
a mutable indirect iterator is used for the destination. The last part
|
||||||
|
of the example prints the original array of characters, but this time
|
||||||
|
using the ``make_indirect_iterator`` helper function.
|
||||||
|
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
char characters[] = "abcdefg";
|
||||||
|
const int N = sizeof(characters)/sizeof(char) - 1; // -1 since characters has a null char
|
||||||
|
char* pointers_to_chars[N]; // at the end.
|
||||||
|
for (int i = 0; i < N; ++i)
|
||||||
|
pointers_to_chars[i] = &characters[i];
|
||||||
|
|
||||||
|
// Example of using indirect_iterator
|
||||||
|
|
||||||
|
boost::indirect_iterator<char**, char>
|
||||||
|
indirect_first(pointers_to_chars), indirect_last(pointers_to_chars + N);
|
||||||
|
|
||||||
|
std::copy(indirect_first, indirect_last, std::ostream_iterator<char>(std::cout, ","));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
// Example of making mutable and constant indirect iterators
|
||||||
|
|
||||||
|
char mutable_characters[N];
|
||||||
|
char* pointers_to_mutable_chars[N];
|
||||||
|
for (int j = 0; j < N; ++j)
|
||||||
|
pointers_to_mutable_chars[j] = &mutable_characters[j];
|
||||||
|
|
||||||
|
boost::indirect_iterator<char* const*> mutable_indirect_first(pointers_to_mutable_chars),
|
||||||
|
mutable_indirect_last(pointers_to_mutable_chars + N);
|
||||||
|
boost::indirect_iterator<char* const*, char const> const_indirect_first(pointers_to_chars),
|
||||||
|
const_indirect_last(pointers_to_chars + N);
|
||||||
|
|
||||||
|
std::transform(const_indirect_first, const_indirect_last,
|
||||||
|
mutable_indirect_first, std::bind1st(std::plus<char>(), 1));
|
||||||
|
|
||||||
|
std::copy(mutable_indirect_first, mutable_indirect_last,
|
||||||
|
std::ostream_iterator<char>(std::cout, ","));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
// Example of using make_indirect_iterator()
|
||||||
|
|
||||||
|
std::copy(boost::make_indirect_iterator(pointers_to_chars),
|
||||||
|
boost::make_indirect_iterator(pointers_to_chars + N),
|
||||||
|
std::ostream_iterator<char>(std::cout, ","));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
The output is::
|
||||||
|
|
||||||
|
a,b,c,d,e,f,g,
|
||||||
|
b,c,d,e,f,g,h,
|
||||||
|
a,b,c,d,e,f,g,
|
||||||
|
|
||||||
|
|
||||||
|
The source code for this example can be found `here`__.
|
||||||
|
|
||||||
|
__ ../example/indirect_iterator_example.cpp
|
||||||
|
|
232
doc/interoperability-revisited.rst
Executable file
232
doc/interoperability-revisited.rst
Executable file
@@ -0,0 +1,232 @@
|
|||||||
|
++++++++++++++++++++++++++++
|
||||||
|
Interoperability Revisited
|
||||||
|
++++++++++++++++++++++++++++
|
||||||
|
|
||||||
|
:date: $Date$
|
||||||
|
:copyright: Copyright Thomas Witt 2004.
|
||||||
|
|
||||||
|
|
||||||
|
Problem
|
||||||
|
=======
|
||||||
|
|
||||||
|
The current iterator_facade specification makes it unneccessarily tedious to
|
||||||
|
implement interoperable iterators.
|
||||||
|
|
||||||
|
In the following text a simplified example of the current iterator_facade specification is used to
|
||||||
|
illustrate the problem.
|
||||||
|
|
||||||
|
In the current specification binary operators are implemented in the following way:
|
||||||
|
|
||||||
|
template <class Derived>
|
||||||
|
struct Facade
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T1, T2>
|
||||||
|
struct is_interoperable :
|
||||||
|
or_<
|
||||||
|
is_convertible<T1, T2>
|
||||||
|
, is_convertible<T2, T1>
|
||||||
|
>
|
||||||
|
{};
|
||||||
|
|
||||||
|
template<
|
||||||
|
class Derived1
|
||||||
|
, class Derived2
|
||||||
|
>
|
||||||
|
enable_if<is_interoperable<Derived1, Derived2>, bool> operator==(
|
||||||
|
Derived1 const& lhs
|
||||||
|
, Derived2 const& rhs
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return static_cast<Derived1 const&>(lhs).equal_to(static_cast<Derived2 const&(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
The problem with this is that operator== always forwards to Derived1::equal_to. The net effect is that the
|
||||||
|
following "obvious" implementation of to interoperable types does not quite work.
|
||||||
|
|
||||||
|
struct Mutable : Facade<Mutable>
|
||||||
|
{
|
||||||
|
bool equal_to(Mutable const&);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Constant : Facade<Constant>
|
||||||
|
{
|
||||||
|
Constant();
|
||||||
|
Constant(Constant const&);
|
||||||
|
Constant(Mutable const&);
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
bool equal_to(Constant const&);
|
||||||
|
};
|
||||||
|
|
||||||
|
Constant c;
|
||||||
|
Mutable m;
|
||||||
|
|
||||||
|
c == m; // ok, dispatched to Constant::equal_to
|
||||||
|
m == c; // !! error, dispatched to Mutable::equal_to
|
||||||
|
|
||||||
|
Instead the following "slightly" more complicated implementation is neccessary
|
||||||
|
|
||||||
|
struct Mutable : Facade<Mutable>
|
||||||
|
{
|
||||||
|
template <class T>
|
||||||
|
enable_if<is_convertible<Mutable, T> || is_convertible<T, Mutable>, bool>::type equal_to(T const&);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Constant : Tag<Constant>
|
||||||
|
{
|
||||||
|
Constant();
|
||||||
|
Constant(Constant const&);
|
||||||
|
Constant(Mutable const&);
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
enable_if<is_convertible<Constant, T> || is_convertible<T, Constant>, bool>::type equal_to(T const&);
|
||||||
|
};
|
||||||
|
|
||||||
|
Beside the fact that the code is significantly more complex to understand and to teach there is
|
||||||
|
a major design problem lurking here. Note that in both types equal_to is a function template with
|
||||||
|
an unconstrained argument T. This is neccessary so that further types can be made interoperable with
|
||||||
|
Mutable or Constant. Would Mutable be defined as
|
||||||
|
|
||||||
|
struct Mutable : Facade<Mutable>
|
||||||
|
{
|
||||||
|
bool equal_to(Mutable const&);
|
||||||
|
bool equal_to(Constant const&);
|
||||||
|
};
|
||||||
|
|
||||||
|
Constant and Mutable would still be interoperable but no further interoperable could be added
|
||||||
|
without changing Mutable. Even if this would be considered acceptable the current specification forces
|
||||||
|
a two way dependency between interoperable types. Note in the templated equal_to case this dependency
|
||||||
|
is implicitly created when specializing equal_to.
|
||||||
|
|
||||||
|
Solution
|
||||||
|
========
|
||||||
|
|
||||||
|
The two way dependency can be avoided by enabling type conversion in the binary operator
|
||||||
|
implementation. Note that this is the usual way interoperability betwween types is achieved
|
||||||
|
for binary operators and one reason why binary operators are usually implemented as non-members.
|
||||||
|
|
||||||
|
A simple implementation of this strategy would look like this
|
||||||
|
|
||||||
|
template<
|
||||||
|
class T1
|
||||||
|
, class T2
|
||||||
|
>
|
||||||
|
struct interoperable_base :
|
||||||
|
if_<
|
||||||
|
is_convertible<
|
||||||
|
T2
|
||||||
|
, T1
|
||||||
|
>
|
||||||
|
, T1
|
||||||
|
, T2>
|
||||||
|
{};
|
||||||
|
|
||||||
|
|
||||||
|
template<
|
||||||
|
class Derived1
|
||||||
|
, class Derived2
|
||||||
|
>
|
||||||
|
enable_if<is_interoperable<Derived1, Derived2>, bool> operator==(
|
||||||
|
Derived1 const& lhs
|
||||||
|
, Derived2 const& rhs
|
||||||
|
)
|
||||||
|
{
|
||||||
|
typedef interoperable_base<
|
||||||
|
Derived1
|
||||||
|
, Derived2
|
||||||
|
>::type Base;
|
||||||
|
|
||||||
|
return static_cast<Base const&>(lhs).equal_to(static_cast<Derived2 const&(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
This way our original simple and "obvious" implementation would work again.
|
||||||
|
|
||||||
|
c == m; // ok, dispatched to Constant::equal_to
|
||||||
|
m == c; // ok, dispatched to Constant::equal_to, m converted to Constant
|
||||||
|
|
||||||
|
The backdraw of this approach is that a possibly costly conversion of iterator objects
|
||||||
|
is forced on the user even in cases where direct comparison could be implemented
|
||||||
|
in a much more efficient way. This problem arises especially for iterator_adaptor
|
||||||
|
specializations and can be significantly slow down the iteration over ranges. Given the fact
|
||||||
|
that iteration is a very basic operation this possible performance degradation is not
|
||||||
|
acceptable.
|
||||||
|
|
||||||
|
Luckily whe can have our cake and eat it by a slightly more clever implementation of the binary
|
||||||
|
operators.
|
||||||
|
|
||||||
|
template<
|
||||||
|
class Derived1
|
||||||
|
, class Derived2
|
||||||
|
>
|
||||||
|
enable_if<is_convertible<Derived2, Derived1>, bool> operator==(
|
||||||
|
Derived1 const& lhs
|
||||||
|
, Derived2 const& rhs
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return static_cast<Derived1 const&>(lhs).equal_to(static_cast<Derived2 const&(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
class Derived1
|
||||||
|
, class Derived2
|
||||||
|
>
|
||||||
|
enable_if<is_convertible<Derived1, Derived2>, bool> operator==(
|
||||||
|
Derived1 const& lhs
|
||||||
|
, Derived2 const& rhs
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return static_cast<Derived2 const&>(rhs).equal_to(static_cast<Derived1 const&(lhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
Given our simple and obvious definition of Mutable and Constant nothing has changed yet.
|
||||||
|
|
||||||
|
c == m; // ok, dispatched to Constant::equal_to, m converted to Constant
|
||||||
|
m == c; // ok, dispatched to Constant::equal_to, m converted to Constant
|
||||||
|
|
||||||
|
But now the user can avoid the type conversion by supplying the appropriate overload in Constant
|
||||||
|
|
||||||
|
struct Constant : Facade<Constant>
|
||||||
|
{
|
||||||
|
Constant();
|
||||||
|
Constant(Constant const&);
|
||||||
|
Constant(Mutable const&);
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
bool equal_to(Constant const&);
|
||||||
|
bool equal_to(Mutable const&);
|
||||||
|
};
|
||||||
|
|
||||||
|
c == m; // ok, dispatched to Constant::equal_to(Mutable const&), no conversion
|
||||||
|
m == c; // ok, dispatched to Constant::equal_to(Mutable const&), no conversion
|
||||||
|
|
||||||
|
This definition of operator== introduces a possible ambiguity when both types are convertible
|
||||||
|
to each other. I don't think this is a problem as this behaviour is the same with concrete types.
|
||||||
|
I.e.
|
||||||
|
|
||||||
|
struct A {};
|
||||||
|
|
||||||
|
bool operator==(A, A);
|
||||||
|
|
||||||
|
struct B { B(A); };
|
||||||
|
|
||||||
|
bool operator==(B, B);
|
||||||
|
|
||||||
|
A a;
|
||||||
|
B b(a);
|
||||||
|
|
||||||
|
a == b; // error, ambiguous overload
|
||||||
|
|
||||||
|
Effect
|
||||||
|
======
|
||||||
|
|
||||||
|
Iterator implementations using iterator_facade look exactly as if they were
|
||||||
|
"hand-implemented" (I am working on better wording).
|
||||||
|
|
||||||
|
a) Less burden for the user
|
||||||
|
|
||||||
|
b) The definition (standardese) of specialized adpters might be easier
|
||||||
|
(This has to be proved yet)
|
9
doc/make_counting_iterator.rst
Executable file
9
doc/make_counting_iterator.rst
Executable file
@@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
template <class Incrementable>
|
||||||
|
counting_iterator<Incrementable> make_counting_iterator(Incrementable x);
|
||||||
|
|
||||||
|
:Returns: An instance of ``counting_iterator<Incrementable>``
|
||||||
|
with ``current`` constructed from ``x``.
|
||||||
|
|
9
doc/make_reverse_iterator.rst
Normal file
9
doc/make_reverse_iterator.rst
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
::
|
||||||
|
|
||||||
|
template <class BidirectionalIterator>
|
||||||
|
reverse_iterator<BidirectionalIterator>n
|
||||||
|
make_reverse_iterator(BidirectionalIterator x);
|
||||||
|
|
||||||
|
:Returns: An instance of ``reverse_iterator<BidirectionalIterator>``
|
||||||
|
with a ``current`` constructed from ``x``.
|
||||||
|
|
19
doc/make_transform_iterator.rst
Executable file
19
doc/make_transform_iterator.rst
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
::
|
||||||
|
|
||||||
|
template <class UnaryFunction, class Iterator>
|
||||||
|
transform_iterator<UnaryFunction, Iterator>
|
||||||
|
make_transform_iterator(Iterator it, UnaryFunction fun);
|
||||||
|
|
||||||
|
:Returns: An instance of ``transform_iterator<UnaryFunction, Iterator>`` with ``m_f``
|
||||||
|
initialized to ``f`` and ``m_iterator`` initialized to ``x``.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
template <class UnaryFunction, class Iterator>
|
||||||
|
transform_iterator<UnaryFunction, Iterator>
|
||||||
|
make_transform_iterator(Iterator it);
|
||||||
|
|
||||||
|
:Returns: An instance of ``transform_iterator<UnaryFunction, Iterator>`` with ``m_f``
|
||||||
|
default constructed and ``m_iterator`` initialized to ``x``.
|
67
doc/permutation_iterator_eg.rst
Normal file
67
doc/permutation_iterator_eg.rst
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
::
|
||||||
|
|
||||||
|
using namespace boost;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
typedef std::vector< int > element_range_type;
|
||||||
|
typedef std::list< int > index_type;
|
||||||
|
|
||||||
|
static const int element_range_size = 10;
|
||||||
|
static const int index_size = 4;
|
||||||
|
|
||||||
|
element_range_type elements( element_range_size );
|
||||||
|
for(element_range_type::iterator el_it = elements.begin() ; el_it != elements.end() ; ++el_it)
|
||||||
|
*el_it = std::distance(elements.begin(), el_it);
|
||||||
|
|
||||||
|
index_type indices( index_size );
|
||||||
|
for(index_type::iterator i_it = indices.begin() ; i_it != indices.end() ; ++i_it )
|
||||||
|
*i_it = element_range_size - index_size + std::distance(indices.begin(), i_it);
|
||||||
|
std::reverse( indices.begin(), indices.end() );
|
||||||
|
|
||||||
|
typedef permutation_iterator< element_range_type::iterator, index_type::iterator > permutation_type;
|
||||||
|
permutation_type begin = make_permutation_iterator( elements.begin(), indices.begin() );
|
||||||
|
permutation_type it = begin;
|
||||||
|
permutation_type end = make_permutation_iterator( elements.begin(), indices.end() );
|
||||||
|
|
||||||
|
std::cout << "The original range is : ";
|
||||||
|
std::copy( elements.begin(), elements.end(), std::ostream_iterator< int >( std::cout, " " ) );
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
std::cout << "The reindexing scheme is : ";
|
||||||
|
std::copy( indices.begin(), indices.end(), std::ostream_iterator< int >( std::cout, " " ) );
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
std::cout << "The permutated range is : ";
|
||||||
|
std::copy( begin, end, std::ostream_iterator< int >( std::cout, " " ) );
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
std::cout << "Elements at even indices in the permutation : ";
|
||||||
|
it = begin;
|
||||||
|
for(i = 0; i < index_size / 2 ; ++i, it+=2 ) std::cout << *it << " ";
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
std::cout << "Permutation backwards : ";
|
||||||
|
it = begin + (index_size);
|
||||||
|
assert( it != begin );
|
||||||
|
for( ; it-- != begin ; ) std::cout << *it << " ";
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
std::cout << "Iterate backward with stride 2 : ";
|
||||||
|
it = begin + (index_size - 1);
|
||||||
|
for(i = 0 ; i < index_size / 2 ; ++i, it-=2 ) std::cout << *it << " ";
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
|
||||||
|
The output is::
|
||||||
|
|
||||||
|
The original range is : 0 1 2 3 4 5 6 7 8 9
|
||||||
|
The reindexing scheme is : 9 8 7 6
|
||||||
|
The permutated range is : 9 8 7 6
|
||||||
|
Elements at even indices in the permutation : 9 7
|
||||||
|
Permutation backwards : 6 7 8 9
|
||||||
|
Iterate backward with stride 2 : 6 8
|
||||||
|
|
||||||
|
|
||||||
|
The source code for this example can be found `here`__.
|
||||||
|
|
||||||
|
__ ../example/permutation_iterator_example.cpp
|
42
doc/reverse_iterator_eg.rst
Normal file
42
doc/reverse_iterator_eg.rst
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
Example
|
||||||
|
.......
|
||||||
|
|
||||||
|
The following example prints an array of characters in reverse order
|
||||||
|
using ``reverse_iterator``.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
char letters_[] = "hello world!";
|
||||||
|
const int N = sizeof(letters_)/sizeof(char) - 1;
|
||||||
|
typedef char* base_iterator;
|
||||||
|
base_iterator letters(letters_);
|
||||||
|
std::cout << "original sequence of letters:\t\t\t" << letters_ << std::endl;
|
||||||
|
|
||||||
|
boost::reverse_iterator<base_iterator>
|
||||||
|
reverse_letters_first(letters + N),
|
||||||
|
reverse_letters_last(letters);
|
||||||
|
|
||||||
|
std::cout << "sequence in reverse order:\t\t\t";
|
||||||
|
std::copy(reverse_letters_first, reverse_letters_last,
|
||||||
|
std::ostream_iterator<char>(std::cout));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
std::cout << "sequence in double-reversed (normal) order:\t";
|
||||||
|
std::copy(boost::make_reverse_iterator(reverse_letters_last),
|
||||||
|
boost::make_reverse_iterator(reverse_letters_first),
|
||||||
|
std::ostream_iterator<char>(std::cout));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The output is::
|
||||||
|
|
||||||
|
original sequence of letters: hello world!
|
||||||
|
sequence in reverse order: !dlrow olleh
|
||||||
|
sequence in double-reversed (normal) order: hello world!
|
||||||
|
|
||||||
|
|
||||||
|
The source code for this example can be found `here`__.
|
||||||
|
|
||||||
|
__ ../example/reverse_iterator_example.cpp
|
42
doc/transform_iterator_eg.rst
Executable file
42
doc/transform_iterator_eg.rst
Executable file
@@ -0,0 +1,42 @@
|
|||||||
|
Example
|
||||||
|
.......
|
||||||
|
|
||||||
|
This is a simple example of using the transform_iterators class to
|
||||||
|
generate iterators that multiply (or add to) the value returned by
|
||||||
|
dereferencing the iterator. It would be cooler to use lambda library
|
||||||
|
in this example.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||||
|
const int N = sizeof(x)/sizeof(int);
|
||||||
|
|
||||||
|
typedef boost::binder1st< std::multiplies<int> > Function;
|
||||||
|
typedef boost::transform_iterator<Function, int*> doubling_iterator;
|
||||||
|
|
||||||
|
doubling_iterator i(x, boost::bind1st(std::multiplies<int>(), 2)),
|
||||||
|
i_end(x + N, boost::bind1st(std::multiplies<int>(), 2));
|
||||||
|
|
||||||
|
std::cout << "multiplying the array by 2:" << std::endl;
|
||||||
|
while (i != i_end)
|
||||||
|
std::cout << *i++ << " ";
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
std::cout << "adding 4 to each element in the array:" << std::endl;
|
||||||
|
std::copy(boost::make_transform_iterator(x, boost::bind1st(std::plus<int>(), 4)),
|
||||||
|
boost::make_transform_iterator(x + N, boost::bind1st(std::plus<int>(), 4)),
|
||||||
|
std::ostream_iterator<int>(std::cout, " "));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
The output is::
|
||||||
|
|
||||||
|
multiplying the array by 2:
|
||||||
|
2 4 6 8 10 12 14 16
|
||||||
|
adding 4 to each element in the array:
|
||||||
|
5 6 7 8 9 10 11 12
|
||||||
|
|
||||||
|
|
||||||
|
The source code for this example can be found `here`__.
|
||||||
|
|
||||||
|
__ ../example/transform_iterator_example.cpp
|
54
example/counting_iterator_example.cpp
Normal file
54
example/counting_iterator_example.cpp
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
// (C) Copyright Jeremy Siek 2000-2004.
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iterator>
|
||||||
|
#include <vector>
|
||||||
|
#include <boost/iterator/counting_iterator.hpp>
|
||||||
|
#include <boost/iterator/indirect_iterator.hpp>
|
||||||
|
#include <boost/cstdlib.hpp>
|
||||||
|
|
||||||
|
int main(int, char*[])
|
||||||
|
{
|
||||||
|
// Example of using counting_iterator
|
||||||
|
std::cout << "counting from 0 to 4:" << std::endl;
|
||||||
|
boost::counting_iterator<int> first(0), last(4);
|
||||||
|
std::copy(first, last, std::ostream_iterator<int>(std::cout, " "));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
// Example of using counting iterator to create an array of pointers.
|
||||||
|
int N = 7;
|
||||||
|
std::vector<int> numbers;
|
||||||
|
typedef std::vector<int>::iterator n_iter;
|
||||||
|
// Fill "numbers" array with [0,N)
|
||||||
|
std::copy(
|
||||||
|
boost::counting_iterator<int>(0)
|
||||||
|
, boost::counting_iterator<int>(N)
|
||||||
|
, std::back_inserter(numbers));
|
||||||
|
|
||||||
|
std::vector<std::vector<int>::iterator> pointers;
|
||||||
|
|
||||||
|
// Use counting iterator to fill in the array of pointers.
|
||||||
|
// causes an ICE with MSVC6
|
||||||
|
std::copy(boost::make_counting_iterator(numbers.begin()),
|
||||||
|
boost::make_counting_iterator(numbers.end()),
|
||||||
|
std::back_inserter(pointers));
|
||||||
|
|
||||||
|
// Use indirect iterator to print out numbers by accessing
|
||||||
|
// them through the array of pointers.
|
||||||
|
std::cout << "indirectly printing out the numbers from 0 to "
|
||||||
|
<< N << std::endl;
|
||||||
|
std::copy(boost::make_indirect_iterator(pointers.begin()),
|
||||||
|
boost::make_indirect_iterator(pointers.end()),
|
||||||
|
std::ostream_iterator<int>(std::cout, " "));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
return boost::exit_success;
|
||||||
|
}
|
60
example/filter_iterator_example.cpp
Normal file
60
example/filter_iterator_example.cpp
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
// (C) Copyright Jeremy Siek 1999-2004.
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
|
#include <boost/iterator/filter_iterator.hpp>
|
||||||
|
#include <boost/cstdlib.hpp> // for exit_success
|
||||||
|
|
||||||
|
struct is_positive_number {
|
||||||
|
bool operator()(int x) { return 0 < x; }
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int numbers_[] = { 0, -1, 4, -3, 5, 8, -2 };
|
||||||
|
const int N = sizeof(numbers_)/sizeof(int);
|
||||||
|
|
||||||
|
typedef int* base_iterator;
|
||||||
|
base_iterator numbers(numbers_);
|
||||||
|
|
||||||
|
// Example using make_filter_iterator()
|
||||||
|
std::copy(boost::make_filter_iterator<is_positive_number>(numbers, numbers + N),
|
||||||
|
boost::make_filter_iterator<is_positive_number>(numbers + N, numbers + N),
|
||||||
|
std::ostream_iterator<int>(std::cout, " "));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
// Example using filter_iterator
|
||||||
|
typedef boost::filter_iterator<is_positive_number, base_iterator>
|
||||||
|
FilterIter;
|
||||||
|
|
||||||
|
is_positive_number predicate;
|
||||||
|
FilterIter filter_iter_first(predicate, numbers, numbers + N);
|
||||||
|
FilterIter filter_iter_last(predicate, numbers + N, numbers + N);
|
||||||
|
|
||||||
|
std::copy(filter_iter_first, filter_iter_last, std::ostream_iterator<int>(std::cout, " "));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
// Another example using make_filter_iterator()
|
||||||
|
std::copy(
|
||||||
|
boost::make_filter_iterator(
|
||||||
|
std::bind2nd(std::greater<int>(), -2)
|
||||||
|
, numbers, numbers + N)
|
||||||
|
|
||||||
|
, boost::make_filter_iterator(
|
||||||
|
std::bind2nd(std::greater<int>(), -2)
|
||||||
|
, numbers + N, numbers + N)
|
||||||
|
|
||||||
|
, std::ostream_iterator<int>(std::cout, " ")
|
||||||
|
);
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
return boost::exit_success;
|
||||||
|
}
|
48
example/function_output_iterator_example.cpp
Normal file
48
example/function_output_iterator_example.cpp
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// (C) Copyright Jeremy Siek 2001-2004.
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Revision History:
|
||||||
|
|
||||||
|
// 27 Feb 2001 Jeremy Siek
|
||||||
|
// Initial checkin.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <boost/function_output_iterator.hpp>
|
||||||
|
|
||||||
|
struct string_appender
|
||||||
|
{
|
||||||
|
string_appender(std::string& s)
|
||||||
|
: m_str(&s)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void operator()(const std::string& x) const
|
||||||
|
{
|
||||||
|
*m_str += x;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string* m_str;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int, char*[])
|
||||||
|
{
|
||||||
|
std::vector<std::string> x;
|
||||||
|
x.push_back("hello");
|
||||||
|
x.push_back(" ");
|
||||||
|
x.push_back("world");
|
||||||
|
x.push_back("!");
|
||||||
|
|
||||||
|
std::string s = "";
|
||||||
|
std::copy(x.begin(), x.end(),
|
||||||
|
boost::make_function_output_iterator(string_appender(s)));
|
||||||
|
|
||||||
|
std::cout << s << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
61
example/indirect_iterator_example.cpp
Normal file
61
example/indirect_iterator_example.cpp
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// (C) Copyright Jeremy Siek 2000-2004.
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
#include <iterator>
|
||||||
|
#include <functional>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <boost/iterator/indirect_iterator.hpp>
|
||||||
|
|
||||||
|
int main(int, char*[])
|
||||||
|
{
|
||||||
|
char characters[] = "abcdefg";
|
||||||
|
const int N = sizeof(characters)/sizeof(char) - 1; // -1 since characters has a null char
|
||||||
|
char* pointers_to_chars[N]; // at the end.
|
||||||
|
for (int i = 0; i < N; ++i)
|
||||||
|
pointers_to_chars[i] = &characters[i];
|
||||||
|
|
||||||
|
// Example of using indirect_iterator
|
||||||
|
|
||||||
|
boost::indirect_iterator<char**, char>
|
||||||
|
indirect_first(pointers_to_chars), indirect_last(pointers_to_chars + N);
|
||||||
|
|
||||||
|
std::copy(indirect_first, indirect_last, std::ostream_iterator<char>(std::cout, ","));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
// Example of making mutable and constant indirect iterators
|
||||||
|
|
||||||
|
char mutable_characters[N];
|
||||||
|
char* pointers_to_mutable_chars[N];
|
||||||
|
for (int j = 0; j < N; ++j)
|
||||||
|
pointers_to_mutable_chars[j] = &mutable_characters[j];
|
||||||
|
|
||||||
|
boost::indirect_iterator<char* const*> mutable_indirect_first(pointers_to_mutable_chars),
|
||||||
|
mutable_indirect_last(pointers_to_mutable_chars + N);
|
||||||
|
boost::indirect_iterator<char* const*, char const> const_indirect_first(pointers_to_chars),
|
||||||
|
const_indirect_last(pointers_to_chars + N);
|
||||||
|
|
||||||
|
std::transform(const_indirect_first, const_indirect_last,
|
||||||
|
mutable_indirect_first, std::bind1st(std::plus<char>(), 1));
|
||||||
|
|
||||||
|
std::copy(mutable_indirect_first, mutable_indirect_last,
|
||||||
|
std::ostream_iterator<char>(std::cout, ","));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
// Example of using make_indirect_iterator()
|
||||||
|
|
||||||
|
std::copy(boost::make_indirect_iterator(pointers_to_chars),
|
||||||
|
boost::make_indirect_iterator(pointers_to_chars + N),
|
||||||
|
std::ostream_iterator<char>(std::cout, ","));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
60
example/node.hpp
Executable file
60
example/node.hpp
Executable file
@@ -0,0 +1,60 @@
|
|||||||
|
// Copyright David Abrahams 2004. 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)
|
||||||
|
#ifndef NODE_DWA2004110_HPP
|
||||||
|
# define NODE_DWA2004110_HPP
|
||||||
|
|
||||||
|
# include <iostream>
|
||||||
|
|
||||||
|
// Polymorphic list node base class
|
||||||
|
|
||||||
|
struct node_base
|
||||||
|
{
|
||||||
|
node_base() : m_next(0) {}
|
||||||
|
|
||||||
|
virtual ~node_base()
|
||||||
|
{
|
||||||
|
delete m_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_base* next() const
|
||||||
|
{
|
||||||
|
return m_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void print(std::ostream& s) const = 0;
|
||||||
|
virtual void double_me() = 0;
|
||||||
|
|
||||||
|
void append(node_base* p)
|
||||||
|
{
|
||||||
|
if (m_next)
|
||||||
|
m_next->append(p);
|
||||||
|
else
|
||||||
|
m_next = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
node_base* m_next;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& s, node_base const& n)
|
||||||
|
{
|
||||||
|
n.print(s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct node : node_base
|
||||||
|
{
|
||||||
|
node(T x)
|
||||||
|
: m_value(x)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void print(std::ostream& s) const { s << this->m_value; }
|
||||||
|
void double_me() { m_value += m_value; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
T m_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // NODE_DWA2004110_HPP
|
34
example/node_iterator1.cpp
Executable file
34
example/node_iterator1.cpp
Executable file
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright David Abrahams 2004. 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)
|
||||||
|
|
||||||
|
#include "node_iterator1.hpp"
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
std::auto_ptr<node<int> > nodes(new node<int>(42));
|
||||||
|
nodes->append(new node<std::string>(" is greater than "));
|
||||||
|
nodes->append(new node<int>(13));
|
||||||
|
|
||||||
|
std::copy(
|
||||||
|
node_iterator(nodes.get()), node_iterator()
|
||||||
|
, std::ostream_iterator<node_base>(std::cout, " ")
|
||||||
|
);
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
std::for_each(
|
||||||
|
node_iterator(nodes.get()), node_iterator()
|
||||||
|
, std::mem_fun_ref(&node_base::double_me)
|
||||||
|
);
|
||||||
|
|
||||||
|
std::copy(
|
||||||
|
node_iterator(nodes.get()), node_iterator()
|
||||||
|
, std::ostream_iterator<node_base>(std::cout, "/")
|
||||||
|
);
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
42
example/node_iterator1.hpp
Executable file
42
example/node_iterator1.hpp
Executable file
@@ -0,0 +1,42 @@
|
|||||||
|
// Copyright David Abrahams 2004. 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)
|
||||||
|
#ifndef NODE_ITERATOR1_DWA2004110_HPP
|
||||||
|
# define NODE_ITERATOR1_DWA2004110_HPP
|
||||||
|
|
||||||
|
# include "node.hpp"
|
||||||
|
# include <boost/iterator/iterator_facade.hpp>
|
||||||
|
|
||||||
|
class node_iterator
|
||||||
|
: public boost::iterator_facade<
|
||||||
|
node_iterator
|
||||||
|
, node_base
|
||||||
|
, boost::forward_traversal_tag
|
||||||
|
>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
node_iterator()
|
||||||
|
: m_node(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit node_iterator(node_base* p)
|
||||||
|
: m_node(p)
|
||||||
|
{}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class boost::iterator_core_access;
|
||||||
|
|
||||||
|
void increment()
|
||||||
|
{ m_node = m_node->next(); }
|
||||||
|
|
||||||
|
bool equal(node_iterator const& other) const
|
||||||
|
{ return this->m_node == other.m_node; }
|
||||||
|
|
||||||
|
node_base& dereference() const
|
||||||
|
{ return *m_node; }
|
||||||
|
|
||||||
|
node_base* m_node;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // NODE_ITERATOR1_DWA2004110_HPP
|
43
example/node_iterator2.cpp
Executable file
43
example/node_iterator2.cpp
Executable file
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright David Abrahams 2004. 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)
|
||||||
|
|
||||||
|
#include "node_iterator2.hpp"
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <boost/mem_fn.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
std::auto_ptr<node<int> > nodes(new node<int>(42));
|
||||||
|
nodes->append(new node<std::string>(" is greater than "));
|
||||||
|
nodes->append(new node<int>(13));
|
||||||
|
|
||||||
|
// Check interoperability
|
||||||
|
assert(node_iterator(nodes.get()) == node_const_iterator(nodes.get()));
|
||||||
|
assert(node_const_iterator(nodes.get()) == node_iterator(nodes.get()));
|
||||||
|
|
||||||
|
assert(node_iterator(nodes.get()) != node_const_iterator());
|
||||||
|
assert(node_const_iterator(nodes.get()) != node_iterator());
|
||||||
|
|
||||||
|
std::copy(
|
||||||
|
node_iterator(nodes.get()), node_iterator()
|
||||||
|
, std::ostream_iterator<node_base>(std::cout, " ")
|
||||||
|
);
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
std::for_each(
|
||||||
|
node_iterator(nodes.get()), node_iterator()
|
||||||
|
, boost::mem_fn(&node_base::double_me)
|
||||||
|
);
|
||||||
|
|
||||||
|
std::copy(
|
||||||
|
node_const_iterator(nodes.get()), node_const_iterator()
|
||||||
|
, std::ostream_iterator<node_base>(std::cout, "/")
|
||||||
|
);
|
||||||
|
std::cout << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
58
example/node_iterator2.hpp
Executable file
58
example/node_iterator2.hpp
Executable file
@@ -0,0 +1,58 @@
|
|||||||
|
// Copyright David Abrahams 2004. 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)
|
||||||
|
#ifndef NODE_ITERATOR2_DWA2004110_HPP
|
||||||
|
# define NODE_ITERATOR2_DWA2004110_HPP
|
||||||
|
|
||||||
|
# include "node.hpp"
|
||||||
|
# include <boost/iterator/iterator_adaptor.hpp>
|
||||||
|
|
||||||
|
# ifndef BOOST_NO_SFINAE
|
||||||
|
# include <boost/type_traits/is_convertible.hpp>
|
||||||
|
# include <boost/utility/enable_if.hpp>
|
||||||
|
# endif
|
||||||
|
|
||||||
|
template <class Value>
|
||||||
|
class node_iter
|
||||||
|
: public boost::iterator_adaptor<
|
||||||
|
node_iter<Value> // Derived
|
||||||
|
, Value* // Base
|
||||||
|
, boost::use_default // Value
|
||||||
|
, boost::forward_traversal_tag // CategoryOrTraversal
|
||||||
|
>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
struct enabler {}; // a private type avoids misuse
|
||||||
|
|
||||||
|
typedef boost::iterator_adaptor<
|
||||||
|
node_iter<Value>, Value*, boost::use_default, boost::forward_traversal_tag
|
||||||
|
> super_t;
|
||||||
|
|
||||||
|
public:
|
||||||
|
node_iter()
|
||||||
|
: super_t(0) {}
|
||||||
|
|
||||||
|
explicit node_iter(Value* p)
|
||||||
|
: super_t(p) {}
|
||||||
|
|
||||||
|
template <class OtherValue>
|
||||||
|
node_iter(
|
||||||
|
node_iter<OtherValue> const& other
|
||||||
|
# ifndef BOOST_NO_SFINAE
|
||||||
|
, typename boost::enable_if<
|
||||||
|
boost::is_convertible<OtherValue*,Value*>
|
||||||
|
, enabler
|
||||||
|
>::type = enabler()
|
||||||
|
# endif
|
||||||
|
)
|
||||||
|
: m_node(other.m_node) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class boost::iterator_core_access;
|
||||||
|
void increment() { m_node = m_node->next(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef node_iter<node_base> node_iterator;
|
||||||
|
typedef node_iter<node_base const> node_const_iterator;
|
||||||
|
|
||||||
|
#endif // NODE_ITERATOR2_DWA2004110_HPP
|
43
example/node_iterator3.cpp
Executable file
43
example/node_iterator3.cpp
Executable file
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright David Abrahams 2004. 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)
|
||||||
|
|
||||||
|
#include "node_iterator3.hpp"
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <boost/mem_fn.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
std::auto_ptr<node<int> > nodes(new node<int>(42));
|
||||||
|
nodes->append(new node<std::string>(" is greater than "));
|
||||||
|
nodes->append(new node<int>(13));
|
||||||
|
|
||||||
|
// Check interoperability
|
||||||
|
assert(node_iterator(nodes.get()) == node_const_iterator(nodes.get()));
|
||||||
|
assert(node_const_iterator(nodes.get()) == node_iterator(nodes.get()));
|
||||||
|
|
||||||
|
assert(node_iterator(nodes.get()) != node_const_iterator());
|
||||||
|
assert(node_const_iterator(nodes.get()) != node_iterator());
|
||||||
|
|
||||||
|
std::copy(
|
||||||
|
node_iterator(nodes.get()), node_iterator()
|
||||||
|
, std::ostream_iterator<node_base>(std::cout, " ")
|
||||||
|
);
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
std::for_each(
|
||||||
|
node_iterator(nodes.get()), node_iterator()
|
||||||
|
, boost::mem_fn(&node_base::double_me)
|
||||||
|
);
|
||||||
|
|
||||||
|
std::copy(
|
||||||
|
node_const_iterator(nodes.get()), node_const_iterator()
|
||||||
|
, std::ostream_iterator<node_base>(std::cout, "/")
|
||||||
|
);
|
||||||
|
std::cout << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
58
example/node_iterator3.hpp
Executable file
58
example/node_iterator3.hpp
Executable file
@@ -0,0 +1,58 @@
|
|||||||
|
// Copyright David Abrahams 2004. 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)
|
||||||
|
#ifndef NODE_ITERATOR3_DWA2004110_HPP
|
||||||
|
# define NODE_ITERATOR3_DWA2004110_HPP
|
||||||
|
|
||||||
|
# include "node.hpp"
|
||||||
|
# include <boost/iterator/iterator_adaptor.hpp>
|
||||||
|
|
||||||
|
# ifndef BOOST_NO_SFINAE
|
||||||
|
# include <boost/type_traits/is_convertible.hpp>
|
||||||
|
# include <boost/utility/enable_if.hpp>
|
||||||
|
# endif
|
||||||
|
|
||||||
|
template <class Value>
|
||||||
|
class node_iter
|
||||||
|
: public boost::iterator_adaptor<
|
||||||
|
node_iter<Value> // Derived
|
||||||
|
, Value* // Base
|
||||||
|
, boost::use_default // Value
|
||||||
|
, boost::forward_traversal_tag // CategoryOrTraversal
|
||||||
|
>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
struct enabler {}; // a private type avoids misuse
|
||||||
|
|
||||||
|
typedef boost::iterator_adaptor<
|
||||||
|
node_iter<Value>, Value*, boost::use_default, boost::forward_traversal_tag
|
||||||
|
> super_t;
|
||||||
|
|
||||||
|
public:
|
||||||
|
node_iter()
|
||||||
|
: super_t(0) {}
|
||||||
|
|
||||||
|
explicit node_iter(Value* p)
|
||||||
|
: super_t(p) {}
|
||||||
|
|
||||||
|
template <class OtherValue>
|
||||||
|
node_iter(
|
||||||
|
node_iter<OtherValue> const& other
|
||||||
|
# ifndef BOOST_NO_SFINAE
|
||||||
|
, typename boost::enable_if<
|
||||||
|
boost::is_convertible<OtherValue*,Value*>
|
||||||
|
, enabler
|
||||||
|
>::type = enabler()
|
||||||
|
# endif
|
||||||
|
)
|
||||||
|
: m_node(other.m_node) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class boost::iterator_core_access;
|
||||||
|
void increment() { this->base_reference() = this->base()->next(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef node_iter<node_base> node_iterator;
|
||||||
|
typedef node_iter<node_base const> node_const_iterator;
|
||||||
|
|
||||||
|
#endif // NODE_ITERATOR3_DWA2004110_HPP
|
61
example/permutation_iterator_example.cpp
Normal file
61
example/permutation_iterator_example.cpp
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <list>
|
||||||
|
#include <boost/iterator/permutation_iterator.hpp>
|
||||||
|
#include <boost/cstdlib.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
using namespace boost;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
typedef std::vector< int > element_range_type;
|
||||||
|
typedef std::list< int > index_type;
|
||||||
|
|
||||||
|
static const int element_range_size = 10;
|
||||||
|
static const int index_size = 4;
|
||||||
|
|
||||||
|
element_range_type elements( element_range_size );
|
||||||
|
for(element_range_type::iterator el_it = elements.begin() ; el_it != elements.end() ; ++el_it)
|
||||||
|
*el_it = std::distance(elements.begin(), el_it);
|
||||||
|
|
||||||
|
index_type indices( index_size );
|
||||||
|
for(index_type::iterator i_it = indices.begin() ; i_it != indices.end() ; ++i_it )
|
||||||
|
*i_it = element_range_size - index_size + std::distance(indices.begin(), i_it);
|
||||||
|
std::reverse( indices.begin(), indices.end() );
|
||||||
|
|
||||||
|
typedef permutation_iterator< element_range_type::iterator, index_type::iterator > permutation_type;
|
||||||
|
permutation_type begin = make_permutation_iterator( elements.begin(), indices.begin() );
|
||||||
|
permutation_type it = begin;
|
||||||
|
permutation_type end = make_permutation_iterator( elements.begin(), indices.end() );
|
||||||
|
|
||||||
|
std::cout << "The original range is : ";
|
||||||
|
std::copy( elements.begin(), elements.end(), std::ostream_iterator< int >( std::cout, " " ) );
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
std::cout << "The reindexing scheme is : ";
|
||||||
|
std::copy( indices.begin(), indices.end(), std::ostream_iterator< int >( std::cout, " " ) );
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
std::cout << "The permutated range is : ";
|
||||||
|
std::copy( begin, end, std::ostream_iterator< int >( std::cout, " " ) );
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
std::cout << "Elements at even indices in the permutation : ";
|
||||||
|
it = begin;
|
||||||
|
for(i = 0; i < index_size / 2 ; ++i, it+=2 ) std::cout << *it << " ";
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
std::cout << "Permutation backwards : ";
|
||||||
|
it = begin + (index_size);
|
||||||
|
assert( it != begin );
|
||||||
|
for( ; it-- != begin ; ) std::cout << *it << " ";
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
std::cout << "Iterate backward with stride 2 : ";
|
||||||
|
it = begin + (index_size - 1);
|
||||||
|
for(i = 0 ; i < index_size / 2 ; ++i, it-=2 ) std::cout << *it << " ";
|
||||||
|
std::cout << "\n";
|
||||||
|
|
||||||
|
return boost::exit_success;
|
||||||
|
}
|
43
example/reverse_iterator_example.cpp
Normal file
43
example/reverse_iterator_example.cpp
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// (C) Copyright Jeremy Siek 2000-2004.
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <boost/iterator/reverse_iterator.hpp>
|
||||||
|
#include <boost/cstdlib.hpp>
|
||||||
|
|
||||||
|
int main(int, char*[])
|
||||||
|
{
|
||||||
|
char letters_[] = "hello world!";
|
||||||
|
const int N = sizeof(letters_)/sizeof(char) - 1;
|
||||||
|
typedef char* base_iterator;
|
||||||
|
base_iterator letters(letters_);
|
||||||
|
|
||||||
|
std::cout << "original sequence of letters:\t\t\t"
|
||||||
|
<< letters_ << std::endl;
|
||||||
|
|
||||||
|
// Use reverse_iterator to print a sequence of letters in reverse
|
||||||
|
// order.
|
||||||
|
|
||||||
|
boost::reverse_iterator<base_iterator>
|
||||||
|
reverse_letters_first(letters + N),
|
||||||
|
reverse_letters_last(letters);
|
||||||
|
|
||||||
|
std::cout << "sequence in reverse order:\t\t\t";
|
||||||
|
std::copy(reverse_letters_first, reverse_letters_last,
|
||||||
|
std::ostream_iterator<char>(std::cout));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
std::cout << "sequence in double-reversed (normal) order:\t";
|
||||||
|
std::copy(boost::make_reverse_iterator(reverse_letters_last),
|
||||||
|
boost::make_reverse_iterator(reverse_letters_first),
|
||||||
|
std::ostream_iterator<char>(std::cout));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
return boost::exit_success;
|
||||||
|
}
|
78
example/transform_iterator_example.cpp
Normal file
78
example/transform_iterator_example.cpp
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
// (C) Copyright Jeremy Siek 2000-2004.
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
#include <boost/iterator/transform_iterator.hpp>
|
||||||
|
|
||||||
|
// What a bummer. We can't use std::binder1st with transform iterator
|
||||||
|
// because it does not have a default constructor. Here's a version
|
||||||
|
// that does.
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
|
||||||
|
template <class Operation>
|
||||||
|
class binder1st
|
||||||
|
: public std::unary_function<typename Operation::second_argument_type,
|
||||||
|
typename Operation::result_type> {
|
||||||
|
protected:
|
||||||
|
Operation op;
|
||||||
|
typename Operation::first_argument_type value;
|
||||||
|
public:
|
||||||
|
binder1st() { } // this had to be added!
|
||||||
|
binder1st(const Operation& x,
|
||||||
|
const typename Operation::first_argument_type& y)
|
||||||
|
: op(x), value(y) {}
|
||||||
|
typename Operation::result_type
|
||||||
|
operator()(const typename Operation::second_argument_type& x) const {
|
||||||
|
return op(value, x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Operation, class T>
|
||||||
|
inline binder1st<Operation> bind1st(const Operation& op, const T& x) {
|
||||||
|
typedef typename Operation::first_argument_type arg1_type;
|
||||||
|
return binder1st<Operation>(op, arg1_type(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int, char*[])
|
||||||
|
{
|
||||||
|
// This is a simple example of using the transform_iterators class to
|
||||||
|
// generate iterators that multiply the value returned by dereferencing
|
||||||
|
// the iterator. In this case we are multiplying by 2.
|
||||||
|
// Would be cooler to use lambda library in this example.
|
||||||
|
|
||||||
|
int x[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||||
|
const int N = sizeof(x)/sizeof(int);
|
||||||
|
|
||||||
|
typedef boost::binder1st< std::multiplies<int> > Function;
|
||||||
|
typedef boost::transform_iterator<Function, int*> doubling_iterator;
|
||||||
|
|
||||||
|
doubling_iterator i(x, boost::bind1st(std::multiplies<int>(), 2)),
|
||||||
|
i_end(x + N, boost::bind1st(std::multiplies<int>(), 2));
|
||||||
|
|
||||||
|
std::cout << "multiplying the array by 2:" << std::endl;
|
||||||
|
while (i != i_end)
|
||||||
|
std::cout << *i++ << " ";
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
std::cout << "adding 4 to each element in the array:" << std::endl;
|
||||||
|
|
||||||
|
std::copy(boost::make_transform_iterator(x, boost::bind1st(std::plus<int>(), 4)),
|
||||||
|
boost::make_transform_iterator(x + N, boost::bind1st(std::plus<int>(), 4)),
|
||||||
|
std::ostream_iterator<int>(std::cout, " "));
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
72
test/pointee.cpp
Executable file
72
test/pointee.cpp
Executable file
@@ -0,0 +1,72 @@
|
|||||||
|
// Copyright David Abrahams 2004. 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)
|
||||||
|
|
||||||
|
#include <boost/pointee.hpp>
|
||||||
|
#include <boost/type_traits/add_const.hpp>
|
||||||
|
#include "static_assert_same.hpp"
|
||||||
|
#include <memory>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
template <class T, class Ref>
|
||||||
|
struct proxy_ptr
|
||||||
|
{
|
||||||
|
typedef T element_type;
|
||||||
|
struct proxy
|
||||||
|
{
|
||||||
|
operator Ref() const;
|
||||||
|
};
|
||||||
|
proxy operator*() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct proxy_ref_ptr : proxy_ptr<T,T&>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct proxy_value_ptr : proxy_ptr<T,T>
|
||||||
|
{
|
||||||
|
typedef typename boost::add_const<T>::type element_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct X {
|
||||||
|
template <class T> X(T const&);
|
||||||
|
template <class T> operator T&() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
BOOST_TT_BROKEN_COMPILER_SPEC(X)
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<proxy_ref_ptr<int> >::type, int);
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<proxy_ref_ptr<X> >::type, X);
|
||||||
|
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<proxy_ref_ptr<int const> >::type, int const);
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<proxy_ref_ptr<X const> >::type, X const);
|
||||||
|
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<proxy_value_ptr<int> >::type, int const);
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<proxy_value_ptr<X> >::type, X const);
|
||||||
|
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<proxy_value_ptr<int const> >::type, int const);
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<proxy_value_ptr<X const> >::type, X const);
|
||||||
|
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<int*>::type, int);
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<int const*>::type, int const);
|
||||||
|
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<X*>::type, X);
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<X const*>::type, X const);
|
||||||
|
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<std::auto_ptr<int> >::type, int);
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<std::auto_ptr<X> >::type, X);
|
||||||
|
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<std::auto_ptr<int const> >::type, int const);
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<std::auto_ptr<X const> >::type, X const);
|
||||||
|
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<std::list<int>::iterator >::type, int);
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<std::list<X>::iterator >::type, X);
|
||||||
|
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<std::list<int>::const_iterator >::type, int const);
|
||||||
|
STATIC_ASSERT_SAME(boost::pointee<std::list<X>::const_iterator >::type, X const);
|
||||||
|
return 0;
|
||||||
|
}
|
Reference in New Issue
Block a user